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

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 (30) hide show
  1. package/dist/{__build_info__-BwrKe6yz.mjs → __build_info__-1i1IwLg7.mjs} +2 -2
  2. package/dist/bin.mjs +37 -29
  3. package/dist/{clean-hXSaN8BT.mjs → clean-B1zPxq6A.mjs} +1 -1
  4. package/dist/{completion-Cga01yQP.mjs → completion-BY-frez8.mjs} +5 -5
  5. package/dist/{context-mCAwzFFM.mjs → context-CD5TCD1D.mjs} +3 -3
  6. package/dist/{decide-BvZnKErW.mjs → decide-CBhYcjwI.mjs} +1 -1
  7. package/dist/{find-CbetS8I2.mjs → find-BgZjVKhv.mjs} +1 -1
  8. package/dist/{format-D87bY6Ud.mjs → format-Creyq4U3.mjs} +2 -2
  9. package/dist/{in-a-run-Bs4Wv-Cz.mjs → in-a-run-CsSBQQ2q.mjs} +1 -1
  10. package/dist/{limits-RzKQ_zPk.mjs → limits-D_HxH0CK.mjs} +1 -1
  11. package/dist/{list-DX65Sbu7.mjs → list-CzzpVEpM.mjs} +1 -1
  12. package/dist/{mcp-DKrrxowo.mjs → mcp-DYmQt372.mjs} +6 -6
  13. package/dist/{output-Q3TZ-Ave.mjs → output-CuivUcDa.mjs} +1 -1
  14. package/dist/{pause-B5Z41lR3.mjs → pause-W6MzQqg8.mjs} +4 -4
  15. package/dist/{relay-BLnjMdjT.mjs → relay-CsdoZUXJ.mjs} +2 -2
  16. package/dist/{remove-IbcZOemm.mjs → remove-DLfDjBdF.mjs} +3 -3
  17. package/dist/{send-CJKEhBL1.mjs → send-Bw2FI_Sv.mjs} +3 -3
  18. package/dist/{src-DnETlJ1r.mjs → src-BRB5EQyC.mjs} +133 -11
  19. package/dist/{src-XDSRnAZV.mjs → src-Bc9yaAiZ.mjs} +159 -161
  20. package/dist/{src-LSxjnWDH.mjs → src-CrYCkU9J.mjs} +16 -8
  21. package/dist/{src-BTDzibW3.mjs → src-CsjumY1t.mjs} +7 -7
  22. package/dist/ui/assets/{app-BNElhp7Z.js → app-m9Gfrg_S.js} +1 -1
  23. package/dist/ui/assets/{index-BkI68sr5.js → index-UEC5ZLYw.js} +2 -2
  24. package/dist/ui/index.html +1 -1
  25. package/dist/{ui-fvrO7Gxd.mjs → ui-wX050aH1.mjs} +4 -4
  26. package/dist/{usage-bNdcBcj9.mjs → usage-C96RDH-G.mjs} +5 -5
  27. package/dist/{watch-EhlO304A.mjs → watch-vdRobJil.mjs} +6 -6
  28. package/dist/{workflows-C5hYAVcE.mjs → workflows-B28q8zMY.mjs} +3 -3
  29. package/dist/{worktrees-BQFcpYz1.mjs → worktrees-CKDRkl6b.mjs} +4 -4
  30. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
- import { $n as timeoutMs, $t as parseTemplate, At as runScope, F as declaredProblem, Jn as beforeOf, Mt as envReadsOf, Ot as heldTimeout, Pt as declaredOutputOf, Qt as evaluate, Vn as markValue, Xn as isToolNode, Zn as programsRunBy, en as renderTemplate, er as INTEGRATIONS, ft as sessionDriver, jt as calledWorkflows, mt as reportSchemaFor, nr as integrationFor, s as planReason, tr as TOOL_PREFIX, ut as planNodeSession } from "./src-DnETlJ1r.mjs";
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, nn as parseTemplate, nr as timeoutMs, rn as renderTemplate, rr as INTEGRATIONS, s as planReason, tn as evaluate, ut as planNodeSession, zt as mcpNotText } from "./src-BRB5EQyC.mjs";
2
2
  import path from "node:path";
