@oxgeneral/orch 0.3.4 → 1.0.0

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.
Files changed (57) hide show
  1. package/dist/{App-RKAPZNZO.js → App-GJVTVGRU.js} +55 -20
  2. package/dist/{agent-KBTLGGCT.js → agent-7ZJ3ZDJ7.js} +1 -1
  3. package/dist/{chunk-D6RFF3KN.js → chunk-4IFIOMCW.js} +4 -3
  4. package/dist/{chunk-S3QYSBW4.js → chunk-C6XZ3FJT.js} +6 -3
  5. package/dist/chunk-C6XZ3FJT.js.map +1 -0
  6. package/dist/{chunk-VMDQVRBR.js → chunk-GBXUNDKN.js} +16 -7
  7. package/dist/chunk-GBXUNDKN.js.map +1 -0
  8. package/dist/{chunk-W6RSVMXR.js → chunk-MGGSRXWJ.js} +5 -2
  9. package/dist/{chunk-B4JQM4NU.js → chunk-VG4465AG.js} +119 -45
  10. package/dist/chunk-VG4465AG.js.map +1 -0
  11. package/dist/{chunk-A36WAF2S.js → chunk-VXS2CJFH.js} +117 -43
  12. package/dist/{chunk-52BFUGDD.js → chunk-XJTJ2TJV.js} +3 -2
  13. package/dist/{claude-INM52PTH.js → claude-WUJU5KIE.js} +6 -5
  14. package/dist/claude-WUJU5KIE.js.map +1 -0
  15. package/dist/claude-ZUEKJJ4X.js +5 -0
  16. package/dist/cli.js +10 -10
  17. package/dist/{codex-DIXT44JR.js → codex-7IXXXG5U.js} +3 -3
  18. package/dist/{codex-QGH2GRV6.js → codex-NYJWEPRQ.js} +4 -4
  19. package/dist/codex-NYJWEPRQ.js.map +1 -0
  20. package/dist/{container-LJU4QNDH.js → container-LUWGNBSS.js} +12 -10
  21. package/dist/{cursor-KQJTQ73D.js → cursor-3YHVD4NP.js} +4 -4
  22. package/dist/cursor-3YHVD4NP.js.map +1 -0
  23. package/dist/{cursor-C3TR2IJC.js → cursor-622RBRHH.js} +3 -3
  24. package/dist/{doctor-V2FPS236.js → doctor-XSGQSD57.js} +5 -5
  25. package/dist/index.d.ts +4 -1
  26. package/dist/index.js +15 -13
  27. package/dist/index.js.map +1 -1
  28. package/dist/{init-U7MCIOB2.js → init-JU343RXK.js} +3 -3
  29. package/dist/opencode-FAMPSA6X.js +100 -0
  30. package/dist/opencode-FAMPSA6X.js.map +1 -0
  31. package/dist/opencode-WOR53TSC.js +98 -0
  32. package/dist/orchestrator-IYWBVA7J.js +5 -0
  33. package/dist/{orchestrator-ADO66XZ3.js.map → orchestrator-IYWBVA7J.js.map} +1 -1
  34. package/dist/{orchestrator-E3FQ4SOE.js → orchestrator-QNAD7MFH.js} +14 -5
  35. package/dist/shell-DVFHHYAZ.js +5 -0
  36. package/dist/{shell-JXOPKDXH.js → shell-NJNW3O6K.js} +5 -3
  37. package/dist/shell-NJNW3O6K.js.map +1 -0
  38. package/dist/{task-2TJW6Z7O.js → task-3O2OFSP6.js} +1 -1
  39. package/dist/template-engine-5ZKVJMYA.js +3 -0
  40. package/dist/{template-engine-MFL5B677.js.map → template-engine-5ZKVJMYA.js.map} +1 -1
  41. package/dist/template-engine-AWIS56BL.js +3 -0
  42. package/dist/{tui-IM3YUUVD.js → tui-LN5XHSQY.js} +1 -1
  43. package/package.json +2 -1
  44. package/readme.md +3 -3
  45. package/scripts/load-test.ts +478 -0
  46. package/dist/chunk-B4JQM4NU.js.map +0 -1
  47. package/dist/chunk-S3QYSBW4.js.map +0 -1
  48. package/dist/chunk-VMDQVRBR.js.map +0 -1
  49. package/dist/claude-INM52PTH.js.map +0 -1
  50. package/dist/claude-NHUNA5RZ.js +0 -5
  51. package/dist/codex-QGH2GRV6.js.map +0 -1
  52. package/dist/cursor-KQJTQ73D.js.map +0 -1
  53. package/dist/orchestrator-ADO66XZ3.js +0 -5
  54. package/dist/shell-3S4VLYEG.js +0 -4
  55. package/dist/shell-JXOPKDXH.js.map +0 -1
  56. package/dist/template-engine-4IZKRRHG.js +0 -3
  57. package/dist/template-engine-MFL5B677.js +0 -3
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
- import { DEFAULT_PROMPT_TEMPLATE } from './chunk-A36WAF2S.js';
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';
@@ -23,7 +23,7 @@ var AGENT_CREATOR_ROLE = `Agent architect \u2014 designs and creates AI agents f
23
23
  Do NOT include CLI documentation or goal-mode instructions \u2014 these are already injected by the system prompt template.
24
24
 
25
25
  3) CHOOSE CONFIGURATION:
26
- - adapter: \`claude\` (AI tasks), \`shell\` (bash scripts), \`codex\` (OpenAI Codex), \`cursor\` (Cursor IDE)
26
+ - adapter: \`claude\` (AI tasks), \`shell\` (bash scripts), \`codex\` (OpenAI Codex), \`cursor\` (Cursor IDE), \`opencode\` (OpenCode \u2014 multi-provider)
27
27
  - model: \`claude-opus-4-6\` (complex/architectural), \`claude-sonnet-4-6\` (fast/routine), \`claude-haiku-4-5-20251001\` (simple/templated)
28
28
  - approval_policy: \`auto\` (no confirmation) / \`suggest\` (proposes actions) / \`manual\` (human approval)
29
29
  - max_turns: 50 (default), up to 100 for complex tasks
@@ -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":"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","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 };
@@ -0,0 +1,5 @@
1
+ export { Orchestrator } from './chunk-GBXUNDKN.js';
2
+ import './chunk-VG4465AG.js';
3
+ import './chunk-NLQAJ7TW.js';
4
+ //# sourceMappingURL=orchestrator-IYWBVA7J.js.map
5
+ //# sourceMappingURL=orchestrator-IYWBVA7J.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"orchestrator-ADO66XZ3.js"}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"orchestrator-IYWBVA7J.js"}
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { DEFAULT_PROMPT_TEMPLATE, buildPromptContext } from './chunk-A36WAF2S.js';
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 template = this.deps.config.prompt?.template ?? DEFAULT_PROMPT_TEMPLATE;
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.length > MAX_GOAL_TASK_NAMES ? [...taskNames.slice(0, MAX_GOAL_TASK_NAMES), `... and ${taskNames.length - MAX_GOAL_TASK_NAMES} more`] : 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
- const prompt = await this.deps.templateEngine.render(template, context);
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,
@@ -969,6 +977,7 @@ Agent role: ${role}` : `Autonomous work cycle. Agent role: ${role}`;
969
977
  this.abortControllers.set(taskId, abortController);
