diff --git a/packages/fs/tool-str-replace-editor/tests/tools.spec.ts b/packages/fs/tool-str-replace-editor/tests/tools.spec.ts index 64bdd481ee..f1fafcfa04 100644 --- a/packages/fs/tool-str-replace-editor/tests/tools.spec.ts +++ b/packages/fs/tool-str-replace-editor/tests/tools.spec.ts @@ -78,13 +78,13 @@ async function setup( await ctx.plugin(SandboxedFileSystem, { cwd: root }) } if (options.fsPolicy === true) await ctx.plugin(FsPolicy) - await ctx.plugin(ToolStrReplaceEditor, config) - return { ctx, root, owner: agent(ctx, root) } + const fiber = await ctx.plugin(ToolStrReplaceEditor, config) + return { ctx, root, fiber, owner: agent(ctx, root) } } describe('tool-str-replace-editor', () => { it('registers the standalone schema and configurable description', async () => { - const { ctx } = await setup({ description: 'custom editor description' }) + const { ctx, fiber } = await setup({ description: 'custom editor description' }) const schema = ctx.tools.schemas()[0] expect(ctx.tools.schemas().map(item => item.name)).toEqual(['str_replace_editor']) expect(schema?.description).toBe('custom editor description') @@ -147,6 +147,10 @@ describe('tool-str-replace-editor', () => { })).toMatchObject({ locations: [{ path: '/workspace/a.txt' }], }) + + await fiber.dispose() + expect(ctx.tools.schemas()).toEqual([]) + expect(ctx.tools.get('str_replace_editor')).toBeUndefined() }) it('creates, views, replaces, and inserts with the canonical model-facing output', async () => { diff --git a/packages/pty/tool-bash-persistent/src/invariant.ts b/packages/pty/tool-bash-persistent/src/invariant.ts index f6b5acfbc7..5e276d4c45 100644 --- a/packages/pty/tool-bash-persistent/src/invariant.ts +++ b/packages/pty/tool-bash-persistent/src/invariant.ts @@ -15,8 +15,9 @@ export const name = 'tool-bash-persistent-invariant' export const inject = ['invariants'] /** - * No runtime invariant: the tool adapter owns no independent durable state; - * PTY ownership and filesystem mutation relations stay with their services. + * No runtime invariant: the adapter's private owner-to-shell cache has no + * observable event or data relation. Lifecycle tests prove its cleanup without + * adding a public surface solely for an invariant. */ const install: InvariantInstaller = () => {} diff --git a/packages/pty/tool-bash-persistent/tests/tools.spec.ts b/packages/pty/tool-bash-persistent/tests/tools.spec.ts index 81a4f28b87..1a9d15c476 100644 --- a/packages/pty/tool-bash-persistent/tests/tools.spec.ts +++ b/packages/pty/tool-bash-persistent/tests/tools.spec.ts @@ -260,7 +260,7 @@ async function setup( describe('tool-bash-persistent', () => { it('registers a configurable schema and reuses one owner shell', async () => { - const { ctx, owner, stub } = await setup({ + const { ctx, owner, stub, fiber } = await setup({ backendType: 'stub', description: 'deployment-specific persistent shell', }) @@ -282,6 +282,10 @@ describe('tool-bash-persistent', () => { const ownerWithoutCwd = agent(ctx, undefined) expect(text(await call(ctx, ownerWithoutCwd, 'pwd'))).toBe('hello from stub') expect(stub.sessions).toHaveLength(2) + + await fiber.dispose() + expect(ctx.tools.schemas()).toEqual([]) + expect(ctx.tools.get('bash')).toBeUndefined() }) it('handles inferred idle, prompt fallback, shell exit, clipping, and cleanup', async () => {