{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../../src/core/orchestration/cli.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAqB,oBAAoB,EAA6B,MAAM,YAAY,CAAC;AA4CrG,wBAAgB,uBAAuB,IAAI,MAAM,CAWhD;AACD,MAAM,WAAW,0BAA0B;IAC1C,sEAAsE;IACtE,OAAO,CAAC,EAAE,oBAAoB,CAAC;CAC/B;AACD,wBAAsB,yBAAyB,CAC9C,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,GAAE,0BAA+B,GACtC,OAAO,CAAC,OAAO,CAAC,CA+FlB","sourcesContent":["import chalk from \"chalk\";\nimport { getAgentDir } from \"../../config.js\";\nimport { defaultChildSessionDir } from \"../durable-child-session/index.js\";\nimport { createFileDurableMissionStore } from \"../mission-durable/index.js\";\nimport { OrchestratorService } from \"./orchestrator.js\";\nimport { createFileOrchestrationStore } from \"./store.js\";\nimport type { OrchestrationNode, OrchestrationPlanner, OrchestrationPlanProposal } from \"./types.js\";\n\nconst COMMANDS = new Set([\"preview\", \"start\", \"status\", \"graph\", \"join\", \"cancel\"]);\nfunction flag(args: string[], name: string): boolean {\n\treturn args.includes(name);\n}\nfunction value(args: string[], name: string): string | undefined {\n\tconst index = args.indexOf(name);\n\treturn index >= 0 ? args[index + 1] : undefined;\n}\nfunction json(valueToPrint: unknown): void {\n\tprocess.stdout.write(`${JSON.stringify(valueToPrint, null, 2)}\\n`);\n}\nfunction error(errorValue: unknown): void {\n\tconst message = errorValue instanceof Error ? errorValue.message : String(errorValue);\n\tprocess.stderr.write(`${chalk.red(message)}\\n`);\n\tprocess.exitCode = 1;\n}\nfunction buildService(options: OrchestratorCommandOptions = {}): OrchestratorService {\n\tconst missions = createFileDurableMissionStore();\n\treturn new OrchestratorService({\n\t\tstore: createFileOrchestrationStore(),\n\t\tmissions,\n\t\tsessionDir: defaultChildSessionDir(getAgentDir()),\n\t\tplanner: options.planner,\n\t});\n}\nfunction parseProposal(raw: string | undefined): OrchestrationPlanProposal {\n\tif (!raw)\n\t\treturn {\n\t\t\tdecision: \"DIRECT\",\n\t\t\trationale: \"No proposal supplied; direct execution is the safe default.\",\n\t\t\tnodes: [],\n\t\t\tedges: [],\n\t\t};\n\tconst parsed = JSON.parse(raw) as OrchestrationPlanProposal;\n\treturn {\n\t\t...parsed,\n\t\tnodes: parsed.nodes as OrchestrationNode[],\n\t\tedges: parsed.edges,\n\t\trationale: parsed.rationale,\n\t\tdecision: parsed.decision,\n\t};\n}\nexport function printOrchestrationUsage(): string {\n\treturn [\n\t\t\"  orchestrator preview <PARENT_MISSION_ID> [--proposal JSON] [--json]\",\n\t\t\"  orchestrator start <PARENT_MISSION_ID> [--proposal JSON] [--authority NAME] [--json]\",\n\t\t\"  orchestrator status <ORCHESTRATION_ID> [--json]\",\n\t\t\"  orchestrator graph <ORCHESTRATION_ID> [--json]\",\n\t\t\"  orchestrator join <ORCHESTRATION_ID> [--json]\",\n\t\t\"  orchestrator cancel <ORCHESTRATION_ID> [--json]\",\n\t\t\"  (without --proposal the automatic Qwen planner proposes the plan;\",\n\t\t\"   --proposal JSON is the explicit operator debug override)\",\n\t].join(\"\\n\");\n}\nexport interface OrchestratorCommandOptions {\n\t/** Planner for the automatic path. Default: `createQwenPlanner()`. */\n\tplanner?: OrchestrationPlanner;\n}\nexport async function handleOrchestratorCommand(\n\targs: string[],\n\toptions: OrchestratorCommandOptions = {},\n): Promise<boolean> {\n\tif (args[0] !== \"orchestrator\") return false;\n\tif (!args[1] || !COMMANDS.has(args[1])) {\n\t\tprocess.stderr.write(`${printOrchestrationUsage()}\\n`);\n\t\tprocess.exitCode = 1;\n\t\treturn true;\n\t}\n\tconst service = buildService(options);\n\tconst command = args[1];\n\tconst machine = flag(args, \"--json\");\n\ttry {\n\t\tif (command === \"preview\" || command === \"start\") {\n\t\t\tconst parentMissionId = args[2];\n\t\t\tif (!parentMissionId) throw new Error(\"orchestrator command requires <PARENT_MISSION_ID>\");\n\t\t\tconst proposalRaw = value(args, \"--proposal\");\n\t\t\tif (proposalRaw === undefined) {\n\t\t\t\t// Automatic path: the Qwen planner proposes the plan from the\n\t\t\t\t// parent mission's objective and constraints.\n\t\t\t\tif (command === \"preview\") {\n\t\t\t\t\tconst preview = await service.previewAutomatic(parentMissionId);\n\t\t\t\t\tif (machine) json(preview);\n\t\t\t\t\telse\n\t\t\t\t\t\tprocess.stdout.write(\n\t\t\t\t\t\t\t`${preview.validation.valid ? \"valid\" : \"invalid\"} ${preview.plan?.decision ?? \"-\"}\\n`,\n\t\t\t\t\t\t);\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tconst authority = value(args, \"--authority\");\n\t\t\t\tconst result = await service.startAutomatic(parentMissionId, {\n\t\t\t\t\t...(authority === undefined ? {} : { childExecutionAuthority: authority }),\n\t\t\t\t});\n\t\t\t\tif (machine) json(result);\n\t\t\t\telse\n\t\t\t\t\tprocess.stdout.write(\n\t\t\t\t\t\t`started ${result.plan.orchestrationId} materialized=${result.materializedMissionIds.length}\\n`,\n\t\t\t\t\t);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tconst proposal = parseProposal(proposalRaw);\n\t\t\tif (command === \"preview\") {\n\t\t\t\tconst preview = await service.preview({ parentMissionId, proposal });\n\t\t\t\tif (machine) json(preview);\n\t\t\t\telse\n\t\t\t\t\tprocess.stdout.write(\n\t\t\t\t\t\t`${preview.validation.valid ? \"valid\" : \"invalid\"} ${preview.plan?.decision ?? \"-\"}\\n`,\n\t\t\t\t\t);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tconst created = await service.create({ parentMissionId, proposal });\n\t\t\tconst result = await service.materializeReady(created.orchestrationId);\n\t\t\tif (machine) json(result);\n\t\t\telse\n\t\t\t\tprocess.stdout.write(\n\t\t\t\t\t`started ${created.orchestrationId} materialized=${result.materializedMissionIds.length}\\n`,\n\t\t\t\t);\n\t\t\treturn true;\n\t\t}\n\t\tconst orchestrationId = args[2];\n\t\tif (!orchestrationId) throw new Error(`${command} requires <ORCHESTRATION_ID>`);\n\t\tif (command === \"status\") {\n\t\t\tconst result = await service.status(orchestrationId);\n\t\t\tif (machine) json(result);\n\t\t\telse\n\t\t\t\tprocess.stdout.write(\n\t\t\t\t\t`${result.orchestrationId} [${result.state}] nodes=${result.nodesTotal} materialized=${result.childrenMaterialized} blocked=${result.childrenBlocked}\\n`,\n\t\t\t\t);\n\t\t\treturn true;\n\t\t}\n\t\tif (command === \"graph\") {\n\t\t\tconst result = (await service.status(orchestrationId)).graph;\n\t\t\tif (machine) json(result);\n\t\t\telse\n\t\t\t\tfor (const node of result)\n\t\t\t\t\tprocess.stdout.write(\n\t\t\t\t\t\t`${node.nodeId} [${node.status}] role=${node.role}${node.reason ? ` reason=${node.reason}` : \"\"}${node.waitingFor.length ? ` waits=${node.waitingFor.join(\",\")}` : \"\"}\\n`,\n\t\t\t\t\t);\n\t\t\treturn true;\n\t\t}\n\t\tif (command === \"join\") {\n\t\t\tconst result = await service.join(orchestrationId);\n\t\t\tif (machine) json(result);\n\t\t\telse\n\t\t\t\tprocess.stdout.write(\n\t\t\t\t\t`${result.orchestrationId} [${result.state}] terminal=${result.terminal} completed=${result.completedNodeIds.length}\\n`,\n\t\t\t\t);\n\t\t\treturn true;\n\t\t}\n\t\tconst result = await service.cancel(orchestrationId);\n\t\tif (machine) json(result);\n\t\telse process.stdout.write(`${result.orchestrationId} [${result.state}] cancelled\\n`);\n\t\treturn true;\n\t} catch (caught) {\n\t\terror(caught);\n\t\treturn true;\n\t}\n}\n"]}