@oxgeneral/orch 1.0.2 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/App-SSYYVFGW.js +22 -0
- package/dist/agent-Q34L27AY.js +9 -0
- package/dist/agent-shop-D2RS4BZK.js +2 -0
- package/dist/chunk-4MMHVHA6.js +112 -0
- package/dist/chunk-64WUDYEM.js +6 -0
- package/dist/chunk-6MJ7V6VY.js +2 -0
- package/dist/{chunk-DAVHOWGD.js → chunk-BCPUTULS.js} +16 -188
- package/dist/{chunk-INZ4O2RI.js → chunk-BSJVYRI3.js} +5 -2
- package/dist/chunk-BSJVYRI3.js.map +1 -0
- package/dist/chunk-CDFA4IIQ.js +2 -0
- package/dist/chunk-CHRW4CLD.js +2 -0
- package/dist/chunk-HMMPM7MF.js +3 -0
- package/dist/chunk-HXOMNULD.js +2 -0
- package/dist/chunk-IKNBPOQL.js +2 -0
- package/dist/chunk-KFQTWMZI.js +3 -0
- package/dist/chunk-LXNRCJ22.js +2 -0
- package/dist/{chunk-C6XZ3FJT.js → chunk-MOWC2CHX.js} +7 -4
- package/dist/chunk-MOWC2CHX.js.map +1 -0
- package/dist/chunk-P4JTJBWO.js +2 -0
- package/dist/chunk-PJ5DKXGR.js +2 -0
- package/dist/chunk-QNZ6D63E.js +4 -0
- package/dist/chunk-RHFRHCN5.js +16 -0
- package/dist/chunk-RHFRHCN5.js.map +1 -0
- package/dist/chunk-TPTHLFOB.js +2 -0
- package/dist/chunk-UMZEA3JT.js +5 -0
- package/dist/chunk-X54D5JZG.js +11 -0
- package/dist/{chunk-O2OQCSBL.js → chunk-YHIYJ5OL.js} +105 -29
- package/dist/chunk-YHIYJ5OL.js.map +1 -0
- package/dist/{claude-WUJU5KIE.js → claude-4R6L6BWY.js} +4 -4
- package/dist/{claude-WUJU5KIE.js.map → claude-4R6L6BWY.js.map} +1 -1
- package/dist/claude-ZLVOLRUG.js +2 -0
- package/dist/cli.js +1 -213
- package/dist/clipboard-service-WVON5ZN4.js +25 -0
- package/dist/{codex-NYJWEPRQ.js → codex-IMOW5ZUZ.js} +4 -4
- package/dist/{codex-NYJWEPRQ.js.map → codex-IMOW5ZUZ.js.map} +1 -1
- package/dist/codex-YRSODLH4.js +2 -0
- package/dist/config-OOB7QEKM.js +2 -0
- package/dist/container-FJI7RN2L.js +4 -0
- package/dist/context-FXRERFSP.js +7 -0
- package/dist/cursor-2HILMNM3.js +2 -0
- package/dist/{cursor-3YHVD4NP.js → cursor-NHV7X3WG.js} +4 -4
- package/dist/{cursor-3YHVD4NP.js.map → cursor-NHV7X3WG.js.map} +1 -1
- package/dist/doctor-GKTV4YYD.js +2 -0
- package/dist/doctor-service-PB7YBH3F.js +2 -0
- package/dist/editor-7IFRWVTL.js +8 -0
- package/dist/goal-RNNZYMNR.js +8 -0
- package/dist/index.d.ts +26 -8
- package/dist/index.js +247 -75
- package/dist/index.js.map +1 -1
- package/dist/init-56QC5QVX.js +53 -0
- package/dist/logs-4ISTWUWV.js +12 -0
- package/dist/msg-4ELI7Q52.js +9 -0
- package/dist/opencode-3S4VDXRG.js +2 -0
- package/dist/{opencode-FAMPSA6X.js → opencode-ULT6DYCT.js} +6 -5
- package/dist/opencode-ULT6DYCT.js.map +1 -0
- package/dist/orchestrator-PM4BW7W5.js +13 -0
- package/dist/orchestrator-QFNYZ6AH.js +6 -0
- package/dist/{orchestrator-X2CWGFCL.js.map → orchestrator-QFNYZ6AH.js.map} +1 -1
- package/dist/org-WAK3CDPG.js +3 -0
- package/dist/process-manager-33H27MQF.js +2 -0
- package/dist/registry-BO2PPRNG.js +2 -0
- package/dist/run-NE5E4JPW.js +3 -0
- package/dist/shell-OBHIVC2H.js +2 -0
- package/dist/{shell-NJNW3O6K.js → shell-UXEJRK3D.js} +4 -4
- package/dist/{shell-NJNW3O6K.js.map → shell-UXEJRK3D.js.map} +1 -1
- package/dist/shop-picker-LE3SKFOX.js +5 -0
- package/dist/status-NYHZ7Q5G.js +2 -0
- package/dist/task-SZBYNAZP.js +20 -0
- package/dist/team-VCJSUDWX.js +4 -0
- package/dist/template-engine-42PKL5KD.js +2 -0
- package/dist/tui-4VRDSRVB.js +2 -0
- package/dist/update-FFKCOV63.js +2 -0
- package/dist/update-check-HGMBDYHL.js +2 -0
- package/dist/{workspace-manager-2SFPKPLZ.js → workspace-manager-ABXFBL2A.js} +3 -3
- package/dist/{workspace-manager-2SFPKPLZ.js.map → workspace-manager-ABXFBL2A.js.map} +1 -1
- package/dist/workspace-manager-Q6WWXSTR.js +3 -0
- package/package.json +1 -1
- package/dist/App-YQOT4LBE.js +0 -6727
- package/dist/agent-7ZJ3ZDJ7.js +0 -183
- package/dist/agent-shop-YN2BSLHM.js +0 -2
- package/dist/chunk-2C2TFQ7K.js +0 -136
- package/dist/chunk-45K2XID7.js +0 -29
- package/dist/chunk-4IFIOMCW.js +0 -86
- package/dist/chunk-7X2GI5OV.js +0 -181
- package/dist/chunk-C6XZ3FJT.js.map +0 -1
- package/dist/chunk-CHIP7O6V.js +0 -83
- package/dist/chunk-FRTKB575.js +0 -87
- package/dist/chunk-HXYAZGLP.js +0 -15
- package/dist/chunk-I3SMISEF.js +0 -29
- package/dist/chunk-INZ4O2RI.js.map +0 -1
- package/dist/chunk-ITLJKMTP.js +0 -297
- package/dist/chunk-K6DMQERQ.js +0 -89
- package/dist/chunk-MGGSRXWJ.js +0 -69
- package/dist/chunk-O2OQCSBL.js.map +0 -1
- package/dist/chunk-P6ATSXGL.js +0 -107
- package/dist/chunk-PNE6LQRF.js +0 -5
- package/dist/chunk-U2VDNUZL.js +0 -52
- package/dist/chunk-VXS2CJFH.js +0 -273
- package/dist/chunk-XDVMX2FO.js +0 -8
- package/dist/chunk-XDVMX2FO.js.map +0 -1
- package/dist/chunk-XJTJ2TJV.js +0 -221
- package/dist/claude-ZUEKJJ4X.js +0 -5
- package/dist/clipboard-service-RTDUUQQU.js +0 -200
- package/dist/codex-7IXXXG5U.js +0 -123
- package/dist/config-OTAVSMOD.js +0 -75
- package/dist/container-IZZVO4AH.js +0 -1596
- package/dist/context-OL4BVUV5.js +0 -83
- package/dist/cursor-622RBRHH.js +0 -97
- package/dist/doctor-SETNAS4S.js +0 -67
- package/dist/doctor-service-TPOMFAIG.js +0 -2
- package/dist/goal-C6YGSX5D.js +0 -143
- package/dist/init-SWAAXP5H.js +0 -199
- package/dist/logs-PHPYWQ6I.js +0 -207
- package/dist/msg-FUWWLEKM.js +0 -95
- package/dist/opencode-FAMPSA6X.js.map +0 -1
- package/dist/opencode-WOR53TSC.js +0 -98
- package/dist/orchestrator-O6MFMATT.js +0 -1448
- package/dist/orchestrator-X2CWGFCL.js +0 -5
- package/dist/org-JSMMBZHI.js +0 -249
- package/dist/process-manager-HUVNAPQV.js +0 -2
- package/dist/registry-PQWRVNF2.js +0 -2
- package/dist/run-N72G5V2H.js +0 -95
- package/dist/shell-DVFHHYAZ.js +0 -5
- package/dist/shop-picker-2HY67UWP.js +0 -79
- package/dist/status-RZWN2C6C.js +0 -56
- package/dist/task-XNYZHPCS.js +0 -221
- package/dist/team-PFLP4PPL.js +0 -97
- package/dist/template-engine-AWIS56BL.js +0 -3
- package/dist/tui-JW3DOOKH.js +0 -245
- package/dist/update-YLP7FPNY.js +0 -64
- package/dist/update-check-4YKLGBFB.js +0 -2
- package/dist/workspace-manager-ESPU7WOH.js +0 -215
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {f}from'./chunk-4MMHVHA6.js';import {a}from'./chunk-PJ5DKXGR.js';import'./chunk-CHRW4CLD.js';import {m,j,i,c as c$1,a as a$1}from'./chunk-X54D5JZG.js';import {k,j as j$1,q}from'./chunk-64WUDYEM.js';import'./chunk-IKNBPOQL.js';import A from'path';import k$1 from'fs/promises';import {execFile}from'child_process';import {promisify}from'util';var x=`Agent architect \u2014 designs and creates AI agents for the orchestrator via \`orch agent add\`.
|
|
3
|
+
|
|
4
|
+
## CREATION PROCESS
|
|
5
|
+
|
|
6
|
+
1) ANALYZE \u2014 determine: agent function, required skills, adapter, team interactions.
|
|
7
|
+
|
|
8
|
+
2) WRITE THE ROLE \u2014 this is the most important part. A good role includes:
|
|
9
|
+
- Identity and specialization (who you are)
|
|
10
|
+
- Concrete workflow (numbered steps)
|
|
11
|
+
- Which skills to invoke (\`/skill-name\`)
|
|
12
|
+
- Rules and constraints
|
|
13
|
+
Do NOT include CLI documentation or goal-mode instructions \u2014 these are already injected by the system prompt template.
|
|
14
|
+
|
|
15
|
+
3) CHOOSE CONFIGURATION:
|
|
16
|
+
- adapter: \`claude\` (AI tasks), \`shell\` (bash scripts), \`codex\` (OpenAI Codex), \`cursor\` (Cursor IDE), \`opencode\` (OpenCode \u2014 multi-provider)
|
|
17
|
+
- model: \`claude-opus-4-6\` (complex/architectural), \`claude-sonnet-4-6\` (fast/routine), \`claude-haiku-4-5-20251001\` (simple/templated)
|
|
18
|
+
- approval_policy: \`auto\` (no confirmation) / \`suggest\` (proposes actions) / \`manual\` (human approval)
|
|
19
|
+
- max_turns: 50 (default), up to 100 for complex tasks
|
|
20
|
+
|
|
21
|
+
4) CREATE:
|
|
22
|
+
\`orch agent add "<name>" --adapter claude --model <model> --skills "<skills>" --role "<role>" --approval-policy auto\`
|
|
23
|
+
|
|
24
|
+
## AVAILABLE SKILLS
|
|
25
|
+
|
|
26
|
+
Development: feature-dev:feature-dev, feature-dev:code-explorer, feature-dev:code-architect, feature-dev:code-reviewer, simplify, claude-api
|
|
27
|
+
Testing: testing-suite:generate-tests, testing-suite:test-coverage, testing-suite:e2e-setup, testing-suite:test-quality-analyzer
|
|
28
|
+
Frontend: frontend-design, document-skills:frontend-design
|
|
29
|
+
Documents: pdf, xlsx, docx, pptx
|
|
30
|
+
Marketing: marketing-psychology, product-manager-toolkit
|
|
31
|
+
|
|
32
|
+
## ANTI-PATTERNS
|
|
33
|
+
|
|
34
|
+
- Never create agents without skills \u2014 they cannot be auto-matched to tasks.
|
|
35
|
+
- Never write generic roles like "helper" \u2014 be specific about actions and tools.
|
|
36
|
+
- Never use opus for simple tasks \u2014 it is expensive; use sonnet or haiku.
|
|
37
|
+
- Never assign more than 3-4 skills per agent \u2014 create specialized agents instead.
|
|
38
|
+
- Never use the -e/--edit flag in automated mode \u2014 it opens an interactive editor.
|
|
39
|
+
- Always specify --role when calling \`orch agent add\`.
|
|
40
|
+
|
|
41
|
+
After creation \u2014 \`orch context set agent-<name> "<capabilities>"\`.`;function w(){return [{id:"agt_creator",name:"Agent Creator",adapter:"claude",role:x,config:{model:"claude-sonnet-4-6",approval_policy:"suggest",max_turns:50,timeout_ms:36e5,stall_timeout_ms:3e5,skills:["document-skills:skill-creator"]},status:"idle",stats:{tasks_completed:0,tasks_failed:0,total_runs:0,total_runtime_ms:0}}]}var c=promisify(execFile);async function P(t={}){let o=process.cwd(),e=new m(o);if(await j(e.root)){k("Already initialized");return}await Promise.all([i(e.tasksDir),i(e.agentsDir),i(e.goalsDir),i(e.runsDir),i(e.templatesDir),i(e.logsDir)]);let l=await I(o),i$1=structuredClone(a);i$1.project.name=t.name??A.basename(o),l||(i$1.defaults.agent.workspace_mode="shared");let v=["# Runtime state","state.json","*.lock","","# Logs and runs","runs/","logs/","","# Agent workspaces","workspaces/"].join(`
|
|
42
|
+
`)+`
|
|
43
|
+
`,_=[".orchestry","node_modules",".env",".env.*","dist","build",".next","__pycache__","*.pyc",".venv"].join(`
|
|
44
|
+
`)+`
|
|
45
|
+
`,m$1=w();await Promise.all([c$1(e.configPath,i$1),a$1(e.gitignorePath,v),a$1(e.workspaceExcludePath,_),a$1(e.defaultTemplatePath(),f),...m$1.map(s=>c$1(e.agentPath(s.id),s))]),await D(o),l&&await T(o),console.log(),j$1("initialized"),console.log(),console.log(` Created ${q(".orchestry/")}`),console.log(` ${q("\u251C\u2500\u2500")} config.yml`),console.log(` ${q("\u251C\u2500\u2500")} tasks/`),console.log(` ${q("\u251C\u2500\u2500")} agents/`);for(let s of m$1)console.log(` ${q("\u2502 \u2514\u2500\u2500")} ${s.id}.yml ${q(`(${s.name})`)}`);console.log(` ${q("\u251C\u2500\u2500")} templates/default.md`),console.log(` ${q("\u2514\u2500\u2500")} .gitignore`),console.log();}async function I(t){try{return await c("git",["rev-parse","--is-inside-work-tree"],{cwd:t}),!0}catch{try{return await c("git",["init"],{cwd:t}),!0}catch{return false}}}async function T(t){try{await c("git",["rev-parse","HEAD"],{cwd:t});}catch{try{await c("git",["add","-A"],{cwd:t}),await c("git",["commit","-m","Initial commit","--allow-empty"],{cwd:t});}catch{}}}async function D(t){let o=A.join(t,".gitignore");try{let e=await k$1.readFile(o,"utf-8");if(e.split(`
|
|
46
|
+
`).some(i=>i.trim()===".orchestry"))return;let l=e.endsWith(`
|
|
47
|
+
`)?"":`
|
|
48
|
+
`;await k$1.appendFile(o,`${l}
|
|
49
|
+
# Orchestry state
|
|
50
|
+
.orchestry
|
|
51
|
+
`);}catch{await a$1(o,`# Orchestry state
|
|
52
|
+
.orchestry
|
|
53
|
+
`);}}function H(t){t.command("init").description("Initialize .orchestry/ in the current directory").option("--name <name>","Project name").action(async o=>{await P(o),console.log(` Next: ${q('orch task add "Create backend agent" --assignee agt_creator')}`),console.log();});}export{H as registerInitCommand,P as runInit};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {i,q,c}from'./chunk-64WUDYEM.js';import {c as c$1}from'./chunk-IKNBPOQL.js';function k(e,o){e.command("logs [run-id]").description("View run logs").option("--agent <agent-id>","Filter by agent").option("--task <task-id>","Filter by task").option("--follow","Live stream").option("--since <duration>","Filter by time (e.g. 5m, 1h)").action(async(s,t)=>{let i$1=t.since?y(t.since):void 0;t.follow?await v(o,{runId:s,taskId:t.task,agentId:t.agent}):s?await h(o,s,i$1):t.task?await w(o,t.task,i$1):t.agent?await p(o,t.agent,i$1):(i("Specify a run ID, --task, or --agent"),process.exit(2));});}function u(e){let o=new Date(e.timestamp).toLocaleTimeString("en-US",{hour12:false,hour:"2-digit",minute:"2-digit",second:"2-digit"}),s=e.type==="error"?c("failed"):c("agentAction"),t=typeof e.data=="string"?e.data:JSON.stringify(e.data);return ` ${q(o)} ${s} ${t.slice(0,80)}`}function f(e,o){if(!o)return e;let s=Date.now()-o;return e.filter(t=>new Date(t.timestamp).getTime()>=s)}async function h(e,o,s){let t=s?f(await e.runService.readEventsTail(o,500),s):await e.runService.readEventsTail(o,50);if(e.context.json){console.log(JSON.stringify(t,null,2));return}if(t.length===0){console.log(`
|
|
3
|
+
No events for run ${o}
|
|
4
|
+
`);return}console.log();for(let i of t)console.log(u(i));console.log();}async function w(e,o,s){let t=await e.runService.listForTask(o);if(e.context.json){console.log(JSON.stringify(t,null,2));return}if(t.length===0){console.log(`
|
|
5
|
+
No runs for task ${o}
|
|
6
|
+
`);return}let i=s?t.slice(-20):t,g=await Promise.all(i.map(n=>s?e.runService.readEventsTail(n.id,500).then(r=>f(r,s)):e.runService.readEventsTail(n.id,10)));for(let n=0;n<i.length;n++){let r=i[n],l=g[n];console.log(`
|
|
7
|
+
Run ${r.id} \xB7 attempt ${r.attempt} \xB7 ${r.status}`);for(let d of l.slice(-10))console.log(u(d));}console.log();}async function p(e,o,s){let t=await e.runService.listForAgent(o);if(e.context.json){console.log(JSON.stringify(t,null,2));return}if(t.length===0){console.log(`
|
|
8
|
+
No runs for agent ${o}
|
|
9
|
+
`);return}let i=t.slice(-5),g=await Promise.all(i.map(n=>s?e.runService.readEventsTail(n.id,500).then(r=>f(r,s)):e.runService.readEventsTail(n.id,5)));for(let n=0;n<i.length;n++){let r=i[n],l=g[n];console.log(`
|
|
10
|
+
Run ${r.id} \xB7 task ${r.task_id} \xB7 ${r.status}`);for(let d of l.slice(-5))console.log(u(d));}console.log();}async function v(e,o){let s=new Set,t=new Set;if(o.runId&&s.add(o.runId),o.taskId){let n=await e.runService.listForTask(o.taskId);for(let r of n)s.add(r.id);}o.agentId&&t.add(o.agentId);let i=s.size>0||t.size>0;console.log(`
|
|
11
|
+
${q("Following live events...")} ${q("(Ctrl+C to stop)")}
|
|
12
|
+
`);let g=e.eventBus.onAny(n=>{let r=new Date().toLocaleTimeString("en-US",{hour12:false,hour:"2-digit",minute:"2-digit",second:"2-digit"});if(i){if("runId"in n&&s.size>0&&!s.has(n.runId))return;if("agentId"in n&&t.size>0){let l=n;if(!t.has(l.agentId))return}}switch(n.type){case "agent:output":{let l=typeof n.data=="string"?n.data.slice(0,80):"";console.log(` ${q(r)} ${c("agentAction")} ${l}`);break}case "agent:file_changed":console.log(` ${q(r)} ${c("agentAction")} Modified ${n.path}`);break;case "agent:error":console.log(` ${q(r)} ${c("failed")} ${n.error}`);break;case "agent:started":console.log(` ${q(r)} ${c("orchestratorEvent")} Started ${n.runId} (agent: ${n.agentId})`);break;case "agent:completed":n.success?console.log(` ${q(r)} ${c("done")} DONE ${n.runId}`):console.log(` ${q(r)} ${c("failed")} FAIL ${n.runId}`);break;case "run:retry":console.log(` ${q(r)} ${c("retrying")} RETRY attempt ${n.attempt} \xB7 next in ${Math.round(n.delay_ms/1e3)}s`);break;case "orchestrator:stall_detected":console.log(` ${q(r)} ${c("warning")} STALL ${n.runId}`);break}});await new Promise(n=>{let r=()=>{g(),n();};process.once("SIGINT",r),process.once("SIGTERM",r);});}function y(e){let o=e.match(/^(\d+)(s|m|h|d)$/);if(!o)throw new c$1(`Invalid duration: "${e}". Use format: 5m, 1h, 30s, 1d`);let s=parseInt(o[1],10);switch(o[2]){case "s":return s*1e3;case "m":return s*6e4;case "h":return s*36e5;case "d":return s*864e5;default:return s*6e4}}export{k as registerLogsCommand};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {j,q,g,l}from'./chunk-64WUDYEM.js';function f(r,n){let a=r.command("msg").description("Inter-agent messaging");a.command("send <to-agent-id> <body>").description("Send a direct message to an agent").option("-s, --subject <subject>","Message subject").option("--from <agent-id>","Sender agent ID (default: cli)").option("--ttl <ms>","TTL in milliseconds").option("--reply-to <msg-id>","Reply to a message").action(async(s,e,t)=>{let o=await n.messageService.send({channel:"direct",from_agent_id:t.from??"cli",to_agent_id:s,subject:t.subject??"",body:e,ttl_ms:t.ttl?parseInt(t.ttl,10):void 0,reply_to:t.replyTo});n.context.json?console.log(JSON.stringify(o,null,2)):n.context.quiet?console.log(o[0]?.id):j(`Message sent: ${o[0]?.id} \u2192 ${s}`);}),a.command("broadcast <body>").description("Broadcast a message to all agents (or team members)").option("-s, --subject <subject>","Message subject").option("--from <agent-id>","Sender agent ID (default: cli)").option("--team <team-id>","Limit broadcast to team members").option("--ttl <ms>","TTL in milliseconds").action(async(s,e)=>{let t=await n.messageService.send({channel:"broadcast",from_agent_id:e.from??"cli",subject:e.subject??"",body:s,ttl_ms:e.ttl?parseInt(e.ttl,10):void 0,team_id:e.team});n.context.json?console.log(JSON.stringify(t,null,2)):n.context.quiet?console.log(t.map(o=>o.id).join(`
|
|
3
|
+
`)):j(`Broadcast sent to ${t.length} agent(s)`);}),a.command("inbox <agent-id>").description("Show pending messages for an agent").action(async s=>{let e=await n.messageService.listPendingForAgent(s);if(n.context.json){console.log(JSON.stringify(e,null,2));return}if(e.length===0){console.log(q(`
|
|
4
|
+
No pending messages.
|
|
5
|
+
`));return}console.log();for(let t of e)console.log(` ${q(t.id)} from ${t.from_agent_id}${t.subject?` \u2014 ${t.subject}`:""}`),console.log(` ${t.body}`),console.log();}),a.command("list").description("List all messages").option("--agent <agent-id>","Filter by agent (sent or received)").action(async s=>{let e;if(s.agent?e=await n.messageService.listForAgent(s.agent):e=await n.messageService.listAll(),n.context.json){console.log(JSON.stringify(e,null,2));return}if(e.length===0){console.log(q(`
|
|
6
|
+
No messages.
|
|
7
|
+
`));return}let t=["ID","FROM","TO","CHANNEL","STATUS","SENT"],o=e.map(i=>[i.id,i.from_agent_id,i.to_agent_id??"*",i.channel,i.status,g(i.created_at)]);console.log(),l(t,o),console.log(`
|
|
8
|
+
${e.length} message(s)
|
|
9
|
+
`);});}export{f as registerMsgCommand};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {a,c}from'./chunk-QNZ6D63E.js';import {a as a$1}from'./chunk-P4JTJBWO.js';import {n}from'./chunk-IKNBPOQL.js';import'./chunk-6MJ7V6VY.js';import {execFile}from'child_process';import {promisify}from'util';var f=promisify(execFile),d=class{constructor(e){this.processManager=e;}kind="opencode";async test(){try{let{stdout:e}=await f("opencode",["--version"]);return {ok:!0,version:e.trim()}}catch(e){let r=e instanceof Error?e.message:String(e);return {ok:false,error:"OpenCode CLI not found. Install: npm i -g opencode",errorKind:n(r)}}}execute(e){let r=["run","--format","json"];e.config.model&&r.push("--model",e.config.model);let a$1=a(e.systemPrompt,e.prompt);r.push(a$1);let{process:t,pid:n}=this.processManager.spawn("opencode",r,{cwd:e.workspace,env:{...process.env,...e.env},signal:e.signal}),s=c(t,y,"OpenCode",e.signal);return {pid:n,events:s}}async stop(e){await this.processManager.killWithGrace(e);}};function y(o){if(!o.trim())return null;try{let e=JSON.parse(o),r=new Date().toISOString(),a=e.type??"",t=e.part??{};switch(a){case "step_start":return null;case "text":return {type:"output",timestamp:r,data:t.text??t};case "tool_use":{let n$1=t.state??{};if(n$1.status==="error"){let s=typeof n$1.error=="string"?n$1.error:JSON.stringify(n$1);return {type:"error",timestamp:r,data:n$1,errorKind:n(s)}}return {type:"tool_call",timestamp:r,data:{name:t.tool,input:n$1.input}}}case "step_finish":{let n$1=t.reason,s=k(t);if(n$1==="error"){let g=typeof t.error=="string"?t.error:JSON.stringify(t);return {type:"error",timestamp:r,data:t,tokens:s,errorKind:n(g)}}return n$1==="tool-calls"?null:{type:"done",timestamp:r,data:t,tokens:s}}default:return {type:"output",timestamp:r,data:e}}}catch{return {type:"output",timestamp:new Date().toISOString(),data:o}}}function k(o){let e=o.tokens;if(!e||typeof e.input!="number")return;let r=e.input,a=typeof e.output=="number"?e.output:0,t=typeof e.reasoning=="number"?e.reasoning:0;return a$1(r,a,{reasoning:t})}export{d as OpenCodeAdapter};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { buildFullPrompt, createStreamingEvents } from './chunk-
|
|
2
|
-
import { createTokenUsage } from './chunk-
|
|
1
|
+
import { buildFullPrompt, createStreamingEvents } from './chunk-MOWC2CHX.js';
|
|
2
|
+
import { createTokenUsage } from './chunk-RHFRHCN5.js';
|
|
3
3
|
import { classifyAdapterError } from './chunk-NLQAJ7TW.js';
|
|
4
4
|
import './chunk-O2MSGW3V.js';
|
|
5
5
|
import { execFile } from 'child_process';
|
|
@@ -92,9 +92,10 @@ function extractOpenCodeTokens(part) {
|
|
|
92
92
|
if (!tokens || typeof tokens.input !== "number") return void 0;
|
|
93
93
|
const input = tokens.input;
|
|
94
94
|
const output = typeof tokens.output === "number" ? tokens.output : 0;
|
|
95
|
-
|
|
95
|
+
const reasoning = typeof tokens.reasoning === "number" ? tokens.reasoning : 0;
|
|
96
|
+
return createTokenUsage(input, output, { reasoning });
|
|
96
97
|
}
|
|
97
98
|
|
|
98
99
|
export { OpenCodeAdapter };
|
|
99
|
-
//# sourceMappingURL=opencode-
|
|
100
|
-
//# sourceMappingURL=opencode-
|
|
100
|
+
//# sourceMappingURL=opencode-ULT6DYCT.js.map
|
|
101
|
+
//# sourceMappingURL=opencode-ULT6DYCT.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/infrastructure/adapters/opencode.ts"],"names":[],"mappings":"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","file":"opencode-ULT6DYCT.js","sourcesContent":["/**\n * OpenCode adapter.\n *\n * Spawns `opencode run --format json` in headless mode.\n * Parses JSONL events from stdout into AgentEvent stream.\n */\n\nimport type { IAgentAdapter, AdapterTestResult, ExecuteParams, AgentEvent, ExecuteHandle } from './interface.js';\nimport type { IProcessManager } from '../process/process-manager.js';\nimport { createStreamingEvents, buildFullPrompt } from './utils.js';\nimport { classifyAdapterError } from '../../domain/errors.js';\nimport { createTokenUsage } from '../../domain/run.js';\nimport { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\n\nconst execFileAsync = promisify(execFile);\n\nexport class OpenCodeAdapter implements IAgentAdapter {\n readonly kind = 'opencode';\n\n constructor(private readonly processManager: IProcessManager) {}\n\n async test(): Promise<AdapterTestResult> {\n try {\n const { stdout } = await execFileAsync('opencode', ['--version']);\n return { ok: true, version: stdout.trim() };\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return {\n ok: false,\n error: 'OpenCode CLI not found. Install: npm i -g opencode',\n errorKind: classifyAdapterError(msg),\n };\n }\n }\n\n execute(params: ExecuteParams): ExecuteHandle {\n const args = [\n 'run',\n '--format', 'json',\n ];\n\n if (params.config.model) {\n args.push('--model', params.config.model);\n }\n\n // OpenCode has no native --system-prompt; prepend to user prompt\n const fullPrompt = buildFullPrompt(params.systemPrompt, params.prompt);\n args.push(fullPrompt);\n\n const { process: proc, pid } = this.processManager.spawn('opencode', args, {\n cwd: params.workspace,\n env: { ...process.env, ...params.env },\n signal: params.signal,\n });\n\n const events = createStreamingEvents(proc, parseOpenCodeEvent, 'OpenCode', params.signal);\n\n return { pid, events };\n }\n\n async stop(pid: number): Promise<void> {\n await this.processManager.killWithGrace(pid);\n }\n}\n\nfunction parseOpenCodeEvent(line: string): AgentEvent | null {\n if (!line.trim()) return null;\n\n try {\n const parsed: Record<string, unknown> = JSON.parse(line);\n const timestamp = new Date().toISOString();\n const type = (parsed.type as string) ?? '';\n const part = (parsed.part as Record<string, unknown>) ?? {};\n\n switch (type) {\n case 'step_start':\n return null; // lifecycle event — no user-visible content\n\n case 'text':\n return { type: 'output', timestamp, data: part.text ?? part };\n\n case 'tool_use': {\n const state = (part.state as Record<string, unknown>) ?? {};\n if (state.status === 'error') {\n const errMsg = typeof state.error === 'string' ? state.error : JSON.stringify(state);\n return { type: 'error', timestamp, data: state, errorKind: classifyAdapterError(errMsg) };\n }\n // Map to { name, input } shape expected by TUI formatToolInput\n return { type: 'tool_call', timestamp, data: { name: part.tool, input: state.input } };\n }\n\n case 'step_finish': {\n const reason = part.reason as string | undefined;\n const tokens = extractOpenCodeTokens(part);\n\n if (reason === 'error') {\n const errMsg = typeof part.error === 'string' ? part.error : JSON.stringify(part);\n return { type: 'error', timestamp, data: part, tokens, errorKind: classifyAdapterError(errMsg) };\n }\n if (reason === 'tool-calls') {\n return null; // intermediate lifecycle — tool_use events carry the actual content\n }\n // reason === 'stop', 'max_tokens', or any other terminal reason → done\n return { type: 'done', timestamp, data: part, tokens };\n }\n\n default:\n return { type: 'output', timestamp, data: parsed };\n }\n } catch {\n return { type: 'output', timestamp: new Date().toISOString(), data: line };\n }\n}\n\n/** Extract token usage from opencode step_finish part. */\nfunction extractOpenCodeTokens(part: Record<string, unknown>): import('../../domain/run.js').TokenUsage | undefined {\n const tokens = part.tokens as Record<string, unknown> | undefined;\n if (!tokens || typeof tokens.input !== 'number') return undefined;\n\n const input = tokens.input;\n const output = typeof tokens.output === 'number' ? tokens.output : 0;\n const reasoning = typeof tokens.reasoning === 'number' ? tokens.reasoning : 0;\n return createTokenUsage(input, output, { reasoning });\n}\n"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {d as d$2,e as e$2,c as c$1}from'./chunk-4MMHVHA6.js';import {e,c,b as b$1,d as d$1,f,g}from'./chunk-LXNRCJ22.js';import {a}from'./chunk-CHRW4CLD.js';import {a as a$1}from'./chunk-P4JTJBWO.js';import {d,l,h,e as e$1,n}from'./chunk-IKNBPOQL.js';import {dirname}from'path';import D from'fs/promises';import {execFile}from'child_process';function et(u,t){if(!u?.length||!t?.length)return false;for(let e of u)for(let s of t)if(ut(e,s))return true;return false}function L(u){let t=u.split("*")[0],e=!t.endsWith("/"),s=e?dirname(t):"";return {raw:u,base:t,isFile:e,dir:s}}var x=class{entries;constructor(t){this.entries=[];for(let e of t)if(e?.length)for(let s of e)this.entries.push(L(s));}overlapsAny(t){if(!t?.length||this.entries.length===0)return false;for(let e of t){let s=L(e);for(let a of this.entries)if(dt(s,a))return true}return false}add(t){if(t?.length)for(let e of t)this.entries.push(L(e));}get size(){return this.entries.length}};function dt(u,t){return u.raw===t.raw||u.base.startsWith(t.base)||t.base.startsWith(u.base)?true:u.isFile&&t.isFile?u.dir===t.dir&&u.dir!==".":false}function ut(u,t){if(u===t)return true;let e=u.split("*")[0],s=t.split("*")[0];if(e.startsWith(s)||s.startsWith(e))return true;if(!e.endsWith("/")&&!s.endsWith("/")){let a=dirname(e),r=dirname(s);return a===r&&a!=="."}return false}var st=Promise.resolve();async function q(u){let t,e=new Promise(a=>{t=a;}),s=st;st=e,await s;try{return await ht(u)}finally{t();}}async function ht(u){let t=await it(u);if(t!==null){if(pt(t))return {acquired:false,pid:t};await D.unlink(u).catch(()=>{});}try{let e=await D.open(u,"wx");return await e.writeFile(String(process.pid),"utf-8"),await e.close(),{acquired:!0,pid:process.pid}}catch(e){if(e.code==="EEXIST")return {acquired:false,pid:await it(u)??void 0};throw e}}async function G(u){await D.unlink(u).catch(()=>{});}async function it(u){try{let t=await D.readFile(u,"utf-8"),e=parseInt(t.trim(),10);return isNaN(e)?null:e}catch{return null}}function pt(u){try{return process.kill(u,0),!0}catch(t){return t.code==="EPERM"}}var b=class{constructor(t){this.inner=t;}cache=new Map;async list(t){let e=t?`${t.status??""}:${t.goalId??""}`:"__all__";if(this.cache.has(e))return this.cache.get(e);let s=await this.inner.list(t);return this.cache.set(e,s),s}async get(t){return this.inner.get(t)}async save(t){await this.inner.save(t),this.cache.clear();}async delete(t){await this.inner.delete(t),this.cache.clear();}invalidate(){this.cache.clear();}},C=class{constructor(t){this.inner=t;}listCache=null;nameCache=new Map;async list(){if(this.listCache)return this.listCache;let t=await this.inner.list();return this.listCache=t,t}async get(t){return this.inner.get(t)}async getByName(t){if(this.nameCache.has(t))return this.nameCache.get(t)??null;let e=await this.inner.getByName(t);return this.nameCache.set(t,e),e}async save(t){await this.inner.save(t),this.listCache=null,this.nameCache.clear();}async delete(t){await this.inner.delete(t),this.listCache=null,this.nameCache.clear();}invalidate(){this.listCache=null,this.nameCache.clear();}},B=class{constructor(t){this.inner=t;}cache=new Map;async list(t){let e=t?.status??"__all__";if(this.cache.has(e))return this.cache.get(e);let s=await this.inner.list(t);return this.cache.set(e,s),s}async get(t){return this.inner.get(t)}async save(t){await this.inner.save(t),this.cache.clear();}async delete(t){await this.inner.delete(t),this.cache.clear();}invalidate(){this.cache.clear();}};var gt={test_pass:{cmd:"npm",args:["test"]},typecheck:{cmd:"npx",args:["tsc","--noEmit"]},lint:{cmd:"npm",args:["run","lint"]}},_=class{cwd;timeoutMs;constructor(t){this.cwd=t.cwd,this.timeoutMs=t.timeout_ms??12e4;}async runAll(t){let e=[];for(let s of t){let a=await this.runCriterion(s);e.push(a);}return e}static allPassed(t){return t.length>0&&t.every(e=>e.passed)}static formatReport(t){return t.map(s=>{let a=s.passed?"\u2713":"\u2717",r=s.output.slice(0,500);return `${a} ${s.criterion}: ${s.passed?"PASSED":"FAILED"}
|
|
3
|
+
${r}`}).join(`
|
|
4
|
+
|
|
5
|
+
`)}runCriterion(t){let{cmd:e,args:s}=gt[t];return new Promise(a=>{execFile(e,s,{cwd:this.cwd,timeout:this.timeoutMs,maxBuffer:1024*1024},(r,d,n)=>{let l=(d+`
|
|
6
|
+
`+n).trim();a({criterion:t,passed:!r,output:l.slice(0,2e3)});});})}};var mt=8192,vt=4096,at=class{constructor(t){this.deps=t;this.cachedTaskStore=new b(t.taskStore),this.cachedAgentStore=new C(t.agentStore),this.cachedGoalStore=t.goalStore?new B(t.goalStore):null;}intervalId=null;shuttingDown=false;state=null;abortControllers=new Map;cachedTaskStore;cachedAgentStore;cachedGoalStore;saveStateTimer=null;saveStateDirty=false;lockAcquired=false;consecutiveTickFailures=0;maxConsecutiveTickFailures=5;maxRetryQueueSize=100;signalHandlers=[];immediateDispatchTimer=null;taskCreatedUnsub=null;tickInProgress=false;stateMutex=Promise.resolve();get isOwner(){return this.lockAcquired}withStateLock(t){let e,s=new Promise(r=>{e=r;}),a=this.stateMutex;return this.stateMutex=s,a.then(async()=>{try{return await t()}finally{e();}})}async runTask(t){if(this.lockAcquired){await this.freshDispatch(()=>this.dispatchTask(t));return}await this.withTemporaryLock(()=>this.freshDispatch(()=>this.dispatchTask(t)));}async runAll(){if(this.lockAcquired){await this.freshDispatch(()=>this.dispatchAll());return}await this.withTemporaryLock(()=>this.freshDispatch(()=>this.dispatchAll()));}async freshDispatch(t){await this.withStateLock(async()=>{this.cachedTaskStore.invalidate(),this.cachedAgentStore.invalidate(),await this.loadState(),await t(),await this.saveState();});}async withTemporaryLock(t){let e=await q(this.deps.lockPath);if(!e.acquired)throw new d(e.pid);this.lockAcquired=true;try{await t();}finally{this.lockAcquired=false,await G(this.deps.lockPath);}}async startWatch(){let t=await q(this.deps.lockPath);if(!t.acquired)throw new d(t.pid);this.lockAcquired=true,await this.loadState(),await this.cleanupStaleRunningEntries(),this.state.pid=process.pid,this.state.started_at=new Date().toISOString(),await this.saveState(),this.registerSignalHandlers(),this.taskCreatedUnsub=this.deps.eventBus.on("task:created",()=>{this.scheduleImmediateDispatch();}),await this.tick(),this.intervalId=setInterval(()=>this.tick().then(()=>{this.consecutiveTickFailures=0;},e=>{this.consecutiveTickFailures++;let s=e instanceof Error?e.message:String(e);this.deps.eventBus.emit({type:"orchestrator:error",error:s,context:"tick",fatal:this.consecutiveTickFailures>=this.maxConsecutiveTickFailures}),this.consecutiveTickFailures>=this.maxConsecutiveTickFailures&&(this.deps.eventBus.emit({type:"orchestrator:shutdown",reason:`${this.consecutiveTickFailures} consecutive tick failures`}),this.stop().catch(a=>{this.deps.eventBus.emit({type:"orchestrator:error",error:a instanceof Error?a.message:String(a),context:"stop after consecutive tick failures",fatal:false});}));}),this.deps.config.scheduling.poll_interval_ms);}registerSignalHandlers(){let t=e=>{this.deps.eventBus.emit({type:"orchestrator:shutdown",reason:`Received ${e}`}),this.stop().catch(s=>{this.deps.eventBus.emit({type:"orchestrator:error",error:s instanceof Error?s.message:String(s),context:`stop after ${e} signal`,fatal:false});});};for(let e of ["SIGINT","SIGTERM"]){let s=()=>t(e);this.signalHandlers.push([e,s]),process.on(e,s);}}removeSignalHandlers(){for(let[t,e]of this.signalHandlers)process.removeListener(t,e);this.signalHandlers=[];}async stop(){this.shuttingDown||(this.shuttingDown=true,this.intervalId&&(clearInterval(this.intervalId),this.intervalId=null),this.taskCreatedUnsub&&(this.taskCreatedUnsub(),this.taskCreatedUnsub=null),this.immediateDispatchTimer&&(clearTimeout(this.immediateDispatchTimer),this.immediateDispatchTimer=null),await this.flushStateLazy(),await this.withStateLock(async()=>{if(this.state){for(let[t,e$1]of Object.entries(this.state.running)){this.abortControllers.get(t)?.abort(),this.abortControllers.delete(t),await this.deps.processManager.killWithGrace(e$1.pid),await this.deps.runService.finish(e$1.run_id,"cancelled");let s=await this.deps.taskStore.get(t);s&&await this.deps.taskService.updateStatus(t,e(s)),await this.deps.agentService.setStatus(e$1.agent_id,"idle");}this.state.running={},this.state.claimed=new Set,this.state.pid=void 0,this.state.started_at=void 0,await this.saveState();}}),this.lockAcquired&&(await G(this.deps.lockPath),this.lockAcquired=false),this.removeSignalHandlers());}async cancelTask(t){if(!this.lockAcquired)return this.withTemporaryLock(()=>this.cancelTask(t));await this.withStateLock(async()=>{await this.loadState();let e=this.state,s=e.running[t];s&&(this.abortControllers.get(t)?.abort(),this.abortControllers.delete(t),await this.deps.processManager.killWithGrace(s.pid,3e3).catch(a=>{this.deps.eventBus.emit({type:"orchestrator:error",error:a instanceof Error?a.message:String(a),context:`cancelTask kill process ${s.pid} for task ${t}`,fatal:false});}),await this.deps.runService.finish(s.run_id,"cancelled").catch(a=>{this.deps.eventBus.emit({type:"orchestrator:error",error:a instanceof Error?a.message:String(a),context:`cancelTask finish run ${s.run_id}`,fatal:false});}),await this.deps.agentService.setStatus(s.agent_id,"idle").catch(a=>{this.deps.eventBus.emit({type:"orchestrator:error",error:a instanceof Error?a.message:String(a),context:`cancelTask setStatus idle for agent ${s.agent_id}`,fatal:false});}),delete e.running[t],await this.saveState()),e.retry_queue=e.retry_queue.filter(a=>a.task_id!==t);try{await this.deps.taskService.cancel(t);}catch{try{await this.deps.taskService.updateStatus(t,"cancelled");}catch{}}await this.saveState();});}async forceStopAgent(t){if(!this.lockAcquired)return this.withTemporaryLock(()=>this.forceStopAgent(t));await this.withStateLock(async()=>{await this.loadState();let e=this.state;for(let[s,a]of Object.entries(e.running))if(a.agent_id===t){this.abortControllers.get(s)?.abort(),this.abortControllers.delete(s),await this.deps.processManager.killWithGrace(a.pid,3e3),await this.deps.runService.finish(a.run_id,"cancelled");try{await this.deps.taskService.updateStatus(s,"failed");}catch{}delete e.running[s];}await this.deps.agentService.setStatus(t,"idle"),await this.saveState();});}async tick(){if(!this.shuttingDown){this.tickInProgress=true;try{await this.withStateLock(async()=>{if(this.shuttingDown)return;this.cachedTaskStore.invalidate(),this.cachedAgentStore.invalidate(),this.cachedGoalStore?.invalidate(),await this.loadState(),await this.reconcile(),await this.seedAutonomousTasks(),await this.dispatchAll();let t=await this.cachedTaskStore.list(),e=Object.keys(this.state.running).length,s=t.filter(a=>c(a.status)).length;this.deps.eventBus.emit({type:"orchestrator:tick",running:e,queued:s});});}finally{this.tickInProgress=false;}}}scheduleImmediateDispatch(t=0){this.shuttingDown||this.immediateDispatchTimer||(this.immediateDispatchTimer=setTimeout(()=>{if(this.immediateDispatchTimer=null,!this.shuttingDown){if(this.tickInProgress){t<10&&this.scheduleImmediateDispatch(t+1);return}this.immediateDispatch().catch(e=>{this.deps.eventBus.emit({type:"orchestrator:error",error:e instanceof Error?e.message:String(e),context:"immediate dispatch on task:created",fatal:false});});}},500));}async immediateDispatch(){this.shuttingDown||await this.freshDispatch(()=>this.shuttingDown?Promise.resolve():this.dispatchAll());}async reconcile(){let t=this.state,e=Date.now(),s=Object.entries(t.running),a=await Promise.all(s.map(([i])=>this.deps.taskStore.get(i)));for(let i=0;i<s.length;i++){let[h,c]=s[i],S=a[i];if(!S||b$1(S.status)){this.abortControllers.delete(h),delete t.running[h],await this.deps.agentService.setStatus(c.agent_id,"idle").catch(o=>{this.deps.eventBus.emit({type:"orchestrator:error",error:o instanceof Error?o.message:String(o),context:`reconcile setStatus idle for stale agent ${c.agent_id} (task ${h})`,fatal:false});});continue}if(!this.deps.processManager.isAlive(c.pid)){try{await this._handleRunFailure(h,c,"Process crashed unexpectedly");}catch{delete t.running[h],await this.deps.agentService.setStatus(c.agent_id,"idle").catch(o=>{this.deps.eventBus.emit({type:"orchestrator:error",error:o instanceof Error?o.message:String(o),context:`reconcile crash fallback setStatus idle for agent ${c.agent_id} (task ${h})`,fatal:false});});}continue}let w=new Date(c.last_event_at).getTime(),m=this.deps.config.defaults.agent.stall_timeout_ms;if(e-w>m){this.deps.eventBus.emit({type:"orchestrator:stall_detected",runId:c.run_id}),this.abortControllers.get(h)?.abort(),await this.deps.processManager.killWithGrace(c.pid,5e3);try{await this._handleRunFailure(h,c,"Agent stalled (no events)");}catch{delete t.running[h],await this.deps.agentService.setStatus(c.agent_id,"idle").catch(o=>{this.deps.eventBus.emit({type:"orchestrator:error",error:o instanceof Error?o.message:String(o),context:`reconcile stall fallback setStatus idle for agent ${c.agent_id} (task ${h})`,fatal:false});});}}}let r=new Set(Object.values(t.running).map(i=>i.agent_id)),[d,n]=await Promise.all([this.cachedAgentStore.list(),this.cachedTaskStore.list()]),l=d.filter(i=>i.status==="running"&&!r.has(i.id));l.length>0&&await Promise.all(l.map(i=>this.deps.agentService.setStatus(i.id,"idle")));let p=n.filter(i=>i.status==="in_progress"&&!t.running[i.id]);p.length>0&&await Promise.all(p.map(async i=>{try{await this.deps.taskService.updateStatus(i.id,"failed");}catch{i.status="failed",i.updated_at=new Date().toISOString(),await this.deps.taskStore.save(i).catch(h=>{this.deps.eventBus.emit({type:"orchestrator:error",error:h instanceof Error?h.message:String(h),context:`force-write orphaned task ${i.id}`,fatal:false});});}this.deps.eventBus.emit({type:"task:orphaned",taskId:i.id});}));let f=[];t.retry_queue=t.retry_queue.filter(i=>e>=new Date(i.due_at).getTime()?(f.push(i.task_id),false):true);for(let i of f)await this.dispatchTask(i);await this.saveState();}async seedAutonomousTasks(){let e=(await this.cachedAgentStore.list()).filter(n=>n.autonomous&&n.status==="idle");if(e.length===0)return;let s=await this.cachedTaskStore.list(),a$1=this.cachedGoalStore?await this.cachedGoalStore.list({status:"active"}):[],r=false,d=new Set;for(let n of e){if(s.some(c=>c.assignee===n.id&&!b$1(c.status)))continue;let p=a$1.find(c=>c.assignee===n.id&&!d.has(c.id))??a$1.find(c=>!c.assignee&&!d.has(c.id));p&&d.add(p.id);let f=n.role??"general assistant",i=p?`[auto] ${n.name}: ${p.title.slice(0,60)}`:`[auto] ${n.name}: ${f.slice(0,60)}`,h=p?`## GOAL (highest priority)
|
|
7
|
+
|
|
8
|
+
${p.description||p.title}
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
Agent role: ${f}`:`Autonomous work cycle. Agent role: ${f}`;try{await this.deps.taskService.create({title:i,description:h,assignee:n.id,labels:[a],priority:3,goalId:p?.id}),r=!0;}catch(c){this.deps.eventBus.emit({type:"orchestrator:error",error:c instanceof Error?c.message:String(c),context:`autonomous task for agent ${n.id}`,fatal:false});}}r&&this.cachedTaskStore.invalidate();}async dispatchAll(){let t=this.state,e=this.deps.config.scheduling.max_concurrent_agents,s=Object.keys(t.running).length,a=e-s;if(a<=0)return;let r=await this.cachedTaskStore.list(),d=new Map(r.map(i=>[i.id,i])),n=r.filter(i=>c(i.status)&&!d$1(i,d)&&!t.running[i.id]&&!t.claimed.has(i.id)).sort((i,h)=>{let c=(i.priority??3)-(h.priority??3);if(c!==0)return c;let S=(i.goalId?0:1)-(h.goalId?0:1);if(S!==0)return S;let w=h.updated_at??"",m=i.updated_at??"";return w<m?-1:w>m?1:0}).slice(0,a),l$1=new Set,p=r.filter(i=>i.status==="in_progress"&&i.scope?.length),f=new x(p.map(i=>i.scope));for(let i of n)if(i.scope?.length)if(f.overlapsAny(i.scope)){let h=p.find(c=>et(i.scope,c.scope));this.deps.eventBus.emit({type:"task:scope_overlap",taskId:i.id,overlappingTaskId:h?.id??i.id,patterns:i.scope}),l$1.add(i.id);}else f.add(i.scope);for(let i of n)if(!l$1.has(i.id))try{await this.dispatchTask(i.id);}catch(h){if(h instanceof l)try{let c=await this.deps.taskStore.get(i.id);c&&!b$1(c.status)&&(c.status="failed",c.updated_at=new Date().toISOString(),await this.deps.taskStore.save(c));}catch{}this.deps.eventBus.emit({type:"orchestrator:error",error:h instanceof Error?h.message:String(h),context:`dispatch task ${i.id}`,fatal:false});}}async dispatchTask(t){let e=this.state;if(e.running[t]){let a=e.running[t];throw new h(t,a.run_id,a.agent_id)}let s=await this.deps.taskService.get(t);e.claimed.add(t),await this.saveState();try{let a=await this.cachedAgentStore.list(),r=await this.deps.agentService.findBestAgent(s);if(!r){if(a.length===0)throw new e$1;this.unclaim(t),await this.saveState();return}let{path:d,branch:n}=await this.deps.workspaceManager.prepare(s,r,this.deps.config),l=this.deps.config.prompt?.system_template??d$2,p=this.deps.config.prompt?.user_template??e$2,f=this.deps.config.prompt?.template,i=s.attempts+1,h;if(i>1){let v=await this.deps.runService.getLastFailedRunContext(s.id);v&&(h={previous_error:v.error,previous_output:v.output});}let c=s.goalId,[S,w,m]=await Promise.all([this.deps.contextStore?.getAll(),this.deps.messageService?this.deps.messageService.drainMailbox(r.id,s.id):[],c&&this.cachedGoalStore?this.cachedGoalStore.get(c).catch(()=>null):null]),o;if(m){let ot=(await this.cachedTaskStore.list()).filter(P=>P.goalId===c),ct=await this.deps.contextStore?.get(`${c}-progress`),lt=ot.map(P=>`[${P.status}] ${P.title}`);o={id:m.id,title:m.title,description:m.description,status:m.status,task_names:lt,progress:ct?.value};}let g=c$1(s,r,i,d,this.deps.config,{allAgents:a,retryContext:h,sharedContext:S,feedback:s.feedback,messages:w.length?w:void 0,goal:o}),y,R;f?y=await this.deps.templateEngine.render(f,g):(R=await this.deps.templateEngine.render(l,g),y=await this.deps.templateEngine.render(p,g));let T=await this.deps.runService.create({taskId:s.id,agentId:r.id,attempt:i,prompt:y,workspacePath:d});if((s.status==="failed"||s.status==="cancelled")&&(await this.deps.taskService.retry(t),s.status="todo",s.attempts=0),await this.deps.taskService.updateStatus(t,"in_progress"),await this.deps.taskService.assign(t,r.id),await this.deps.taskService.incrementAttempts(t),n){let v=await this.deps.taskStore.get(t);v&&(v.proof={...v.proof??{files_changed:[]},branch:n},v.workspace=d,await this.deps.taskStore.save(v));}await this.deps.agentService.setStatus(r.id,"running");let k=await this.deps.agentService.get(r.id);k.current_task=t,k.last_error=void 0,await this.deps.agentStore.save(k);let nt=this.deps.adapterRegistry.require(r.adapter),I=new AbortController;this.abortControllers.set(t,I);let F=nt.execute({prompt:y,systemPrompt:R,workspace:d,env:{...r.config.env,ORCH_AGENT_ID:r.id,ORCH_AGENT_NAME:r.name,ORCH_TASK_ID:s.id},config:k.config,signal:I.signal}),N=F.pid,U=new Date().toISOString();await this.deps.runService.start(T.id,N),this.unclaim(t),e.running[t]={run_id:T.id,agent_id:r.id,task_id:t,pid:N,started_at:U,last_event_at:U},await this.saveState(),this.collectEvents(F.events,T.id,t,r.id).catch(v=>{this.deps.eventBus.emit({type:"orchestrator:error",error:v instanceof Error?v.message:String(v),context:`adapter execution for ${t}`,fatal:!1});});}catch(a){throw this.unclaim(t),await this.saveState(),a}}async collectEvents(t,e,s,a){let r,d,n,l,p=new Set;try{for await(let i of t){if(this.shuttingDown)break;if(i.type==="done"){if(i.tokens){let{input:g,output:y,reasoning:R,cache_read:T,cache_write:k}=i.tokens;r=a$1(g,y,{reasoning:R,cache_read:T,cache_write:k});}let o=i.data;o&&typeof o.result=="string"&&(d=o.result);}if(i.type==="output"){let o=i.data;if(o){let g=typeof o.text=="string"?o.text:typeof o.message=="string"?o.message:void 0;g?.trim()&&(n=g);}}if(i.type==="file_change"){let o=i.data;if(o&&Array.isArray(o.paths))for(let g of o.paths)typeof g=="string"&&p.add(g);else {let g=o&&typeof o.path=="string"?o.path:typeof i.data=="string"?i.data:String(i.data);p.add(g);}}let h=St(i.timestamp)?i.timestamp:new Date().toISOString(),c=i.type==="file_change"?(()=>{let o=i.data;return o&&typeof o.path=="string"?o.path:typeof i.data=="string"?i.data:String(i.data)})():null,S=rt(i.data,mt);i.data=void 0;let w={timestamp:h,type:i.type==="output"?"agent_output":i.type==="file_change"?"file_changed":i.type==="command"?"command_run":i.type==="tool_call"?"tool_call":i.type==="error"?"error":"done",data:S};await this.deps.runService.appendEvent(e,w),this.state?.running[s]&&(this.state.running[s].last_event_at=h,this.saveStateLazy());let m=rt(S,vt);i.type==="output"||i.type==="tool_call"?this.deps.eventBus.emit({type:"agent:output",runId:e,agentId:a,data:m}):i.type==="file_change"?this.deps.eventBus.emit({type:"agent:file_changed",runId:e,agentId:a,path:c}):i.type==="error"&&(i.errorKind&&(l=i.errorKind),this.deps.eventBus.emit({type:"agent:error",runId:e,agentId:a,error:m,...i.errorKind?{errorKind:i.errorKind}:{}}));}let f=d??n;await this.handleRunSuccess(s,e,a,r,f,[...p]);}catch(f){let i=f instanceof Error?f.message:String(f),h=l??(f instanceof Error?f.errorKind:void 0),c=this.state?.running[s];c&&await this.handleRunFailure(s,c,i,h);}}async handleRunSuccess(t,e,s,a,r,d){return this.withStateLock(()=>this._handleRunSuccess(t,e,s,a,r,d))}async _handleRunSuccess(t,e,s,a$1,r,d){await this.flushStateLazy(),this.abortControllers.delete(t);let n=this.state;if(!n.running[t])return;let l=await this.deps.taskStore.get(t);if(!l)return;l.proof={...l.proof,agent_summary:r?.slice(0,2e3)??l.proof?.agent_summary,files_changed:d?.length?d:l.proof?.files_changed??[]},delete l.feedback,await this.deps.taskStore.save(l);let p=await this.deps.agentStore.get(s),i=l.labels?.includes(a)||p?.config.approval_policy==="auto",h=f(l,true,i);await this.deps.runService.finish(e,"succeeded",a$1);let c=n.running[t],S=c?Date.now()-new Date(c.started_at).getTime():0;c&&(n.stats.total_runtime_ms+=S),delete n.running[t];let w={tasks_completed:(p?.stats.tasks_completed??0)+1,total_runs:(p?.stats.total_runs??0)+1,total_runtime_ms:(p?.stats.total_runtime_ms??0)+S};if(a$1&&(w.tokens_used=(p?.stats.tokens_used??0)+a$1.total),await this.deps.agentService.updateStats(s,w).catch(o=>{this.deps.eventBus.emit({type:"orchestrator:error",error:o instanceof Error?o.message:String(o),context:`agent stats update for ${s}`,fatal:false});}),n.stats.total_tasks_completed++,n.stats.total_runs++,a$1&&(n.stats.total_tokens.input+=a$1.input,n.stats.total_tokens.output+=a$1.output,n.stats.total_tokens.reasoning+=a$1.reasoning,n.stats.total_tokens.cache_read+=a$1.cache_read,n.stats.total_tokens.cache_write+=a$1.cache_write,n.stats.total_tokens.total=n.stats.total_tokens.input+n.stats.total_tokens.output+n.stats.total_tokens.reasoning),l.proof?.branch)try{let o=await this.deps.workspaceManager.mergeBack(l.proof.branch);if(o.success)this.deps.eventBus.emit({type:"workspace:merge_succeeded",taskId:t,branch:l.proof.branch}),await this.deps.workspaceManager.cleanup(t).catch(g=>{this.deps.eventBus.emit({type:"orchestrator:error",error:g instanceof Error?g.message:String(g),context:`workspace cleanup for ${t}`,fatal:!1});});else {this.deps.eventBus.emit({type:"workspace:merge_conflict",taskId:t,branch:l.proof.branch,conflictInfo:o.conflictInfo}),await this.forceTaskToReview(l,s,`MERGE CONFLICT: ${o.conflictInfo}`);return}}catch(o){let g=o instanceof Error?o.message:String(o);await this.forceTaskToReview(l,s,`MERGE ERROR: ${g}`);return}try{await this.deps.taskService.updateStatus(t,h);}catch(o){let g=o instanceof Error?o.message:String(o);this.deps.eventBus.emit({type:"orchestrator:error",error:g,context:`state machine validation failed for task ${t} -> ${h}, force-writing`,fatal:false}),l.status=h,l.updated_at=new Date().toISOString(),await this.deps.taskStore.save(l).catch(y=>{this.deps.eventBus.emit({type:"orchestrator:error",error:y instanceof Error?y.message:String(y),context:`force-write task ${t} to store failed`,fatal:false});});}await this.deps.agentService.setStatus(s,"idle").catch(o=>{this.deps.eventBus.emit({type:"orchestrator:error",error:o instanceof Error?o.message:String(o),context:`_handleRunSuccess setStatus idle for agent ${s}`,fatal:false});});let m=await this.deps.agentStore.get(s);m&&(m.current_task=void 0,await this.deps.agentStore.save(m)),h==="review"&&l.review_criteria?.length?await this.runAutoReview(t,l.review_criteria,l.workspace??this.deps.projectRoot,i):h==="review"&&i&&await this.deps.taskService.updateStatus(t,"done"),await this.saveState(),this.scheduleImmediateDispatch();}async handleRunFailure(t,e,s,a){return this.withStateLock(()=>this._handleRunFailure(t,e,s,a))}async _handleRunFailure(t,e$1,s,a){await this.flushStateLazy(),this.abortControllers.delete(t);let r=this.state,d=await this.deps.taskStore.get(t);if(!d)return;await this.deps.runService.finish(e$1.run_id,"failed",void 0,s),await this.deps.agentService.setStatus(e$1.agent_id,"idle");let n$1=await this.deps.agentStore.get(e$1.agent_id);n$1&&(n$1.current_task=void 0,n$1.last_error={message:s.slice(0,500),kind:a??n(s),timestamp:new Date().toISOString()},await this.deps.agentStore.save(n$1));let l=await this.deps.agentStore.get(e$1.agent_id),p=Date.now()-new Date(e$1.started_at).getTime();await this.deps.agentService.updateStats(e$1.agent_id,{tasks_failed:(l?.stats.tasks_failed??0)+1,total_runs:(l?.stats.total_runs??0)+1,total_runtime_ms:(l?.stats.total_runtime_ms??0)+p});let f=e(d);if(await this.deps.taskService.updateStatus(t,f),f==="retrying"){let i=g(d.attempts-1,this.deps.config.scheduling.retry_base_delay_ms,this.deps.config.scheduling.retry_max_delay_ms);r.retry_queue.some(c=>c.task_id===t)||(r.retry_queue.length>=this.maxRetryQueueSize&&r.retry_queue.shift(),r.retry_queue.push({task_id:t,attempt:d.attempts+1,due_at:new Date(Date.now()+i).toISOString(),error:s})),this.deps.eventBus.emit({type:"run:retry",runId:e$1.run_id,attempt:d.attempts+1,delay_ms:i});}else r.stats.total_tasks_failed++;r.stats.total_runtime_ms+=p,delete r.running[t],r.stats.total_runs++,await this.saveState(),this.scheduleImmediateDispatch();}async runAutoReview(t,e,s,a=false){let d=await new _({cwd:s}).runAll(e),n=_.allPassed(d),l=await this.deps.taskStore.get(t);if(l&&(l.review_results=d,l.proof={...l.proof,test_results:_.formatReport(d),files_changed:l.proof?.files_changed??[]},await this.deps.taskStore.save(l),this.deps.eventBus.emit({type:"task:auto_reviewed",taskId:t,passed:n,results:d}),n||a)){n||this.deps.eventBus.emit({type:"orchestrator:error",error:`Review criteria failed for task ${t} but autoApprove is set \u2014 force-approving`,context:"auto-review-with-auto-approve",fatal:false});try{await this.deps.taskService.updateStatus(t,"done");}catch(p){let f=p instanceof Error?p.message:String(p);this.deps.eventBus.emit({type:"orchestrator:error",error:f,context:`auto-review transition failed for task ${t} -> done, force-writing`,fatal:false}),l.status="done",l.updated_at=new Date().toISOString(),await this.deps.taskStore.save(l).catch(i=>{this.deps.eventBus.emit({type:"orchestrator:error",error:i instanceof Error?i.message:String(i),context:`force-write task ${t} to store failed (auto-review)`,fatal:false});});}}}async forceTaskToReview(t,e,s){t.proof={...t.proof,agent_summary:`${s}
|
|
12
|
+
|
|
13
|
+
${t.proof?.agent_summary??""}`.slice(0,2e3),files_changed:t.proof?.files_changed??[]},t.status="review",t.updated_at=new Date().toISOString(),await this.deps.taskStore.save(t),await this.deps.agentService.setStatus(e,"idle").catch(r=>{this.deps.eventBus.emit({type:"orchestrator:error",error:r instanceof Error?r.message:String(r),context:`forceTaskToReview setStatus idle for agent ${e}`,fatal:false});});let a=await this.deps.agentStore.get(e);a&&(a.current_task=void 0,await this.deps.agentStore.save(a)),await this.saveState();}unclaim(t){this.state.claimed.delete(t);}requireOwnership(){if(!this.lockAcquired)throw new d(0)}async loadState(){this.state=await this.deps.stateStore.read();}async cleanupStaleRunningEntries(){let t=this.state,e=Object.entries(t.running).filter(([,a])=>!this.deps.processManager.isAlive(a.pid)),s=new Set;if(e.length>0){for(let[a]of e)delete t.running[a],s.add(a);await Promise.all(e.map(async([a,r])=>{await this.deps.agentService.setStatus(r.agent_id,"idle").catch(d=>{this.deps.eventBus.emit({type:"orchestrator:error",error:d instanceof Error?d.message:String(d),context:`startup cleanup: setStatus idle for agent ${r.agent_id}`,fatal:false});}),await this.forceTaskCancelled(a),await this.deps.runService.finish(r.run_id,"cancelled",void 0,"Orchestrator restarted").catch(d=>{this.deps.eventBus.emit({type:"orchestrator:error",error:d instanceof Error?d.message:String(d),context:`startup cleanup: finish run ${r.run_id}`,fatal:false});});}));}if(s.size>0){let r=(await this.cachedTaskStore.list()).filter(n=>n.status==="in_progress"&&!t.running[n.id]);r.length>0&&await Promise.all(r.map(n=>this.forceTaskCancelled(n.id)));let d=new Set([...s,...r.map(n=>n.id)]);t.retry_queue=t.retry_queue.filter(n=>!d.has(n.task_id)),await this.saveState();}}async forceTaskCancelled(t){try{await this.deps.taskService.updateStatus(t,"cancelled");}catch{let e=await this.deps.taskStore.get(t);e&&!b$1(e.status)&&(e.status="cancelled",e.updated_at=new Date().toISOString(),await this.deps.taskStore.save(e).catch(s=>{this.deps.eventBus.emit({type:"orchestrator:error",error:s instanceof Error?s.message:String(s),context:`startup cleanup: force-cancel task ${t}`,fatal:false});}));}}async saveState(){this.state&&await this.deps.stateStore.write(this.state);}saveStateLazy(){this.saveStateDirty=true,!this.saveStateTimer&&(this.saveStateTimer=setTimeout(()=>{this.saveStateTimer=null,this.saveStateDirty&&(this.saveStateDirty=false,this.saveState().catch(t=>{this.deps.eventBus.emit({type:"orchestrator:error",error:t instanceof Error?t.message:String(t),context:"debounced state save",fatal:false});}));},500));}async flushStateLazy(){this.saveStateTimer&&(clearTimeout(this.saveStateTimer),this.saveStateTimer=null),this.saveStateDirty&&(this.saveStateDirty=false,await this.saveState());}};function St(u){if(typeof u!="string")return false;let t=new Date(u);return !isNaN(t.getTime())&&t.toISOString()===u}function rt(u,t){let e=typeof u=="string"?u:JSON.stringify(u);return e.length>t?e.slice(0,t)+"\u2026":e}export{at as Orchestrator};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"orchestrator-
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"orchestrator-QFNYZ6AH.js"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {b}from'./chunk-BCPUTULS.js';import {l,q,i,j}from'./chunk-64WUDYEM.js';var d=[{key:"startup-mvp",name:"Startup MVP",description:"Ship an MVP in 48 hours",lead_index:0,agents:[{shop_key:"architect",name:"CTO"},{shop_key:"backend-dev",name:"Backend"},{shop_key:"backend-dev",name:"Backend 2"},{shop_key:"frontend-dev",name:"Frontend"},{shop_key:"qa-engineer",name:"QA"},{shop_key:"code-reviewer",name:"Reviewer"}]},{key:"pr-review-corp",name:"PR Review Corp",description:"Automated review for every PR",lead_index:0,agents:[{shop_key:"architect",name:"CTO"},{shop_key:"security-auditor",name:"Security"},{shop_key:"performance-engineer",name:"Performance"},{shop_key:"code-reviewer",name:"Style"},{shop_key:"qa-engineer",name:"QA"}]},{key:"migration-squad",name:"Migration Squad",description:"JS-to-TS migration over a weekend",lead_index:0,agents:[{shop_key:"architect",name:"CTO"},{shop_key:"fullstack-dev",name:"Migrator"},{shop_key:"fullstack-dev",name:"Migrator 2"},{shop_key:"fullstack-dev",name:"Migrator 3"},{shop_key:"qa-engineer",name:"QA"},{shop_key:"code-reviewer",name:"Reviewer"}]},{key:"security-dept",name:"Security Department",description:"Multi-layer security audit",lead_index:0,agents:[{shop_key:"security-auditor",name:"Lead Auditor"},{shop_key:"security-auditor",name:"Scanner"},{shop_key:"security-auditor",name:"Secrets Auditor"},{shop_key:"bug-hunter",name:"Hunter"},{shop_key:"code-reviewer",name:"Reviewer"}]},{key:"test-factory",name:"Test Factory",description:"Coverage from 40% to 80% overnight",lead_index:0,agents:[{shop_key:"qa-engineer",name:"Coverage Lead"},{shop_key:"backend-dev",name:"Backend"},{shop_key:"backend-dev",name:"Backend 2"},{shop_key:"qa-engineer",name:"QA"},{shop_key:"qa-engineer",name:"QA 2"},{shop_key:"code-reviewer",name:"Reviewer"}]},{key:"content-agency",name:"Content Agency",description:"Content factory: plan, write, edit, optimize",lead_index:0,agents:[{shop_key:"marketer",name:"Strategist"},{shop_key:"content-creator",name:"Writer"},{shop_key:"content-creator",name:"Writer 2"},{shop_key:"tech-writer",name:"Editor"},{shop_key:"growth-hacker",name:"SEO"}]},{key:"data-lab",name:"Data Lab",description:"3 CSVs to executive report by morning",lead_index:0,agents:[{shop_key:"data-engineer",name:"Lead Analyst"},{shop_key:"data-engineer",name:"Data Engineer"}]},{key:"sales-machine",name:"Sales Machine",description:"Outbound pipeline: research, outreach, follow-up, close",lead_index:0,agents:[{shop_key:"marketer",name:"Sales Director"},{shop_key:"content-creator",name:"SDR"},{shop_key:"content-creator",name:"SDR 2"},{shop_key:"content-creator",name:"Copywriter"},{shop_key:"growth-hacker",name:"Growth Analyst"}]},{key:"bugfix-dept",name:"Bugfix Department",description:"100 issues to 0 in a week",lead_index:0,agents:[{shop_key:"architect",name:"Triager"},{shop_key:"bug-hunter",name:"Fixer"},{shop_key:"bug-hunter",name:"Fixer 2"},{shop_key:"bug-hunter",name:"Fixer 3"},{shop_key:"qa-engineer",name:"QA"},{shop_key:"code-reviewer",name:"Reviewer"}]},{key:"docs-team",name:"Docs Team",description:"Technical docs from codebase analysis",lead_index:0,agents:[{shop_key:"architect",name:"Docs Lead"},{shop_key:"tech-writer",name:"Writer"},{shop_key:"tech-writer",name:"Writer 2"},{shop_key:"tech-writer",name:"Editor"},{shop_key:"code-reviewer",name:"Reviewer"}]}];function v(l){return d.find(t=>t.key===l)}function C(l$1,t){let h=l$1.command("org").description("Pre-built AI companies \u2014 deploy a full department with one command");h.command("list").alias("ls").description("List available company templates").action(async()=>{if(t.context.json){console.log(JSON.stringify(d,null,2));return}console.log();let c=["KEY","NAME","AGENTS","DESCRIPTION"],s=d.map(e=>[e.key,e.name,String(e.agents.length),e.description]);l(c,s),console.log(),console.log(` ${q("Deploy:")} orch org deploy <key> --goal "Your objective"`),console.log();}),h.command("deploy <template>").description("Deploy a pre-built AI company").option("--goal <goal>","Set a goal for the team").action(async(c,s)=>{let e=v(c);if(!e){i(`Unknown template "${c}"`,"Run: orch org list \u2014 to see available templates"),process.exitCode=1;return}let a=[];for(let n of e.agents){let o=b(n.shop_key);if(!o){i(`Agent shop template not found: ${n.shop_key}`),process.exitCode=1;return}try{let r=await t.agentService.create({name:n.name,adapter:o.adapter,role:o.role,model:o.model,approval_policy:o.approval_policy,skills:o.skills});a.push(r.id);}catch(r){i(`Failed to create agent "${n.name}": ${r instanceof Error?r.message:String(r)}`,a.length>0?`${a.length} agent(s) were already created. Clean up with: orch agent list`:void 0),process.exitCode=1;return}}let g=a[e.lead_index],w=a.filter(n=>n!==g),y=await t.teamService.create({name:e.name,description:e.description,lead_agent_id:g,member_agent_ids:w}),m;if(s.goal&&(m=(await t.goalService.create({title:s.goal,assignee:g})).id),t.context.json){console.log(JSON.stringify({team:y,agentIds:a,goalId:m},null,2));return}if(t.context.quiet){console.log(y.id);return}console.log(),j(`Deployed team "${e.name}" \u2014 ${e.agents.length} agents`),console.log();for(let n=0;n<e.agents.length;n++){let o=e.agents[n],r=a[n],k=n===e.lead_index,S=k?"lead":"member";console.log(` ${k?"\u2605":"\u2022"} ${o.name} ${q(`(${r}, ${S})`)}`);}console.log(`
|
|
3
|
+
Team: ${q(y.id)}`),m&&console.log(` Goal: ${q(m)} \u2014 "${s.goal}"`),console.log(),console.log(` ${q("Next:")} orch run --all --watch`),console.log();});}export{C as registerOrgCommand};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {i,p as p$1,j,q,c}from'./chunk-64WUDYEM.js';function p(t,o){t.command("run [task-id]").description("Run tasks").option("--all","Run all todo tasks").option("--watch","Watch mode: continuous orchestration").action(async(e,r)=>{r.watch?await m(o):r.all?await d(o):e?await u(o,e):(i("Specify a task ID, --all, or --watch"),process.exit(2));});}async function u(t,o){let e=await t.taskService.get(o);console.log(),console.log(` ${p$1("orch")} \xB7 running ${o} "${e.title}"`);let r=t.eventBus.onAny(s=>{let c$1=new Date().toLocaleTimeString("en-US",{hour12:false,hour:"2-digit",minute:"2-digit",second:"2-digit"});switch(s.type){case "agent:output":console.log(` ${q(c$1)} ${c("agentAction")} ${typeof s.data=="string"?s.data.slice(0,80):""}`);break;case "agent:file_changed":console.log(` ${q(c$1)} ${c("agentAction")} Modified ${s.path}`);break;case "agent:error":console.log(` ${q(c$1)} ${c("failed")} ${s.error}`);break;case "agent:completed":s.success?j("Done"):i("Failed");break}});try{await t.orchestrator.runTask(o);}finally{r();}console.log();}async function d(t){console.log(),console.log(` ${p$1("orch")} \xB7 running all todo tasks`),console.log(),await t.orchestrator.runAll();}async function m(t){console.log(`${p$1("orch")} \xB7 watching \xB7 poll interval ${t.config.scheduling.poll_interval_ms/1e3}s`),console.log("\u2501".repeat(43)),console.log(),t.eventBus.onAny(o=>{let e=new Date().toLocaleTimeString("en-US",{hour12:false,hour:"2-digit",minute:"2-digit"});switch(o.type){case "agent:output":{let r=typeof o.data=="string"?o.data.slice(0,60):"";console.log(`${q(e)} ${c("agentAction")} ${r}`);break}case "agent:completed":o.success?console.log(`${q(e)} ${c("done")} DONE ${o.runId}`):console.log(`${q(e)} ${c("failed")} FAIL ${o.runId}`);break;case "run:retry":console.log(`${q(e)} ${c("retrying")} RETRY attempt ${o.attempt} \xB7 next in ${Math.round(o.delay_ms/1e3)}s`);break;case "orchestrator:tick":process.stdout.write(`\r${p$1("orch")} \xB7 watching \xB7 ${o.running} running \xB7 ${o.queued} queued `);break;case "orchestrator:stall_detected":console.log(`${q(e)} ${c("warning")} STALL ${o.runId}`);break;case "orchestrator:shutdown":console.log(`
|
|
3
|
+
${q("Shutting down...")}`);break}}),await t.orchestrator.startWatch();}export{p as registerRunCommand};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { buildFullPrompt } from './chunk-
|
|
2
|
-
import './chunk-
|
|
1
|
+
import { buildFullPrompt } from './chunk-MOWC2CHX.js';
|
|
2
|
+
import './chunk-RHFRHCN5.js';
|
|
3
3
|
import { classifyAdapterError } from './chunk-NLQAJ7TW.js';
|
|
4
4
|
import { readLines } from './chunk-O2MSGW3V.js';
|
|
5
5
|
import { execFile } from 'child_process';
|
|
@@ -219,5 +219,5 @@ var ShellAdapter = class {
|
|
|
219
219
|
};
|
|
220
220
|
|
|
221
221
|
export { ShellAdapter };
|
|
222
|
-
//# sourceMappingURL=shell-
|
|
223
|
-
//# sourceMappingURL=shell-
|
|
222
|
+
//# sourceMappingURL=shell-UXEJRK3D.js.map
|
|
223
|
+
//# sourceMappingURL=shell-UXEJRK3D.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/infrastructure/adapters/event-buffer.ts","../src/infrastructure/adapters/shell.ts"],"names":[],"mappings":"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","file":"shell-NJNW3O6K.js","sourcesContent":["/**\n * Lock-free ring buffer for AgentEvent streaming.\n *\n * Replaces Array.shift() O(n) polling with O(1) dequeue\n * and event-driven notification instead of 50ms busy-wait.\n * Includes backpressure: when buffer is full, push() returns\n * a promise that resolves when space is available.\n */\n\nimport type { AgentEvent } from './interface.js';\n\nconst DEFAULT_CAPACITY = 1024;\n\ninterface Deferred<T> {\n promise: Promise<T>;\n resolve: (value: T) => void;\n}\n\nfunction deferred<T>(): Deferred<T> {\n let resolve!: (value: T) => void;\n const promise = new Promise<T>((r) => { resolve = r; });\n return { promise, resolve };\n}\n\nexport class EventBuffer {\n private buf: (AgentEvent | undefined)[];\n private head = 0; // read index\n private tail = 0; // write index\n private count = 0;\n private readonly capacity: number;\n\n // Consumer notification: resolved when new data is available\n private dataReady: Deferred<void> | null = null;\n // Producer notification: resolved when space is available\n private spaceReady: Deferred<void> | null = null;\n\n private closed = false;\n\n constructor(capacity = DEFAULT_CAPACITY) {\n this.capacity = capacity;\n this.buf = new Array(capacity);\n }\n\n /** Number of buffered events. */\n get size(): number {\n return this.count;\n }\n\n get isFull(): boolean {\n return this.count >= this.capacity;\n }\n\n /**\n * Push an event into the buffer.\n * If the buffer is full, waits until space is available (backpressure).\n */\n async push(event: AgentEvent): Promise<void> {\n while (this.isFull && !this.closed) {\n if (!this.spaceReady) {\n this.spaceReady = deferred<void>();\n }\n await this.spaceReady.promise;\n }\n if (this.closed) return;\n\n this.buf[this.tail] = event;\n this.tail = (this.tail + 1) % this.capacity;\n this.count++;\n\n // Wake up consumer if waiting\n if (this.dataReady) {\n const dr = this.dataReady;\n this.dataReady = null;\n dr.resolve();\n }\n }\n\n /**\n * Dequeue the next event. O(1).\n * Returns undefined only when buffer is empty AND closed.\n */\n async take(): Promise<AgentEvent | undefined> {\n while (this.count === 0) {\n if (this.closed) return undefined;\n if (!this.dataReady) {\n this.dataReady = deferred<void>();\n }\n await this.dataReady.promise;\n }\n\n const event = this.buf[this.head];\n this.buf[this.head] = undefined; // allow GC\n this.head = (this.head + 1) % this.capacity;\n this.count--;\n\n // Wake up producer if waiting for space\n if (this.spaceReady) {\n const sr = this.spaceReady;\n this.spaceReady = null;\n sr.resolve();\n }\n\n return event;\n }\n\n /**\n * Signal that no more events will be pushed.\n * Wakes up any waiting consumer/producer.\n */\n close(): void {\n this.closed = true;\n if (this.dataReady) {\n const dr = this.dataReady;\n this.dataReady = null;\n dr.resolve();\n }\n if (this.spaceReady) {\n const sr = this.spaceReady;\n this.spaceReady = null;\n sr.resolve();\n }\n }\n\n get isClosed(): boolean {\n return this.closed;\n }\n\n /**\n * Async iterator that drains the buffer until closed and empty.\n */\n async *[Symbol.asyncIterator](): AsyncGenerator<AgentEvent> {\n while (true) {\n const event = await this.take();\n if (event === undefined) return;\n yield event;\n }\n }\n}\n","/**\n * Shell adapter.\n *\n * Spawns an arbitrary command via `bash -lc`.\n * Task prompt is passed via ORCHESTRY_TASK_PROMPT env variable.\n * Consumes stdout and stderr concurrently to avoid deadlocks.\n */\n\nimport type { IAgentAdapter, AdapterTestResult, ExecuteParams, AgentEvent, ExecuteHandle } from './interface.js';\nimport type { IProcessManager } from '../process/process-manager.js';\nimport { buildFullPrompt } from './utils.js';\nimport { readLines } from '../process/process-manager.js';\nimport { EventBuffer } from './event-buffer.js';\nimport { classifyAdapterError, AdapterErrorKind } from '../../domain/errors.js';\nimport { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\n\nconst execFileAsync = promisify(execFile);\n\nexport class ShellAdapter implements IAgentAdapter {\n readonly kind = 'shell';\n\n constructor(private readonly processManager: IProcessManager) {}\n\n async test(): Promise<AdapterTestResult> {\n try {\n const { stdout } = await execFileAsync('bash', ['--version']);\n const version = stdout.split('\\n')[0]?.trim() ?? 'unknown';\n return { ok: true, version };\n } catch {\n return { ok: false, error: 'bash not found', errorKind: classifyAdapterError('bash not found') };\n }\n }\n\n execute(params: ExecuteParams): ExecuteHandle {\n const command = params.config.command;\n if (!command) {\n // Return a handle that immediately yields an error\n async function* errorGen(): AsyncGenerator<AgentEvent> {\n yield {\n type: 'error',\n timestamp: new Date().toISOString(),\n data: 'Shell adapter requires a command in agent config',\n errorKind: AdapterErrorKind.SPAWN_FAILED,\n };\n }\n return { pid: 0, events: errorGen() };\n }\n\n const { process: proc, pid } = this.processManager.spawn('bash', ['-lc', command], {\n cwd: params.workspace,\n env: {\n ...process.env,\n ...params.env,\n ORCHESTRY_TASK_PROMPT: buildFullPrompt(params.systemPrompt, params.prompt),\n },\n signal: params.signal,\n });\n\n const signal = params.signal;\n const processManager = this.processManager;\n\n async function* generateEvents(): AsyncGenerator<AgentEvent> {\n // Ring buffer with backpressure replaces Array.shift() polling\n const buffer = new EventBuffer();\n\n // Ensure process is reaped on abort — SIGTERM + grace period + SIGKILL\n const onAbort = () => {\n processManager.killWithGrace(pid, 5_000).catch(() => {});\n };\n if (signal) {\n if (signal.aborted) {\n onAbort();\n } else {\n signal.addEventListener('abort', onAbort, { once: true });\n }\n }\n\n const stdoutPromise = (async () => {\n if (!proc.stdout) return;\n for await (const line of readLines(proc.stdout)) {\n if (signal?.aborted) break;\n await buffer.push({\n type: 'output',\n timestamp: new Date().toISOString(),\n data: line,\n });\n }\n })();\n\n const stderrPromise = (async () => {\n if (!proc.stderr) return;\n for await (const line of readLines(proc.stderr)) {\n if (signal?.aborted) break;\n await buffer.push({\n type: 'error',\n timestamp: new Date().toISOString(),\n data: line,\n errorKind: classifyAdapterError(line),\n });\n }\n })();\n\n // Close the buffer once both streams are drained (or on error)\n void Promise.all([stdoutPromise, stderrPromise]).then(\n () => buffer.close(),\n () => buffer.close(),\n );\n\n // Yield events as they arrive — no polling, no busy-wait\n yield* buffer;\n\n // Clean up abort listener\n if (signal && !signal.aborted) {\n signal.removeEventListener('abort', onAbort);\n }\n\n // Wait for process to exit\n await new Promise<void>((resolve, reject) => {\n // If process already exited, resolve immediately\n if (proc.exitCode !== null || proc.killed) {\n resolve();\n return;\n }\n proc.on('close', (code) => {\n if (code === 0 || signal?.aborted) {\n resolve();\n } else {\n reject(new Error(`Shell command exited with code ${code}`));\n }\n });\n proc.on('error', reject);\n });\n }\n\n return { pid, events: generateEvents() };\n }\n\n async stop(pid: number): Promise<void> {\n await this.processManager.killWithGrace(pid);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/infrastructure/adapters/event-buffer.ts","../src/infrastructure/adapters/shell.ts"],"names":[],"mappings":"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","file":"shell-UXEJRK3D.js","sourcesContent":["/**\n * Lock-free ring buffer for AgentEvent streaming.\n *\n * Replaces Array.shift() O(n) polling with O(1) dequeue\n * and event-driven notification instead of 50ms busy-wait.\n * Includes backpressure: when buffer is full, push() returns\n * a promise that resolves when space is available.\n */\n\nimport type { AgentEvent } from './interface.js';\n\nconst DEFAULT_CAPACITY = 1024;\n\ninterface Deferred<T> {\n promise: Promise<T>;\n resolve: (value: T) => void;\n}\n\nfunction deferred<T>(): Deferred<T> {\n let resolve!: (value: T) => void;\n const promise = new Promise<T>((r) => { resolve = r; });\n return { promise, resolve };\n}\n\nexport class EventBuffer {\n private buf: (AgentEvent | undefined)[];\n private head = 0; // read index\n private tail = 0; // write index\n private count = 0;\n private readonly capacity: number;\n\n // Consumer notification: resolved when new data is available\n private dataReady: Deferred<void> | null = null;\n // Producer notification: resolved when space is available\n private spaceReady: Deferred<void> | null = null;\n\n private closed = false;\n\n constructor(capacity = DEFAULT_CAPACITY) {\n this.capacity = capacity;\n this.buf = new Array(capacity);\n }\n\n /** Number of buffered events. */\n get size(): number {\n return this.count;\n }\n\n get isFull(): boolean {\n return this.count >= this.capacity;\n }\n\n /**\n * Push an event into the buffer.\n * If the buffer is full, waits until space is available (backpressure).\n */\n async push(event: AgentEvent): Promise<void> {\n while (this.isFull && !this.closed) {\n if (!this.spaceReady) {\n this.spaceReady = deferred<void>();\n }\n await this.spaceReady.promise;\n }\n if (this.closed) return;\n\n this.buf[this.tail] = event;\n this.tail = (this.tail + 1) % this.capacity;\n this.count++;\n\n // Wake up consumer if waiting\n if (this.dataReady) {\n const dr = this.dataReady;\n this.dataReady = null;\n dr.resolve();\n }\n }\n\n /**\n * Dequeue the next event. O(1).\n * Returns undefined only when buffer is empty AND closed.\n */\n async take(): Promise<AgentEvent | undefined> {\n while (this.count === 0) {\n if (this.closed) return undefined;\n if (!this.dataReady) {\n this.dataReady = deferred<void>();\n }\n await this.dataReady.promise;\n }\n\n const event = this.buf[this.head];\n this.buf[this.head] = undefined; // allow GC\n this.head = (this.head + 1) % this.capacity;\n this.count--;\n\n // Wake up producer if waiting for space\n if (this.spaceReady) {\n const sr = this.spaceReady;\n this.spaceReady = null;\n sr.resolve();\n }\n\n return event;\n }\n\n /**\n * Signal that no more events will be pushed.\n * Wakes up any waiting consumer/producer.\n */\n close(): void {\n this.closed = true;\n if (this.dataReady) {\n const dr = this.dataReady;\n this.dataReady = null;\n dr.resolve();\n }\n if (this.spaceReady) {\n const sr = this.spaceReady;\n this.spaceReady = null;\n sr.resolve();\n }\n }\n\n get isClosed(): boolean {\n return this.closed;\n }\n\n /**\n * Async iterator that drains the buffer until closed and empty.\n */\n async *[Symbol.asyncIterator](): AsyncGenerator<AgentEvent> {\n while (true) {\n const event = await this.take();\n if (event === undefined) return;\n yield event;\n }\n }\n}\n","/**\n * Shell adapter.\n *\n * Spawns an arbitrary command via `bash -lc`.\n * Task prompt is passed via ORCHESTRY_TASK_PROMPT env variable.\n * Consumes stdout and stderr concurrently to avoid deadlocks.\n */\n\nimport type { IAgentAdapter, AdapterTestResult, ExecuteParams, AgentEvent, ExecuteHandle } from './interface.js';\nimport type { IProcessManager } from '../process/process-manager.js';\nimport { buildFullPrompt } from './utils.js';\nimport { readLines } from '../process/process-manager.js';\nimport { EventBuffer } from './event-buffer.js';\nimport { classifyAdapterError, AdapterErrorKind } from '../../domain/errors.js';\nimport { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\n\nconst execFileAsync = promisify(execFile);\n\nexport class ShellAdapter implements IAgentAdapter {\n readonly kind = 'shell';\n\n constructor(private readonly processManager: IProcessManager) {}\n\n async test(): Promise<AdapterTestResult> {\n try {\n const { stdout } = await execFileAsync('bash', ['--version']);\n const version = stdout.split('\\n')[0]?.trim() ?? 'unknown';\n return { ok: true, version };\n } catch {\n return { ok: false, error: 'bash not found', errorKind: classifyAdapterError('bash not found') };\n }\n }\n\n execute(params: ExecuteParams): ExecuteHandle {\n const command = params.config.command;\n if (!command) {\n // Return a handle that immediately yields an error\n async function* errorGen(): AsyncGenerator<AgentEvent> {\n yield {\n type: 'error',\n timestamp: new Date().toISOString(),\n data: 'Shell adapter requires a command in agent config',\n errorKind: AdapterErrorKind.SPAWN_FAILED,\n };\n }\n return { pid: 0, events: errorGen() };\n }\n\n const { process: proc, pid } = this.processManager.spawn('bash', ['-lc', command], {\n cwd: params.workspace,\n env: {\n ...process.env,\n ...params.env,\n ORCHESTRY_TASK_PROMPT: buildFullPrompt(params.systemPrompt, params.prompt),\n },\n signal: params.signal,\n });\n\n const signal = params.signal;\n const processManager = this.processManager;\n\n async function* generateEvents(): AsyncGenerator<AgentEvent> {\n // Ring buffer with backpressure replaces Array.shift() polling\n const buffer = new EventBuffer();\n\n // Ensure process is reaped on abort — SIGTERM + grace period + SIGKILL\n const onAbort = () => {\n processManager.killWithGrace(pid, 5_000).catch(() => {});\n };\n if (signal) {\n if (signal.aborted) {\n onAbort();\n } else {\n signal.addEventListener('abort', onAbort, { once: true });\n }\n }\n\n const stdoutPromise = (async () => {\n if (!proc.stdout) return;\n for await (const line of readLines(proc.stdout)) {\n if (signal?.aborted) break;\n await buffer.push({\n type: 'output',\n timestamp: new Date().toISOString(),\n data: line,\n });\n }\n })();\n\n const stderrPromise = (async () => {\n if (!proc.stderr) return;\n for await (const line of readLines(proc.stderr)) {\n if (signal?.aborted) break;\n await buffer.push({\n type: 'error',\n timestamp: new Date().toISOString(),\n data: line,\n errorKind: classifyAdapterError(line),\n });\n }\n })();\n\n // Close the buffer once both streams are drained (or on error)\n void Promise.all([stdoutPromise, stderrPromise]).then(\n () => buffer.close(),\n () => buffer.close(),\n );\n\n // Yield events as they arrive — no polling, no busy-wait\n yield* buffer;\n\n // Clean up abort listener\n if (signal && !signal.aborted) {\n signal.removeEventListener('abort', onAbort);\n }\n\n // Wait for process to exit\n await new Promise<void>((resolve, reject) => {\n // If process already exited, resolve immediately\n if (proc.exitCode !== null || proc.killed) {\n resolve();\n return;\n }\n proc.on('close', (code) => {\n if (code === 0 || signal?.aborted) {\n resolve();\n } else {\n reject(new Error(`Shell command exited with code ${code}`));\n }\n });\n proc.on('error', reject);\n });\n }\n\n return { pid, events: generateEvents() };\n }\n\n async stop(pid: number): Promise<void> {\n await this.processManager.killWithGrace(pid);\n }\n}\n"]}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import*as a from'readline';import r from'chalk';async function w(o){if(!process.stdin.isTTY)return null;let s=0;function u(){let n=process.stdout.rows??24;return Math.max(1,Math.min(o.length,n-4))}function d(){let n=u();process.stdout.write("\x1B[2J\x1B[H"),console.log(r.bold.yellow(`
|
|
3
|
+
AGENT SHOP`)+r.gray(` \u2014 arrow keys to navigate, enter to select, q to cancel
|
|
4
|
+
`));let c=Math.max(0,Math.min(s-Math.floor(n/2),o.length-n)),t=Math.min(c+n,o.length);for(let l=c;l<t;l++){let i=o[l],e=l===s,p=e?r.yellow(" \u25B8 "):" ",m=e?r.bold.white(i.name):r.gray(i.name),g=r.gray(` \u2014 ${i.description}`),h=r.gray.dim(` [${i.model.replace("claude-","")}]`);console.log(`${p}${m}${g}${h}`);}o.length>n&&console.log(r.gray(`
|
|
5
|
+
${c+1}-${t} of ${o.length}`));}return new Promise(n=>{let c=a.createInterface({input:process.stdin});process.stdin.setRawMode(true),a.emitKeypressEvents(process.stdin);function t(){process.stdin.removeListener("keypress",l);try{process.stdin.setRawMode(!1);}catch{}c.close(),process.stdout.write("\x1B[2J\x1B[H");}let l=(i,e)=>{e.name==="up"||e.ctrl&&e.name==="p"?(s=(s-1+o.length)%o.length,d()):e.name==="down"||e.ctrl&&e.name==="n"?(s=(s+1)%o.length,d()):e.name==="return"?(t(),n(o[s])):(e.name==="q"||e.name==="escape"||e.ctrl&&e.name==="c")&&(t(),n(null));};c.on("error",()=>{t(),n(null);}),c.on("close",()=>{t(),n(null);});try{d();}catch{t(),n(null);return}process.stdin.on("keypress",l);})}export{w as pickFromShop};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {g,p,q,d,o,e,h}from'./chunk-64WUDYEM.js';function C(k,e$1){k.command("status").description("Show orchestrator status").action(async()=>{let a=await e$1.taskService.list(),u=await e$1.agentService.list(),o$1=await e$1.stateStore.read();if(e$1.context.json){console.log(JSON.stringify({tasks:a,agents:u,state:o$1},null,2));return}let p$1=Object.keys(o$1.running).length,y=o$1.pid?"watching":"idle",m=o$1.started_at?g(o$1.started_at):"";console.log(),console.log(`${p("orch")} \xB7 ${e$1.config.project.name} \xB7 ${y}`),console.log();let r={};for(let t of a)r[t.status]=(r[t.status]??0)+1;p$1>0&&console.log(` ${"RUNNING".padEnd(12)}${p$1}${"".padEnd(20)}AGENTS ${u.length}`);for(let[t,c]of Object.entries(r))t!=="in_progress"&&console.log(` ${q(t.padEnd(12))}${c}`);let d$1=a.filter(t=>t.status==="in_progress");if(d$1.length>0){console.log();for(let t of d$1){let c=g(t.updated_at);console.log(` ${d("in_progress")} ${t.assignee?o(t.assignee):""} ${t.title.slice(0,35).padEnd(37)}${c} ${e(t.priority)}`);}}let n=o$1.stats.total_tokens,s=[];n.total>0&&(s.push(`\u2191${h(n.input)}`),s.push(`\u2193${h(n.output)}`),n.reasoning>0&&s.push(`\u{1F9E0}${h(n.reasoning)}`),s.push(`\u03A3${h(n.total)}`));let f=[m?`up ${m}`:null,s.length>0?s.join(" "):null].filter(Boolean).join(" \xB7 ");f&&(console.log(),console.log(` ${q(f)}`)),console.log();});}export{C as registerStatusCommand};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {j,q,g,d,e,o,l,n,m}from'./chunk-64WUDYEM.js';function x(_,a){let c=_.command("task").description("Manage tasks");c.command("add <title>").description("Create a new task").option("-d, --description <desc>","Task description").option("-p, --priority <n>","Priority (1-4)","3").option("-l, --labels <labels>","Comma-separated labels").option("--depends-on <ids>","Comma-separated dependency task IDs").option("--max-attempts <n>","Max retry attempts").option("--workspace-mode <mode>","Workspace mode: shared|worktree|isolated").option("--assignee <agent-id>","Assign to agent").option("--review-criteria <criteria>","Comma-separated auto-review criteria: test_pass,typecheck,lint").option("--scope <patterns>","Comma-separated glob patterns for file scope (e.g. src/auth/**,src/session/**)").option("--goal-id <goalId>","Associate task with a goal").option("--attach <paths>","Comma-separated file paths to attach (screenshots, docs)").option("-e, --edit","Open $EDITOR to write the description").action(async(e,t)=>{let i=t.description;if(t.edit){let{openInEditor:n,toEditorContent:l,fromEditorContent:d}=await import('./editor-7IFRWVTL.js'),s=await n(l({title:e,priority:parseInt(t.priority,10),description:i}));i=d(s).description;}let o=await a.taskService.create({title:e,description:i,priority:parseInt(t.priority,10),labels:t.labels?.split(",").map(n=>n.trim()),depends_on:t.dependsOn?.split(",").map(n=>n.trim()),max_attempts:t.maxAttempts?parseInt(t.maxAttempts,10):void 0,workspace_mode:t.workspaceMode,assignee:t.assignee,review_criteria:t.reviewCriteria?.split(",").map(n=>n.trim()),scope:t.scope?.split(",").map(n=>n.trim()),goalId:t.goalId,attachments:t.attach?.split(",").map(n=>n.trim())});a.context.json?console.log(JSON.stringify(o,null,2)):a.context.quiet?console.log(o.id):j(`Created ${o.id} "${o.title}"`);}),c.command("list").description("List all tasks").option("--status <status>","Filter by status").action(async e$1=>{let t=await a.taskService.list(e$1.status?{status:e$1.status}:void 0);if(a.context.json){console.log(JSON.stringify(t,null,2));return}if(a.context.quiet){t.forEach(s=>console.log(s.id));return}if(t.length===0){console.log(`
|
|
3
|
+
No tasks. Create one: ${q('orch task add "Title"')}
|
|
4
|
+
`);return}let i=["STATUS","PRI","TASK","AGENT","TIME"],o$1=t.map(s=>{let r=(s.status==="in_progress"||s.status==="done")&&s.updated_at?g(s.updated_at):q("\u2014");return [`${d(s.status)} ${s.status}`,e(s.priority),s.title.slice(0,35),s.assignee?o(s.assignee):q("\u2014"),r]});console.log(),l(i,o$1);let n=t.filter(s=>s.status==="in_progress").length,l$1=t.filter(s=>s.status==="review").length,d$1=t.filter(s=>s.status==="done").length;console.log(`
|
|
5
|
+
${t.length} tasks${n?` \xB7 ${n} running`:""}${l$1?` \xB7 ${l$1} review`:""}${d$1?` \xB7 ${d$1} done`:""}
|
|
6
|
+
`);}),c.command("show <id>").description("Show task details").action(async e$1=>{let t=await a.taskService.get(e$1);if(a.context.json){console.log(JSON.stringify(t,null,2));return}console.log(`
|
|
7
|
+
${t.title}`),console.log(` ${"\u2550".repeat(42)}`),console.log();let i=[["Status",`${d(t.status)} ${t.status} \xB7 attempt ${t.attempts}/${t.max_attempts}`],["Priority",e(t.priority)]];if(t.assignee&&i.push(["Agent",o(t.assignee)]),t.labels.length&&i.push(["Labels",t.labels.join(", ")]),t.scope?.length&&i.push(["Scope",t.scope.join(", ")]),t.workspace_mode&&i.push(["Workspace",t.workspace_mode]),t.workspace&&i.push(["Path",n(t.workspace)]),t.review_criteria?.length&&i.push(["Review",t.review_criteria.join(", ")]),t.feedback&&i.push(["Feedback",t.feedback]),i.push(["Created",t.created_at]),m(i),t.attachments?.length){console.log(`
|
|
8
|
+
Attachments (${t.attachments.length})
|
|
9
|
+
${"\u2500".repeat(42)}`);for(let o of t.attachments)console.log(` ${n(o)}`);}if(t.description){console.log(`
|
|
10
|
+
Description
|
|
11
|
+
${"\u2500".repeat(42)}`);for(let o of t.description.split(`
|
|
12
|
+
`))console.log(` ${o}`);}if(t.proof){if(console.log(`
|
|
13
|
+
Result
|
|
14
|
+
${"\u2500".repeat(42)}`),t.proof.branch&&console.log(` Branch: ${t.proof.branch}`),t.proof.pr_url&&console.log(` PR: ${t.proof.pr_url}`),t.proof.files_changed.length){console.log(" Files changed:");for(let o of t.proof.files_changed)console.log(` \u2022 ${o}`);}if(t.proof.test_results){console.log(" Test results:");for(let o of t.proof.test_results.split(`
|
|
15
|
+
`))console.log(` ${o}`);}if(t.proof.agent_summary){console.log(" Agent summary:");for(let o of t.proof.agent_summary.split(`
|
|
16
|
+
`))console.log(` ${o}`);}}if(t.review_results?.length){console.log(`
|
|
17
|
+
Review Results
|
|
18
|
+
${"\u2500".repeat(42)}`);for(let o of t.review_results){let n=o.passed?"\u2713":"\u2717";if(console.log(` ${n} ${o.criterion}: ${o.passed?"passed":"failed"}`),o.output)for(let l of o.output.split(`
|
|
19
|
+
`))console.log(` ${l}`);}}console.log();}),c.command("edit <id>").description("Open task in $EDITOR to modify title, priority and description").action(async e=>{let t=await a.taskService.get(e),{openInEditor:i,toEditorContent:o,fromEditorContent:n}=await import('./editor-7IFRWVTL.js'),l=t.attachments?.length?`
|
|
20
|
+
# Attachments: ${t.attachments.join(", ")}`:"",d=o({title:t.title,priority:t.priority,description:t.description})+l,s=await i(d),r=n(s),g={};if(r.title&&r.title!==t.title&&(g.title=r.title),r.priority&&r.priority!==t.priority&&(g.priority=r.priority),r.description!==void 0&&r.description!==t.description&&(g.description=r.description??""),Object.keys(g).length===0){console.log(" No changes.");return}let w=await a.taskService.update(e,g);j(`Updated ${w.id} "${w.title}"`);}),c.command("assign <task-id> <agent-id>").description("Assign task to agent").action(async(e,t)=>{let i=await a.taskService.assign(e,t);j(`Assigned ${i.id} \u2192 ${t}`);}),c.command("cancel <id>").description("Cancel a task").action(async e=>{if((await a.taskService.get(e)).status==="in_progress"){let{buildFullContainer:i}=await import('./container-FJI7RN2L.js');await(await i(a.context)).orchestrator.cancelTask(e);}else await a.taskService.cancel(e);j(`Cancelled ${e}`);}),c.command("approve <id>").description("Approve a task in review").action(async e=>{await a.taskService.updateStatus(e,"done"),j(`Approved ${e}`);}),c.command("reject <id>").description("Reject a task and send it back for rework").option("-r, --reason <reason>","Feedback for the agent explaining what to fix").action(async(e,t)=>{await a.taskService.reject(e,t.reason),j(`Rejected ${e} \u2192 todo${t.reason?` (reason: ${t.reason})`:""}`);}),c.command("retry <id>").description("Retry a failed task").action(async e=>{await a.taskService.retry(e),j(`Reset ${e} to todo`);});}export{x as registerTaskCommand};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {j,q,l,m}from'./chunk-64WUDYEM.js';function g(c,t){let n=c.command("team").description("Manage agent teams");n.command("create <name>").description("Create a new team").requiredOption("--lead <agent-id>","Lead agent ID").option("--members <ids>","Comma-separated member agent IDs").option("-d, --description <desc>","Team description").option("--no-auto-claim","Disable auto-claiming").action(async(a,e)=>{let i=await t.teamService.create({name:a,description:e.description,lead_agent_id:e.lead,member_agent_ids:e.members?.split(",").map(o=>o.trim()),config:{auto_claim:e.autoClaim!==false}});t.context.json?console.log(JSON.stringify(i,null,2)):t.context.quiet?console.log(i.id):j(`Created team "${i.name}" \u2192 ${i.id}`);}),n.command("list").description("List all teams").action(async()=>{let a=await t.teamService.list();if(t.context.json){console.log(JSON.stringify(a,null,2));return}if(a.length===0){console.log(q(`
|
|
3
|
+
No teams. Create one: orch team create <name> --lead <agent-id>
|
|
4
|
+
`));return}let e=["ID","NAME","STATUS","LEAD","MEMBERS","POOL"],i=a.map(o=>[o.id,o.name,o.status,o.lead_agent_id,String(o.members.length),String(o.task_pool.length)]);console.log(),l(e,i),console.log();}),n.command("show <id>").description("Show team details").action(async a=>{let e=await t.teamService.get(a);if(t.context.json){console.log(JSON.stringify(e,null,2));return}console.log(),m([["ID",e.id],["Name",e.name],["Status",e.status],["Lead",e.lead_agent_id],["Members",e.members.map(i=>`${i.agent_id} (${i.role})`).join(", ")],["Pool",e.task_pool.length>0?e.task_pool.join(", "):q("empty")],["Auto-claim",String(e.config.auto_claim)],["Created",e.created_at]]),console.log();}),n.command("join <team-id> <agent-id>").description("Add an agent to a team").action(async(a,e)=>{await t.teamService.join(a,e),j(`Agent ${e} joined team ${a}`);}),n.command("leave <team-id> <agent-id>").description("Remove an agent from a team").action(async(a,e)=>{await t.teamService.leave(a,e),j(`Agent ${e} left team ${a}`);}),n.command("add-task <team-id> <task-id>").description("Add a task to the team pool").action(async(a,e)=>{await t.teamService.addTask(a,e),j(`Task ${e} added to team ${a} pool`);}),n.command("set-lead <team-id> <agent-id>").description("Transfer team lead to another member").action(async(a,e)=>{await t.teamService.setLead(a,e),j(`${e} is now lead of team ${a}`);}),n.command("disband <id>").description("Disband a team").action(async a=>{await t.teamService.disband(a),j(`Team ${a} disbanded`);});}export{g as registerTeamCommand};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
function ot(c,e){c.command("tui").description("Launch interactive TUI dashboard").action(async()=>{let v=await e.taskService.list(),S=await e.agentService.list(),w=await e.stateStore.read(),{render:f}=await import('ink'),{createElement:h}=await import('react'),{App:T}=await import('./App-SSYYVFGW.js'),k=async t=>{await e.orchestrator.runTask(t);},A=async(t,s)=>e.taskService.create({title:t,priority:s?.priority,description:s?.description,attachments:s?.attachments}),b=async t=>{await e.orchestrator.cancelTask(t);},C=async t=>{await e.taskService.retry(t);},R=async(t,s)=>{await e.taskService.assign(t,s);},_=async()=>{await e.orchestrator.runAll();},E=async t=>{await e.agentService.disable(t);},j=async t=>{await e.agentService.enable(t);},D=t=>e.eventBus.onAny(t),P=async()=>e.taskService.list(),G=async()=>e.agentService.list(),U=async()=>e.stateStore.read(),x=async(t,s,n)=>e.agentService.create({name:t,adapter:s??"claude",model:n?.model||void 0,role:n?.role||void 0,approval_policy:n?.approval_policy||void 0,skills:n?.skills||void 0}),L=async t=>{await e.agentService.remove(t);},H=async t=>{await e.taskService.delete(t);},I=async t=>{await e.taskService.updateStatus(t,"done");},W=async(t,s)=>{await e.taskService.reject(t,s);},F=async(t,s)=>e.taskService.update(t,s),N=async(t,s)=>e.agentService.update(t,{...s,approval_policy:s.approval_policy}),O=async t=>{await e.orchestrator.forceStopAgent(t);},M=async(t,s)=>e.agentService.setAutonomous(t,s),V=async t=>{let s=await e.runService.listAll();s.sort((a,r)=>new Date(r.started_at).getTime()-new Date(a.started_at).getTime());let n=s.filter(a=>a.status==="succeeded"||a.status==="failed"),m=3,rt=10,p=n.slice(0,m),u=n.slice(m,rt),y=async a=>(await e.runService.readEventsTail(a.id,30)).map(i=>({timestamp:i.timestamp,agentId:a.agent_id,taskId:a.task_id,type:i.type,data:i.data}));if(p.length>0){let a=(await Promise.all(p.map(y))).flat();a.sort((r,i)=>new Date(r.timestamp).getTime()-new Date(i.timestamp).getTime()),t(a.slice(-200));}if(u.length>0){let a=(await Promise.all(u.map(y))).flat();a.sort((r,i)=>new Date(r.timestamp).getTime()-new Date(i.timestamp).getTime()),t(a.slice(-200));}},B=async t=>e.teamService.create(t),J=async()=>e.teamService.list(),K=async(t,s)=>e.teamService.join(t,s),q=async(t,s)=>e.teamService.leave(t,s),z=async t=>{await e.teamService.disband(t);},Q=async(t,s)=>e.teamService.setLead(t,s),X=async()=>e.goalService.list(),Y=async t=>e.goalService.create(t),Z=async(t,s)=>e.goalService.update(t,s),$=async(t,s)=>e.goalService.updateStatus(t,s),tt=async t=>{await e.goalService.delete(t);},et=async t=>e.goalService.getProgressReport(t),st=async()=>{await e.orchestrator.startWatch();},at=async()=>{await e.orchestrator.stop();},l=c.version()??"0.0.0",nt=import('./update-check-HGMBDYHL.js').then(t=>t.checkForUpdateSWR(l)).catch(()=>null),o=false,g;try{await e.orchestrator.startWatch(),o=!0;}catch(t){g=t instanceof Error?t.message:String(t);}let d=await nt,{waitUntilExit:it}=f(h(T,{projectName:e.config.project.name,tasks:v,agents:S,state:w,onRunTask:k,onCreateTask:A,onCancelTask:b,onRetryTask:C,onAssignTask:R,onRunAll:_,onDisableAgent:E,onEnableAgent:j,onSubscribeEvents:D,onRefreshTasks:P,onRefreshAgents:G,onRefreshState:U,onLoadHistory:V,onAddAgent:x,onDeleteAgent:L,onApproveTask:I,onRejectTask:W,onDeleteTask:H,onUpdateTask:F,onUpdateAgent:N,onForceStopAgent:O,onToggleAutonomous:M,onRefreshGoals:X,onCreateGoal:Y,onUpdateGoal:Z,onUpdateGoalStatus:$,onDeleteGoal:tt,onGetGoalProgress:et,onCreateTeam:B,onListTeams:J,onJoinTeam:K,onLeaveTeam:q,onDisbandTeam:z,onSetTeamLead:Q,onStartWatch:st,onStopWatch:at,initialWatchActive:o,watchError:g,version:l,latestVersion:d?.updateAvailable?d.latest:void 0,initialActivityFilter:e.globalConfig.tui.activity_filter,onSaveActivityFilter:async t=>{await e.globalConfigStore.set("activity_filter",t);},initialNotifications:e.globalConfig.tui.notifications,onSaveNotifications:async t=>{await e.globalConfigStore.set("notifications",t);},initialMaxConcurrent:e.config.scheduling.max_concurrent_agents,onSaveMaxConcurrent:async t=>{await e.configStore.set("scheduling.max_concurrent_agents",t),e.config.scheduling.max_concurrent_agents=t;},onCompleteOnboarding:async()=>{let t=await e.stateStore.read();t.onboardingCompleted=true,await e.stateStore.write(t);}}),{kittyKeyboard:{mode:"auto",flags:["disambiguateEscapeCodes"]}});await it(),o&&await e.orchestrator.stop().catch(()=>{});});}export{ot as registerTuiCommand};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {a}from'./chunk-UMZEA3JT.js';import {p,q}from'./chunk-64WUDYEM.js';import {execFile}from'child_process';import e from'chalk';var c="@oxgeneral/orch";function u(){return new Promise(n=>{let t=execFile("npm",["install","-g",`${c}@latest`],{timeout:6e4},(s,o,a)=>{let d=(o??"")+(a??"");n({code:s?1:0,output:d});});t.stdout?.pipe(process.stdout),t.stderr?.pipe(process.stderr);})}function h(n){n.command("update").description("Check for updates and install the latest version").option("--check","Only check, do not install").action(async t=>{console.log(),console.log(` ${p("orch update")} \xB7 checking for updates\u2026`),console.log();let s=n.version()??"0.0.0",o=await a(s);if(o||(console.log(` ${e.ansi256(167)("\u2715")} Could not reach npm registry`),console.log(" Check your network connection and try again."),console.log(),process.exit(1)),!o.updateAvailable){console.log(` ${e.ansi256(72)("\u2713")} Already up to date ${q(`(${o.current})`)}`),console.log();return}if(console.log(` ${e.ansi256(214)("\u25CF")} Update available: ${q(o.current)} \u2192 ${e.ansi256(72)(o.latest)}`),console.log(),t.check){console.log(` Run ${q("orch update")} to install.`),console.log();return}console.log(` Installing ${c}@${o.latest}\u2026`),console.log(),(await u()).code!==0&&(console.log(),console.log(` ${e.ansi256(167)("\u2715")} Update failed. Try manually:`),console.log(` npm install -g ${c}@latest`),console.log(),process.exit(1)),console.log(),console.log(` ${e.ansi256(72)("\u2713")} Updated to ${o.latest}`),console.log();});}export{h as registerUpdateCommand};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { sanitizeId, validateWorkspacePath, ensureDir } from './chunk-
|
|
1
|
+
import { sanitizeId, validateWorkspacePath, ensureDir } from './chunk-BSJVYRI3.js';
|
|
2
2
|
import { WorkspaceError } from './chunk-NLQAJ7TW.js';
|
|
3
3
|
import path from 'path';
|
|
4
4
|
import fs from 'fs/promises';
|
|
@@ -212,5 +212,5 @@ function sanitizeTitle(title) {
|
|
|
212
212
|
}
|
|
213
213
|
|
|
214
214
|
export { WorkspaceManager };
|
|
215
|
-
//# sourceMappingURL=workspace-manager-
|
|
216
|
-
//# sourceMappingURL=workspace-manager-
|
|
215
|
+
//# sourceMappingURL=workspace-manager-ABXFBL2A.js.map
|
|
216
|
+
//# sourceMappingURL=workspace-manager-ABXFBL2A.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/infrastructure/workspace/merge-strategy.ts","../src/infrastructure/workspace/workspace-manager.ts"],"names":[],"mappings":"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","file":"workspace-manager-2SFPKPLZ.js","sourcesContent":["/**\n * Git merge strategy for worktree branches.\n *\n * Encapsulates `git merge --no-ff` execution and conflict handling.\n */\n\nimport type { IProcessManager } from '../process/process-manager.js';\n\nexport type MergeResult =\n | { success: true }\n | { success: false; conflictInfo: string };\n\nexport class MergeStrategy {\n constructor(\n private readonly projectRoot: string,\n private readonly processManager: IProcessManager,\n ) {}\n\n /**\n * Merge a branch into the current branch with --no-ff.\n * On conflict, aborts the merge and returns conflict info.\n */\n async mergeBack(branch: string): Promise<MergeResult> {\n return new Promise((resolve) => {\n const { process: proc } = this.processManager.spawn(\n 'git',\n ['merge', '--no-ff', branch, '-m', `Merge ${branch}`],\n { cwd: this.projectRoot },\n );\n\n let output = '';\n const maxOutputLen = 2000;\n const appendOutput = (chunk: Buffer) => {\n if (output.length < maxOutputLen) output += chunk.toString();\n };\n proc.stdout?.on('data', appendOutput);\n proc.stderr?.on('data', appendOutput);\n\n proc.on('close', (code) => {\n if (code === 0) {\n resolve({ success: true });\n return;\n }\n\n const trimmedOutput = output.slice(0, 1000);\n const isConflict = trimmedOutput.includes('CONFLICT') || trimmedOutput.includes('Merge conflict');\n\n if (!isConflict) {\n // Non-conflict failure (branch not found, hook failure, etc.) — no merge to abort\n resolve({ success: false, conflictInfo: trimmedOutput });\n return;\n }\n\n // Abort the failed merge to restore clean state\n try {\n const { process: abortProc } = this.processManager.spawn(\n 'git',\n ['merge', '--abort'],\n { cwd: this.projectRoot },\n );\n abortProc.on('close', () => {\n resolve({ success: false, conflictInfo: trimmedOutput });\n });\n abortProc.on('error', () => {\n resolve({ success: false, conflictInfo: trimmedOutput });\n });\n } catch {\n resolve({ success: false, conflictInfo: trimmedOutput });\n }\n });\n\n proc.on('error', (err) => {\n resolve({ success: false, conflictInfo: err.message });\n });\n });\n }\n}\n","/**\n * Workspace manager implementation.\n *\n * Resolves workspace path based on mode priority chain:\n * task.workspace_mode → agent.config.workspace_mode → defaults.agent.workspace_mode → 'worktree'\n */\n\nimport path from 'node:path';\nimport fs from 'node:fs/promises';\nimport type { Agent } from '../../domain/agent.js';\nimport type { OrchestratorConfig } from '../../domain/config.js';\nimport type { Task, WorkspaceMode } from '../../domain/task.js';\nimport type { IProcessManager } from '../process/process-manager.js';\nimport { validateWorkspacePath, sanitizeId } from '../storage/paths.js';\nimport { ensureDir } from '../storage/fs-utils.js';\nimport type { IWorkspaceManager, PrepareResult } from './interface.js';\nimport { MergeStrategy, type MergeResult } from './merge-strategy.js';\nimport { WorkspaceError } from '../../domain/errors.js';\n\nexport class WorkspaceManager implements IWorkspaceManager {\n private readonly mergeStrategy: MergeStrategy;\n private gitRepoChecked = false;\n private isGitRepo = false;\n\n constructor(\n private readonly projectRoot: string,\n private readonly orchestryDir: string,\n private readonly processManager: IProcessManager,\n ) {\n this.mergeStrategy = new MergeStrategy(projectRoot, processManager);\n }\n\n async prepare(task: Task, agent: Agent, config: OrchestratorConfig): Promise<PrepareResult> {\n const mode = this.resolveMode(task, agent, config);\n\n if (mode !== 'shared') {\n await this.requireGitRepo(mode);\n }\n\n switch (mode) {\n case 'shared':\n return { path: this.projectRoot };\n\n case 'worktree':\n return this.prepareWorktree(task);\n\n case 'isolated':\n return { path: await this.prepareIsolated(task) };\n\n default:\n return { path: this.projectRoot };\n }\n }\n\n private async requireGitRepo(mode: WorkspaceMode): Promise<void> {\n if (!this.gitRepoChecked) {\n try {\n const { process: proc } = this.processManager.spawn(\n 'git',\n ['rev-parse', '--is-inside-work-tree'],\n { cwd: this.projectRoot },\n );\n const code = await new Promise<number | null>((resolve) => {\n proc.on('close', resolve);\n proc.on('error', () => resolve(1));\n });\n this.isGitRepo = code === 0;\n } catch {\n this.isGitRepo = false;\n }\n // Only cache positive result — negative may change if user runs git init\n if (this.isGitRepo) this.gitRepoChecked = true;\n }\n\n if (!this.isGitRepo) {\n throw new WorkspaceError(\n `workspace_mode \"${mode}\" requires a git repository`,\n 'Run: git init && git add -A && git commit -m \"Initial commit\"\\n Or set workspace_mode: shared in .orchestry/config.yml',\n );\n }\n }\n\n async mergeBack(branch: string): Promise<MergeResult> {\n return this.mergeStrategy.mergeBack(branch);\n }\n\n async cleanup(taskId: string): Promise<void> {\n const workspacePath = path.join(this.orchestryDir, 'workspaces', sanitizeId(taskId));\n\n // Try git worktree remove first (cleans up .git/worktrees/ metadata)\n try {\n const { process: proc } = this.processManager.spawn(\n 'git',\n ['worktree', 'remove', '--force', workspacePath],\n { cwd: this.projectRoot },\n );\n await new Promise<void>((resolve) => {\n proc.on('close', () => resolve());\n proc.on('error', () => resolve());\n });\n } catch {\n // Not a worktree or git not available — fall through to rm\n }\n\n // Remove directory regardless (handles isolated mode and worktree cleanup failures)\n try {\n await fs.rm(workspacePath, { recursive: true, force: true });\n } catch {\n // Workspace may not exist\n }\n }\n\n validate(workspacePath: string, projectRoot: string): void {\n validateWorkspacePath(workspacePath, projectRoot);\n }\n\n private resolveMode(task: Task, agent: Agent, config: OrchestratorConfig): WorkspaceMode {\n return (\n task.workspace_mode ??\n agent.config.workspace_mode ??\n config.defaults.agent.workspace_mode ??\n 'worktree'\n );\n }\n\n private async prepareWorktree(task: Task): Promise<PrepareResult> {\n const workspacePath = path.join(\n this.orchestryDir,\n 'workspaces',\n sanitizeId(task.id),\n );\n await ensureDir(path.dirname(workspacePath));\n\n const titleSlug = sanitizeTitle(task.title) || sanitizeId(task.id);\n const branchName = `orchestry/${sanitizeId(task.id)}/${titleSlug}`;\n\n const { process: proc } = this.processManager.spawn(\n 'git',\n ['worktree', 'add', workspacePath, '-b', branchName],\n { cwd: this.projectRoot },\n );\n\n await new Promise<void>((resolve, reject) => {\n proc.on('close', (code) => {\n if (code === 0) resolve();\n else reject(new Error(`git worktree add failed with code ${code}`));\n });\n proc.on('error', reject);\n });\n\n // Remove .orchestry/ from worktree to prevent recursive state/workspaces\n const worktreeOrchestry = path.join(workspacePath, '.orchestry');\n await fs.rm(worktreeOrchestry, { recursive: true, force: true }).catch(() => {});\n\n return { path: workspacePath, branch: branchName };\n }\n\n private async prepareIsolated(task: Task): Promise<string> {\n const workspacePath = path.join(\n this.orchestryDir,\n 'workspaces',\n sanitizeId(task.id),\n );\n await ensureDir(path.dirname(workspacePath));\n\n // Try git clone first, fall back to rsync\n try {\n const { process: proc } = this.processManager.spawn(\n 'git',\n ['clone', '--local', '--no-hardlinks', '.', workspacePath],\n { cwd: this.projectRoot },\n );\n\n await new Promise<void>((resolve, reject) => {\n proc.on('close', (code) => {\n if (code === 0) resolve();\n else reject(new Error('git clone failed'));\n });\n proc.on('error', reject);\n });\n } catch {\n // Fallback: rsync\n const excludeFile = path.join(this.orchestryDir, 'workspace-exclude');\n const args = ['-a', `--exclude-from=${excludeFile}`, './', `${workspacePath}/`];\n\n const { process: proc } = this.processManager.spawn('rsync', args, {\n cwd: this.projectRoot,\n });\n\n await new Promise<void>((resolve, reject) => {\n proc.on('close', (code) => {\n if (code === 0) resolve();\n else reject(new Error(`rsync failed with code ${code}`));\n });\n proc.on('error', reject);\n });\n }\n\n // Remove .orchestry/ to prevent recursive workspaces (covers both clone and rsync)\n const clonedOrchestry = path.join(workspacePath, '.orchestry');\n await fs.rm(clonedOrchestry, { recursive: true, force: true }).catch(() => {});\n\n return workspacePath;\n }\n}\n\nfunction sanitizeTitle(title: string): string {\n return title\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-|-$/g, '')\n .slice(0, 40);\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/infrastructure/workspace/merge-strategy.ts","../src/infrastructure/workspace/workspace-manager.ts"],"names":[],"mappings":"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","file":"workspace-manager-ABXFBL2A.js","sourcesContent":["/**\n * Git merge strategy for worktree branches.\n *\n * Encapsulates `git merge --no-ff` execution and conflict handling.\n */\n\nimport type { IProcessManager } from '../process/process-manager.js';\n\nexport type MergeResult =\n | { success: true }\n | { success: false; conflictInfo: string };\n\nexport class MergeStrategy {\n constructor(\n private readonly projectRoot: string,\n private readonly processManager: IProcessManager,\n ) {}\n\n /**\n * Merge a branch into the current branch with --no-ff.\n * On conflict, aborts the merge and returns conflict info.\n */\n async mergeBack(branch: string): Promise<MergeResult> {\n return new Promise((resolve) => {\n const { process: proc } = this.processManager.spawn(\n 'git',\n ['merge', '--no-ff', branch, '-m', `Merge ${branch}`],\n { cwd: this.projectRoot },\n );\n\n let output = '';\n const maxOutputLen = 2000;\n const appendOutput = (chunk: Buffer) => {\n if (output.length < maxOutputLen) output += chunk.toString();\n };\n proc.stdout?.on('data', appendOutput);\n proc.stderr?.on('data', appendOutput);\n\n proc.on('close', (code) => {\n if (code === 0) {\n resolve({ success: true });\n return;\n }\n\n const trimmedOutput = output.slice(0, 1000);\n const isConflict = trimmedOutput.includes('CONFLICT') || trimmedOutput.includes('Merge conflict');\n\n if (!isConflict) {\n // Non-conflict failure (branch not found, hook failure, etc.) — no merge to abort\n resolve({ success: false, conflictInfo: trimmedOutput });\n return;\n }\n\n // Abort the failed merge to restore clean state\n try {\n const { process: abortProc } = this.processManager.spawn(\n 'git',\n ['merge', '--abort'],\n { cwd: this.projectRoot },\n );\n abortProc.on('close', () => {\n resolve({ success: false, conflictInfo: trimmedOutput });\n });\n abortProc.on('error', () => {\n resolve({ success: false, conflictInfo: trimmedOutput });\n });\n } catch {\n resolve({ success: false, conflictInfo: trimmedOutput });\n }\n });\n\n proc.on('error', (err) => {\n resolve({ success: false, conflictInfo: err.message });\n });\n });\n }\n}\n","/**\n * Workspace manager implementation.\n *\n * Resolves workspace path based on mode priority chain:\n * task.workspace_mode → agent.config.workspace_mode → defaults.agent.workspace_mode → 'worktree'\n */\n\nimport path from 'node:path';\nimport fs from 'node:fs/promises';\nimport type { Agent } from '../../domain/agent.js';\nimport type { OrchestratorConfig } from '../../domain/config.js';\nimport type { Task, WorkspaceMode } from '../../domain/task.js';\nimport type { IProcessManager } from '../process/process-manager.js';\nimport { validateWorkspacePath, sanitizeId } from '../storage/paths.js';\nimport { ensureDir } from '../storage/fs-utils.js';\nimport type { IWorkspaceManager, PrepareResult } from './interface.js';\nimport { MergeStrategy, type MergeResult } from './merge-strategy.js';\nimport { WorkspaceError } from '../../domain/errors.js';\n\nexport class WorkspaceManager implements IWorkspaceManager {\n private readonly mergeStrategy: MergeStrategy;\n private gitRepoChecked = false;\n private isGitRepo = false;\n\n constructor(\n private readonly projectRoot: string,\n private readonly orchestryDir: string,\n private readonly processManager: IProcessManager,\n ) {\n this.mergeStrategy = new MergeStrategy(projectRoot, processManager);\n }\n\n async prepare(task: Task, agent: Agent, config: OrchestratorConfig): Promise<PrepareResult> {\n const mode = this.resolveMode(task, agent, config);\n\n if (mode !== 'shared') {\n await this.requireGitRepo(mode);\n }\n\n switch (mode) {\n case 'shared':\n return { path: this.projectRoot };\n\n case 'worktree':\n return this.prepareWorktree(task);\n\n case 'isolated':\n return { path: await this.prepareIsolated(task) };\n\n default:\n return { path: this.projectRoot };\n }\n }\n\n private async requireGitRepo(mode: WorkspaceMode): Promise<void> {\n if (!this.gitRepoChecked) {\n try {\n const { process: proc } = this.processManager.spawn(\n 'git',\n ['rev-parse', '--is-inside-work-tree'],\n { cwd: this.projectRoot },\n );\n const code = await new Promise<number | null>((resolve) => {\n proc.on('close', resolve);\n proc.on('error', () => resolve(1));\n });\n this.isGitRepo = code === 0;\n } catch {\n this.isGitRepo = false;\n }\n // Only cache positive result — negative may change if user runs git init\n if (this.isGitRepo) this.gitRepoChecked = true;\n }\n\n if (!this.isGitRepo) {\n throw new WorkspaceError(\n `workspace_mode \"${mode}\" requires a git repository`,\n 'Run: git init && git add -A && git commit -m \"Initial commit\"\\n Or set workspace_mode: shared in .orchestry/config.yml',\n );\n }\n }\n\n async mergeBack(branch: string): Promise<MergeResult> {\n return this.mergeStrategy.mergeBack(branch);\n }\n\n async cleanup(taskId: string): Promise<void> {\n const workspacePath = path.join(this.orchestryDir, 'workspaces', sanitizeId(taskId));\n\n // Try git worktree remove first (cleans up .git/worktrees/ metadata)\n try {\n const { process: proc } = this.processManager.spawn(\n 'git',\n ['worktree', 'remove', '--force', workspacePath],\n { cwd: this.projectRoot },\n );\n await new Promise<void>((resolve) => {\n proc.on('close', () => resolve());\n proc.on('error', () => resolve());\n });\n } catch {\n // Not a worktree or git not available — fall through to rm\n }\n\n // Remove directory regardless (handles isolated mode and worktree cleanup failures)\n try {\n await fs.rm(workspacePath, { recursive: true, force: true });\n } catch {\n // Workspace may not exist\n }\n }\n\n validate(workspacePath: string, projectRoot: string): void {\n validateWorkspacePath(workspacePath, projectRoot);\n }\n\n private resolveMode(task: Task, agent: Agent, config: OrchestratorConfig): WorkspaceMode {\n return (\n task.workspace_mode ??\n agent.config.workspace_mode ??\n config.defaults.agent.workspace_mode ??\n 'worktree'\n );\n }\n\n private async prepareWorktree(task: Task): Promise<PrepareResult> {\n const workspacePath = path.join(\n this.orchestryDir,\n 'workspaces',\n sanitizeId(task.id),\n );\n await ensureDir(path.dirname(workspacePath));\n\n const titleSlug = sanitizeTitle(task.title) || sanitizeId(task.id);\n const branchName = `orchestry/${sanitizeId(task.id)}/${titleSlug}`;\n\n const { process: proc } = this.processManager.spawn(\n 'git',\n ['worktree', 'add', workspacePath, '-b', branchName],\n { cwd: this.projectRoot },\n );\n\n await new Promise<void>((resolve, reject) => {\n proc.on('close', (code) => {\n if (code === 0) resolve();\n else reject(new Error(`git worktree add failed with code ${code}`));\n });\n proc.on('error', reject);\n });\n\n // Remove .orchestry/ from worktree to prevent recursive state/workspaces\n const worktreeOrchestry = path.join(workspacePath, '.orchestry');\n await fs.rm(worktreeOrchestry, { recursive: true, force: true }).catch(() => {});\n\n return { path: workspacePath, branch: branchName };\n }\n\n private async prepareIsolated(task: Task): Promise<string> {\n const workspacePath = path.join(\n this.orchestryDir,\n 'workspaces',\n sanitizeId(task.id),\n );\n await ensureDir(path.dirname(workspacePath));\n\n // Try git clone first, fall back to rsync\n try {\n const { process: proc } = this.processManager.spawn(\n 'git',\n ['clone', '--local', '--no-hardlinks', '.', workspacePath],\n { cwd: this.projectRoot },\n );\n\n await new Promise<void>((resolve, reject) => {\n proc.on('close', (code) => {\n if (code === 0) resolve();\n else reject(new Error('git clone failed'));\n });\n proc.on('error', reject);\n });\n } catch {\n // Fallback: rsync\n const excludeFile = path.join(this.orchestryDir, 'workspace-exclude');\n const args = ['-a', `--exclude-from=${excludeFile}`, './', `${workspacePath}/`];\n\n const { process: proc } = this.processManager.spawn('rsync', args, {\n cwd: this.projectRoot,\n });\n\n await new Promise<void>((resolve, reject) => {\n proc.on('close', (code) => {\n if (code === 0) resolve();\n else reject(new Error(`rsync failed with code ${code}`));\n });\n proc.on('error', reject);\n });\n }\n\n // Remove .orchestry/ to prevent recursive workspaces (covers both clone and rsync)\n const clonedOrchestry = path.join(workspacePath, '.orchestry');\n await fs.rm(clonedOrchestry, { recursive: true, force: true }).catch(() => {});\n\n return workspacePath;\n }\n}\n\nfunction sanitizeTitle(title: string): string {\n return title\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-|-$/g, '')\n .slice(0, 40);\n}\n"]}
|