/** * tool-registry 单测 */ const registry = require('../../../src/tools/devloop/tool-registry'); describe('tool-registry', () => { beforeEach(() => registry._resetForTesting()); it('loadAllTools returns a Map with unique tool names', () => { const all = registry.loadAllTools(); expect(all instanceof Map).toBe(true); expect(all.size).toBeGreaterThanOrEqual(30); for (const [name, tool] of all) { expect(typeof name).toBe('string'); expect(tool.name).toBe(name); expect(typeof tool.execute).toBe('function'); } }); it('listToolNames includes core 5 persistence tools', () => { const names = registry.listToolNames(); expect(names).toContain('write_todolist'); expect(names).toContain('update_todo_item'); expect(names).toContain('timeline_append'); expect(names).toContain('record_memory'); expect(names).toContain('update_runtime_state'); }); it('listToolNames includes PM/Architect doc tools', () => { const names = registry.listToolNames(); expect(names).toContain('write_chapter'); expect(names).toContain('write_mvcp_page'); expect(names).toContain('hash_contract'); expect(names).toContain('validate_prd_site'); }); it('listToolNames includes Coder/Tester/Integrator/Triager tools', () => { const names = registry.listToolNames(); expect(names).toContain('contract_bridge'); // coder expect(names).toContain('parse_vitest'); // tester expect(names).toContain('port_picker'); // integrator expect(names).toContain('extract_evidence'); // triager }); it('getDevLoopTools filters by toolPolicy', () => { const subset = registry.getDevLoopTools(['hash_contract', 'parse_vitest', 'nope']); expect(subset).toHaveLength(2); expect(subset.map(t => t.name).sort()).toEqual(['hash_contract', 'parse_vitest']); }); it('dispatch invokes a known tool', async () => { const r = await registry.dispatch('hash_contract', { contract: { name: 'login', method: 'POST' }, }, {}); expect(r.ok).toBe(true); expect(r.hash).toMatch(/^sha256:[a-f0-9]{16}$/); }); it('dispatch rejects unknown tool', async () => { await expect(registry.dispatch('does_not_exist', {}, {})).rejects.toThrow(/Unknown tool/); }); it('dispatch validates required fields', async () => { await expect(registry.dispatch('hash_contract', {}, {})).rejects.toThrow(/missing required field "contract"/); }); });