@oxgeneral/orch 0.3.3 → 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.
- package/dist/App-GJVTVGRU.js +6717 -0
- package/dist/agent-7ZJ3ZDJ7.js +183 -0
- package/dist/agent-shop-YN2BSLHM.js +2 -0
- package/dist/chunk-2C2TFQ7K.js +136 -0
- package/dist/chunk-45K2XID7.js +29 -0
- package/dist/chunk-4IFIOMCW.js +86 -0
- package/dist/chunk-7X2GI5OV.js +181 -0
- package/dist/{chunk-S3QYSBW4.js → chunk-C6XZ3FJT.js} +6 -3
- package/dist/chunk-C6XZ3FJT.js.map +1 -0
- package/dist/chunk-CHIP7O6V.js +83 -0
- package/dist/{chunk-BCPUTULS.js → chunk-DAVHOWGD.js} +188 -16
- package/dist/chunk-FRTKB575.js +87 -0
- package/dist/{chunk-BGHCY7WY.js → chunk-GBXUNDKN.js} +32 -13
- package/dist/chunk-GBXUNDKN.js.map +1 -0
- package/dist/chunk-HXYAZGLP.js +15 -0
- package/dist/chunk-I3SMISEF.js +29 -0
- package/dist/chunk-K6DMQERQ.js +89 -0
- package/dist/chunk-LV6GDBBI.js +297 -0
- package/dist/chunk-MGGSRXWJ.js +69 -0
- package/dist/chunk-P6ATSXGL.js +107 -0
- package/dist/chunk-PNE6LQRF.js +5 -0
- package/dist/chunk-U2VDNUZL.js +52 -0
- package/dist/chunk-VG4465AG.js +275 -0
- package/dist/chunk-VG4465AG.js.map +1 -0
- package/dist/{chunk-B4JQM4NU.js → chunk-VXS2CJFH.js} +119 -47
- package/dist/chunk-XJTJ2TJV.js +221 -0
- 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 +199 -1
- package/dist/clipboard-service-RTDUUQQU.js +200 -0
- package/dist/codex-7IXXXG5U.js +123 -0
- package/dist/{codex-QGH2GRV6.js → codex-NYJWEPRQ.js} +4 -4
- package/dist/codex-NYJWEPRQ.js.map +1 -0
- package/dist/config-OTAVSMOD.js +75 -0
- package/dist/container-LUWGNBSS.js +1596 -0
- package/dist/context-OL4BVUV5.js +83 -0
- package/dist/{cursor-KQJTQ73D.js → cursor-3YHVD4NP.js} +4 -4
- package/dist/cursor-3YHVD4NP.js.map +1 -0
- package/dist/cursor-622RBRHH.js +97 -0
- package/dist/doctor-XSGQSD57.js +67 -0
- package/dist/doctor-service-TPOMFAIG.js +2 -0
- package/dist/goal-FMYYN2FR.js +138 -0
- package/dist/index.d.ts +16 -2
- package/dist/index.js +25 -16
- package/dist/index.js.map +1 -1
- package/dist/init-JU343RXK.js +165 -0
- package/dist/logs-PHPYWQ6I.js +207 -0
- package/dist/msg-FUWWLEKM.js +95 -0
- 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-IYWBVA7J.js +5 -0
- package/dist/{orchestrator-KF4UY5GD.js.map → orchestrator-IYWBVA7J.js.map} +1 -1
- package/dist/orchestrator-QNAD7MFH.js +1433 -0
- package/dist/process-manager-HUVNAPQV.js +2 -0
- package/dist/registry-PQWRVNF2.js +2 -0
- package/dist/run-N72G5V2H.js +95 -0
- package/dist/shell-DVFHHYAZ.js +5 -0
- package/dist/{shell-UXJNTNBC.js → shell-NJNW3O6K.js} +6 -4
- package/dist/shell-NJNW3O6K.js.map +1 -0
- package/dist/shop-picker-2HY67UWP.js +79 -0
- package/dist/status-RZWN2C6C.js +56 -0
- package/dist/task-3O2OFSP6.js +221 -0
- package/dist/team-PFLP4PPL.js +97 -0
- 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-LN5XHSQY.js +245 -0
- package/dist/update-YLP7FPNY.js +64 -0
- package/dist/update-check-4YKLGBFB.js +2 -0
- package/dist/workspace-manager-JM6U7JOH.js +215 -0
- package/package.json +2 -1
- package/readme.md +11 -4
- package/scripts/load-test.ts +478 -0
- package/scripts/postinstall.js +44 -2
- package/dist/App-NN7HR7UE.js +0 -20
- package/dist/agent-S4DKSX63.js +0 -9
- package/dist/agent-shop-D2RS4BZK.js +0 -2
- package/dist/chunk-3MQNQ7QW.js +0 -2
- package/dist/chunk-5AJ4LYO5.js +0 -8
- package/dist/chunk-6MJ7V6VY.js +0 -2
- package/dist/chunk-B4JQM4NU.js.map +0 -1
- package/dist/chunk-BGHCY7WY.js.map +0 -1
- package/dist/chunk-CDFA4IIQ.js +0 -2
- package/dist/chunk-CHRW4CLD.js +0 -2
- package/dist/chunk-HMMPM7MF.js +0 -3
- package/dist/chunk-HSBYJ5C5.js +0 -112
- package/dist/chunk-HXOMNULD.js +0 -2
- package/dist/chunk-IS3YBE2B.js +0 -3
- package/dist/chunk-KPCT44WU.js +0 -2
- package/dist/chunk-L26TK7Y5.js +0 -2
- package/dist/chunk-LXNRCJ22.js +0 -2
- package/dist/chunk-OQKREZUF.js +0 -11
- package/dist/chunk-PJ5DKXGR.js +0 -2
- package/dist/chunk-QFKVCNKL.js +0 -2
- package/dist/chunk-S3QYSBW4.js.map +0 -1
- package/dist/chunk-UMZEA3JT.js +0 -5
- package/dist/claude-GQZNDJ6L.js +0 -2
- package/dist/claude-INM52PTH.js.map +0 -1
- package/dist/clipboard-service-MYLSWM5E.js +0 -25
- package/dist/codex-QGH2GRV6.js.map +0 -1
- package/dist/codex-SJV7ZZBY.js +0 -2
- package/dist/config-CCSS2P7R.js +0 -2
- package/dist/container-NEKK5W2B.js +0 -6
- package/dist/context-GSMQHQES.js +0 -7
- package/dist/cursor-4JQOCP5X.js +0 -2
- package/dist/cursor-KQJTQ73D.js.map +0 -1
- package/dist/doctor-UAII4VWN.js +0 -2
- package/dist/doctor-service-PB7YBH3F.js +0 -2
- package/dist/goal-RFKFPR7M.js +0 -8
- package/dist/init-2D4RAN7B.js +0 -53
- package/dist/logs-UXFXVYCP.js +0 -12
- package/dist/msg-4SCLBO4K.js +0 -9
- package/dist/orchestrator-KF4UY5GD.js +0 -5
- package/dist/orchestrator-MFL3XK5L.js +0 -13
- package/dist/process-manager-33H27MQF.js +0 -2
- package/dist/registry-BO2PPRNG.js +0 -2
- package/dist/run-HSHRELOP.js +0 -3
- package/dist/shell-F42UUF3U.js +0 -2
- package/dist/shell-UXJNTNBC.js.map +0 -1
- package/dist/shop-picker-LE3SKFOX.js +0 -5
- package/dist/status-DLBNWSWM.js +0 -2
- package/dist/task-AP2TIOOF.js +0 -20
- package/dist/team-MSIBKOQC.js +0 -4
- package/dist/template-engine-MFL5B677.js +0 -3
- package/dist/template-engine-ONIDVD4F.js +0 -2
- package/dist/tui-PIQT4ZZ2.js +0 -2
- package/dist/update-PC2ENCKU.js +0 -2
- package/dist/update-check-HGMBDYHL.js +0 -2
- package/dist/workspace-manager-DYN3XJ7X.js +0 -3
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { buildFullPrompt } from './chunk-MGGSRXWJ.js';
|
|
3
|
+
import { classifyAdapterError } from './chunk-2C2TFQ7K.js';
|
|
4
|
+
import { readLines } from './chunk-CHIP7O6V.js';
|
|
5
|
+
import { execFile } from 'child_process';
|
|
6
|
+
import { promisify } from 'util';
|
|
7
|
+
|
|
8
|
+
// src/infrastructure/adapters/event-buffer.ts
|
|
9
|
+
var DEFAULT_CAPACITY = 1024;
|
|
10
|
+
function deferred() {
|
|
11
|
+
let resolve;
|
|
12
|
+
const promise = new Promise((r) => {
|
|
13
|
+
resolve = r;
|
|
14
|
+
});
|
|
15
|
+
return { promise, resolve };
|
|
16
|
+
}
|
|
17
|
+
var EventBuffer = class {
|
|
18
|
+
buf;
|
|
19
|
+
head = 0;
|
|
20
|
+
// read index
|
|
21
|
+
tail = 0;
|
|
22
|
+
// write index
|
|
23
|
+
count = 0;
|
|
24
|
+
capacity;
|
|
25
|
+
// Consumer notification: resolved when new data is available
|
|
26
|
+
dataReady = null;
|
|
27
|
+
// Producer notification: resolved when space is available
|
|
28
|
+
spaceReady = null;
|
|
29
|
+
closed = false;
|
|
30
|
+
constructor(capacity = DEFAULT_CAPACITY) {
|
|
31
|
+
this.capacity = capacity;
|
|
32
|
+
this.buf = new Array(capacity);
|
|
33
|
+
}
|
|
34
|
+
/** Number of buffered events. */
|
|
35
|
+
get size() {
|
|
36
|
+
return this.count;
|
|
37
|
+
}
|
|
38
|
+
get isFull() {
|
|
39
|
+
return this.count >= this.capacity;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Push an event into the buffer.
|
|
43
|
+
* If the buffer is full, waits until space is available (backpressure).
|
|
44
|
+
*/
|
|
45
|
+
async push(event) {
|
|
46
|
+
while (this.isFull && !this.closed) {
|
|
47
|
+
if (!this.spaceReady) {
|
|
48
|
+
this.spaceReady = deferred();
|
|
49
|
+
}
|
|
50
|
+
await this.spaceReady.promise;
|
|
51
|
+
}
|
|
52
|
+
if (this.closed) return;
|
|
53
|
+
this.buf[this.tail] = event;
|
|
54
|
+
this.tail = (this.tail + 1) % this.capacity;
|
|
55
|
+
this.count++;
|
|
56
|
+
if (this.dataReady) {
|
|
57
|
+
const dr = this.dataReady;
|
|
58
|
+
this.dataReady = null;
|
|
59
|
+
dr.resolve();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Dequeue the next event. O(1).
|
|
64
|
+
* Returns undefined only when buffer is empty AND closed.
|
|
65
|
+
*/
|
|
66
|
+
async take() {
|
|
67
|
+
while (this.count === 0) {
|
|
68
|
+
if (this.closed) return void 0;
|
|
69
|
+
if (!this.dataReady) {
|
|
70
|
+
this.dataReady = deferred();
|
|
71
|
+
}
|
|
72
|
+
await this.dataReady.promise;
|
|
73
|
+
}
|
|
74
|
+
const event = this.buf[this.head];
|
|
75
|
+
this.buf[this.head] = void 0;
|
|
76
|
+
this.head = (this.head + 1) % this.capacity;
|
|
77
|
+
this.count--;
|
|
78
|
+
if (this.spaceReady) {
|
|
79
|
+
const sr = this.spaceReady;
|
|
80
|
+
this.spaceReady = null;
|
|
81
|
+
sr.resolve();
|
|
82
|
+
}
|
|
83
|
+
return event;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Signal that no more events will be pushed.
|
|
87
|
+
* Wakes up any waiting consumer/producer.
|
|
88
|
+
*/
|
|
89
|
+
close() {
|
|
90
|
+
this.closed = true;
|
|
91
|
+
if (this.dataReady) {
|
|
92
|
+
const dr = this.dataReady;
|
|
93
|
+
this.dataReady = null;
|
|
94
|
+
dr.resolve();
|
|
95
|
+
}
|
|
96
|
+
if (this.spaceReady) {
|
|
97
|
+
const sr = this.spaceReady;
|
|
98
|
+
this.spaceReady = null;
|
|
99
|
+
sr.resolve();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
get isClosed() {
|
|
103
|
+
return this.closed;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Async iterator that drains the buffer until closed and empty.
|
|
107
|
+
*/
|
|
108
|
+
async *[Symbol.asyncIterator]() {
|
|
109
|
+
while (true) {
|
|
110
|
+
const event = await this.take();
|
|
111
|
+
if (event === void 0) return;
|
|
112
|
+
yield event;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
var execFileAsync = promisify(execFile);
|
|
117
|
+
var ShellAdapter = class {
|
|
118
|
+
constructor(processManager) {
|
|
119
|
+
this.processManager = processManager;
|
|
120
|
+
}
|
|
121
|
+
kind = "shell";
|
|
122
|
+
async test() {
|
|
123
|
+
try {
|
|
124
|
+
const { stdout } = await execFileAsync("bash", ["--version"]);
|
|
125
|
+
const version = stdout.split("\n")[0]?.trim() ?? "unknown";
|
|
126
|
+
return { ok: true, version };
|
|
127
|
+
} catch {
|
|
128
|
+
return { ok: false, error: "bash not found", errorKind: classifyAdapterError("bash not found") };
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
execute(params) {
|
|
132
|
+
const command = params.config.command;
|
|
133
|
+
if (!command) {
|
|
134
|
+
async function* errorGen() {
|
|
135
|
+
yield {
|
|
136
|
+
type: "error",
|
|
137
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
138
|
+
data: "Shell adapter requires a command in agent config",
|
|
139
|
+
errorKind: "spawn_failed" /* SPAWN_FAILED */
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
return { pid: 0, events: errorGen() };
|
|
143
|
+
}
|
|
144
|
+
const { process: proc, pid } = this.processManager.spawn("bash", ["-lc", command], {
|
|
145
|
+
cwd: params.workspace,
|
|
146
|
+
env: {
|
|
147
|
+
...process.env,
|
|
148
|
+
...params.env,
|
|
149
|
+
ORCHESTRY_TASK_PROMPT: buildFullPrompt(params.systemPrompt, params.prompt)
|
|
150
|
+
},
|
|
151
|
+
signal: params.signal
|
|
152
|
+
});
|
|
153
|
+
const signal = params.signal;
|
|
154
|
+
const processManager = this.processManager;
|
|
155
|
+
async function* generateEvents() {
|
|
156
|
+
const buffer = new EventBuffer();
|
|
157
|
+
const onAbort = () => {
|
|
158
|
+
processManager.killWithGrace(pid, 5e3).catch(() => {
|
|
159
|
+
});
|
|
160
|
+
};
|
|
161
|
+
if (signal) {
|
|
162
|
+
if (signal.aborted) {
|
|
163
|
+
onAbort();
|
|
164
|
+
} else {
|
|
165
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
const stdoutPromise = (async () => {
|
|
169
|
+
if (!proc.stdout) return;
|
|
170
|
+
for await (const line of readLines(proc.stdout)) {
|
|
171
|
+
if (signal?.aborted) break;
|
|
172
|
+
await buffer.push({
|
|
173
|
+
type: "output",
|
|
174
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
175
|
+
data: line
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
})();
|
|
179
|
+
const stderrPromise = (async () => {
|
|
180
|
+
if (!proc.stderr) return;
|
|
181
|
+
for await (const line of readLines(proc.stderr)) {
|
|
182
|
+
if (signal?.aborted) break;
|
|
183
|
+
await buffer.push({
|
|
184
|
+
type: "error",
|
|
185
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
186
|
+
data: line,
|
|
187
|
+
errorKind: classifyAdapterError(line)
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
})();
|
|
191
|
+
void Promise.all([stdoutPromise, stderrPromise]).then(
|
|
192
|
+
() => buffer.close(),
|
|
193
|
+
() => buffer.close()
|
|
194
|
+
);
|
|
195
|
+
yield* buffer;
|
|
196
|
+
if (signal && !signal.aborted) {
|
|
197
|
+
signal.removeEventListener("abort", onAbort);
|
|
198
|
+
}
|
|
199
|
+
await new Promise((resolve, reject) => {
|
|
200
|
+
if (proc.exitCode !== null || proc.killed) {
|
|
201
|
+
resolve();
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
proc.on("close", (code) => {
|
|
205
|
+
if (code === 0 || signal?.aborted) {
|
|
206
|
+
resolve();
|
|
207
|
+
} else {
|
|
208
|
+
reject(new Error(`Shell command exited with code ${code}`));
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
proc.on("error", reject);
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
return { pid, events: generateEvents() };
|
|
215
|
+
}
|
|
216
|
+
async stop(pid) {
|
|
217
|
+
await this.processManager.killWithGrace(pid);
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
export { ShellAdapter };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createStreamingEvents, extractTokens } from './chunk-
|
|
1
|
+
import { createStreamingEvents, extractTokens } from './chunk-C6XZ3FJT.js';
|
|
2
2
|
import './chunk-XDVMX2FO.js';
|
|
3
3
|
import { classifyAdapterError } from './chunk-NLQAJ7TW.js';
|
|
4
4
|
import './chunk-O2MSGW3V.js';
|
|
@@ -38,8 +38,9 @@ var ClaudeAdapter = class {
|
|
|
38
38
|
if (params.config.model) {
|
|
39
39
|
args.push("--model", params.config.model);
|
|
40
40
|
}
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
const effectiveSystemPrompt = params.systemPrompt ?? params.config.system_prompt;
|
|
42
|
+
if (effectiveSystemPrompt) {
|
|
43
|
+
args.push("--system-prompt", effectiveSystemPrompt);
|
|
43
44
|
}
|
|
44
45
|
args.push(params.prompt);
|
|
45
46
|
const { process: proc, pid } = this.processManager.spawn("claude", args, {
|
|
@@ -84,5 +85,5 @@ function parseClaudeEvent(line) {
|
|
|
84
85
|
}
|
|
85
86
|
|
|
86
87
|
export { ClaudeAdapter };
|
|
87
|
-
//# sourceMappingURL=claude-
|
|
88
|
-
//# sourceMappingURL=claude-
|
|
88
|
+
//# sourceMappingURL=claude-WUJU5KIE.js.map
|
|
89
|
+
//# sourceMappingURL=claude-WUJU5KIE.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/infrastructure/adapters/claude.ts"],"names":[],"mappings":"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","file":"claude-WUJU5KIE.js","sourcesContent":["/**\n * Claude Code adapter.\n *\n * Spawns `claude --print --output-format stream-json` in headless mode.\n * Parses JSON-lines 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 { extractTokens, createStreamingEvents } from './utils.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 ClaudeAdapter implements IAgentAdapter {\n readonly kind = 'claude';\n\n constructor(private readonly processManager: IProcessManager) {}\n\n async test(): Promise<AdapterTestResult> {\n try {\n const { stdout } = await execFileAsync('claude', ['--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: 'Claude Code CLI not found. Install: npm i -g @anthropic-ai/claude-code',\n errorKind: classifyAdapterError(msg),\n };\n }\n }\n\n execute(params: ExecuteParams): ExecuteHandle {\n const args = [\n '--print',\n '--output-format', 'stream-json',\n '--max-turns', String(params.config.max_turns ?? 50),\n '--verbose',\n '--dangerously-skip-permissions', // Agents run autonomously; stdin is 'ignore' so prompts would hang\n ];\n\n if (params.config.model) {\n args.push('--model', params.config.model);\n }\n\n // System prompt: orchestrator-generated (cacheable) takes priority, then per-agent config\n const effectiveSystemPrompt = params.systemPrompt ?? params.config.system_prompt;\n if (effectiveSystemPrompt) {\n args.push('--system-prompt', effectiveSystemPrompt);\n }\n\n args.push(params.prompt);\n\n const { process: proc, pid } = this.processManager.spawn('claude', args, {\n cwd: params.workspace,\n env: { ...process.env, ...params.env },\n signal: params.signal,\n });\n\n const events = createStreamingEvents(proc, parseClaudeEvent, 'Claude', 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 parseClaudeEvent(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\n switch (parsed.type) {\n case 'assistant':\n return { type: 'output', timestamp, data: (parsed.message as unknown) ?? parsed };\n case 'tool_use':\n return { type: 'tool_call', timestamp, data: parsed };\n case 'tool_result':\n return { type: 'output', timestamp, data: parsed };\n case 'error': {\n const errData = (parsed.error as unknown) ?? parsed;\n const errMsg = typeof errData === 'string' ? errData : JSON.stringify(errData);\n return { type: 'error', timestamp, data: errData, errorKind: classifyAdapterError(errMsg) };\n }\n case 'result': {\n const tokens = extractTokens(parsed, { statsFallback: true });\n return { type: 'done', timestamp, data: parsed, tokens };\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"]}
|
package/dist/cli.js
CHANGED
|
@@ -1,2 +1,200 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { findProjectRoot } from './chunk-LV6GDBBI.js';
|
|
3
|
+
import { setAsciiMode, setNoColor, printError } from './chunk-7X2GI5OV.js';
|
|
4
|
+
import { OrchestryError, NotInitializedError } from './chunk-2C2TFQ7K.js';
|
|
5
|
+
import { Command } from 'commander';
|
|
6
|
+
|
|
7
|
+
// src/cli/context.ts
|
|
8
|
+
function createContext(opts) {
|
|
9
|
+
const noColor = opts.noColor || "NO_COLOR" in process.env || false;
|
|
10
|
+
const ascii = opts.ascii || process.env["TERM"] === "dumb" || false;
|
|
11
|
+
return {
|
|
12
|
+
projectRoot: findProjectRoot(),
|
|
13
|
+
json: opts.json ?? false,
|
|
14
|
+
quiet: opts.quiet ?? false,
|
|
15
|
+
noColor,
|
|
16
|
+
ascii
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// src/bin/cli.ts
|
|
21
|
+
var LIGHT_COMMANDS = {
|
|
22
|
+
task: async (p, c) => {
|
|
23
|
+
const m = await import('./task-3O2OFSP6.js');
|
|
24
|
+
m.registerTaskCommand(p, c);
|
|
25
|
+
},
|
|
26
|
+
agent: async (p, c) => {
|
|
27
|
+
const m = await import('./agent-7ZJ3ZDJ7.js');
|
|
28
|
+
m.registerAgentCommand(p, c);
|
|
29
|
+
},
|
|
30
|
+
status: async (p, c) => {
|
|
31
|
+
const m = await import('./status-RZWN2C6C.js');
|
|
32
|
+
m.registerStatusCommand(p, c);
|
|
33
|
+
},
|
|
34
|
+
logs: async (p, c) => {
|
|
35
|
+
const m = await import('./logs-PHPYWQ6I.js');
|
|
36
|
+
m.registerLogsCommand(p, c);
|
|
37
|
+
},
|
|
38
|
+
config: async (p, c) => {
|
|
39
|
+
const m = await import('./config-OTAVSMOD.js');
|
|
40
|
+
m.registerConfigCommand(p, c);
|
|
41
|
+
},
|
|
42
|
+
context: async (p, c) => {
|
|
43
|
+
const m = await import('./context-OL4BVUV5.js');
|
|
44
|
+
m.registerContextCommand(p, c);
|
|
45
|
+
},
|
|
46
|
+
msg: async (p, c) => {
|
|
47
|
+
const m = await import('./msg-FUWWLEKM.js');
|
|
48
|
+
m.registerMsgCommand(p, c);
|
|
49
|
+
},
|
|
50
|
+
goal: async (p, c) => {
|
|
51
|
+
const m = await import('./goal-FMYYN2FR.js');
|
|
52
|
+
m.registerGoalCommand(p, c);
|
|
53
|
+
},
|
|
54
|
+
team: async (p, c) => {
|
|
55
|
+
const m = await import('./team-PFLP4PPL.js');
|
|
56
|
+
m.registerTeamCommand(p, c);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
var FULL_COMMANDS = {
|
|
60
|
+
run: async (p, c) => {
|
|
61
|
+
const m = await import('./run-N72G5V2H.js');
|
|
62
|
+
m.registerRunCommand(p, c);
|
|
63
|
+
},
|
|
64
|
+
doctor: async (p, c) => {
|
|
65
|
+
const m = await import('./doctor-XSGQSD57.js');
|
|
66
|
+
m.registerDoctorCommand(p, c);
|
|
67
|
+
},
|
|
68
|
+
tui: async (p, c) => {
|
|
69
|
+
const m = await import('./tui-LN5XHSQY.js');
|
|
70
|
+
m.registerTuiCommand(p, c);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
var program = new Command();
|
|
74
|
+
program.name("orchestry").description("Agents Organizations \u2014 CLI orchestrator for AI agents").version("1.0.0").option("--json", "Output as JSON").option("--quiet", "Minimal output (IDs only)").option("--no-color", "Disable colors").option("--ascii", "ASCII-only output (no Unicode)").hook("preAction", async (thisCommand) => {
|
|
75
|
+
const opts = thisCommand.opts();
|
|
76
|
+
if (opts.ascii) setAsciiMode(true);
|
|
77
|
+
if (opts.color === false) setNoColor(true);
|
|
78
|
+
});
|
|
79
|
+
var COMMAND_STUBS = [
|
|
80
|
+
["task", "Manage tasks"],
|
|
81
|
+
["agent", "Manage agents"],
|
|
82
|
+
["status", "Show orchestrator status"],
|
|
83
|
+
["logs", "View run logs"],
|
|
84
|
+
["config", "Manage configuration"],
|
|
85
|
+
["context", "Shared context store for inter-agent data exchange"],
|
|
86
|
+
["msg", "Inter-agent messaging"],
|
|
87
|
+
["goal", "Manage goals"],
|
|
88
|
+
["team", "Manage teams"],
|
|
89
|
+
["run", "Run tasks"],
|
|
90
|
+
["doctor", "Check adapters and dependencies"],
|
|
91
|
+
["tui", "Launch TUI dashboard"],
|
|
92
|
+
["init", "Initialize project"],
|
|
93
|
+
["update", "Check for updates"]
|
|
94
|
+
];
|
|
95
|
+
var ALL_KNOWN_COMMANDS = new Set(COMMAND_STUBS.map(([name]) => name));
|
|
96
|
+
async function main() {
|
|
97
|
+
program.parseOptions(process.argv);
|
|
98
|
+
const globalOpts = program.opts();
|
|
99
|
+
const context = createContext({
|
|
100
|
+
json: globalOpts.json,
|
|
101
|
+
quiet: globalOpts.quiet,
|
|
102
|
+
noColor: globalOpts.color === false,
|
|
103
|
+
ascii: globalOpts.ascii
|
|
104
|
+
});
|
|
105
|
+
const sub = process.argv.slice(2).find((arg) => !arg.startsWith("-"));
|
|
106
|
+
const hasRealSub = sub !== void 0 && ALL_KNOWN_COMMANDS.has(sub);
|
|
107
|
+
const isHelpOrVersion = process.argv.includes("--help") || process.argv.includes("-h") || process.argv.includes("--version") || process.argv.includes("-V");
|
|
108
|
+
if (isHelpOrVersion && !hasRealSub) {
|
|
109
|
+
for (const [name, desc] of COMMAND_STUBS) {
|
|
110
|
+
program.command(name).description(desc);
|
|
111
|
+
}
|
|
112
|
+
await program.parseAsync(process.argv);
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
if (sub === "init") {
|
|
116
|
+
const { registerInitCommand } = await import('./init-JU343RXK.js');
|
|
117
|
+
registerInitCommand(program);
|
|
118
|
+
} else if (sub === "update") {
|
|
119
|
+
const { registerUpdateCommand } = await import('./update-YLP7FPNY.js');
|
|
120
|
+
registerUpdateCommand(program);
|
|
121
|
+
}
|
|
122
|
+
const needsFull = !sub || sub in FULL_COMMANDS;
|
|
123
|
+
const { buildFullContainer, buildLightContainer } = await import('./container-LUWGNBSS.js');
|
|
124
|
+
try {
|
|
125
|
+
if (needsFull) {
|
|
126
|
+
const container = await buildFullContainer(context);
|
|
127
|
+
const fullLoader = sub ? FULL_COMMANDS[sub] : void 0;
|
|
128
|
+
if (fullLoader) {
|
|
129
|
+
await fullLoader(program, container);
|
|
130
|
+
} else {
|
|
131
|
+
await Promise.all(
|
|
132
|
+
Object.values(FULL_COMMANDS).map((fn) => fn(program, container))
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
const lightLoader = sub ? LIGHT_COMMANDS[sub] : void 0;
|
|
136
|
+
if (lightLoader) {
|
|
137
|
+
await lightLoader(program, container);
|
|
138
|
+
}
|
|
139
|
+
} else {
|
|
140
|
+
const container = await buildLightContainer(context);
|
|
141
|
+
const lightLoader = LIGHT_COMMANDS[sub];
|
|
142
|
+
if (lightLoader) {
|
|
143
|
+
await lightLoader(program, container);
|
|
144
|
+
} else {
|
|
145
|
+
await Promise.all(
|
|
146
|
+
Object.values(LIGHT_COMMANDS).map((fn) => fn(program, container))
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
} catch (err) {
|
|
151
|
+
if (err instanceof NotInitializedError) {
|
|
152
|
+
if (sub === "doctor") {
|
|
153
|
+
const { registerDoctorCommand } = await import('./doctor-XSGQSD57.js');
|
|
154
|
+
registerDoctorCommand(program);
|
|
155
|
+
}
|
|
156
|
+
if (process.argv.length <= 2) {
|
|
157
|
+
const { runInit } = await import('./init-JU343RXK.js');
|
|
158
|
+
await runInit();
|
|
159
|
+
const freshContainer = await buildFullContainer(context);
|
|
160
|
+
await FULL_COMMANDS["tui"](program, freshContainer);
|
|
161
|
+
await program.parseAsync([...process.argv, "tui"]);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
if (sub === "init" || sub === "doctor" || sub === "update") {
|
|
165
|
+
await program.parseAsync(process.argv);
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
printError(err.message, err.hint);
|
|
169
|
+
process.exit(err.exitCode);
|
|
170
|
+
}
|
|
171
|
+
throw err;
|
|
172
|
+
}
|
|
173
|
+
if (process.argv.length <= 2) {
|
|
174
|
+
process.argv.push("tui");
|
|
175
|
+
}
|
|
176
|
+
let updateMod;
|
|
177
|
+
const skipUpdateCheck = sub === "tui" || sub === "update";
|
|
178
|
+
const updateCheck = skipUpdateCheck ? Promise.resolve(null) : import('./update-check-4YKLGBFB.js').then((m) => {
|
|
179
|
+
updateMod = m;
|
|
180
|
+
return m.checkForUpdateSWR(program.version() ?? "0.0.0");
|
|
181
|
+
});
|
|
182
|
+
await program.parseAsync(process.argv);
|
|
183
|
+
if (!skipUpdateCheck) {
|
|
184
|
+
const info = await updateCheck;
|
|
185
|
+
if (info && updateMod) updateMod.printUpdateNotification(info);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
main().catch((err) => {
|
|
189
|
+
if (err instanceof OrchestryError) {
|
|
190
|
+
printError(err.message, err.hint);
|
|
191
|
+
process.exit(err.exitCode);
|
|
192
|
+
}
|
|
193
|
+
printError(
|
|
194
|
+
err instanceof Error ? err.message : String(err)
|
|
195
|
+
);
|
|
196
|
+
if (process.env["ORCHESTRY_DEBUG"]) {
|
|
197
|
+
console.error(err);
|
|
198
|
+
}
|
|
199
|
+
process.exit(1);
|
|
200
|
+
});
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { OrchestryError } from './chunk-2C2TFQ7K.js';
|
|
3
|
+
import { execFile as execFile$1, execFileSync } from 'child_process';
|
|
4
|
+
import { promisify } from 'util';
|
|
5
|
+
import { mkdtemp, readFile, unlink, rm } from 'fs/promises';
|
|
6
|
+
import { tmpdir } from 'os';
|
|
7
|
+
import { join } from 'path';
|
|
8
|
+
|
|
9
|
+
var execFile = promisify(execFile$1);
|
|
10
|
+
var EXEC_TIMEOUT_MS = 3e3;
|
|
11
|
+
function isClipboardToolAvailable() {
|
|
12
|
+
const platform = process.platform;
|
|
13
|
+
if (platform === "darwin") {
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
if (platform === "linux") {
|
|
17
|
+
try {
|
|
18
|
+
execFileSync("which", ["xclip"], { timeout: EXEC_TIMEOUT_MS, stdio: "ignore" });
|
|
19
|
+
return true;
|
|
20
|
+
} catch {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
if (platform === "win32") {
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
async function detectClipboardType() {
|
|
30
|
+
const platform = process.platform;
|
|
31
|
+
if (platform === "darwin") {
|
|
32
|
+
return detectMacOS();
|
|
33
|
+
}
|
|
34
|
+
if (platform === "linux") {
|
|
35
|
+
return detectLinux();
|
|
36
|
+
}
|
|
37
|
+
if (platform === "win32") {
|
|
38
|
+
return detectWindows();
|
|
39
|
+
}
|
|
40
|
+
throw new OrchestryError(
|
|
41
|
+
`Unsupported platform for clipboard: ${platform}`,
|
|
42
|
+
1,
|
|
43
|
+
"Supported: macOS, Linux, Windows"
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
async function getClipboardImage() {
|
|
47
|
+
const type = await detectClipboardType();
|
|
48
|
+
if (type !== "image") return null;
|
|
49
|
+
const platform = process.platform;
|
|
50
|
+
if (platform === "darwin") {
|
|
51
|
+
return getImageMacOS();
|
|
52
|
+
}
|
|
53
|
+
if (platform === "linux") {
|
|
54
|
+
return getImageLinux();
|
|
55
|
+
}
|
|
56
|
+
if (platform === "win32") {
|
|
57
|
+
return getImageWindows();
|
|
58
|
+
}
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
async function detectMacOS() {
|
|
62
|
+
try {
|
|
63
|
+
const { stdout } = await execFile("osascript", ["-e", "clipboard info"], {
|
|
64
|
+
timeout: EXEC_TIMEOUT_MS
|
|
65
|
+
});
|
|
66
|
+
if (stdout.includes("\xABclass PNGf\xBB") || stdout.includes("\xABclass TIFF\xBB")) {
|
|
67
|
+
return "image";
|
|
68
|
+
}
|
|
69
|
+
if (stdout.includes("\xABclass ut16\xBB") || stdout.includes("\xABclass utf8\xBB")) {
|
|
70
|
+
return "text";
|
|
71
|
+
}
|
|
72
|
+
return stdout.trim().length > 0 ? "text" : "empty";
|
|
73
|
+
} catch {
|
|
74
|
+
return "empty";
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
async function getImageMacOS() {
|
|
78
|
+
const dir = await mkdtemp(join(tmpdir(), "orch-clip-"));
|
|
79
|
+
const filePath = join(dir, "clipboard.png");
|
|
80
|
+
try {
|
|
81
|
+
const script = `
|
|
82
|
+
set theFile to POSIX file "${filePath}"
|
|
83
|
+
try
|
|
84
|
+
set imgData to the clipboard as \xABclass PNGf\xBB
|
|
85
|
+
set fRef to open for access theFile with write permission
|
|
86
|
+
write imgData to fRef
|
|
87
|
+
close access fRef
|
|
88
|
+
return "ok"
|
|
89
|
+
on error
|
|
90
|
+
try
|
|
91
|
+
close access theFile
|
|
92
|
+
end try
|
|
93
|
+
return "error"
|
|
94
|
+
end try
|
|
95
|
+
`;
|
|
96
|
+
const { stdout } = await execFile("osascript", ["-e", script], {
|
|
97
|
+
timeout: EXEC_TIMEOUT_MS
|
|
98
|
+
});
|
|
99
|
+
if (stdout.trim() !== "ok") return null;
|
|
100
|
+
const data = await readFile(filePath);
|
|
101
|
+
return { data, ext: "png" };
|
|
102
|
+
} catch {
|
|
103
|
+
return null;
|
|
104
|
+
} finally {
|
|
105
|
+
try {
|
|
106
|
+
await unlink(filePath);
|
|
107
|
+
} catch {
|
|
108
|
+
}
|
|
109
|
+
try {
|
|
110
|
+
await rm(dir, { recursive: true });
|
|
111
|
+
} catch {
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
async function detectLinux() {
|
|
116
|
+
try {
|
|
117
|
+
const { stdout } = await execFile(
|
|
118
|
+
"xclip",
|
|
119
|
+
["-selection", "clipboard", "-t", "TARGETS", "-o"],
|
|
120
|
+
{ timeout: EXEC_TIMEOUT_MS }
|
|
121
|
+
);
|
|
122
|
+
const targets = stdout.toLowerCase();
|
|
123
|
+
if (targets.includes("image/png") || targets.includes("image/tiff") || targets.includes("image/jpeg")) {
|
|
124
|
+
return "image";
|
|
125
|
+
}
|
|
126
|
+
if (targets.includes("text/plain") || targets.includes("utf8_string") || targets.includes("string")) {
|
|
127
|
+
return "text";
|
|
128
|
+
}
|
|
129
|
+
return targets.trim().length > 0 ? "text" : "empty";
|
|
130
|
+
} catch {
|
|
131
|
+
return "empty";
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
async function getImageLinux() {
|
|
135
|
+
try {
|
|
136
|
+
const { stdout } = await execFile(
|
|
137
|
+
"xclip",
|
|
138
|
+
["-selection", "clipboard", "-t", "image/png", "-o"],
|
|
139
|
+
{ timeout: EXEC_TIMEOUT_MS, encoding: "buffer", maxBuffer: 50 * 1024 * 1024 }
|
|
140
|
+
);
|
|
141
|
+
const data = Buffer.isBuffer(stdout) ? stdout : Buffer.from(stdout, "binary");
|
|
142
|
+
if (data.length === 0) return null;
|
|
143
|
+
return { data, ext: "png" };
|
|
144
|
+
} catch {
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
async function detectWindows() {
|
|
149
|
+
try {
|
|
150
|
+
const { stdout: imgCheck } = await execFile(
|
|
151
|
+
"powershell",
|
|
152
|
+
["-NoProfile", "-Command", 'if (Get-Clipboard -Format Image) { "image" } else { "none" }'],
|
|
153
|
+
{ timeout: EXEC_TIMEOUT_MS }
|
|
154
|
+
);
|
|
155
|
+
if (imgCheck.trim() === "image") return "image";
|
|
156
|
+
const { stdout: textCheck } = await execFile(
|
|
157
|
+
"powershell",
|
|
158
|
+
["-NoProfile", "-Command", 'if (Get-Clipboard) { "text" } else { "empty" }'],
|
|
159
|
+
{ timeout: EXEC_TIMEOUT_MS }
|
|
160
|
+
);
|
|
161
|
+
return textCheck.trim() === "text" ? "text" : "empty";
|
|
162
|
+
} catch {
|
|
163
|
+
return "empty";
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
async function getImageWindows() {
|
|
167
|
+
const dir = await mkdtemp(join(tmpdir(), "orch-clip-"));
|
|
168
|
+
const filePath = join(dir, "clipboard.png");
|
|
169
|
+
try {
|
|
170
|
+
const script = `
|
|
171
|
+
Add-Type -AssemblyName System.Windows.Forms
|
|
172
|
+
$img = [System.Windows.Forms.Clipboard]::GetImage()
|
|
173
|
+
if ($img) {
|
|
174
|
+
$img.Save('${filePath.replace(/\\/g, "\\\\")}', [System.Drawing.Imaging.ImageFormat]::Png)
|
|
175
|
+
Write-Output 'ok'
|
|
176
|
+
} else {
|
|
177
|
+
Write-Output 'error'
|
|
178
|
+
}
|
|
179
|
+
`;
|
|
180
|
+
const { stdout } = await execFile("powershell", ["-NoProfile", "-Command", script], {
|
|
181
|
+
timeout: EXEC_TIMEOUT_MS
|
|
182
|
+
});
|
|
183
|
+
if (stdout.trim() !== "ok") return null;
|
|
184
|
+
const data = await readFile(filePath);
|
|
185
|
+
return { data, ext: "png" };
|
|
186
|
+
} catch {
|
|
187
|
+
return null;
|
|
188
|
+
} finally {
|
|
189
|
+
try {
|
|
190
|
+
await unlink(filePath);
|
|
191
|
+
} catch {
|
|
192
|
+
}
|
|
193
|
+
try {
|
|
194
|
+
await rm(dir, { recursive: true });
|
|
195
|
+
} catch {
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export { detectClipboardType, getClipboardImage, isClipboardToolAvailable };
|