@krapht/ork 1.0.0-alpha.4 → 1.0.0-alpha.6
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__-1i1IwLg7.mjs → __build_info__-CxH89h1r.mjs} +2 -2
- package/dist/bin.mjs +54 -224
- package/dist/{clean-B1zPxq6A.mjs → clean-BbrkMQQi.mjs} +1 -1
- package/dist/{completion-BY-frez8.mjs → completion-BeS2NCgO.mjs} +5 -5
- package/dist/{context-CD5TCD1D.mjs → context-CHV6aTs7.mjs} +3 -3
- package/dist/{decide-CBhYcjwI.mjs → decide-Cnt7o3ya.mjs} +3 -3
- package/dist/{find-BgZjVKhv.mjs → find-Dy2H5IvT.mjs} +1 -1
- package/dist/{format-Creyq4U3.mjs → format-OL0E1AjA.mjs} +223 -17
- package/dist/{in-a-run-CsSBQQ2q.mjs → in-a-run-emTc-kZI.mjs} +1 -1
- package/dist/{limits-D_HxH0CK.mjs → limits-TxTnWxix.mjs} +1 -1
- package/dist/{list-CzzpVEpM.mjs → list-P5CfcoWx.mjs} +1 -1
- package/dist/{mcp-DYmQt372.mjs → mcp-qUwFT9yi.mjs} +6 -6
- package/dist/{output-CuivUcDa.mjs → output-CjOPL8W0.mjs} +9 -6
- package/dist/{pause-W6MzQqg8.mjs → pause-CBSAxtTp.mjs} +4 -4
- package/dist/{relay-CsdoZUXJ.mjs → relay-UgK1Cp9a.mjs} +2 -2
- package/dist/{remove-DLfDjBdF.mjs → remove-ccycC3vI.mjs} +3 -3
- package/dist/{send-Bw2FI_Sv.mjs → send-B39-Xeo7.mjs} +3 -3
- package/dist/{src-CrYCkU9J.mjs → src-5-sCA7cY.mjs} +50 -19
- package/dist/{src-Bc9yaAiZ.mjs → src-8nec4uoe.mjs} +14 -7
- package/dist/{src-BRB5EQyC.mjs → src-DG4dyBqm.mjs} +61 -20
- package/dist/{src-CsjumY1t.mjs → src-jyCJE1kd.mjs} +26 -12
- package/dist/ui/THIRD_PARTY_LICENSES.txt +594 -0
- package/dist/ui/assets/app-C1DAgdU2.js +75 -0
- package/dist/ui/assets/app-Dt_tjFj6.css +1 -0
- package/dist/ui/assets/{index-UEC5ZLYw.js → index-BZKXPhht.js} +3 -3
- package/dist/ui/assets/theme-CdXvqTQ6.js +1 -0
- package/dist/ui/index.html +2 -2
- package/dist/{ui-wX050aH1.mjs → ui-DmJWLgxL.mjs} +4 -4
- package/dist/{usage-C96RDH-G.mjs → usage-Bh1lVioA.mjs} +5 -5
- package/dist/{watch-vdRobJil.mjs → watch-C_vcsn_g.mjs} +6 -6
- package/dist/{workflows-B28q8zMY.mjs → workflows-lpexsAYt.mjs} +3 -3
- package/dist/{worktrees-CKDRkl6b.mjs → worktrees-D4bVVKfY.mjs} +10 -4
- package/package.json +1 -1
- package/dist/ui/assets/app-BNT0SuIz.css +0 -1
- package/dist/ui/assets/app-m9Gfrg_S.js +0 -67
- package/dist/ui/assets/theme-3xH5jxKs.js +0 -1
|
@@ -1,6 +1,211 @@
|
|
|
1
|
-
import { ht as liveStatus } from "./src-
|
|
2
|
-
import { i as style, n as cost } from "./output-
|
|
1
|
+
import { cn as maskSecrets, ht as liveStatus } from "./src-DG4dyBqm.mjs";
|
|
2
|
+
import { i as style, n as cost } from "./output-CjOPL8W0.mjs";
|
|
3
3
|
import { createInterface } from "node:readline/promises";
|
|
4
|
+
// ../core/src/control/queue.ts
|
|
5
|
+
const PERMISSION_OPTIONS = [{
|
|
6
|
+
id: "allow",
|
|
7
|
+
label: "Allow"
|
|
8
|
+
}, {
|
|
9
|
+
id: "deny",
|
|
10
|
+
label: "Deny"
|
|
11
|
+
}];
|
|
12
|
+
const DENIED = "The user did not allow this tool.";
|
|
13
|
+
/** The deny message a session gets, with the person's words when given. */
|
|
14
|
+
const deniedMessage = (note) => note === void 0 ? DENIED : `${DENIED} They said: ${note}`;
|
|
15
|
+
/** The input fields that say what a tool will do, the first one present. */
|
|
16
|
+
const TOOL_INPUT_KEYS = [
|
|
17
|
+
"command",
|
|
18
|
+
"file_path",
|
|
19
|
+
"path",
|
|
20
|
+
"url",
|
|
21
|
+
"pattern"
|
|
22
|
+
];
|
|
23
|
+
/** A tool's input for the decision's context: as written, cut at `max`. */
|
|
24
|
+
const inputContext = (input, max = 4e3) => {
|
|
25
|
+
const key = TOOL_INPUT_KEYS.find((k) => typeof input[k] === "string");
|
|
26
|
+
const text = key === void 0 ? JSON.stringify(input, void 0, 2) : String(input[key]);
|
|
27
|
+
return text.length > max ? `${text.slice(0, max - 1)}…` : text;
|
|
28
|
+
};
|
|
29
|
+
const createDecisionQueue = (options) => {
|
|
30
|
+
const { store, runId, emit } = options;
|
|
31
|
+
let count = 0;
|
|
32
|
+
/** Opens a decision and settles it with the first answer. */
|
|
33
|
+
const decide = (open, local, withdrawn) => {
|
|
34
|
+
count += 1;
|
|
35
|
+
const id = `${runId}-${String(count)}`;
|
|
36
|
+
const record = store.openDecision({
|
|
37
|
+
...open,
|
|
38
|
+
id,
|
|
39
|
+
runId
|
|
40
|
+
});
|
|
41
|
+
const event = {
|
|
42
|
+
type: "decision.opened",
|
|
43
|
+
node: record.node,
|
|
44
|
+
decision: id,
|
|
45
|
+
kind: record.kind,
|
|
46
|
+
question: record.question,
|
|
47
|
+
options: record.options
|
|
48
|
+
};
|
|
49
|
+
if (record.recommended !== void 0) event.recommended = record.recommended;
|
|
50
|
+
if (record.owner !== void 0) event.owner = record.owner;
|
|
51
|
+
emit(event);
|
|
52
|
+
const { promise, resolve, reject } = Promise.withResolvers();
|
|
53
|
+
const settled = new AbortController();
|
|
54
|
+
/** `note` is the stored one: masked, and absent when blank. */
|
|
55
|
+
const finish = (answer, by, note) => {
|
|
56
|
+
if (settled.signal.aborted) return;
|
|
57
|
+
settled.abort();
|
|
58
|
+
const answered = {
|
|
59
|
+
type: "decision.answered",
|
|
60
|
+
node: open.node,
|
|
61
|
+
decision: id,
|
|
62
|
+
answer,
|
|
63
|
+
by
|
|
64
|
+
};
|
|
65
|
+
if (note !== void 0) answered.note = note;
|
|
66
|
+
emit(answered);
|
|
67
|
+
resolve(note === void 0 ? {
|
|
68
|
+
answer,
|
|
69
|
+
by
|
|
70
|
+
} : {
|
|
71
|
+
answer,
|
|
72
|
+
by,
|
|
73
|
+
note
|
|
74
|
+
});
|
|
75
|
+
};
|
|
76
|
+
const withdraw = () => {
|
|
77
|
+
if (settled.signal.aborted) return;
|
|
78
|
+
settled.abort();
|
|
79
|
+
store.withdrawDecision(id);
|
|
80
|
+
emit({
|
|
81
|
+
type: "decision.withdrawn",
|
|
82
|
+
node: open.node,
|
|
83
|
+
decision: id
|
|
84
|
+
});
|
|
85
|
+
reject(/* @__PURE__ */ new Error("the question was withdrawn"));
|
|
86
|
+
};
|
|
87
|
+
if (withdrawn?.aborted === true) withdraw();
|
|
88
|
+
withdrawn?.addEventListener("abort", withdraw, { once: true });
|
|
89
|
+
const fromStore = async () => {
|
|
90
|
+
try {
|
|
91
|
+
const closed = await options.waitFor(id, settled.signal);
|
|
92
|
+
if (closed.status === "answered" && closed.answer !== void 0) finish(closed.answer, closed.answeredBy ?? "decide", closed.note);
|
|
93
|
+
} catch {}
|
|
94
|
+
};
|
|
95
|
+
const fromTerminal = async (ask) => {
|
|
96
|
+
try {
|
|
97
|
+
const { answer, note } = await ask(settled.signal);
|
|
98
|
+
if (store.answerDecision(id, answer, "terminal", note)) finish(answer, "terminal", store.decision(id)?.note);
|
|
99
|
+
} catch {}
|
|
100
|
+
};
|
|
101
|
+
fromStore();
|
|
102
|
+
if (local !== void 0) fromTerminal(local);
|
|
103
|
+
return promise;
|
|
104
|
+
};
|
|
105
|
+
return {
|
|
106
|
+
ask: (question) => {
|
|
107
|
+
const open = {
|
|
108
|
+
node: question.nodeId,
|
|
109
|
+
kind: "question",
|
|
110
|
+
question: question.question,
|
|
111
|
+
options: question.options
|
|
112
|
+
};
|
|
113
|
+
if (question.recommended !== void 0) open.recommended = question.recommended;
|
|
114
|
+
if (question.context !== void 0) open.context = question.context;
|
|
115
|
+
if (question.document !== void 0) open.document = question.document;
|
|
116
|
+
if (question.owner !== void 0) open.owner = question.owner;
|
|
117
|
+
const { local } = options;
|
|
118
|
+
return decide(open, local === void 0 ? void 0 : (signal) => {
|
|
119
|
+
let note;
|
|
120
|
+
return local.ask({
|
|
121
|
+
...question,
|
|
122
|
+
question: maskSecrets(question.question),
|
|
123
|
+
...question.context === void 0 ? {} : { context: maskSecrets(question.context) },
|
|
124
|
+
...question.document === void 0 ? {} : { document: maskSecrets(question.document) },
|
|
125
|
+
signal,
|
|
126
|
+
onNote: (given) => {
|
|
127
|
+
note = given;
|
|
128
|
+
}
|
|
129
|
+
}).then((answer) => note === void 0 ? { answer } : {
|
|
130
|
+
answer,
|
|
131
|
+
note
|
|
132
|
+
});
|
|
133
|
+
}, question.signal).then(({ answer, note }) => {
|
|
134
|
+
if (note !== void 0) question.onNote?.(note);
|
|
135
|
+
return answer;
|
|
136
|
+
});
|
|
137
|
+
},
|
|
138
|
+
settled: (question) => {
|
|
139
|
+
count += 1;
|
|
140
|
+
const id = `${runId}-${String(count)}`;
|
|
141
|
+
const { owner } = question;
|
|
142
|
+
const record = store.openDecision({
|
|
143
|
+
id,
|
|
144
|
+
runId,
|
|
145
|
+
node: question.nodeId,
|
|
146
|
+
kind: "question",
|
|
147
|
+
question: question.question,
|
|
148
|
+
options: question.options,
|
|
149
|
+
owner,
|
|
150
|
+
...question.recommended === void 0 ? {} : { recommended: question.recommended },
|
|
151
|
+
...question.context === void 0 ? {} : { context: question.context }
|
|
152
|
+
});
|
|
153
|
+
emit({
|
|
154
|
+
type: "decision.opened",
|
|
155
|
+
node: record.node,
|
|
156
|
+
decision: id,
|
|
157
|
+
kind: "question",
|
|
158
|
+
question: record.question,
|
|
159
|
+
options: record.options,
|
|
160
|
+
owner,
|
|
161
|
+
...record.recommended === void 0 ? {} : { recommended: record.recommended }
|
|
162
|
+
});
|
|
163
|
+
store.answerDecision(id, question.answer, "owner", question.note);
|
|
164
|
+
const note = store.decision(id)?.note;
|
|
165
|
+
emit({
|
|
166
|
+
type: "decision.answered",
|
|
167
|
+
node: record.node,
|
|
168
|
+
decision: id,
|
|
169
|
+
answer: question.answer,
|
|
170
|
+
by: "owner",
|
|
171
|
+
owner,
|
|
172
|
+
...note === void 0 ? {} : { note }
|
|
173
|
+
});
|
|
174
|
+
},
|
|
175
|
+
permit: async (request) => {
|
|
176
|
+
const { local } = options;
|
|
177
|
+
let localMessage = DENIED;
|
|
178
|
+
const { answer, note } = await decide({
|
|
179
|
+
node: request.nodeId,
|
|
180
|
+
kind: "permission",
|
|
181
|
+
question: `Allow ${request.toolName}?`,
|
|
182
|
+
options: PERMISSION_OPTIONS,
|
|
183
|
+
context: inputContext(request.input)
|
|
184
|
+
}, local === void 0 ? void 0 : (signal) => {
|
|
185
|
+
let said;
|
|
186
|
+
return local.permit({
|
|
187
|
+
...request,
|
|
188
|
+
signal,
|
|
189
|
+
onNote: (given) => {
|
|
190
|
+
said = given;
|
|
191
|
+
}
|
|
192
|
+
}).then((result) => {
|
|
193
|
+
if (!result.allow) localMessage = result.message;
|
|
194
|
+
const choice = result.allow ? "allow" : "deny";
|
|
195
|
+
return said === void 0 ? { answer: choice } : {
|
|
196
|
+
answer: choice,
|
|
197
|
+
note: said
|
|
198
|
+
};
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
if (note !== void 0) request.onNote?.(note);
|
|
202
|
+
return answer === "allow" ? { allow: true } : {
|
|
203
|
+
allow: false,
|
|
204
|
+
message: note === void 0 ? localMessage : deniedMessage(note)
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
};
|
|
4
209
|
// src/human.ts
|
|
5
210
|
/**
|
|
6
211
|
* @file The terminal `HumanChannel`: answers `ask_user` questions, gates and
|
|
@@ -10,18 +215,14 @@ import { createInterface } from "node:readline/promises";
|
|
|
10
215
|
* answerer, racing `ork decide`.
|
|
11
216
|
*/
|
|
12
217
|
const PREVIEW = 160;
|
|
218
|
+
/** A document longer than this is offered (`d`) rather than printed. */
|
|
219
|
+
const SHORT_DOCUMENT_LINES = 40;
|
|
13
220
|
const NO_ONE_TO_PERMIT = "No one is at the terminal to approve this tool, so it is not allowed in this run.";
|
|
14
221
|
const NOTE_PROMPT = " Note for the run (optional, Enter to skip): ";
|
|
15
222
|
const NO_ONE_TO_ASK = "no one (nobody is at the terminal; use your best judgment and say so in your report)";
|
|
16
223
|
/** One line that shows what a tool is about to do. */
|
|
17
224
|
const previewInput = (toolName, input) => {
|
|
18
|
-
const key = [
|
|
19
|
-
"command",
|
|
20
|
-
"file_path",
|
|
21
|
-
"path",
|
|
22
|
-
"url",
|
|
23
|
-
"pattern"
|
|
24
|
-
].find((k) => typeof input[k] === "string");
|
|
225
|
+
const key = TOOL_INPUT_KEYS.find((k) => typeof input[k] === "string");
|
|
25
226
|
const line = (key === void 0 ? JSON.stringify(input) : `${key}: ${String(input[key])}`).replaceAll(/\s+/gu, " ").trim();
|
|
26
227
|
return line.length > PREVIEW ? `${toolName} ${line.slice(0, 159)}…` : `${toolName} ${line}`;
|
|
27
228
|
};
|
|
@@ -63,11 +264,13 @@ const createTerminalHuman = (io) => {
|
|
|
63
264
|
const note = (await prompt(NOTE_PROMPT, signal)).trim();
|
|
64
265
|
if (note !== "") onNote(note);
|
|
65
266
|
};
|
|
66
|
-
const choose = async (hint, options, recommended, signal) => {
|
|
67
|
-
const
|
|
267
|
+
const choose = async (hint, options, recommended, signal, document) => {
|
|
268
|
+
const answer = await prompt(` Choose${hint}: `, signal);
|
|
269
|
+
const picked = pickOption(answer, options, recommended);
|
|
68
270
|
if (picked !== void 0) return picked;
|
|
69
|
-
|
|
70
|
-
|
|
271
|
+
if (document !== void 0 && answer.trim() === "d") say(document);
|
|
272
|
+
else say(style("dim", " Type an option's number or id."));
|
|
273
|
+
return choose(hint, options, recommended, signal, document);
|
|
71
274
|
};
|
|
72
275
|
const oneAtATime = (work) => {
|
|
73
276
|
const result = turn.then(work);
|
|
@@ -93,10 +296,12 @@ const createTerminalHuman = (io) => {
|
|
|
93
296
|
message: "The user did not allow this tool."
|
|
94
297
|
};
|
|
95
298
|
}),
|
|
96
|
-
ask: ({ nodeId, question, options, recommended, context, signal, onNote }) => oneAtATime(async () => {
|
|
299
|
+
ask: ({ nodeId, question, options, recommended, context, document, signal, onNote }) => oneAtATime(async () => {
|
|
97
300
|
if (signal?.aborted === true) throw new Error("the question was withdrawn");
|
|
301
|
+
const documentLines = document?.trimEnd().split("\n").length ?? 0;
|
|
302
|
+
if (document !== void 0 && documentLines <= SHORT_DOCUMENT_LINES) say(document);
|
|
98
303
|
say(`${style(["yellow", "bold"], "?")} ${style("bold", nodeId)} asks: ${question}`);
|
|
99
|
-
if (context !== void 0) say(style("dim", ` ${context}`));
|
|
304
|
+
if (context !== void 0) say(style("dim", ` ${context.replaceAll("\n", "\n ")}`));
|
|
100
305
|
for (const [index, option] of options.entries()) say(optionLine(option, index, recommended));
|
|
101
306
|
if (!io.interactive) {
|
|
102
307
|
const answer = recommended ?? NO_ONE_TO_ASK;
|
|
@@ -105,7 +310,8 @@ const createTerminalHuman = (io) => {
|
|
|
105
310
|
}
|
|
106
311
|
const fallback = options.findIndex((o) => o.id === recommended);
|
|
107
312
|
const hint = fallback === -1 ? "" : ` [${String(fallback + 1)}]`;
|
|
108
|
-
|
|
313
|
+
if (documentLines > SHORT_DOCUMENT_LINES) say(` Document: ${String(documentLines)} lines. Type d to read it.`);
|
|
314
|
+
const picked = await choose(hint, options, recommended, signal, document);
|
|
109
315
|
await takeNote(onNote, signal);
|
|
110
316
|
return picked;
|
|
111
317
|
}),
|
|
@@ -424,4 +630,4 @@ const formatTree = (roots) => {
|
|
|
424
630
|
return `${text.padEnd(label)} ${style("dim", node.type.padEnd(type))} ${state}${usage}`;
|
|
425
631
|
});
|
|
426
632
|
};
|
|
427
|
-
export { formatRunEvent as a, formatEvent as i, formatRuns as n, createTerminalHuman as o, formatTree as r, ago as t };
|
|
633
|
+
export { formatRunEvent as a, formatEvent as i, formatRuns as n, createTerminalHuman as o, formatTree as r, createDecisionQueue as s, ago as t };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as limitsNow, i as NOT_STARTED, o as limitsReport, r as capsHere } from "./src-
|
|
1
|
+
import { a as limitsNow, i as NOT_STARTED, o as limitsReport, r as capsHere } from "./src-DG4dyBqm.mjs";
|
|
2
2
|
// src/run/limits.ts
|
|
3
3
|
/**
|
|
4
4
|
* @file The limits across runs that apply here (RFC-007): the user's settings
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { h as isNewer } from "./src-
|
|
2
|
-
import { n as ORK_VERSION } from "./__build_info__-
|
|
3
|
-
import { a as openMcp, c as refused, o as tool, s as answer } from "./src-
|
|
4
|
-
import { p as runMarkerIn } from "./src-
|
|
5
|
-
import { n as explainNode } from "./context-
|
|
1
|
+
import { h as isNewer } from "./src-DG4dyBqm.mjs";
|
|
2
|
+
import { n as ORK_VERSION } from "./__build_info__-CxH89h1r.mjs";
|
|
3
|
+
import { a as openMcp, c as refused, o as tool, s as answer } from "./src-jyCJE1kd.mjs";
|
|
4
|
+
import { p as runMarkerIn } from "./src-8nec4uoe.mjs";
|
|
5
|
+
import { n as explainNode } from "./context-CHV6aTs7.mjs";
|
|
6
6
|
import { z } from "zod";
|
|
7
7
|
import { defineCommand } from "citty";
|
|
8
8
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
@@ -43,7 +43,7 @@ const orkMcpServer = (options = {}) => {
|
|
|
43
43
|
...options.script === void 0 ? {} : { script: options.script }
|
|
44
44
|
});
|
|
45
45
|
const all = [...opened.tools, explainTool(opened, options.home)];
|
|
46
|
-
const tools = options.expects !== void 0 && isNewer(options.expects, "1.0.0-alpha.
|
|
46
|
+
const tools = options.expects !== void 0 && isNewer(options.expects, "1.0.0-alpha.6") ? tooOld(all, options.expects) : all;
|
|
47
47
|
const server = new McpServer({
|
|
48
48
|
name: "ork",
|
|
49
49
|
version: ORK_VERSION
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as text,
|
|
1
|
+
import { $ as text, Ht as FEEDBACK_SEVERITIES, Q as inTransaction, Ut as FEEDBACK_TARGETS, Vt as FEEDBACK_KINDS, X as usageQueries, Y as backfillUsage, Z as eventOf, cn as maskSecrets, sn as maskReplacer, yn as PROJECT_MODES, yt as ownProcessStart } from "./src-DG4dyBqm.mjs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { mkdirSync } from "node:fs";
|
|
4
4
|
import { homedir } from "node:os";
|
|
@@ -70,6 +70,7 @@ const decisionOf = (row) => {
|
|
|
70
70
|
const optional = {
|
|
71
71
|
recommended: text(row, "recommended"),
|
|
72
72
|
context: text(row, "context"),
|
|
73
|
+
document: text(row, "document"),
|
|
73
74
|
answer: text(row, "answer"),
|
|
74
75
|
answeredAt: text(row, "answered_at"),
|
|
75
76
|
note: text(row, "note"),
|
|
@@ -81,8 +82,8 @@ const decisionOf = (row) => {
|
|
|
81
82
|
return record;
|
|
82
83
|
};
|
|
83
84
|
const decisionQueries = (db) => {
|
|
84
|
-
const insert = db.prepare(`INSERT INTO decisions (id, run_id, node, kind, question, options, recommended, context, owner, opened_at, status)
|
|
85
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'open')`);
|
|
85
|
+
const insert = db.prepare(`INSERT INTO decisions (id, run_id, node, kind, question, options, recommended, context, document, owner, opened_at, status)
|
|
86
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'open')`);
|
|
86
87
|
const answer = db.prepare(`UPDATE decisions SET status = 'answered', answer = ?, answered_by = ?, answered_at = ?, note = ?
|
|
87
88
|
WHERE id = ? AND status = 'open'`);
|
|
88
89
|
const withdraw = db.prepare("UPDATE decisions SET status = 'withdrawn', answered_at = ? WHERE id = ? AND status = 'open'");
|
|
@@ -102,9 +103,10 @@ const decisionQueries = (db) => {
|
|
|
102
103
|
const masked = {
|
|
103
104
|
...decision,
|
|
104
105
|
question: maskSecrets(decision.question),
|
|
105
|
-
...decision.context === void 0 ? {} : { context: maskSecrets(decision.context) }
|
|
106
|
+
...decision.context === void 0 ? {} : { context: maskSecrets(decision.context) },
|
|
107
|
+
...decision.document === void 0 ? {} : { document: maskSecrets(decision.document) }
|
|
106
108
|
};
|
|
107
|
-
insert.run(masked.id, masked.runId, masked.node, masked.kind, masked.question, JSON.stringify(masked.options), masked.recommended ?? null, masked.context ?? null, masked.owner ?? null, openedAt);
|
|
109
|
+
insert.run(masked.id, masked.runId, masked.node, masked.kind, masked.question, JSON.stringify(masked.options), masked.recommended ?? null, masked.context ?? null, masked.document ?? null, masked.owner ?? null, openedAt);
|
|
108
110
|
return {
|
|
109
111
|
...masked,
|
|
110
112
|
openedAt,
|
|
@@ -731,7 +733,8 @@ const MIGRATIONS = [
|
|
|
731
733
|
`ALTER TABLE runs ADD COLUMN skipped INTEGER;
|
|
732
734
|
ALTER TABLE runs ADD COLUMN failures_handled INTEGER;`,
|
|
733
735
|
`ALTER TABLE decisions ADD COLUMN note TEXT;`,
|
|
734
|
-
`ALTER TABLE decisions ADD COLUMN owner TEXT
|
|
736
|
+
`ALTER TABLE decisions ADD COLUMN owner TEXT;`,
|
|
737
|
+
`ALTER TABLE decisions ADD COLUMN document TEXT;`
|
|
735
738
|
];
|
|
736
739
|
const versionOf = (db) => Number(db.prepare("PRAGMA user_version").get()?.["user_version"] ?? 0);
|
|
737
740
|
/**
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { G as requestContinue, K as requestPause } from "./src-
|
|
2
|
-
import { t as findRun } from "./find-
|
|
3
|
-
import { a as write, c as openStore, i as style, o as writeErr } from "./output-
|
|
4
|
-
import { r as continueRefusal } from "./in-a-run-
|
|
1
|
+
import { G as requestContinue, K as requestPause } from "./src-DG4dyBqm.mjs";
|
|
2
|
+
import { t as findRun } from "./find-Dy2H5IvT.mjs";
|
|
3
|
+
import { a as write, c as openStore, i as style, o as writeErr } from "./output-CjOPL8W0.mjs";
|
|
4
|
+
import { r as continueRefusal } from "./in-a-run-emTc-kZI.mjs";
|
|
5
5
|
import { defineCommand } from "citty";
|
|
6
6
|
// src/commands/pause.ts
|
|
7
7
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { B as linkNodes, L as addressOf, U as unlinkNodes } from "./src-
|
|
2
|
-
import { a as write, c as openStore, i as style, o as writeErr } from "./output-
|
|
1
|
+
import { B as linkNodes, L as addressOf, U as unlinkNodes } from "./src-DG4dyBqm.mjs";
|
|
2
|
+
import { a as write, c as openStore, i as style, o as writeErr } from "./output-CjOPL8W0.mjs";
|
|
3
3
|
import { defineCommand } from "citty";
|
|
4
4
|
// src/commands/relay.ts
|
|
5
5
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { ht as liveStatus, j as lines, k as git } from "./src-
|
|
2
|
-
import { n as listOrkWorktrees, t as createdWorktrees } from "./list-
|
|
3
|
-
import { i as keyOf, n as applyStep, r as cleanStep, s as stepPrunes } from "./clean-
|
|
1
|
+
import { ht as liveStatus, j as lines, k as git } from "./src-DG4dyBqm.mjs";
|
|
2
|
+
import { n as listOrkWorktrees, t as createdWorktrees } from "./list-P5CfcoWx.mjs";
|
|
3
|
+
import { i as keyOf, n as applyStep, r as cleanStep, s as stepPrunes } from "./clean-BbrkMQQi.mjs";
|
|
4
4
|
// ../core/src/worktree/words.ts
|
|
5
5
|
/**
|
|
6
6
|
* @file The plain words for what `ork worktrees` shows, in one place, so the
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { c as openStore, o as writeErr } from "./output-
|
|
3
|
-
import { u as inheritedScrubber } from "./src-
|
|
1
|
+
import { ht as liveStatus, in as socketPath, kt as scriptContactsOf, on as wakeRun } from "./src-DG4dyBqm.mjs";
|
|
2
|
+
import { c as openStore, o as writeErr } from "./output-CjOPL8W0.mjs";
|
|
3
|
+
import { u as inheritedScrubber } from "./src-8nec4uoe.mjs";
|
|
4
4
|
import { defineCommand } from "citty";
|
|
5
5
|
// ../core/src/remote/send.ts
|
|
6
6
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Ht as FEEDBACK_SEVERITIES, Ut as FEEDBACK_TARGETS, Vt as FEEDBACK_KINDS, pt as parseReport } from "./src-
|
|
1
|
+
import { Ht as FEEDBACK_SEVERITIES, Ut as FEEDBACK_TARGETS, Vt as FEEDBACK_KINDS, pt as parseReport } from "./src-DG4dyBqm.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
364
|
description: definition.description,
|
|
346
|
-
shape
|
|
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
|
|
@@ -621,10 +646,13 @@ const delegationText = (delegation) => text(JSON.stringify({
|
|
|
621
646
|
const delegateTool = defineTool({
|
|
622
647
|
name: "delegate",
|
|
623
648
|
description: "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.",
|
|
624
|
-
shape: {
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
649
|
+
shape: ({ ports }) => {
|
|
650
|
+
const ids = ports.ownership?.children.map((child) => child.id) ?? [];
|
|
651
|
+
return { tasks: z.array(z.strictObject({
|
|
652
|
+
child: z.enum(ids).describe(`The id of a node you own: ${ids.join(", ")}.`),
|
|
653
|
+
brief: BRIEF
|
|
654
|
+
})).min(1) };
|
|
655
|
+
},
|
|
628
656
|
available: ({ ports }) => (ports.ownership?.children.length ?? 0) > 0,
|
|
629
657
|
run: async ({ ports }, args) => {
|
|
630
658
|
if (ports.ownership === void 0) return text("You own no nodes.");
|
|
@@ -634,10 +662,13 @@ const delegateTool = defineTool({
|
|
|
634
662
|
const spawnWorkerTool = defineTool({
|
|
635
663
|
name: "spawn_worker",
|
|
636
664
|
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
|
-
|
|
665
|
+
shape: ({ ports }) => {
|
|
666
|
+
const ids = ports.ownership?.templates ?? [];
|
|
667
|
+
return { tasks: z.array(z.strictObject({
|
|
668
|
+
template: z.enum(ids).describe(`The id of a child worker you own: ${ids.join(", ")}.`),
|
|
669
|
+
brief: BRIEF
|
|
670
|
+
})).min(1) };
|
|
671
|
+
},
|
|
641
672
|
available: ({ ports }) => ports.ownership !== void 0 && ports.ownership.templates.length > 0 && ports.ownership.workersLeft() > 0,
|
|
642
673
|
run: async ({ ports }, args) => {
|
|
643
674
|
if (ports.ownership === void 0) return text("You own no workers.");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $n as isToolNode, At as runScope, Bt as serversIn, F as declaredProblem, Mt as envReadsOf, Ot as heldTimeout, Pt as declaredOutputOf, Rt as MCP_FILE, Wn as markValue, Zn as beforeOf, ar as integrationFor, er as programsRunBy, ft as sessionDriver, ir as TOOL_PREFIX, jt as calledWorkflows, mt as reportSchemaFor,
|
|
1
|
+
import { $n as isToolNode, $t as evaluate, At as runScope, Bt as serversIn, F as declaredProblem, Mt as envReadsOf, Ot as heldTimeout, Pt as declaredOutputOf, Rt as MCP_FILE, Wn as markValue, Zn as beforeOf, ar as integrationFor, en as parseTemplate, er as programsRunBy, ft as sessionDriver, ir as TOOL_PREFIX, jt as calledWorkflows, mt as reportSchemaFor, nr as timeoutMs, rr as INTEGRATIONS, s as planReason, tn as renderTemplate, ut as planNodeSession, zt as mcpNotText } from "./src-DG4dyBqm.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";
|
|
@@ -1689,10 +1689,11 @@ const claudeExecutor = (options) => async (context) => {
|
|
|
1689
1689
|
};
|
|
1690
1690
|
// ../nodes/src/gate.ts
|
|
1691
1691
|
/**
|
|
1692
|
-
* @file The `human.gate` node type: asks the human the rendered question,
|
|
1693
|
-
*
|
|
1694
|
-
*
|
|
1695
|
-
*
|
|
1692
|
+
* @file The `human.gate` node type: asks the human the rendered question, with
|
|
1693
|
+
* its document if it has one, both in readable text (no raw JSON), outputs
|
|
1694
|
+
* their choice with the note they gave, and answers with the `default` when
|
|
1695
|
+
* the `timeout` passes. The timeout counts only while the run and the gate
|
|
1696
|
+
* are not paused (ADR-041).
|
|
1696
1697
|
*/
|
|
1697
1698
|
/** A promise that never settles: the losing side of a race. */
|
|
1698
1699
|
const NEVER = new Promise(() => {});
|
|
@@ -1714,8 +1715,13 @@ const gateExecutor = async (context) => {
|
|
|
1714
1715
|
output: {},
|
|
1715
1716
|
error: `${context.id} is not a gate`
|
|
1716
1717
|
};
|
|
1717
|
-
const
|
|
1718
|
-
const
|
|
1718
|
+
const scope = runScope(context.inputs, context.outputs, context.runId);
|
|
1719
|
+
const render = (text) => {
|
|
1720
|
+
const template = parseTemplate(text);
|
|
1721
|
+
return template.ok ? renderTemplate(template.parts, scope, { readable: true }) : text;
|
|
1722
|
+
};
|
|
1723
|
+
const question = render(node.question);
|
|
1724
|
+
const document = render(node.document ?? "");
|
|
1719
1725
|
const options = node.options.map((o) => choiceOf(o));
|
|
1720
1726
|
const withdraw = new AbortController();
|
|
1721
1727
|
context.signal.addEventListener("abort", () => {
|
|
@@ -1732,6 +1738,7 @@ const gateExecutor = async (context) => {
|
|
|
1732
1738
|
}
|
|
1733
1739
|
};
|
|
1734
1740
|
if (node.recommended !== void 0) asked.recommended = node.recommended;
|
|
1741
|
+
if (document.trim() !== "") asked.document = document;
|
|
1735
1742
|
const answer = context.human.ask(asked).then((choice) => ({
|
|
1736
1743
|
choice,
|
|
1737
1744
|
answeredBy: "user",
|