@ordewell/core 0.5.4 → 0.5.6

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 (56) hide show
  1. package/dist/IFileSystem-BkPX7mLD.d.mts +76 -0
  2. package/dist/IFileSystem-C0l-4MGT.d.ts +76 -0
  3. package/dist/{ModeResolver-Dkig8ghQ.d.ts → ModeResolver--16lh7dS.d.mts} +1 -1
  4. package/dist/{ModeResolver-DVJ7HV3k.d.mts → ModeResolver-CjpG5Wli.d.ts} +1 -1
  5. package/dist/Task-Dyxp67s2.d.mts +2086 -0
  6. package/dist/Task-Dyxp67s2.d.ts +2086 -0
  7. package/dist/{chunk-T2S5O36I.mjs → chunk-C44UWIAD.mjs} +6 -6
  8. package/dist/chunk-C44UWIAD.mjs.map +1 -0
  9. package/dist/{chunk-JVMDEHRQ.mjs → chunk-EDGUFCIR.mjs} +77 -37
  10. package/dist/chunk-EDGUFCIR.mjs.map +1 -0
  11. package/dist/{chunk-XWOUIA6A.mjs → chunk-JBEFAJ2W.mjs} +2 -2
  12. package/dist/chunk-ROVYWEBI.mjs +2115 -0
  13. package/dist/chunk-ROVYWEBI.mjs.map +1 -0
  14. package/dist/index.d.mts +1647 -758
  15. package/dist/index.d.ts +1647 -758
  16. package/dist/index.js +9301 -4857
  17. package/dist/index.js.map +1 -1
  18. package/dist/index.mjs +6222 -2968
  19. package/dist/index.mjs.map +1 -1
  20. package/dist/order-labels.d.mts +3 -1
  21. package/dist/order-labels.d.ts +3 -1
  22. package/dist/{parsing-DRp4dPC0.d.mts → parsing-DPEpAszP.d.mts} +11 -3
  23. package/dist/{parsing-CF_grC29.d.ts → parsing-EcmCsF1y.d.ts} +11 -3
  24. package/dist/parsing.d.mts +5 -3
  25. package/dist/parsing.d.ts +5 -3
  26. package/dist/parsing.js.map +1 -1
  27. package/dist/parsing.mjs +2 -2
  28. package/dist/plan-utils-BAvW3hvl.d.mts +877 -0
  29. package/dist/plan-utils-BMyEiDKv.d.ts +877 -0
  30. package/dist/plan-utils.d.mts +5 -4
  31. package/dist/plan-utils.d.ts +5 -4
  32. package/dist/plan-utils.js +956 -8
  33. package/dist/plan-utils.js.map +1 -1
  34. package/dist/plan-utils.mjs +47 -7
  35. package/dist/testing.d.mts +57 -5
  36. package/dist/testing.d.ts +57 -5
  37. package/dist/testing.js +96 -2
  38. package/dist/testing.js.map +1 -1
  39. package/dist/testing.mjs +94 -2
  40. package/dist/testing.mjs.map +1 -1
  41. package/package.json +2 -1
  42. package/skills/grilling/SKILL.md +6 -16
  43. package/skills/improve-codebase-architecture/SKILL.md +1 -1
  44. package/dist/ApprovalPolicy-BVhGdECT.d.mts +0 -79
  45. package/dist/ApprovalPolicy-BVhGdECT.d.ts +0 -79
  46. package/dist/ITerminalRunner-Bd-vAJnw.d.ts +0 -561
  47. package/dist/ITerminalRunner-ByeoLF57.d.mts +0 -561
  48. package/dist/Task-BxQkPlXO.d.mts +0 -664
  49. package/dist/Task-BxQkPlXO.d.ts +0 -664
  50. package/dist/chunk-GWPIYDQW.mjs +0 -945
  51. package/dist/chunk-GWPIYDQW.mjs.map +0 -1
  52. package/dist/chunk-JVMDEHRQ.mjs.map +0 -1
  53. package/dist/chunk-T2S5O36I.mjs.map +0 -1
  54. package/dist/plan-utils-CkNbqAmS.d.ts +0 -329
  55. package/dist/plan-utils-CtB3_Ovf.d.mts +0 -329
  56. /package/dist/{chunk-XWOUIA6A.mjs.map → chunk-JBEFAJ2W.mjs.map} +0 -0
