@oxgeneral/orch 0.3.4 → 1.0.1
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-RKAPZNZO.js → App-GJVTVGRU.js} +55 -20
- package/dist/{agent-KBTLGGCT.js → agent-7ZJ3ZDJ7.js} +1 -1
- package/dist/{chunk-D6RFF3KN.js → chunk-4IFIOMCW.js} +4 -3
- package/dist/{chunk-S3QYSBW4.js → chunk-C6XZ3FJT.js} +6 -3
- package/dist/chunk-C6XZ3FJT.js.map +1 -0
- package/dist/{chunk-W6RSVMXR.js → chunk-MGGSRXWJ.js} +5 -2
- package/dist/{chunk-VMDQVRBR.js → chunk-O2OQCSBL.js} +40 -16
- package/dist/chunk-O2OQCSBL.js.map +1 -0
- package/dist/{chunk-B4JQM4NU.js → chunk-VG4465AG.js} +119 -45
- package/dist/chunk-VG4465AG.js.map +1 -0
- package/dist/{chunk-A36WAF2S.js → chunk-VXS2CJFH.js} +117 -43
- package/dist/{chunk-52BFUGDD.js → chunk-XJTJ2TJV.js} +3 -2
- package/dist/{claude-INM52PTH.js → claude-WUJU5KIE.js} +6 -5
- package/dist/claude-WUJU5KIE.js.map +1 -0
- package/dist/claude-ZUEKJJ4X.js +5 -0
- package/dist/cli.js +10 -10
- package/dist/{codex-DIXT44JR.js → codex-7IXXXG5U.js} +3 -3
- package/dist/{codex-QGH2GRV6.js → codex-NYJWEPRQ.js} +4 -4
- package/dist/codex-NYJWEPRQ.js.map +1 -0
- package/dist/{container-LJU4QNDH.js → container-RY54L3XC.js} +12 -10
- package/dist/{cursor-KQJTQ73D.js → cursor-3YHVD4NP.js} +4 -4
- package/dist/cursor-3YHVD4NP.js.map +1 -0
- package/dist/{cursor-C3TR2IJC.js → cursor-622RBRHH.js} +3 -3
- package/dist/{doctor-V2FPS236.js → doctor-XSGQSD57.js} +5 -5
- package/dist/index.d.ts +4 -1
- package/dist/index.js +15 -13
- package/dist/index.js.map +1 -1
- package/dist/{init-U7MCIOB2.js → init-45BEMVL6.js} +38 -4
- package/dist/opencode-FAMPSA6X.js +100 -0
- package/dist/opencode-FAMPSA6X.js.map +1 -0
- package/dist/opencode-WOR53TSC.js +98 -0
- package/dist/{orchestrator-E3FQ4SOE.js → orchestrator-O6MFMATT.js} +38 -14
- package/dist/orchestrator-X2CWGFCL.js +5 -0
- package/dist/{orchestrator-ADO66XZ3.js.map → orchestrator-X2CWGFCL.js.map} +1 -1
- package/dist/shell-DVFHHYAZ.js +5 -0
- package/dist/{shell-JXOPKDXH.js → shell-NJNW3O6K.js} +5 -3
- package/dist/shell-NJNW3O6K.js.map +1 -0
- package/dist/{task-2TJW6Z7O.js → task-5EL2RNGW.js} +1 -1
- package/dist/template-engine-5ZKVJMYA.js +3 -0
- package/dist/{template-engine-MFL5B677.js.map → template-engine-5ZKVJMYA.js.map} +1 -1
- package/dist/template-engine-AWIS56BL.js +3 -0
- package/dist/{tui-IM3YUUVD.js → tui-LN5XHSQY.js} +1 -1
- package/package.json +14 -10
- package/readme.md +208 -152
- package/scripts/load-test.ts +478 -0
- package/dist/chunk-B4JQM4NU.js.map +0 -1
- package/dist/chunk-S3QYSBW4.js.map +0 -1
- package/dist/chunk-VMDQVRBR.js.map +0 -1
- package/dist/claude-INM52PTH.js.map +0 -1
- package/dist/claude-NHUNA5RZ.js +0 -5
- package/dist/codex-QGH2GRV6.js.map +0 -1
- package/dist/cursor-KQJTQ73D.js.map +0 -1
- package/dist/orchestrator-ADO66XZ3.js +0 -5
- package/dist/shell-3S4VLYEG.js +0 -4
- package/dist/shell-JXOPKDXH.js.map +0 -1
- package/dist/template-engine-4IZKRRHG.js +0 -3
- package/dist/template-engine-MFL5B677.js +0 -3
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { DEFAULT_PROMPT_TEMPLATE } from './chunk-
|
|
2
|
+
import { DEFAULT_PROMPT_TEMPLATE } from './chunk-VXS2CJFH.js';
|
|
3
3
|
import { DEFAULT_CONFIG } from './chunk-I3SMISEF.js';
|
|
4
4
|
import './chunk-PNE6LQRF.js';
|
|
5
|
-
import { printWarning, printSuccess, dim } from './chunk-7X2GI5OV.js';
|
|
6
5
|
import { Paths, pathExists, ensureDir, writeYaml, atomicWrite } from './chunk-LV6GDBBI.js';
|
|
6
|
+
import { printWarning, printSuccess, dim } from './chunk-7X2GI5OV.js';
|
|
7
7
|
import './chunk-2C2TFQ7K.js';
|
|
8
8
|
import path from 'path';
|
|
9
9
|
import fs from 'fs/promises';
|
|
10
|
+
import { execFile } from 'child_process';
|
|
11
|
+
import { promisify } from 'util';
|
|
10
12
|
|
|
11
13
|
// src/domain/default-agents.ts
|
|
12
14
|
var AGENT_CREATOR_ROLE = `Agent architect \u2014 designs and creates AI agents for the orchestrator via \`orch agent add\`.
|
|
@@ -23,7 +25,7 @@ var AGENT_CREATOR_ROLE = `Agent architect \u2014 designs and creates AI agents f
|
|
|
23
25
|
Do NOT include CLI documentation or goal-mode instructions \u2014 these are already injected by the system prompt template.
|
|
24
26
|
|
|
25
27
|
3) CHOOSE CONFIGURATION:
|
|
26
|
-
- adapter: \`claude\` (AI tasks), \`shell\` (bash scripts), \`codex\` (OpenAI Codex), \`cursor\` (Cursor IDE)
|
|
28
|
+
- adapter: \`claude\` (AI tasks), \`shell\` (bash scripts), \`codex\` (OpenAI Codex), \`cursor\` (Cursor IDE), \`opencode\` (OpenCode \u2014 multi-provider)
|
|
27
29
|
- model: \`claude-opus-4-6\` (complex/architectural), \`claude-sonnet-4-6\` (fast/routine), \`claude-haiku-4-5-20251001\` (simple/templated)
|
|
28
30
|
- approval_policy: \`auto\` (no confirmation) / \`suggest\` (proposes actions) / \`manual\` (human approval)
|
|
29
31
|
- max_turns: 50 (default), up to 100 for complex tasks
|
|
@@ -76,6 +78,7 @@ function getDefaultAgents() {
|
|
|
76
78
|
}
|
|
77
79
|
|
|
78
80
|
// src/cli/commands/init.ts
|
|
81
|
+
var execFileAsync = promisify(execFile);
|
|
79
82
|
async function runInit(opts = {}) {
|
|
80
83
|
const projectRoot = process.cwd();
|
|
81
84
|
const paths = new Paths(projectRoot);
|
|
@@ -91,8 +94,12 @@ async function runInit(opts = {}) {
|
|
|
91
94
|
ensureDir(paths.templatesDir),
|
|
92
95
|
ensureDir(paths.logsDir)
|
|
93
96
|
]);
|
|
94
|
-
const
|
|
97
|
+
const gitAvailable = await ensureGitRepo(projectRoot);
|
|
98
|
+
const config = structuredClone(DEFAULT_CONFIG);
|
|
95
99
|
config.project.name = opts.name ?? path.basename(projectRoot);
|
|
100
|
+
if (!gitAvailable) {
|
|
101
|
+
config.defaults.agent.workspace_mode = "shared";
|
|
102
|
+
}
|
|
96
103
|
const gitignoreContent = [
|
|
97
104
|
"# Runtime state",
|
|
98
105
|
"state.json",
|
|
@@ -126,6 +133,9 @@ async function runInit(opts = {}) {
|
|
|
126
133
|
...defaultAgents.map((agent) => writeYaml(paths.agentPath(agent.id), agent))
|
|
127
134
|
]);
|
|
128
135
|
await ensureRootGitignore(projectRoot);
|
|
136
|
+
if (gitAvailable) {
|
|
137
|
+
await ensureGitCommit(projectRoot);
|
|
138
|
+
}
|
|
129
139
|
console.log();
|
|
130
140
|
printSuccess("initialized");
|
|
131
141
|
console.log();
|
|
@@ -140,6 +150,30 @@ async function runInit(opts = {}) {
|
|
|
140
150
|
console.log(` ${dim("\u2514\u2500\u2500")} .gitignore`);
|
|
141
151
|
console.log();
|
|
142
152
|
}
|
|
153
|
+
async function ensureGitRepo(projectRoot) {
|
|
154
|
+
try {
|
|
155
|
+
await execFileAsync("git", ["rev-parse", "--is-inside-work-tree"], { cwd: projectRoot });
|
|
156
|
+
return true;
|
|
157
|
+
} catch {
|
|
158
|
+
try {
|
|
159
|
+
await execFileAsync("git", ["init"], { cwd: projectRoot });
|
|
160
|
+
return true;
|
|
161
|
+
} catch {
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
async function ensureGitCommit(projectRoot) {
|
|
167
|
+
try {
|
|
168
|
+
await execFileAsync("git", ["rev-parse", "HEAD"], { cwd: projectRoot });
|
|
169
|
+
} catch {
|
|
170
|
+
try {
|
|
171
|
+
await execFileAsync("git", ["add", "-A"], { cwd: projectRoot });
|
|
172
|
+
await execFileAsync("git", ["commit", "-m", "Initial commit", "--allow-empty"], { cwd: projectRoot });
|
|
173
|
+
} catch {
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
143
177
|
async function ensureRootGitignore(projectRoot) {
|
|
144
178
|
const gitignorePath = path.join(projectRoot, ".gitignore");
|
|
145
179
|
try {
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { buildFullPrompt, createStreamingEvents } from './chunk-C6XZ3FJT.js';
|
|
2
|
+
import { createTokenUsage } from './chunk-XDVMX2FO.js';
|
|
3
|
+
import { classifyAdapterError } from './chunk-NLQAJ7TW.js';
|
|
4
|
+
import './chunk-O2MSGW3V.js';
|
|
5
|
+
import { execFile } from 'child_process';
|
|
6
|
+
import { promisify } from 'util';
|
|
7
|
+
|
|
8
|
+
var execFileAsync = promisify(execFile);
|
|
9
|
+
var OpenCodeAdapter = class {
|
|
10
|
+
constructor(processManager) {
|
|
11
|
+
this.processManager = processManager;
|
|
12
|
+
}
|
|
13
|
+
kind = "opencode";
|
|
14
|
+
async test() {
|
|
15
|
+
try {
|
|
16
|
+
const { stdout } = await execFileAsync("opencode", ["--version"]);
|
|
17
|
+
return { ok: true, version: stdout.trim() };
|
|
18
|
+
} catch (err) {
|
|
19
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
20
|
+
return {
|
|
21
|
+
ok: false,
|
|
22
|
+
error: "OpenCode CLI not found. Install: npm i -g opencode",
|
|
23
|
+
errorKind: classifyAdapterError(msg)
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
execute(params) {
|
|
28
|
+
const args = [
|
|
29
|
+
"run",
|
|
30
|
+
"--format",
|
|
31
|
+
"json"
|
|
32
|
+
];
|
|
33
|
+
if (params.config.model) {
|
|
34
|
+
args.push("--model", params.config.model);
|
|
35
|
+
}
|
|
36
|
+
const fullPrompt = buildFullPrompt(params.systemPrompt, params.prompt);
|
|
37
|
+
args.push(fullPrompt);
|
|
38
|
+
const { process: proc, pid } = this.processManager.spawn("opencode", args, {
|
|
39
|
+
cwd: params.workspace,
|
|
40
|
+
env: { ...process.env, ...params.env },
|
|
41
|
+
signal: params.signal
|
|
42
|
+
});
|
|
43
|
+
const events = createStreamingEvents(proc, parseOpenCodeEvent, "OpenCode", params.signal);
|
|
44
|
+
return { pid, events };
|
|
45
|
+
}
|
|
46
|
+
async stop(pid) {
|
|
47
|
+
await this.processManager.killWithGrace(pid);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
function parseOpenCodeEvent(line) {
|
|
51
|
+
if (!line.trim()) return null;
|
|
52
|
+
try {
|
|
53
|
+
const parsed = JSON.parse(line);
|
|
54
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
55
|
+
const type = parsed.type ?? "";
|
|
56
|
+
const part = parsed.part ?? {};
|
|
57
|
+
switch (type) {
|
|
58
|
+
case "step_start":
|
|
59
|
+
return null;
|
|
60
|
+
// lifecycle event — no user-visible content
|
|
61
|
+
case "text":
|
|
62
|
+
return { type: "output", timestamp, data: part.text ?? part };
|
|
63
|
+
case "tool_use": {
|
|
64
|
+
const state = part.state ?? {};
|
|
65
|
+
if (state.status === "error") {
|
|
66
|
+
const errMsg = typeof state.error === "string" ? state.error : JSON.stringify(state);
|
|
67
|
+
return { type: "error", timestamp, data: state, errorKind: classifyAdapterError(errMsg) };
|
|
68
|
+
}
|
|
69
|
+
return { type: "tool_call", timestamp, data: { name: part.tool, input: state.input } };
|
|
70
|
+
}
|
|
71
|
+
case "step_finish": {
|
|
72
|
+
const reason = part.reason;
|
|
73
|
+
const tokens = extractOpenCodeTokens(part);
|
|
74
|
+
if (reason === "error") {
|
|
75
|
+
const errMsg = typeof part.error === "string" ? part.error : JSON.stringify(part);
|
|
76
|
+
return { type: "error", timestamp, data: part, tokens, errorKind: classifyAdapterError(errMsg) };
|
|
77
|
+
}
|
|
78
|
+
if (reason === "tool-calls") {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
return { type: "done", timestamp, data: part, tokens };
|
|
82
|
+
}
|
|
83
|
+
default:
|
|
84
|
+
return { type: "output", timestamp, data: parsed };
|
|
85
|
+
}
|
|
86
|
+
} catch {
|
|
87
|
+
return { type: "output", timestamp: (/* @__PURE__ */ new Date()).toISOString(), data: line };
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function extractOpenCodeTokens(part) {
|
|
91
|
+
const tokens = part.tokens;
|
|
92
|
+
if (!tokens || typeof tokens.input !== "number") return void 0;
|
|
93
|
+
const input = tokens.input;
|
|
94
|
+
const output = typeof tokens.output === "number" ? tokens.output : 0;
|
|
95
|
+
return createTokenUsage(input, output);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export { OpenCodeAdapter };
|
|
99
|
+
//# sourceMappingURL=opencode-FAMPSA6X.js.map
|
|
100
|
+
//# sourceMappingURL=opencode-FAMPSA6X.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/infrastructure/adapters/opencode.ts"],"names":[],"mappings":";;;;;;;AAeA,IAAM,aAAA,GAAgB,UAAU,QAAQ,CAAA;AAEjC,IAAM,kBAAN,MAA+C;AAAA,EAGpD,YAA6B,cAAA,EAAiC;AAAjC,IAAA,IAAA,CAAA,cAAA,GAAA,cAAA;AAAA,EAAkC;AAAA,EAFtD,IAAA,GAAO,UAAA;AAAA,EAIhB,MAAM,IAAA,GAAmC;AACvC,IAAA,IAAI;AACF,MAAA,MAAM,EAAE,QAAO,GAAI,MAAM,cAAc,UAAA,EAAY,CAAC,WAAW,CAAC,CAAA;AAChE,MAAA,OAAO,EAAE,EAAA,EAAI,IAAA,EAAM,OAAA,EAAS,MAAA,CAAO,MAAK,EAAE;AAAA,IAC5C,SAAS,GAAA,EAAK;AACZ,MAAA,MAAM,MAAM,GAAA,YAAe,KAAA,GAAQ,GAAA,CAAI,OAAA,GAAU,OAAO,GAAG,CAAA;AAC3D,MAAA,OAAO;AAAA,QACL,EAAA,EAAI,KAAA;AAAA,QACJ,KAAA,EAAO,oDAAA;AAAA,QACP,SAAA,EAAW,qBAAqB,GAAG;AAAA,OACrC;AAAA,IACF;AAAA,EACF;AAAA,EAEA,QAAQ,MAAA,EAAsC;AAC5C,IAAA,MAAM,IAAA,GAAO;AAAA,MACX,KAAA;AAAA,MACA,UAAA;AAAA,MAAY;AAAA,KACd;AAEA,IAAA,IAAI,MAAA,CAAO,OAAO,KAAA,EAAO;AACvB,MAAA,IAAA,CAAK,IAAA,CAAK,SAAA,EAAW,MAAA,CAAO,MAAA,CAAO,KAAK,CAAA;AAAA,IAC1C;AAGA,IAAA,MAAM,UAAA,GAAa,eAAA,CAAgB,MAAA,CAAO,YAAA,EAAc,OAAO,MAAM,CAAA;AACrE,IAAA,IAAA,CAAK,KAAK,UAAU,CAAA;AAEpB,IAAA,MAAM,EAAE,SAAS,IAAA,EAAM,GAAA,KAAQ,IAAA,CAAK,cAAA,CAAe,KAAA,CAAM,UAAA,EAAY,IAAA,EAAM;AAAA,MACzE,KAAK,MAAA,CAAO,SAAA;AAAA,MACZ,KAAK,EAAE,GAAG,QAAQ,GAAA,EAAK,GAAG,OAAO,GAAA,EAAI;AAAA,MACrC,QAAQ,MAAA,CAAO;AAAA,KAChB,CAAA;AAED,IAAA,MAAM,SAAS,qBAAA,CAAsB,IAAA,EAAM,kBAAA,EAAoB,UAAA,EAAY,OAAO,MAAM,CAAA;AAExF,IAAA,OAAO,EAAE,KAAK,MAAA,EAAO;AAAA,EACvB;AAAA,EAEA,MAAM,KAAK,GAAA,EAA4B;AACrC,IAAA,MAAM,IAAA,CAAK,cAAA,CAAe,aAAA,CAAc,GAAG,CAAA;AAAA,EAC7C;AACF;AAEA,SAAS,mBAAmB,IAAA,EAAiC;AAC3D,EAAA,IAAI,CAAC,IAAA,CAAK,IAAA,EAAK,EAAG,OAAO,IAAA;AAEzB,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,GAAkC,IAAA,CAAK,KAAA,CAAM,IAAI,CAAA;AACvD,IAAA,MAAM,SAAA,GAAA,iBAAY,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AACzC,IAAA,MAAM,IAAA,GAAQ,OAAO,IAAA,IAAmB,EAAA;AACxC,IAAA,MAAM,IAAA,GAAQ,MAAA,CAAO,IAAA,IAAoC,EAAC;AAE1D,IAAA,QAAQ,IAAA;AAAM,MACZ,KAAK,YAAA;AACH,QAAA,OAAO,IAAA;AAAA;AAAA,MAET,KAAK,MAAA;AACH,QAAA,OAAO,EAAE,IAAA,EAAM,QAAA,EAAU,WAAW,IAAA,EAAM,IAAA,CAAK,QAAQ,IAAA,EAAK;AAAA,MAE9D,KAAK,UAAA,EAAY;AACf,QAAA,MAAM,KAAA,GAAS,IAAA,CAAK,KAAA,IAAqC,EAAC;AAC1D,QAAA,IAAI,KAAA,CAAM,WAAW,OAAA,EAAS;AAC5B,UAAA,MAAM,MAAA,GAAS,OAAO,KAAA,CAAM,KAAA,KAAU,WAAW,KAAA,CAAM,KAAA,GAAQ,IAAA,CAAK,SAAA,CAAU,KAAK,CAAA;AACnF,UAAA,OAAO,EAAE,MAAM,OAAA,EAAS,SAAA,EAAW,MAAM,KAAA,EAAO,SAAA,EAAW,oBAAA,CAAqB,MAAM,CAAA,EAAE;AAAA,QAC1F;AAEA,QAAA,OAAO,EAAE,IAAA,EAAM,WAAA,EAAa,SAAA,EAAW,IAAA,EAAM,EAAE,IAAA,EAAM,IAAA,CAAK,IAAA,EAAM,KAAA,EAAO,KAAA,CAAM,KAAA,EAAM,EAAE;AAAA,MACvF;AAAA,MAEA,KAAK,aAAA,EAAe;AAClB,QAAA,MAAM,SAAS,IAAA,CAAK,MAAA;AACpB,QAAA,MAAM,MAAA,GAAS,sBAAsB,IAAI,CAAA;AAEzC,QAAA,IAAI,WAAW,OAAA,EAAS;AACtB,UAAA,MAAM,MAAA,GAAS,OAAO,IAAA,CAAK,KAAA,KAAU,WAAW,IAAA,CAAK,KAAA,GAAQ,IAAA,CAAK,SAAA,CAAU,IAAI,CAAA;AAChF,UAAA,OAAO,EAAE,IAAA,EAAM,OAAA,EAAS,SAAA,EAAW,IAAA,EAAM,MAAM,MAAA,EAAQ,SAAA,EAAW,oBAAA,CAAqB,MAAM,CAAA,EAAE;AAAA,QACjG;AACA,QAAA,IAAI,WAAW,YAAA,EAAc;AAC3B,UAAA,OAAO,IAAA;AAAA,QACT;AAEA,QAAA,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,SAAA,EAAW,IAAA,EAAM,MAAM,MAAA,EAAO;AAAA,MACvD;AAAA,MAEA;AACE,QAAA,OAAO,EAAE,IAAA,EAAM,QAAA,EAAU,SAAA,EAAW,MAAM,MAAA,EAAO;AAAA;AACrD,EACF,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,EAAE,IAAA,EAAM,QAAA,EAAU,SAAA,EAAA,iBAAW,IAAI,MAAK,EAAE,WAAA,EAAY,EAAG,IAAA,EAAM,IAAA,EAAK;AAAA,EAC3E;AACF;AAGA,SAAS,sBAAsB,IAAA,EAA6F;AAC1H,EAAA,MAAM,SAAS,IAAA,CAAK,MAAA;AACpB,EAAA,IAAI,CAAC,MAAA,IAAU,OAAO,MAAA,CAAO,KAAA,KAAU,UAAU,OAAO,MAAA;AAExD,EAAA,MAAM,QAAQ,MAAA,CAAO,KAAA;AACrB,EAAA,MAAM,SAAS,OAAO,MAAA,CAAO,MAAA,KAAW,QAAA,GAAW,OAAO,MAAA,GAAS,CAAA;AACnE,EAAA,OAAO,gBAAA,CAAiB,OAAO,MAAM,CAAA;AACvC","file":"opencode-FAMPSA6X.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>): { input: number; output: number; total: number } | 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 return createTokenUsage(input, output);\n}\n"]}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { buildFullPrompt, createStreamingEvents, createTokenUsage } from './chunk-MGGSRXWJ.js';
|
|
3
|
+
import { classifyAdapterError } from './chunk-2C2TFQ7K.js';
|
|
4
|
+
import './chunk-CHIP7O6V.js';
|
|
5
|
+
import { execFile } from 'child_process';
|
|
6
|
+
import { promisify } from 'util';
|
|
7
|
+
|
|
8
|
+
var execFileAsync = promisify(execFile);
|
|
9
|
+
var OpenCodeAdapter = class {
|
|
10
|
+
constructor(processManager) {
|
|
11
|
+
this.processManager = processManager;
|
|
12
|
+
}
|
|
13
|
+
kind = "opencode";
|
|
14
|
+
async test() {
|
|
15
|
+
try {
|
|
16
|
+
const { stdout } = await execFileAsync("opencode", ["--version"]);
|
|
17
|
+
return { ok: true, version: stdout.trim() };
|
|
18
|
+
} catch (err) {
|
|
19
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
20
|
+
return {
|
|
21
|
+
ok: false,
|
|
22
|
+
error: "OpenCode CLI not found. Install: npm i -g opencode",
|
|
23
|
+
errorKind: classifyAdapterError(msg)
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
execute(params) {
|
|
28
|
+
const args = [
|
|
29
|
+
"run",
|
|
30
|
+
"--format",
|
|
31
|
+
"json"
|
|
32
|
+
];
|
|
33
|
+
if (params.config.model) {
|
|
34
|
+
args.push("--model", params.config.model);
|
|
35
|
+
}
|
|
36
|
+
const fullPrompt = buildFullPrompt(params.systemPrompt, params.prompt);
|
|
37
|
+
args.push(fullPrompt);
|
|
38
|
+
const { process: proc, pid } = this.processManager.spawn("opencode", args, {
|
|
39
|
+
cwd: params.workspace,
|
|
40
|
+
env: { ...process.env, ...params.env },
|
|
41
|
+
signal: params.signal
|
|
42
|
+
});
|
|
43
|
+
const events = createStreamingEvents(proc, parseOpenCodeEvent, "OpenCode", params.signal);
|
|
44
|
+
return { pid, events };
|
|
45
|
+
}
|
|
46
|
+
async stop(pid) {
|
|
47
|
+
await this.processManager.killWithGrace(pid);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
function parseOpenCodeEvent(line) {
|
|
51
|
+
if (!line.trim()) return null;
|
|
52
|
+
try {
|
|
53
|
+
const parsed = JSON.parse(line);
|
|
54
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
55
|
+
const type = parsed.type ?? "";
|
|
56
|
+
const part = parsed.part ?? {};
|
|
57
|
+
switch (type) {
|
|
58
|
+
case "step_start":
|
|
59
|
+
return null;
|
|
60
|
+
// lifecycle event — no user-visible content
|
|
61
|
+
case "text":
|
|
62
|
+
return { type: "output", timestamp, data: part.text ?? part };
|
|
63
|
+
case "tool_use": {
|
|
64
|
+
const state = part.state ?? {};
|
|
65
|
+
if (state.status === "error") {
|
|
66
|
+
const errMsg = typeof state.error === "string" ? state.error : JSON.stringify(state);
|
|
67
|
+
return { type: "error", timestamp, data: state, errorKind: classifyAdapterError(errMsg) };
|
|
68
|
+
}
|
|
69
|
+
return { type: "tool_call", timestamp, data: { name: part.tool, input: state.input } };
|
|
70
|
+
}
|
|
71
|
+
case "step_finish": {
|
|
72
|
+
const reason = part.reason;
|
|
73
|
+
const tokens = extractOpenCodeTokens(part);
|
|
74
|
+
if (reason === "error") {
|
|
75
|
+
const errMsg = typeof part.error === "string" ? part.error : JSON.stringify(part);
|
|
76
|
+
return { type: "error", timestamp, data: part, tokens, errorKind: classifyAdapterError(errMsg) };
|
|
77
|
+
}
|
|
78
|
+
if (reason === "tool-calls") {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
return { type: "done", timestamp, data: part, tokens };
|
|
82
|
+
}
|
|
83
|
+
default:
|
|
84
|
+
return { type: "output", timestamp, data: parsed };
|
|
85
|
+
}
|
|
86
|
+
} catch {
|
|
87
|
+
return { type: "output", timestamp: (/* @__PURE__ */ new Date()).toISOString(), data: line };
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function extractOpenCodeTokens(part) {
|
|
91
|
+
const tokens = part.tokens;
|
|
92
|
+
if (!tokens || typeof tokens.input !== "number") return void 0;
|
|
93
|
+
const input = tokens.input;
|
|
94
|
+
const output = typeof tokens.output === "number" ? tokens.output : 0;
|
|
95
|
+
return createTokenUsage(input, output);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export { OpenCodeAdapter };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { DEFAULT_SYSTEM_TEMPLATE, DEFAULT_USER_TEMPLATE, buildPromptContext } from './chunk-VXS2CJFH.js';
|
|
3
3
|
import { resolveFailureStatus, isDispatchable, isTerminal, isBlocked, resolveCompletionStatus, calculateRetryDelay } from './chunk-U2VDNUZL.js';
|
|
4
4
|
import { AUTONOMOUS_LABEL } from './chunk-PNE6LQRF.js';
|
|
5
5
|
import { LockConflictError, WorkspaceError, TaskAlreadyRunningError, NoAgentsError, classifyAdapterError } from './chunk-2C2TFQ7K.js';
|
|
@@ -896,7 +896,9 @@ Agent role: ${role}` : `Autonomous work cycle. Agent role: ${role}`;
|
|
|
896
896
|
agent,
|
|
897
897
|
this.deps.config
|
|
898
898
|
);
|
|
899
|
-
const
|
|
899
|
+
const systemTemplate = this.deps.config.prompt?.system_template ?? DEFAULT_SYSTEM_TEMPLATE;
|
|
900
|
+
const userTemplate = this.deps.config.prompt?.user_template ?? DEFAULT_USER_TEMPLATE;
|
|
901
|
+
const legacyTemplate = this.deps.config.prompt?.template;
|
|
900
902
|
const attempt = task.attempts + 1;
|
|
901
903
|
let retryContext;
|
|
902
904
|
if (attempt > 1) {
|
|
@@ -919,14 +921,13 @@ Agent role: ${role}` : `Autonomous work cycle. Agent role: ${role}`;
|
|
|
919
921
|
const allTasks = await this.cachedTaskStore.list();
|
|
920
922
|
const goalTasks = allTasks.filter((t) => t.goalId === goalId);
|
|
921
923
|
const progressEntry = await this.deps.contextStore?.get(`${goalId}-progress`);
|
|
922
|
-
const MAX_GOAL_TASK_NAMES = 30;
|
|
923
924
|
const taskNames = goalTasks.map((t) => `[${t.status}] ${t.title}`);
|
|
924
925
|
goalContext = {
|
|
925
926
|
id: goalRaw.id,
|
|
926
927
|
title: goalRaw.title,
|
|
927
928
|
description: goalRaw.description,
|
|
928
929
|
status: goalRaw.status,
|
|
929
|
-
task_names: taskNames
|
|
930
|
+
task_names: taskNames,
|
|
930
931
|
progress: progressEntry?.value
|
|
931
932
|
};
|
|
932
933
|
}
|
|
@@ -938,7 +939,14 @@ Agent role: ${role}` : `Autonomous work cycle. Agent role: ${role}`;
|
|
|
938
939
|
this.deps.config,
|
|
939
940
|
{ allAgents, retryContext, sharedContext, feedback: task.feedback, messages: pendingMessages.length ? pendingMessages : void 0, goal: goalContext }
|
|
940
941
|
);
|
|
941
|
-
|
|
942
|
+
let prompt;
|
|
943
|
+
let systemPrompt;
|
|
944
|
+
if (legacyTemplate) {
|
|
945
|
+
prompt = await this.deps.templateEngine.render(legacyTemplate, context);
|
|
946
|
+
} else {
|
|
947
|
+
systemPrompt = await this.deps.templateEngine.render(systemTemplate, context);
|
|
948
|
+
prompt = await this.deps.templateEngine.render(userTemplate, context);
|
|
949
|
+
}
|
|
942
950
|
const run = await this.deps.runService.create({
|
|
943
951
|
taskId: task.id,
|
|
944
952
|
agentId: agent.id,
|
|
@@ -955,9 +963,12 @@ Agent role: ${role}` : `Autonomous work cycle. Agent role: ${role}`;
|
|
|
955
963
|
await this.deps.taskService.assign(taskId, agent.id);
|
|
956
964
|
await this.deps.taskService.incrementAttempts(taskId);
|
|
957
965
|
if (worktreeBranch) {
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
966
|
+
const freshTask = await this.deps.taskStore.get(taskId);
|
|
967
|
+
if (freshTask) {
|
|
968
|
+
freshTask.proof = { ...freshTask.proof ?? { files_changed: [] }, branch: worktreeBranch };
|
|
969
|
+
freshTask.workspace = workspacePath;
|
|
970
|
+
await this.deps.taskStore.save(freshTask);
|
|
971
|
+
}
|
|
961
972
|
}
|
|
962
973
|
await this.deps.agentService.setStatus(agent.id, "running");
|
|
963
974
|
const agentData = await this.deps.agentService.get(agent.id);
|
|
@@ -969,6 +980,7 @@ Agent role: ${role}` : `Autonomous work cycle. Agent role: ${role}`;
|
|
|
969
980
|
this.abortControllers.set(taskId, abortController);
|
|
970
981
|
const handle = adapter.execute({
|
|
971
982
|
prompt,
|
|
983
|
+
systemPrompt,
|
|
972
984
|
workspace: workspacePath,
|
|
973
985
|
env: {
|
|
974
986
|
...agent.config.env,
|
|
@@ -1044,11 +1056,15 @@ Agent role: ${role}` : `Autonomous work cycle. Agent role: ${role}`;
|
|
|
1044
1056
|
if (typeof p === "string") filesChangedSet.add(p);
|
|
1045
1057
|
}
|
|
1046
1058
|
} else {
|
|
1047
|
-
const
|
|
1048
|
-
filesChangedSet.add(
|
|
1059
|
+
const filePath2 = data && typeof data.path === "string" ? data.path : typeof event.data === "string" ? event.data : String(event.data);
|
|
1060
|
+
filesChangedSet.add(filePath2);
|
|
1049
1061
|
}
|
|
1050
1062
|
}
|
|
1051
1063
|
const eventTimestamp = isValidISOTimestamp(event.timestamp) ? event.timestamp : (/* @__PURE__ */ new Date()).toISOString();
|
|
1064
|
+
const filePath = event.type === "file_change" ? (() => {
|
|
1065
|
+
const d = event.data;
|
|
1066
|
+
return d && typeof d.path === "string" ? d.path : typeof event.data === "string" ? event.data : String(event.data);
|
|
1067
|
+
})() : null;
|
|
1052
1068
|
const serialized = serializeEventData(event.data, MAX_EVENT_DATA_LEN);
|
|
1053
1069
|
event.data = void 0;
|
|
1054
1070
|
const runEvent = {
|
|
@@ -1074,7 +1090,7 @@ Agent role: ${role}` : `Autonomous work cycle. Agent role: ${role}`;
|
|
|
1074
1090
|
type: "agent:file_changed",
|
|
1075
1091
|
runId,
|
|
1076
1092
|
agentId,
|
|
1077
|
-
path:
|
|
1093
|
+
path: filePath
|
|
1078
1094
|
});
|
|
1079
1095
|
} else if (event.type === "error") {
|
|
1080
1096
|
if (event.errorKind) lastErrorKind = event.errorKind;
|
|
@@ -1212,7 +1228,7 @@ Agent role: ${role}` : `Autonomous work cycle. Agent role: ${role}`;
|
|
|
1212
1228
|
await this.deps.agentStore.save(agentAfter);
|
|
1213
1229
|
}
|
|
1214
1230
|
if (newStatus === "review" && task.review_criteria?.length) {
|
|
1215
|
-
await this.runAutoReview(taskId, task.review_criteria, task.workspace ?? this.deps.projectRoot);
|
|
1231
|
+
await this.runAutoReview(taskId, task.review_criteria, task.workspace ?? this.deps.projectRoot, autoApprove);
|
|
1216
1232
|
} else if (newStatus === "review" && autoApprove) {
|
|
1217
1233
|
await this.deps.taskService.updateStatus(taskId, "done");
|
|
1218
1234
|
}
|
|
@@ -1287,7 +1303,7 @@ Agent role: ${role}` : `Autonomous work cycle. Agent role: ${role}`;
|
|
|
1287
1303
|
* If all criteria pass, transition review → done.
|
|
1288
1304
|
* If any fail, stay in review with results attached.
|
|
1289
1305
|
*/
|
|
1290
|
-
async runAutoReview(taskId, criteria, cwd) {
|
|
1306
|
+
async runAutoReview(taskId, criteria, cwd, autoApprove = false) {
|
|
1291
1307
|
const runner = new ReviewRunner({ cwd });
|
|
1292
1308
|
const results = await runner.runAll(criteria);
|
|
1293
1309
|
const allPassed = ReviewRunner.allPassed(results);
|
|
@@ -1306,7 +1322,15 @@ Agent role: ${role}` : `Autonomous work cycle. Agent role: ${role}`;
|
|
|
1306
1322
|
passed: allPassed,
|
|
1307
1323
|
results
|
|
1308
1324
|
});
|
|
1309
|
-
if (allPassed) {
|
|
1325
|
+
if (allPassed || autoApprove) {
|
|
1326
|
+
if (!allPassed) {
|
|
1327
|
+
this.deps.eventBus.emit({
|
|
1328
|
+
type: "orchestrator:error",
|
|
1329
|
+
error: `Review criteria failed for task ${taskId} but autoApprove is set \u2014 force-approving`,
|
|
1330
|
+
context: "auto-review-with-auto-approve",
|
|
1331
|
+
fatal: false
|
|
1332
|
+
});
|
|
1333
|
+
}
|
|
1310
1334
|
try {
|
|
1311
1335
|
await this.deps.taskService.updateStatus(taskId, "done");
|
|
1312
1336
|
} catch (validationErr) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"orchestrator-
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"orchestrator-X2CWGFCL.js"}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { buildFullPrompt } from './chunk-C6XZ3FJT.js';
|
|
2
|
+
import './chunk-XDVMX2FO.js';
|
|
1
3
|
import { classifyAdapterError } from './chunk-NLQAJ7TW.js';
|
|
2
4
|
import { readLines } from './chunk-O2MSGW3V.js';
|
|
3
5
|
import { execFile } from 'child_process';
|
|
@@ -144,7 +146,7 @@ var ShellAdapter = class {
|
|
|
144
146
|
env: {
|
|
145
147
|
...process.env,
|
|
146
148
|
...params.env,
|
|
147
|
-
ORCHESTRY_TASK_PROMPT: params.prompt
|
|
149
|
+
ORCHESTRY_TASK_PROMPT: buildFullPrompt(params.systemPrompt, params.prompt)
|
|
148
150
|
},
|
|
149
151
|
signal: params.signal
|
|
150
152
|
});
|
|
@@ -217,5 +219,5 @@ var ShellAdapter = class {
|
|
|
217
219
|
};
|
|
218
220
|
|
|
219
221
|
export { ShellAdapter };
|
|
220
|
-
//# sourceMappingURL=shell-
|
|
221
|
-
//# sourceMappingURL=shell-
|
|
222
|
+
//# sourceMappingURL=shell-NJNW3O6K.js.map
|
|
223
|
+
//# sourceMappingURL=shell-NJNW3O6K.js.map
|
|
@@ -0,0 +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"]}
|
|
@@ -193,7 +193,7 @@ function registerTaskCommand(program, container) {
|
|
|
193
193
|
await container.paths.requireInit();
|
|
194
194
|
const task2 = await container.taskService.get(id);
|
|
195
195
|
if (task2.status === "in_progress") {
|
|
196
|
-
const { buildFullContainer } = await import('./container-
|
|
196
|
+
const { buildFullContainer } = await import('./container-RY54L3XC.js');
|
|
197
197
|
const full = await buildFullContainer(container.context);
|
|
198
198
|
await full.orchestrator.cancelTask(id);
|
|
199
199
|
} else {
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { DEFAULT_PROMPT_TEMPLATE, DEFAULT_SYSTEM_TEMPLATE, DEFAULT_USER_TEMPLATE, LiquidTemplateEngine, buildPromptContext, filterRelevantContext } from './chunk-VG4465AG.js';
|
|
2
|
+
//# sourceMappingURL=template-engine-5ZKVJMYA.js.map
|
|
3
|
+
//# sourceMappingURL=template-engine-5ZKVJMYA.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"template-engine-
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"template-engine-5ZKVJMYA.js"}
|
|
@@ -8,7 +8,7 @@ function registerTuiCommand(program, container) {
|
|
|
8
8
|
const state = await container.stateStore.read();
|
|
9
9
|
const { render } = await import('ink');
|
|
10
10
|
const { createElement } = await import('react');
|
|
11
|
-
const { App } = await import('./App-
|
|
11
|
+
const { App } = await import('./App-GJVTVGRU.js');
|
|
12
12
|
const onRunTask = async (taskId) => {
|
|
13
13
|
await container.orchestrator.runTask(taskId);
|
|
14
14
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oxgeneral/orch",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "Open-source orchestration for zero-human companies, processes and departments — deploy AI engineering, editorial, sales, analytics teams from your terminal",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
7
7
|
"node": ">=20.0.0"
|
|
@@ -34,22 +34,26 @@
|
|
|
34
34
|
"clean": "rm -rf dist",
|
|
35
35
|
"postinstall": "node scripts/postinstall.js || true",
|
|
36
36
|
"benchmark": "tsx scripts/benchmark.ts",
|
|
37
|
+
"load-test": "tsx scripts/load-test.ts",
|
|
37
38
|
"prepublishOnly": "npm run build"
|
|
38
39
|
},
|
|
39
40
|
"keywords": [
|
|
40
|
-
"
|
|
41
|
+
"ai-agent-runtime",
|
|
42
|
+
"agent-orchestration",
|
|
43
|
+
"ai-agents",
|
|
44
|
+
"multi-agent",
|
|
45
|
+
"ai-team",
|
|
41
46
|
"orchestrator",
|
|
42
|
-
"ai",
|
|
43
|
-
"agents",
|
|
44
47
|
"claude",
|
|
45
48
|
"codex",
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"multi-agent",
|
|
49
|
-
"ai-team",
|
|
50
|
-
"agent-orchestration",
|
|
49
|
+
"cursor",
|
|
50
|
+
"opencode",
|
|
51
51
|
"claude-code",
|
|
52
52
|
"openai",
|
|
53
|
+
"llm",
|
|
54
|
+
"cli",
|
|
55
|
+
"typescript",
|
|
56
|
+
"git-worktree",
|
|
53
57
|
"workflow",
|
|
54
58
|
"devops"
|
|
55
59
|
],
|