Merge remote-tracking branch 'refs/remotes/upstream/main'
ci / check (macos-latest) (push) Canceled after 0s
ci / check (ubuntu-latest) (push) Canceled after 0s
ci / check (windows-latest) (push) Canceled after 0s

# Conflicts:
#	ROADMAP.md
#	TODO.md
#	src/cli.tsx
#	src/config.ts
#	src/mcp.ts
#	src/permission.ts
#	src/prompt.ts
#	src/session.ts
#	src/snapshot.ts
#	src/subagent.ts
#	src/tools-extra.ts
#	src/tools.ts
#	src/ui/App.tsx
#	test/mcp.test.ts
#	test/prune.test.ts
#	test/session.test.ts
#	test/tools.test.ts
This commit is contained in:
asepharyana
2026-09-21 20:43:35 +07:00
59 changed files with 3481 additions and 463 deletions
+26
View File
@@ -430,3 +430,29 @@ test('a background command runs, streams via the listener, and can be stopped',
const { shutdownBackgrounds } = await import('../src/tools');
await shutdownBackgrounds();
}), 30_000);
test('a skill installed mid-session is callable next turn with no rebuild', async () =>
inTempDir(async () => {
const session = new Session({
model: new MockLanguageModelV4({ doStream: async () => stream(text('done')) }) as never,
askApproval: async () => 'deny',
});
// No skills at boot: the skill tool is not offered (the fork registers it
// only when a skill exists, and an install rebuilds the tool set at the
// next turn boundary).
expect(session.tools['skill']).toBeUndefined();
// Hot-reload swaps the live list.
session.updateSkills([{ name: 'hot', description: 'installed', origin: 'registry', body: 'fresh instructions' }]);
// Rebuild happens at the turn boundary, so the tool appears next turn.
for await (const _ of session.send('hi')) void _;
const skillTool = session.tools['skill'] as {
execute: (input: { name: string }, ctx: unknown) => Promise<unknown>;
};
expect(skillTool).toBeDefined();
const out = await skillTool.execute({ name: 'hot' }, {});
expect(out).toContain('fresh instructions');
expect(out).toContain('registry');
}));