970
978
  const handle = adapter.execute({
971
979
  prompt,
980
+ systemPrompt,
972
981
  workspace: workspacePath,
973
982
  env: {
974
983
  ...agent.config.env,
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ export { ShellAdapter } from './chunk-XJTJ2TJV.js';
3
+ import './chunk-MGGSRXWJ.js';
4
+ import './chunk-2C2TFQ7K.js';
5
+ import './chunk-CHIP7O6V.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-JXOPKDXH.js.map
221
- //# sourceMappingURL=shell-JXOPKDXH.js.map
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-LJU4QNDH.js');
196
+ const { buildFullContainer } = await import('./container-LUWGNBSS.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-MFL5B677.js"}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"template-engine-5ZKVJMYA.js"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export { DEFAULT_PROMPT_TEMPLATE, DEFAULT_SYSTEM_TEMPLATE, DEFAULT_USER_TEMPLATE, LiquidTemplateEngine, buildPromptContext, filterRelevantContext } from './chunk-VXS2CJFH.js';
3
+ import './chunk-PNE6LQRF.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-RKAPZNZO.js');
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,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxgeneral/orch",
3
- "version": "0.3.4",
3
+ "version": "1.0.0",
4
4
  "description": "Agents Organizations — CLI orchestrator for AI agents",
5
5
  "type": "module",
6
6
  "engines": {
@@ -34,6 +34,7 @@
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": [
package/readme.md CHANGED
@@ -2,7 +2,7 @@
2
2
  <img src="assets/logo.svg" alt="ORCH" height="60" />
3
3
  <p align="center">
4
4
  <strong>Stop babysitting AI agents. Start orchestrating them.</strong><br/>
5
- One CLI to run Claude, Codex, Cursor, and shell scripts as a team — in parallel, with retries, from your terminal.
5
+ One CLI to run Claude, OpenCode, Codex, Cursor, and shell scripts as a team — in parallel, with retries, from your terminal.
6
6
  </p>
7
7
  <p align="center">
8
8
  <a href="https://github.com/oxgeneral/ORCH/stargazers"><img src="https://img.shields.io/github/stars/oxgeneral/ORCH?style=social" alt="GitHub Stars" /></a>
@@ -10,7 +10,7 @@
10
10
  <a href="https://www.npmjs.com/package/@oxgeneral/orch"><img src="https://img.shields.io/npm/v/@oxgeneral/orch?color=cb0000" alt="npm" /></a>
11
11
  <a href="#get-started-in-30-seconds"><img src="https://img.shields.io/badge/setup-one%20command-brightgreen" alt="One command setup" /></a>
12
12
  <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue" alt="MIT License" /></a>
13
- <a href="#development"><img src="https://img.shields.io/badge/tests-1386%20passing-brightgreen" alt="Tests" /></a>
13
+ <a href="#development"><img src="https://img.shields.io/badge/tests-1493%20passing-brightgreen" alt="Tests" /></a>
14
14
  <a href="#architecture"><img src="https://img.shields.io/badge/TypeScript-strict-blue" alt="TypeScript strict" /></a>
15
15
  </p>
16
16
  </p>
@@ -224,7 +224,7 @@ src/
224
224
  │ └── errors.ts # Domain error types
225
225
  ├── application/ # Orchestrator engine, services, event bus
226
226
  ├── infrastructure/
227
- │ ├── adapters/ # Claude, Codex, Cursor, Shell (pluggable)
227
+ │ ├── adapters/ # Claude, OpenCode, Codex, Cursor, Shell (pluggable)
228
228
  │ ├── storage/ # File-based (YAML/JSON/JSONL)
229
229
  │ ├── process/ # PID management, graceful kill
230
230
  │ ├── template/ # LiquidJS template engine