@krapht/ork 1.0.0-alpha.5 → 1.0.0-alpha.7
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/{__build_info__-Dl8yTEu-.mjs → __build_info__-BGoaUwLd.mjs} +72 -3
- package/dist/bin.mjs +149 -44
- package/dist/{clean-DYVmLkd4.mjs → clean-BPITM-6p.mjs} +1 -1
- package/dist/{completion-BVx917Yr.mjs → completion-CCn8xWmO.mjs} +5 -5
- package/dist/{context-CepHRoj9.mjs → context-CZNM454F.mjs} +3 -3
- package/dist/{decide-CK_-lI5V.mjs → decide-DsA6kOT7.mjs} +1 -1
- package/dist/{find-DWiDJ5Lc.mjs → find-ntyniv2E.mjs} +1 -1
- package/dist/{format-yBEAXZhk.mjs → format-DaROJUgG.mjs} +34 -5
- package/dist/{in-a-run-CKFIeMpU.mjs → in-a-run-D_fnj1Mw.mjs} +1 -1
- package/dist/{limits-CwzPe9wZ.mjs → limits-BKzVMwkt.mjs} +1 -1
- package/dist/{list-BE02pCZ9.mjs → list-D9HPWLPH.mjs} +1 -1
- package/dist/{mcp-DMuBbUHU.mjs → mcp-BFl3cIDp.mjs} +6 -6
- package/dist/{output-BhYkshYq.mjs → output-CwqlG1Le.mjs} +11 -2
- package/dist/{pause-C_Q0W6iX.mjs → pause-DhgKQORW.mjs} +4 -4
- package/dist/{relay-COCvG-0I.mjs → relay-Cp8JGrdv.mjs} +2 -2
- package/dist/{remove-RVcX1KqP.mjs → remove-CSpT_nJH.mjs} +3 -3
- package/dist/{send-OVpRei_5.mjs → send-CHiYkM6X.mjs} +3 -3
- package/dist/{src-Do_MhwiV.mjs → src-BsLHKQRc.mjs} +3903 -3204
- package/dist/{src-QEycKJWk.mjs → src-BwnitlJh.mjs} +8 -77
- package/dist/{src-HxtJOMRr.mjs → src-CUeMUVwW.mjs} +40 -23
- package/dist/{src-CxZr4Bp2.mjs → src-DhGLtYR-.mjs} +54 -21
- package/dist/ui/assets/{app-DzI77WV9.js → app-D4CoH-lh.js} +8 -8
- package/dist/ui/assets/app-Dt_tjFj6.css +1 -0
- package/dist/ui/assets/{index-2G_6XIIv.js → index-DxDGdEwz.js} +2 -2
- package/dist/ui/index.html +1 -1
- package/dist/{ui-Dz_qfUOz.mjs → ui-BxE0L7V0.mjs} +4 -4
- package/dist/{usage-BcLUZ1xw.mjs → usage-BuzDsEhq.mjs} +5 -5
- package/dist/{watch-Buyn0Mhz.mjs → watch-CCj0vU3B.mjs} +6 -6
- package/dist/{workflows-1sntXqSd.mjs → workflows-BNCDD6J-.mjs} +3 -3
- package/dist/{worktrees-B_Go_A9w.mjs → worktrees-DBBcaimX.mjs} +10 -4
- package/package.json +1 -1
- package/dist/ui/assets/app-pTYGrAbI.css +0 -1
|
@@ -1,86 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { C as
|
|
3
|
-
import { n as pendingDecisions, r as builtinProblem, t as answerDecision } from "./decide-
|
|
4
|
-
import { n as newRunId, t as findRun } from "./find-
|
|
5
|
-
import { c as openStore, l as storePath, s as
|
|
1
|
+
import { Bn as readDocument, Cn as placeFiles, En as runDirOf, Et as processAlive, G as requestPause, Gt as planPost, H as unlinkNodes, In as skillsIn, K as requestStop, Kt as runGh, Ln as WorkflowEditSchema, Nt as nodeSays, On as workflowDirOf, Qn as NodeSchema, Rn as applyEdits, St as runStatus, Un as renderJsonSchema, W as requestContinue, Wn as parseWorkflow, Wt as DISCUSSIONS, Xn as expandEdge, at as followEvents, bt as liveStatus, d as runningRunIds, et as detachResume, f as runningScript, ht as walkSummary, it as detachRun, jn as LESSON_CAP_TOKENS, kn as inside, l as planUpgrade, mt as walkChecks, nn as readCondition, o as limitsReport, ot as explainWorkflowText, p as detectInstaller, pt as checkWorkflowText, q as tellLiveRun, qn as EdgeInputSchema, qt as sendPost, r as capsHere, tt as resumable, u as releaseNotes, v as triggersReport, vn as loadAgents, wn as placeFor, xt as pausedOf, z as linkNodes, zn as newWorkflowText } from "./src-BsLHKQRc.mjs";
|
|
2
|
+
import { C as placeOf$1, S as lessonPlaceOf, T as openFixRun, _ as nodeSession, a as registryShown, b as recordNote, c as checkDue, f as readUpdateCache, g as activeTree, h as writeUpdateCache, i as registryOf, l as fetchLatest, m as updateCachePath, o as updateSwitchOff, p as refreshUpdateCache, s as runInstall, u as newerVersion, v as previewPost, w as feedbackActions, x as acceptItem } from "./__build_info__-BGoaUwLd.mjs";
|
|
3
|
+
import { n as pendingDecisions, r as builtinProblem, t as answerDecision } from "./decide-DsA6kOT7.mjs";
|
|
4
|
+
import { n as newRunId, t as findRun } from "./find-ntyniv2E.mjs";
|
|
5
|
+
import { c as openStore, l as storePath, s as isNodeEvent } from "./output-CwqlG1Le.mjs";
|
|
6
6
|
import { n as usageReport } from "./report-DK4LGqwF.mjs";
|
|
7
|
-
import { a as planClean, i as keyOf, o as stepActs, r as cleanStep, s as stepPrunes, t as applyClean } from "./clean-
|
|
8
|
-
import { a as readWorktrees, c as planLine, i as projectHead, l as removeRefusal, n as lostWork, o as labelOf, r as planRemove, s as mergeStateOf, t as applyRemove, u as stateParts } from "./remove-
|
|
7
|
+
import { a as planClean, i as keyOf, o as stepActs, r as cleanStep, s as stepPrunes, t as applyClean } from "./clean-BPITM-6p.mjs";
|
|
8
|
+
import { a as readWorktrees, c as planLine, i as projectHead, l as removeRefusal, n as lostWork, o as labelOf, r as planRemove, s as mergeStateOf, t as applyRemove, u as stateParts } from "./remove-CSpT_nJH.mjs";
|
|
9
9
|
import path from "node:path";
|
|
10
10
|
import { z } from "zod";
|
|
11
11
|
import { chmodSync, existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
12
12
|
import { createHash, randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
|
|
13
13
|
import { homedir } from "node:os";
|
|
14
14
|
import { createServer } from "node:http";
|
|
15
|
-
// ../core/src/store/activity.ts
|
|
16
|
-
const LONGEST_LINE = 120;
|
|
17
|
-
/**
|
|
18
|
-
* The fields of a tool's input that say what it's working on, best first. Only
|
|
19
|
-
* these are shown, so what else a tool was given stays in the logs.
|
|
20
|
-
*/
|
|
21
|
-
const TARGETS = [
|
|
22
|
-
"file_path",
|
|
23
|
-
"notebook_path",
|
|
24
|
-
"path",
|
|
25
|
-
"url",
|
|
26
|
-
"pattern",
|
|
27
|
-
"query",
|
|
28
|
-
"command"
|
|
29
|
-
];
|
|
30
|
-
const oneLine = (text) => {
|
|
31
|
-
const line = text.replaceAll(/\s+/gu, " ").trim();
|
|
32
|
-
return line.length > LONGEST_LINE ? `${line.slice(0, 119)}…` : line;
|
|
33
|
-
};
|
|
34
|
-
const toolLine = ({ name, input }) => {
|
|
35
|
-
const target = TARGETS.map((field) => input[field]).find((value) => typeof value === "string" && value.trim() !== "");
|
|
36
|
-
if (typeof target !== "string") return name;
|
|
37
|
-
return oneLine(target.startsWith(`${name} `) ? target : `${name} ${target}`);
|
|
38
|
-
};
|
|
39
|
-
/** What a finished node said, or why it failed. */
|
|
40
|
-
const finishedNow = (ok, error, summary) => {
|
|
41
|
-
if (!ok) return error === void 0 ? void 0 : oneLine(error);
|
|
42
|
-
return typeof summary === "string" && summary.trim() !== "" ? oneLine(summary) : void 0;
|
|
43
|
-
};
|
|
44
|
-
/** Each node's activity, by id; a node that never started has none. */
|
|
45
|
-
const runActivity = (stored) => {
|
|
46
|
-
const nodes = /* @__PURE__ */ new Map();
|
|
47
|
-
const of = (id) => {
|
|
48
|
-
const found = nodes.get(id);
|
|
49
|
-
if (found !== void 0) return found;
|
|
50
|
-
const fresh = {};
|
|
51
|
-
nodes.set(id, fresh);
|
|
52
|
-
return fresh;
|
|
53
|
-
};
|
|
54
|
-
for (const { at, event } of stored) if (event.type === "node.started") {
|
|
55
|
-
const node = of(event.id);
|
|
56
|
-
node.startedAt ??= at;
|
|
57
|
-
delete node.finishedAt;
|
|
58
|
-
delete node.now;
|
|
59
|
-
} else if (event.type === "node.event") {
|
|
60
|
-
if (event.event.type === "tool.called") of(event.id).now = toolLine(event.event);
|
|
61
|
-
} else if (event.type === "decision.opened") of(event.node).now = oneLine(`Asked: ${event.question}`);
|
|
62
|
-
else if (event.type === "decision.answered") of(event.node).now = oneLine(`Answered: ${event.answer}`);
|
|
63
|
-
else if (event.type === "decision.withdrawn") delete of(event.node).now;
|
|
64
|
-
else if (event.type === "node.finished") {
|
|
65
|
-
const node = of(event.id);
|
|
66
|
-
node.finishedAt = at;
|
|
67
|
-
const now = finishedNow(event.ok, event.error, event.output["summary"]);
|
|
68
|
-
if (now === void 0) delete node.now;
|
|
69
|
-
else node.now = now;
|
|
70
|
-
}
|
|
71
|
-
return nodes;
|
|
72
|
-
};
|
|
73
|
-
/** The ownership tree, with what each node is doing and when it ran. */
|
|
74
|
-
const activeTree = (stored) => {
|
|
75
|
-
const activity = runActivity(stored);
|
|
76
|
-
const dress = (node) => {
|
|
77
|
-
Object.assign(node, activity.get(node.id));
|
|
78
|
-
for (const child of node.children) dress(child);
|
|
79
|
-
};
|
|
80
|
-
const roots = runTree(stored.map(({ event }) => event));
|
|
81
|
-
for (const root of roots) dress(root);
|
|
82
|
-
return roots;
|
|
83
|
-
};
|
|
84
15
|
// ../server/src/contract-builder.ts
|
|
85
16
|
/** A new workflow's name, as its file and its `name:` take it. */
|
|
86
17
|
const NewWorkflowSchema = z.strictObject({ name: z.string().min(1) });
|
|
@@ -1623,7 +1554,7 @@ const readRoutes = (context) => ({
|
|
|
1623
1554
|
events: ({ params, query }) => {
|
|
1624
1555
|
const found = runOf(context, params.id);
|
|
1625
1556
|
if (!found.ok) return found.refusal;
|
|
1626
|
-
const events = context.store.events(found.run.id, query.after ?? 0).filter((s) => query.node === void 0 ||
|
|
1557
|
+
const events = context.store.events(found.run.id, query.after ?? 0).filter((s) => query.node === void 0 || isNodeEvent(s.event, query.node));
|
|
1627
1558
|
const newest = query.last === void 0 ? events : events.slice(-query.last);
|
|
1628
1559
|
return ok(query.limit === void 0 ? newest : newest.slice(0, query.limit));
|
|
1629
1560
|
},
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $
|
|
1
|
+
import { $t as evaluate, At as declaredProblem, Bt as serversIn, Hn as programsRunBy, Kn as markValue, Mt as envReadsOf, Ot as runScope, Pt as declaredOutputOf, Rt as MCP_FILE, Vn as beforeOf, ar as integrationFor, ct as planNodeSession, en as parseTemplate, er as isToolNode, ft as reportSchemaFor, ir as TOOL_PREFIX, jt as calledWorkflows, nr as timeoutMs, rr as INTEGRATIONS, s as planReason, tn as renderTemplate, ut as sessionDriver, yt as heldTimeout, zt as mcpNotText } from "./src-BsLHKQRc.mjs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { accessSync, constants, lstatSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { spawn } from "node:child_process";
|
|
@@ -35,7 +35,7 @@ const callExecutor = (context) => {
|
|
|
35
35
|
output: { status: "fail" },
|
|
36
36
|
error: "This run cannot call workflows."
|
|
37
37
|
});
|
|
38
|
-
const scope = runScope(context.inputs, context.outputs, context.runId);
|
|
38
|
+
const scope = runScope(context.inputs, context.outputs, context.runId, context.item);
|
|
39
39
|
const render = (text) => {
|
|
40
40
|
const template = parseTemplate(text);
|
|
41
41
|
return template.ok ? renderTemplate(template.parts, scope) : text;
|
|
@@ -61,6 +61,32 @@ const callExecutor = (context) => {
|
|
|
61
61
|
}
|
|
62
62
|
}, context.signal).then(limitedCall);
|
|
63
63
|
};
|
|
64
|
+
// ../nodes/src/claude-plan.ts
|
|
65
|
+
/**
|
|
66
|
+
* @file What a Claude node's session is planned with, read from the node's
|
|
67
|
+
* context.
|
|
68
|
+
*/
|
|
69
|
+
/** The plan options every session of a node starts from. */
|
|
70
|
+
const planOptionsOf = (context, inPlace) => {
|
|
71
|
+
const planOptions = {
|
|
72
|
+
cwd: context.cwd,
|
|
73
|
+
inputs: context.inputs,
|
|
74
|
+
outputs: context.outputs,
|
|
75
|
+
inPlace,
|
|
76
|
+
workflowDir: context.workflowDir,
|
|
77
|
+
projectRoot: context.projectRoot,
|
|
78
|
+
...context.orkDir === void 0 ? {} : { orkDir: context.orkDir },
|
|
79
|
+
pluginDir: path.join(context.runDir, "plugins", context.id)
|
|
80
|
+
};
|
|
81
|
+
if (context.checkout !== void 0) planOptions.checkout = context.checkout;
|
|
82
|
+
if (context.brief !== void 0) planOptions.brief = context.brief;
|
|
83
|
+
if (context.template !== void 0) planOptions.template = context.template;
|
|
84
|
+
if (context.item !== void 0) planOptions.item = context.item;
|
|
85
|
+
if (context.ownership !== void 0) planOptions.ownership = context.ownership;
|
|
86
|
+
if (context.mailbox !== void 0) planOptions.mailbox = context.mailbox;
|
|
87
|
+
if (context.claims !== void 0) planOptions.claims = context.claims;
|
|
88
|
+
return planOptions;
|
|
89
|
+
};
|
|
64
90
|
// ../nodes/src/claude-result.ts
|
|
65
91
|
/**
|
|
66
92
|
* @file A finished session as a node's result: its report is the output, held
|
|
@@ -991,7 +1017,9 @@ const IDENTITY_KEYS = /* @__PURE__ */ new Set([
|
|
|
991
1017
|
"ORK_WORKFLOW",
|
|
992
1018
|
"ORK_BIN",
|
|
993
1019
|
OUTPUT_ENV,
|
|
994
|
-
STATE_ENV
|
|
1020
|
+
STATE_ENV,
|
|
1021
|
+
"ORK_ITEM",
|
|
1022
|
+
"ORK_INDEX"
|
|
995
1023
|
]);
|
|
996
1024
|
/**
|
|
997
1025
|
* `env` without Ork's identity variables. A run started by a program in another
|
|
@@ -1019,7 +1047,11 @@ const identityOf = (context, orkBin) => ({
|
|
|
1019
1047
|
ORK_RUN_DIR: context.runDir,
|
|
1020
1048
|
ORK_PROJECT: context.projectRoot,
|
|
1021
1049
|
ORK_WORKFLOW: context.workflow.name,
|
|
1022
|
-
...orkBin === void 0 ? {} : { ORK_BIN: orkBin }
|
|
1050
|
+
...orkBin === void 0 ? {} : { ORK_BIN: orkBin },
|
|
1051
|
+
...context.item === void 0 ? {} : {
|
|
1052
|
+
ORK_ITEM: typeof context.item.value === "string" ? context.item.value : JSON.stringify(context.item.value),
|
|
1053
|
+
ORK_INDEX: String(context.item.index)
|
|
1054
|
+
}
|
|
1023
1055
|
});
|
|
1024
1056
|
/** The variables a workflow's nodes read that no `plainEnv` excuses. */
|
|
1025
1057
|
const secretNamesOf = (workflow) => Object.values(workflow.nodes).flatMap((node) => programsRunBy(node, workflow.defaults)).flatMap(({ program }) => {
|
|
@@ -1061,7 +1093,7 @@ const secretsOf = (workflow, environ, also = []) => valuesOf(namesToMask(workflo
|
|
|
1061
1093
|
const renderEnv = (node, context, environ) => {
|
|
1062
1094
|
const values = {};
|
|
1063
1095
|
const scope = {
|
|
1064
|
-
...runScope(context.inputs, context.outputs, context.runId),
|
|
1096
|
+
...runScope(context.inputs, context.outputs, context.runId, context.item),
|
|
1065
1097
|
output: { env: environ }
|
|
1066
1098
|
};
|
|
1067
1099
|
for (const [key, text] of Object.entries(node.env ?? {})) {
|
|
@@ -1151,7 +1183,7 @@ const render = (text, context) => {
|
|
|
1151
1183
|
};
|
|
1152
1184
|
return {
|
|
1153
1185
|
ok: true,
|
|
1154
|
-
value: renderTemplate(template.parts, runScope(context.inputs, context.outputs, context.runId))
|
|
1186
|
+
value: renderTemplate(template.parts, runScope(context.inputs, context.outputs, context.runId, context.item))
|
|
1155
1187
|
};
|
|
1156
1188
|
};
|
|
1157
1189
|
/** The program and arguments a tool node runs, before the allow check. */
|
|
@@ -1538,22 +1570,7 @@ const specFor = (spec, context) => {
|
|
|
1538
1570
|
};
|
|
1539
1571
|
/** Runs a `claude.leader` or `claude.worker` as one session. */
|
|
1540
1572
|
const claudeExecutor = (options) => async (context) => {
|
|
1541
|
-
const planOptions =
|
|
1542
|
-
cwd: context.cwd,
|
|
1543
|
-
inputs: context.inputs,
|
|
1544
|
-
outputs: context.outputs,
|
|
1545
|
-
inPlace: options.inPlace,
|
|
1546
|
-
workflowDir: context.workflowDir,
|
|
1547
|
-
projectRoot: context.projectRoot,
|
|
1548
|
-
...context.orkDir === void 0 ? {} : { orkDir: context.orkDir },
|
|
1549
|
-
pluginDir: path.join(context.runDir, "plugins", context.id)
|
|
1550
|
-
};
|
|
1551
|
-
if (context.checkout !== void 0) planOptions.checkout = context.checkout;
|
|
1552
|
-
if (context.brief !== void 0) planOptions.brief = context.brief;
|
|
1553
|
-
if (context.template !== void 0) planOptions.template = context.template;
|
|
1554
|
-
if (context.ownership !== void 0) planOptions.ownership = context.ownership;
|
|
1555
|
-
if (context.mailbox !== void 0) planOptions.mailbox = context.mailbox;
|
|
1556
|
-
if (context.claims !== void 0) planOptions.claims = context.claims;
|
|
1573
|
+
const planOptions = planOptionsOf(context, options.inPlace);
|
|
1557
1574
|
const before = beforeOf(context.node, context.workflow.defaults);
|
|
1558
1575
|
if (before !== void 0) {
|
|
1559
1576
|
const ran = await runStep(options.steps ?? noSteps, context, before, {
|
|
@@ -1853,7 +1870,7 @@ const mcpCallExecutor = (options = {}) => async (context) => {
|
|
|
1853
1870
|
}, node.plainEnv);
|
|
1854
1871
|
if (!expanded.ok) return failed(expanded.error);
|
|
1855
1872
|
const scrub = scrubberOf([...secretsOf(context.workflow, environ, options.maskedNames), ...expanded.value.values]);
|
|
1856
|
-
const scope = runScope(context.inputs, context.outputs, context.runId);
|
|
1873
|
+
const scope = runScope(context.inputs, context.outputs, context.runId, context.item);
|
|
1857
1874
|
const args = Object.fromEntries(Object.entries(node.arguments ?? {}).map(([key, value]) => [key, renderValue(value, scope)]));
|
|
1858
1875
|
const name = `${node.server}.${node.tool}`;
|
|
1859
1876
|
context.emit({
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Ht as FEEDBACK_SEVERITIES, Ut as FEEDBACK_TARGETS, Vt as FEEDBACK_KINDS,
|
|
1
|
+
import { Ht as FEEDBACK_SEVERITIES, Ut as FEEDBACK_TARGETS, Vt as FEEDBACK_KINDS, dt as parseReport } from "./src-BsLHKQRc.mjs";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { randomBytes, timingSafeEqual } from "node:crypto";
|
|
4
4
|
import { createInterface } from "node:readline";
|
|
@@ -336,20 +336,45 @@ const text = (value) => ({ content: [{
|
|
|
336
336
|
type: "text",
|
|
337
337
|
text: value
|
|
338
338
|
}] });
|
|
339
|
-
const
|
|
340
|
-
const
|
|
341
|
-
return {
|
|
342
|
-
|
|
343
|
-
|
|
339
|
+
const issueAt = (issue) => {
|
|
340
|
+
const where = z.core.toDotPath(issue.path);
|
|
341
|
+
return where === "" ? "" : `${where}: `;
|
|
342
|
+
};
|
|
343
|
+
/** Whether `issue` is about a field of the object `parent` is about. */
|
|
344
|
+
const isFieldOf = (issue, parent) => issue.path.length === parent.path.length + 1 && parent.path.every((key, index) => key === issue.path[index]);
|
|
345
|
+
const expectedField = (issue) => `; the field is \`${String(issue.path.at(-1))}\`${issue.code === "invalid_value" ? `, one of: ${issue.values.join(", ")}` : ""}`;
|
|
346
|
+
/**
|
|
347
|
+
* A failed parse as text a model can act on. A stray key is reported with the
|
|
348
|
+
* fields its object lacks, read from the schema's own issues: a wrong name is
|
|
349
|
+
* otherwise only a "missing" error that hides what was sent.
|
|
350
|
+
*/
|
|
351
|
+
const readableIssues = (issues) => {
|
|
352
|
+
const strays = issues.filter((issue) => issue.code === "unrecognized_keys");
|
|
353
|
+
const lacking = issues.filter((issue) => issue.input === void 0 && strays.some((stray) => isFieldOf(issue, stray)));
|
|
354
|
+
return [...strays.map((stray) => `${issueAt(stray)}unknown field ${stray.keys.map((key) => `\`${key}\``).join(", ")}${lacking.filter((issue) => isFieldOf(issue, stray)).map((issue) => expectedField(issue)).join("")}`), ...issues.filter((issue) => issue.code !== "unrecognized_keys" && !lacking.includes(issue)).map((issue) => `${issueAt(issue)}${issue.message}`)].join("\n");
|
|
355
|
+
};
|
|
356
|
+
const defineTool = (definition) => ({
|
|
357
|
+
name: definition.name,
|
|
358
|
+
bind: (context) => {
|
|
359
|
+
if (!(definition.available?.(context) ?? true)) return null;
|
|
360
|
+
const shape = typeof definition.shape === "function" ? definition.shape(context) : definition.shape;
|
|
361
|
+
const schema = z.object(shape);
|
|
362
|
+
return {
|
|
344
363
|
name: definition.name,
|
|
345
|
-
description: definition.description,
|
|
346
|
-
shape
|
|
364
|
+
description: typeof definition.description === "function" ? definition.description(context) : definition.description,
|
|
365
|
+
shape,
|
|
347
366
|
schema,
|
|
348
367
|
preapproved: definition.preapproved ?? true,
|
|
349
|
-
call: (args) =>
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
368
|
+
call: (args) => {
|
|
369
|
+
const parsed = schema.safeParse(args, { reportInput: true });
|
|
370
|
+
return parsed.success ? definition.run(context, parsed.data) : Promise.resolve({
|
|
371
|
+
...text(readableIssues(parsed.error.issues)),
|
|
372
|
+
isError: true
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
});
|
|
353
378
|
// ../runtime-claude/src/mcp-http.ts
|
|
354
379
|
/**
|
|
355
380
|
* @file A minimal MCP server over the streamable HTTP transport, for the
|
|
@@ -618,13 +643,18 @@ const delegationText = (delegation) => text(JSON.stringify({
|
|
|
618
643
|
reports: delegation.reports.map(reportLine),
|
|
619
644
|
...delegation.notes.length > 0 ? { notes: delegation.notes } : {}
|
|
620
645
|
}));
|
|
646
|
+
/** Why a child the leader owns isn't offered, so it doesn't go looking. */
|
|
647
|
+
const fannedNote = (fanned) => fanned.length === 0 ? "" : ` Not listed: ${fanned.join(", ")}; such a node runs once per item of a list, from its edges, so it can't be delegated to.`;
|
|
621
648
|
const delegateTool = defineTool({
|
|
622
649
|
name: "delegate",
|
|
623
|
-
description:
|
|
624
|
-
shape: {
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
650
|
+
description: ({ ports }) => `Hand tasks to nodes you own. Tasks in one call run in parallel; the call returns every child's report when all are done. Ork merges a passing child's branch into yours.${fannedNote(ports.ownership?.fanned ?? [])}`,
|
|
651
|
+
shape: ({ ports }) => {
|
|
652
|
+
const ids = ports.ownership?.children.map((child) => child.id) ?? [];
|
|
653
|
+
return { tasks: z.array(z.strictObject({
|
|
654
|
+
child: z.enum(ids).describe(`The id of a node you own: ${ids.join(", ")}.`),
|
|
655
|
+
brief: BRIEF
|
|
656
|
+
})).min(1) };
|
|
657
|
+
},
|
|
628
658
|
available: ({ ports }) => (ports.ownership?.children.length ?? 0) > 0,
|
|
629
659
|
run: async ({ ports }, args) => {
|
|
630
660
|
if (ports.ownership === void 0) return text("You own no nodes.");
|
|
@@ -634,10 +664,13 @@ const delegateTool = defineTool({
|
|
|
634
664
|
const spawnWorkerTool = defineTool({
|
|
635
665
|
name: "spawn_worker",
|
|
636
666
|
description: "Start new instances of a child worker for work that splits into independent parts. Each runs in its own worktree; the call returns their reports when all are done.",
|
|
637
|
-
shape: {
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
667
|
+
shape: ({ ports }) => {
|
|
668
|
+
const ids = ports.ownership?.templates ?? [];
|
|
669
|
+
return { tasks: z.array(z.strictObject({
|
|
670
|
+
template: z.enum(ids).describe(`The id of a child worker you own: ${ids.join(", ")}.`),
|
|
671
|
+
brief: BRIEF
|
|
672
|
+
})).min(1) };
|
|
673
|
+
},
|
|
641
674
|
available: ({ ports }) => ports.ownership !== void 0 && ports.ownership.templates.length > 0 && ports.ownership.workersLeft() > 0,
|
|
642
675
|
run: async ({ ports }, args) => {
|
|
643
676
|
if (ports.ownership === void 0) return text("You own no workers.");
|