3
- import { accessSync, constants, existsSync, lstatSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
3
+ import { accessSync, constants, lstatSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
4
4
  import { spawn } from "node:child_process";
5
5
  import { Client } from "@modelcontextprotocol/sdk/client/index.js";
6
6
  import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
@@ -123,6 +123,156 @@ const resultOf = (outcome, declared) => {
123
123
  if (!result.ok) result.error = report.summary;
124
124
  return result;
125
125
  };
126
+ // ../nodes/src/environ.ts
127
+ /** A variable of the user's. */
128
+ const readEnv = (environ, name) => Object.hasOwn(environ, name) ? environ[name] : void 0;
129
+ // ../nodes/src/mcp-servers.ts
130
+ /**
131
+ * @file Reading an MCP server's definition from the project's `.mcp.json`, the
132
+ * file Claude Code reads too, so a server is defined in one place (RFC-006).
133
+ * `${VAR}` and `${VAR:-default}` read the user's environment, which is where
134
+ * secrets stay: Ork stores none, and a run masks each value read this way. A
135
+ * server that needs an OAuth sign-in holds Claude Code's tokens, not Ork's,
136
+ * so it is refused.
137
+ */
138
+ const VARIABLE = /\$\{([A-Za-z_]\w*)(?::-([^}]*))?\}/gu;
139
+ const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
140
+ const stringsOf = (value) => isRecord(value) ? Object.fromEntries(Object.entries(value).flatMap(([key, item]) => typeof item === "string" ? [[key, item]] : [])) : {};
141
+ const listOf = (value) => Array.isArray(value) ? value.flatMap((item) => typeof item === "string" ? [item] : []) : [];
142
+ /** The server as written, or why Ork can't call it. */
143
+ const readMcpServer = (root, name) => {
144
+ const servers = serversIn(root);
145
+ if (!servers.ok) return servers;
146
+ const known = Object.keys(servers.value);
147
+ const server = Object.hasOwn(servers.value, name) ? servers.value[name] : void 0;
148
+ if (!isRecord(server)) return {
149
+ ok: false,
150
+ error: `no MCP server \`${name}\` in ${MCP_FILE}${known.length === 0 ? "" : `, which has ${known.join(", ")}`}`
151
+ };
152
+ if ("oauth" in server) return {
153
+ ok: false,
154
+ error: `MCP server \`${name}\` signs in with OAuth, whose tokens are Claude Code's: give it a token through headers and \`env:\`, or call it from a session`
155
+ };
156
+ const notText = mcpNotText(server);
157
+ if (notText !== void 0) return {
158
+ ok: false,
159
+ error: `MCP server \`${name}\` has a value in ${notText} that isn't a string: write it in quotes`
160
+ };
161
+ const { type, url, command } = server;
162
+ if (type === "http" && typeof url === "string") return {
163
+ ok: true,
164
+ value: {
165
+ kind: "http",
166
+ url,
167
+ headers: stringsOf(server["headers"])
168
+ }
169
+ };
170
+ if ((type === void 0 || type === "stdio") && typeof command === "string") return {
171
+ ok: true,
172
+ value: {
173
+ kind: "stdio",
174
+ command,
175
+ args: listOf(server["args"]),
176
+ env: stringsOf(server["env"])
177
+ }
178
+ };
179
+ return {
180
+ ok: false,
181
+ error: `MCP server \`${name}\` is not one Ork can call: it takes stdio and http servers`
182
+ };
183
+ };
184
+ /**
185
+ * The named servers' entries as written, for a session: `${VAR}` stays text for
186
+ * the `claude` that loads them to expand. The compiler has checked the names.
187
+ */
188
+ const namedMcpEntries = (root, names) => {
189
+ if (names.length === 0) return {
190
+ ok: true,
191
+ value: {}
192
+ };
193
+ const servers = serversIn(root);
194
+ if (!servers.ok) return servers;
195
+ const mcpServers = {};
196
+ for (const name of names) {
197
+ const server = Object.hasOwn(servers.value, name) ? servers.value[name] : void 0;
198
+ if (!isRecord(server)) return {
199
+ ok: false,
200
+ error: `no MCP server \`${name}\` in ${MCP_FILE}`
201
+ };
202
+ mcpServers[name] = server;
203
+ }
204
+ return {
205
+ ok: true,
206
+ value: { mcpServers }
207
+ };
208
+ };
209
+ /** Each variable a server reads, and whether it has a default. */
210
+ const readsOf = (server) => {
211
+ return (server.kind === "stdio" ? [
212
+ server.command,
213
+ ...server.args,
214
+ ...Object.values(server.env)
215
+ ] : [server.url, ...Object.values(server.headers)]).flatMap((text) => [...text.matchAll(VARIABLE)].map((match) => ({
216
+ name: String(match[1]),
217
+ fallback: match[2] !== void 0
218
+ })));
219
+ };
220
+ /**
221
+ * The server with its variables filled in, and the values to mask: all it read
222
+ * but those `plain` names, which aren't secret.
223
+ */
224
+ const expandServer = (server, environ, plain = []) => {
225
+ const unset = readsOf(server).find(({ name, fallback }) => !fallback && readEnv(environ, name) === void 0);
226
+ if (unset !== void 0) return {
227
+ ok: false,
228
+ error: `${MCP_FILE} reads ${unset.name}, which is not set`
229
+ };
230
+ const values = [];
231
+ const fill = (text) => text.replaceAll(VARIABLE, (_all, name, fallback) => {
232
+ const value = readEnv(environ, name);
233
+ if (value !== void 0 && !plain.includes(name)) values.push(value);
234
+ return value ?? fallback ?? "";
235
+ });
236
+ const fillAll = (record) => Object.fromEntries(Object.entries(record).map(([key, text]) => [key, fill(text)]));
237
+ return {
238
+ ok: true,
239
+ value: {
240
+ server: server.kind === "stdio" ? {
241
+ kind: "stdio",
242
+ command: fill(server.command),
243
+ args: server.args.map((arg) => fill(arg)),
244
+ env: fillAll(server.env)
245
+ } : {
246
+ kind: "http",
247
+ url: fill(server.url),
248
+ headers: fillAll(server.headers)
249
+ },
250
+ values
251
+ }
252
+ };
253
+ };
254
+ /** What a workflow's MCP servers read of the user's, unless called not secret. */
255
+ const mcpVariablesOf = (workflow, root) => Object.values(workflow.nodes).flatMap((node) => {
256
+ if (node.type !== "mcp.call") return [];
257
+ const read = readMcpServer(root, node.server);
258
+ return read.ok ? readsOf(read.value).map(({ name }) => name).filter((name) => node.plainEnv?.includes(name) !== true) : [];
259
+ });
260
+ /** A stdio server's program, when its name can be known before it is filled in. */
261
+ const programOf = (server) => server.kind === "stdio" && !server.command.includes("$") ? server.command : void 0;
262
+ /**
263
+ * What stops a workflow's `mcp.call` nodes, found before a run spends anything:
264
+ * a server that isn't there or can't be called, a program that isn't installed,
265
+ * or a variable that is not set.
266
+ */
267
+ const mcpProblems = (workflow, root, environ = process.env, finished = /* @__PURE__ */ new Set(), installed = () => true) => Object.entries(workflow.nodes).flatMap(([id, node]) => {
268
+ if (node.type !== "mcp.call" || finished.has(id)) return [];
269
+ const read = readMcpServer(root, node.server);
270
+ if (!read.ok) return [`${id}: ${read.error}`];
271
+ const given = new Set(Object.keys(node.env ?? {}));
272
+ const unset = readsOf(read.value).flatMap(({ name, fallback }) => fallback || given.has(name) || readEnv(environ, name) !== void 0 ? [] : [`${id}: ${MCP_FILE} reads ${name}, which is not set`]);
273
+ const program = programOf(read.value);
274
+ return program === void 0 || installed(program) ? unset : [`\`${id}\`: MCP server \`${node.server}\` runs \`${program}\`, which is not installed`].concat(unset);
275
+ });
126
276
  /** The only built-in tools a fork has: it reads, and reports. */
127
277
  const FORK_TOOLS = [
128
278
  "Read",
@@ -660,163 +810,6 @@ const tokenize = (command) => {
660
810
  args
661
811
  };
662
812
  };
663
- // ../nodes/src/environ.ts
664
- /** A variable of the user's. */
665
- const readEnv = (environ, name) => Object.hasOwn(environ, name) ? environ[name] : void 0;
666
- // ../nodes/src/mcp-servers.ts
667
- /**
668
- * @file Reading an MCP server's definition from the project's `.mcp.json`, the
669
- * file Claude Code reads too, so a server is defined in one place (RFC-006).
670
- * `${VAR}` and `${VAR:-default}` read the user's environment, which is where
671
- * secrets stay: Ork stores none, and a run masks each value read this way. A
672
- * server that needs an OAuth sign-in holds Claude Code's tokens, not Ork's,
673
- * so it is refused.
674
- */
675
- const MCP_FILE = ".mcp.json";
676
- const VARIABLE = /\$\{([A-Za-z_]\w*)(?::-([^}]*))?\}/gu;
677
- const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
678
- /** The file's `mcpServers`; `{}` when there is no file. */
679
- const serversIn = (root) => {
680
- const file = path.join(root, MCP_FILE);
681
- if (!existsSync(file)) return {
682
- ok: true,
683
- value: {}
684
- };
685
- try {
686
- const parsed = JSON.parse(readFileSync(file, "utf8"));
687
- const servers = isRecord(parsed) ? parsed["mcpServers"] : void 0;
688
- return {
689
- ok: true,
690
- value: isRecord(servers) ? servers : {}
691
- };
692
- } catch (error) {
693
- const reason = error instanceof SyntaxError ? "it is not valid JSON" : error instanceof Error ? error.message : String(error);
694
- return {
695
- ok: false,
696
- error: `${MCP_FILE} can't be read: ${reason}`
697
- };
698
- }
699
- };
700
- const stringsOf = (value) => isRecord(value) ? Object.fromEntries(Object.entries(value).flatMap(([key, item]) => typeof item === "string" ? [[key, item]] : [])) : {};
701
- const listOf = (value) => Array.isArray(value) ? value.flatMap((item) => typeof item === "string" ? [item] : []) : [];
702
- /** A server's field that holds something other than text: it would be dropped. */
703
- const notTextIn = (server) => [
704
- "args",
705
- "env",
706
- "headers"
707
- ].find((field) => {
708
- const value = server[field];
709
- return (Array.isArray(value) ? value : isRecord(value) ? Object.values(value) : []).some((item) => typeof item !== "string");
710
- });
711
- /** The server as written, or why Ork can't call it. */
712
- const readMcpServer = (root, name) => {
713
- const servers = serversIn(root);
714
- if (!servers.ok) return servers;
715
- const known = Object.keys(servers.value);
716
- const server = Object.hasOwn(servers.value, name) ? servers.value[name] : void 0;
717
- if (!isRecord(server)) return {
718
- ok: false,
719
- error: `no MCP server \`${name}\` in ${MCP_FILE}${known.length === 0 ? "" : `, which has ${known.join(", ")}`}`
720
- };
721
- if ("oauth" in server) return {
722
- ok: false,
723
- error: `MCP server \`${name}\` signs in with OAuth, whose tokens are Claude Code's: give it a token through headers and \`env:\`, or call it from a session`
724
- };
725
- const notText = notTextIn(server);
726
- if (notText !== void 0) return {
727
- ok: false,
728
- error: `MCP server \`${name}\` has a value in ${notText} that isn't a string: write it in quotes`
729
- };
730
- const { type, url, command } = server;
731
- if (type === "http" && typeof url === "string") return {
732
- ok: true,
733
- value: {
734
- kind: "http",
735
- url,
736
- headers: stringsOf(server["headers"])
737
- }
738
- };
739
- if ((type === void 0 || type === "stdio") && typeof command === "string") return {
740
- ok: true,
741
- value: {
742
- kind: "stdio",
743
- command,
744
- args: listOf(server["args"]),
745
- env: stringsOf(server["env"])
746
- }
747
- };
748
- return {
749
- ok: false,
750
- error: `MCP server \`${name}\` is not one Ork can call: it takes stdio and http servers`
751
- };
752
- };
753
- /** Each variable a server reads, and whether it has a default. */
754
- const readsOf = (server) => {
755
- return (server.kind === "stdio" ? [
756
- server.command,
757
- ...server.args,
758
- ...Object.values(server.env)
759
- ] : [server.url, ...Object.values(server.headers)]).flatMap((text) => [...text.matchAll(VARIABLE)].map((match) => ({
760
- name: String(match[1]),
761
- fallback: match[2] !== void 0
762
- })));
763
- };
764
- /**
765
- * The server with its variables filled in, and the values to mask: all it read
766
- * but those `plain` names, which aren't secret.
767
- */
768
- const expandServer = (server, environ, plain = []) => {
769
- const unset = readsOf(server).find(({ name, fallback }) => !fallback && readEnv(environ, name) === void 0);
770
- if (unset !== void 0) return {
771
- ok: false,
772
- error: `${MCP_FILE} reads ${unset.name}, which is not set`
773
- };
774
- const values = [];
775
- const fill = (text) => text.replaceAll(VARIABLE, (_all, name, fallback) => {
776
- const value = readEnv(environ, name);
777
- if (value !== void 0 && !plain.includes(name)) values.push(value);
778
- return value ?? fallback ?? "";
779
- });
780
- const fillAll = (record) => Object.fromEntries(Object.entries(record).map(([key, text]) => [key, fill(text)]));
781
- return {
782
- ok: true,
783
- value: {
784
- server: server.kind === "stdio" ? {
785
- kind: "stdio",
786
- command: fill(server.command),
787
- args: server.args.map((arg) => fill(arg)),
788
- env: fillAll(server.env)
789
- } : {
790
- kind: "http",
791
- url: fill(server.url),
792
- headers: fillAll(server.headers)
793
- },
794
- values
795
- }
796
- };
797
- };
798
- /** What a workflow's MCP servers read of the user's, unless called not secret. */
799
- const mcpVariablesOf = (workflow, root) => Object.values(workflow.nodes).flatMap((node) => {
800
- if (node.type !== "mcp.call") return [];
801
- const read = readMcpServer(root, node.server);
802
- return read.ok ? readsOf(read.value).map(({ name }) => name).filter((name) => node.plainEnv?.includes(name) !== true) : [];
803
- });
804
- /** A stdio server's program, when its name can be known before it is filled in. */
805
- const programOf = (server) => server.kind === "stdio" && !server.command.includes("$") ? server.command : void 0;
806
- /**
807
- * What stops a workflow's `mcp.call` nodes, found before a run spends anything:
808
- * a server that isn't there or can't be called, a program that isn't installed,
809
- * or a variable that is not set.
810
- */
811
- const mcpProblems = (workflow, root, environ = process.env, finished = /* @__PURE__ */ new Set(), installed = () => true) => Object.entries(workflow.nodes).flatMap(([id, node]) => {
812
- if (node.type !== "mcp.call" || finished.has(id)) return [];
813
- const read = readMcpServer(root, node.server);
814
- if (!read.ok) return [`${id}: ${read.error}`];
815
- const given = new Set(Object.keys(node.env ?? {}));
816
- const unset = readsOf(read.value).flatMap(({ name, fallback }) => fallback || given.has(name) || readEnv(environ, name) !== void 0 ? [] : [`${id}: ${MCP_FILE} reads ${name}, which is not set`]);
817
- const program = programOf(read.value);
818
- return program === void 0 || installed(program) ? unset : [`\`${id}\`: MCP server \`${node.server}\` runs \`${program}\`, which is not installed`].concat(unset);
819
- });
820
813
  // ../nodes/src/tool-scrub.ts
