From c92cac8a8792465d6e2c682ce9402240f9e5dfe0 Mon Sep 17 00:00:00 2001 From: marius-kilocode Date: Tue, 25 Aug 2026 11:35:57 +0200 Subject: [PATCH] fix(cli): keep location map scoped to listener --- packages/opencode/src/effect/app-runtime.ts | 4 ---- .../src/server/routes/instance/httpapi/server.ts | 13 +++++++------ .../test/kilocode/shared-location-map.test.ts | 13 +++++-------- 3 files changed, 12 insertions(+), 18 deletions(-) diff --git a/packages/opencode/src/effect/app-runtime.ts b/packages/opencode/src/effect/app-runtime.ts index bac49f4a63..eb61a88fea 100644 --- a/packages/opencode/src/effect/app-runtime.ts +++ b/packages/opencode/src/effect/app-runtime.ts @@ -67,12 +67,10 @@ import { ProjectCopy } from "@opencode-ai/core/project/copy" // kilocode_change import { MoveSession } from "@opencode-ai/core/control-plane/move-session" // kilocode_change import { PtyTicket } from "@opencode-ai/core/pty/ticket" // kilocode_change import { Pty } from "@opencode-ai/core/pty" // kilocode_change -import { buildLocationServiceMap, LocationServiceMap } from "@opencode-ai/core/location-services" // kilocode_change // kilocode_change start - retain Kilo runtime services in the upstream node graph const memory = LayerNode.make({ service: MemoryService.Service, layer: MemoryService.layer, deps: [] }) const kilo = LayerNode.group([Credential.node, ModelCache.node, AgentManager.node, Notebook.node, memory]) -const locationServiceMap = buildLocationServiceMap() // kilocode_change - bind fallback consumers to one process-wide map // kilocode_change end export const AppLayer = AppNodeBuilderV1.build( @@ -134,10 +132,8 @@ export const AppLayer = AppNodeBuilderV1.build( MoveSession.node, PtyTicket.node, Pty.shutdownNode, // kilocode_change - LocationServiceMap.node, // kilocode_change - expose the process-wide location cache to listeners // kilocode_change end ]), - [[LocationServiceMap.node, locationServiceMap]], // kilocode_change ).pipe(Layer.provideMerge(AppNodeBuilderV1.build(Ripgrep.node)), Layer.provideMerge(Observability.layer)) const rt = ManagedRuntime.make(AppLayer, { memoMap }) diff --git a/packages/opencode/src/server/routes/instance/httpapi/server.ts b/packages/opencode/src/server/routes/instance/httpapi/server.ts index 9f112cbcd4..dc35b2ddbf 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/server.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/server.ts @@ -337,7 +337,7 @@ export function createRoutes( ), Layer.provide(locationServiceMapV2), - Layer.provide(AppNodeBuilderV1.build(app, [[LocationServiceMap.node, locationServiceMapV2]])), // kilocode_change + Layer.provide(AppNodeBuilderV1.build(app)), // Must stay last: layers provided later in this pipe build beneath earlier ones, // so Observability must come after every service graph. Otherwise eagerly forked // fibers (e.g. the ModelsDev background refresh) capture Effect's default stdout @@ -348,9 +348,7 @@ export function createRoutes( // kilocode_change start - keep listener routes local while application services come from AppRuntime export function createListenerRoutes(corsOptions?: CorsOptions) { - // Re-export AppRuntime's process-wide map through listener-local graphs instead of - // materializing another full catalog and native file index for every worktree. - const locationServiceMapV2 = Layer.effect(LocationServiceMap.Service, LocationServiceMap.Service) + const locationServiceMapV2 = buildLocationServiceMap() return Layer.mergeAll( rootApiRoutes, @@ -366,8 +364,11 @@ export function createListenerRoutes(corsOptions?: CorsOptions) { // satisfied when the layer is built, not at request time, so the listener needs the same chain // createRoutes uses. // - // SessionV2 remains listener-local because it uses SessionExecutionLocal. Its location map is - // inherited from AppRuntime so every server graph shares one cache. + // These builds sit inside KiloListener's Layer.fresh boundary, so each one self-provides its own + // dependency subtree rather than resolving AppRuntime's. That is deliberate: SessionV2 is bound + // to this listener's LocationServiceMap and to SessionExecutionLocal, so it cannot be the + // process-wide instance. Everything the graph does not rebind (the nodes listed in AppLayer) + // still comes from AppRuntime, and the scope teardown releases the rest. Layer.provide(sessionLocationLayer), Layer.provide(locationLayer), Layer.provide(PtyEnvironment.layer), diff --git a/packages/opencode/test/kilocode/shared-location-map.test.ts b/packages/opencode/test/kilocode/shared-location-map.test.ts index c8f9b8c7ac..84e363d2a1 100644 --- a/packages/opencode/test/kilocode/shared-location-map.test.ts +++ b/packages/opencode/test/kilocode/shared-location-map.test.ts @@ -20,16 +20,13 @@ describe("shared location service map", () => { } }) - test("server app graph receives the listener location map", () => { + test("listener owns its location map scope", () => { expect(source("server/routes/instance/httpapi/server.ts")).toContain( + "const locationServiceMapV2 = buildLocationServiceMap()", + ) + expect(source("server/routes/instance/httpapi/server.ts")).not.toContain( "AppNodeBuilderV1.build(app, [[LocationServiceMap.node, locationServiceMapV2]])", ) - }) - - test("listener inherits the process-wide location map", () => { - expect(source("server/routes/instance/httpapi/server.ts")).toContain( - "Layer.effect(LocationServiceMap.Service, LocationServiceMap.Service)", - ) - expect(source("effect/app-runtime.ts")).toContain("LocationServiceMap.node") + expect(source("effect/app-runtime.ts")).not.toContain("LocationServiceMap.node") }) })