@krapht/ork 1.0.0-alpha.3 → 1.0.0-alpha.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/dist/{__build_info__-BwrKe6yz.mjs → __build_info__-Dl8yTEu-.mjs} +2 -2
  2. package/dist/bin.mjs +63 -225
  3. package/dist/{clean-hXSaN8BT.mjs → clean-DYVmLkd4.mjs} +1 -1
  4. package/dist/{completion-Cga01yQP.mjs → completion-BVx917Yr.mjs} +5 -5
  5. package/dist/{context-mCAwzFFM.mjs → context-CepHRoj9.mjs} +3 -3
  6. package/dist/{decide-BvZnKErW.mjs → decide-CK_-lI5V.mjs} +3 -3
  7. package/dist/{find-CbetS8I2.mjs → find-DWiDJ5Lc.mjs} +1 -1
  8. package/dist/{format-D87bY6Ud.mjs → format-yBEAXZhk.mjs} +223 -17
  9. package/dist/{in-a-run-Bs4Wv-Cz.mjs → in-a-run-CKFIeMpU.mjs} +1 -1
  10. package/dist/{limits-RzKQ_zPk.mjs → limits-CwzPe9wZ.mjs} +1 -1
  11. package/dist/{list-DX65Sbu7.mjs → list-BE02pCZ9.mjs} +1 -1
  12. package/dist/{mcp-DKrrxowo.mjs → mcp-DMuBbUHU.mjs} +6 -6
  13. package/dist/{output-Q3TZ-Ave.mjs → output-BhYkshYq.mjs} +9 -6
  14. package/dist/{pause-B5Z41lR3.mjs → pause-C_Q0W6iX.mjs} +4 -4
  15. package/dist/{relay-BLnjMdjT.mjs → relay-COCvG-0I.mjs} +2 -2
  16. package/dist/{remove-IbcZOemm.mjs → remove-RVcX1KqP.mjs} +3 -3
  17. package/dist/{send-CJKEhBL1.mjs → send-OVpRei_5.mjs} +3 -3
  18. package/dist/{src-LSxjnWDH.mjs → src-CxZr4Bp2.mjs} +16 -8
  19. package/dist/{src-DnETlJ1r.mjs → src-Do_MhwiV.mjs} +186 -30
  20. package/dist/{src-XDSRnAZV.mjs → src-HxtJOMRr.mjs} +172 -167
  21. package/dist/{src-BTDzibW3.mjs → src-QEycKJWk.mjs} +26 -12
  22. package/dist/ui/THIRD_PARTY_LICENSES.txt +594 -0
  23. package/dist/ui/assets/app-DzI77WV9.js +75 -0
  24. package/dist/ui/assets/app-pTYGrAbI.css +1 -0
  25. package/dist/ui/assets/{index-BkI68sr5.js → index-2G_6XIIv.js} +3 -3
  26. package/dist/ui/assets/theme-CdXvqTQ6.js +1 -0
  27. package/dist/ui/index.html +2 -2
  28. package/dist/{ui-fvrO7Gxd.mjs → ui-Dz_qfUOz.mjs} +4 -4
  29. package/dist/{usage-bNdcBcj9.mjs → usage-BcLUZ1xw.mjs} +5 -5
  30. package/dist/{watch-EhlO304A.mjs → watch-Buyn0Mhz.mjs} +6 -6
  31. package/dist/{workflows-C5hYAVcE.mjs → workflows-1sntXqSd.mjs} +3 -3
  32. package/dist/{worktrees-BQFcpYz1.mjs → worktrees-B_Go_A9w.mjs} +4 -4
  33. package/package.json +1 -1
  34. package/dist/ui/assets/app-BNElhp7Z.js +0 -67
  35. package/dist/ui/assets/app-BNT0SuIz.css +0 -1
  36. package/dist/ui/assets/theme-3xH5jxKs.js +0 -1