821
814
  /**
822
815
  * @file Masking a secret in what a program prints. A plain search, so a value
@@ -1589,7 +1582,12 @@ const claudeExecutor = (options) => async (context) => {
1589
1582
  },
1590
1583
  error: plan.error
1591
1584
  };
1592
- const spec = specFor(plan.spec, context);
1585
+ const servers = namedMcpEntries(context.projectRoot, plan.mcp);
1586
+ if (!servers.ok) return notStarted(servers.error);
1587
+ const spec = {
1588
+ ...specFor(plan.spec, context),
1589
+ ...servers.value
1590
+ };
1593
1591
  if (options.machineClaude === true) spec.machineClaude = true;
1594
1592
  const driver = sessionDriver({
1595
1593
  override: options.driver,
@@ -2130,4 +2128,4 @@ const missingPrograms = (workflow, installed = (program) => onPath(program)) =>
2130
2128
  }
2131
2129
  return [...missing.values()];
2132
2130
  };
2133
- export { resultOf as _, builtinExecutors as a, toolExecutor as c, maskedEnv as d, maskedNamesOfRun as f, clearOutputFiles as g, sessionEnv as h, onPath as i, clearStateFiles as l, runScrubber as m, missingProgramMessage as n, spawnTool as o, runMarkerIn as p, missingPrograms as r, mcpCallExecutor as s, envProblems as t, inheritedScrubber as u };
2131
+ export { namedMcpEntries as _, builtinExecutors as a, toolExecutor as c, maskedEnv as d, maskedNamesOfRun as f, clearOutputFiles as g, sessionEnv as h, onPath as i, clearStateFiles as l, runScrubber as m, missingProgramMessage as n, spawnTool as o, runMarkerIn as p, missingPrograms as r, mcpCallExecutor as s, envProblems as t, inheritedScrubber as u, resultOf as v };
@@ -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-BRB5EQyC.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
@@ -1,11 +1,11 @@
1
- import { B as linkNodes, Cn as runDirOf, Ct as walkChecks, En as inside, Fn as applyEdits, G as requestContinue, Gn as expandEdge, Hn as EdgeInputSchema, Ht as planPost, In as newWorkflowText, J as tellLiveRun, K as requestPause, Ln as readDocument, Nn as skillsIn, Nt as nodeSays, On as LESSON_CAP_TOKENS, Pn as WorkflowEditSchema, Rn as renderJsonSchema, St as checkWorkflowText, Tn as workflowDirOf, U as unlinkNodes, Ut as runGh, Vt as DISCUSSIONS, Wt as sendPost, _t as runStatus, bn as placeFiles, bt as processAlive, ct as explainWorkflowText, d as runningRunIds, f as runningScript, gt as pausedOf, hn as loadAgents, ht as liveStatus, l as planUpgrade, nt as resumable, o as limitsReport, ot as detachRun, p as detectInstaller, q as requestStop, qn as NodeSchema, r as capsHere, st as followEvents, tn as readCondition, tt as detachResume, u as releaseNotes, v as triggersReport, vt as runTree, wt as walkSummary, xn as placeFor, zn as parseWorkflow } from "./src-DnETlJ1r.mjs";
2
- import { C as feedbackActions, S as placeOf$1, _ as previewPost, a as registryShown, b as acceptItem, c as checkDue, f as readUpdateCache, g as nodeSession, h as writeUpdateCache, i as registryOf, l as fetchLatest, m as updateCachePath, o as updateSwitchOff, p as refreshUpdateCache, s as runInstall, u as newerVersion, w as openFixRun, x as lessonPlaceOf, y as recordNote } from "./__build_info__-BwrKe6yz.mjs";
3
- import { n as pendingDecisions, r as builtinProblem, t as answerDecision } from "./decide-BvZnKErW.mjs";
4
- import { n as newRunId, t as findRun } from "./find-CbetS8I2.mjs";
5
- import { c as openStore, l as storePath, s as nodeOf } from "./output-Q3TZ-Ave.mjs";
1
+ import { B as linkNodes, Bn as readDocument, Cn as placeFiles, Ct as walkChecks, En as runDirOf, G as requestContinue, Gn as EdgeInputSchema, Gt as planPost, Hn as parseWorkflow, In as skillsIn, J as tellLiveRun, Jn as expandEdge, K as requestPause, Kt as runGh, Ln as WorkflowEditSchema, Nt as nodeSays, On as workflowDirOf, Rn as applyEdits, St as checkWorkflowText, U as unlinkNodes, Vn as renderJsonSchema, Wt as DISCUSSIONS, Xn as NodeSchema, _t as runStatus, bt as processAlive, ct as explainWorkflowText, d as runningRunIds, f as runningScript, gt as pausedOf, ht as liveStatus, in as readCondition, jn as LESSON_CAP_TOKENS, kn as inside, l as planUpgrade, nt as resumable, o as limitsReport, ot as detachRun, p as detectInstaller, q as requestStop, qt as sendPost, r as capsHere, st as followEvents, tt as detachResume, u as releaseNotes, v as triggersReport, vn as loadAgents, vt as runTree, wn as placeFor, wt as walkSummary, zn as newWorkflowText } from "./src-BRB5EQyC.mjs";
2
+ import { C as feedbackActions, S as placeOf$1, _ as previewPost, a as registryShown, b as acceptItem, c as checkDue, f as readUpdateCache, g as nodeSession, h as writeUpdateCache, i as registryOf, l as fetchLatest, m as updateCachePath, o as updateSwitchOff, p as refreshUpdateCache, s as runInstall, u as newerVersion, w as openFixRun, x as lessonPlaceOf, y as recordNote } from "./__build_info__-1i1IwLg7.mjs";
3
+ import { n as pendingDecisions, r as builtinProblem, t as answerDecision } from "./decide-CBhYcjwI.mjs";
4
+ import { n as newRunId, t as findRun } from "./find-BgZjVKhv.mjs";
5
+ import { c as openStore, l as storePath, s as nodeOf } from "./output-CuivUcDa.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-hXSaN8BT.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-IbcZOemm.mjs";
7
+ import { a as planClean, i as keyOf, o as stepActs, r as cleanStep, s as stepPrunes, t as applyClean } from "./clean-B1zPxq6A.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-DLfDjBdF.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";