fix(reference): initialize bridge state before returning

This commit is contained in:
Shoubhit Dash 2026-06-03 17:50:04 +05:30
commit cfe8327e19
2 changed files with 123 additions and 104 deletions

View file

@ -9,7 +9,7 @@ import { ProjectReference } from "@opencode-ai/core/project-reference"
import { ConfigReference } from "@opencode-ai/core/config/reference" import { ConfigReference } from "@opencode-ai/core/config/reference"
import { RepositoryCache } from "@opencode-ai/core/repository-cache" import { RepositoryCache } from "@opencode-ai/core/repository-cache"
import { AbsolutePath } from "@opencode-ai/core/schema" import { AbsolutePath } from "@opencode-ai/core/schema"
import { Context, Effect, Layer, Schema, Scope } from "effect" import { Context, Effect, Layer, Schema } from "effect"
export type Resolved = ProjectReference.Resolved export type Resolved = ProjectReference.Resolved
@ -51,7 +51,6 @@ export const layer = Layer.effect(
Service, Service,
Effect.gen(function* () { Effect.gen(function* () {
const config = yield* Config.Service const config = yield* Config.Service
const scope = yield* Scope.Scope
const state = yield* InstanceState.make( const state = yield* InstanceState.make(
Effect.fn("Reference.state")(function* (ctx) { Effect.fn("Reference.state")(function* (ctx) {
const { Config: ConfigV2 } = yield* Effect.promise(() => import("@opencode-ai/core/config")) const { Config: ConfigV2 } = yield* Effect.promise(() => import("@opencode-ai/core/config"))
@ -93,7 +92,7 @@ export const layer = Layer.effect(
return Service.of({ return Service.of({
init: Effect.fn("Reference.init")(function* () { init: Effect.fn("Reference.init")(function* () {
yield* ensure().pipe(Effect.forkIn(scope), Effect.asVoid) yield* InstanceState.get(state)
}), }),
list: Effect.fn("Reference.list")(function* () { list: Effect.fn("Reference.list")(function* () {
return yield* InstanceState.useEffect(state, (service) => service.list()) return yield* InstanceState.useEffect(state, (service) => service.list())

View file

@ -89,7 +89,7 @@ const waitForContent = (
fs: FSUtil.Interface, fs: FSUtil.Interface,
file: string, file: string,
content: string, content: string,
attempts = 300, attempts = 50,
): Effect.Effect<void, FSUtil.Error> => ): Effect.Effect<void, FSUtil.Error> =>
Effect.gen(function* () { Effect.gen(function* () {
if ((yield* fs.readFileStringSafe(file)) === content) return if ((yield* fs.readFileStringSafe(file)) === content) return
@ -190,6 +190,32 @@ describe("reference", () => {
), ),
) )
references.live("resolves configured remotes before init returns", () =>
withReferences(
provideTmpdirInstance(
(_dir) =>
Effect.gen(function* () {
const remoteRoot = yield* tmpdirScoped()
const reference = yield* Reference.Service
yield* githubBase(`file://${remoteRoot}/`, reference.init())
const resolved = yield* reference.get("docs")
expect(resolved?.kind).toBe("git")
if (resolved?.kind === "git") {
expect(resolved.reference.remote).toBe(`file://${remoteRoot}/opencode-reference-init/repo.git`)
}
}),
{
config: {
reference: {
docs: "opencode-reference-init/repo",
},
},
},
),
),
)
it.live("marks same-cache references with different branches invalid", () => it.live("marks same-cache references with different branches invalid", () =>
Effect.gen(function* () { Effect.gen(function* () {
const root = path.resolve("opencode-reference-root") const root = path.resolve("opencode-reference-root")
@ -233,124 +259,118 @@ describe("reference", () => {
}), }),
) )
references.live( references.live("materializes configured git references during init", () =>
"materializes configured git references during init", withReferences(
() => provideTmpdirInstance(
withReferences( (_dir) =>
provideTmpdirInstance( Effect.gen(function* () {
(_dir) => const fs = yield* FSUtil.Service
Effect.gen(function* () { const cache = path.join(Global.Path.repos, "github.com", "opencode-reference-test", "repo")
const fs = yield* FSUtil.Service yield* fs.remove(cache, { recursive: true }).pipe(Effect.ignore)
const cache = path.join(Global.Path.repos, "github.com", "opencode-reference-test", "repo") yield* Effect.addFinalizer(() => fs.remove(cache, { recursive: true }).pipe(Effect.ignore))
yield* fs.remove(cache, { recursive: true }).pipe(Effect.ignore)
yield* Effect.addFinalizer(() => fs.remove(cache, { recursive: true }).pipe(Effect.ignore))
const source = yield* tmpdirScoped({ git: true }) const source = yield* tmpdirScoped({ git: true })
const remoteRoot = yield* tmpdirScoped() const remoteRoot = yield* tmpdirScoped()
const remoteDir = path.join(remoteRoot, "opencode-reference-test") const remoteDir = path.join(remoteRoot, "opencode-reference-test")
const remoteRepo = path.join(remoteDir, "repo.git") const remoteRepo = path.join(remoteDir, "repo.git")
yield* Effect.promise(() => Bun.write(path.join(source, "README.md"), "configured\n")) yield* Effect.promise(() => Bun.write(path.join(source, "README.md"), "configured\n"))
yield* git(source, ["add", "."]) yield* git(source, ["add", "."])
yield* git(source, ["commit", "-m", "add readme"]) yield* git(source, ["commit", "-m", "add readme"])
yield* fs.makeDirectory(remoteDir, { recursive: true }).pipe(Effect.orDie) yield* fs.makeDirectory(remoteDir, { recursive: true }).pipe(Effect.orDie)
yield* git(remoteRoot, ["clone", "--bare", source, remoteRepo]) yield* git(remoteRoot, ["clone", "--bare", source, remoteRepo])
const reference = yield* Reference.Service const reference = yield* Reference.Service
yield* githubBase( yield* githubBase(
`file://${remoteRoot}/`, `file://${remoteRoot}/`,
Effect.gen(function* () { Effect.gen(function* () {
yield* reference.init() yield* reference.init()
yield* waitForContent(fs, path.join(cache, "README.md"), "configured\n") yield* waitForContent(fs, path.join(cache, "README.md"), "configured\n")
}), }),
) )
expect(yield* fs.existsSafe(path.join(cache, ".git"))).toBe(true) expect(yield* fs.existsSafe(path.join(cache, ".git"))).toBe(true)
expect(yield* fs.readFileString(path.join(cache, "README.md"))).toBe("configured\n") expect(yield* fs.readFileString(path.join(cache, "README.md"))).toBe("configured\n")
const resolved = yield* reference.get("docs") const resolved = yield* reference.get("docs")
expect(resolved?.kind).toBe("git") expect(resolved?.kind).toBe("git")
if (resolved?.kind === "git") expect(resolved.path).toBe(cache) if (resolved?.kind === "git") expect(resolved.path).toBe(cache)
}), }),
{ {
config: { config: {
reference: { reference: {
docs: "opencode-reference-test/repo", docs: "opencode-reference-test/repo",
},
}, },
}, },
), },
), ),
{ timeout: 40_000 }, ),
) )
references.live( references.live("refreshes configured git references on new instance init", () =>
"refreshes configured git references on new instance init", withReferences(
() => Effect.gen(function* () {
withReferences( const fs = yield* FSUtil.Service
Effect.gen(function* () { const cache = path.join(Global.Path.repos, "github.com", "opencode-reference-refresh", "repo")
const fs = yield* FSUtil.Service yield* fs.remove(cache, { recursive: true }).pipe(Effect.ignore)
const cache = path.join(Global.Path.repos, "github.com", "opencode-reference-refresh", "repo") yield* Effect.addFinalizer(() => fs.remove(cache, { recursive: true }).pipe(Effect.ignore))
yield* fs.remove(cache, { recursive: true }).pipe(Effect.ignore)
yield* Effect.addFinalizer(() => fs.remove(cache, { recursive: true }).pipe(Effect.ignore))
const source = yield* tmpdirScoped({ git: true }) const source = yield* tmpdirScoped({ git: true })
const remoteRoot = yield* tmpdirScoped() const remoteRoot = yield* tmpdirScoped()
const remoteDir = path.join(remoteRoot, "opencode-reference-refresh") const remoteDir = path.join(remoteRoot, "opencode-reference-refresh")
const remoteRepo = path.join(remoteDir, "repo.git") const remoteRepo = path.join(remoteDir, "repo.git")
yield* Effect.promise(() => Bun.write(path.join(source, "README.md"), "v1\n")) yield* Effect.promise(() => Bun.write(path.join(source, "README.md"), "v1\n"))
yield* git(source, ["add", "."]) yield* git(source, ["add", "."])
yield* git(source, ["commit", "-m", "add readme"]) yield* git(source, ["commit", "-m", "add readme"])
yield* fs.makeDirectory(remoteDir, { recursive: true }).pipe(Effect.orDie) yield* fs.makeDirectory(remoteDir, { recursive: true }).pipe(Effect.orDie)
yield* git(remoteRoot, ["clone", "--bare", source, remoteRepo]) yield* git(remoteRoot, ["clone", "--bare", source, remoteRepo])
yield* githubBase( yield* githubBase(
`file://${remoteRoot}/`, `file://${remoteRoot}/`,
provideTmpdirInstance( provideTmpdirInstance(
(_dir) => (_dir) =>
Effect.gen(function* () { Effect.gen(function* () {
const reference = yield* Reference.Service const reference = yield* Reference.Service
yield* reference.init() yield* reference.init()
yield* waitForContent(fs, path.join(cache, "README.md"), "v1\n") yield* waitForContent(fs, path.join(cache, "README.md"), "v1\n")
}), }),
{ {
config: { config: {
reference: { reference: {
docs: "opencode-reference-refresh/repo", docs: "opencode-reference-refresh/repo",
},
}, },
}, },
), },
) ),
)
const branch = yield* git(source, ["branch", "--show-current"]) const branch = yield* git(source, ["branch", "--show-current"])
yield* git(source, ["remote", "add", "origin", remoteRepo]) yield* git(source, ["remote", "add", "origin", remoteRepo])
yield* Effect.promise(() => Bun.write(path.join(source, "README.md"), "v2\n")) yield* Effect.promise(() => Bun.write(path.join(source, "README.md"), "v2\n"))
yield* git(source, ["add", "."]) yield* git(source, ["add", "."])
yield* git(source, ["commit", "-m", "update readme"]) yield* git(source, ["commit", "-m", "update readme"])
yield* git(source, ["push", "origin", `${branch}:${branch}`]) yield* git(source, ["push", "origin", `${branch}:${branch}`])
yield* githubBase( yield* githubBase(
`file://${remoteRoot}/`, `file://${remoteRoot}/`,
provideTmpdirInstance( provideTmpdirInstance(
(_dir) => (_dir) =>
Effect.gen(function* () { Effect.gen(function* () {
const reference = yield* Reference.Service const reference = yield* Reference.Service
yield* reference.init() yield* reference.init()
yield* waitForContent(fs, path.join(cache, "README.md"), "v2\n") yield* waitForContent(fs, path.join(cache, "README.md"), "v2\n")
}), }),
{ {
config: { config: {
reference: { reference: {
docs: "opencode-reference-refresh/repo", docs: "opencode-reference-refresh/repo",
},
}, },
}, },
), },
) ),
}), )
), }),
{ timeout: 40_000 }, ),
) )
}) })