@ordewell/core 0.5.5 → 0.6.0

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 (54) hide show
  1. package/dist/IFileSystem-CFYf4yR2.d.mts +76 -0
  2. package/dist/IFileSystem-D4dAl2r8.d.ts +76 -0
  3. package/dist/{ModeResolver-D-SUFRNF.d.mts → ModeResolver-DVYVRbJp.d.ts} +6 -2
  4. package/dist/{ModeResolver-D3XO0fT9.d.ts → ModeResolver-a4xJFlEp.d.mts} +6 -2
  5. package/dist/Task-CZJr6rmz.d.mts +2121 -0
  6. package/dist/Task-CZJr6rmz.d.ts +2121 -0
  7. package/dist/{chunk-KLN7ELXO.mjs → chunk-2SOVKO7P.mjs} +1561 -1269
  8. package/dist/chunk-2SOVKO7P.mjs.map +1 -0
  9. package/dist/{chunk-T2S5O36I.mjs → chunk-C44UWIAD.mjs} +6 -6
  10. package/dist/chunk-C44UWIAD.mjs.map +1 -0
  11. package/dist/{chunk-HD2FWPRV.mjs → chunk-EDGUFCIR.mjs} +6 -1
  12. package/dist/chunk-EDGUFCIR.mjs.map +1 -0
  13. package/dist/{chunk-UUBGVCGJ.mjs → chunk-OM4D274O.mjs} +20 -2
  14. package/dist/chunk-OM4D274O.mjs.map +1 -0
  15. package/dist/index.d.mts +1594 -803
  16. package/dist/index.d.ts +1594 -803
  17. package/dist/index.js +9540 -6040
  18. package/dist/index.js.map +1 -1
  19. package/dist/index.mjs +8167 -4996
  20. package/dist/index.mjs.map +1 -1
  21. package/dist/order-labels.d.mts +3 -1
  22. package/dist/order-labels.d.ts +3 -1
  23. package/dist/{parsing-BTP4bwkk.d.ts → parsing-Bd6-b644.d.ts} +2 -2
  24. package/dist/{parsing-CDtRSxBY.d.mts → parsing-DIaGZmiQ.d.mts} +2 -2
  25. package/dist/parsing.d.mts +5 -3
  26. package/dist/parsing.d.ts +5 -3
  27. package/dist/parsing.js.map +1 -1
  28. package/dist/parsing.mjs +2 -2
  29. package/dist/{plan-utils-pE4TBwxl.d.mts → plan-utils-Ba-l8EZS.d.mts} +212 -43
  30. package/dist/{plan-utils-BFaPo-IT.d.ts → plan-utils-_T5S7Mnk.d.ts} +212 -43
  31. package/dist/plan-utils.d.mts +5 -4
  32. package/dist/plan-utils.d.ts +5 -4
  33. package/dist/plan-utils.js +352 -64
  34. package/dist/plan-utils.js.map +1 -1
  35. package/dist/plan-utils.mjs +11 -5
  36. package/dist/testing.d.mts +54 -4
  37. package/dist/testing.d.ts +54 -4
  38. package/dist/testing.js +93 -2
  39. package/dist/testing.js.map +1 -1
  40. package/dist/testing.mjs +91 -2
  41. package/dist/testing.mjs.map +1 -1
  42. package/package.json +2 -1
  43. package/skills/grilling/SKILL.md +6 -16
  44. package/skills/improve-codebase-architecture/SKILL.md +1 -1
  45. package/dist/ApprovalPolicy-BVhGdECT.d.mts +0 -79
  46. package/dist/ApprovalPolicy-BVhGdECT.d.ts +0 -79
  47. package/dist/ITerminalRunner-BV9Rd2o9.d.ts +0 -563
  48. package/dist/ITerminalRunner-C77ZNZS9.d.mts +0 -563
  49. package/dist/Task-Vl5Zq_D-.d.mts +0 -825
  50. package/dist/Task-Vl5Zq_D-.d.ts +0 -825
  51. package/dist/chunk-HD2FWPRV.mjs.map +0 -1
  52. package/dist/chunk-KLN7ELXO.mjs.map +0 -1
  53. package/dist/chunk-T2S5O36I.mjs.map +0 -1
  54. package/dist/chunk-UUBGVCGJ.mjs.map +0 -1
