Procházet zdrojové kódy

fix(core): preserve global instructions across read races

Kit Langton před 3 týdny
rodič
revize
1bbe16b93e

+ 5 - 2
packages/core/src/instruction-discovery.ts

@@ -66,7 +66,10 @@ export const layer = (options?: Options) => Layer.effect(
           fs.resolve,
         ),
       )
-      const paths = Array.dedupe([yield* fs.resolve(join(global.config, "AGENTS.md")), ...discovered])
+      const globalPath = yield* fs.resolve(join(global.config, "AGENTS.md"))
+      const observed = new Set(discovered)
+      if (yield* fs.exists(globalPath)) observed.add(globalPath)
+      const paths = Array.dedupe([globalPath, ...discovered])
       const files = yield* Effect.forEach(
         paths,
         (path) =>
@@ -79,7 +82,7 @@ export const layer = (options?: Options) => Layer.effect(
             ),
         { concurrency: "unbounded" },
       )
-      if (files.some((file, index) => file === undefined && discovered.has(paths[index])))
+      if (files.some((file, index) => file === undefined && observed.has(paths[index])))
         return Instructions.unavailable
       return files.filter((file): file is File => file !== undefined)
     })

+ 36 - 0
packages/core/test/instruction-discovery.test.ts

@@ -199,6 +199,42 @@ describe("InstructionDiscovery", () => {
     }),
   )
 
+  it.effect("preserves admitted instructions when the global file disappears before read", () =>
+    Effect.gen(function* () {
+      const file = AbsolutePath.make("/global/AGENTS.md")
+      const racingFS = Layer.effect(
+        FSUtil.Service,
+        FSUtil.Service.pipe(
+          Effect.map((fs) =>
+            FSUtil.Service.of({
+              ...fs,
+              exists: () => Effect.succeed(true),
+              up: () => Effect.succeed([]),
+              readFileStringSafe: () => Effect.succeed(undefined),
+            }),
+          ),
+        ),
+      ).pipe(Layer.provide(LayerNode.compile(FSUtil.node)))
+      const context = yield* InstructionDiscovery.Service.pipe(
+        Effect.flatMap((service) => service.load()),
+        Effect.provide(
+          instructionLayer({
+            config: "/global",
+            filesystemLayer: racingFS,
+            locationServiceLayer: Layer.succeed(
+              Location.Service,
+              Location.Service.of(location({ directory: AbsolutePath.make("/repo") })),
+            ),
+          }),
+        ),
+      )
+
+      expect(
+        (yield* readUpdate(context, state({ "core/instructions": [{ path: file, content: "old" }] }))).changed,
+      ).toBe(false)
+    }),
+  )
+
   it.effect("canonicalizes upward discovery boundaries", () =>
     Effect.gen(function* () {
       let observed: { targets: string[]; start: string; stop?: string } | undefined