{"version":3,"file":"subagent-registry.test.d.ts","sourceRoot":"","sources":["../../src/core/subagent-registry.test.ts"],"names":[],"mappings":"","sourcesContent":["import { describe, expect, it } from \"vitest\";\nimport {\n\tANALYTICAL_MODEL,\n\tBUILTIN_SUBAGENT_DEFINITIONS,\n\tgetCanonicalSubagentRegistry,\n\tresolveSubagentModel,\n\tvalidateSkillAgentReferences,\n\tvalidateSubagentOutput,\n} from \"./subagent-registry.js\";\nimport {\n\tcreateSubagentContextPacket,\n\tresolveSubagentInvocation,\n\tSubagentRuntimeError,\n\tvalidateParentSubagentOutput,\n} from \"./subagent-runtime.js\";\n\ndescribe(\"canonical subagent registry\", () => {\n\tit(\"contains all advertised agents in deterministic order\", () => {\n\t\tconst registry = getCanonicalSubagentRegistry();\n\t\texpect(registry.validate().valid).toBe(true);\n\t\texpect(registry.list().map((agent) => agent.name)).toEqual([\n\t\t\t\"cavecrew-builder\",\n\t\t\t\"cavecrew-investigator\",\n\t\t\t\"cavecrew-reviewer\",\n\t\t\t\"librarian\",\n\t\t\t\"pentester\",\n\t\t\t\"planner\",\n\t\t\t\"reviewer\",\n\t\t\t\"scout\",\n\t\t\t\"security\",\n\t\t\t\"worker\",\n\t\t]);\n\t\texpect(BUILTIN_SUBAGENT_DEFINITIONS).toHaveLength(10);\n\t});\n\n\tit(\"resolves registered aliases only and rejects unknown agents without fallback\", () => {\n\t\tconst registry = getCanonicalSubagentRegistry();\n\t\tconst alias = registry.resolve(\"cavecrew-investigate\");\n\t\texpect(\"code\" in alias).toBe(false);\n\t\tconst unknown = registry.resolve(\"cavecrew-investigator-typo\");\n\t\texpect(unknown).toMatchObject({ code: \"SUBAGENT_NOT_REGISTERED\", automaticFallbackAttempted: false });\n\t\texpect((unknown as { availableAgents: string[] }).availableAgents).toContain(\"cavecrew-builder\");\n\t});\n\n\tit(\"assigns analytical and worker model policies explicitly\", () => {\n\t\tconst registry = getCanonicalSubagentRegistry();\n\t\tfor (const name of [\n\t\t\t\"librarian\",\n\t\t\t\"pentester\",\n\t\t\t\"planner\",\n\t\t\t\"reviewer\",\n\t\t\t\"scout\",\n\t\t\t\"security\",\n\t\t\t\"cavecrew-investigator\",\n\t\t\t\"cavecrew-reviewer\",\n\t\t]) {\n\t\t\tconst resolved = registry.resolve(name);\n\t\t\texpect(resolved).toMatchObject({\n\t\t\t\tmodel: { configuredProvider: \"openrouter\", configuredModel: ANALYTICAL_MODEL },\n\t\t\t});\n\t\t}\n\t\tfor (const name of [\"worker\", \"cavecrew-builder\"]) {\n\t\t\tconst resolved = registry.resolve(name);\n\t\t\texpect(resolved).toMatchObject({\n\t\t\t\tmodel: { configuredProvider: \"openrouter\", configuredModel: \"openai/gpt-5.6-luna\" },\n\t\t\t});\n\t\t}\n\t});\n\n\tit(\"enforces read-only and builder policy boundaries\", () => {\n\t\tconst registry = getCanonicalSubagentRegistry();\n\t\texpect(registry.resolve(\"cavecrew-investigator\")).toMatchObject({\n\t\t\tdefinition: { executionMode: \"observe\", deniedEffects: expect.arrayContaining([\"writesWorkspace\"]) },\n\t\t});\n\t\texpect(registry.resolve(\"cavecrew-reviewer\")).toMatchObject({\n\t\t\tdefinition: { executionMode: \"observe\", deniedEffects: expect.arrayContaining([\"writesWorkspace\"]) },\n\t\t});\n\t\texpect(registry.resolve(\"cavecrew-builder\")).toMatchObject({\n\t\t\tdefinition: {\n\t\t\t\trecursion: { maximumDepth: 0 },\n\t\t\t\tconcurrency: { maximumInstances: 1 },\n\t\t\t\tfallbackAgents: [\"worker\"],\n\t\t\t},\n\t\t});\n\t});\n\n\tit(\"strips a profile marker only at the registry boundary\", () => {\n\t\tconst definition = {\n\t\t\t...BUILTIN_SUBAGENT_DEFINITIONS.find((agent) => agent.name === \"scout\")!,\n\t\t\tmodel: `~${ANALYTICAL_MODEL}`,\n\t\t};\n\t\tconst result = resolveSubagentModel(definition);\n\t\texpect(result).toMatchObject({\n\t\t\tok: true,\n\t\t\tvalue: { resolvedModel: ANALYTICAL_MODEL, resolutionKind: \"provider_alias\" },\n\t\t});\n\t});\n\n\tit(\"validates skill references before activation\", () => {\n\t\texpect(\n\t\t\tvalidateSkillAgentReferences(\n\t\t\t\t\"cavecrew\",\n\t\t\t\t\"/skill/cavecrew/SKILL.md\",\n\t\t\t\t\"Use cavecrew-investigator, cavecrew-builder, cavecrew-reviewer.\",\n\t\t\t),\n\t\t).toEqual([]);\n\t\texpect(\n\t\t\tvalidateSkillAgentReferences(\"broken\", \"/skill/broken/SKILL.md\", \"Use cavecrew-investigator-typo.\"),\n\t\t).toMatchObject([{ missingAgent: \"cavecrew-investigator-typo\" }]);\n\t});\n\n\tit(\"requires structured output fields\", () => {\n\t\texpect(\n\t\t\tvalidateSubagentOutput(\"cavecrew-review-result-v1\", {\n\t\t\t\tverdict: \"pass\",\n\t\t\t\tfindings: [],\n\t\t\t\tmissingTests: [],\n\t\t\t\tacceptanceGaps: [],\n\t\t\t}).valid,\n\t\t).toBe(true);\n\t\texpect(validateSubagentOutput(\"cavecrew-review-result-v1\", { verdict: \"pass\" }).valid).toBe(false);\n\t});\n\n\tit(\"rejects unavailable models and does not substitute a dated model\", () => {\n\t\tconst registry = getCanonicalSubagentRegistry();\n\t\tconst result = registry.resolve(\"scout\", { availableModels: [\"deepseek/deepseek-v4-flash-0731\"] });\n\t\texpect(result).toMatchObject({ code: \"SUBAGENT_MODEL_UNAVAILABLE\", automaticFallbackAttempted: false });\n\t});\n\n\tit(\"creates an immutable isolated context packet from a resolved invocation\", () => {\n\t\tconst invocation = resolveSubagentInvocation({\n\t\t\trequestedAgent: \"cavecrew-investigator\",\n\t\t\tparentRunId: \"parent-1\",\n\t\t});\n\t\tconst packet = createSubagentContextPacket({\n\t\t\tinvocation,\n\t\t\tobjective: \"Trace dispatch\",\n\t\t\tacceptanceCriteria: [\"No mutation\"],\n\t\t\tselectedEvidenceIds: [\"ev-1\"],\n\t\t\tselectedFileReferences: [\"src/index.ts\"],\n\t\t\tconstraints: [\"No secrets\"],\n\t\t});\n\t\texpect(packet).toMatchObject({\n\t\t\tobjective: \"Trace dispatch\",\n\t\t\teffectiveExecutionMode: \"observe\",\n\t\t\trequiredOutputSchema: \"cavecrew-investigation-result-v1\",\n\t\t\tparentRunId: \"parent-1\",\n\t\t});\n\t\texpect(Object.isFrozen(packet)).toBe(true);\n\t\texpect(packet).not.toHaveProperty(\"transcript\");\n\t});\n\n\tit(\"rejects a child that exceeds parent tools or mode\", () => {\n\t\texpect(() =>\n\t\t\tresolveSubagentInvocation({\n\t\t\t\trequestedAgent: \"worker\",\n\t\t\t\tparentRunId: \"parent-1\",\n\t\t\t\tparentPolicy: { allowedTools: [\"read\"], executionMode: \"observe\" },\n\t\t\t}),\n\t\t).toThrowError(SubagentRuntimeError);\n\t});\n\n\tit(\"validates child structured output at the parent boundary\", () => {\n\t\tconst invocation = resolveSubagentInvocation({ requestedAgent: \"cavecrew-reviewer\", parentRunId: \"parent-1\" });\n\t\tconst result = validateParentSubagentOutput({\n\t\t\tinvocation,\n\t\t\trawOutput: JSON.stringify({ verdict: \"pass\", findings: [], missingTests: [], acceptanceGaps: [] }),\n\t\t});\n\t\texpect(result.value.verdict).toBe(\"pass\");\n\t\texpect(() => validateParentSubagentOutput({ invocation, rawOutput: \"arbitrary prose\" })).toThrow(\n\t\t\t\"SUBAGENT_OUTPUT_INVALID\",\n\t\t);\n\t});\n});\n"]}