@@ -21,14 +21,35 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var plan_utils_exports = {};
22
22
  __export(plan_utils_exports, {
23
23
  CHECKPOINT_TRUNCATE_LENGTH: () => CHECKPOINT_TRUNCATE_LENGTH,
24
+ EMPTY_CONVERSATION: () => EMPTY_CONVERSATION,
25
+ EMPTY_HOLD: () => EMPTY_HOLD,
26
+ EMPTY_TASK_LOG: () => EMPTY_TASK_LOG,
27
+ NO_TURN: () => NO_TURN,
28
+ aheadOfDraft: () => aheadOfDraft,
24
29
  canMergeTasks: () => canMergeTasks,
25
30
  canSetDependencies: () => canSetDependencies,
26
31
  canSplitTask: () => canSplitTask,
27
32
  capConflictFiles: () => capConflictFiles,
28
33
  dependencyCandidates: () => dependencyCandidates,
29
34
  dependentsOf: () => dependentsOf,
35
+ drainNext: () => drainNext,
36
+ followTurn: () => followTurn,
37
+ fromTranscript: () => fromTranscript,
38
+ hasHiddenDetail: () => hasHiddenDetail,
39
+ holdPrompt: () => holdPrompt,
40
+ outputLines: () => outputLines,
41
+ outputPreview: () => outputPreview,
42
+ reduceConversation: () => reduceConversation,
43
+ reduceTaskLog: () => reduceTaskLog,
44
+ replayTaskLog: () => replayTaskLog,
45
+ runnerToolSubject: () => runnerToolSubject,
46
+ stopTurn: () => stopTurn,
30
47
  summarizeToolCall: () => summarizeToolCall,
31
- truncateCheckpointSummary: () => truncateCheckpointSummary
48
+ taskStartedNotice: () => taskStartedNotice,
49
+ toolHeadline: () => toolHeadline,
50
+ truncateCheckpointSummary: () => truncateCheckpointSummary,
51
+ unsendAll: () => unsendAll,
52
+ unsendLatest: () => unsendLatest
32
53
  });
33
54
  module.exports = __toCommonJS(plan_utils_exports);
34
55
 
@@ -105,9 +126,9 @@ function canSplitTask(tasks, taskId) {
105
126
  }
106
127
 
107
128
  // src/services/researchStepSummary.ts
