@karowanorg/orc-ops 0.1.0 → 0.1.2
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/guide.d.ts +1 -1
- package/dist/guide.js +2 -3
- package/dist/ops.d.ts +1 -10
- package/dist/ops.js +18 -28
- package/dist/registry.js +2 -2
- package/package.json +6 -6
package/dist/guide.d.ts
CHANGED
|
@@ -3,4 +3,4 @@
|
|
|
3
3
|
* - CLI: `orc guide`
|
|
4
4
|
* - MCP: the `orc_guide` tool
|
|
5
5
|
*/
|
|
6
|
-
export declare const GUIDE = "# orc \u2014 how to write and run a program\n\norc runs a \"program\": a script that fans out AI-agent subtasks (\"leaves\") and\nrecords each one, so a run is reproducible, resumable, and observable. You write\na program, launch it, then watch it and collect the result.\n\n## 1. Write a program\n\nA program is a `.orc.ts` file with a single default-exported async function.\nIt receives an api object and returns the run's result:\n\n import type { Program } from \"@karowanorg/orc-sdk/program\"; // optional, type-only\n\n const program: Program = async ({ agent, parallel, phase }) => {\n const inventory = await agent(\"List the modules in this repo.\", {\n schema: { type: \"object\",\n properties: { modules: { type: \"array\", items: { type: \"string\" } } },\n required: [\"modules\"] },\n });\n\n // Ordinary async/await controls the flow. Awaiting a result before the\n // next call makes it a dependency; independent calls run concurrently.\n const plans = await Promise.all((inventory.modules as string[]).map(async (m) => {\n const findings = await agent(`Audit module ${m}`, { id: `audit-${m}` });\n return agent(`Plan a fix for ${m}: ${JSON.stringify(findings)}`, { id: `plan-${m}` });\n }));\n\n return phase(\"synthesis\", () => agent(`Merge these plans: ${JSON.stringify(plans)}`, { id: \"merge\" }));\n };\n export default program;\n\n## The api\n\nIMPORTANT \u2014 leaves are isolated. Each agent() runs a FRESH subagent that shares\nNONE of your context: it cannot see this program, your conversation, other\nleaves' prompts or results, or anything you know that you haven't written into\nits prompt (plus the shared `--brief`).\n\n- agent(prompt, opts?) => Promise<result>\n Dispatch one agent. Returns its result (matching `schema` if you pass one).\n A failed leaf rejects the promise, so wrap it in try/catch if you want to\n handle failure. Options:\n id a label shown in the monitor\n schema JSON Schema; the result is structured output matching it\n harness \"claude\" | \"codex\" | a configured harness (default: auto)\n model e.g. \"claude-fable-5\", \"gpt-5.6-sol\"\n reasoningEffort \"low\" | \"medium\" | \"high\" | \"xhigh\" | \"max\"\n readOnly default true; set false for a leaf that edits files\n cwd working directory for this leaf (defaults to the run's)\n
|
|
6
|
+
export declare const GUIDE = "# orc \u2014 how to write and run a program\n\norc runs a \"program\": a script that fans out AI-agent subtasks (\"leaves\") and\nrecords each one, so a run is reproducible, resumable, and observable. You write\na program, launch it, then watch it and collect the result.\n\n## 1. Write a program\n\nA program is a `.orc.ts` file with a single default-exported async function.\nIt receives an api object and returns the run's result:\n\n import type { Program } from \"@karowanorg/orc-sdk/program\"; // optional, type-only\n\n const program: Program = async ({ agent, parallel, phase }) => {\n const inventory = await agent(\"List the modules in this repo.\", {\n schema: { type: \"object\",\n properties: { modules: { type: \"array\", items: { type: \"string\" } } },\n required: [\"modules\"] },\n });\n\n // Ordinary async/await controls the flow. Awaiting a result before the\n // next call makes it a dependency; independent calls run concurrently.\n const plans = await Promise.all((inventory.modules as string[]).map(async (m) => {\n const findings = await agent(`Audit module ${m}`, { id: `audit-${m}` });\n return agent(`Plan a fix for ${m}: ${JSON.stringify(findings)}`, { id: `plan-${m}` });\n }));\n\n return phase(\"synthesis\", () => agent(`Merge these plans: ${JSON.stringify(plans)}`, { id: \"merge\" }));\n };\n export default program;\n\n## The api\n\nIMPORTANT \u2014 leaves are isolated. Each agent() runs a FRESH subagent that shares\nNONE of your context: it cannot see this program, your conversation, other\nleaves' prompts or results, or anything you know that you haven't written into\nits prompt (plus the shared `--brief`).\n\n- agent(prompt, opts?) => Promise<result>\n Dispatch one agent. Returns its result (matching `schema` if you pass one).\n A failed leaf rejects the promise, so wrap it in try/catch if you want to\n handle failure. Options:\n id a label shown in the monitor\n schema JSON Schema; the result is structured output matching it\n harness \"claude\" | \"codex\" | a configured harness (default: auto)\n model e.g. \"claude-fable-5\", \"gpt-5.6-sol\"\n reasoningEffort \"low\" | \"medium\" | \"high\" | \"xhigh\" | \"max\"\n readOnly default true; set false for a leaf that edits files\n cwd working directory for this leaf (defaults to the run's)\n idleTimeout ms with no output before the leaf is killed (false = off)\n phase group this call under a phase label\n To see valid `harness`, `model`, and `reasoningEffort` values for your\n machine, run `orc capabilities` (or `orc capabilities --json`) \u2014 it lists\n each installed harness with its available models and reasoning levels.\n Omit any of them to use the default; an unknown value is rejected up front\n by `orc validate`.\n\n- parallel(specs[]) => Promise<outcomes[]>\n Run several agents at once from an array of option objects (each with a\n `prompt`). Every lane runs to completion INDEPENDENTLY \u2014 one lane failing\n never cancels the others. Outcomes come back in order as\n `{ status: \"ok\", value } | { status: \"error\", error }`, so you decide how to\n handle partial failure. (For fail-fast, use `Promise.all` over `agent()`,\n which rejects on the first failure.)\n\n- phase(name, fn) => Promise<result>\n Group every agent() call made inside `fn` under a phase, for a readable\n run timeline.\n\n- settle(promise) => { status: \"ok\", value } | { status: \"error\", error }\n Run a lane and capture its outcome instead of letting a failure stop the run\n \u2014 useful for \"do all of these, some may fail\" fan-outs.\n\n- log(message) \u2014 write a line to the run's live event feed.\n- ext.<name>(payload) \u2014 call a custom step you registered in orc.config.\n\nBecause leaves can't see each other, pass data between them as plain values:\nput a previous result into the next prompt with JSON.stringify so the receiving\nleaf actually has it. Use normal try/catch, Promise.all/allSettled, and bounded\nloops for control flow.\n\n## What a program may and may not do\n\n- No wall clock or randomness. `Date`, `Math.random`, timers, network, file\n access, and imports (beyond type-only) are unavailable \u2014 a program only\n decides which agents to run and how to combine their results.\n- Loops must be finite; an unbounded loop is stopped by a step limit.\n- These constraints let orc replay a program exactly when you resume it, so the\n same inputs always produce the same run.\n\n## Writing files\n\nBy default leaves are read-only. To let a leaf directly modify files or run\nmutating commands, set `readOnly: false` and launch the run with\n`--allow-writes`. Configured hooks and MCP tools are not disabled for read-only\nleaves; their side effects are outside this guarantee. A write leaf runs with\nwhatever permissions your own agent has; add `--sandbox` to confine its writes\nto the working directory. If a run stops on a write leaf, `orc resume` picks it\nback up (it re-checks the working-tree state first, never blindly redoing work).\n\n## 2. Validate and launch\n\n orc validate --program-path ./my.orc.ts # compile + preview, no run\n orc launch --program-path ./my.orc.ts --brief \"what this run is for\"\n\n`--brief` (required) is shared context added to every leaf. Common launch flags:\n`--allow-writes`, `--approval-mode manual|accept-edits|auto|bypass`,\n`--sandbox`, `--harness claude|codex`, `--budget <usd>` (fail the run after\nobserved estimated cost exceeds this; concurrent work may overshoot), `--wait`\n(block for the result instead of running in the background).\n\n## 3. Watch and collect\n\n orc status --run-id <id> # summary\n orc wait --run-id <id> # block until it finishes\n orc get-result --run-id <id> # the final result (or --seq N for one leaf)\n orc trace --run-id <id> # per-leaf and per-tool detail\n orc open --run-id <id> # open the live monitor, print its URL\n orc list # recent runs\n\n## 4. Approvals\n\nIn `manual` or `accept-edits` mode a leaf can pause to ask permission for a\ntool. Answer it from anywhere:\n\n orc approvals --run-id <id>\n orc respond --run-id <id> --approval-id <aid> --behavior allow|deny\n\n## Discover more\n\n orc --help # every command\n orc <command> --help # a command's flags\n orc commands # JSON catalog of all operations\n orc capabilities # available harnesses, models, and reasoning levels\n orc doctor # check this machine is ready\n\nEvery command supports `--json`. Run state lives in `$ORC_HOME` (default\n`~/.orc`). Real runs need `claude` and/or `codex` installed and logged in.\n";
|
package/dist/guide.js
CHANGED
|
@@ -52,7 +52,6 @@ its prompt (plus the shared \`--brief\`).
|
|
|
52
52
|
reasoningEffort "low" | "medium" | "high" | "xhigh" | "max"
|
|
53
53
|
readOnly default true; set false for a leaf that edits files
|
|
54
54
|
cwd working directory for this leaf (defaults to the run's)
|
|
55
|
-
host SSH destination to run this leaf on a remote machine
|
|
56
55
|
idleTimeout ms with no output before the leaf is killed (false = off)
|
|
57
56
|
phase group this call under a phase label
|
|
58
57
|
To see valid \`harness\`, \`model\`, and \`reasoningEffort\` values for your
|
|
@@ -110,7 +109,7 @@ back up (it re-checks the working-tree state first, never blindly redoing work).
|
|
|
110
109
|
orc launch --program-path ./my.orc.ts --brief "what this run is for"
|
|
111
110
|
|
|
112
111
|
\`--brief\` (required) is shared context added to every leaf. Common launch flags:
|
|
113
|
-
\`--allow-writes\`, \`--
|
|
112
|
+
\`--allow-writes\`, \`--approval-mode manual|accept-edits|auto|bypass\`,
|
|
114
113
|
\`--sandbox\`, \`--harness claude|codex\`, \`--budget <usd>\` (fail the run after
|
|
115
114
|
observed estimated cost exceeds this; concurrent work may overshoot), \`--wait\`
|
|
116
115
|
(block for the result instead of running in the background).
|
|
@@ -138,7 +137,7 @@ tool. Answer it from anywhere:
|
|
|
138
137
|
orc <command> --help # a command's flags
|
|
139
138
|
orc commands # JSON catalog of all operations
|
|
140
139
|
orc capabilities # available harnesses, models, and reasoning levels
|
|
141
|
-
orc doctor
|
|
140
|
+
orc doctor # check this machine is ready
|
|
142
141
|
|
|
143
142
|
Every command supports \`--json\`. Run state lives in \`$ORC_HOME\` (default
|
|
144
143
|
\`~/.orc\`). Real runs need \`claude\` and/or \`codex\` installed and logged in.
|
package/dist/ops.d.ts
CHANGED
|
@@ -18,7 +18,6 @@ interface FirstFrontierCall {
|
|
|
18
18
|
id?: string;
|
|
19
19
|
readOnly: boolean;
|
|
20
20
|
harness?: string;
|
|
21
|
-
host?: string;
|
|
22
21
|
model?: string;
|
|
23
22
|
reasoningEffort?: string;
|
|
24
23
|
schema?: Json;
|
|
@@ -27,7 +26,6 @@ interface FirstFrontierCall {
|
|
|
27
26
|
export declare const launch: OpDef<z.ZodObject<{
|
|
28
27
|
programPath: z.ZodString;
|
|
29
28
|
cwd: z.ZodOptional<z.ZodString>;
|
|
30
|
-
host: z.ZodOptional<z.ZodString>;
|
|
31
29
|
brief: z.ZodString;
|
|
32
30
|
allowWrites: z.ZodDefault<z.ZodBoolean>;
|
|
33
31
|
approvalMode: z.ZodDefault<z.ZodEnum<{
|
|
@@ -38,6 +36,7 @@ export declare const launch: OpDef<z.ZodObject<{
|
|
|
38
36
|
}>>;
|
|
39
37
|
sandbox: z.ZodDefault<z.ZodBoolean>;
|
|
40
38
|
sandboxDirs: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
39
|
+
networkAccess: z.ZodDefault<z.ZodBoolean>;
|
|
41
40
|
maxParallel: z.ZodOptional<z.ZodNumber>;
|
|
42
41
|
idleTimeoutSeconds: z.ZodOptional<z.ZodNumber>;
|
|
43
42
|
budget: z.ZodOptional<z.ZodNumber>;
|
|
@@ -79,7 +78,6 @@ export declare const validate: OpDef<z.ZodObject<{
|
|
|
79
78
|
bypass: "bypass";
|
|
80
79
|
}>>;
|
|
81
80
|
harness: z.ZodOptional<z.ZodString>;
|
|
82
|
-
host: z.ZodOptional<z.ZodString>;
|
|
83
81
|
checkCapabilities: z.ZodDefault<z.ZodBoolean>;
|
|
84
82
|
}, z.core.$strip>, {
|
|
85
83
|
ok: boolean;
|
|
@@ -137,7 +135,6 @@ export declare const getTrace: OpDef<z.ZodObject<{
|
|
|
137
135
|
harness?: string;
|
|
138
136
|
model?: string;
|
|
139
137
|
reasoningEffort?: string;
|
|
140
|
-
host?: string;
|
|
141
138
|
cwd?: string;
|
|
142
139
|
readOnly: boolean;
|
|
143
140
|
startMs: number;
|
|
@@ -159,7 +156,6 @@ export declare const list: OpDef<z.ZodObject<{
|
|
|
159
156
|
name: string | undefined;
|
|
160
157
|
state: string;
|
|
161
158
|
createdAtMs: number;
|
|
162
|
-
host: string | undefined;
|
|
163
159
|
cwd: string;
|
|
164
160
|
}[]>;
|
|
165
161
|
export declare const cancel: OpDef<z.ZodObject<{
|
|
@@ -194,10 +190,8 @@ export declare const respondApproval: OpDef<z.ZodObject<{
|
|
|
194
190
|
enqueued: boolean;
|
|
195
191
|
}>;
|
|
196
192
|
export declare const capabilities: OpDef<z.ZodObject<{
|
|
197
|
-
host: z.ZodOptional<z.ZodString>;
|
|
198
193
|
refresh: z.ZodDefault<z.ZodBoolean>;
|
|
199
194
|
}, z.core.$strip>, {
|
|
200
|
-
host: string;
|
|
201
195
|
defaultHarness: string;
|
|
202
196
|
harnesses: Record<string, unknown>;
|
|
203
197
|
extensions: string[];
|
|
@@ -214,16 +208,13 @@ export declare const report: OpDef<z.ZodObject<{
|
|
|
214
208
|
path: string;
|
|
215
209
|
}>;
|
|
216
210
|
export declare const guide: OpDef<z.ZodObject<{
|
|
217
|
-
host: z.ZodOptional<z.ZodString>;
|
|
218
211
|
probe: z.ZodDefault<z.ZodBoolean>;
|
|
219
212
|
}, z.core.$strip>, {
|
|
220
213
|
guide: string;
|
|
221
214
|
}>;
|
|
222
215
|
export declare const doctor: OpDef<z.ZodObject<{
|
|
223
|
-
host: z.ZodOptional<z.ZodString>;
|
|
224
216
|
cwd: z.ZodOptional<z.ZodString>;
|
|
225
217
|
}, z.core.$strip>, {
|
|
226
|
-
host: string;
|
|
227
218
|
checks: Record<string, unknown>;
|
|
228
219
|
}>;
|
|
229
220
|
export declare const ALL_OPS: OpDef[];
|
package/dist/ops.js
CHANGED
|
@@ -25,12 +25,12 @@ export const launch = defineOp({
|
|
|
25
25
|
input: z.object({
|
|
26
26
|
programPath: z.string().describe("path to the program (.orc.ts/.ts/.js)"),
|
|
27
27
|
cwd: z.string().optional().describe("working directory (plain path); defaults to the caller's cwd"),
|
|
28
|
-
host: z.string().optional().describe("SSH destination (separate field; e.g. 'build@ci-box' or an ssh-config alias)"),
|
|
29
28
|
brief: z.string().describe("shared context injected into every leaf"),
|
|
30
29
|
allowWrites: z.boolean().default(false).describe("grant write-declared leaves permission to mutate files"),
|
|
31
30
|
approvalMode: ApprovalMode.default("auto").describe("manual | accept-edits | auto | bypass"),
|
|
32
31
|
sandbox: z.boolean().default(false).describe("confine write leaves to cwd + sandboxDirs (default: unconfined, like the caller)"),
|
|
33
32
|
sandboxDirs: z.array(z.string()).optional().describe("extra writable roots when sandboxed (e.g. cache dirs outside the workspace)"),
|
|
33
|
+
networkAccess: z.boolean().default(false).describe("permit outbound network while retaining filesystem sandboxing"),
|
|
34
34
|
maxParallel: z.number().int().min(1).max(64).optional(),
|
|
35
35
|
idleTimeoutSeconds: z.number().int().optional().describe("run default for the per-call output-idle watchdog; 0 disables"),
|
|
36
36
|
budget: z.number().positive().optional().describe("reactive USD cap: fail the run once observed estimated cost exceeds this (may overshoot)"),
|
|
@@ -42,12 +42,12 @@ export const launch = defineOp({
|
|
|
42
42
|
const manifest = await prepareRun({
|
|
43
43
|
programPath: input.programPath,
|
|
44
44
|
cwd: input.cwd,
|
|
45
|
-
host: input.host,
|
|
46
45
|
brief: input.brief,
|
|
47
46
|
allowWrites: input.allowWrites,
|
|
48
47
|
approvalMode: input.approvalMode,
|
|
49
48
|
sandbox: input.sandbox,
|
|
50
49
|
sandboxDirs: input.sandboxDirs,
|
|
50
|
+
networkAccess: input.networkAccess,
|
|
51
51
|
maxParallel: input.maxParallel,
|
|
52
52
|
idleTimeout: input.idleTimeoutSeconds === undefined
|
|
53
53
|
? undefined
|
|
@@ -87,7 +87,6 @@ export const validate = defineOp({
|
|
|
87
87
|
allowWrites: z.boolean().default(false),
|
|
88
88
|
approvalMode: ApprovalMode.default("auto").describe("check the first-frontier harnesses can honor this mode"),
|
|
89
89
|
harness: z.string().optional().describe("default harness override (same precedence as launch)"),
|
|
90
|
-
host: z.string().optional().describe("check capabilities on this remote host"),
|
|
91
90
|
checkCapabilities: z.boolean().default(true).describe("probe referenced harnesses for model/effort/mode support (slower)"),
|
|
92
91
|
}),
|
|
93
92
|
async handler(input, ctx) {
|
|
@@ -105,7 +104,6 @@ export const validate = defineOp({
|
|
|
105
104
|
id: spec.id,
|
|
106
105
|
readOnly: spec.readOnly,
|
|
107
106
|
harness: spec.harness,
|
|
108
|
-
host: spec.host,
|
|
109
107
|
model: spec.model,
|
|
110
108
|
reasoningEffort: spec.reasoningEffort,
|
|
111
109
|
schema: spec.schema,
|
|
@@ -127,19 +125,16 @@ export const validate = defineOp({
|
|
|
127
125
|
finally {
|
|
128
126
|
vm?.dispose();
|
|
129
127
|
}
|
|
130
|
-
// Host can change per leaf, so only share probes with the same effective
|
|
131
|
-
// harness and executor destination.
|
|
132
128
|
const capsCache = new Map();
|
|
133
|
-
const capsFor = (harnessName
|
|
134
|
-
const
|
|
135
|
-
const cached = capsCache.get(key);
|
|
129
|
+
const capsFor = (harnessName) => {
|
|
130
|
+
const cached = capsCache.get(harnessName);
|
|
136
131
|
if (cached)
|
|
137
132
|
return cached;
|
|
138
133
|
const harness = ctx.registry.harnesses.get(harnessName);
|
|
139
134
|
if (!harness)
|
|
140
135
|
return Promise.reject(new Error(`unknown harness "${harnessName}"`));
|
|
141
|
-
const pending = Promise.resolve().then(() => harness.discover({ executor: ctx.registry.
|
|
142
|
-
capsCache.set(
|
|
136
|
+
const pending = Promise.resolve().then(() => harness.discover({ executor: ctx.registry.executor }));
|
|
137
|
+
capsCache.set(harnessName, pending);
|
|
143
138
|
return pending;
|
|
144
139
|
};
|
|
145
140
|
for (const call of firstCalls) {
|
|
@@ -159,7 +154,6 @@ export const validate = defineOp({
|
|
|
159
154
|
}
|
|
160
155
|
if (call.kind === "agent") {
|
|
161
156
|
const harnessName = call.harness ?? input.harness ?? ctx.registry.defaultHarness;
|
|
162
|
-
const host = call.host ?? input.host;
|
|
163
157
|
const harness = ctx.registry.harnesses.get(harnessName);
|
|
164
158
|
if (!harness) {
|
|
165
159
|
problems.push(`call ${call.seq} uses unknown harness "${harnessName}" (available: ${[...ctx.registry.harnesses.keys()].join(", ")})`);
|
|
@@ -177,10 +171,10 @@ export const validate = defineOp({
|
|
|
177
171
|
if (harness && input.checkCapabilities) {
|
|
178
172
|
let caps;
|
|
179
173
|
try {
|
|
180
|
-
caps = await capsFor(harnessName
|
|
174
|
+
caps = await capsFor(harnessName);
|
|
181
175
|
}
|
|
182
176
|
catch (err) {
|
|
183
|
-
problems.push(`call ${call.seq}: could not discover harness "${harnessName}"
|
|
177
|
+
problems.push(`call ${call.seq}: could not discover harness "${harnessName}" (${String(err instanceof Error ? err.message : err)})`);
|
|
184
178
|
continue;
|
|
185
179
|
}
|
|
186
180
|
if (!caps.available) {
|
|
@@ -218,7 +212,7 @@ export const validate = defineOp({
|
|
|
218
212
|
}
|
|
219
213
|
const approvalMode = input.approvalMode ?? "auto";
|
|
220
214
|
if (caps.approvalModes.length > 0 && !caps.approvalModes.includes(approvalMode)) {
|
|
221
|
-
problems.push(`call ${call.seq}: harness "${harnessName}" cannot honor approval mode "${approvalMode}"
|
|
215
|
+
problems.push(`call ${call.seq}: harness "${harnessName}" cannot honor approval mode "${approvalMode}" (supports: ${caps.approvalModes.join(", ")})`);
|
|
222
216
|
}
|
|
223
217
|
}
|
|
224
218
|
}
|
|
@@ -322,13 +316,13 @@ export const list = defineOp({
|
|
|
322
316
|
catch {
|
|
323
317
|
/* partial run dir */
|
|
324
318
|
}
|
|
325
|
-
return { runId: m.runId, name: m.name, state, createdAtMs: m.createdAtMs,
|
|
319
|
+
return { runId: m.runId, name: m.name, state, createdAtMs: m.createdAtMs, cwd: m.cwd };
|
|
326
320
|
});
|
|
327
321
|
},
|
|
328
322
|
});
|
|
329
323
|
export const cancel = defineOp({
|
|
330
324
|
name: "cancel",
|
|
331
|
-
doc: "Queue cancellation.
|
|
325
|
+
doc: "Queue cancellation. Leaves get TERM→KILL on their whole process group.",
|
|
332
326
|
readOnly: false,
|
|
333
327
|
input: z.object({ runId: RunId }),
|
|
334
328
|
async handler(input) {
|
|
@@ -401,11 +395,10 @@ export const capabilities = defineOp({
|
|
|
401
395
|
doc: "List harnesses, models, and reasoning levels — each discovered through the harness's native mechanism.",
|
|
402
396
|
readOnly: true,
|
|
403
397
|
input: z.object({
|
|
404
|
-
host: z.string().optional().describe("probe a remote host instead of local"),
|
|
405
398
|
refresh: z.boolean().default(false),
|
|
406
399
|
}),
|
|
407
400
|
async handler(input, ctx) {
|
|
408
|
-
const executor = ctx.registry.
|
|
401
|
+
const executor = ctx.registry.executor;
|
|
409
402
|
const out = {};
|
|
410
403
|
for (const [name, harness] of ctx.registry.harnesses) {
|
|
411
404
|
out[name] = await harness.discover({ executor }).catch((err) => ({
|
|
@@ -414,7 +407,6 @@ export const capabilities = defineOp({
|
|
|
414
407
|
}));
|
|
415
408
|
}
|
|
416
409
|
return {
|
|
417
|
-
host: input.host ?? "(local)",
|
|
418
410
|
defaultHarness: ctx.registry.defaultHarness,
|
|
419
411
|
harnesses: out,
|
|
420
412
|
extensions: [...ctx.registry.extensions.keys()],
|
|
@@ -450,7 +442,6 @@ export const guide = defineOp({
|
|
|
450
442
|
doc: "How to write and run an orc program — the authoring + usage guide, with this machine's live harness/model catalog appended.",
|
|
451
443
|
readOnly: true,
|
|
452
444
|
input: z.object({
|
|
453
|
-
host: z.string().optional().describe("probe this remote host's harnesses instead of local"),
|
|
454
445
|
probe: z.boolean().default(true).describe("append the live capability catalog (set false for the static doc only)"),
|
|
455
446
|
}),
|
|
456
447
|
async handler(input, ctx) {
|
|
@@ -461,7 +452,7 @@ export const guide = defineOp({
|
|
|
461
452
|
// values in hand instead of guessing. Never let a slow or missing harness
|
|
462
453
|
// break the guide — degrade to the static doc, which already points at
|
|
463
454
|
// `orc capabilities`.
|
|
464
|
-
const caps = await withDeadline(capabilities.handler({
|
|
455
|
+
const caps = await withDeadline(capabilities.handler({ refresh: false }, ctx), 15_000).catch(() => null);
|
|
465
456
|
return { guide: GUIDE + (caps ? renderCapabilitiesForGuide(caps) : "") };
|
|
466
457
|
},
|
|
467
458
|
});
|
|
@@ -483,7 +474,7 @@ function renderCapabilitiesForGuide(caps) {
|
|
|
483
474
|
"",
|
|
484
475
|
"## Available on this machine",
|
|
485
476
|
"",
|
|
486
|
-
|
|
477
|
+
"Discovered live — these are the valid \`harness\`, \`model\`, and",
|
|
487
478
|
`\`reasoningEffort\` values right now, so you don't have to guess. Default harness: **${c.defaultHarness}**.`,
|
|
488
479
|
"Omit any of them to take the default.",
|
|
489
480
|
];
|
|
@@ -502,19 +493,18 @@ function renderCapabilitiesForGuide(caps) {
|
|
|
502
493
|
if (h.approvalModes?.length)
|
|
503
494
|
lines.push(` - approval modes: ${h.approvalModes.join(", ")}`);
|
|
504
495
|
}
|
|
505
|
-
lines.push("", "Re-run `orc capabilities` any time
|
|
496
|
+
lines.push("", "Re-run `orc capabilities` any time.");
|
|
506
497
|
return lines.join("\n");
|
|
507
498
|
}
|
|
508
499
|
export const doctor = defineOp({
|
|
509
500
|
name: "doctor",
|
|
510
|
-
doc: "Preflight
|
|
501
|
+
doc: "Preflight this machine: harness binaries, versions, cwd existence.",
|
|
511
502
|
readOnly: true,
|
|
512
503
|
input: z.object({
|
|
513
|
-
host: z.string().optional(),
|
|
514
504
|
cwd: z.string().optional(),
|
|
515
505
|
}),
|
|
516
506
|
async handler(input, ctx) {
|
|
517
|
-
const executor = ctx.registry.
|
|
507
|
+
const executor = ctx.registry.executor;
|
|
518
508
|
const checks = {};
|
|
519
509
|
for (const [name, harness] of ctx.registry.harnesses) {
|
|
520
510
|
const caps = await harness.discover({ executor }).catch(() => null);
|
|
@@ -523,7 +513,7 @@ export const doctor = defineOp({
|
|
|
523
513
|
if (input.cwd) {
|
|
524
514
|
checks.cwd = { path: input.cwd, exists: await executor.exists(input.cwd) };
|
|
525
515
|
}
|
|
526
|
-
return {
|
|
516
|
+
return { checks };
|
|
527
517
|
},
|
|
528
518
|
});
|
|
529
519
|
// ---------------------------------------------------------------------------
|
package/dist/registry.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* come only from an explicit orc.config.(js|json).
|
|
6
6
|
*/
|
|
7
7
|
import { callerAffinity, loadConfig } from "@karowanorg/orc-core";
|
|
8
|
-
import {
|
|
8
|
+
import { LocalExecutor } from "@karowanorg/orc-executors";
|
|
9
9
|
import { claudeHarness } from "@karowanorg/orc-harness-claude";
|
|
10
10
|
import { codexHarness, createCodexHarness } from "@karowanorg/orc-harness-codex";
|
|
11
11
|
import { makeExecHarness } from "./exec-harness.js";
|
|
@@ -31,5 +31,5 @@ export async function buildRegistry(opts = {}) {
|
|
|
31
31
|
config.defaultHarness ??
|
|
32
32
|
callerAffinity(opts.mcpClientName) ??
|
|
33
33
|
"codex";
|
|
34
|
-
return { harnesses, extensions, defaultHarness,
|
|
34
|
+
return { harnesses, extensions, defaultHarness, executor: new LocalExecutor() };
|
|
35
35
|
}
|
package/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@karowanorg/orc-ops",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"license": "0BSD",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"@karowanorg/orc-core": "^0.1.
|
|
9
|
-
"@karowanorg/orc-executors": "^0.1.
|
|
10
|
-
"@karowanorg/orc-harness-claude": "^0.1.
|
|
11
|
-
"@karowanorg/orc-harness-codex": "^0.1.
|
|
12
|
-
"@karowanorg/orc-ui": "^0.1.
|
|
8
|
+
"@karowanorg/orc-core": "^0.1.2",
|
|
9
|
+
"@karowanorg/orc-executors": "^0.1.1",
|
|
10
|
+
"@karowanorg/orc-harness-claude": "^0.1.3",
|
|
11
|
+
"@karowanorg/orc-harness-codex": "^0.1.3",
|
|
12
|
+
"@karowanorg/orc-ui": "^0.1.1",
|
|
13
13
|
"zod": "^4.1.0"
|
|
14
14
|
},
|
|
15
15
|
"description": "The zod-first operation registry orc's CLI, MCP server, and SDK all interpret.",
|