@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
@@ -459,6 +459,7 @@ const PracticesSchema = z.strictObject({
459
459
  ])]).optional().describe("Smallest complete change. `true` is `full`. Default: `full`.")
460
460
  });
461
461
  const TurnsSchema = z.number().int().positive();
462
+ const McpNamesSchema = z.array(z.string().min(1)).optional().describe("MCP servers from the project's `.mcp.json` this node's sessions load, beside Ork's own. Default: none.");
462
463
  const ToolRulesSchema = z.strictObject({
463
464
  allow: z.array(z.string()).optional(),
464
465
  deny: z.array(z.string()).optional(),
@@ -612,6 +613,7 @@ const claudeFields = {
612
613
  const ClaudeLeaderNodeSchema = z.strictObject({
613
614
  type: z.literal("claude.leader"),
614
615
  ...claudeFields,
616
+ mcp: McpNamesSchema,
615
617
  ...notifyFields,
616
618
  ...stepFields,
617
619
  maxWorkers: z.number().int().nonnegative().optional().describe("Cap on dynamically spawned workers."),
@@ -620,6 +622,7 @@ const ClaudeLeaderNodeSchema = z.strictObject({
620
622
  const ClaudeWorkerNodeSchema = z.strictObject({
621
623
  type: z.literal("claude.worker"),
622
624
  ...claudeFields,
625
+ mcp: McpNamesSchema,
623
626
  ...notifyFields,
624
627
  ...stepFields
625
628
  });
@@ -658,6 +661,7 @@ const HumanGateNodeSchema = z.strictObject({
658
661
  ...base,
659
662
  ...notifyFields,
660
663
  question: z.string(),
664
+ document: z.string().optional(),
661
665
  options: z.array(DecisionOptionSchema).min(2),
662
666
  recommended: z.string().optional(),
663
667
  timeout: DurationSchema.optional(),
@@ -922,6 +926,7 @@ const DefaultsSchema = z.strictObject({
922
926
  maxTurns: TurnsSchema.optional(),
923
927
  timeout: TimeoutSchema.optional().describe("For tool and Claude nodes that set none; a gate's own timeout is separate."),
924
928
  practices: PracticesSchema.optional(),
929
+ mcp: McpNamesSchema,
925
930
  before: stepFields.before
926
931
  });
927
932
  /** What the placeholders in a git template may name. */
@@ -1283,7 +1288,7 @@ const renderJsonSchema = () => {
1283
1288
  * model the serializer follows, so that a document edit puts a new key where
1284
1289
  * the serializer would and a canonical file stays canonical (RFC-008).
1285
1290
  */
1286
- const isRecord$2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
1291
+ const isRecord$3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
1287
1292
  const unwrapped = (schema) => {
1288
1293
  let current = schema;
1289
1294
  while (current instanceof z.ZodOptional || current instanceof z.ZodNullable || current instanceof z.ZodDefault) current = current.unwrap();
@@ -1304,8 +1309,8 @@ const declaresType = (object, type) => {
1304
1309
  /** The object `value` is, among those `schema` allows. */
1305
1310
  const objectFor = (schema, value) => {
1306
1311
  const objects = objectsIn(schema);
1307
- const keys = isRecord$2(value) ? Object.keys(value) : [];
1308
- const type = isRecord$2(value) ? value["type"] : void 0;
1312
+ const keys = isRecord$3(value) ? Object.keys(value) : [];
1313
+ const type = isRecord$3(value) ? value["type"] : void 0;
1309
1314
  return objects.find((object) => declaresType(object, type)) ?? objects.find((object) => keys.every((key) => key in object.shape)) ?? objects[0];
1310
1315
  };
1311
1316
  /** The keys `schema` declares for `value`, in canonical order. */
@@ -1321,14 +1326,14 @@ const childOf = (schema, key, value) => {
1321
1326
  /** `value` with every object's keys in canonical order and no undefined. */
1322
1327
  const inCanonicalOrder = (value, schema) => {
1323
1328
  if (Array.isArray(value)) return value.map((item, index) => inCanonicalOrder(item, childOf(schema, index, value)));
1324
- if (!isRecord$2(value)) return value;
1329
+ if (!isRecord$3(value)) return value;
1325
1330
  const order = keysOf(schema, value);
1326
1331
  return Object.fromEntries([...order.filter((known) => known in value), ...Object.keys(value).filter((other) => !order.includes(other))].filter((key) => value[key] !== void 0).map((key) => [key, inCanonicalOrder(value[key], childOf(schema, key, value))]));
1327
1332
  };
1328
1333
  /** Two plain values alike, whatever the order of their keys. */
1329
1334
  const sameValue$1 = (a, b) => {
1330
1335
  if (Array.isArray(a) && Array.isArray(b)) return a.length === b.length && a.every((x, i) => sameValue$1(x, b[i]));
1331
- if (isRecord$2(a) && isRecord$2(b)) {
1336
+ if (isRecord$3(a) && isRecord$3(b)) {
1332
1337
  const left = Object.entries(a);
1333
1338
  return left.length === Object.keys(b).length && left.every(([key, value]) => sameValue$1(value, b[key]));
1334
1339
  }
@@ -1495,7 +1500,7 @@ const entryOf = (doc, raw) => {
1495
1500
  }
1496
1501
  if (!isMap(item)) return void 0;
1497
1502
  const value = item.toJS(doc);
1498
- if (!isRecord$2(value)) return void 0;
1503
+ if (!isRecord$3(value)) return void 0;
1499
1504
  const { from, to, when, maxRounds, ...rest } = value;
1500
1505
  const whenIsText = typeof when === "string";
1501
1506
  const roundsIsNumber = typeof maxRounds === "number";
@@ -1713,7 +1718,7 @@ const withOptions = (doc, item, next) => {
1713
1718
  const custom = Object.keys(next.extra).length > 0;
1714
1719
  if (!isMap(item) || !hasOptions && !custom && !hasComment(item)) return authored(next);
1715
1720
  const value = item.toJS(doc);
1716
- const { when: _when, maxRounds: _rounds, ...rest } = isRecord$2(value) ? value : {};
1721
+ const { when: _when, maxRounds: _rounds, ...rest } = isRecord$3(value) ? value : {};
1717
1722
  return {
1718
1723
  ...rest,
1719
1724
  ...next.when === void 0 ? {} : { when: next.when },
@@ -3597,6 +3602,26 @@ const writePlugin = (stack, dir, description) => {
3597
3602
  }
3598
3603
  return dir;
3599
3604
  };
3605
+ // ../core/src/store/mask.ts
3606
+ /**
3607
+ * @file Masks secrets before anything is stored: tokens and keys in common
3608
+ * formats, anywhere in an event's strings. The store and feedback records use
3609
+ * the same patterns; the terminal is not masked (it is the user's own).
3610
+ */
3611
+ const PATTERNS = [
3612
+ /sk-ant-[\w-]{20,}/gu,
3613
+ /\bgh[opsur]_[A-Za-z0-9]{20,}/gu,
3614
+ /\bgithub_pat_\w{20,}/gu,
3615
+ /\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/gu,
3616
+ /\bxox[abprs]-[\w-]{10,}/gu,
3617
+ /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/gu,
3618
+ /(?<=\bbearer\s+)[\w.~+/-]{20,}=*/giu,
3619
+ /(?<=aws_secret_access_key\s*[=:]\s*)\S+/giu
3620
+ ];
3621
+ const MASK = "[masked]";
3622
+ const maskSecrets = (text) => PATTERNS.reduce((out, pattern) => out.replaceAll(pattern, MASK), text);
3623
+ /** A `JSON.stringify` replacer that masks every string. */
3624
+ const maskReplacer = (_key, value) => typeof value === "string" ? maskSecrets(value) : value;
3600
3625
  // ../core/src/control/socket.ts
3601
3626
  /**
3602
3627
  * @file The per-run local socket (`~/.ork/sockets/<run>.sock`): the fast path
@@ -4219,27 +4244,39 @@ const stringify$1 = (value) => {
4219
4244
  if (typeof value === "number" || typeof value === "boolean") return String(value);
4220
4245
  return JSON.stringify(value);
4221
4246
  };
4222
- const renderTemplate = (parts, scope) => parts.map((part) => typeof part === "string" ? part : stringify$1(evaluate(part.expr, scope))).join("");
4223
- // ../core/src/store/mask.ts
4247
+ const isContainer = (value) => value !== null && typeof value === "object";
4248
+ const depthOf = (value) => isContainer(value) ? 1 + Math.max(0, ...Object.values(value).map((item) => depthOf(item))) : 0;
4249
+ /** Keeps a multi-line value inside its list item or `key:` line. */
4250
+ const hang = (text) => text.replaceAll("\n", "\n ");
4251
+ /** A value at most two levels deep as Markdown list items and `key: value`. */
4252
+ const listed$2 = (value) => {
4253
+ if (!isContainer(value)) return stringify$1(value);
4254
+ if (Array.isArray(value)) return value.map((item) => `- ${hang(listed$2(item))}`).join("\n");
4255
+ return Object.entries(value).map(([key, item]) => isContainer(item) ? `${key}:\n ${hang(listed$2(item))}` : `${key}: ${hang(stringify$1(item))}`).join("\n");
4256
+ };
4224
4257
  /**
4225
- * @file Masks secrets before anything is stored: tokens and keys in common
4226
- * formats, anywhere in an event's strings. The store and feedback records use
4227
- * the same patterns; the terminal is not masked (it is the user's own).
4258
+ * A value as a person reads it: Markdown, never a line of raw JSON. `before` is
4259
+ * the text so far: a list or object starts on its own line, after a blank one
4260
+ * when text shares its line.
4228
4261
  */
4229
- const PATTERNS = [
4230
- /sk-ant-[\w-]{20,}/gu,
4231
- /\bgh[opsur]_[A-Za-z0-9]{20,}/gu,
4232
- /\bgithub_pat_\w{20,}/gu,
4233
- /\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/gu,
4234
- /\bxox[abprs]-[\w-]{10,}/gu,
4235
- /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/gu,
4236
- /(?<=\bbearer\s+)[\w.~+/-]{20,}=*/giu,
4237
- /(?<=aws_secret_access_key\s*[=:]\s*)\S+/giu
4238
- ];
4239
- const MASK = "[masked]";
4240
- const maskSecrets = (text) => PATTERNS.reduce((out, pattern) => out.replaceAll(pattern, MASK), text);
4241
- /** A `JSON.stringify` replacer that masks every string. */
4242
- const maskReplacer = (_key, value) => typeof value === "string" ? maskSecrets(value) : value;
4262
+ const readableText = (value, before) => {
4263
+ if (!isContainer(value)) return stringify$1(value);
4264
+ if (depthOf(value) <= 2) {
4265
+ const list = listed$2(value);
4266
+ return list === "" || before === "" || before.endsWith("\n") ? list : `\n\n${list}`;
4267
+ }
4268
+ const code = JSON.stringify(value, void 0, 2).replaceAll(/^/gmu, " ");
4269
+ return before === "" || before.endsWith("\n\n") ? code : `\n\n${code}`;
4270
+ };
4271
+ /**
4272
+ * Fills a parsed template. `readable` is for text a person reads (a gate's
4273
+ * `question` and `document`); scripts and prompts keep JSON (ADR-047).
4274
+ */
4275
+ const renderTemplate = (parts, scope, { readable = false } = {}) => parts.reduce((text, part) => {
4276
+ if (typeof part === "string") return text + part;
4277
+ const value = evaluate(part.expr, scope);
4278
+ return text + (readable ? readableText(value, text) : stringify$1(value));
4279
+ }, "");
4243
4280
  // ../core/src/feedback/fingerprint.ts
4244
4281
  /**
4245
4282
  * @file Feedback fingerprints: records about the same thing (same target, kind,
@@ -4563,6 +4600,119 @@ const FEEDBACK_SEVERITIES = [
4563
4600
  "medium",
4564
4601
  "high"
4565
4602
  ];
4603
+ // ../core/src/project/mcp-file.ts
4604
+ /**
4605
+ * @file The project's `.mcp.json`, the file Claude Code reads too, so a server
4606
+ * is defined in one place: reading its servers, and the compiler's check of
4607
+ * the servers a Claude node names (`mcp:`, ADR-067). A session's servers are
4608
+ * read with the file's text left as written, so no value leaves the file.
4609
+ */
4610
+ const MCP_FILE = ".mcp.json";
4611
+ /** Ork's own MCP server: a project can't redefine it. */
4612
+ const ORK_MCP_NAME = "ork";
4613
+ const isRecord$2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
4614
+ /** The file's `mcpServers`; `{}` when there is no file. */
4615
+ const serversIn = (root) => {
4616
+ const file = path.join(root, MCP_FILE);
4617
+ if (!existsSync(file)) return {
4618
+ ok: true,
4619
+ value: {}
4620
+ };
4621
+ try {
4622
+ const parsed = JSON.parse(readFileSync(file, "utf8"));
4623
+ const servers = isRecord$2(parsed) ? parsed["mcpServers"] : void 0;
4624
+ return {
4625
+ ok: true,
4626
+ value: isRecord$2(servers) ? servers : {}
4627
+ };
4628
+ } catch (error) {
4629
+ const reason = error instanceof SyntaxError ? "it is not valid JSON" : error instanceof Error ? error.message : String(error);
4630
+ return {
4631
+ ok: false,
4632
+ error: `${MCP_FILE} can't be read: ${reason}`
4633
+ };
4634
+ }
4635
+ };
4636
+ /** A server's field that holds something other than text: it would be dropped. */
4637
+ const mcpNotText = (server) => [
4638
+ "args",
4639
+ "env",
4640
+ "headers"
4641
+ ].find((field) => {
4642
+ const value = server[field];
4643
+ return (Array.isArray(value) ? value : isRecord$2(value) ? Object.values(value) : []).some((item) => typeof item !== "string");
4644
+ });
4645
+ /** Why an entry can't be loaded, whatever its name; its values aren't quoted. */
4646
+ const entryProblem = (server) => {
4647
+ if (!isRecord$2(server)) return "it is not an object";
4648
+ if (server["args"] !== void 0 && !Array.isArray(server["args"])) return "its args is not a list";
4649
+ const notRecord = ["env", "headers"].find((field) => server[field] !== void 0 && !isRecord$2(server[field]));
4650
+ if (notRecord !== void 0) return `its ${notRecord} is not an object`;
4651
+ const field = mcpNotText(server);
4652
+ if (field !== void 0) return `its ${field} holds a value that isn't text`;
4653
+ return typeof server["command"] === "string" || typeof server["url"] === "string" ? void 0 : "it has neither a command nor a url";
4654
+ };
4655
+ /** What the compiler checks a workflow's `mcp:` names against. */
4656
+ const mcpFileOptions = (root) => {
4657
+ const read = serversIn(root);
4658
+ if (!read.ok) return {
4659
+ mcpServers: [],
4660
+ mcpFileProblem: read.error
4661
+ };
4662
+ if (!existsSync(path.join(root, ".mcp.json"))) return {
4663
+ mcpServers: [],
4664
+ mcpFileProblem: `there is no ${MCP_FILE}`
4665
+ };
4666
+ return {
4667
+ mcpServers: Object.keys(read.value),
4668
+ mcpMalformed: Object.fromEntries(Object.entries(read.value).flatMap(([name, server]) => {
4669
+ const problem = entryProblem(server);
4670
+ return problem === void 0 ? [] : [[name, problem]];
4671
+ }))
4672
+ };
4673
+ };
4674
+ /** The error for one name a node gave, or nothing when it can load. */
4675
+ const nameProblem = (id, name, options, known) => {
4676
+ if (name === ORK_MCP_NAME) return {
4677
+ code: "mcp.reserved",
4678
+ message: `\`${id}\`: \`${ORK_MCP_NAME}\` is Ork's own server, name another`
4679
+ };
4680
+ if (!known.includes(name)) return {
4681
+ code: "mcp.unknown",
4682
+ message: `\`${id}\`: no MCP server \`${name}\`${options.mcpFileProblem === void 0 ? ` in ${MCP_FILE}, which has ${known.length === 0 ? "none" : known.join(", ")}` : `: ${options.mcpFileProblem}`}`
4683
+ };
4684
+ const problem = Object.hasOwn(options.mcpMalformed ?? {}, name) ? options.mcpMalformed?.[name] : void 0;
4685
+ return problem === void 0 ? void 0 : {
4686
+ code: "mcp.malformed",
4687
+ message: `\`${id}\`: MCP server \`${name}\` in ${MCP_FILE} is malformed: ${problem}`
4688
+ };
4689
+ };
4690
+ /** Every server a Claude node's sessions would load exists and can load. */
4691
+ const checkMcpServers = (workflow, options) => {
4692
+ const known = options.mcpServers;
4693
+ if (known === void 0) return [];
4694
+ return Object.entries(workflow.nodes).flatMap(([id, node]) => {
4695
+ if (node.type !== "claude.leader" && node.type !== "claude.worker") return [];
4696
+ const own = node.mcp !== void 0;
4697
+ return (node.mcp ?? workflow.defaults?.mcp ?? []).flatMap((name, index) => {
4698
+ const problem = nameProblem(id, name, options, known);
4699
+ return problem === void 0 ? [] : [{
4700
+ severity: "error",
4701
+ ...problem,
4702
+ path: own ? [
4703
+ "nodes",
4704
+ id,
4705
+ "mcp",
4706
+ index
4707
+ ] : [
4708
+ "defaults",
4709
+ "mcp",
4710
+ index
4711
+ ]
4712
+ }];
4713
+ });
4714
+ });
4715
+ };
4566
4716
  // ../core/src/project/templates.ts
4567
4717
  /**
4568
4718
  * @file Git name templates (`ork/{run}/{node}`, `{inputs.type}/{inputs.slug}`):
@@ -5776,6 +5926,7 @@ const TEMPLATE_FIELDS = [
5776
5926
  "command",
5777
5927
  "cwd",
5778
5928
  "question",
5929
+ "document",
5779
5930
  "workflow",
5780
5931
  "project",
5781
5932
  "ref"
@@ -5942,6 +6093,7 @@ const compileWorkflow = (authored, options = {}) => {
5942
6093
  ...rules.diagnostics,
5943
6094
  ...channels.diagnostics,
5944
6095
  ...checkRules(workflow),
6096
+ ...checkMcpServers(workflow, options),
5945
6097
  ...checkReach(workflow, edges, entries)
5946
6098
  ];
5947
6099
  diagnostics.sort((a, b) => SEVERITY_ORDER[a.severity] - SEVERITY_ORDER[b.severity]);
@@ -9073,7 +9225,8 @@ const checkWorkflowText = (text, { place, workflowDir, registered, home }) => {
9073
9225
  catalog,
9074
9226
  workflowDir,
9075
9227
  projectRoot,
9076
- ...loaded.project === void 0 ? {} : { project: loaded.project }
9228
+ ...loaded.project === void 0 ? {} : { project: loaded.project },
9229
+ ...mcpFileOptions(projectRoot)
9077
9230
  });
9078
9231
  const { graph } = compiled;
9079
9232
  const diagnostics = [];
@@ -9667,10 +9820,11 @@ const roleSection = (workflow, node) => {
9667
9820
  return role === void 0 || role === "" ? [] : [`# Your role: ${node.agent}\n\n${role}`];
9668
9821
  };
9669
9822
  /** The node's own tool rules, the project's and workflow's, and isolation's. */
9670
- const toolRules = (node, readonly, rules) => ({
9823
+ const toolRules = (node, readonly, rules, mcp) => ({
9671
9824
  allow: [.../* @__PURE__ */ new Set([
9672
9825
  ...rules?.permissions?.allow ?? [],
9673
9826
  ...node.tools?.allow ?? [],
9827
+ ...mcp.map((server) => `mcp__${server.replaceAll(/[^\w-]/gu, "_")}`),
9674
9828
  ...readonly ? READ_ONLY_COMMANDS : []
9675
9829
  ])],
9676
9830
  deny: [.../* @__PURE__ */ new Set([
@@ -9700,6 +9854,7 @@ const planNodeSession = (workflow, id, options) => {
9700
9854
  error: `\`${id}\` is a sub-agent; it runs inside \`${node.parent}\`'s session`
9701
9855
  };
9702
9856
  const defaults = workflow.defaults ?? {};
9857
+ const mcp = node.mcp ?? defaults.mcp ?? [];
9703
9858
  const isolation = node.isolation ?? defaults.isolation ?? "worktree";
9704
9859
  const ownWorktree = options.checkout?.own === true;
9705
9860
  if ((isolation === "worktree" && !ownWorktree || isolation === "continue" && options.checkout === void 0) && options.inPlace !== true) return {
@@ -9743,7 +9898,7 @@ const planNodeSession = (workflow, id, options) => {
9743
9898
  ...contextSections(context.files, "node")
9744
9899
  ].join("\n\n"),
9745
9900
  settingSources: ["project", "local"],
9746
- tools: toolRules(node, isolation === "readonly", workflow.rules),
9901
+ tools: toolRules(node, isolation === "readonly", workflow.rules, mcp),
9747
9902
  permissionMode: "default",
9748
9903
  reportSchema: reportSchemaFor(node)
9749
9904
  };
@@ -9769,6 +9924,7 @@ const planNodeSession = (workflow, id, options) => {
9769
9924
  ok: true,
9770
9925
  spec,
9771
9926
  driver: namedDriver(node, workflow),
9927
+ mcp,
9772
9928
  warnings,
9773
9929
  context
9774
9930
  };
@@ -13018,4 +13174,4 @@ const createWorkspace = (options) => {
13018
13174
  close
13019
13175
  };
13020
13176
  };
13021
- export { text as $, timeoutMs as $n, parseTemplate as $t, gitOk as A, guardedBase as An, runScope as At, linkNodes as B, serializeWorkflow as Bn, FEEDBACK_TARGETS as Bt, workflowTextHash as C, runDirOf as Cn, walkChecks as Ct, inspectProject as D, projectRootOf as Dn, userMessageText as Dt, BRANCH_PREFIX as E, inside as En, MESSAGE_LIMIT as Et, declaredProblem as F, applyEdits as Fn, PROJECT_FILE as Ft, requestContinue as G, expandEdge as Gn, publishPost as Gt, tellNode as H, EdgeInputSchema as Hn, planPost as Ht, createCalls as I, newWorkflowText as In, gitRulesOf as It, tellLiveRun as J, beforeOf as Jn, normalizeTitle as Jt, requestPause as K, settingsOf as Kn, createFeedback as Kt, addressOf as L, readDocument as Ln, loadProject as Lt, clearGitLocalEnv as M, writePlainFile as Mn, envReadsOf as Mt, parseInputPairs as N, skillsIn as Nn, nodeSays as Nt, removeWorktree as O, LESSON_CAP_TOKENS as On, heldTimeout as Ot, resolveInputs as P, WorkflowEditSchema as Pn, declaredOutputOf as Pt, inTransaction as Q, NodeIdSchema as Qn, evaluate as Qt, endLink as R, renderJsonSchema as Rn, FEEDBACK_KINDS as Rt, readProjectTriggers as S, projectsHome as Sn, checkWorkflowText as St, watchingPid as T, workflowDirOf as Tn, startRun as Tt, unlinkNodes as U, WorkflowSchema as Un, runGh as Ut, peerOf as V, markValue as Vn, DISCUSSIONS as Vt, flattenTree as W, CheckReportSchema as Wn, sendPost as Wt, usageQueries as X, isToolNode as Xn, maskReplacer as Xt, backfillUsage as Y, isClaudeNode as Yn, targetOf as Yt, eventOf as Z, programsRunBy as Zn, maskSecrets as Zt, lateTriggers as _, hasInRepoFiles as _n, runStatus as _t, limitsNow as a, wakeRun as an, CLAUDE_DRIVERS as ar, DETACHED_ENV as at, triggerStanding as b, placeFiles as bn, processAlive as bt, usd as c, planMoveInto as cn, experimentsOn as cr, explainWorkflowText as ct, runningRunIds as d, toolsInUse as dn, namingNoDriver as dt, renderTemplate as en, INTEGRATIONS as er, adoptedCalls as et, runningScript as f, createAgent as fn, sessionDriver as ft, parseVersion as g, PROJECT_MODES as gn, pausedOf as gt, isNewer as h, loadAgents as hn, liveStatus as ht, NOT_STARTED as i, socketRoom as in, ORK_LAYOUT as ir, replayLoopAnswers as it, lines as j, plainPathInside as jn, calledWorkflows as jt, git as k, estimateTokens as kn, scriptContactsOf as kt, planUpgrade as l, linkTools as ln, knownExperiments as lr, explainSession as lt, compareVersions as m, catalogAgent as mn, reportSchemaFor as mt, resolveBase as n, serveRun as nn, integrationFor as nr, resumable as nt, limitsReport as o, planAgentMigration as on, firstLine as or, detachRun as ot, detectInstaller as p, deleteAgent as pn, parseReport as pt, requestStop as q, NodeSchema as qn, fingerprint as qt, capsHere as r, socketPath as rn, AGENT_TOOL_LAYOUTS as rr, createReplay as rt, planReason as s, applySteps as sn, EXPERIMENTS as sr, followEvents as st, createWorkspace as t, readCondition as tn, TOOL_PREFIX as tr, detachResume as tt, releaseNotes as u, toolLinks as un, planNodeSession as ut, triggersReport as v, inRepoPlace as vn, runTree as vt, takeWatchLock as w, shownPath as wn, walkSummary as wt, declaredTriggers as x, placeFor as xn, stillTheSameProcess as xt, createWatcher as y, newProjectId as yn, ownProcessStart as yt, endLinksOf as z, parseWorkflow as zn, FEEDBACK_SEVERITIES as zt };
13177
+ export { text as $, isToolNode as $n, evaluate as $t, gitOk as A, projectRootOf as An, runScope as At, linkNodes as B, readDocument as Bn, serversIn as Bt, workflowTextHash as C, placeFiles as Cn, walkChecks as Ct, inspectProject as D, shownPath as Dn, userMessageText as Dt, BRANCH_PREFIX as E, runDirOf as En, MESSAGE_LIMIT as Et, declaredProblem as F, writePlainFile as Fn, PROJECT_FILE as Ft, requestContinue as G, EdgeInputSchema as Gn, planPost as Gt, tellNode as H, parseWorkflow as Hn, FEEDBACK_SEVERITIES as Ht, createCalls as I, skillsIn as In, gitRulesOf as It, tellLiveRun as J, expandEdge as Jn, publishPost as Jt, requestPause as K, WorkflowSchema as Kn, runGh as Kt, addressOf as L, WorkflowEditSchema as Ln, loadProject as Lt, clearGitLocalEnv as M, estimateTokens as Mn, envReadsOf as Mt, parseInputPairs as N, guardedBase as Nn, nodeSays as Nt, removeWorktree as O, workflowDirOf as On, heldTimeout as Ot, resolveInputs as P, plainPathInside as Pn, declaredOutputOf as Pt, inTransaction as Q, isClaudeNode as Qn, targetOf as Qt, endLink as R, applyEdits as Rn, MCP_FILE as Rt, readProjectTriggers as S, newProjectId as Sn, checkWorkflowText as St, watchingPid as T, projectsHome as Tn, startRun as Tt, unlinkNodes as U, serializeWorkflow as Un, FEEDBACK_TARGETS as Ut, peerOf as V, renderJsonSchema as Vn, FEEDBACK_KINDS as Vt, flattenTree as W, markValue as Wn, DISCUSSIONS as Wt, usageQueries as X, NodeSchema as Xn, fingerprint as Xt, backfillUsage as Y, settingsOf as Yn, createFeedback as Yt, eventOf as Z, beforeOf as Zn, normalizeTitle as Zt, lateTriggers as _, catalogAgent as _n, runStatus as _t, limitsNow as a, socketRoom as an, integrationFor as ar, DETACHED_ENV as at, triggerStanding as b, hasInRepoFiles as bn, processAlive as bt, usd as c, maskSecrets as cn, CLAUDE_DRIVERS as cr, explainWorkflowText as ct, runningRunIds as d, planMoveInto as dn, experimentsOn as dr, namingNoDriver as dt, parseTemplate as en, programsRunBy as er, adoptedCalls as et, runningScript as f, linkTools as fn, knownExperiments as fr, sessionDriver as ft, parseVersion as g, deleteAgent as gn, pausedOf as gt, isNewer as h, createAgent as hn, liveStatus as ht, NOT_STARTED as i, socketPath as in, TOOL_PREFIX as ir, replayLoopAnswers as it, lines as j, LESSON_CAP_TOKENS as jn, calledWorkflows as jt, git as k, inside as kn, scriptContactsOf as kt, planUpgrade as l, planAgentMigration as ln, firstLine as lr, explainSession as lt, compareVersions as m, toolsInUse as mn, reportSchemaFor as mt, resolveBase as n, readCondition as nn, timeoutMs as nr, resumable as nt, limitsReport as o, wakeRun as on, AGENT_TOOL_LAYOUTS as or, detachRun as ot, detectInstaller as p, toolLinks as pn, parseReport as pt, requestStop as q, CheckReportSchema as qn, sendPost as qt, capsHere as r, serveRun as rn, INTEGRATIONS as rr, createReplay as rt, planReason as s, maskReplacer as sn, ORK_LAYOUT as sr, followEvents as st, createWorkspace as t, renderTemplate as tn, NodeIdSchema as tr, detachResume as tt, releaseNotes as u, applySteps as un, EXPERIMENTS as ur, planNodeSession as ut, triggersReport as v, loadAgents as vn, runTree as vt, takeWatchLock as w, placeFor as wn, walkSummary as wt, declaredTriggers as x, inRepoPlace as xn, stillTheSameProcess as xt, createWatcher as y, PROJECT_MODES as yn, ownProcessStart as yt, endLinksOf as z, newWorkflowText as zn, mcpNotText as zt };