Drei vom Architekten abgenommene Tasks, gebündelt als Checkpoint: - TSK-0242: Agent-Alias-Mapping (kimi-ah → kimi kanonisiert, Rollen → preferredAgent), reopenTask räumt claimedBy ab, fsWatch reindiziert direkte Datei-Edits, work-Default 300s → 50s, task_list mit Limit. - TSK-0245: zwei Agent-Klassen (dispatch loop|architect). Watchdog mahnt architekt-getriebene Agenten nur noch EINMAL statt im Minutentakt; `task dispatch` startet sie explizit, `task record` trägt extern erledigte Arbeit mit origin=external nach. - TSK-0249: Lifecycle wird serverseitig erzwungen (open→review scheitert mit klarer Meldung), claimedBy/doneBy überleben bis done, Presence pro Agent, Review-Watchdog, GET /architect/pulse (1.4 kB statt 34 kB, since-Cursor, omitted statt stillem Abschneiden), unbekannter Agent → 400 statt 500. Alle Punkte live am laufenden Hub nachgemessen, nicht aus Agenten-Logs übernommen. Tests: 242 → 279 grün, tsc sauber. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
38 lines
1.5 KiB
TypeScript
38 lines
1.5 KiB
TypeScript
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
import { mkdtempSync, rmSync } from 'node:fs';
|
|
import { tmpdir } from 'node:os';
|
|
import { join } from 'node:path';
|
|
import { init } from '../src/cli/commands/init.js';
|
|
import { loadConfig, saveConfig } from '../src/core/config.js';
|
|
import { agentIdentity, resolveAgentName } from '../src/core/services/identityService.js';
|
|
|
|
describe('agent identity resolution', () => {
|
|
let cwd: string;
|
|
|
|
beforeEach(() => {
|
|
cwd = mkdtempSync(join(tmpdir(), 'ah-identity-'));
|
|
init(cwd, { projectName: 'identity-test', yes: true });
|
|
const config = loadConfig(cwd);
|
|
config.agents = {
|
|
claude: { role: 'architect', aliases: ['windows-claude'] },
|
|
kimi: { role: 'implementer', aliases: ['kimi-ah'] },
|
|
};
|
|
config.roles.architect.preferredAgent = 'claude';
|
|
config.roles.implementer.preferredAgent = 'kimi';
|
|
saveConfig(cwd, config);
|
|
});
|
|
|
|
afterEach(() => rmSync(cwd, { recursive: true, force: true }));
|
|
|
|
it('maps aliases and roles to the canonical roster agent', () => {
|
|
expect(resolveAgentName(cwd, 'kimi-ah')).toBe('kimi');
|
|
expect(resolveAgentName(cwd, 'implementer')).toBe('kimi');
|
|
expect(resolveAgentName(cwd, 'architect')).toBe('claude');
|
|
expect(agentIdentity(cwd, 'kimi').names).toEqual(new Set(['kimi', 'kimi-ah', 'implementer']));
|
|
});
|
|
|
|
it('rejects an unknown recipient when a roster is configured', () => {
|
|
expect(() => resolveAgentName(cwd, 'ghost-agent')).toThrow(/unknown agent, alias, or role/i);
|
|
});
|
|
});
|