108
- function ellipsize(text, max) {
109
- const oneLine = text.replace(/\s+/g, " ").trim();
110
- return oneLine.length > max ? `${oneLine.slice(0, max)}\u2026` : oneLine;
129
+ function ellipsize(text2, max) {
130
+ const oneLine2 = text2.replace(/\s+/g, " ").trim();
131
+ return oneLine2.length > max ? `${oneLine2.slice(0, max)}\u2026` : oneLine2;
111
132
  }
112
133
  function summarizeToolCall(tool, argsJson, toolLabel) {
113
134
  const display = toolLabel?.trim() || tool;
@@ -124,8 +145,8 @@ function summarizeToolCall(tool, argsJson, toolLabel) {
124
145
  try {
125
146
  const args = JSON.parse(argsJson);
126
147
  const prompt = typeof args.prompt === "string" ? args.prompt : "";
127
- const oneLine = prompt.replace(/\s+/g, " ").trim();
128
- return `spawn: "${oneLine.slice(0, 60)}${oneLine.length > 60 ? "\u2026" : ""}"`;
148
+ const oneLine2 = prompt.replace(/\s+/g, " ").trim();
149
+ return `spawn: "${oneLine2.slice(0, 60)}${oneLine2.length > 60 ? "\u2026" : ""}"`;
129
150
  } catch {
130
151
  return "spawn_research_agent";
131
152
  }
@@ -173,20 +194,947 @@ function truncateCheckpointSummary(summary) {
173
194
  return firstLine.slice(0, CHECKPOINT_TRUNCATE_LENGTH - 1) + "\u2026";
174
195
  }
175
196
 
176
- // src/services/isolationRecord.ts
197
+ // src/services/conflictFiles.ts
177
198
  function capConflictFiles(files, max = 5) {
178
199
  return files.length <= max ? files.join(", ") : `${files.slice(0, max).join(", ")}, +${files.length - max} more`;
179
200
  }
201
+
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
+ }
226
+ function isMeasured(totals) {
227
+ return totals.inputTokens !== void 0 || totals.outputTokens !== void 0 || totals.cachedInputTokens !== void 0 || Object.keys(totals.reportedCost ?? {}).length > 0;
228
+ }
229
+ function usageLine(usage) {
230
+ const contextFill = plannerContextFill(usage);
231
+ return {
232
+ totals: usage.totals,
233
+ ...usage.bySubagent ? { bySubagent: usage.bySubagent } : {},
234
+ ...contextFill ? { contextFill } : {}
235
+ };
236
+ }
237
+ function plannerContextFill(usage) {
238
+ if (usage.lastPromptTokens === void 0 || usage.contextWindow === void 0 || usage.contextWindow <= 0) return void 0;
239
+ return { usedTokens: usage.lastPromptTokens, windowTokens: usage.contextWindow };
240
+ }
241
+
242
+ // src/services/terminalRender.ts
243
+ var ANSI_OR_CTRL_RE = /\x1b\[[0-9;?]*[A-Za-z]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)?|\x1b[()][AB012]|\x1b[=>]|[\x00-\x08\x0b-\x1f\x7f]/g;
244
+
245
+ // src/conversation/format.ts
246
+ var DISPLAY_NAMES = {
247
+ read_file: "Read",
248
+ read_files: "Read",
249
+ list_dir: "List",
250
+ glob: "Glob",
251
+ grep: "Grep",
252
+ find_symbol: "Symbol",
253
+ bash: "Bash",
254
+ fetch: "Fetch",
255
+ web_search: "WebSearch",
256
+ spawn_research_agent: "Agent"
257
+ };
258
+ var HINT_FIELDS = ["file_path", "filePath", "path", "url", "pattern", "query", "command", "description", "prompt"];
259
+ function parseArgs(args) {
260
+ try {
261
+ const parsed = JSON.parse(args);
262
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
263
+ } catch {
264
+ return null;
265
+ }
266
+ }
267
+ function oneLine(text2) {
268
+ return text2.replace(/\s+/g, " ").trim();
269
+ }
270
+ function firstLineOf(command) {
271
+ const lines = command.trim().split(/\r?\n/);
272
+ const more = lines.length - 1;
273
+ return more > 0 ? `${lines[0]} \u2026 +${more} line${more === 1 ? "" : "s"}` : lines[0];
274
+ }
275
+ function text(value) {
276
+ return typeof value === "string" ? value : "";
277
+ }
278
+ function searchArg(pattern, path, include = "") {
279
+ return `${pattern}${path ? ` in ${path}` : ""}${include ? ` (${include})` : ""}`;
280
+ }
281
+ function hintArg(args) {
282
+ for (const field of HINT_FIELDS) {
283
+ const value = text(args[field]);
284
+ if (value) return field === "command" ? firstLineOf(value) : oneLine(value);
285
+ }
286
+ const firstText = Object.values(args).find((v) => typeof v === "string" && v.trim() !== "");
287
+ return firstText ? oneLine(firstText) : "";
288
+ }
289
+ function keyArgOf(tool, args) {
290
+ switch (tool) {
291
+ case "bash":
292
+ return firstLineOf(text(args.command));
293
+ case "read_file":
294
+ case "list_dir":
295
+ return text(args.path);
296
+ case "read_files":
297
+ return Array.isArray(args.paths) ? args.paths.map(String).join(", ") : "";
298
+ case "glob":
299
+ return searchArg(text(args.pattern), text(args.path));
300
+ case "grep":
301
+ return searchArg(text(args.pattern), text(args.path), text(args.include));
302
+ case "find_symbol":
303
+ return `${text(args.symbol)}${text(args.language) ? ` [${text(args.language)}]` : ""}`;
304
+ case "fetch":
305
+ return text(args.url);
306
+ case "web_search":
307
+ return oneLine(text(args.query));
308
+ case "spawn_research_agent":
309
+ return oneLine(text(args.prompt));
310
+ default:
311
+ return hintArg(args);
312
+ }
313
+ }
314
+ function toolHeadline(tool, args, toolLabel) {
315
+ const name = toolLabel?.trim() || DISPLAY_NAMES[tool] || tool;
316
+ const parsed = parseArgs(args);
317
+ return { name, keyArg: parsed ? keyArgOf(tool, parsed) : oneLine(args) };
318
+ }
319
+ function outputLines(output) {
320
+ const lines = output.replace(/\r\n?/g, "\n").replace(ANSI_OR_CTRL_RE, "").split("\n");
321
+ while (lines.length > 0 && lines[lines.length - 1].trim() === "") lines.pop();
322
+ return lines;
323
+ }
324
+ function outputPreview(output, maxLines) {
325
+ const lines = outputLines(output);
326
+ const shown = lines.slice(0, Math.max(0, maxLines));
327
+ return { lines: shown, hiddenLineCount: lines.length - shown.length };
328
+ }
329
+
330
+ // src/conversation/records.ts
331
+ function settledMessage(id, role, text2, turnId) {
332
+ return { type: "message", id, role, text: text2, streaming: false, ...turnId ? { turnId } : {} };
333
+ }
334
+ function subagentBlock(id, { toolCallId, model, usage, turnId, ...fields }) {
335
+ return {
336
+ type: "subagent",
337
+ id,
338
+ ...fields,
339
+ ...toolCallId ? { toolCallId } : {},
340
+ ...model ? { model } : {},
341
+ ...usage ? { usage } : {},
342
+ ...turnId ? { turnId } : {}
343
+ };
344
+ }
345
+ function usageBlock(id, { totals, bySubagent, contextFill }) {
346
+ return { type: "usage", id, totals, ...bySubagent ? { bySubagent } : {}, ...contextFill ? { contextFill } : {} };
347
+ }
348
+ var STATUS_OF_OUTCOME = {
349
+ success: "ok",
350
+ failure: "error",
351
+ refused: "denied",
352
+ denied: "denied",
353
+ not_executed: "interrupted"
354
+ };
355
+ function finishedTool(call, output, outcome) {
356
+ return { ...call, status: STATUS_OF_OUTCOME[outcome], outcome, output, outputLineCount: outputLines(output).length };
357
+ }
358
+ function settledTool(call, step) {
359
+ return finishedTool(call, step.result, step.outcome);
360
+ }
361
+ function pendingTool(id, { tool, toolLabel, args, toolCallId, turnId }) {
362
+ return {
363
+ type: "tool",
364
+ id,
365
+ tool,
366
+ headline: toolHeadline(tool, args, toolLabel),
367
+ args,
368
+ status: "pending",
369
+ output: "",
370
+ outputLineCount: 0,
371
+ ...toolCallId ? { toolCallId } : {},
372
+ ...toolLabel ? { toolLabel } : {},
373
+ ...turnId ? { turnId } : {}
374
+ };
375
+ }
376
+ function toolFromStep(id, step, turnId) {
377
+ return settledTool(pendingTool(id, { ...step, turnId }), step);
378
+ }
379
+ function planMarker(content) {
380
+ const count = /(\d+) tasks?\b/.exec(content);
381
+ return { status: content.startsWith("Plan updated") ? "updated" : "generated", ...count ? { taskCount: Number(count[1]) } : {} };
382
+ }
383
+
384
+ // src/conversation/lanes.ts
385
+ function findLastIndex(items, match) {
386
+ for (let i = items.length - 1; i >= 0; i--) if (match(items[i])) return i;
387
+ return -1;
388
+ }
389
+ function replaceAt(items, index, item) {
390
+ const next = items.slice();
391
+ next[index] = item;
392
+ return next;
393
+ }
394
+ function insertTop(blocks, block) {
395
+ const last = blocks[blocks.length - 1];
396
+ return last?.type === "usage" ? [...blocks.slice(0, -1), block, last] : [...blocks, block];
397
+ }
398
+ function append(view, make) {
399
+ return { ...view, blocks: insertTop(view.blocks, make(`b${view.nextId}`)), nextId: view.nextId + 1 };
400
+ }
401
+ function subagentAt(view, lane) {
402
+ const block = view.blocks[lane];
403
+ if (block.type !== "subagent") throw new Error(`block ${lane} is not a subagent`);
404
+ return block;
405
+ }
406
+ function laneBlocks(view, lane) {
407
+ return lane === null ? view.blocks : subagentAt(view, lane).children;
408
+ }
409
+ function setChildren(view, lane, children) {
410
+ return { ...view, blocks: replaceAt(view.blocks, lane, { ...subagentAt(view, lane), children }) };
411
+ }
412
+ function laneReplace(view, lane, index, block) {
413
+ if (lane === null) return { ...view, blocks: replaceAt(view.blocks, index, block) };
414
+ return setChildren(view, lane, replaceAt(subagentAt(view, lane).children, index, block));
415
+ }
416
+ function laneAppend(view, lane, make) {
417
+ if (lane === null) return append(view, make);
418
+ const children = [...subagentAt(view, lane).children, make(`b${view.nextId}`)];
419
+ return { ...setChildren(view, lane, children), nextId: view.nextId + 1 };
420
+ }
421
+ function isStreaming(block) {
422
+ return (block.type === "message" || block.type === "thinking") && block.streaming;
423
+ }
424
+ function sealed(block) {
425
+ return isStreaming(block) ? { ...block, streaming: false } : block;
426
+ }
427
+ function sealLane(view, lane, keep) {
428
+ const blocks = laneBlocks(view, lane);
429
+ if (!blocks.some((b, i) => i !== keep && isStreaming(b))) return view;
430
+ if (lane === null) return { ...view, blocks: view.blocks.map((b, i) => i === keep ? b : sealed(b)) };
431
+ return setChildren(view, lane, subagentAt(view, lane).children.map((b, i) => i === keep ? b : sealed(b)));
432
+ }
433
+ function appendOutput(view, lane, make) {
434
+ const next = laneAppend(view, lane, make);
435
+ return sealLane(next, lane, findLastIndex(laneBlocks(next, lane), (b) => b.type !== "usage"));
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 };
503
+ function isUnsettledSegment(block, turnId) {
504
+ return block.type === "message" && block.turnId === turnId && block.segmentId !== void 0;
505
+ }
506
+ function isBuildingPlan(block, turnId) {
507
+ return block.type === "plan" && block.status === "building" && block.turnId === turnId;
508
+ }
509
+ function finalSegmentIndex(blocks, turnId, pastPlan = false) {
510
+ for (let i = blocks.length - 1; i >= 0; i--) {
511
+ const block = blocks[i];
512
+ if (block.type === "usage" || block.type === "thinking" || block.type === "approval" || pastPlan && block.type === "plan") continue;
513
+ if (block.turnId !== turnId) continue;
514
+ return isUnsettledSegment(block, turnId) ? i : -1;
515
+ }
516
+ return -1;
517
+ }
518
+ function openTurn(view, turnId, prompt) {
519
+ const i = findLastIndex(view.blocks, (b) => b.type === "message" && b.role === "user");
520
+ const sent = view.blocks[i];
521
+ if (sent?.type === "message" && sent.turnId === void 0 && sent.text === prompt) {
522
+ return { ...view, blocks: replaceAt(view.blocks, i, { ...sent, turnId }) };
523
+ }
524
+ return append(view, (id) => settledMessage(id, "user", prompt, turnId));
525
+ }
526
+ function streamText(view, { turnId, segmentId, text: text2 }) {
527
+ const i = findLastIndex(view.blocks, (b) => isUnsettledSegment(b, turnId) && b.segmentId === segmentId);
528
+ const segment = view.blocks[i];
529
+ if (segment?.type === "message") {
530
+ return sealLane(laneReplace(view, null, i, { ...segment, text: segment.text + text2, streaming: true }), null, i);
531
+ }
532
+ return appendOutput(view, null, (id) => ({ type: "message", id, role: "planner", text: text2, streaming: true, turnId, segmentId }));
533
+ }
534
+ function dropBuildingPlan(view, turnId, segmentId) {
535
+ const blocks = view.blocks.filter((b) => !(isBuildingPlan(b, turnId) && (segmentId === void 0 || b.segmentId === segmentId)));
536
+ return blocks.length === view.blocks.length ? view : { ...view, blocks };
537
+ }
538
+ function settleReply(view, { content, turnId }) {
539
+ if (turnId !== void 0) {
540
+ const i = finalSegmentIndex(view.blocks, turnId);
541
+ if (i >= 0) {
542
+ return dropBuildingPlan({ ...view, blocks: replaceAt(view.blocks, i, settledMessage(view.blocks[i].id, "planner", content, turnId)) }, turnId);
543
+ }
544
+ }
545
+ return append(dropBuildingPlan(view, turnId), (id) => settledMessage(id, "planner", content, turnId));
546
+ }
547
+ function retractText(view, { turnId, segmentId }) {
548
+ const blocks = view.blocks.filter((b) => !(isUnsettledSegment(b, turnId) && (segmentId === void 0 || b.segmentId === segmentId)));
549
+ return dropBuildingPlan(blocks.length === view.blocks.length ? view : { ...view, blocks }, turnId, segmentId);
550
+ }
551
+ function startSubagent(view, { subagentId, brief, model, turnId }) {
552
+ return updateSubagent(view, subagentId, turnId, (block) => ({ ...block, ...brief ? { brief } : {}, ...model ? { model } : {} }));
553
+ }
554
+ function finishSubagent(view, { subagentId, outcome, digest, usage, turnId }) {
555
+ return updateSubagent(view, subagentId, turnId, (block) => ({
556
+ ...block,
557
+ status: outcome,
558
+ digest,
559
+ children: block.children.map(sealed),
560
+ ...usage ? { usage } : {}
561
+ }));
562
+ }
563
+ function announceTool(view, call) {
564
+ const spawns = call.tool === "spawn_research_agent" ? call.subagentId : void 0;
565
+ const [placed, lane] = laneOf(view, spawns ? void 0 : call.subagentId, call.turnId);
566
+ return appendOutput(placed, lane, (id) => ({ ...pendingTool(id, call), ...spawns ? { spawns } : {} }));
567
+ }
568
+ function isPendingCallOf(block, step) {
569
+ if (block.type !== "tool" || block.status !== "pending") return false;
570
+ return step.toolCallId ? block.toolCallId === step.toolCallId : block.toolCallId === void 0 && block.tool === step.tool;
571
+ }
572
+ function settleTool(view, { step, turnId }) {
573
+ const [placed, lane] = laneOf(view, step.subagentId, turnId);
574
+ const blocks = laneBlocks(placed, lane);
575
+ const i = findLastIndex(blocks, (b) => isPendingCallOf(b, step));
576
+ const pending = blocks[i];
577
+ if (pending?.type === "tool") return laneReplace(placed, lane, i, settledTool(pending, step));
578
+ if (lane === null && step.toolCallId && blocks.some((b) => b.type === "subagent" && b.toolCallId === step.toolCallId)) return view;
579
+ return laneAppend(placed, lane, (id) => toolFromStep(id, step, turnId));
580
+ }
581
+ function streamPlan(view, { token, turnId, segmentId }) {
582
+ const i = findLastIndex(view.blocks, (b) => isBuildingPlan(b, turnId));
583
+ const building = view.blocks[i];
584
+ if (building?.type === "plan" && building.segmentId === segmentId) {
585
+ return { ...view, blocks: replaceAt(view.blocks, i, { ...building, text: building.text + token }) };
586
+ }
587
+ return append(dropBuildingPlan(view, turnId), (id) => ({
588
+ type: "plan",
589
+ id,
590
+ status: "building",
591
+ text: token,
592
+ ...turnId ? { turnId } : {},
593
+ ...segmentId ? { segmentId } : {}
594
+ }));
595
+ }
596
+ function markPlan(view, content, turnId) {
597
+ const marker = planMarker(content);
598
+ const i = findLastIndex(view.blocks, (b) => isBuildingPlan(b, turnId));
599
+ const building = view.blocks[i];
600
+ if (building?.type === "plan") {
601
+ const settled = { type: "plan", id: building.id, ...marker, text: "", ...building.turnId ? { turnId: building.turnId } : {} };
602
+ return { ...view, blocks: replaceAt(view.blocks, i, settled) };
603
+ }
604
+ return append(view, (id) => ({ type: "plan", id, text: "", ...marker }));
605
+ }
606
+ function requestApproval(view, { id: approvalId, kind, subject, scope, detail, turnId }) {
607
+ return append(view, (id) => ({
608
+ type: "approval",
609
+ id,
610
+ approvalId,
611
+ kind,
612
+ subject,
613
+ scope,
614
+ status: "pending",
615
+ ...detail ? { detail } : {},
616
+ ...turnId ? { turnId } : {}
617
+ }));
618
+ }
619
+ function settleApproval(view, { id, granted }) {
620
+ const i = findLastIndex(view.blocks, (b) => b.type === "approval" && b.approvalId === id);
621
+ const request = view.blocks[i];
622
+ if (request?.type !== "approval") return view;
623
+ return { ...view, blocks: replaceAt(view.blocks, i, { ...request, status: granted ? "granted" : "denied", decidedBy: "asked" }) };
624
+ }
625
+ function decideApproval(view, { kind, subject, scope, detail, granted, source }) {
626
+ return append(view, (id) => ({
627
+ type: "approval",
628
+ id,
629
+ kind,
630
+ subject,
631
+ scope,
632
+ status: granted ? "granted" : "denied",
633
+ decidedBy: source,
634
+ ...detail ? { detail } : {}
635
+ }));
636
+ }
637
+ function reportUsage(view, message) {
638
+ return isMeasured(message.totals) ? setUsageLine(view, message) : view;
639
+ }
640
+ function endTurn(view, { turnId, outcome }) {
641
+ let next = dropBuildingPlan(view, turnId);
642
+ const planText = outcome === "plan" ? finalSegmentIndex(next.blocks, turnId, true) : -1;
643
+ if (planText >= 0) next = { ...next, blocks: next.blocks.filter((_, i) => i !== planText) };
644
+ return closeOpenBlocks(next, outcome === "stopped" ? "stopped" : outcome === "error" ? "failed" : null);
645
+ }
646
+ function markCompaction(view, summary) {
647
+ const i = findLastIndex(view.blocks, (b) => b.type === "message" && b.role === "planner" && b.turnId === void 0 && b.text === summary);
648
+ const announced = view.blocks[i];
649
+ if (announced?.type === "message") return { ...view, blocks: replaceAt(view.blocks, i, { ...announced, role: "system" }) };
650
+ return append(view, (id) => settledMessage(id, "system", summary));
651
+ }
652
+ function syncTranscript(view, { plan, turnId }) {
653
+ const history = plan.conversationHistory ?? [];
654
+ const committed = findLastIndex(history, (e) => e.kind === "plan_generated");
655
+ let next = view;
656
+ let latest = view.transcriptAt;
657
+ for (const [i, entry] of history.entries()) {
658
+ const isNew = view.transcriptAt === void 0 || entry.timestamp > view.transcriptAt;
659
+ if (isNew && entry.kind === "plan_generated") next = markPlan(next, entry.content, i === committed ? turnId : void 0);
660
+ if (isNew && entry.kind === "system") next = append(next, (id) => settledMessage(id, "system", entry.content));
661
+ if (isNew && entry.kind === "compaction") next = markCompaction(next, entry.content);
662
+ if (latest === void 0 || entry.timestamp > latest) latest = entry.timestamp;
663
+ }
664
+ return next === view && latest === view.transcriptAt ? view : { ...next, transcriptAt: latest };
665
+ }
666
+ function reduceConversation(view, input) {
667
+ switch (input.type) {
668
+ case "local_entry":
669
+ return append(view, (id) => settledMessage(id, input.role, input.text));
670
+ case "planner_turn_started":
671
+ return input.prompt === void 0 ? view : openTurn(view, input.turnId, input.prompt);
672
+ case "planner_text_delta":
673
+ return streamText(view, input);
674
+ case "planner_message":
675
+ return settleReply(view, input);
676
+ case "planner_text_retracted":
677
+ return retractText(view, input);
678
+ case "planner_thinking_delta":
679
+ return think(view, input.text, input.turnId, input.segmentId, input.subagentId);
680
+ case "research_step":
681
+ return announceTool(view, input);
682
+ case "research_step_done":
683
+ return settleTool(view, input);
684
+ case "subagent_started":
685
+ return startSubagent(view, input);
686
+ case "subagent_finished":
687
+ return finishSubagent(view, input);
688
+ case "plan_token":
689
+ return streamPlan(view, input);
690
+ case "plan_generated":
691
+ return syncTranscript(view, input);
692
+ case "planner_turn_ended":
693
+ return endTurn(view, input);
694
+ case "approval_request":
695
+ return requestApproval(view, input);
696
+ case "approval_settled":
697
+ return settleApproval(view, input);
698
+ case "approval_decided":
699
+ return decideApproval(view, input);
700
+ case "planner_usage":
701
+ return reportUsage(view, input);
702
+ default:
703
+ return view;
704
+ }
705
+ }
706
+
707
+ // src/conversation/transcript.ts
708
+ var USER = 0;
709
+ var RESEARCH = 1;
710
+ var SETTLED = 2;
711
+ function fromEntry(entry) {
712
+ if (entry.kind === "plan_generated") return (id) => ({ type: "plan", id: id(), text: "", ...planMarker(entry.content) });
713
+ const role = entry.kind === "system" || entry.kind === "compaction" ? "system" : entry.role === "user" ? "user" : "planner";
714
+ return (id) => settledMessage(id(), role, entry.content);
715
+ }
716
+ function spawnBrief(step) {
717
+ try {
718
+ const args = JSON.parse(step.args);
719
+ const prompt = args && typeof args === "object" ? args.prompt : void 0;
720
+ return typeof prompt === "string" ? prompt.trim() : void 0;
721
+ } catch {
722
+ return void 0;
723
+ }
724
+ }
725
+ function spawnedBy(step, unclaimed) {
726
+ const byId = unclaimed.find((e) => e.subagentId === step.toolCallId);
727
+ if (byId) return byId;
728
+ if (step.tool !== "spawn_research_agent") return void 0;
729
+ const brief = spawnBrief(step);
730
+ return brief === void 0 ? void 0 : unclaimed.find((e) => e.brief === brief);
731
+ }
732
+ function research(log) {
733
+ const subagents = log.filter((e) => "type" in e && e.type === "subagent");
734
+ const ownSubagent = new Set(subagents.map((e) => e.subagentId));
735
+ const unclaimed = [...subagents];
736
+ const spawnCall = /* @__PURE__ */ new Map();
737
+ const placed = [];
738
+ for (const entry of log) {
739
+ if ("type" in entry) {
740
+ if (entry.type === "system") placed.push({ at: entry.timestamp, rank: RESEARCH, build: (id) => settledMessage(id(), "system", entry.content) });
741
+ continue;
742
+ }
743
+ if (entry.subagentId && ownSubagent.has(entry.subagentId)) continue;
744
+ const spawned = spawnedBy(entry, unclaimed);
745
+ if (spawned) {
746
+ unclaimed.splice(unclaimed.indexOf(spawned), 1);
747
+ spawnCall.set(spawned.subagentId, entry.toolCallId);
748
+ continue;
749
+ }
750
+ placed.push({ at: entry.timestamp, rank: RESEARCH, build: (id) => toolFromStep(id(), entry) });
751
+ }
752
+ for (const entry of subagents) {
753
+ const toolCallId = spawnCall.get(entry.subagentId);
754
+ const steps = log.filter((e) => !("type" in e) && e.subagentId === entry.subagentId);
755
+ placed.push({
756
+ at: entry.timestamp,
757
+ rank: RESEARCH,
758
+ build: (id) => subagentBlock(id(), {
759
+ subagentId: entry.subagentId,
760
+ brief: entry.brief,
761
+ status: entry.outcome,
762
+ digest: entry.digest,
763
+ children: steps.map((step) => toolFromStep(id(), step)),
764
+ toolCallId,
765
+ model: entry.model,
766
+ usage: entry.usage
767
+ })
768
+ });
769
+ }
770
+ return placed;
771
+ }
772
+ function fromTranscript(conversationHistory, researchLog, plannerUsage) {
773
+ const history = conversationHistory ?? [];
774
+ const compacted = history[0]?.kind === "compaction" ? history[0] : void 0;
775
+ const kept = compacted ? history.slice(1) : history;
776
+ const cutoff = compacted ? kept[0]?.timestamp ?? compacted.timestamp : "";
777
+ const placed = [
778
+ ...kept.map((entry) => ({ at: entry.timestamp, rank: entry.role === "user" && !entry.kind ? USER : SETTLED, build: fromEntry(entry) })),
779
+ ...research(researchLog ?? []).filter((item) => item.at >= cutoff)
780
+ ];
781
+ placed.sort((a, b) => a.at < b.at ? -1 : a.at > b.at ? 1 : a.rank - b.rank);
782
+ if (compacted) placed.unshift({ at: "", rank: SETTLED, build: fromEntry(compacted) });
783
+ let nextId = 1;
784
+ const id = () => `b${nextId++}`;
785
+ const blocks = placed.map((item) => item.build(id));
786
+ if (plannerUsage && isMeasured(plannerUsage.totals)) blocks.push(usageBlock(id(), usageLine(plannerUsage)));
787
+ const transcriptAt = history.reduce((latest, e) => latest === void 0 || e.timestamp > latest ? e.timestamp : latest, void 0);
788
+ return { blocks, nextId, ...transcriptAt ? { transcriptAt } : {} };
789
+ }
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
+ return append({ ...view, queued, working: true }, (id) => settledMessage(id, "user", message));
977
+ }
978
+ var CUT = { completed: null, interrupted: "stopped", failed: "failed" };
979
+ function endTurn2(view, { reason }) {
980
+ const closed = closeOpenBlocks({ ...view, working: false, lastTurnEnd: reason, streams: {} }, CUT[reason]);
981
+ return reason === "interrupted" ? append(closed, (id) => settledMessage(id, "system", "Interrupted.")) : closed;
982
+ }
983
+ function queueMessage(view, { messageId, text: text2 }) {
984
+ if (view.queued.some((m) => m.id === messageId)) return view;
985
+ return { ...view, queued: [...view.queued, { id: messageId, text: text2 }] };
986
+ }
987
+ function unqueueMessage(view, { messageId }) {
988
+ const queued = view.queued.filter((m) => m.id !== messageId);
989
+ return queued.length === view.queued.length ? view : { ...view, queued };
990
+ }
991
+ function reduceTaskLog(view, event) {
992
+ switch (event.type) {
993
+ case "turn_start":
994
+ return startTurn(view, event);
995
+ case "turn_end":
996
+ return endTurn2(view, event);
997
+ case "text_delta":
998
+ return agentTextDelta(view, event.text);
999
+ case "text":
1000
+ return agentText(view, event.text);
1001
+ case "thinking_delta":
1002
+ return thinkingDelta(view, event);
1003
+ case "thinking":
1004
+ return thinkingWhole(view, event);
1005
+ case "tool_call":
1006
+ return announceTool2(view, event);
1007
+ case "tool_result":
1008
+ return settleTool2(view, event);
1009
+ case "subagent_started":
1010
+ return startSubagent2(view, event);
1011
+ case "subagent_finished":
1012
+ return finishSubagent2(view, event);
1013
+ case "usage":
1014
+ return reportUsage2(view, event);
1015
+ case "message_queued":
1016
+ return queueMessage(view, event);
1017
+ case "message_removed":
1018
+ return unqueueMessage(view, event);
1019
+ case "error":
1020
+ return appendOutput(view, null, (id) => settledMessage(id, "error", event.message));
1021
+ case "approval_requested":
1022
+ return requestApproval2(view, event);
1023
+ case "approval_decided":
1024
+ return decideApproval2(view, event);
1025
+ case "approval_withdrawn":
1026
+ return settleApproval2(view, event.approvalId, (block) => ({ ...block, status: "withdrawn" }));
1027
+ default:
1028
+ return view;
1029
+ }
1030
+ }
1031
+ function replayTaskLog(events, from = EMPTY_TASK_LOG) {
1032
+ return events.reduce(reduceTaskLog, from);
1033
+ }
1034
+
1035
+ // src/conversation/promptHold.ts
1036
+ var EMPTY_HOLD = [];
1037
+ function holdPrompt(hold, text2) {
1038
+ return [...hold, text2];
1039
+ }
1040
+ function drainNext(hold) {
1041
+ const [text2, ...rest] = hold;
1042
+ return text2 === void 0 ? void 0 : { text: text2, rest };
1043
+ }
1044
+ function unsendLatest(hold) {
1045
+ if (hold.length === 0) return void 0;
1046
+ return { text: hold[hold.length - 1], rest: hold.slice(0, -1) };
1047
+ }
1048
+ function unsendAll(hold) {
1049
+ if (hold.length === 0) return void 0;
1050
+ return { text: hold.join("\n"), rest: EMPTY_HOLD };
1051
+ }
1052
+ function aheadOfDraft(text2, draft) {
1053
+ return draft ? `${text2}
1054
+ ${draft}` : text2;
1055
+ }
1056
+
1057
+ // src/conversation/turnGate.ts
1058
+ var NO_TURN = { open: null, stopped: null };
1059
+ var TURN_STREAM = /* @__PURE__ */ new Set([
1060
+ "planner_text_delta",
1061
+ "planner_thinking_delta",
1062
+ "planner_text_retracted",
1063
+ "planner_message",
1064
+ "plan_token",
1065
+ "research_step",
1066
+ "research_step_done",
1067
+ "subagent_started",
1068
+ "subagent_finished",
1069
+ "planner_turn_ended"
1070
+ ]);
1071
+ function cutOff(gate, input) {
1072
+ if (gate.stopped === null || !TURN_STREAM.has(input.type)) return false;
1073
+ const turnId = "turnId" in input ? input.turnId : void 0;
1074
+ return turnId === void 0 || turnId === gate.stopped;
1075
+ }
1076
+ function withGate(live, gate) {
1077
+ return gate.open === live.gate.open && gate.stopped === live.gate.stopped ? live : { ...live, gate };
1078
+ }
1079
+ function followTurn(view, gate, input) {
1080
+ const live = { view, gate };
1081
+ if (input.type === "planner_turn_started") {
1082
+ return withGate({ view: reduceConversation(view, input), gate }, { open: input.turnId, stopped: null });
1083
+ }
1084
+ if (cutOff(gate, input)) {
1085
+ return input.type === "planner_turn_ended" ? withGate(live, { ...gate, stopped: null }) : live;
1086
+ }
1087
+ const next = { view: reduceConversation(view, input), gate };
1088
+ return input.type === "planner_turn_ended" && input.turnId === gate.open ? withGate(next, { ...gate, open: null }) : next;
1089
+ }
1090
+ function stopTurn(view, gate) {
1091
+ if (gate.open === null) return { view, gate };
1092
+ return {
1093
+ view: reduceConversation(view, { type: "planner_turn_ended", turnId: gate.open, outcome: "stopped" }),
1094
+ gate: { open: null, stopped: gate.open }
1095
+ };
1096
+ }
1097
+
1098
+ // src/conversation/detail.ts
1099
+ function hasHiddenDetail(blocks) {
1100
+ return blocks.some((b) => b.type === "thinking" || b.type === "tool" || b.type === "subagent");
1101
+ }
1102
+
1103
+ // src/conversation/notices.ts
1104
+ function taskStartedNotice(title, runner) {
1105
+ return runner ? `Started "${title}" \xB7 ${runner}` : `Started "${title}"`;
1106
+ }
180
1107
  // Annotate the CommonJS export names for ESM import in node:
181
1108
  0 && (module.exports = {
182
1109
  CHECKPOINT_TRUNCATE_LENGTH,
1110
+ EMPTY_CONVERSATION,
1111
+ EMPTY_HOLD,
1112
+ EMPTY_TASK_LOG,
1113
+ NO_TURN,
1114
+ aheadOfDraft,
183
1115
  canMergeTasks,
184
1116
  canSetDependencies,
185
1117
  canSplitTask,
186
1118
  capConflictFiles,
187
1119
  dependencyCandidates,
188
1120
  dependentsOf,
1121
+ drainNext,
1122
+ followTurn,
1123
+ fromTranscript,
1124
+ hasHiddenDetail,
1125
+ holdPrompt,
1126
+ outputLines,
1127
+ outputPreview,
1128
+ reduceConversation,
1129
+ reduceTaskLog,
1130
+ replayTaskLog,
1131
+ runnerToolSubject,
1132
+ stopTurn,
189
1133
  summarizeToolCall,
190
- truncateCheckpointSummary
1134
+ taskStartedNotice,
1135
+ toolHeadline,
1136
+ truncateCheckpointSummary,
1137
+ unsendAll,
1138
+ unsendLatest
191
1139
  });
192
1140
  //# sourceMappingURL=plan-utils.js.map