@krapht/ork 1.0.0-alpha.11 → 1.0.0-alpha.13

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 (40) hide show
  1. package/dist/{__build_info__-CIchF6nr.mjs → __build_info__-Da73_nBs.mjs} +4 -3
  2. package/dist/attach-E6NNyA3T.mjs +89 -0
  3. package/dist/bin.mjs +213 -1230
  4. package/dist/{decide-B6PnKeqo.mjs → builtin-files-n6o6oWpB.mjs} +3 -51
  5. package/dist/{chips-BA7SrrH5.mjs → chips-CyeB_rhR.mjs} +1 -1
  6. package/dist/{clean-Di-KT7Mf.mjs → clean-Bh4KZgzc.mjs} +1 -1
  7. package/dist/{completion-C5D0sEs5.mjs → completion-SNNNxnv9.mjs} +7 -6
  8. package/dist/{context-BaNshWr9.mjs → context-DHudLA5e.mjs} +6 -6
  9. package/dist/decide-DuIHACvH.mjs +50 -0
  10. package/dist/{find-BicBbGMg.mjs → find-CjsNYAAf.mjs} +1 -1
  11. package/dist/{format-lWhN-jYR.mjs → format-C60TFpRe.mjs} +5 -85
  12. package/dist/{help-groups-BwYoAWsh.mjs → help-groups-CyfPWlST.mjs} +8 -0
  13. package/dist/{in-a-run-CgkVouyG.mjs → in-a-run-BYjTXaST.mjs} +4 -2
  14. package/dist/{limits-jZQp9ZJC.mjs → limits-C5QKZNLT.mjs} +2 -2
  15. package/dist/{list-CEaJ07jd.mjs → list-BUb5Uc3H.mjs} +1 -1
  16. package/dist/{mcp-DYgVA9f5.mjs → mcp-bcctR-wc.mjs} +6 -6
  17. package/dist/once-DPQu5Q3H.mjs +76 -0
  18. package/dist/{output-CM95njYt.mjs → output-CnRzrbUM.mjs} +3 -1
  19. package/dist/{pause-D6PuSlNl.mjs → pause-BPvlDIvz.mjs} +4 -4
  20. package/dist/{relay-DNx7be9k.mjs → relay-C8W0t_zc.mjs} +2 -2
  21. package/dist/{remove-CpMb4NDl.mjs → remove-BkFWGVYo.mjs} +3 -3
  22. package/dist/run-CQIfq918.mjs +192 -0
  23. package/dist/{send-CLs_fyg7.mjs → send-CaZlGG5a.mjs} +3 -3
  24. package/dist/{src-D6_xjm-x.mjs → src-BeR6f70A.mjs} +595 -228
  25. package/dist/{src-B6KvTm7B.mjs → src-CGJGL1sZ.mjs} +7 -6
  26. package/dist/{src-BnZgZGrf.mjs → src-CqRqsb2t.mjs} +44 -7
  27. package/dist/{src-9iGkjnsy.mjs → src-D93tHZ5B.mjs} +110 -35
  28. package/dist/store-CM3cERGl.mjs +1365 -0
  29. package/dist/ui/THIRD_PARTY_LICENSES.txt +18 -0
  30. package/dist/ui/assets/app-DYRC0V4p.js +111 -0
  31. package/dist/ui/assets/{index-By_8KKG6.js → index-CWwm8HTG.js} +2 -2
  32. package/dist/ui/index.html +1 -1
  33. package/dist/{ui-CIci4UBW.mjs → ui-D2Ydofq0.mjs} +4 -4
  34. package/dist/{usage-GceBGMjU.mjs → usage-6WIowblz.mjs} +6 -6
  35. package/dist/verdict-CIy8tAyX.mjs +84 -0
  36. package/dist/{watch-BmoybMQg.mjs → watch-uOU_WeBI.mjs} +7 -7
  37. package/dist/{workflows-DZvW3i1e.mjs → workflows-7tQdMnrA.mjs} +3 -3
  38. package/dist/{worktrees-Be51E2rB.mjs → worktrees-ZCII298F.mjs} +5 -5
  39. package/package.json +1 -1
  40. package/dist/ui/assets/app-CxURph7a.js +0 -75
@@ -175,7 +175,8 @@ const claudeCode = {
175
175
  midTurnMessages: true,
176
176
  reportSchema: true,
177
177
  turnLimit: true,
178
- mcpServers: true
178
+ mcpServers: true,
179
+ subagents: true
179
180
  },
180
181
  proven: true,
181
182
  onePerCheckout: false,
@@ -257,7 +258,8 @@ const AGENT_DRIVERS = [
257
258
  midTurnMessages: false,
258
259
  reportSchema: false,
259
260
  turnLimit: true,
260
- mcpServers: true
261
+ mcpServers: true,
262
+ subagents: false
261
263
  }
262
264
  }),
263
265
  installedCli("command-code", "cmd", "cmd login", {
@@ -271,7 +273,8 @@ const AGENT_DRIVERS = [
271
273
  midTurnMessages: false,
272
274
  reportSchema: false,
273
275
  turnLimit: true,
274
- mcpServers: false
276
+ mcpServers: false,
277
+ subagents: false
275
278
  }
276
279
  })
277
280
  ];