@@ -1,6 +1,211 @@
1
- import { ht as liveStatus } from "./src-DnETlJ1r.mjs";
2
- import { i as style, n as cost } from "./output-Q3TZ-Ave.mjs";
1
+ import { cn as maskSecrets, ht as liveStatus } from "./src-Do_MhwiV.mjs";
2
+ import { i as style, n as cost } from "./output-BhYkshYq.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 picked = pickOption(await prompt(` Choose${hint}: `, signal), options, recommended);
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
- say(style("dim", " Type an option's number or id."));
70
- return choose(hint, options, recommended, signal);
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
- const picked = await choose(hint, options, recommended, signal);
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 { p as runMarkerIn } from "./src-XDSRnAZV.mjs";
1
+ import { p as runMarkerIn } from "./src-HxtJOMRr.mjs";
2
2
  // src/commands/in-a-run.ts
3
3
  /**
4
4
  * @file The commands that act as the user refuse a program or an agent in a run
@@ -1,4 +1,4 @@
1
- import { a as limitsNow, i as NOT_STARTED, o as limitsReport, r as capsHere } from "./src-DnETlJ1r.mjs";
1
+ import { a as limitsNow, i as NOT_STARTED, o as limitsReport, r as capsHere } from "./src-Do_MhwiV.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,4 +1,4 @@
1
- import { A as gitOk, j as lines, k as git } from "./src-DnETlJ1r.mjs";
1
+ import { A as gitOk, j as lines, k as git } from "./src-Do_MhwiV.mjs";
2
2
  import { existsSync } from "node:fs";
3
3
  // ../core/src/worktree/list.ts
4
4
  /**
@@ -1,8 +1,8 @@
1
- import { h as isNewer } from "./src-DnETlJ1r.mjs";
2
- import { n as ORK_VERSION } from "./__build_info__-BwrKe6yz.mjs";
3
- import { a as openMcp, c as refused, o as tool, s as answer } from "./src-BTDzibW3.mjs";
4
- import { n as explainNode } from "./context-mCAwzFFM.mjs";
5
- import { p as runMarkerIn } from "./src-XDSRnAZV.mjs";
1
+ import { h as isNewer } from "./src-Do_MhwiV.mjs";
2
+ import { n as ORK_VERSION } from "./__build_info__-Dl8yTEu-.mjs";
3
+ import { a as openMcp, c as refused, o as tool, s as answer } from "./src-QEycKJWk.mjs";
4
+ import { p as runMarkerIn } from "./src-HxtJOMRr.mjs";
5
+ import { n as explainNode } from "./context-CepHRoj9.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.3") ? tooOld(all, options.expects) : all;
46
+ const tools = options.expects !== void 0 && isNewer(options.expects, "1.0.0-alpha.5") ? 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, Bt as FEEDBACK_TARGETS, Q as inTransaction, Rt as FEEDBACK_KINDS, X as usageQueries, Xt as maskReplacer, Y as backfillUsage, Z as eventOf, Zt as maskSecrets, gn as PROJECT_MODES, yt as ownProcessStart, zt as FEEDBACK_SEVERITIES } from "./src-DnETlJ1r.mjs";
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-Do_MhwiV.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-DnETlJ1r.mjs";
2
- import { t as findRun } from "./find-CbetS8I2.mjs";
3
- import { a as write, c as openStore, i as style, o as writeErr } from "./output-Q3TZ-Ave.mjs";
4
- import { r as continueRefusal } from "./in-a-run-Bs4Wv-Cz.mjs";
1
+ import { G as requestContinue, K as requestPause } from "./src-Do_MhwiV.mjs";
2
+ import { t as findRun } from "./find-DWiDJ5Lc.mjs";
3
+ import { a as write, c as openStore, i as style, o as writeErr } from "./output-BhYkshYq.mjs";
4
+ import { r as continueRefusal } from "./in-a-run-CKFIeMpU.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-DnETlJ1r.mjs";
2
- import { a as write, c as openStore, i as style, o as writeErr } from "./output-Q3TZ-Ave.mjs";
1
+ import { B as linkNodes, L as addressOf, U as unlinkNodes } from "./src-Do_MhwiV.mjs";
2
+ import { a as write, c as openStore, i as style, o as writeErr } from "./output-BhYkshYq.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-DnETlJ1r.mjs";
2
- import { n as listOrkWorktrees, t as createdWorktrees } from "./list-DX65Sbu7.mjs";
3
- import { i as keyOf, n as applyStep, r as cleanStep, s as stepPrunes } from "./clean-hXSaN8BT.mjs";
1
+ import { ht as liveStatus, j as lines, k as git } from "./src-Do_MhwiV.mjs";
2
+ import { n as listOrkWorktrees, t as createdWorktrees } from "./list-BE02pCZ9.mjs";
3
+ import { i as keyOf, n as applyStep, r as cleanStep, s as stepPrunes } from "./clean-DYVmLkd4.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 { an as wakeRun, ht as liveStatus, kt as scriptContactsOf, rn as socketPath } from "./src-DnETlJ1r.mjs";
2
- import { c as openStore, o as writeErr } from "./output-Q3TZ-Ave.mjs";
3
- import { u as inheritedScrubber } from "./src-XDSRnAZV.mjs";
1
+ import { ht as liveStatus, in as socketPath, kt as scriptContactsOf, on as wakeRun } from "./src-Do_MhwiV.mjs";
2
+ import { c as openStore, o as writeErr } from "./output-BhYkshYq.mjs";
3
+ import { u as inheritedScrubber } from "./src-HxtJOMRr.mjs";
4
4
  import { defineCommand } from "citty";
5
5
  // ../core/src/remote/send.ts
6
6
  /**
@@ -1,4 +1,4 @@
1
- import { Bt as FEEDBACK_TARGETS, Rt as FEEDBACK_KINDS, pt as parseReport, zt as FEEDBACK_SEVERITIES } from "./src-DnETlJ1r.mjs";
1
+ import { Ht as FEEDBACK_SEVERITIES, Ut as FEEDBACK_TARGETS, Vt as FEEDBACK_KINDS, pt as parseReport } from "./src-Do_MhwiV.mjs";
2
2
  import { z } from "zod";
3
3
  import { randomBytes, timingSafeEqual } from "node:crypto";
4
4
  import { createInterface } from "node:readline";
@@ -818,12 +818,15 @@ const userLine = (text, later = false) => `${JSON.stringify({
818
818
  * `allowed` are the Ork tools that need no permission prompt.
819
819
  */
