Skip to content

Commit 37ca44e

Browse files
committed
fix(project): ne pas écraser le worktree du projet global
Quand git init est exécuté dans un répertoire sans validation, fromDirectory() retombait sur ProjectID.global avec worktree=sandbox au lieu de worktree="/". L'upsert Phase 2 écrasait alors le worktree du projet global existant, corrompant toutes les sessions globales. Refs: anomalyco#21230
1 parent 98b60ac commit 37ca44e

2 files changed

Lines changed: 26 additions & 3 deletions

File tree

‎packages/opencode/src/project/project.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ export const layer: Layer.Layer<
231231
}
232232

233233
if (!id) {
234-
return { id: ProjectID.global, worktree: sandbox, sandbox, vcs: "git" as const }
234+
return { id: ProjectID.global, worktree: "/", sandbox, vcs: "git" as const }
235235
}
236236

237237
const topLevel = yield* git(["rev-parse", "--show-toplevel"], { cwd: sandbox })

‎packages/opencode/test/project/project.test.ts‎

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import path from "path"
66
import { tmpdir } from "../fixture/fixture"
77
import { GlobalBus } from "../../src/bus/global"
88
import { ProjectID } from "../../src/project/schema"
9+
import { ProjectTable } from "../../src/project/project.sql"
10+
import { Database, eq } from "../../src/storage"
911
import { Effect, Layer, Stream } from "effect"
1012
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"
1113
import { NodePath } from "@effect/platform-node"
@@ -78,7 +80,7 @@ describe("Project.fromDirectory", () => {
7880
expect(project).toBeDefined()
7981
expect(project.id).toBe(ProjectID.global)
8082
expect(project.vcs).toBe("git")
81-
expect(project.worktree).toBe(tmp.path)
83+
expect(project.worktree).toBe("/")
8284

8385
const opencodeFile = path.join(tmp.path, ".git", "opencode")
8486
expect(await Bun.file(opencodeFile).exists()).toBe(false)
@@ -110,6 +112,27 @@ describe("Project.fromDirectory", () => {
110112
const { project: b } = await run((svc) => svc.fromDirectory(tmp.path))
111113
expect(b.id).toBe(a.id)
112114
})
115+
116+
test("git init without commits must not overwrite global worktree", async () => {
117+
// Step 1: non-git directory creates global project with worktree="/"
118+
await using dirA = await tmpdir()
119+
const { project: p1 } = await run((svc) => svc.fromDirectory(dirA.path))
120+
expect(p1.id).toBe(ProjectID.global)
121+
expect(p1.worktree).toBe("/")
122+
123+
const row1 = Database.use((db) => db.select().from(ProjectTable).where(eq(ProjectTable.id, ProjectID.global)).get())
124+
expect(row1?.worktree).toBe("/")
125+
126+
// Step 2: git init (no commits) in a different directory
127+
await using dirB = await tmpdir()
128+
await $`git init`.cwd(dirB.path).quiet()
129+
const { project: p2 } = await run((svc) => svc.fromDirectory(dirB.path))
130+
expect(p2.id).toBe(ProjectID.global)
131+
132+
// The global project worktree must remain "/"
133+
const row2 = Database.use((db) => db.select().from(ProjectTable).where(eq(ProjectTable.id, ProjectID.global)).get())
134+
expect(row2?.worktree).toBe("/")
135+
})
113136
})
114137

115138
describe("Project.fromDirectory git failure paths", () => {
@@ -121,7 +144,7 @@ describe("Project.fromDirectory git failure paths", () => {
121144
const { project } = await run((svc) => svc.fromDirectory(tmp.path))
122145
expect(project.vcs).toBe("git")
123146
expect(project.id).toBe(ProjectID.global)
124-
expect(project.worktree).toBe(tmp.path)
147+
expect(project.worktree).toBe("/")
125148
})
126149

127150
test("handles show-toplevel failure gracefully", async () => {

0 commit comments

Comments
 (0)