| ... | @@ -2287,6 +2287,77 @@ describe("ClaudeAdapterLive", () => { | ... | @@ -2287,6 +2287,77 @@ describe("ClaudeAdapterLive", () => { |
| 2287 | ); | 2287 | ); |
| 2288 | }); | 2288 | }); |
| 2289 | | 2289 | |
| | 2290 | it.effect("consumes Claude command lifecycle notifications silently", () => { |
| | 2291 | const harness = makeHarness(); |
| | 2292 | return Effect.gen(function* () { |
| | 2293 | const adapter = yield* ClaudeAdapter; |
| | 2294 | const sessionId = "6e81554e-5cff-4b37-8a39-f3a9051ac234"; |
| | 2295 | |
| | 2296 | yield* adapter.startSession({ |
| | 2297 | threadId: THREAD_ID, |
| | 2298 | provider: ProviderDriverKind.make("claudeAgent"), |
| | 2299 | runtimeMode: "full-access", |
| | 2300 | }); |
| | 2301 | |
| | 2302 | const readyMessage = "command lifecycle test ready"; |
| | 2303 | const readyFiber = yield* Stream.takeUntil( |
| | 2304 | adapter.streamEvents, |
| | 2305 | (event) => event.type === "runtime.warning" && event.payload.message === readyMessage, |
| | 2306 | ).pipe(Stream.runDrain, Effect.forkChild); |
| | 2307 | harness.query.emit({ |
| | 2308 | type: "system", |
| | 2309 | subtype: "notification", |
| | 2310 | key: "command-lifecycle-ready", |
| | 2311 | text: readyMessage, |
| | 2312 | priority: "high", |
| | 2313 | session_id: sessionId, |
| | 2314 | uuid: "command-lifecycle-ready", |
| | 2315 | } as unknown as SDKMessage); |
| | 2316 | yield* Fiber.join(readyFiber); |
| | 2317 | |
| | 2318 | const processedMessage = "command lifecycle messages processed"; |
| | 2319 | const runtimeEventsFiber = yield* Stream.takeUntil( |
| | 2320 | adapter.streamEvents, |
| | 2321 | (event) => event.type === "runtime.warning" && event.payload.message === processedMessage, |
| | 2322 | ).pipe(Stream.runCollect, Effect.forkChild); |
| | 2323 | for (const [state, uuid] of [ |
| | 2324 | ["started", "command-started"], |
| | 2325 | ["completed", "command-completed"], |
| | 2326 | ]) { |
| | 2327 | harness.query.emit({ |
| | 2328 | type: "command_lifecycle", |
| | 2329 | command_uuid: "4cd8e8a3-df7a-425d-b6c9-4053abc0b8fd", |
| | 2330 | state, |
| | 2331 | session_id: sessionId, |
| | 2332 | uuid, |
| | 2333 | } as unknown as SDKMessage); |
| | 2334 | } |
| | 2335 | harness.query.emit({ |
| | 2336 | type: "system", |
| | 2337 | subtype: "notification", |
| | 2338 | key: "command-lifecycle-processed", |
| | 2339 | text: processedMessage, |
| | 2340 | priority: "high", |
| | 2341 | session_id: sessionId, |
| | 2342 | uuid: "command-lifecycle-processed", |
| | 2343 | } as unknown as SDKMessage); |
| | 2344 | |
| | 2345 | const runtimeEvents = Array.from(yield* Fiber.join(runtimeEventsFiber)); |
| | 2346 | assert.deepEqual( |
| | 2347 | runtimeEvents.map((event) => event.type), |
| | 2348 | ["runtime.warning"], |
| | 2349 | ); |
| | 2350 | const warning = runtimeEvents[0]; |
| | 2351 | assert.equal(warning?.type, "runtime.warning"); |
| | 2352 | if (warning?.type === "runtime.warning") { |
| | 2353 | assert.equal(warning.payload.message, processedMessage); |
| | 2354 | } |
| | 2355 | }).pipe( |
| | 2356 | Effect.provideService(Random.Random, makeDeterministicRandomService()), |
| | 2357 | Effect.provide(harness.layer), |
| | 2358 | ); |
| | 2359 | }); |
| | 2360 | |
| 2290 | it.effect("emits thread token usage updates from Claude task progress", () => { | 2361 | it.effect("emits thread token usage updates from Claude task progress", () => { |
| 2291 | const harness = makeHarness(); | 2362 | const harness = makeHarness(); |
| 2292 | return Effect.gen(function* () { | 2363 | return Effect.gen(function* () { |