@@ -23,6 +23,7 @@ __export(plan_utils_exports, {
23
23
  CHECKPOINT_TRUNCATE_LENGTH: () => CHECKPOINT_TRUNCATE_LENGTH,
24
24
  EMPTY_CONVERSATION: () => EMPTY_CONVERSATION,
25
25
  EMPTY_HOLD: () => EMPTY_HOLD,
26
+ EMPTY_TASK_LOG: () => EMPTY_TASK_LOG,
26
27
  NO_TURN: () => NO_TURN,
27
28
  aheadOfDraft: () => aheadOfDraft,
28
29
  canMergeTasks: () => canMergeTasks,
@@ -39,6 +40,9 @@ __export(plan_utils_exports, {
39
40
  outputLines: () => outputLines,
40
41
  outputPreview: () => outputPreview,
41
42
  reduceConversation: () => reduceConversation,
43
+ reduceTaskLog: () => reduceTaskLog,
44
+ replayTaskLog: () => replayTaskLog,
45
+ runnerToolSubject: () => runnerToolSubject,
42
46
  stopTurn: () => stopTurn,
43
47
  summarizeToolCall: () => summarizeToolCall,
44
48
  taskStartedNotice: () => taskStartedNotice,
@@ -190,12 +194,35 @@ function truncateCheckpointSummary(summary) {
190
194
  return firstLine.slice(0, CHECKPOINT_TRUNCATE_LENGTH - 1) + "\u2026";
191
195
  }
192
196
 
193
- // src/services/isolationRecord.ts
197
+ // src/services/conflictFiles.ts
194
198
  function capConflictFiles(files, max = 5) {
195
199
  return files.length <= max ? files.join(", ") : `${files.slice(0, max).join(", ")}, +${files.length - max} more`;
196
200
  }
197
201
 
198
202
  // src/models/Usage.ts
203
+ var TOKEN_FIELDS = ["inputTokens", "outputTokens", "cachedInputTokens"];
204
+ function addUsage(totals, record) {
205
+ const next = { ...totals };
206
+ for (const field of TOKEN_FIELDS) {
207
+ const reported = record[field];
208
+ if (reported !== void 0) next[field] = (totals[field] ?? 0) + reported;
209
+ }
210
+ if (record.reportedCost) {
211
+ const { amount, currency } = record.reportedCost;
212
+ next.reportedCost = { ...totals.reportedCost, [currency]: (totals.reportedCost?.[currency] ?? 0) + amount };
213
+ }
214
+ return next;
215
+ }
216
+ function addPlannerUsage(usage, record) {
217
+ const next = { ...usage, totals: addUsage(usage.totals, record) };
218
+ if (record.subagentId) {
219
+ next.bySubagent = { ...usage.bySubagent, [record.subagentId]: addUsage(usage.bySubagent?.[record.subagentId] ?? {}, record) };
220
+ return next;
221
+ }
222
+ if (record.inputTokens !== void 0) next.lastPromptTokens = record.inputTokens;
223
+ if (record.contextWindow !== void 0 && record.contextWindow > 0) next.contextWindow = record.contextWindow;
224
+ return next;
225
+ }
199
226
  function isMeasured(totals) {
200
227
  return totals.inputTokens !== void 0 || totals.outputTokens !== void 0 || totals.cachedInputTokens !== void 0 || Object.keys(totals.reportedCost ?? {}).length > 0;
201
228
  }
@@ -325,8 +352,11 @@ var STATUS_OF_OUTCOME = {
325
352
  denied: "denied",
326
353
  not_executed: "interrupted"
327
354
  };
355
+ function finishedTool(call, output, outcome) {
356
+ return { ...call, status: STATUS_OF_OUTCOME[outcome], outcome, output, outputLineCount: outputLines(output).length };
357
+ }
328
358
  function settledTool(call, step) {
329
- return { ...call, status: STATUS_OF_OUTCOME[step.outcome], outcome: step.outcome, output: step.result, outputLineCount: outputLines(step.result).length };
359
+ return finishedTool(call, step.result, step.outcome);
330
360
  }
331
361
  function pendingTool(id, { tool, toolLabel, args, toolCallId, turnId }) {
332
362
  return {
@@ -351,8 +381,7 @@ function planMarker(content) {
351
381
  return { status: content.startsWith("Plan updated") ? "updated" : "generated", ...count ? { taskCount: Number(count[1]) } : {} };
352
382
  }
353
383
 
354
- // src/conversation/reduce.ts
355
- var EMPTY_CONVERSATION = { blocks: [], nextId: 1 };
384
+ // src/conversation/lanes.ts
356
385
  function findLastIndex(items, match) {
357
386
  for (let i = items.length - 1; i >= 0; i--) if (match(items[i])) return i;
358
387
  return -1;
@@ -405,6 +434,72 @@ function appendOutput(view, lane, make) {
405
434
  const next = laneAppend(view, lane, make);
406
435
  return sealLane(next, lane, findLastIndex(laneBlocks(next, lane), (b) => b.type !== "usage"));
407
436
  }
437
+ function subagentLane(view, subagentId, turnId) {
438
+ const existing = findLastIndex(view.blocks, (b) => b.type === "subagent" && b.subagentId === subagentId);
439
+ if (existing >= 0) return [view, existing];
440
+ const spawn = findLastIndex(view.blocks, (b) => b.type === "tool" && (b.spawns === subagentId || b.toolCallId === subagentId));
441
+ const call = view.blocks[spawn];
442
+ if (call?.type === "tool") {
443
+ const block = subagentBlock(call.id, {
444
+ subagentId,
445
+ brief: call.headline.keyArg,
446
+ status: "running",
447
+ children: [],
448
+ digest: "",
449
+ toolCallId: call.toolCallId,
450
+ turnId: call.turnId
451
+ });
452
+ return [{ ...view, blocks: replaceAt(view.blocks, spawn, block) }, spawn];
453
+ }
454
+ const next = append(view, (id) => subagentBlock(id, { subagentId, brief: "", status: "running", children: [], digest: "", turnId }));
455
+ return [next, findLastIndex(next.blocks, (b) => b.type === "subagent" && b.subagentId === subagentId)];
456
+ }
457
+ function updateSubagent(view, subagentId, turnId, update) {
458
+ const [next, lane] = subagentLane(view, subagentId, turnId);
459
+ return { ...next, blocks: replaceAt(next.blocks, lane, update(subagentAt(next, lane))) };
460
+ }
461
+ function laneOf(view, subagentId, turnId) {
462
+ return subagentId ? subagentLane(view, subagentId, turnId) : [view, null];
463
+ }
464
+ function think(view, text2, turnId, segmentId, subagentId) {
465
+ const [placed, lane] = laneOf(view, subagentId, turnId);
466
+ const blocks = laneBlocks(placed, lane);
467
+ const lastIndex = findLastIndex(blocks, (b) => b.type !== "usage");
468
+ const last = blocks[lastIndex];
469
+ if (last?.type === "thinking" && last.streaming && last.segmentId === segmentId) {
470
+ return laneReplace(placed, lane, lastIndex, { ...last, text: last.text + text2 });
471
+ }
472
+ return appendOutput(placed, lane, (id) => ({
473
+ type: "thinking",
474
+ id,
475
+ text: text2,
476
+ streaming: true,
477
+ ...turnId ? { turnId } : {},
478
+ ...segmentId ? { segmentId } : {},
479
+ ...subagentId ? { subagentId } : {}
480
+ }));
481
+ }
482
+ function setUsageLine(view, line) {
483
+ const last = view.blocks[view.blocks.length - 1];
484
+ const block = usageBlock(last?.type === "usage" ? last.id : `b${view.nextId}`, line);
485
+ if (last?.type === "usage") return { ...view, blocks: replaceAt(view.blocks, view.blocks.length - 1, block) };
486
+ return { ...view, blocks: [...view.blocks, block], nextId: view.nextId + 1 };
487
+ }
488
+ function closeBlock(block, interrupted) {
489
+ return interrupted && block.type === "tool" && block.status === "pending" ? { ...block, status: "interrupted" } : sealed(block);
490
+ }
491
+ function closeSubagent(block, cut) {
492
+ const children = block.children.map((c) => closeBlock(c, cut !== null));
493
+ const status = cut && block.status === "running" ? cut : block.status;
494
+ return status === block.status && children.every((c, i) => c === block.children[i]) ? block : { ...block, status, children };
495
+ }
496
+ function closeOpenBlocks(view, cut) {
497
+ const blocks = view.blocks.map((b) => b.type === "subagent" ? closeSubagent(b, cut) : closeBlock(b, cut !== null));
498
+ return blocks.every((b, i) => b === view.blocks[i]) ? view : { ...view, blocks };
499
+ }
500
+
501
+ // src/conversation/reduce.ts
502
+ var EMPTY_CONVERSATION = { blocks: [], nextId: 1 };
408
503
  function isUnsettledSegment(block, turnId) {
409
504
  return block.type === "message" && block.turnId === turnId && block.segmentId !== void 0;
410
505
  }
@@ -453,30 +548,6 @@ function retractText(view, { turnId, segmentId }) {
453
548
  const blocks = view.blocks.filter((b) => !(isUnsettledSegment(b, turnId) && (segmentId === void 0 || b.segmentId === segmentId)));
454
549
  return dropBuildingPlan(blocks.length === view.blocks.length ? view : { ...view, blocks }, turnId, segmentId);
455
550
  }
456
- function subagentLane(view, subagentId, turnId) {
457
- const existing = findLastIndex(view.blocks, (b) => b.type === "subagent" && b.subagentId === subagentId);
458
- if (existing >= 0) return [view, existing];
459
- const spawn = findLastIndex(view.blocks, (b) => b.type === "tool" && (b.spawns === subagentId || b.toolCallId === subagentId));
460
- const call = view.blocks[spawn];
461
- if (call?.type === "tool") {
462
- const block = subagentBlock(call.id, {
463
- subagentId,
464
- brief: call.headline.keyArg,
465
- status: "running",
466
- children: [],
467
- digest: "",
468
- toolCallId: call.toolCallId,
469
- turnId: call.turnId
470
- });
471
- return [{ ...view, blocks: replaceAt(view.blocks, spawn, block) }, spawn];
472
- }
473
- const next = append(view, (id) => subagentBlock(id, { subagentId, brief: "", status: "running", children: [], digest: "", turnId }));
474
- return [next, findLastIndex(next.blocks, (b) => b.type === "subagent" && b.subagentId === subagentId)];
475
- }
476
- function updateSubagent(view, subagentId, turnId, update) {
477
- const [next, lane] = subagentLane(view, subagentId, turnId);
478
- return { ...next, blocks: replaceAt(next.blocks, lane, update(subagentAt(next, lane))) };
479
- }
480
551
  function startSubagent(view, { subagentId, brief, model, turnId }) {
481
552
  return updateSubagent(view, subagentId, turnId, (block) => ({ ...block, ...brief ? { brief } : {}, ...model ? { model } : {} }));
482
553
  }
@@ -489,27 +560,9 @@ function finishSubagent(view, { subagentId, outcome, digest, usage, turnId }) {
489
560
  ...usage ? { usage } : {}
490
561
  }));
491
562
  }
492
- function think(view, text2, turnId, segmentId, subagentId) {
493
- const [placed, lane] = subagentId ? subagentLane(view, subagentId, turnId) : [view, null];
494
- const blocks = laneBlocks(placed, lane);
495
- const lastIndex = findLastIndex(blocks, (b) => b.type !== "usage");
496
- const last = blocks[lastIndex];
497
- if (last?.type === "thinking" && last.streaming && last.segmentId === segmentId) {
498
- return laneReplace(placed, lane, lastIndex, { ...last, text: last.text + text2 });
499
- }
500
- return appendOutput(placed, lane, (id) => ({
501
- type: "thinking",
502
- id,
503
- text: text2,
504
- streaming: true,
505
- ...turnId ? { turnId } : {},
506
- ...segmentId ? { segmentId } : {},
507
- ...subagentId ? { subagentId } : {}
508
- }));
509
- }
510
563
  function announceTool(view, call) {
511
564
  const spawns = call.tool === "spawn_research_agent" ? call.subagentId : void 0;
512
- const [placed, lane] = call.subagentId && !spawns ? subagentLane(view, call.subagentId, call.turnId) : [view, null];
565
+ const [placed, lane] = laneOf(view, spawns ? void 0 : call.subagentId, call.turnId);
513
566
  return appendOutput(placed, lane, (id) => ({ ...pendingTool(id, call), ...spawns ? { spawns } : {} }));
514
567
  }
515
568
  function isPendingCallOf(block, step) {
@@ -517,7 +570,7 @@ function isPendingCallOf(block, step) {
517
570
  return step.toolCallId ? block.toolCallId === step.toolCallId : block.toolCallId === void 0 && block.tool === step.tool;
518
571
  }
519
572
  function settleTool(view, { step, turnId }) {
520
- const [placed, lane] = step.subagentId ? subagentLane(view, step.subagentId, turnId) : [view, null];
573
+ const [placed, lane] = laneOf(view, step.subagentId, turnId);
521
574
  const blocks = laneBlocks(placed, lane);
522
575
  const i = findLastIndex(blocks, (b) => isPendingCallOf(b, step));
523
576
  const pending = blocks[i];
@@ -582,27 +635,13 @@ function decideApproval(view, { kind, subject, scope, detail, granted, source })
582
635
  }));
583
636
  }
584
637
  function reportUsage(view, message) {
585
- if (!isMeasured(message.totals)) return view;
586
- const last = view.blocks[view.blocks.length - 1];
587
- const line = usageBlock(last?.type === "usage" ? last.id : `b${view.nextId}`, message);
588
- if (last?.type === "usage") return { ...view, blocks: replaceAt(view.blocks, view.blocks.length - 1, line) };
589
- return { ...view, blocks: [...view.blocks, line], nextId: view.nextId + 1 };
590
- }
591
- function closeBlock(block, interrupted) {
592
- return interrupted && block.type === "tool" && block.status === "pending" ? { ...block, status: "interrupted" } : sealed(block);
593
- }
594
- function closeSubagent(block, cut) {
595
- const children = block.children.map((c) => closeBlock(c, cut !== null));
596
- const status = cut && block.status === "running" ? cut : block.status;
597
- return status === block.status && children.every((c, i) => c === block.children[i]) ? block : { ...block, status, children };
638
+ return isMeasured(message.totals) ? setUsageLine(view, message) : view;
598
639
  }
599
640
  function endTurn(view, { turnId, outcome }) {
600
641
  let next = dropBuildingPlan(view, turnId);
601
642
  const planText = outcome === "plan" ? finalSegmentIndex(next.blocks, turnId, true) : -1;
602
643
  if (planText >= 0) next = { ...next, blocks: next.blocks.filter((_, i) => i !== planText) };
603
- const cut = outcome === "stopped" ? "stopped" : outcome === "error" ? "failed" : null;
604
- const blocks = next.blocks.map((b) => b.type === "subagent" ? closeSubagent(b, cut) : closeBlock(b, cut !== null));
605
- return blocks.every((b, i) => b === next.blocks[i]) ? next : { ...next, blocks };
644
+ return closeOpenBlocks(next, outcome === "stopped" ? "stopped" : outcome === "error" ? "failed" : null);
606
645
  }
607
646
  function markCompaction(view, summary) {
608
647
  const i = findLastIndex(view.blocks, (b) => b.type === "message" && b.role === "planner" && b.turnId === void 0 && b.text === summary);
@@ -749,6 +788,251 @@ function fromTranscript(conversationHistory, researchLog, plannerUsage) {
749
788
  return { blocks, nextId, ...transcriptAt ? { transcriptAt } : {} };
750
789
  }
751
790
 
791
+ // src/services/harness/agentTools.ts
792
+ var KNOWN_TOOLS = {
793
+ // Claude Code
794
+ read: "read_file",
795
+ grep: "grep",
796
+ glob: "glob",
797
+ bash: "bash",
798
+ ls: "list_dir",
799
+ webfetch: "fetch",
800
+ websearch: "web_search",
801
+ // Codex — its sandboxed command tool is a shell by another name
802
+ shell: "bash",
803
+ exec_command: "bash",
804
+ local_shell: "bash",
805
+ // OpenCode
806
+ list: "list_dir",
807
+ fetch: "fetch"
808
+ };
809
+ function mapAgentTool(name) {
810
+ const normalized = name.trim().toLowerCase().replace(/[_-]/g, "");
811
+ const direct = KNOWN_TOOLS[normalized] ?? KNOWN_TOOLS[name.trim().toLowerCase()];
812
+ if (direct) {
813
+ return { tool: direct, toolLabel: name };
814
+ }
815
+ return { tool: "agent_tool", toolLabel: name };
816
+ }
817
+ function normalizeAgentArgs(tool, args) {
818
+ const out = { ...args };
819
+ const alias = (from, to) => {
820
+ if (out[to] === void 0 && out[from] !== void 0) out[to] = out[from];
821
+ };
822
+ if (tool === "read_file" || tool === "list_dir") {
823
+ alias("filePath", "path");
824
+ alias("file_path", "path");
825
+ alias("target", "path");
826
+ }
827
+ if (tool === "bash") {
828
+ alias("cmd", "command");
829
+ alias("script", "command");
830
+ if (typeof out.command !== "string" && Array.isArray(out.command)) {
831
+ out.command = out.command.join(" ");
832
+ }
833
+ }
834
+ if (tool === "fetch") alias("uri", "url");
835
+ if (tool === "web_search") alias("q", "query");
836
+ return out;
837
+ }
838
+
839
+ // src/conversation/taskLog.ts
840
+ var EMPTY_TASK_LOG = { blocks: [], nextId: 1, queued: [], working: false, streams: {} };
841
+ var TEXT_STREAM = "text";
842
+ var thinkingStream = (subagentId) => `thinking:${subagentId ?? ""}`;
843
+ function withoutStream(view, key) {
844
+ if (!(key in view.streams)) return view;
845
+ return { ...view, streams: Object.fromEntries(Object.entries(view.streams).filter(([k]) => k !== key)) };
846
+ }
847
+ function blockText(text2) {
848
+ return text2.replace(/^\n+/, "");
849
+ }
850
+ function openStream(view, lane, key) {
851
+ const id = view.streams[key];
852
+ if (id === void 0) return -1;
853
+ const blocks = laneBlocks(view, lane);
854
+ const i = findLastIndex(blocks, (b) => b.type !== "usage");
855
+ const block = blocks[i];
856
+ return block?.id === id && (block.type === "message" || block.type === "thinking") && block.streaming ? i : -1;
857
+ }
858
+ function streamDelta(view, lane, key, text2, make) {
859
+ const i = openStream(view, lane, key);
860
+ const open = laneBlocks(view, lane)[i];
861
+ if (open?.type === "message" || open?.type === "thinking") return laneReplace(view, lane, i, { ...open, text: open.text + text2 });
862
+ const next = appendOutput(view, lane, (id) => make(id, blockText(text2)));
863
+ return { ...next, streams: { ...next.streams, [key]: `b${view.nextId}` } };
864
+ }
865
+ function streamWhole(view, lane, key, text2, make) {
866
+ const id = view.streams[key];
867
+ const blocks = laneBlocks(view, lane);
868
+ const i = id === void 0 ? -1 : findLastIndex(blocks, (b) => b.id === id);
869
+ const streamed = blocks[i];
870
+ const next = withoutStream(view, key);
871
+ if (streamed?.type === "message" || streamed?.type === "thinking") {
872
+ return laneReplace(next, lane, i, { ...streamed, text: blockText(text2), streaming: false });
873
+ }
874
+ return appendOutput(next, lane, make);
875
+ }
876
+ function agentText(view, text2) {
877
+ return streamWhole(view, null, TEXT_STREAM, text2, (id) => settledMessage(id, "agent", blockText(text2)));
878
+ }
879
+ function agentTextDelta(view, text2) {
880
+ return streamDelta(view, null, TEXT_STREAM, text2, (id, t) => ({ type: "message", id, role: "agent", text: t, streaming: true }));
881
+ }
882
+ function thinkingBlock(id, text2, streaming, subagentId) {
883
+ return { type: "thinking", id, text: text2, streaming, ...subagentId ? { subagentId } : {} };
884
+ }
885
+ function thinkingDelta(view, { text: text2, subagentId }) {
886
+ const [placed, lane] = laneOf(view, subagentId);
887
+ return streamDelta(placed, lane, thinkingStream(subagentId), text2, (id, t) => thinkingBlock(id, t, true, subagentId));
888
+ }
889
+ function thinkingWhole(view, { text: text2, subagentId }) {
890
+ const [placed, lane] = laneOf(view, subagentId);
891
+ return streamWhole(placed, lane, thinkingStream(subagentId), text2, (id) => thinkingBlock(id, blockText(text2), false, subagentId));
892
+ }
893
+ function announceTool2(view, { id: toolCallId, name, args, subagentId }) {
894
+ const { tool, toolLabel } = mapAgentTool(name);
895
+ const [placed, lane] = laneOf(view, subagentId);
896
+ return appendOutput(placed, lane, (id) => {
897
+ const call = pendingTool(id, { tool, toolLabel, args, toolCallId });
898
+ const parsed = parseArgs2(args);
899
+ return parsed ? { ...call, headline: toolHeadline(tool, JSON.stringify(normalizeAgentArgs(tool, parsed)), toolLabel) } : call;
900
+ });
901
+ }
902
+ function parseArgs2(args) {
903
+ try {
904
+ const parsed = JSON.parse(args);
905
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
906
+ } catch {
907
+ return null;
908
+ }
909
+ }
910
+ function settleTool2(view, { id: toolCallId, output, success, subagentId }) {
911
+ const [placed, lane] = laneOf(view, subagentId);
912
+ const blocks = laneBlocks(placed, lane);
913
+ const i = findLastIndex(blocks, (b) => b.type === "tool" && b.status === "pending" && b.toolCallId === toolCallId);
914
+ const pending = blocks[i];
915
+ const outcome = success ? "success" : "failure";
916
+ if (pending?.type === "tool") return laneReplace(placed, lane, i, finishedTool(pending, output, outcome));
917
+ if (lane === null && blocks.some((b) => b.type === "subagent" && b.toolCallId === toolCallId)) return view;
918
+ return laneAppend(placed, lane, (id) => finishedTool(pendingTool(id, { tool: "agent_tool", toolLabel: "Tool", args: "", toolCallId }), output, outcome));
919
+ }
920
+ function startSubagent2(view, { subagentId, brief, model }) {
921
+ return updateSubagent(view, subagentId, void 0, (block) => ({ ...block, ...brief ? { brief } : {}, ...model ? { model } : {} }));
922
+ }
923
+ function finishSubagent2(view, { subagentId, outcome, digest }) {
924
+ const usage = view.usage?.bySubagent?.[subagentId];
925
+ const next = updateSubagent(view, subagentId, void 0, (block) => ({
926
+ ...block,
927
+ status: outcome,
928
+ digest,
929
+ children: block.children.map(sealed),
930
+ ...usage ? { usage } : {}
931
+ }));
932
+ return withoutStream(next, thinkingStream(subagentId));
933
+ }
934
+ function reportUsage2(view, { record }) {
935
+ const usage = addPlannerUsage(view.usage ?? { totals: {} }, record);
936
+ const next = { ...view, usage };
937
+ return isMeasured(usage.totals) ? setUsageLine(next, usageLine(usage)) : next;
938
+ }
939
+ function runnerToolSubject(tool, args) {
940
+ const { tool: mapped, toolLabel } = mapAgentTool(tool);
941
+ const parsed = parseArgs2(args);
942
+ const headline = toolHeadline(mapped, parsed ? JSON.stringify(normalizeAgentArgs(mapped, parsed)) : args, toolLabel);
943
+ return headline.keyArg ? `${headline.name}(${headline.keyArg})` : headline.name;
944
+ }
945
+ function requestApproval2(view, { approvalId, tool, args, allowForTask, toolCallId }) {
946
+ if (view.blocks.some((b) => b.type === "approval" && b.approvalId === approvalId)) return view;
947
+ return append(view, (id) => ({
948
+ type: "approval",
949
+ id,
950
+ approvalId,
951
+ kind: "runner_tool",
952
+ subject: runnerToolSubject(tool, args),
953
+ scope: tool,
954
+ status: "pending",
955
+ ...allowForTask ? { allowForTask } : {},
956
+ ...toolCallId ? { toolCallId } : {}
957
+ }));
958
+ }
959
+ function settleApproval2(view, approvalId, settle) {
960
+ const i = findLastIndex(view.blocks, (b) => b.type === "approval" && b.approvalId === approvalId);
961
+ const block = view.blocks[i];
962
+ if (block?.type !== "approval" || block.status !== "pending") return view;
963
+ return { ...view, blocks: replaceAt(view.blocks, i, settle(block)) };
964
+ }
965
+ function decideApproval2(view, { approvalId, decision, note }) {
966
+ return settleApproval2(view, approvalId, (block) => ({
967
+ ...block,
968
+ status: decision === "deny" ? "denied" : "granted",
969
+ decidedBy: "asked",
970
+ ...decision === "allowForTask" ? { forTask: true } : {},
971
+ ...note ? { note } : {}
972
+ }));
973
+ }
974
+ function startTurn(view, { message, messageId }) {
975
+ const queued = messageId ? view.queued.filter((m) => m.id !== messageId) : view.queued;
976
+ const working = { ...view, queued, working: true };
977
+ return message ? append(working, (id) => settledMessage(id, "user", message)) : working;
978
+ }
979
+ var CUT = { completed: null, interrupted: "stopped", failed: "failed" };
980
+ function endTurn2(view, { reason }) {
981
+ const closed = closeOpenBlocks({ ...view, working: false, lastTurnEnd: reason, streams: {} }, CUT[reason]);
982
+ return reason === "interrupted" ? append(closed, (id) => settledMessage(id, "system", "Interrupted.")) : closed;
983
+ }
984
+ function queueMessage(view, { messageId, text: text2 }) {
985
+ if (view.queued.some((m) => m.id === messageId)) return view;
986
+ return { ...view, queued: [...view.queued, { id: messageId, text: text2 }] };
987
+ }
988
+ function unqueueMessage(view, { messageId }) {
989
+ const queued = view.queued.filter((m) => m.id !== messageId);
990
+ return queued.length === view.queued.length ? view : { ...view, queued };
991
+ }
992
+ function reduceTaskLog(view, event) {
993
+ switch (event.type) {
994
+ case "turn_start":
995
+ return startTurn(view, event);
996
+ case "turn_end":
997
+ return endTurn2(view, event);
998
+ case "text_delta":
999
+ return agentTextDelta(view, event.text);
1000
+ case "text":
1001
+ return agentText(view, event.text);
1002
+ case "thinking_delta":
1003
+ return thinkingDelta(view, event);
1004
+ case "thinking":
1005
+ return thinkingWhole(view, event);
1006
+ case "tool_call":
1007
+ return announceTool2(view, event);
1008
+ case "tool_result":
1009
+ return settleTool2(view, event);
1010
+ case "subagent_started":
1011
+ return startSubagent2(view, event);
1012
+ case "subagent_finished":
1013
+ return finishSubagent2(view, event);
1014
+ case "usage":
1015
+ return reportUsage2(view, event);
1016
+ case "message_queued":
1017
+ return queueMessage(view, event);
1018
+ case "message_removed":
1019
+ return unqueueMessage(view, event);
1020
+ case "error":
1021
+ return appendOutput(view, null, (id) => settledMessage(id, "error", event.message));
1022
+ case "approval_requested":
1023
+ return requestApproval2(view, event);
1024
+ case "approval_decided":
1025
+ return decideApproval2(view, event);
1026
+ case "approval_withdrawn":
1027
+ return settleApproval2(view, event.approvalId, (block) => ({ ...block, status: "withdrawn" }));
1028
+ default:
1029
+ return view;
1030
+ }
1031
+ }
1032
+ function replayTaskLog(events, from = EMPTY_TASK_LOG) {
1033
+ return events.reduce(reduceTaskLog, from);
1034
+ }
1035
+
752
1036
  // src/conversation/promptHold.ts
753
1037
  var EMPTY_HOLD = [];
754
1038
  function holdPrompt(hold, text2) {
@@ -826,6 +1110,7 @@ function taskStartedNotice(title, runner) {
826
1110
  CHECKPOINT_TRUNCATE_LENGTH,
827
1111
  EMPTY_CONVERSATION,
828
1112
  EMPTY_HOLD,
1113
+ EMPTY_TASK_LOG,
829
1114
  NO_TURN,
830
1115
  aheadOfDraft,
831
1116
  canMergeTasks,
@@ -842,6 +1127,9 @@ function taskStartedNotice(title, runner) {
842
1127
  outputLines,
843
1128
  outputPreview,
844
1129
  reduceConversation,
1130
+ reduceTaskLog,
1131
+ replayTaskLog,
1132
+ runnerToolSubject,
845
1133
  stopTurn,
846
1134
  summarizeToolCall,
847
1135
  taskStartedNotice,