820
820
  const buildCliArgs = (spec, mcp, allowed) => {
821
- const mcpConfig = { mcpServers: { ["ork"]: {
822
- type: "http",
823
- url: mcp.url,
824
- headers: { Authorization: `Bearer ${mcp.token}` },
825
- timeout: ORK_TOOL_TIMEOUT_MS
826
- } } };
821
+ const mcpConfig = { mcpServers: {
822
+ ...spec.mcpServers,
823
+ ["ork"]: {
824
+ type: "http",
825
+ url: mcp.url,
826
+ headers: { Authorization: `Bearer ${mcp.token}` },
827
+ timeout: ORK_TOOL_TIMEOUT_MS
828
+ }
829
+ } };
827
830
  const args = [
828
831
  "-p",
829
832
  "--input-format",
@@ -1041,6 +1044,8 @@ const holdHook = (hold, onDefer, windowMs) => ({
1041
1044
  } };
1042
1045
  }]
1043
1046
  });
1047
+ /** The compiler has checked each entry has a command or a url. */
1048
+ const namedServers = (spec) => Object.fromEntries(Object.entries(spec.mcpServers ?? {}).filter((entry) => typeof entry[1]["command"] === "string" || typeof entry[1]["url"] === "string"));
1044
1049
  /** The Agent SDK options for a session spec. */
1045
1050
  const buildSdkOptions = (spec, ports, env, held) => {
1046
1051
  const { human } = ports;
@@ -1070,7 +1075,10 @@ const buildSdkOptions = (spec, ports, env, held) => {
1070
1075
  permissionMode: spec.permissionMode,
1071
1076
  allowedTools: [...spec.tools.allow, ...preapprovedTools(tools)],
1072
1077
  disallowedTools: spec.tools.deny,
1073
- mcpServers: { ["ork"]: ork },
1078
+ mcpServers: {
1079
+ ...namedServers(spec),
1080
+ ["ork"]: ork
1081
+ },
1074
1082
  outputFormat: {
1075
1083
  type: "json_schema",
1076
1084
  schema: spec.reportSchema