@@ -544,13 +547,14 @@ const DriverSchema = z.enum(DRIVER_IDS, { error: (issue) => retiredDriverHint(is
544
547
  /** `opus`, `sonnet`, `haiku`, or a full model id such as `claude-opus-5-5`. */
545
548
  const ModelSchema = z.string().min(1);
546
549
  /** How hard the model thinks; Claude Code's own default when unset. */
547
- const EffortSchema = z.enum([
550
+ const EFFORTS = [
548
551
  "low",
549
552
  "medium",
550
553
  "high",
551
554
  "xhigh",
552
555
  "max"
553
- ]).describe("Reasoning effort. Default: Claude Code's for the model.");
556
+ ];
557
+ const EffortSchema = z.enum(EFFORTS).describe("Reasoning effort. Default: Claude Code's for the model.");
554
558
  const IsolationSchema = z.enum([
555
559
  "worktree",
556
560
  "continue",
@@ -623,7 +627,7 @@ const nodeBaseFields = {
623
627
  };
624
628
  /** A message a workflow declares, sent when its node finishes (RFC-005). */
625
629
  const NotifyRuleSchema = z.strictObject({
626
- to: NodeIdSchema.describe("The `claude.leader` or `claude.worker` to write to."),
630
+ to: NodeIdSchema.describe("The `agent.leader` or `agent.worker` to write to."),
627
631
  when: z.string().optional().describe("Send only when this holds. It reads what an edge's when: does, plus ok and error. Default: every finish."),
628
632
  body: z.string().optional().describe("The message, a template. Default: Ork's one line on the result.")
629
633
  });
@@ -662,12 +666,17 @@ const runFields = {
662
666
  script: z.string().optional().describe("The text of a short program, instead of command. It takes no templates: values arrive through env:, as $NAME, so a value cannot become code."),
663
667
  interpreter: z.string().optional().describe("What runs `script:`: a program and arguments. Default: `sh -eu`.")
664
668
  };
669
+ /** `once:` on a `verify:` and on a tool node. */
670
+ const onceField = z.boolean().optional().describe("Skip the command when the same check already passed on identical files (a hash of the working tree, the command, Node's version); a pass is recorded. Default: false.");
665
671
  const StepSchema = z.strictObject({
666
672
  ...runFields,
667
673
  ...toolProgramFields,
668
674
  timeout: TimeoutSchema.optional().describe("How long the program may run, e.g. 5m; then it is killed and the step fails.")
669
675
  });
670
- const VerifySchema = StepSchema.extend({ attempts: z.number().int().min(0).max(5).optional().describe("How many times a failed check resumes the session to fix it before the node fails. Default: 1.") }).describe("A program that must pass before the node's report is accepted. It runs in the node's checkout.");
676
+ const VerifySchema = StepSchema.extend({
677
+ attempts: z.number().int().min(0).max(5).optional().describe("How many times a failed check resumes the session to fix it before the node fails. Default: 1."),
678
+ once: onceField
679
+ }).describe("A program that must pass before the node's report is accepted. It runs in the node's checkout.");
671
680
  /** The fields a leader or worker takes its steps from. */
672
681
  const stepFields = {
673
682
  before: StepSchema.optional().describe("A program to run in the node's checkout before its session starts: if it fails, the node fails and no model turn is spent. Its prompt can read {{before.stdout}}, {{before.json.*}}."),
@@ -686,6 +695,7 @@ const toolFields = {
686
695
  cwd: z.string().optional(),
687
696
  timeout: TimeoutSchema.optional().describe("How long the command may run, e.g. 5m; then it is killed and the node fails. With watch:, how long one look may take."),
688
697
  watch: WatchSchema.optional().describe("Run the command again and again until a condition holds, with no model turn."),
698
+ once: onceField,
689
699
  ...toolProgramFields,
690
700
  ...notifyFields,
691
701
  ...forEachFields
@@ -720,13 +730,20 @@ const TOOL_NODE_SCHEMAS = INTEGRATIONS.map((i) => toolNodeSchema(i));
720
730
  const base = nodeBaseFields;
721
731
  /** A Claude node's output field that is not a list: a rule or JSON Schema. */
722
732
  const NotListSchema = z.unknown().refine((value) => typeof value !== "object" || value === null || !("list" in value), { message: LIST_RULE_HINT });
733
+ const NODE_EFFORT_HINT = "expected low, medium, high, xhigh or max, or {{item.<field>}}";
734
+ /**
735
+ * A Claude node's effort: a level, or on a `forEach` node a template reading
736
+ * its item (`{{item.effort}}`), which the compiler checks and each item
737
+ * renders.
738
+ */
739
+ const NodeEffortSchema = z.union([EffortSchema, z.string().regex(/\{\{.*\}\}/su, { error: NODE_EFFORT_HINT })], { error: NODE_EFFORT_HINT }).describe("Reasoning effort, or {{item.<field>}} on a forEach node. Default: Claude Code's for the model.");
723
740
  /**
724
741
  * What an agent brings to the node it fills, and what a plain Claude node sets
725
742
  * itself. A node's own value wins over its agent's.
726
743
  */
727
744
  const agentSettings = {
728
745
  model: ModelSchema.optional(),
729
- effort: EffortSchema.optional(),
746
+ effort: NodeEffortSchema.optional(),
730
747
  driver: DriverSchema.optional(),
731
748
  skills: z.array(z.string()).optional().describe("Node-layer skills (highest precedence)."),
732
749
  context: z.array(z.string()).optional().describe("Node-layer context files."),
@@ -766,7 +783,7 @@ const claudeFields = {
766
783
  ...agentSettings
767
784
  };
768
785
  const ClaudeLeaderNodeSchema = z.strictObject({
769
- type: z.literal("claude.leader"),
786
+ type: z.literal("agent.leader"),
770
787
  ...claudeFields,
771
788
  mcp: McpNamesSchema,
772
789
  ...notifyFields,
@@ -775,7 +792,7 @@ const ClaudeLeaderNodeSchema = z.strictObject({
775
792
  questions: z.enum(["owner", "user"]).optional().describe("Who a child's ask_user goes to first: `owner` asks a fork of this leader's session, which answers when what it was given settles it or passes it on; `user` (the default) asks the person.")
776
793
  });
777
794
  const ClaudeWorkerNodeSchema = z.strictObject({
778
- type: z.literal("claude.worker"),
795
+ type: z.literal("agent.worker"),
779
796
  ...claudeFields,
780
797
  mcp: McpNamesSchema,
781
798
  ...notifyFields,
@@ -783,7 +800,7 @@ const ClaudeWorkerNodeSchema = z.strictObject({
783
800
  ...stepFields
784
801
  });
785
802
  const ClaudeSubagentNodeSchema = z.strictObject({
786
- type: z.literal("claude.subagent"),
803
+ type: z.literal("agent.subagent"),
787
804
  ...claudeFields,
788
805
  parent: NodeIdSchema.describe("The Claude node whose session hosts this sub-agent."),
789
806
  description: z.string().describe("When the parent should use this sub-agent.")
@@ -855,9 +872,9 @@ const NodeSchema = z.discriminatedUnion("type", [
855
872
  ]);
856
873
  const isToolNode = (node) => node.type.startsWith(TOOL_PREFIX);
857
874
  const CLAUDE_NODE_TYPES = [
858
- "claude.leader",
859
- "claude.worker",
860
- "claude.subagent"
875
+ "agent.leader",
876
+ "agent.worker",
877
+ "agent.subagent"
861
878
  ];
862
879
  const isClaudeNode = (node) => CLAUDE_NODE_TYPES.includes(node.type);
863
880
  // ../schema/src/agents.ts
@@ -1191,6 +1208,16 @@ const markValue = (value) => {
1191
1208
  const pad = line.startsWith("`") || line.endsWith("`") ? " " : "";
1192
1209
  return `${fence}${pad}${line}${pad}${fence}`;
1193
1210
  };
1211
+ // ../schema/src/retired-types.ts
1212
+ /**
1213
+ * The node types RFC-015 renamed, and the one that replaces each: refused in a
1214
+ * workflow with the way out (`ork migrate`), never read as the new one.
1215
+ */
1216
+ const RETIRED_NODE_TYPES = {
1217
+ "claude.leader": "agent.leader",
1218
+ "claude.worker": "agent.worker",
1219
+ "claude.subagent": "agent.subagent"
1220
+ };
1194
1221
  // ../schema/src/issue-messages.ts
1195
1222
  const NODE_TYPES = NodeSchema.options.map((o) => o.shape.type.value);
1196
1223
  const isMap$1 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
@@ -1213,6 +1240,8 @@ const listRuleMessage = (issue, value) => issue.code === "invalid_union" && isMa
1213
1240
  /** The text for a node whose `type` is missing or unknown, else `null`. */
1214
1241
  const nodeTypeMessage = (issue, value) => {
1215
1242
  if (issue.code !== "invalid_union" || issue.discriminator !== "type") return null;
1243
+ const renamed = typeof value === "string" && Object.hasOwn(RETIRED_NODE_TYPES, value) ? RETIRED_NODE_TYPES[value] : void 0;
1244
+ if (renamed !== void 0) return `${markValue(String(value))} was renamed to ${markValue(renamed)}; run \`ork migrate\``;
1216
1245
  const types = NODE_TYPES.map((type) => markValue(type)).join(", ");
1217
1246
  return value === void 0 ? `node needs a \`type\`: one of ${types}` : `unknown node type ${markValue(typeof value === "string" ? value : JSON.stringify(value) ?? "")}: expected one of ${types}`;
1218
1247
  };
@@ -1440,6 +1469,22 @@ const renderJsonSchema = () => {
1440
1469
  title: "Ork workflow"
1441
1470
  }, void 0, 2)}\n`;
1442
1471
  };
1472
+ // ../schema/src/model-driver.ts
1473
+ /**
1474
+ * The text before the first `.` is the driver only when it is one of `drivers`
1475
+ * (ids have no dots); the rest goes to the tool as it is. Any other value is a
1476
+ * plain model for the run's driver, so `deepseek/deepseek-v4.1-flash` stays
1477
+ * plain.
1478
+ */
1479
+ const driverOf = (model, drivers) => {
1480
+ const dot = model.indexOf(".");
1481
+ if (dot <= 0) return { model };
1482
+ const id = model.slice(0, dot);
1483
+ return drivers.includes(id) ? {
1484
+ driver: id,
1485
+ model: model.slice(dot + 1)
1486
+ } : { model };
1487
+ };
1443
1488
  // ../schema/src/node-programs.ts
1444
1489
  /**
1445
1490
  * @file Which programs a node runs: its own, its `before:` and its `verify:`,
@@ -1467,7 +1512,7 @@ const programsOf = (node) => {
1467
1512
  }] : []];
1468
1513
  };
1469
1514
  /** The `before:` a leader or worker runs: its own, or the workflow's default. */
1470
- const beforeOf = (node, defaults) => node.type === "claude.leader" || node.type === "claude.worker" ? node.before ?? defaults?.before : void 0;
1515
+ const beforeOf = (node, defaults) => node.type === "agent.leader" || node.type === "agent.worker" ? node.before ?? defaults?.before : void 0;
1471
1516
  /** Each program a node runs, with what it takes from the workflow's defaults. */
1472
1517
  const programsRunBy = (node, defaults) => {
1473
1518
  const inherited = beforeOf(node, defaults);
@@ -1476,6 +1521,55 @@ const programsRunBy = (node, defaults) => {
1476
1521
  program: inherited
1477
1522
  }, ...programsOf(node)] : programsOf(node);
1478
1523
  };
1524
+ // ../schema/src/rename-types.ts
1525
+ /**
1526
+ * @file Rewrites a workflow file that names the node types RFC-015 renamed
1527
+ * (`claude.worker` and the others), for `ork migrate`: the types are renamed
1528
+ * in the YAML document, so the file keeps its comments and its own layout,
1529
+ * and the result is checked against the workflow schema. Models and every
1530
+ * other value are left as they are.
1531
+ */
1532
+ /**
1533
+ * The file with its retired node types renamed, keeping comments and layout,
1534
+ * and with how many of each; `null` when it names none (nothing to do, so a
1535
+ * second run changes nothing). A file that, once renamed, does not validate is
1536
+ * not rewritten: `{ ok: false }` says why.
1537
+ */
1538
+ const renameNodeTypes = (text) => {
1539
+ const doc = parseDocument(text);
1540
+ const nodes = doc.errors.length === 0 ? doc.get("nodes", true) : void 0;
1541
+ const renamed = {};
1542
+ if (isMap(nodes)) for (const pair of nodes.items) {
1543
+ const type = isMap(pair.value) ? pair.value.get("type", true) : void 0;
1544
+ if (isScalar(type) && typeof type.value === "string" && Object.hasOwn(RETIRED_NODE_TYPES, type.value)) {
1545
+ const old = type.value;
1546
+ type.value = RETIRED_NODE_TYPES[old] ?? old;
1547
+ renamed[old] = (renamed[old] ?? 0) + 1;
1548
+ }
1549
+ }
1550
+ if (Object.keys(renamed).length === 0) return doc.errors.length > 0 && /claude\.(worker|leader|subagent)/u.test(text) ? {
1551
+ ok: false,
1552
+ reason: doc.errors[0]?.message.split("\n")[0] ?? "not YAML"
1553
+ } : null;
1554
+ const body = doc.toString({
1555
+ lineWidth: 0,
1556
+ indent: 2
1557
+ });
1558
+ const parsed = parseWorkflow(body);
1559
+ if (!parsed.ok) {
1560
+ const first = parsed.diagnostics[0];
1561
+ return {
1562
+ ok: false,
1563
+ reason: `${first?.line === void 0 ? "" : `line ${String(first.line)}: `}${first?.message ?? "does not validate"}`
1564
+ };
1565
+ }
1566
+ const header = `# yaml-language-server: $schema=${SCHEMA_URL}\n`;
1567
+ return {
1568
+ ok: true,
1569
+ text: body.includes("yaml-language-server") ? body : header + body,
1570
+ renamed
1571
+ };
1572
+ };
1479
1573
  // ../schema/src/edit-order.ts
1480
1574
  /**
1481
1575
  * @file The canonical order of keys anywhere in a workflow, read from the Zod
@@ -2350,7 +2444,7 @@ const fieldNames = (doc, id, field) => String(doc.getIn([
2350
2444
  "nodes",
2351
2445
  id,
2352
2446
  "type"
2353
- ])).startsWith("claude.") ? [field] : [`json.${field}`, field];
2447
+ ])).startsWith("agent.") ? [field] : [`json.${field}`, field];
2354
2448
  const asValues = (raw) => {
2355
2449
  if (!Array.isArray(raw)) return [];
2356
2450
  return raw.map((item) => typeof item === "object" && item !== null && "id" in item ? item.id : item);
@@ -3726,7 +3820,7 @@ const resolveContext = (options) => {
3726
3820
  const contextDiagnostics = (workflow, options) => {
3727
3821
  const seen = /* @__PURE__ */ new Map();
3728
3822
  for (const [nodeId, node] of Object.entries(workflow.nodes)) {
3729
- if (!isClaudeNode(node) || node.type === "claude.subagent") continue;
3823
+ if (!isClaudeNode(node) || node.type === "agent.subagent") continue;
3730
3824
  const stack = resolveContext({
3731
3825
  ...options,
3732
3826
  workflow,
@@ -5275,7 +5369,7 @@ const checkMcpServers = (workflow, options) => {
5275
5369
  const known = options.mcpServers;
5276
5370
  if (known === void 0) return [];
5277
5371
  return Object.entries(workflow.nodes).flatMap(([id, node]) => {
5278
- if (node.type !== "claude.leader" && node.type !== "claude.worker") return [];
5372
+ if (node.type !== "agent.leader" && node.type !== "agent.worker") return [];
5279
5373
  const own = node.mcp !== void 0;
5280
5374
  return (node.mcp ?? workflow.defaults?.mcp ?? []).flatMap((name, index) => {
5281
5375
  const problem = nameProblem(id, name, options, known);
@@ -5486,10 +5580,10 @@ const manyWorktrees = (workflow) => {
5486
5580
  let count = 0;
5487
5581
  for (const node of Object.values(workflow.nodes)) {
5488
5582
  if (!isClaudeNode(node)) continue;
5489
- if (node.type === "claude.leader" && (node.maxWorkers ?? 0) > 0) return true;
5583
+ if (node.type === "agent.leader" && (node.maxWorkers ?? 0) > 0) return true;
5490
5584
  const isolation = node.isolation ?? workflow.defaults?.isolation ?? "worktree";
5491
5585
  const fanned = "forEach" in node && node.forEach !== void 0;
5492
- if (node.type !== "claude.subagent" && isolation === "worktree") count += fanned ? 2 : 1;
5586
+ if (node.type !== "agent.subagent" && isolation === "worktree") count += fanned ? 2 : 1;
5493
5587
  }
5494
5588
  return count > 1;
5495
5589
  };
@@ -5572,7 +5666,7 @@ const gatheredSays = (item) => {
5572
5666
  * passes its input through, so any field may exist.
5573
5667
  */
5574
5668
  const OUTPUT_FIELDS = {
5575
- "claude.leader": [
5669
+ "agent.leader": [
5576
5670
  "status",
5577
5671
  "summary",
5578
5672
  "artifacts",
@@ -5580,7 +5674,7 @@ const OUTPUT_FIELDS = {
5580
5674
  "worktree",
5581
5675
  "usage"
5582
5676
  ],
5583
- "claude.worker": [
5677
+ "agent.worker": [
5584
5678
  "status",
5585
5679
  "summary",
5586
5680
  "artifacts",
@@ -5588,7 +5682,7 @@ const OUTPUT_FIELDS = {
5588
5682
  "worktree",
5589
5683
  "usage"
5590
5684
  ],
5591
- "claude.subagent": [
5685
+ "agent.subagent": [
5592
5686
  "status",
5593
5687
  "summary",
5594
5688
  "artifacts"
@@ -5782,7 +5876,7 @@ const itemSays = (node) => {
5782
5876
  canFail: true,
5783
5877
  canDeclare: false
5784
5878
  };
5785
- if (!node.type.startsWith("claude.")) return NOTHING;
5879
+ if (!node.type.startsWith("agent.")) return NOTHING;
5786
5880
  const declared = declaredFields(node, "").map((field) => withFail(field));
5787
5881
  return {
5788
5882
  fields: [
@@ -5986,7 +6080,7 @@ const compileEdges = (workflow) => {
5986
6080
  diagnostics.push(error("edge.unknown-node", `edge \`${label}\`: unknown node ${missing.map((m) => `\`${m}\``).join(", ")}`, path));
5987
6081
  continue;
5988
6082
  }
5989
- const subagent = [edge.from, edge.to].find((id) => workflow.nodes[id]?.type === "claude.subagent");
6083
+ const subagent = [edge.from, edge.to].find((id) => workflow.nodes[id]?.type === "agent.subagent");
5990
6084
  if (subagent !== void 0) {
5991
6085
  diagnostics.push(error("edge.subagent", `edge \`${label}\`: \`${subagent}\` is a sub-agent; it runs inside its parent's session and takes no edges`, path));
5992
6086
  continue;
@@ -6181,14 +6275,14 @@ const envOutsideEnv = (segments, path) => error("template.env", `\`${describePat
6181
6275
  /**
6182
6276
  * Ownership rules:
6183
6277
  *
6184
- * - A `claude.subagent` is owned by a `claude.leader` or `claude.worker` (it runs
6278
+ * - An `agent.subagent` is owned by an `agent.leader` or `agent.worker` (it runs
6185
6279
  * inside that node's session);
6186
- * - Every other owned node is owned by a `claude.leader`;
6280
+ * - Every other owned node is owned by an `agent.leader`;
6187
6281
  * - The tree has no cycles;
6188
6282
  * - A node that sets `isolation: continue` neither owns nor is owned: it works in
6189
6283
  * the worktree its input came from, outside the tree's merges.
6190
6284
  * - A leader's `questions:` is about its children's questions, so a leader with
6191
- * no `claude.leader` or `claude.worker` child can't set it.
6285
+ * no `agent.leader` or `agent.worker` child can't set it.
6192
6286
  */
6193
6287
  const checkOwnership = (workflow) => {
6194
6288
  const diagnostics = [];
@@ -6203,9 +6297,9 @@ const checkOwnership = (workflow) => {
6203
6297
  const owner = nodes[node.parent];
6204
6298
  if (node.parent === id) diagnostics.push(error("tree.self", `\`${id}\` cannot own itself`, path));
6205
6299
  else if (owner === void 0) diagnostics.push(error("tree.unknown-parent", `unknown parent \`${node.parent}\``, path));
6206
- else if (node.type === "claude.subagent") {
6207
- if (owner.type !== "claude.leader" && owner.type !== "claude.worker") diagnostics.push(error("tree.owner-kind", `a sub-agent runs inside a \`claude.leader\` or \`claude.worker\` session, not a \`${owner.type}\``, path));
6208
- } else if (owner.type !== "claude.leader") diagnostics.push(error("tree.owner-kind", `only a claude.leader can own a \`${node.type}\` (\`${node.parent}\` is a \`${owner.type}\`)`, path));
6300
+ else if (node.type === "agent.subagent") {
6301
+ if (owner.type !== "agent.leader" && owner.type !== "agent.worker") diagnostics.push(error("tree.owner-kind", `a sub-agent runs inside an \`agent.leader\` or \`agent.worker\` session, not a \`${owner.type}\``, path));
6302
+ } else if (owner.type !== "agent.leader") diagnostics.push(error("tree.owner-kind", `only an agent.leader can own a \`${node.type}\` (\`${node.parent}\` is a \`${owner.type}\`)`, path));
6209
6303
  }
6210
6304
  for (const [id, node] of Object.entries(nodes)) {
6211
6305
  if (!("isolation" in node) || node.isolation !== "continue") continue;
@@ -6217,8 +6311,8 @@ const checkOwnership = (workflow) => {
6217
6311
  ]));
6218
6312
  }
6219
6313
  for (const [id, node] of Object.entries(nodes)) {
6220
- if (node.type !== "claude.leader" || node.questions === void 0) continue;
6221
- if (!Object.values(nodes).some((other) => other.parent === id && (other.type === "claude.leader" || other.type === "claude.worker"))) diagnostics.push(error("questions.no-children", `\`${id}\` sets \`questions\`, but owns no \`claude.leader\` or \`claude.worker\` whose questions it could take`, [
6314
+ if (node.type !== "agent.leader" || node.questions === void 0) continue;
6315
+ if (!Object.values(nodes).some((other) => other.parent === id && (other.type === "agent.leader" || other.type === "agent.worker"))) diagnostics.push(error("questions.no-children", `\`${id}\` sets \`questions\`, but owns no \`agent.leader\` or \`agent.worker\` whose questions it could take`, [
6222
6316
  "nodes",
6223
6317
  id,
6224
6318
  "questions"
@@ -6397,7 +6491,7 @@ const sessionsIn = (workflow, members) => {
6397
6491
  const parent = workflow.nodes[id]?.parent;
6398
6492
  return parent !== void 0 && (members.has(parent) || ownedByMember(parent));
6399
6493
  };
6400
- return Object.entries(workflow.nodes).filter(([id, node]) => isClaudeNode(node) && node.type !== "claude.subagent" && (members.has(id) || ownedByMember(id))).reduce((sum, [, node]) => sum + itemCountOf(node), 0);
6494
+ return Object.entries(workflow.nodes).filter(([id, node]) => isClaudeNode(node) && node.type !== "agent.subagent" && (members.has(id) || ownedByMember(id))).reduce((sum, [, node]) => sum + itemCountOf(node), 0);
6401
6495
  };
6402
6496
  /** Plain edges beside a loop edge. A first-match router's is its fallback. */
6403
6497
  const besideLoops = (workflow, edges, loops) => {
@@ -6429,6 +6523,71 @@ const checkGroup = (workflow, edges, component) => {
6429
6523
  };
6430
6524
  /** What's wrong with the shape of each group of nodes that loop together. */
6431
6525
  const checkLoops = (workflow, edges) => stronglyConnected(Object.keys(workflow.nodes), edges).flatMap((component) => checkGroup(workflow, edges, component));
6526
+ // ../core/src/run/driver.ts
6527
+ /**
6528
+ * @file Which agent driver a session runs on, one rule for every caller (`ork
6529
+ * run`, `--node`, `ork chat`, `ork resume`, called and detached runs): the
6530
+ * driver its model names (`claude-code.opus`, RFC-015), else `--driver`, else
6531
+ * the node's (or its agent's), else the workflow's `defaults.driver` (the
6532
+ * project's included), else the one ready on this machine when the run
6533
+ * started. No driver is written into a workflow for lack of one.
6534
+ */
6535
+ /** The node types that start a session of their own, and so need a driver. */
6536
+ const SESSION_TYPES$5 = /* @__PURE__ */ new Set(["agent.leader", "agent.worker"]);
6537
+ /**
6538
+ * A `model` value read once: the driver it names, if any, and what that tool
6539
+ * receives. A plain model (`deepseek/deepseek-v4.1-flash`) names none.
6540
+ */
6541
+ const modelDriver = (model) => {
6542
+ const parsed = driverOf(model, DRIVER_IDS);
6543
+ return {
6544
+ driver: DRIVER_IDS.find((id) => id === parsed.driver),
6545
+ model: parsed.model
6546
+ };
6547
+ };
6548
+ /**
6549
+ * The model a node asks for as written: its own (or its agent's), else the
6550
+ * default.
6551
+ */
6552
+ const writtenModel = (node, workflow) => isClaudeNode(node) ? node.model ?? workflow.defaults?.model : void 0;
6553
+ /**
6554
+ * The driver a node's model pins it to, as written. A template
6555
+ * (`{{item.model}}`) pins nothing here: each item's plan reads what it
6556
+ * renders.
6557
+ */
6558
+ const pinnedDriver = (node, workflow) => {
6559
+ const model = writtenModel(node, workflow);
6560
+ return model === void 0 ? void 0 : modelDriver(model).driver;
6561
+ };
6562
+ /** The driver a workflow names for a node, if it names one. */
6563
+ const namedDriver = (node, workflow) => ("driver" in node ? node.driver : void 0) ?? workflow.defaults?.driver;
6564
+ /**
6565
+ * Why a node's own `driver` and the driver its model names disagree, or
6566
+ * `undefined` when they agree or either is absent. `model` is the value as
6567
+ * written, or as an item rendered it.
6568
+ */
6569
+ const driverContradiction = (node, model) => {
6570
+ const own = "driver" in node ? node.driver : void 0;
6571
+ if (own === void 0 || model === void 0) return void 0;
6572
+ const pinned = modelDriver(model).driver;
6573
+ return pinned === void 0 || pinned === own ? void 0 : `model \`${model}\` names driver \`${pinned}\`, but the node sets \`driver: ${own}\`; remove one, or make them agree`;
6574
+ };
6575
+ /** The session nodes that name no driver, which take the one ready here. */
6576
+ const namingNoDriver = (workflow) => Object.entries(workflow.nodes).filter(([, node]) => SESSION_TYPES$5.has(node.type) && pinnedDriver(node, workflow) === void 0 && namedDriver(node, workflow) === void 0).map(([id]) => id);
6577
+ /**
6578
+ * The driver a session runs on: `pinned` (its model's prefix), else `override`
6579
+ * (`--driver`), else what the workflow names, else `ready`, the driver the run
6580
+ * found ready when it started (and recorded, for a resume). `undefined` only
6581
+ * when none applies, which a run refuses before it starts.
6582
+ */
6583
+ const sessionDriver = (choice) => choice.pinned ?? choice.override ?? choice.named ?? choice.ready;
6584
+ /** `sessionDriver` for a node of the workflow, as written. */
6585
+ const nodeDriver = (node, workflow, choice) => sessionDriver({
6586
+ pinned: pinnedDriver(node, workflow),
6587
+ override: choice.override,
6588
+ named: namedDriver(node, workflow),
6589
+ ready: choice.ready
6590
+ });
6432
6591
  // ../core/src/graph/gather.ts
6433
6592
  /** Whether a declared field is a list: `{ type: array }` or `{ list: … }`. */
6434
6593
  const isList = (rule) => listShape(rule) !== void 0 || typeof rule === "object" && rule !== null && "type" in rule && rule.type === "array";
@@ -6449,6 +6608,122 @@ const gatherProblems = (id, node) => {
6449
6608
  return isList(rule) ? [] : [error("output.gather", `\`${field}\` isn't declared as a list (\`{ type: array }\` or \`{ list: … }\`), so its rounds can't be added together`, [...path, index])];
6450
6609
  });
6451
6610
  };
6611
+ // ../core/src/graph/item-settings.ts
6612
+ /**
6613
+ * @file A fanned node's `model` and `effort` from its item (`{{item.model}}`):
6614
+ * the compiler's checks (only on a `forEach` node, reading only `item`, and
6615
+ * every written item's value), and the rendering each item's session plan
6616
+ * uses, which checks an item from `from:` when it runs.
6617
+ */
6618
+ const FIELDS$1 = ["model", "effort"];
6619
+ /**
6620
+ * The parts of a template that reads something, or `null` for a plain value (or
6621
+ * one that does not parse, which the compiler reports).
6622
+ */
6623
+ const templateOf$1 = (text) => {
6624
+ const parsed = parseTemplate(text);
6625
+ if (!parsed.ok) return null;
6626
+ return parsed.parts.some((part) => typeof part !== "string") ? parsed.parts : null;
6627
+ };
6628
+ const isEffort = (text) => EFFORTS.includes(text);
6629
+ /** Checks what one item's template rendered to. */
6630
+ const checkRendered = (field, template, rendered) => {
6631
+ const text = rendered.trim();
6632
+ if (text === "") return {
6633
+ ok: true,
6634
+ value: void 0
6635
+ };
6636
+ return (field === "effort" ? isEffort(text) : /^[^\s{}"]+$/u.test(text)) ? {
6637
+ ok: true,
6638
+ value: text
6639
+ } : {
6640
+ ok: false,
6641
+ error: `\`${field}: ${template}\` gave \`${text}\`, which is not ${field === "effort" ? `an effort level (${EFFORTS.join(", ")})` : "a model name"}`
6642
+ };
6643
+ };
6644
+ /**
6645
+ * A node's `model` or `effort` for one item: a plain value as written, a
6646
+ * template rendered with the item. Without an item, a template renders empty.
6647
+ */
6648
+ const itemSetting = (field, value, scope) => {
6649
+ if (value === void 0) return {
6650
+ ok: true,
6651
+ value: void 0
6652
+ };
6653
+ const parts = templateOf$1(value);
6654
+ if (parts === null) return {
6655
+ ok: true,
6656
+ value
6657
+ };
6658
+ return checkRendered(field, value, renderTemplate(parts, scope));
6659
+ };
6660
+ /** `itemSetting` for `effort`, as an effort level. */
6661
+ const itemEffort = (value, scope) => {
6662
+ const given = itemSetting("effort", value, scope);
6663
+ if (!given.ok) return given;
6664
+ if (given.value === void 0) return {
6665
+ ok: true,
6666
+ value: void 0
6667
+ };
6668
+ return isEffort(given.value) ? {
6669
+ ok: true,
6670
+ value: given.value
6671
+ } : {
6672
+ ok: false,
6673
+ error: `\`effort\` is \`${given.value}\``
6674
+ };
6675
+ };
6676
+ /** A `model` or `effort` template's problems on one node. */
6677
+ const checkNodeField = (workflow, says, id, field) => {
6678
+ const node = workflow.nodes[id];
6679
+ const value = node === void 0 ? void 0 : Reflect.get(node, field);
6680
+ if (node === void 0 || typeof value !== "string") return [];
6681
+ const path = [
6682
+ "nodes",
6683
+ id,
6684
+ field
6685
+ ];
6686
+ const parsed = parseTemplate(value);
6687
+ if (!parsed.ok) return [error("template.syntax", `${parsed.message} at column ${parsed.offset + 1}`, path)];
6688
+ if (parsed.parts.every((part) => typeof part === "string")) return [];
6689
+ const each = forEachOf$1(node);
6690
+ if (each === void 0) return [error(`${field}.template`, `\`${field}\` may be a template only on a node with \`forEach\`, reading its item, e.g. \`{{item.${field}}}\``, path)];
6691
+ const reads = parsed.parts.flatMap((part) => typeof part === "string" ? [] : collectPaths(part.expr));
6692
+ const outside = reads.filter(([root]) => root !== "item");
6693
+ if (outside.length > 0) return outside.map((segments) => error(`${field}.template`, `\`${describePath(segments)}\`: a \`${field}\` template reads only the item, e.g. \`{{item.${field}}}\``, path));
6694
+ const scope = { fields: itemFieldsOf(node, says) };
6695
+ const fields = reads.flatMap((segments) => checkItemRead(segments, scope, path));
6696
+ if (fields.length > 0 || !("items" in each)) return fields;
6697
+ return each.items.flatMap((item, index) => {
6698
+ const given = checkRendered(field, value, renderTemplate(parsed.parts, {
6699
+ inputs: {},
6700
+ nodes: {},
6701
+ item,
6702
+ index
6703
+ }));
6704
+ return given.ok ? [] : [error(`${field}.item`, `item ${String(index)}: ${given.error}`, [
6705
+ "nodes",
6706
+ id,
6707
+ "forEach",
6708
+ "items",
6709
+ index
6710
+ ])];
6711
+ });
6712
+ };
6713
+ /**
6714
+ * `model` and `effort` templates: only on a `forEach` node, reading only
6715
+ * `item`, and every written item's value a model name or an effort level.
6716
+ * `defaults:` belong to no node, so they take no template.
6717
+ */
6718
+ const checkItemSettings = (workflow, edges) => {
6719
+ const says = nodeSays(workflow.nodes, edges);
6720
+ const defaults = FIELDS$1.flatMap((field) => {
6721
+ const value = workflow.defaults?.[field];
6722
+ return value !== void 0 && templateOf$1(value) !== null ? [error(`${field}.template`, `\`defaults.${field}\` applies to every node, so it can't read an item; set the template on the \`forEach\` node`, ["defaults", field])] : [];
6723
+ });
6724
+ const nodes = Object.entries(workflow.nodes).flatMap(([id, node]) => isClaudeNode(node) ? FIELDS$1.flatMap((field) => checkNodeField(workflow, says, id, field)) : []);
6725
+ return [...defaults, ...nodes];
6726
+ };
6452
6727
  // ../core/src/graph/script.ts
6453
6728
  /**
6454
6729
  * @file Checks on the programs a workflow declares (RFC-006): a tool node's and
@@ -6499,7 +6774,7 @@ const optionId = (option) => typeof option === "string" ? option : option.id;
6499
6774
  * another would fail on every run. It can narrow them, to fail on the rest.
6500
6775
  */
6501
6776
  const statusProblems = (id, node) => {
6502
- if (!isClaudeNode(node) || node.type === "claude.subagent") return [];
6777
+ if (!isClaudeNode(node) || node.type === "agent.subagent") return [];
6503
6778
  const rule = declaredOutputOf(node)?.["status"];
6504
6779
  const list = typeof rule === "object" && rule !== null && "enum" in rule ? rule.enum : rule;
6505
6780
  if (!Array.isArray(list)) return [];
@@ -6512,15 +6787,28 @@ const statusProblems = (id, node) => {
6512
6787
  "status"
6513
6788
  ]));
6514
6789
  };
6790
+ /**
6791
+ * A node's `driver` and the driver its model names (`claude-code.opus`) must
6792
+ * agree; the model may be the workflow's `defaults.model`.
6793
+ */
6794
+ const modelDriverProblems = (id, node, workflow) => {
6795
+ const own = isClaudeNode(node) ? node.model : void 0;
6796
+ const problem = driverContradiction(node, writtenModel(node, workflow));
6797
+ return problem === void 0 ? [] : [error("model.driver", own === void 0 ? `${problem} (the model is \`defaults.model\`)` : problem, [
6798
+ "nodes",
6799
+ id,
6800
+ own === void 0 ? "driver" : "model"
6801
+ ])];
6802
+ };
6515
6803
  /** Per-type checks that need the rest of the graph. */
6516
6804
  const checkNodes = (workflow, edges) => {
6517
- const diagnostics = checkScripts(workflow);
6805
+ const diagnostics = [...checkScripts(workflow), ...checkItemSettings(workflow, edges)];
6518
6806
  for (const [id, node] of Object.entries(workflow.nodes)) {
6519
6807
  const path = ["nodes", id];
6520
6808
  const incoming = edges.filter((e) => e.to === id);
6521
6809
  const outgoing = edges.filter((e) => e.from === id);
6522
- if (node.type === "claude.subagent" && node.timeout !== void 0) diagnostics.push(warning("timeout.subagent", `sub-agent \`${id}\` runs inside its parent's session, so its timeout has no effect; set one on the parent`, [...path, "timeout"]));
6523
- diagnostics.push(...statusProblems(id, node), ...gatherProblems(id, node));
6810
+ if (node.type === "agent.subagent" && node.timeout !== void 0) diagnostics.push(warning("timeout.subagent", `sub-agent \`${id}\` runs inside its parent's session, so its timeout has no effect; set one on the parent`, [...path, "timeout"]));
6811
+ diagnostics.push(...statusProblems(id, node), ...gatherProblems(id, node), ...modelDriverProblems(id, node, workflow));
6524
6812
  if (node.type === "control.join") {
6525
6813
  const sources = new Set(incoming.map((e) => e.from)).size;
6526
6814
  if (sources < 2) diagnostics.push(warning("join.inputs", `join \`${id}\` has ${sources} incoming node(s); a join waits for two or more`, path));
@@ -6572,10 +6860,10 @@ const checkChannels = (workflow) => {
6572
6860
  }
6573
6861
  const bad = [a, b].filter((id) => {
6574
6862
  const node = workflow.nodes[id];
6575
- return !(node?.type === "claude.leader" || node?.type === "claude.worker" || node !== void 0 && isToolNode(node) || node?.type === "workflow.call" && node.node !== void 0);
6863
+ return !(node?.type === "agent.leader" || node?.type === "agent.worker" || node !== void 0 && isToolNode(node) || node?.type === "workflow.call" && node.node !== void 0);
6576
6864
  });
6577
6865
  if (bad.length > 0) {
6578
- diagnostics.push(error("message.endpoint", `${bad.map((id) => `\`${id}\``).join(", ")}: channels connect \`claude.leader\` and \`claude.worker\` nodes, a tool node, and a \`workflow.call\` that names a node`, path));
6866
+ diagnostics.push(error("message.endpoint", `${bad.map((id) => `\`${id}\``).join(", ")}: channels connect \`agent.leader\` and \`agent.worker\` nodes, a tool node, and a \`workflow.call\` that names a node`, path));
6579
6867
  continue;
6580
6868
  }
6581
6869
  const nodeA = workflow.nodes[a];
@@ -6584,9 +6872,9 @@ const checkChannels = (workflow) => {
6584
6872
  diagnostics.push(error("message.endpoint", `\`${a}\`, \`${b}\`: a channel needs a session on this side, and a \`workflow.call\` has none`, path));
6585
6873
  continue;
6586
6874
  }
6587
- const session = (node) => node?.type === "claude.leader" || node?.type === "claude.worker";
6875
+ const session = (node) => node?.type === "agent.leader" || node?.type === "agent.worker";
6588
6876
  if ((nodeA !== void 0 && isToolNode(nodeA) || nodeB !== void 0 && isToolNode(nodeB)) && !session(nodeA) && !session(nodeB)) {
6589
- diagnostics.push(error("message.endpoint", `\`${a}\`, \`${b}\`: a tool node writes to a session, so the other side must be a \`claude.leader\` or \`claude.worker\``, path));
6877
+ diagnostics.push(error("message.endpoint", `\`${a}\`, \`${b}\`: a tool node writes to a session, so the other side must be an \`agent.leader\` or \`agent.worker\``, path));
6590
6878
  continue;
6591
6879
  }
6592
6880
  if (nodeA?.parent === b || nodeB?.parent === a) diagnostics.push(warning("message.implicit", [nodeA, nodeB].some((node) => node !== void 0 && isToolNode(node)) ? "a tool node can always write to its owner; this channel is not needed" : "a parent and its child can always message each other; this channel is not needed", path));
@@ -6948,7 +7236,7 @@ const checkFlow = (workflow, edges, rules) => [
6948
7236
  ...checkConditions(workflow, edges, rules)
6949
7237
  ];
6950
7238
  // ../core/src/graph/notify.ts
6951
- const RECEIVERS = /* @__PURE__ */ new Set(["claude.leader", "claude.worker"]);
7239
+ const RECEIVERS = /* @__PURE__ */ new Set(["agent.leader", "agent.worker"]);
6952
7240
  const compileRules = (workflow) => {
6953
7241
  const rules = /* @__PURE__ */ new Map();
6954
7242
  const diagnostics = [];
@@ -6966,7 +7254,7 @@ const compileRules = (workflow) => {
6966
7254
  if (hidden.length > 0 && (rule.when !== void 0 || rule.body !== void 0)) diagnostics.push(warning("notify.shadowed", `in a rule, ${hidden.join(" and ")} mean how the node ended, not its field; read that as nodes.${id}.output.${hidden[0] ?? ""}`, path));
6967
7255
  const target = workflow.nodes[rule.to];
6968
7256
  if (rule.to === id) diagnostics.push(error("notify.self", "a node cannot notify itself", [...path, "to"]));
6969
- else if (target === void 0 || !RECEIVERS.has(target.type)) diagnostics.push(error("notify.target", `\`${rule.to}\`: a rule goes to a \`claude.leader\` or \`claude.worker\`, which has a session to read it`, [...path, "to"]));
7257
+ else if (target === void 0 || !RECEIVERS.has(target.type)) diagnostics.push(error("notify.target", `\`${rule.to}\`: a rule goes to an \`agent.leader\` or \`agent.worker\`, which has a session to read it`, [...path, "to"]));
6970
7258
  if (target !== void 0 && forEachOf$1(target) !== void 0) diagnostics.push(error("forEach.notify", `\`${rule.to}\` has \`forEach\`: a rule goes to one session, and its items don't exist until its list is resolved.`, [...path, "to"]));
6971
7259
  const entry = { to: rule.to };
6972
7260
  if (rule.when !== void 0) {
@@ -7049,6 +7337,101 @@ const compileWorkflow = (authored, options = {}) => {
7049
7337
  diagnostics
7050
7338
  };
7051
7339
  };
7340
+ // ../core/src/worktree/git-env.ts
7341
+ /**
7342
+ * @file Git's local environment variables, the ones a git hook sets (`GIT_DIR`,
7343
+ * `GIT_INDEX_FILE`, …), and an environment without them. Ork finds a project
7344
+ * by its path, never through these, so an `ork` started from a hook clears
7345
+ * them at its entry, and core's git runner leaves them out for callers that
7346
+ * don't start there (specs/worktrees.md).
7347
+ */
7348
+ /**
7349
+ * What `git rev-parse --local-env-vars` prints (git 2.39.5). A fixed list, so
7350
+ * no git is spawned at every start; a test fails when the installed git names
7351
+ * one that is missing here.
7352
+ */
7353
+ const GIT_LOCAL_ENV = [
7354
+ "GIT_ALTERNATE_OBJECT_DIRECTORIES",
7355
+ "GIT_CONFIG",
7356
+ "GIT_CONFIG_PARAMETERS",
7357
+ "GIT_CONFIG_COUNT",
7358
+ "GIT_OBJECT_DIRECTORY",
7359
+ "GIT_DIR",
7360
+ "GIT_WORK_TREE",
7361
+ "GIT_IMPLICIT_WORK_TREE",
7362
+ "GIT_GRAFT_FILE",
7363
+ "GIT_INDEX_FILE",
7364
+ "GIT_NO_REPLACE_OBJECTS",
7365
+ "GIT_REPLACE_REF_BASE",
7366
+ "GIT_PREFIX",
7367
+ "GIT_INTERNAL_SUPER_PREFIX",
7368
+ "GIT_SHALLOW_FILE",
7369
+ "GIT_COMMON_DIR"
7370
+ ];
7371
+ /** A copy of `env` without git's local variables. */
7372
+ const withoutGitLocalEnv = (env) => {
7373
+ const clean = { ...env };
7374
+ for (const name of GIT_LOCAL_ENV) delete clean[name];
7375
+ return clean;
7376
+ };
7377
+ /** Removes git's local variables from `env` in place (the CLI's entry). */
7378
+ const clearGitLocalEnv = (env = process.env) => {
7379
+ for (const name of GIT_LOCAL_ENV) delete env[name];
7380
+ };
7381
+ // ../core/src/worktree/git.ts
7382
+ /**
7383
+ * @file A minimal `git` runner for the worktree manager: arguments without a
7384
+ * shell, results that never throw, and none of git's local variables (a
7385
+ * hook's `GIT_DIR` or `GIT_INDEX_FILE`), so it acts on the repository at
7386
+ * `cwd` (specs/worktrees.md). Commands in one folder run one at a time: two
7387
+ * children handed their owner's work at once both stage it (`git add -A`),
7388
+ * and git refuses the second while the first holds the index's lock.
7389
+ */
7390
+ /** The last command queued in each folder, so the next one waits for it. */
7391
+ const queues = /* @__PURE__ */ new Map();
7392
+ /** Runs `task` after every command queued earlier in the same folder. */
7393
+ const inTurn = (cwd, task) => {
7394
+ const key = path.resolve(cwd);
7395
+ const next = (queues.get(key) ?? Promise.resolve()).then(task, task);
7396
+ queues.set(key, next);
7397
+ next.finally(() => {
7398
+ if (queues.get(key) === next) queues.delete(key);
7399
+ });
7400
+ return next;
7401
+ };
7402
+ const runGit = (cwd, args, env) => new Promise((resolve) => {
7403
+ execFile("git", args, {
7404
+ cwd,
7405
+ env: {
7406
+ ...withoutGitLocalEnv(process.env),
7407
+ ...env
7408
+ },
7409
+ maxBuffer: 33554432,
7410
+ encoding: "utf8"
7411
+ }, (error, stdout, stderr) => {
7412
+ resolve({
7413
+ code: error === null ? 0 : typeof error.code === "number" ? error.code : -1,
7414
+ stdout,
7415
+ stderr: error !== null && !existsSync(cwd) ? `the folder ${cwd} doesn't exist` : stderr || (error?.message ?? "")
7416
+ });
7417
+ });
7418
+ });
7419
+ /**
7420
+ * Runs `git` with arguments (no shell) in `cwd`. Never throws. `env` adds
7421
+ * variables, such as a temporary `GIT_INDEX_FILE`.
7422
+ */
7423
+ const git = (cwd, args, env = {}) => inTurn(cwd, () => runGit(cwd, args, env));
7424
+ /** Like `git`, but rejects with git's message when the command fails. */
7425
+ const gitOk = async (cwd, args, env = {}) => {
7426
+ const result = await git(cwd, args, env);
7427
+ if (result.code !== 0) {
7428
+ const reason = result.stderr.trim().split("\n").at(-1) ?? "";
7429
+ throw new Error(`git ${args[0] ?? ""} failed: ${reason}`);
7430
+ }
7431
+ return result.stdout;
7432
+ };
7433
+ /** Output lines without the trailing empty one. */
7434
+ const lines = (text) => text.split("\n").filter((line) => line !== "");
7052
7435
  // ../core/src/machine/priority.ts
7053
7436
  /**
7054
7437
  * @file Starting a child at the project's priority (`priority:`): `low`, the
@@ -7090,11 +7473,13 @@ const startAt = (priority, bin, args, env = process.env) => {
7090
7473
  return [first, [...rest, ...args]];
7091
7474
  };
7092
7475
  /**
7093
- * Lowers a started child's priority for `low`, best effort; what it starts
7094
- * later inherits it.
7476
+ * Lowers a started child's priority for `low` where {@link startAt} had no
7477
+ * `nice` to start it under (Windows), best effort; what it starts later
7478
+ * inherits it. Under `nice` it does nothing: `nice` lowers relative to the
7479
+ * priority it finds, so lowering here too could land first and the two add up.
7095
7480
  */
7096
7481
  const lowerChild = (priority, pid) => {
7097
- if (priority !== "low" || pid === void 0) return;
7482
+ if (priority !== "low" || pid === void 0 || existsSync(NICE)) return;
7098
7483
  try {
7099
7484
  setPriority(pid, constants$1.priority.PRIORITY_BELOW_NORMAL);
7100
7485
  } catch {}
@@ -7256,7 +7641,7 @@ const checkCallTargets = (workflow, own, registered) => Object.entries(workflow.
7256
7641
  const found = [];
7257
7642
  if (node.node !== void 0) {
7258
7643
  const type = called.nodes[node.node]?.type;
7259
- if (type !== "claude.leader" && type !== "claude.worker") found.push(error("call.node", `call \`${id}\`: \`${node.node}\` is not a leader or worker of \`${node.workflow}\``, [...at, "node"]));
7644
+ if (type !== "agent.leader" && type !== "agent.worker") found.push(error("call.node", `call \`${id}\`: \`${node.node}\` is not a leader or worker of \`${node.workflow}\``, [...at, "node"]));
7260
7645
  }
7261
7646
  for (const [name, input] of Object.entries(called.inputs ?? {})) if (input.required === true && input.default === void 0 && node.inputs?.[name] === void 0) found.push(error("call.input", `call \`${id}\`: \`${node.workflow}\` requires the input \`${name}\``, [...at, "inputs"]));
7262
7647
  return found;
@@ -7959,7 +8344,7 @@ const createFanOut = (deps) => {
7959
8344
  };
7960
8345
  // ../core/src/run/delegation.ts
7961
8346
  /** Node types a leader can hand work to. */
7962
- const DELEGABLE = /* @__PURE__ */ new Set(["claude.leader", "claude.worker"]);
8347
+ const DELEGABLE = /* @__PURE__ */ new Set(["agent.leader", "agent.worker"]);
7963
8348
  /** A child a leader delegated to: waits for a slot, runs, reports back. */
7964
8349
  const createRunChild = (hooks) => async (child, brief) => {
7965
8350
  await hooks.slots.take();
@@ -8014,9 +8399,9 @@ const createOwnership = (hooks) => {
8014
8399
  if (node.description !== void 0) child.description = node.description;
8015
8400
  return [child];
8016
8401
  });
8017
- const templates = children.filter((c) => c.type === "claude.worker").map((c) => c.id);
8402
+ const templates = children.filter((c) => c.type === "agent.worker").map((c) => c.id);
8018
8403
  const leaderNode = owner?.node;
8019
- const maxWorkers = leaderNode?.type === "claude.leader" ? leaderNode.maxWorkers ?? 0 : 0;
8404
+ const maxWorkers = leaderNode?.type === "agent.leader" ? leaderNode.maxWorkers ?? 0 : 0;
8020
8405
  const spawned = [];
8021
8406
  /** Runs the accepted jobs in parallel; the slot goes to them meanwhile. */
8022
8407
  const runJobs = async (jobs) => {
@@ -8156,7 +8541,7 @@ const nodeContext = (deps, activation, cwd, round, clock) => {
8156
8541
  budgetLeftUsd: deps.spend.left(),
8157
8542
  budgetLeftNow: deps.spend.budgetLeft,
8158
8543
  reserveBudget: (usd) => {
8159
- deps.spend.reserve(id, usd, deps.nodeOf(activation)?.type !== "claude.leader");
8544
+ deps.spend.reserve(id, usd, deps.nodeOf(activation)?.type !== "agent.leader");
8160
8545
  },
8161
8546
  budgetFreed: (signal) => deps.spend.freed(id, signal),
8162
8547
  quota: deps.spend.quota,
@@ -8177,7 +8562,16 @@ const nodeContext = (deps, activation, cwd, round, clock) => {
8177
8562
  event
8178
8563
  });
8179
8564
  },
8180
- signal: deps.stops.signalFor(id, template)
8565
+ signal: deps.stops.signalFor(id, template),
8566
+ skipped: (check, { at, who }) => {
8567
+ options.onEvent({
8568
+ type: "verify.skipped",
8569
+ id,
8570
+ check,
8571
+ at,
8572
+ who
8573
+ });
8574
+ }
8181
8575
  };
8182
8576
  const owner = ownerPort(deps, id, template);
8183
8577
  if (owner !== void 0) context.owner = owner;
@@ -8188,7 +8582,7 @@ const nodeContext = (deps, activation, cwd, round, clock) => {
8188
8582
  if (activation.item !== void 0) context.item = activation.item;
8189
8583
  const resume = options.replay?.cutOff?.(activation) ?? resumeOf(deps.nodeOf(activation), deps.sessionIds.get(id) ?? options.replay?.previousSession?.(activation));
8190
8584
  if (resume !== void 0) context.resume = resume;
8191
- if (deps.nodeOf(activation)?.type === "claude.leader") context.ownership = createOwnership({
8585
+ if (deps.nodeOf(activation)?.type === "agent.leader") context.ownership = createOwnership({
8192
8586
  graph,
8193
8587
  leader: id,
8194
8588
  runChild: deps.runChild,
@@ -8231,12 +8625,12 @@ const ownerPort = (deps, id, template) => deps.ports.owners.portFor(id, template
8231
8625
  */
8232
8626
  const resumeOf = (node, sessionId) => {
8233
8627
  if (node === void 0 || !isClaudeNode(node)) return void 0;
8234
- if (node.type === "claude.subagent") return void 0;
8235
- return (node.session ?? (node.type === "claude.leader" ? "resume" : "fresh")) === "resume" ? sessionId : void 0;
8628
+ if (node.type === "agent.subagent") return void 0;
8629
+ return (node.session ?? (node.type === "agent.leader" ? "resume" : "fresh")) === "resume" ? sessionId : void 0;
8236
8630
  };
8237
8631
  // ../core/src/run/contacts.ts
8238
- const SESSION_TYPES$5 = /* @__PURE__ */ new Set(["claude.leader", "claude.worker"]);
8239
- const isSession$1 = (node) => SESSION_TYPES$5.has(node?.type ?? "");
8632
+ const SESSION_TYPES$4 = /* @__PURE__ */ new Set(["agent.leader", "agent.worker"]);
8633
+ const isSession$1 = (node) => SESSION_TYPES$4.has(node?.type ?? "");
8240
8634
  const isTool = (node) => node?.type.startsWith("tool.") ?? false;
8241
8635
  const channelPeersOf = (id, channels) => channels.flatMap(([a, b]) => {
8242
8636
  if (a === id) return [b];
@@ -9134,7 +9528,7 @@ const NEVER = new Promise(() => {});
9134
9528
  /** For a rejection no one is left to hear. */
9135
9529
  const ignore = () => {};
9136
9530
  /** The timeout that applies to a node; a gate's own means something else. */
9137
- const timeoutOf = (node, workflow) => (isToolNode(node) || isClaudeNode(node) || node.type === "workflow.call" || node.type === "mcp.call") && node.type !== "claude.subagent" ? node.timeout ?? workflow.defaults?.timeout : void 0;
9531
+ const timeoutOf = (node, workflow) => (isToolNode(node) || isClaudeNode(node) || node.type === "workflow.call" || node.type === "mcp.call") && node.type !== "agent.subagent" ? node.timeout ?? workflow.defaults?.timeout : void 0;
9138
9532
  const createClock = (options) => {
9139
9533
  const { graph, holds, running } = options;
9140
9534
  /** Nodes between two looks of a `watch:`. */
@@ -9628,7 +10022,7 @@ const createOwnerQuestions = ({ ownerOf, deliverTo, onEvent }) => {
9628
10022
  };
9629
10023
  };
9630
10024
  // ../core/src/run/bus.ts
9631
- const SESSION_TYPES$4 = /* @__PURE__ */ new Set(["claude.leader", "claude.worker"]);
10025
+ const SESSION_TYPES$3 = /* @__PURE__ */ new Set(["agent.leader", "agent.worker"]);
9632
10026
  const createBus = ({ graph, onEvent, mail, relay, slots }) => {
9633
10027
  /** Spawned instance -> the declared node it is an instance of. */
9634
10028
  const templates = /* @__PURE__ */ new Map();
@@ -9647,7 +10041,7 @@ const createBus = ({ graph, onEvent, mail, relay, slots }) => {
9647
10041
  /** Sessions in `wait`: called when a message arrives or the session ends. */
9648
10042
  const waiters = /* @__PURE__ */ new Map();
9649
10043
  const declared = (id) => graph.nodes.get(templates.get(id) ?? id);
9650
- const hasSession = (id) => SESSION_TYPES$4.has(graph.nodes.get(id)?.node.type ?? "");
10044
+ const hasSession = (id) => SESSION_TYPES$3.has(graph.nodes.get(id)?.node.type ?? "");
9651
10045
  const inbox = (id) => {
9652
10046
  const existing = inboxes.get(id);
9653
10047
  if (existing !== void 0) return existing;
@@ -9834,7 +10228,7 @@ const createBus = ({ graph, onEvent, mail, relay, slots }) => {
9834
10228
  * notice when it is released; a node's claims are released when it finishes.
9835
10229
  * Claims are advisory: they steer agents, they do not lock files.
9836
10230
  */
9837
- const SESSION_TYPES$3 = /* @__PURE__ */ new Set(["claude.leader", "claude.worker"]);
10231
+ const SESSION_TYPES$2 = /* @__PURE__ */ new Set(["agent.leader", "agent.worker"]);
9838
10232
  const WHOLE = ".";
9839
10233
  /**
9840
10234
  * A resource as the run compares it: a path from the project root (an absolute
@@ -9859,7 +10253,7 @@ const writersOf = (graph) => {
9859
10253
  const isolation = graph.workflow.defaults?.isolation ?? "worktree";
9860
10254
  const writers = /* @__PURE__ */ new Set();
9861
10255
  for (const [id, { node }] of graph.nodes) {
9862
- if (!SESSION_TYPES$3.has(node.type)) continue;
10256
+ if (!SESSION_TYPES$2.has(node.type)) continue;
9863
10257
  if ("isolation" in node && (node.isolation ?? isolation) === "readonly") continue;
9864
10258
  writers.add(id);
9865
10259
  }
@@ -9868,7 +10262,7 @@ const writersOf = (graph) => {
9868
10262
  const spawnable = (graph, writers) => {
9869
10263
  let count = 0;
9870
10264
  for (const { node, children } of graph.nodes.values()) {
9871
- if (node.type !== "claude.leader") continue;
10265
+ if (node.type !== "agent.leader") continue;
9872
10266
  if (children.some((child) => writers.has(child))) count += node.maxWorkers ?? 0;
9873
10267
  }
9874
10268
  return count;
@@ -9960,7 +10354,7 @@ const createClaims = ({ graph, onEvent, notify }) => {
9960
10354
  };
9961
10355
  // ../core/src/run/owners.ts
9962
10356
  /** The node types whose sessions can ask (`ask_user`). */
9963
- const ASKING = /* @__PURE__ */ new Set(["claude.leader", "claude.worker"]);
10357
+ const ASKING = /* @__PURE__ */ new Set(["agent.leader", "agent.worker"]);
9964
10358
  const createOwners = (graph) => {
9965
10359
  const sessions = /* @__PURE__ */ new Map();
9966
10360
  /** The leader that takes `id`'s questions first, if one does. */
@@ -9968,7 +10362,7 @@ const createOwners = (graph) => {
9968
10362
  const node = graph.nodes.get(template ?? id)?.node;
9969
10363
  if (node?.parent === void 0 || !ASKING.has(node.type)) return void 0;
9970
10364
  const owner = graph.nodes.get(node.parent)?.node;
9971
- return owner?.type === "claude.leader" && owner.questions === "owner" ? node.parent : void 0;
10365
+ return owner?.type === "agent.leader" && owner.questions === "owner" ? node.parent : void 0;
9972
10366
  };
9973
10367
  return {
9974
10368
  /** Notes `id`'s own sessions as they start and end; forks aren't its own. */
@@ -11481,12 +11875,13 @@ const parseReport = (value) => {
11481
11875
  // ../core/src/run/brief.ts
11482
11876
  /**
11483
11877
  * @file What a Claude node is asked: its brief, rendered against the run's
11484
- * inputs and outputs, and its `claude.subagent` children as Claude Code
11485
- * subagents of its session (the SDK's `agents`, the CLI's `--agents`). A
11486
- * subagent's role (its agent's instructions), `instructions` and `prompt` are
11487
- * its system prompt, and its `description` says when the session hands it
11488
- * work with the Agent tool; it runs inside that session, with no process,
11489
- * worktree or edges of its own.
11878
+ * inputs and outputs, the model and effort it runs on (a fanned node's from
11879
+ * its item), and its `agent.subagent` children as Claude Code subagents of
11880
+ * its session (the SDK's `agents`, the CLI's `--agents`). A subagent's role
11881
+ * (its agent's instructions), `instructions` and `prompt` are its system
11882
+ * prompt, and its `description` says when the session hands it work with the
11883
+ * Agent tool; it runs inside that session, with no process, worktree or edges
11884
+ * of its own.
11490
11885
  */
11491
11886
  /** The tool a session hands a subagent work with. */
11492
11887
  const AGENT_TOOL = "Agent";
@@ -11515,6 +11910,23 @@ const renderBrief = (text, inputs, outputs, before, item) => {
11515
11910
  warnings
11516
11911
  };
11517
11912
  };
11913
+ /**
11914
+ * The model and effort a session asks for: the node's own, rendered with its
11915
+ * item on a fanned node (`{{item.model}}`), else the workflow's defaults. An
11916
+ * item's value that is no model name or effort level fails it.
11917
+ */
11918
+ const modelOf = (node, defaults, run) => {
11919
+ const scope = runScope(run.inputs, run.outputs ?? {}, void 0, run.item);
11920
+ const model = itemSetting("model", node.model, scope);
11921
+ if (!model.ok) return model;
11922
+ const effort = itemEffort(node.effort, scope);
11923
+ if (!effort.ok) return effort;
11924
+ return {
11925
+ ok: true,
11926
+ model: model.value ?? defaults.model,
11927
+ effort: effort.value ?? defaults.effort
11928
+ };
11929
+ };
11518
11930
  const rendered = (text, inputs, outputs) => {
11519
11931
  const brief = renderBrief(text, inputs, outputs);
11520
11932
  return brief.ok ? brief.text : (text ?? "").trim();
@@ -11522,7 +11934,7 @@ const rendered = (text, inputs, outputs) => {
11522
11934
  /** The subagents of `owner`'s session, by node id, or none. */
11523
11935
  const subagentsOf = (workflow, owner, inputs, outputs = {}) => {
11524
11936
  const entries = Object.entries(workflow.nodes).flatMap(([id, node]) => {
11525
- if (node.type !== "claude.subagent" || node.parent !== owner) return [];
11937
+ if (node.type !== "agent.subagent" || node.parent !== owner) return [];
11526
11938
  if (!isClaudeNode(node)) return [];
11527
11939
  const prompt = [
11528
11940
  node.agent === void 0 ? "" : workflow.agents?.[node.agent]?.instructions?.trim() ?? "",
@@ -11533,7 +11945,7 @@ const subagentsOf = (workflow, owner, inputs, outputs = {}) => {
11533
11945
  description: node.description,
11534
11946
  prompt: prompt === "" ? node.description : prompt
11535
11947
  };
11536
- if (node.model !== void 0) spec.model = node.model;
11948
+ if (node.model !== void 0) spec.model = modelDriver(node.model).model;
11537
11949
  if (node.maxTurns !== void 0) spec.maxTurns = node.maxTurns;
11538
11950
  if (node.tools?.only !== void 0) spec.tools = node.tools.only;
11539
11951
  if (node.tools?.deny !== void 0) spec.disallowedTools = node.tools.deny;
@@ -11541,20 +11953,6 @@ const subagentsOf = (workflow, owner, inputs, outputs = {}) => {
11541
11953
  });
11542
11954
  return entries.length === 0 ? void 0 : Object.fromEntries(entries);
11543
11955
  };
11544
- // ../core/src/run/driver.ts
11545
- /** The node types that start a session of their own, and so need a driver. */
11546
- const SESSION_TYPES$2 = /* @__PURE__ */ new Set(["claude.leader", "claude.worker"]);
11547
- /** The driver a workflow names for a node, if it names one. */
11548
- const namedDriver = (node, workflow) => ("driver" in node ? node.driver : void 0) ?? workflow.defaults?.driver;
11549
- /** The session nodes that name no driver, which take the one ready here. */
11550
- const namingNoDriver = (workflow) => Object.entries(workflow.nodes).filter(([, node]) => SESSION_TYPES$2.has(node.type) && namedDriver(node, workflow) === void 0).map(([id]) => id);
11551
- /**
11552
- * The driver a session runs on: `override` (`--driver`), else what the workflow
11553
- * names, else `ready`, the driver the run found ready when it started (and
11554
- * recorded, for a resume). `undefined` only when none applies, which a run
11555
- * refuses before it starts.
11556
- */
11557
- const sessionDriver = (choice) => choice.override ?? choice.named ?? choice.ready;
11558
11956
  // ../core/src/run/harness.ts
11559
11957
  const CLAIMS_LINE = "- Other nodes may change this project at the same time. Before you edit a file or folder, `claim` it (a path from the project root); if someone holds it, work on something else or ask them. `release` what you are done with; Ork releases the rest when you finish.";
11560
11958
  const HANDOFF = {
@@ -11679,7 +12077,7 @@ const planNodeSession = (workflow, id, options) => {
11679
12077
  ok: false,
11680
12078
  error: `\`${id}\` is a \`${node.type}\`, not a Claude node`
11681
12079
  };
11682
- if (node.type === "claude.subagent") return {
12080
+ if (node.type === "agent.subagent") return {
11683
12081
  ok: false,
11684
12082
  error: `\`${id}\` is a sub-agent; it runs inside \`${node.parent}\`'s session`
11685
12083
  };
@@ -11691,6 +12089,17 @@ const planNodeSession = (workflow, id, options) => {
11691
12089
  ok: false,
11692
12090
  error: `\`${id}\` uses worktree isolation, which a run on its own does not set up; run the whole workflow, or pass \`--in-place\` to run it in this checkout`
11693
12091
  };
12092
+ const models = modelOf(node, defaults, options);
12093
+ if (!models.ok) return {
12094
+ ok: false,
12095
+ error: models.error
12096
+ };
12097
+ const contradiction = driverContradiction(node, models.model);
12098
+ if (contradiction !== void 0) return {
12099
+ ok: false,
12100
+ error: `\`${id}\`: ${contradiction}`
12101
+ };
12102
+ const model = models.model === void 0 ? void 0 : modelDriver(models.model);
11694
12103
  const warnings = [];
11695
12104
  const brief = renderBrief(node.prompt, options.inputs, options.outputs, options.before, options.item);
11696
12105
  if (!brief.ok) return {
@@ -11732,16 +12141,14 @@ const planNodeSession = (workflow, id, options) => {
11732
12141
  permissionMode: "default",
11733
12142
  reportSchema: reportSchemaFor(node)
11734
12143
  };
11735
- if (node.type === "claude.leader") spec.promptCache = "1h";
12144
+ if (node.type === "agent.leader") spec.promptCache = "1h";
11736
12145
  const agents = subagentsOf(workflow, declared, options.inputs, options.outputs);
11737
12146
  if (agents !== void 0) {
11738
12147
  spec.agents = agents;
11739
12148
  spec.tools.only?.push(AGENT_TOOL);
11740
12149
  }
11741
- const model = node.model ?? defaults.model;
11742
- if (model !== void 0) spec.model = model;
11743
- const effort = node.effort ?? defaults.effort;
11744
- if (effort !== void 0) spec.effort = effort;
12150
+ if (model !== void 0) spec.model = model.model;
12151
+ if (models.effort !== void 0) spec.effort = models.effort;
11745
12152
  const maxTurns = node.maxTurns ?? defaults.maxTurns;
11746
12153
  if (maxTurns !== void 0) spec.maxTurns = maxTurns;
11747
12154
  const budgets = [node.budgetUsd ?? defaults.budgetUsd, options.budgetLeftUsd].filter((b) => b !== void 0);
@@ -11754,6 +12161,7 @@ const planNodeSession = (workflow, id, options) => {
11754
12161
  ok: true,
11755
12162
  spec,
11756
12163
  driver: namedDriver(node, workflow),
12164
+ pinned: model?.driver,
11757
12165
  mcp,
11758
12166
  warnings,
11759
12167
  context
@@ -12063,18 +12471,16 @@ const followEvents = async (store, runId, onEvent, options) => {
12063
12471
  seq: options.after ?? 0,
12064
12472
  finished: false
12065
12473
  };
12066
- const done = new AbortController();
12067
12474
  const emit = (stored) => {
12068
12475
  if (stored.seq <= seen.seq) return;
12069
12476
  seen.seq = stored.seq;
12070
12477
  onEvent(stored);
12071
- if (stored.event.type === "run.finished") {
12072
- seen.finished = true;
12073
- done.abort();
12074
- }
12478
+ const { type } = stored.event;
12479
+ if (type === "run.finished") seen.finished = true;
12480
+ else if (type === "run.started" || type === "run.resumed") seen.finished = false;
12075
12481
  };
12076
12482
  const aborted = () => options.signal?.aborted === true;
12077
- /** Takes what the store has; true once `run.finished` is among it. */
12483
+ /** Takes what the store has; true once the run's latest go has finished. */
12078
12484
  const drain = () => {
12079
12485
  for (const stored of store.events(runId, seen.seq)) emit(stored);
12080
12486
  return seen.finished;
@@ -12083,7 +12489,11 @@ const followEvents = async (store, runId, onEvent, options) => {
12083
12489
  if (drain()) return "finished";
12084
12490
  if (!options.follow) return "stored";
12085
12491
  if (aborted()) return "aborted";
12086
- const via = await followSocket(socketPath(runId, options.home), seen.seq, emit, options.signal === void 0 ? done.signal : AbortSignal.any([options.signal, done.signal]));
12492
+ const done = new AbortController();
12493
+ const via = await followSocket(socketPath(runId, options.home), seen.seq, (stored) => {
12494
+ emit(stored);
12495
+ if (seen.finished) done.abort();
12496
+ }, options.signal === void 0 ? done.signal : AbortSignal.any([options.signal, done.signal]));
12087
12497
  if (seen.finished) return "finished";
12088
12498
  if (aborted()) return "aborted";
12089
12499
  if (via === "ended") continue;
@@ -12407,6 +12817,7 @@ const resumeState = (events) => {
12407
12817
  let ended;
12408
12818
  /** Nodes whose last activation did not finish well, and its session. */
12409
12819
  const unfinished = /* @__PURE__ */ new Map();
12820
+ const places = /* @__PURE__ */ new Map();
12410
12821
  /** A new run of `id`'s `round` replaces what is recorded there and after. */
12411
12822
  const supersede = (id, round) => {
12412
12823
  fanOuts.items.get(id)?.delete(round);
@@ -12443,7 +12854,10 @@ const resumeState = (events) => {
12443
12854
  const inner = event.event;
12444
12855
  const current = open.get(event.id);
12445
12856
  if (current === void 0 || inner.fork === true) continue;
12446
- if (inner.type === "session.started") current.sessionId = inner.sessionId;
12857
+ if (inner.type === "session.started") {
12858
+ current.sessionId = inner.sessionId;
12859
+ if (inner.cwd !== void 0) places.set(event.id, inner.cwd);
12860
+ }
12447
12861
  if (inner.type === "session.finished" && inner.outcome.sessionId) current.sessionId = inner.outcome.sessionId;
12448
12862
  continue;
12449
12863
  }
@@ -12536,7 +12950,8 @@ const resumeState = (events) => {
12536
12950
  succeeded,
12537
12951
  cutOff: cut ? unfinished : /* @__PURE__ */ new Map(),
12538
12952
  mail: mailOf(events),
12539
- earlier: earlierSpend(events)
12953
+ earlier: earlierSpend(events),
12954
+ places
12540
12955
  };
12541
12956
  };
12542
12957
  // ../core/src/remote/resume.ts
@@ -13016,7 +13431,7 @@ const requestStop = (store, run, home, node) => request(store, run, withNode("st
13016
13431
  const requestPause = (store, run, home, node) => request(store, run, withNode("pause", node), pauseRefusal(store, run, node), home);
13017
13432
  /** Releases a pause: the run's (and with it every node's), or one node's. */
13018
13433
  const requestContinue = (store, run, home, node) => request(store, run, withNode("continue", node), continueRefusal(store, run, node), home);
13019
- const SESSION_TYPES$1 = /* @__PURE__ */ new Set(["claude.leader", "claude.worker"]);
13434
+ const SESSION_TYPES$1 = /* @__PURE__ */ new Set(["agent.leader", "agent.worker"]);
13020
13435
  const addressOf = ({ run, node }) => `${run}/${node}`;
13021
13436
  /** The other side of `link` from `run`'s `node`, or `undefined` if not on it. */
13022
13437
  const peerOf = (link, run, node) => {
@@ -13398,7 +13813,7 @@ const createCalls = (options) => {
13398
13813
  };
13399
13814
  };
13400
13815
  // ../core/src/run/driver-queues.ts
13401
- const isSession = (node) => node.type === "claude.leader" || node.type === "claude.worker";
13816
+ const isSession = (node) => node.type === "agent.leader" || node.type === "agent.worker";
13402
13817
  const isolationOf = (node, workflow) => ("isolation" in node ? node.isolation : void 0) ?? workflow.defaults?.isolation ?? "worktree";
13403
13818
  /**
13404
13819
  * Where a session works: the node whose worktree it uses, `null` for the
@@ -13470,22 +13885,18 @@ const messageOf$1 = (driver, found) => {
13470
13885
  };
13471
13886
  /**
13472
13887
  * The checkouts where sessions on a one-per-checkout driver could queue: the
13473
- * driver each node takes is as for `driverRefusals` (`override`, else what the
13474
- * workflow names, else `ready`).
13888
+ * driver each node takes is as for `driverRefusals` (its model's prefix, else
13889
+ * `override`, else what the workflow names, else `ready`).
13475
13890
  */
13476
13891
  const driverQueues = (workflow, drivers, choice) => drivers.filter((driver) => driver.onePerCheckout).flatMap((driver) => checkoutContention(workflow, (id) => {
13477
13892
  const node = workflow.nodes[id];
13478
- return node !== void 0 && sessionDriver({
13479
- override: choice.override,
13480
- named: namedDriver(node, workflow),
13481
- ready: choice.ready
13482
- }) === driver.id;
13893
+ return node !== void 0 && nodeDriver(node, workflow, choice) === driver.id;
13483
13894
  }).map((found) => Object.assign({}, found, {
13484
13895
  driver: driver.id,
13485
13896
  message: messageOf$1(driver.id, found)
13486
13897
  })));
13487
13898
  // ../core/src/run/driver-needs.ts
13488
- const SESSION_TYPES = /* @__PURE__ */ new Set(["claude.leader", "claude.worker"]);
13899
+ const SESSION_TYPES = /* @__PURE__ */ new Set(["agent.leader", "agent.worker"]);
13489
13900
  /** The node's turn limit and dollar budget, its own or the workflow's default. */
13490
13901
  const limitsOf = (node, workflow) => {
13491
13902
  const own = isClaudeNode(node) ? node : void 0;
@@ -13499,26 +13910,28 @@ const limitsOf = (node, workflow) => {
13499
13910
  * brings their questions to it).
13500
13911
  */
13501
13912
  const askOfTools = (id, node, workflow) => {
13502
- if (node.type !== "claude.leader") return void 0;
13503
- return Object.values(workflow.nodes).some((child) => child.parent === id && (child.type === "claude.leader" || child.type === "claude.worker")) ? "delegates to the nodes it owns" : void 0;
13913
+ if (node.type !== "agent.leader") return void 0;
13914
+ return Object.values(workflow.nodes).some((child) => child.parent === id && (child.type === "agent.leader" || child.type === "agent.worker")) ? "delegates to the nodes it owns" : void 0;
13504
13915
  };
13505
13916
  /**
13506
- * What stops each session node (or only `only`) from running on its driver:
13507
- * `override` (`--driver`), else what the workflow names, else `ready`. A node
13508
- * with no driver to check is left out; the run refuses that on its own. An
13509
- * owner and a node it owns sharing a checkout on a one-per-checkout driver are
13510
- * refused too: the owner's session holds the checkout while the other waits.
13917
+ * What a session's sub-agents ask of its driver: that it runs subagents at all,
13918
+ * and that a sub-agent's model names no other driver.
13511
13919
  */
13512
- const driverRefusals = (workflow, drivers, choice) => [...Object.entries(workflow.nodes).flatMap(([id, node]) => {
13513
- if (!SESSION_TYPES.has(node.type)) return [];
13514
- if (choice.only !== void 0 && choice.only !== id) return [];
13515
- const driverId = sessionDriver({
13516
- override: choice.override,
13517
- named: namedDriver(node, workflow),
13518
- ready: choice.ready
13519
- });
13520
- const driver = drivers.find((d) => d.id === driverId);
13521
- if (driver === void 0) return [];
13920
+ const subagentRefusals = (id, workflow, driver) => Object.entries(workflow.nodes).flatMap(([child, node]) => {
13921
+ if (node.type !== "agent.subagent" || node.parent !== id) return [];
13922
+ const runs = `sub-agent \`${child}\` runs in \`${id}\`'s session on driver \`${driver.id}\``;
13923
+ const pinned = node.model === void 0 ? void 0 : modelDriver(node.model).driver;
13924
+ return [...driver.capabilities.subagents ? [] : [`${runs}, which does not run subagents`], ...pinned === void 0 || pinned === driver.id ? [] : [`${runs}, but its model \`${node.model ?? ""}\` names driver \`${pinned}\``]].map((message) => ({
13925
+ node: child,
13926
+ message
13927
+ }));
13928
+ });
13929
+ /**
13930
+ * What stops one session node from running on `driver`, its sub-agents
13931
+ * included. A run checks each `forEach` item's this way too, when the model it
13932
+ * rendered names the driver.
13933
+ */
13934
+ const sessionRefusals = (id, node, workflow, driver) => {
13522
13935
  const { maxTurns, budgetUsd } = limitsOf(node, workflow);
13523
13936
  const refuse = (message) => ({
13524
13937
  node: id,
@@ -13532,7 +13945,22 @@ const driverRefusals = (workflow, drivers, choice) => [...Object.entries(workflo
13532
13945
  if ((("mcp" in node ? node.mcp : void 0) ?? workflow.defaults?.mcp ?? []).length > 0 && !driver.capabilities.mcpServers) refusals.push(refuse(`names MCP servers (\`mcp\`), but driver \`${driver.id}\` does not load a node's own MCP servers`));
13533
13946
  const ask = askOfTools(id, node, workflow);
13534
13947
  if (ask !== void 0 && !driver.capabilities.questions) refusals.push(refuse(`${ask}, but driver \`${driver.id}\` does not reach Ork's tools (ask_user, delegate, messages)`));
13535
- return refusals;
13948
+ return [...refusals, ...subagentRefusals(id, workflow, driver)];
13949
+ };
13950
+ /**
13951
+ * What stops each session node (or only `only`) from running on its driver: its
13952
+ * model's prefix, else `override` (`--driver`), else what the workflow names,
13953
+ * else `ready`. A node with no driver to check is left out; the run refuses
13954
+ * that on its own. An owner and a node it owns sharing a checkout on a
13955
+ * one-per-checkout driver are refused too: the owner's session holds the
13956
+ * checkout while the other waits.
13957
+ */
13958
+ const driverRefusals = (workflow, drivers, choice) => [...Object.entries(workflow.nodes).flatMap(([id, node]) => {
13959
+ if (!SESSION_TYPES.has(node.type)) return [];
13960
+ if (choice.only !== void 0 && choice.only !== id) return [];
13961
+ const driverId = nodeDriver(node, workflow, choice);
13962
+ const driver = drivers.find((d) => d.id === driverId);
13963
+ return driver === void 0 ? [] : sessionRefusals(id, node, workflow, driver);
13536
13964
  }), ...driverQueues(workflow, drivers, choice).flatMap(({ owner, nodes, message }) => owner === void 0 || choice.only !== void 0 && !nodes.includes(choice.only) ? [] : [{
13537
13965
  node: owner,
13538
13966
  message
@@ -13625,95 +14053,6 @@ const draftQueries = (db) => {
13625
14053
  }
13626
14054
  };
13627
14055
  };
13628
- // ../core/src/worktree/git-env.ts
13629
- /**
13630
- * @file Git's local environment variables, the ones a git hook sets (`GIT_DIR`,
13631
- * `GIT_INDEX_FILE`, …), and an environment without them. Ork finds a project
13632
- * by its path, never through these, so an `ork` started from a hook clears
13633
- * them at its entry, and core's git runner leaves them out for callers that
13634
- * don't start there (specs/worktrees.md).
13635
- */
13636
- /**
13637
- * What `git rev-parse --local-env-vars` prints (git 2.39.5). A fixed list, so
13638
- * no git is spawned at every start; a test fails when the installed git names
13639
- * one that is missing here.
13640
- */
13641
- const GIT_LOCAL_ENV = [
13642
- "GIT_ALTERNATE_OBJECT_DIRECTORIES",
13643
- "GIT_CONFIG",
13644
- "GIT_CONFIG_PARAMETERS",
13645
- "GIT_CONFIG_COUNT",
13646
- "GIT_OBJECT_DIRECTORY",
13647
- "GIT_DIR",
13648
- "GIT_WORK_TREE",
13649
- "GIT_IMPLICIT_WORK_TREE",
13650
- "GIT_GRAFT_FILE",
13651
- "GIT_INDEX_FILE",
13652
- "GIT_NO_REPLACE_OBJECTS",
13653
- "GIT_REPLACE_REF_BASE",
13654
- "GIT_PREFIX",
13655
- "GIT_INTERNAL_SUPER_PREFIX",
13656
- "GIT_SHALLOW_FILE",
13657
- "GIT_COMMON_DIR"
13658
- ];
13659
- /** A copy of `env` without git's local variables. */
13660
- const withoutGitLocalEnv = (env) => {
13661
- const clean = { ...env };
13662
- for (const name of GIT_LOCAL_ENV) delete clean[name];
13663
- return clean;
13664
- };
13665
- /** Removes git's local variables from `env` in place (the CLI's entry). */
13666
- const clearGitLocalEnv = (env = process.env) => {
13667
- for (const name of GIT_LOCAL_ENV) delete env[name];
13668
- };
13669
- // ../core/src/worktree/git.ts
13670
- /**
13671
- * @file A minimal `git` runner for the worktree manager: arguments without a
13672
- * shell, results that never throw, and none of git's local variables (a
13673
- * hook's `GIT_DIR` or `GIT_INDEX_FILE`), so it acts on the repository at
13674
- * `cwd` (specs/worktrees.md). Commands in one folder run one at a time: two
13675
- * children handed their owner's work at once both stage it (`git add -A`),
13676
- * and git refuses the second while the first holds the index's lock.
13677
- */
13678
- /** The last command queued in each folder, so the next one waits for it. */
13679
- const queues = /* @__PURE__ */ new Map();
13680
- /** Runs `task` after every command queued earlier in the same folder. */
13681
- const inTurn = (cwd, task) => {
13682
- const key = path.resolve(cwd);
13683
- const next = (queues.get(key) ?? Promise.resolve()).then(task, task);
13684
- queues.set(key, next);
13685
- next.finally(() => {
13686
- if (queues.get(key) === next) queues.delete(key);
13687
- });
13688
- return next;
13689
- };
13690
- const runGit = (cwd, args) => new Promise((resolve) => {
13691
- execFile("git", args, {
13692
- cwd,
13693
- env: withoutGitLocalEnv(process.env),
13694
- maxBuffer: 33554432,
13695
- encoding: "utf8"
13696
- }, (error, stdout, stderr) => {
13697
- resolve({
13698
- code: error === null ? 0 : typeof error.code === "number" ? error.code : -1,
13699
- stdout,
13700
- stderr: error !== null && !existsSync(cwd) ? `the folder ${cwd} doesn't exist` : stderr || (error?.message ?? "")
13701
- });
13702
- });
13703
- });
13704
- /** Runs `git` with arguments (no shell) in `cwd`. Never throws. */
13705
- const git = (cwd, args) => inTurn(cwd, () => runGit(cwd, args));
13706
- /** Like `git`, but rejects with git's message when the command fails. */
13707
- const gitOk = async (cwd, args) => {
13708
- const result = await git(cwd, args);
13709
- if (result.code !== 0) {
13710
- const reason = result.stderr.trim().split("\n").at(-1) ?? "";
13711
- throw new Error(`git ${args[0] ?? ""} failed: ${reason}`);
13712
- }
13713
- return result.stdout;
13714
- };
13715
- /** Output lines without the trailing empty one. */
13716
- const lines = (text) => text.split("\n").filter((line) => line !== "");
13717
14056
  // ../core/src/worktree/manager.ts
13718
14057
  /**
13719
14058
  * @file Ork's git worktrees: one per `worktree` node, beside the clone, by
@@ -15808,6 +16147,36 @@ const syncFrom = async (worktree, from) => {
15808
16147
  if (!applied.ok) throw new Error(`could not take ${from}'s changes: ${applied.error}`);
15809
16148
  return snapshot(worktree);
15810
16149
  };
16150
+ // ../core/src/worktree/resumed.ts
16151
+ /**
16152
+ * @file What a resumed run's workspace starts from: the worktrees the run left
16153
+ * whose folders are still there, and where each replayed node worked. A
16154
+ * replayed node is never prepared again, so without this a `continue` or
16155
+ * `readonly` node after it would not find the worktree its input came from.
16156
+ */
16157
+ /**
16158
+ * Adopts the worktrees still there, and records where replayed nodes worked: an
16159
+ * adopted worktree's own node there, and a node without one (a `readonly`
16160
+ * reviewer, a fanned item) where its last session ran, when that is one of
16161
+ * them.
16162
+ */
16163
+ const seedResumed = (adopt, places, into) => {
16164
+ for (const left of adopt) {
16165
+ if (!existsSync(left.path)) continue;
16166
+ const { id, merged: wasMerged, ...worktree } = left;
16167
+ into.worktrees.set(id, worktree);
16168
+ into.placeOf.set(id, worktree.path);
16169
+ if (wasMerged) into.merged.add(id);
16170
+ }
16171
+ const adopted = new Set([...into.worktrees.values()].map((w) => w.path));
16172
+ for (const [id, place] of places) if (!into.placeOf.has(id) && adopted.has(place)) into.placeOf.set(id, place);
16173
+ };
16174
+ /** The workspace options for a resumed run; none for a new one. */
16175
+ const resumedOptions = (resume) => resume === void 0 ? {} : {
16176
+ adopt: resume.worktrees,
16177
+ places: resume.places,
16178
+ known: resume.branches
16179
+ };
15811
16180
  // ../core/src/worktree/upstream.ts
15812
16181
  /** Where `id` worked: its own place, or for a fanned node each item's. */
15813
16182
  const placesOf = (id, placeOf) => {
@@ -16084,13 +16453,11 @@ const createWorkspace = (options) => {
16084
16453
  const templateOf = /* @__PURE__ */ new Map();
16085
16454
  /** A `continue` node → the node whose worktree it works in this time. */
16086
16455
  const continued = /* @__PURE__ */ new Map();
16087
- for (const left of options.adopt ?? []) {
16088
- if (!existsSync(left.path)) continue;
16089
- const { id, merged: wasMerged, ...worktree } = left;
16090
- worktrees.set(id, worktree);
16091
- placeOf.set(id, worktree.path);
16092
- if (wasMerged) merged.add(id);
16093
- }
16456
+ seedResumed(options.adopt ?? [], options.places ?? /* @__PURE__ */ new Map(), {
16457
+ worktrees,
16458
+ placeOf,
16459
+ merged
16460
+ });
16094
16461
  const nodeOf = (id) => graph.nodes.get(templateOf.get(id) ?? id)?.node;
16095
16462
  const ownerOf = (id) => nodeOf(id)?.parent;
16096
16463
  const isolationOf = (id) => {
@@ -16252,4 +16619,4 @@ const createWorkspace = (options) => {
16252
16619
  close
16253
16620
  };
16254
16621
  };
16255
- export { DETACHED_ENV as $, skillsIn as $n, endOf as $t, lines as A, linkTools as An, AGENT_DRIVERS as Ar, nestItems as At, linkNodes as B, placeFiles as Bn, lowerChild as Bt, openStore as C, wakeRun as Cn, TOOL_PREFIX as Cr, runStatus as Ct, removeWorktree as D, planAgentMigration as Dn, readyDriver as Dr, processAlive as Dt, inspectProject as E, maskSecrets as En, driverChecks as Er, templateOf as Et, driverQueues as F, catalogAgent as Fn, knownExperiments as Fr, failedWith as Ft, requestContinue as G, workflowDirOf as Gn, PROJECT_FILE as Gt, tellNode as H, projectsHome as Hn, envReadsOf as Ht, createCalls as I, loadAgents as In, stoppedEnd as It, tellLiveRun as J, LESSON_CAP_TOKENS as Jn, machineRulesOf as Jt, requestPause as K, inside as Kn, gitRulesOf as Kt, addressOf as L, hasInRepoFiles as Ln, calledWorkflows as Lt, parseInputPairs as M, toolsInUse as Mn, firstLine as Mr, runScope as Mt, resolveInputs as N, createAgent as Nn, EXPERIMENTS as Nr, declaredProblem as Nt, git as O, applySteps as On, AGENT_TOOL_LAYOUTS as Or, stillTheSameProcess as Ot, driverRefusals as P, deleteAgent as Pn, experimentsOn as Pr, endedWith as Pt, listKey as Q, writePlainFile as Qn, createSignals as Qt, endLink as R, inRepoPlace as Rn, slotClock as Rt, isNodeEvent as S, socketRoom as Sn, INTEGRATIONS as Sr, pausedOf as St, BRANCH_PREFIX as T, maskReplacer as Tn, PREFERRED_DRIVER as Tr, slotWaitsOf as Tt, unlinkNodes as U, runDirOf as Un, nodeSays as Ut, peerOf as V, placeFor as Vn, startAt as Vt, flattenTree as W, shownPath as Wn, declaredOutputOf as Wt, detachResume as X, guardedBase as Xn, mcpNotText as Xt, adoptedCalls as Y, estimateTokens as Yn, MCP_FILE as Yt, resumable as Z, plainPathInside as Zn, serversIn as Zt, readProjectTriggers as _, parseTemplate as _n, isToolNode as _r, startRun as _t, releaseNotes as a, FEEDBACK_SEVERITIES as an, programsRunBy as ar, planReason as at, watchingPid as b, serveRun as bn, retiredDriverHint as br, heldTimeout as bt, detectInstaller as c, planPost as cn, serializeWorkflow as cr, explainSession as ct, parseVersion as d, publishPost as dn, WorkflowSchema as dr, sessionDriver as dt, outcomeEnd as en, WorkflowEditSchema as er, detachRun as et, lateTriggers as f, createFeedback as fn, CheckReportSchema as fr, parseReport as ft, declaredTriggers as g, evaluate as gn, isClaudeNode as gr, walkSummary as gt, triggerStanding as h, targetOf as hn, NodeSchema as hr, walkChecks as ht, planUpgrade as i, FEEDBACK_KINDS as in, beforeOf as ir, limitsReport as it, clearGitLocalEnv as j, toolLinks as jn, DRIVER_IDS as jr, scriptContactsOf as jt, gitOk as k, planMoveInto as kn, ORK_LAYOUT as kr, isItem as kt, compareVersions as l, runGh as ln, markValue as lr, planNodeSession as lt, createWatcher as m, normalizeTitle as mn, settingsOf as mr, checkWorkflowText as mt, resolveBase as n, END_KINDS as nn, newWorkflowText as nr, NOT_STARTED as nt, runningRunIds as o, FEEDBACK_TARGETS as on, renderJsonSchema as or, usd as ot, triggersReport as p, fingerprint as pn, expandEdge as pr, reportSchemaFor as pt, requestStop as q, projectRootOf as qn, loadProject as qt, capsHere as r, endFor as rn, readDocument as rr, limitsNow as rt, runningScript as s, DISCUSSIONS as sn, parseWorkflow as sr, explainWorkflowText as st, createWorkspace as t, END_DETAIL_LIMIT as tn, applyEdits as tr, followEvents as tt, isNewer as u, sendPost as un, EdgeInputSchema as ur, namingNoDriver as ut, workflowTextHash as v, renderTemplate as vn, DriverSchema as vr, MESSAGE_LIMIT as vt, storePath as w, MASK as wn, integrationFor as wr, runTree as wt, activeTree as x, socketPath as xn, timeoutMs as xr, liveStatus as xt, takeWatchLock as y, readCondition as yn, NodeIdSchema as yr, userMessageText as yt, endLinksOf as z, newProjectId as zn, slotWaitLine as zt };
16622
+ export { followEvents as $, plainPathInside as $n, serversIn as $t, resolveInputs as A, applySteps as An, readyDriver as Ar, endedWith as At, tellNode as B, inRepoPlace as Bn, lines as Bt, isNodeEvent as C, socketPath as Cn, retiredDriverHint as Cr, processAlive as Ct, inspectProject as D, maskReplacer as Dn, integrationFor as Dr, scriptContactsOf as Dt, BRANCH_PREFIX as E, MASK as En, TOOL_PREFIX as Er, nestItems as Et, addressOf as F, createAgent as Fn, firstLine as Fr, slotWaitLine as Ft, requestStop as G, runDirOf as Gn, nodeSays as Gt, flattenTree as H, placeFiles as Hn, envReadsOf as Ht, endLink as I, deleteAgent as In, EXPERIMENTS as Ir, lowerChild as It, detachResume as J, inside as Jn, gitRulesOf as Jt, tellLiveRun as K, shownPath as Kn, declaredOutputOf as Kt, endLinksOf as L, catalogAgent as Ln, experimentsOn as Lr, startAt as Lt, sessionRefusals as M, linkTools as Mn, ORK_LAYOUT as Mr, stoppedEnd as Mt, driverQueues as N, toolLinks as Nn, AGENT_DRIVERS as Nr, calledWorkflows as Nt, removeWorktree as O, maskSecrets as On, PREFERRED_DRIVER as Or, runScope as Ot, createCalls as P, toolsInUse as Pn, DRIVER_IDS as Pr, slotClock as Pt, detachRun as Q, guardedBase as Qn, mcpNotText as Qt, linkNodes as R, loadAgents as Rn, knownExperiments as Rr, git as Rt, activeTree as S, serveRun as Sn, NodeIdSchema as Sr, templateOf as St, storePath as T, wakeRun as Tn, INTEGRATIONS as Tr, isItem as Tt, requestContinue as U, placeFor as Un, namingNoDriver as Ut, unlinkNodes as V, newProjectId as Vn, clearGitLocalEnv as Vt, requestPause as W, projectsHome as Wn, sessionDriver as Wt, listKey as X, LESSON_CAP_TOKENS as Xn, machineRulesOf as Xt, resumable as Y, projectRootOf as Yn, loadProject as Yt, DETACHED_ENV as Z, estimateTokens as Zn, MCP_FILE as Zt, declaredTriggers as _, targetOf as _n, settingsOf as _r, liveStatus as _t, planUpgrade as a, endFor as an, readDocument as ar, explainWorkflowText as at, takeWatchLock as b, renderTemplate as bn, isToolNode as br, runTree as bt, runningScript as c, FEEDBACK_TARGETS as cn, programsRunBy as cr, parseReport as ct, isNewer as d, runGh as dn, serializeWorkflow as dr, walkChecks as dt, createSignals as en, writePlainFile as er, NOT_STARTED as et, parseVersion as f, sendPost as fn, markValue as fr, walkSummary as ft, triggerStanding as g, normalizeTitle as gn, expandEdge as gr, heldTimeout as gt, createWatcher as h, fingerprint as hn, CheckReportSchema as hr, userMessageText as ht, capsHere as i, END_KINDS as in, newWorkflowText as ir, usd as it, driverRefusals as j, planMoveInto as jn, AGENT_TOOL_LAYOUTS as jr, failedWith as jt, parseInputPairs as k, planAgentMigration as kn, driverChecks as kr, declaredProblem as kt, detectInstaller as l, DISCUSSIONS as ln, renderJsonSchema as lr, reportSchemaFor as lt, triggersReport as m, createFeedback as mn, WorkflowSchema as mr, MESSAGE_LIMIT as mt, resumedOptions as n, outcomeEnd as nn, WorkflowEditSchema as nr, limitsReport as nt, releaseNotes as o, FEEDBACK_KINDS as on, renameNodeTypes as or, explainSession as ot, lateTriggers as p, publishPost as pn, EdgeInputSchema as pr, startRun as pt, adoptedCalls as q, workflowDirOf as qn, PROJECT_FILE as qt, resolveBase as r, END_DETAIL_LIMIT as rn, applyEdits as rr, planReason as rt, runningRunIds as s, FEEDBACK_SEVERITIES as sn, beforeOf as sr, planNodeSession as st, createWorkspace as t, endOf as tn, skillsIn as tr, limitsNow as tt, compareVersions as u, planPost as un, parseWorkflow as ur, checkWorkflowText as ut, readProjectTriggers as v, evaluate as vn, NodeSchema as vr, pausedOf as vt, openStore as w, socketRoom as wn, timeoutMs as wr, stillTheSameProcess as wt, watchingPid as x, readCondition as xn, DriverSchema as xr, slotWaitsOf as xt, workflowTextHash as y, parseTemplate as yn, isClaudeNode as yr, runStatus as yt, peerOf as z, hasInRepoFiles as zn, gitOk as zt };