@ordewell/core 0.5.4 → 0.5.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/dist/{ITerminalRunner-Bd-vAJnw.d.ts → ITerminalRunner-BV9Rd2o9.d.ts} +3 -1
  2. package/dist/{ITerminalRunner-ByeoLF57.d.mts → ITerminalRunner-C77ZNZS9.d.mts} +3 -1
  3. package/dist/{ModeResolver-DVJ7HV3k.d.mts → ModeResolver-D-SUFRNF.d.mts} +1 -1
  4. package/dist/{ModeResolver-Dkig8ghQ.d.ts → ModeResolver-D3XO0fT9.d.ts} +1 -1
  5. package/dist/{Task-BxQkPlXO.d.mts → Task-Vl5Zq_D-.d.mts} +168 -7
  6. package/dist/{Task-BxQkPlXO.d.ts → Task-Vl5Zq_D-.d.ts} +168 -7
  7. package/dist/{chunk-JVMDEHRQ.mjs → chunk-HD2FWPRV.mjs} +72 -37
  8. package/dist/chunk-HD2FWPRV.mjs.map +1 -0
  9. package/dist/{chunk-GWPIYDQW.mjs → chunk-KLN7ELXO.mjs} +897 -18
  10. package/dist/chunk-KLN7ELXO.mjs.map +1 -0
  11. package/dist/{chunk-XWOUIA6A.mjs → chunk-UUBGVCGJ.mjs} +2 -2
  12. package/dist/index.d.mts +320 -60
  13. package/dist/index.d.ts +320 -60
  14. package/dist/index.js +2497 -672
  15. package/dist/index.js.map +1 -1
  16. package/dist/index.mjs +1605 -659
  17. package/dist/index.mjs.map +1 -1
  18. package/dist/order-labels.d.mts +1 -1
  19. package/dist/order-labels.d.ts +1 -1
  20. package/dist/{parsing-CF_grC29.d.ts → parsing-BTP4bwkk.d.ts} +11 -3
  21. package/dist/{parsing-DRp4dPC0.d.mts → parsing-CDtRSxBY.d.mts} +11 -3
  22. package/dist/parsing.d.mts +3 -3
  23. package/dist/parsing.d.ts +3 -3
  24. package/dist/parsing.js.map +1 -1
  25. package/dist/parsing.mjs +2 -2
  26. package/dist/plan-utils-BFaPo-IT.d.ts +708 -0
  27. package/dist/plan-utils-pE4TBwxl.d.mts +708 -0
  28. package/dist/plan-utils.d.mts +3 -3
  29. package/dist/plan-utils.d.ts +3 -3
  30. package/dist/plan-utils.js +668 -7
  31. package/dist/plan-utils.js.map +1 -1
  32. package/dist/plan-utils.mjs +38 -4
  33. package/dist/testing.d.mts +5 -3
  34. package/dist/testing.d.ts +5 -3
  35. package/dist/testing.js +3 -0
  36. package/dist/testing.js.map +1 -1
  37. package/dist/testing.mjs +3 -0
  38. package/dist/testing.mjs.map +1 -1
  39. package/package.json +1 -1
  40. package/dist/chunk-GWPIYDQW.mjs.map +0 -1
  41. package/dist/chunk-JVMDEHRQ.mjs.map +0 -1
  42. package/dist/plan-utils-CkNbqAmS.d.ts +0 -329
  43. package/dist/plan-utils-CtB3_Ovf.d.mts +0 -329
  44. /package/dist/{chunk-XWOUIA6A.mjs.map → chunk-UUBGVCGJ.mjs.map} +0 -0
@@ -10,7 +10,54 @@ import {
10
10
  renumberTasks,
11
11
  stripTrailingCommas,
12
12
  updateTaskInPlan
13
- } from "./chunk-JVMDEHRQ.mjs";
13
+ } from "./chunk-HD2FWPRV.mjs";
14
+
15
+ // src/models/Usage.ts
16
+ function partedPromptUsage(parts) {
17
+ const reported = [parts.uncached, parts.cacheRead, parts.cacheWrite].filter((n) => n !== void 0);
18
+ return {
19
+ ...reported.length > 0 ? { inputTokens: reported.reduce((a, b) => a + b, 0) } : {},
20
+ ...parts.cacheRead !== void 0 ? { cachedInputTokens: parts.cacheRead } : {}
21
+ };
22
+ }
23
+ var TOKEN_FIELDS = ["inputTokens", "outputTokens", "cachedInputTokens"];
24
+ function addUsage(totals, record) {
25
+ const next = { ...totals };
26
+ for (const field of TOKEN_FIELDS) {
27
+ const reported = record[field];
28
+ if (reported !== void 0) next[field] = (totals[field] ?? 0) + reported;
29
+ }
30
+ if (record.reportedCost) {
31
+ const { amount, currency } = record.reportedCost;
32
+ next.reportedCost = { ...totals.reportedCost, [currency]: (totals.reportedCost?.[currency] ?? 0) + amount };
33
+ }
34
+ return next;
35
+ }
36
+ function addPlannerUsage(usage, record) {
37
+ const next = { ...usage, totals: addUsage(usage.totals, record) };
38
+ if (record.subagentId) {
39
+ next.bySubagent = { ...usage.bySubagent, [record.subagentId]: addUsage(usage.bySubagent?.[record.subagentId] ?? {}, record) };
40
+ return next;
41
+ }
42
+ if (record.inputTokens !== void 0) next.lastPromptTokens = record.inputTokens;
43
+ if (record.contextWindow !== void 0 && record.contextWindow > 0) next.contextWindow = record.contextWindow;
44
+ return next;
45
+ }
46
+ function isMeasured(totals) {
47
+ return totals.inputTokens !== void 0 || totals.outputTokens !== void 0 || totals.cachedInputTokens !== void 0 || Object.keys(totals.reportedCost ?? {}).length > 0;
48
+ }
49
+ function usageLine(usage) {
50
+ const contextFill = plannerContextFill(usage);
51
+ return {
52
+ totals: usage.totals,
53
+ ...usage.bySubagent ? { bySubagent: usage.bySubagent } : {},
54
+ ...contextFill ? { contextFill } : {}
55
+ };
56
+ }
57
+ function plannerContextFill(usage) {
58
+ if (usage.lastPromptTokens === void 0 || usage.contextWindow === void 0 || usage.contextWindow <= 0) return void 0;
59
+ return { usedTokens: usage.lastPromptTokens, windowTokens: usage.contextWindow };
60
+ }
14
61
 
15
62
  // src/services/ModelAllowlistResolver.ts
16
63
  function effectiveAllowlist(allowlist, runner, modelsByRunner) {
@@ -215,37 +262,37 @@ function taskOpsProtocol(executionNote = "") {
215
262
  '"rearm" puts a failed OR completed task back to pending \u2014 verdict and output summary are cleared, any dependents it had blocked are released, and it may carry field changes (e.g. a corrected "prompt") applied in the same op. A running task cannot be re-armed. Never rearm a task just to relabel it \u2014 only when it should actually run again.'
216
263
  ];
217
264
  }
218
- function textHasTaskOps(text) {
219
- return text.includes(`"${TASK_OPS_ENVELOPE_KEY}"`);
265
+ function textHasTaskOps(text2) {
266
+ return text2.includes(`"${TASK_OPS_ENVELOPE_KEY}"`);
220
267
  }
221
- function parseTaskOpsJson(text) {
222
- const { matches, fallback } = extractObjectsWithKey(text, TASK_OPS_ENVELOPE_KEY);
268
+ function parseTaskOpsJson(text2) {
269
+ const { matches, fallback } = extractObjectsWithKey(text2, TASK_OPS_ENVELOPE_KEY);
223
270
  const candidates = matches.length > 0 ? [...matches].reverse() : [fallback.json];
224
271
  let lastError = null;
225
272
  for (const json of candidates) {
226
273
  try {
227
- return parseTaskOpsObject(json, text);
274
+ return parseTaskOpsObject(json, text2);
228
275
  } catch (err) {
229
276
  if (!(err instanceof PlanParseError)) throw err;
230
277
  if (!lastError) lastError = err;
231
278
  }
232
279
  }
233
- throw lastError ?? new PlanParseError("No JSON object found in task-ops reply", text);
280
+ throw lastError ?? new PlanParseError("No JSON object found in task-ops reply", text2);
234
281
  }
235
- function parseTaskOpsObject(json, text) {
282
+ function parseTaskOpsObject(json, text2) {
236
283
  let parsed;
237
284
  try {
238
285
  parsed = JSON.parse(escapeControlCharsInStrings(stripTrailingCommas(json)));
239
286
  } catch (err) {
240
- throw new PlanParseError(`Task-ops JSON is invalid: ${err instanceof Error ? err.message : String(err)}`, text);
287
+ throw new PlanParseError(`Task-ops JSON is invalid: ${err instanceof Error ? err.message : String(err)}`, text2);
241
288
  }
242
289
  const ops = parsed.taskOps;
243
290
  if (!Array.isArray(ops) || ops.length === 0) {
244
- throw new PlanParseError('"taskOps" must be a non-empty array', text);
291
+ throw new PlanParseError('"taskOps" must be a non-empty array', text2);
245
292
  }
246
293
  for (const op of ops) {
247
294
  if (typeof op !== "object" || op === null || typeof op.op !== "string") {
248
- throw new PlanParseError('Every task op needs an "op" field (update | add | remove | reorder | merge | split)', text);
295
+ throw new PlanParseError('Every task op needs an "op" field (update | add | remove | reorder | merge | split)', text2);
249
296
  }
250
297
  }
251
298
  return ops;
@@ -274,6 +321,27 @@ function resolveRef(ref, originalScope, liveScope, handleOwner, handleId, opInde
274
321
  if (byTitle) return { id: byTitle.id };
275
322
  return { error: `task "${s}" not found` };
276
323
  }
324
+ function taskOpRefs(op) {
325
+ switch (op.op) {
326
+ case "update":
327
+ case "remove":
328
+ case "split":
329
+ case "rearm":
330
+ return [op.taskId];
331
+ case "merge":
332
+ case "reorder":
333
+ return op.taskIds;
334
+ case "add":
335
+ return [];
336
+ }
337
+ }
338
+ function refMatchesTask(ref, task) {
339
+ if (typeof ref !== "string" && typeof ref !== "number") return false;
340
+ const s = String(ref).trim();
341
+ if (task.id === s) return true;
342
+ const orderStr = s.startsWith("#") ? s.slice(1) : s;
343
+ return /^\d+$/.test(orderStr) && task.order === Number(orderStr) || task.title === s;
344
+ }
277
345
  function refCollidesWithExisting(name, originalFlatAll) {
278
346
  if (originalFlatAll.some((t) => t.id === name)) return true;
279
347
  const orderStr = name.startsWith("#") ? name.slice(1) : name;
@@ -796,9 +864,9 @@ function applyTaskOps(currentTasks, ops, runners, catalog) {
796
864
  }
797
865
 
798
866
  // src/services/researchStepSummary.ts
799
- function ellipsize(text, max) {
800
- const oneLine = text.replace(/\s+/g, " ").trim();
801
- return oneLine.length > max ? `${oneLine.slice(0, max)}\u2026` : oneLine;
867
+ function ellipsize(text2, max) {
868
+ const oneLine2 = text2.replace(/\s+/g, " ").trim();
869
+ return oneLine2.length > max ? `${oneLine2.slice(0, max)}\u2026` : oneLine2;
802
870
  }
803
871
  function summarizeToolCall(tool, argsJson, toolLabel) {
804
872
  const display = toolLabel?.trim() || tool;
@@ -815,8 +883,8 @@ function summarizeToolCall(tool, argsJson, toolLabel) {
815
883
  try {
816
884
  const args = JSON.parse(argsJson);
817
885
  const prompt = typeof args.prompt === "string" ? args.prompt : "";
818
- const oneLine = prompt.replace(/\s+/g, " ").trim();
819
- return `spawn: "${oneLine.slice(0, 60)}${oneLine.length > 60 ? "\u2026" : ""}"`;
886
+ const oneLine2 = prompt.replace(/\s+/g, " ").trim();
887
+ return `spawn: "${oneLine2.slice(0, 60)}${oneLine2.length > 60 ? "\u2026" : ""}"`;
820
888
  } catch {
821
889
  return "spawn_research_agent";
822
890
  }
@@ -918,7 +986,796 @@ function truncateCheckpointSummary(summary) {
918
986
  return firstLine.slice(0, CHECKPOINT_TRUNCATE_LENGTH - 1) + "\u2026";
919
987
  }
920
988
 
989
+ // src/services/terminalRender.ts
990
+ 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;
991
+ function flattenTerminalOutput(raw) {
992
+ return raw.replace(ANSI_OR_CTRL_RE, "").replace(/[─-▟]/g, "").replace(/\s+/g, "");
993
+ }
994
+ function renderTerminalOutput(raw) {
995
+ const rows = /* @__PURE__ */ new Map();
996
+ let row = 1;
997
+ let col = 1;
998
+ let savedRow = 1;
999
+ let savedCol = 1;
1000
+ const cells = (r) => {
1001
+ let line = rows.get(r);
1002
+ if (!line) {
1003
+ line = [];
1004
+ rows.set(r, line);
1005
+ }
1006
+ return line;
1007
+ };
1008
+ const firstParam = (params, fallback = 1) => params[0] || fallback;
1009
+ const eraseLine = (mode) => {
1010
+ const line = cells(row);
1011
+ if (mode === 2) {
1012
+ rows.set(row, []);
1013
+ } else if (mode === 1) {
1014
+ for (let c = 0; c < col; c++) line[c] = " ";
1015
+ } else {
1016
+ line.length = Math.max(0, col - 1);
1017
+ }
1018
+ };
1019
+ for (let i = 0; i < raw.length; ) {
1020
+ const ch = raw[i];
1021
+ if (ch === "\x1B") {
1022
+ const kind = raw[i + 1];
1023
+ if (kind === "[") {
1024
+ let end = i + 2;
1025
+ while (end < raw.length) {
1026
+ const code = raw.charCodeAt(end);
1027
+ if (code >= 64 && code <= 126) break;
1028
+ end++;
1029
+ }
1030
+ if (end >= raw.length) break;
1031
+ const final = raw[end];
1032
+ const body = raw.slice(i + 2, end).replace(/^[?<>=!]+/, "");
1033
+ const params = body.split(";").map((p) => Number.parseInt(p, 10) || 0);
1034
+ switch (final) {
1035
+ case "H":
1036
+ case "f":
1037
+ row = params[0] || 1;
1038
+ col = params[1] || 1;
1039
+ break;
1040
+ case "G":
1041
+ col = firstParam(params);
1042
+ break;
1043
+ case "d":
1044
+ row = firstParam(params);
1045
+ break;
1046
+ case "A":
1047
+ row = Math.max(1, row - firstParam(params));
1048
+ break;
1049
+ case "B":
1050
+ row += firstParam(params);
1051
+ break;
1052
+ case "C":
1053
+ col += firstParam(params);
1054
+ break;
1055
+ case "D":
1056
+ col = Math.max(1, col - firstParam(params));
1057
+ break;
1058
+ case "E":
1059
+ row += firstParam(params);
1060
+ col = 1;
1061
+ break;
1062
+ case "F":
1063
+ row = Math.max(1, row - firstParam(params));
1064
+ col = 1;
1065
+ break;
1066
+ case "s":
1067
+ savedRow = row;
1068
+ savedCol = col;
1069
+ break;
1070
+ case "u":
1071
+ row = savedRow;
1072
+ col = savedCol;
1073
+ break;
1074
+ case "K":
1075
+ eraseLine(params[0] || 0);
1076
+ break;
1077
+ case "J":
1078
+ if ((params[0] || 0) === 2 || (params[0] || 0) === 3) rows.clear();
1079
+ break;
1080
+ case "X": {
1081
+ const line = cells(row);
1082
+ for (let c = 0; c < firstParam(params); c++) line[col - 1 + c] = " ";
1083
+ break;
1084
+ }
1085
+ case "P": {
1086
+ cells(row).splice(col - 1, firstParam(params));
1087
+ break;
1088
+ }
1089
+ case "@": {
1090
+ cells(row).splice(col - 1, 0, ...Array(firstParam(params)).fill(" "));
1091
+ break;
1092
+ }
1093
+ default:
1094
+ break;
1095
+ }
1096
+ i = end + 1;
1097
+ continue;
1098
+ }
1099
+ if (kind === "]" || kind === "P" || kind === "^" || kind === "_") {
1100
+ let end = i + 2;
1101
+ while (end < raw.length && raw[end] !== "\x07" && !(raw[end] === "\x1B" && raw[end + 1] === "\\")) end++;
1102
+ if (end >= raw.length) break;
1103
+ i = raw[end] === "\x07" ? end + 1 : end + 2;
1104
+ continue;
1105
+ }
1106
+ if (kind === "7") {
1107
+ savedRow = row;
1108
+ savedCol = col;
1109
+ } else if (kind === "8") {
1110
+ row = savedRow;
1111
+ col = savedCol;
1112
+ } else if (kind === "c") {
1113
+ rows.clear();
1114
+ row = 1;
1115
+ col = 1;
1116
+ }
1117
+ i += kind === "(" || kind === ")" ? 3 : 2;
1118
+ continue;
1119
+ }
1120
+ if (ch === "\r") {
1121
+ col = 1;
1122
+ i++;
1123
+ continue;
1124
+ }
1125
+ if (ch === "\n") {
1126
+ row++;
1127
+ i++;
1128
+ continue;
1129
+ }
1130
+ if (ch === "\b") {
1131
+ col = Math.max(1, col - 1);
1132
+ i++;
1133
+ continue;
1134
+ }
1135
+ if (ch === " ") {
1136
+ col += 8 - (col - 1) % 8;
1137
+ i++;
1138
+ continue;
1139
+ }
1140
+ if (ch < " " || ch === "\x7F") {
1141
+ i++;
1142
+ continue;
1143
+ }
1144
+ cells(row)[col - 1] = ch;
1145
+ col++;
1146
+ i++;
1147
+ }
1148
+ const populated = [...rows.keys()].sort((a, b) => a - b);
1149
+ return populated.map((r) => cells(r).join("")).join("\n");
1150
+ }
1151
+ function renderCleanCapture(raw, doneToken) {
1152
+ const rendered = renderTerminalOutput(raw).replace(/[\s─-▟]+$/gm, "");
1153
+ if (!doneToken) return rendered.trim();
1154
+ const lines = rendered.split("\n");
1155
+ const flat = (s) => flattenTerminalOutput(s);
1156
+ for (let i = 0; i < lines.length; i++) {
1157
+ const own = flat(lines[i]).includes(doneToken);
1158
+ if (own) return lines.slice(0, i).join("\n").trim();
1159
+ const window = flat(lines[i]) + (i + 1 < lines.length ? flat(lines[i + 1]) : "");
1160
+ if (window.includes(doneToken)) return lines.slice(0, i + 1).join("\n").trim();
1161
+ }
1162
+ return rendered.trim();
1163
+ }
1164
+
1165
+ // src/conversation/format.ts
1166
+ var DISPLAY_NAMES = {
1167
+ read_file: "Read",
1168
+ read_files: "Read",
1169
+ list_dir: "List",
1170
+ glob: "Glob",
1171
+ grep: "Grep",
1172
+ find_symbol: "Symbol",
1173
+ bash: "Bash",
1174
+ fetch: "Fetch",
1175
+ web_search: "WebSearch",
1176
+ spawn_research_agent: "Agent"
1177
+ };
1178
+ var HINT_FIELDS = ["file_path", "filePath", "path", "url", "pattern", "query", "command", "description", "prompt"];
1179
+ function parseArgs(args) {
1180
+ try {
1181
+ const parsed = JSON.parse(args);
1182
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
1183
+ } catch {
1184
+ return null;
1185
+ }
1186
+ }
1187
+ function oneLine(text2) {
1188
+ return text2.replace(/\s+/g, " ").trim();
1189
+ }
1190
+ function firstLineOf(command) {
1191
+ const lines = command.trim().split(/\r?\n/);
1192
+ const more = lines.length - 1;
1193
+ return more > 0 ? `${lines[0]} \u2026 +${more} line${more === 1 ? "" : "s"}` : lines[0];
1194
+ }
1195
+ function text(value) {
1196
+ return typeof value === "string" ? value : "";
1197
+ }
1198
+ function searchArg(pattern, path, include = "") {
1199
+ return `${pattern}${path ? ` in ${path}` : ""}${include ? ` (${include})` : ""}`;
1200
+ }
1201
+ function hintArg(args) {
1202
+ for (const field of HINT_FIELDS) {
1203
+ const value = text(args[field]);
1204
+ if (value) return field === "command" ? firstLineOf(value) : oneLine(value);
1205
+ }
1206
+ const firstText = Object.values(args).find((v) => typeof v === "string" && v.trim() !== "");
1207
+ return firstText ? oneLine(firstText) : "";
1208
+ }
1209
+ function keyArgOf(tool, args) {
1210
+ switch (tool) {
1211
+ case "bash":
1212
+ return firstLineOf(text(args.command));
1213
+ case "read_file":
1214
+ case "list_dir":
1215
+ return text(args.path);
1216
+ case "read_files":
1217
+ return Array.isArray(args.paths) ? args.paths.map(String).join(", ") : "";
1218
+ case "glob":
1219
+ return searchArg(text(args.pattern), text(args.path));
1220
+ case "grep":
1221
+ return searchArg(text(args.pattern), text(args.path), text(args.include));
1222
+ case "find_symbol":
1223
+ return `${text(args.symbol)}${text(args.language) ? ` [${text(args.language)}]` : ""}`;
1224
+ case "fetch":
1225
+ return text(args.url);
1226
+ case "web_search":
1227
+ return oneLine(text(args.query));
1228
+ case "spawn_research_agent":
1229
+ return oneLine(text(args.prompt));
1230
+ default:
1231
+ return hintArg(args);
1232
+ }
1233
+ }
1234
+ function toolHeadline(tool, args, toolLabel) {
1235
+ const name = toolLabel?.trim() || DISPLAY_NAMES[tool] || tool;
1236
+ const parsed = parseArgs(args);
1237
+ return { name, keyArg: parsed ? keyArgOf(tool, parsed) : oneLine(args) };
1238
+ }
1239
+ function outputLines(output) {
1240
+ const lines = output.replace(/\r\n?/g, "\n").replace(ANSI_OR_CTRL_RE, "").split("\n");
1241
+ while (lines.length > 0 && lines[lines.length - 1].trim() === "") lines.pop();
1242
+ return lines;
1243
+ }
1244
+ function outputPreview(output, maxLines) {
1245
+ const lines = outputLines(output);
1246
+ const shown = lines.slice(0, Math.max(0, maxLines));
1247
+ return { lines: shown, hiddenLineCount: lines.length - shown.length };
1248
+ }
1249
+
1250
+ // src/conversation/records.ts
1251
+ function settledMessage(id, role, text2, turnId) {
1252
+ return { type: "message", id, role, text: text2, streaming: false, ...turnId ? { turnId } : {} };
1253
+ }
1254
+ function subagentBlock(id, { toolCallId, model, usage, turnId, ...fields }) {
1255
+ return {
1256
+ type: "subagent",
1257
+ id,
1258
+ ...fields,
1259
+ ...toolCallId ? { toolCallId } : {},
1260
+ ...model ? { model } : {},
1261
+ ...usage ? { usage } : {},
1262
+ ...turnId ? { turnId } : {}
1263
+ };
1264
+ }
1265
+ function usageBlock(id, { totals, bySubagent, contextFill }) {
1266
+ return { type: "usage", id, totals, ...bySubagent ? { bySubagent } : {}, ...contextFill ? { contextFill } : {} };
1267
+ }
1268
+ var STATUS_OF_OUTCOME = {
1269
+ success: "ok",
1270
+ failure: "error",
1271
+ refused: "denied",
1272
+ denied: "denied",
1273
+ not_executed: "interrupted"
1274
+ };
1275
+ function settledTool(call, step) {
1276
+ return { ...call, status: STATUS_OF_OUTCOME[step.outcome], outcome: step.outcome, output: step.result, outputLineCount: outputLines(step.result).length };
1277
+ }
1278
+ function pendingTool(id, { tool, toolLabel, args, toolCallId, turnId }) {
1279
+ return {
1280
+ type: "tool",
1281
+ id,
1282
+ tool,
1283
+ headline: toolHeadline(tool, args, toolLabel),
1284
+ args,
1285
+ status: "pending",
1286
+ output: "",
1287
+ outputLineCount: 0,
1288
+ ...toolCallId ? { toolCallId } : {},
1289
+ ...toolLabel ? { toolLabel } : {},
1290
+ ...turnId ? { turnId } : {}
1291
+ };
1292
+ }
1293
+ function toolFromStep(id, step, turnId) {
1294
+ return settledTool(pendingTool(id, { ...step, turnId }), step);
1295
+ }
1296
+ function planMarker(content) {
1297
+ const count = /(\d+) tasks?\b/.exec(content);
1298
+ return { status: content.startsWith("Plan updated") ? "updated" : "generated", ...count ? { taskCount: Number(count[1]) } : {} };
1299
+ }
1300
+
1301
+ // src/conversation/reduce.ts
1302
+ var EMPTY_CONVERSATION = { blocks: [], nextId: 1 };
1303
+ function findLastIndex(items, match) {
1304
+ for (let i = items.length - 1; i >= 0; i--) if (match(items[i])) return i;
1305
+ return -1;
1306
+ }
1307
+ function replaceAt(items, index, item) {
1308
+ const next = items.slice();
1309
+ next[index] = item;
1310
+ return next;
1311
+ }
1312
+ function insertTop(blocks, block) {
1313
+ const last = blocks[blocks.length - 1];
1314
+ return last?.type === "usage" ? [...blocks.slice(0, -1), block, last] : [...blocks, block];
1315
+ }
1316
+ function append(view, make) {
1317
+ return { ...view, blocks: insertTop(view.blocks, make(`b${view.nextId}`)), nextId: view.nextId + 1 };
1318
+ }
1319
+ function subagentAt(view, lane) {
1320
+ const block = view.blocks[lane];
1321
+ if (block.type !== "subagent") throw new Error(`block ${lane} is not a subagent`);
1322
+ return block;
1323
+ }
1324
+ function laneBlocks(view, lane) {
1325
+ return lane === null ? view.blocks : subagentAt(view, lane).children;
1326
+ }
1327
+ function setChildren(view, lane, children) {
1328
+ return { ...view, blocks: replaceAt(view.blocks, lane, { ...subagentAt(view, lane), children }) };
1329
+ }
1330
+ function laneReplace(view, lane, index, block) {
1331
+ if (lane === null) return { ...view, blocks: replaceAt(view.blocks, index, block) };
1332
+ return setChildren(view, lane, replaceAt(subagentAt(view, lane).children, index, block));
1333
+ }
1334
+ function laneAppend(view, lane, make) {
1335
+ if (lane === null) return append(view, make);
1336
+ const children = [...subagentAt(view, lane).children, make(`b${view.nextId}`)];
1337
+ return { ...setChildren(view, lane, children), nextId: view.nextId + 1 };
1338
+ }
1339
+ function isStreaming(block) {
1340
+ return (block.type === "message" || block.type === "thinking") && block.streaming;
1341
+ }
1342
+ function sealed(block) {
1343
+ return isStreaming(block) ? { ...block, streaming: false } : block;
1344
+ }
1345
+ function sealLane(view, lane, keep) {
1346
+ const blocks = laneBlocks(view, lane);
1347
+ if (!blocks.some((b, i) => i !== keep && isStreaming(b))) return view;
1348
+ if (lane === null) return { ...view, blocks: view.blocks.map((b, i) => i === keep ? b : sealed(b)) };
1349
+ return setChildren(view, lane, subagentAt(view, lane).children.map((b, i) => i === keep ? b : sealed(b)));
1350
+ }
1351
+ function appendOutput(view, lane, make) {
1352
+ const next = laneAppend(view, lane, make);
1353
+ return sealLane(next, lane, findLastIndex(laneBlocks(next, lane), (b) => b.type !== "usage"));
1354
+ }
1355
+ function isUnsettledSegment(block, turnId) {
1356
+ return block.type === "message" && block.turnId === turnId && block.segmentId !== void 0;
1357
+ }
1358
+ function isBuildingPlan(block, turnId) {
1359
+ return block.type === "plan" && block.status === "building" && block.turnId === turnId;
1360
+ }
1361
+ function finalSegmentIndex(blocks, turnId, pastPlan = false) {
1362
+ for (let i = blocks.length - 1; i >= 0; i--) {
1363
+ const block = blocks[i];
1364
+ if (block.type === "usage" || block.type === "thinking" || block.type === "approval" || pastPlan && block.type === "plan") continue;
1365
+ if (block.turnId !== turnId) continue;
1366
+ return isUnsettledSegment(block, turnId) ? i : -1;
1367
+ }
1368
+ return -1;
1369
+ }
1370
+ function openTurn(view, turnId, prompt) {
1371
+ const i = findLastIndex(view.blocks, (b) => b.type === "message" && b.role === "user");
1372
+ const sent = view.blocks[i];
1373
+ if (sent?.type === "message" && sent.turnId === void 0 && sent.text === prompt) {
1374
+ return { ...view, blocks: replaceAt(view.blocks, i, { ...sent, turnId }) };
1375
+ }
1376
+ return append(view, (id) => settledMessage(id, "user", prompt, turnId));
1377
+ }
1378
+ function streamText(view, { turnId, segmentId, text: text2 }) {
1379
+ const i = findLastIndex(view.blocks, (b) => isUnsettledSegment(b, turnId) && b.segmentId === segmentId);
1380
+ const segment = view.blocks[i];
1381
+ if (segment?.type === "message") {
1382
+ return sealLane(laneReplace(view, null, i, { ...segment, text: segment.text + text2, streaming: true }), null, i);
1383
+ }
1384
+ return appendOutput(view, null, (id) => ({ type: "message", id, role: "planner", text: text2, streaming: true, turnId, segmentId }));
1385
+ }
1386
+ function dropBuildingPlan(view, turnId, segmentId) {
1387
+ const blocks = view.blocks.filter((b) => !(isBuildingPlan(b, turnId) && (segmentId === void 0 || b.segmentId === segmentId)));
1388
+ return blocks.length === view.blocks.length ? view : { ...view, blocks };
1389
+ }
1390
+ function settleReply(view, { content, turnId }) {
1391
+ if (turnId !== void 0) {
1392
+ const i = finalSegmentIndex(view.blocks, turnId);
1393
+ if (i >= 0) {
1394
+ return dropBuildingPlan({ ...view, blocks: replaceAt(view.blocks, i, settledMessage(view.blocks[i].id, "planner", content, turnId)) }, turnId);
1395
+ }
1396
+ }
1397
+ return append(dropBuildingPlan(view, turnId), (id) => settledMessage(id, "planner", content, turnId));
1398
+ }
1399
+ function retractText(view, { turnId, segmentId }) {
1400
+ const blocks = view.blocks.filter((b) => !(isUnsettledSegment(b, turnId) && (segmentId === void 0 || b.segmentId === segmentId)));
1401
+ return dropBuildingPlan(blocks.length === view.blocks.length ? view : { ...view, blocks }, turnId, segmentId);
1402
+ }
1403
+ function subagentLane(view, subagentId, turnId) {
1404
+ const existing = findLastIndex(view.blocks, (b) => b.type === "subagent" && b.subagentId === subagentId);
1405
+ if (existing >= 0) return [view, existing];
1406
+ const spawn = findLastIndex(view.blocks, (b) => b.type === "tool" && (b.spawns === subagentId || b.toolCallId === subagentId));
1407
+ const call = view.blocks[spawn];
1408
+ if (call?.type === "tool") {
1409
+ const block = subagentBlock(call.id, {
1410
+ subagentId,
1411
+ brief: call.headline.keyArg,
1412
+ status: "running",
1413
+ children: [],
1414
+ digest: "",
1415
+ toolCallId: call.toolCallId,
1416
+ turnId: call.turnId
1417
+ });
1418
+ return [{ ...view, blocks: replaceAt(view.blocks, spawn, block) }, spawn];
1419
+ }
1420
+ const next = append(view, (id) => subagentBlock(id, { subagentId, brief: "", status: "running", children: [], digest: "", turnId }));
1421
+ return [next, findLastIndex(next.blocks, (b) => b.type === "subagent" && b.subagentId === subagentId)];
1422
+ }
1423
+ function updateSubagent(view, subagentId, turnId, update) {
1424
+ const [next, lane] = subagentLane(view, subagentId, turnId);
1425
+ return { ...next, blocks: replaceAt(next.blocks, lane, update(subagentAt(next, lane))) };
1426
+ }
1427
+ function startSubagent(view, { subagentId, brief, model, turnId }) {
1428
+ return updateSubagent(view, subagentId, turnId, (block) => ({ ...block, ...brief ? { brief } : {}, ...model ? { model } : {} }));
1429
+ }
1430
+ function finishSubagent(view, { subagentId, outcome, digest, usage, turnId }) {
1431
+ return updateSubagent(view, subagentId, turnId, (block) => ({
1432
+ ...block,
1433
+ status: outcome,
1434
+ digest,
1435
+ children: block.children.map(sealed),
1436
+ ...usage ? { usage } : {}
1437
+ }));
1438
+ }
1439
+ function think(view, text2, turnId, segmentId, subagentId) {
1440
+ const [placed, lane] = subagentId ? subagentLane(view, subagentId, turnId) : [view, null];
1441
+ const blocks = laneBlocks(placed, lane);
1442
+ const lastIndex = findLastIndex(blocks, (b) => b.type !== "usage");
1443
+ const last = blocks[lastIndex];
1444
+ if (last?.type === "thinking" && last.streaming && last.segmentId === segmentId) {
1445
+ return laneReplace(placed, lane, lastIndex, { ...last, text: last.text + text2 });
1446
+ }
1447
+ return appendOutput(placed, lane, (id) => ({
1448
+ type: "thinking",
1449
+ id,
1450
+ text: text2,
1451
+ streaming: true,
1452
+ ...turnId ? { turnId } : {},
1453
+ ...segmentId ? { segmentId } : {},
1454
+ ...subagentId ? { subagentId } : {}
1455
+ }));
1456
+ }
1457
+ function announceTool(view, call) {
1458
+ const spawns = call.tool === "spawn_research_agent" ? call.subagentId : void 0;
1459
+ const [placed, lane] = call.subagentId && !spawns ? subagentLane(view, call.subagentId, call.turnId) : [view, null];
1460
+ return appendOutput(placed, lane, (id) => ({ ...pendingTool(id, call), ...spawns ? { spawns } : {} }));
1461
+ }
1462
+ function isPendingCallOf(block, step) {
1463
+ if (block.type !== "tool" || block.status !== "pending") return false;
1464
+ return step.toolCallId ? block.toolCallId === step.toolCallId : block.toolCallId === void 0 && block.tool === step.tool;
1465
+ }
1466
+ function settleTool(view, { step, turnId }) {
1467
+ const [placed, lane] = step.subagentId ? subagentLane(view, step.subagentId, turnId) : [view, null];
1468
+ const blocks = laneBlocks(placed, lane);
1469
+ const i = findLastIndex(blocks, (b) => isPendingCallOf(b, step));
1470
+ const pending = blocks[i];
1471
+ if (pending?.type === "tool") return laneReplace(placed, lane, i, settledTool(pending, step));
1472
+ if (lane === null && step.toolCallId && blocks.some((b) => b.type === "subagent" && b.toolCallId === step.toolCallId)) return view;
1473
+ return laneAppend(placed, lane, (id) => toolFromStep(id, step, turnId));
1474
+ }
1475
+ function streamPlan(view, { token, turnId, segmentId }) {
1476
+ const i = findLastIndex(view.blocks, (b) => isBuildingPlan(b, turnId));
1477
+ const building = view.blocks[i];
1478
+ if (building?.type === "plan" && building.segmentId === segmentId) {
1479
+ return { ...view, blocks: replaceAt(view.blocks, i, { ...building, text: building.text + token }) };
1480
+ }
1481
+ return append(dropBuildingPlan(view, turnId), (id) => ({
1482
+ type: "plan",
1483
+ id,
1484
+ status: "building",
1485
+ text: token,
1486
+ ...turnId ? { turnId } : {},
1487
+ ...segmentId ? { segmentId } : {}
1488
+ }));
1489
+ }
1490
+ function markPlan(view, content, turnId) {
1491
+ const marker = planMarker(content);
1492
+ const i = findLastIndex(view.blocks, (b) => isBuildingPlan(b, turnId));
1493
+ const building = view.blocks[i];
1494
+ if (building?.type === "plan") {
1495
+ const settled = { type: "plan", id: building.id, ...marker, text: "", ...building.turnId ? { turnId: building.turnId } : {} };
1496
+ return { ...view, blocks: replaceAt(view.blocks, i, settled) };
1497
+ }
1498
+ return append(view, (id) => ({ type: "plan", id, text: "", ...marker }));
1499
+ }
1500
+ function requestApproval(view, { id: approvalId, kind, subject, scope, detail, turnId }) {
1501
+ return append(view, (id) => ({
1502
+ type: "approval",
1503
+ id,
1504
+ approvalId,
1505
+ kind,
1506
+ subject,
1507
+ scope,
1508
+ status: "pending",
1509
+ ...detail ? { detail } : {},
1510
+ ...turnId ? { turnId } : {}
1511
+ }));
1512
+ }
1513
+ function settleApproval(view, { id, granted }) {
1514
+ const i = findLastIndex(view.blocks, (b) => b.type === "approval" && b.approvalId === id);
1515
+ const request = view.blocks[i];
1516
+ if (request?.type !== "approval") return view;
1517
+ return { ...view, blocks: replaceAt(view.blocks, i, { ...request, status: granted ? "granted" : "denied", decidedBy: "asked" }) };
1518
+ }
1519
+ function decideApproval(view, { kind, subject, scope, detail, granted, source }) {
1520
+ return append(view, (id) => ({
1521
+ type: "approval",
1522
+ id,
1523
+ kind,
1524
+ subject,
1525
+ scope,
1526
+ status: granted ? "granted" : "denied",
1527
+ decidedBy: source,
1528
+ ...detail ? { detail } : {}
1529
+ }));
1530
+ }
1531
+ function reportUsage(view, message) {
1532
+ if (!isMeasured(message.totals)) return view;
1533
+ const last = view.blocks[view.blocks.length - 1];
1534
+ const line = usageBlock(last?.type === "usage" ? last.id : `b${view.nextId}`, message);
1535
+ if (last?.type === "usage") return { ...view, blocks: replaceAt(view.blocks, view.blocks.length - 1, line) };
1536
+ return { ...view, blocks: [...view.blocks, line], nextId: view.nextId + 1 };
1537
+ }
1538
+ function closeBlock(block, interrupted) {
1539
+ return interrupted && block.type === "tool" && block.status === "pending" ? { ...block, status: "interrupted" } : sealed(block);
1540
+ }
1541
+ function closeSubagent(block, cut) {
1542
+ const children = block.children.map((c) => closeBlock(c, cut !== null));
1543
+ const status = cut && block.status === "running" ? cut : block.status;
1544
+ return status === block.status && children.every((c, i) => c === block.children[i]) ? block : { ...block, status, children };
1545
+ }
1546
+ function endTurn(view, { turnId, outcome }) {
1547
+ let next = dropBuildingPlan(view, turnId);
1548
+ const planText = outcome === "plan" ? finalSegmentIndex(next.blocks, turnId, true) : -1;
1549
+ if (planText >= 0) next = { ...next, blocks: next.blocks.filter((_, i) => i !== planText) };
1550
+ const cut = outcome === "stopped" ? "stopped" : outcome === "error" ? "failed" : null;
1551
+ const blocks = next.blocks.map((b) => b.type === "subagent" ? closeSubagent(b, cut) : closeBlock(b, cut !== null));
1552
+ return blocks.every((b, i) => b === next.blocks[i]) ? next : { ...next, blocks };
1553
+ }
1554
+ function markCompaction(view, summary) {
1555
+ const i = findLastIndex(view.blocks, (b) => b.type === "message" && b.role === "planner" && b.turnId === void 0 && b.text === summary);
1556
+ const announced = view.blocks[i];
1557
+ if (announced?.type === "message") return { ...view, blocks: replaceAt(view.blocks, i, { ...announced, role: "system" }) };
1558
+ return append(view, (id) => settledMessage(id, "system", summary));
1559
+ }
1560
+ function syncTranscript(view, { plan, turnId }) {
1561
+ const history = plan.conversationHistory ?? [];
1562
+ const committed = findLastIndex(history, (e) => e.kind === "plan_generated");
1563
+ let next = view;
1564
+ let latest = view.transcriptAt;
1565
+ for (const [i, entry] of history.entries()) {
1566
+ const isNew = view.transcriptAt === void 0 || entry.timestamp > view.transcriptAt;
1567
+ if (isNew && entry.kind === "plan_generated") next = markPlan(next, entry.content, i === committed ? turnId : void 0);
1568
+ if (isNew && entry.kind === "system") next = append(next, (id) => settledMessage(id, "system", entry.content));
1569
+ if (isNew && entry.kind === "compaction") next = markCompaction(next, entry.content);
1570
+ if (latest === void 0 || entry.timestamp > latest) latest = entry.timestamp;
1571
+ }
1572
+ return next === view && latest === view.transcriptAt ? view : { ...next, transcriptAt: latest };
1573
+ }
1574
+ function reduceConversation(view, input) {
1575
+ switch (input.type) {
1576
+ case "local_entry":
1577
+ return append(view, (id) => settledMessage(id, input.role, input.text));
1578
+ case "planner_turn_started":
1579
+ return input.prompt === void 0 ? view : openTurn(view, input.turnId, input.prompt);
1580
+ case "planner_text_delta":
1581
+ return streamText(view, input);
1582
+ case "planner_message":
1583
+ return settleReply(view, input);
1584
+ case "planner_text_retracted":
1585
+ return retractText(view, input);
1586
+ case "planner_thinking_delta":
1587
+ return think(view, input.text, input.turnId, input.segmentId, input.subagentId);
1588
+ case "research_step":
1589
+ return announceTool(view, input);
1590
+ case "research_step_done":
1591
+ return settleTool(view, input);
1592
+ case "subagent_started":
1593
+ return startSubagent(view, input);
1594
+ case "subagent_finished":
1595
+ return finishSubagent(view, input);
1596
+ case "plan_token":
1597
+ return streamPlan(view, input);
1598
+ case "plan_generated":
1599
+ return syncTranscript(view, input);
1600
+ case "planner_turn_ended":
1601
+ return endTurn(view, input);
1602
+ case "approval_request":
1603
+ return requestApproval(view, input);
1604
+ case "approval_settled":
1605
+ return settleApproval(view, input);
1606
+ case "approval_decided":
1607
+ return decideApproval(view, input);
1608
+ case "planner_usage":
1609
+ return reportUsage(view, input);
1610
+ default:
1611
+ return view;
1612
+ }
1613
+ }
1614
+
1615
+ // src/conversation/transcript.ts
1616
+ var USER = 0;
1617
+ var RESEARCH = 1;
1618
+ var SETTLED = 2;
1619
+ function fromEntry(entry) {
1620
+ if (entry.kind === "plan_generated") return (id) => ({ type: "plan", id: id(), text: "", ...planMarker(entry.content) });
1621
+ const role = entry.kind === "system" || entry.kind === "compaction" ? "system" : entry.role === "user" ? "user" : "planner";
1622
+ return (id) => settledMessage(id(), role, entry.content);
1623
+ }
1624
+ function spawnBrief(step) {
1625
+ try {
1626
+ const args = JSON.parse(step.args);
1627
+ const prompt = args && typeof args === "object" ? args.prompt : void 0;
1628
+ return typeof prompt === "string" ? prompt.trim() : void 0;
1629
+ } catch {
1630
+ return void 0;
1631
+ }
1632
+ }
1633
+ function spawnedBy(step, unclaimed) {
1634
+ const byId = unclaimed.find((e) => e.subagentId === step.toolCallId);
1635
+ if (byId) return byId;
1636
+ if (step.tool !== "spawn_research_agent") return void 0;
1637
+ const brief = spawnBrief(step);
1638
+ return brief === void 0 ? void 0 : unclaimed.find((e) => e.brief === brief);
1639
+ }
1640
+ function research(log) {
1641
+ const subagents = log.filter((e) => "type" in e && e.type === "subagent");
1642
+ const ownSubagent = new Set(subagents.map((e) => e.subagentId));
1643
+ const unclaimed = [...subagents];
1644
+ const spawnCall = /* @__PURE__ */ new Map();
1645
+ const placed = [];
1646
+ for (const entry of log) {
1647
+ if ("type" in entry) {
1648
+ if (entry.type === "system") placed.push({ at: entry.timestamp, rank: RESEARCH, build: (id) => settledMessage(id(), "system", entry.content) });
1649
+ continue;
1650
+ }
1651
+ if (entry.subagentId && ownSubagent.has(entry.subagentId)) continue;
1652
+ const spawned = spawnedBy(entry, unclaimed);
1653
+ if (spawned) {
1654
+ unclaimed.splice(unclaimed.indexOf(spawned), 1);
1655
+ spawnCall.set(spawned.subagentId, entry.toolCallId);
1656
+ continue;
1657
+ }
1658
+ placed.push({ at: entry.timestamp, rank: RESEARCH, build: (id) => toolFromStep(id(), entry) });
1659
+ }
1660
+ for (const entry of subagents) {
1661
+ const toolCallId = spawnCall.get(entry.subagentId);
1662
+ const steps = log.filter((e) => !("type" in e) && e.subagentId === entry.subagentId);
1663
+ placed.push({
1664
+ at: entry.timestamp,
1665
+ rank: RESEARCH,
1666
+ build: (id) => subagentBlock(id(), {
1667
+ subagentId: entry.subagentId,
1668
+ brief: entry.brief,
1669
+ status: entry.outcome,
1670
+ digest: entry.digest,
1671
+ children: steps.map((step) => toolFromStep(id(), step)),
1672
+ toolCallId,
1673
+ model: entry.model,
1674
+ usage: entry.usage
1675
+ })
1676
+ });
1677
+ }
1678
+ return placed;
1679
+ }
1680
+ function fromTranscript(conversationHistory, researchLog, plannerUsage) {
1681
+ const history = conversationHistory ?? [];
1682
+ const compacted = history[0]?.kind === "compaction" ? history[0] : void 0;
1683
+ const kept = compacted ? history.slice(1) : history;
1684
+ const cutoff = compacted ? kept[0]?.timestamp ?? compacted.timestamp : "";
1685
+ const placed = [
1686
+ ...kept.map((entry) => ({ at: entry.timestamp, rank: entry.role === "user" && !entry.kind ? USER : SETTLED, build: fromEntry(entry) })),
1687
+ ...research(researchLog ?? []).filter((item) => item.at >= cutoff)
1688
+ ];
1689
+ placed.sort((a, b) => a.at < b.at ? -1 : a.at > b.at ? 1 : a.rank - b.rank);
1690
+ if (compacted) placed.unshift({ at: "", rank: SETTLED, build: fromEntry(compacted) });
1691
+ let nextId = 1;
1692
+ const id = () => `b${nextId++}`;
1693
+ const blocks = placed.map((item) => item.build(id));
1694
+ if (plannerUsage && isMeasured(plannerUsage.totals)) blocks.push(usageBlock(id(), usageLine(plannerUsage)));
1695
+ const transcriptAt = history.reduce((latest, e) => latest === void 0 || e.timestamp > latest ? e.timestamp : latest, void 0);
1696
+ return { blocks, nextId, ...transcriptAt ? { transcriptAt } : {} };
1697
+ }
1698
+
1699
+ // src/conversation/promptHold.ts
1700
+ var EMPTY_HOLD = [];
1701
+ function holdPrompt(hold, text2) {
1702
+ return [...hold, text2];
1703
+ }
1704
+ function drainNext(hold) {
1705
+ const [text2, ...rest] = hold;
1706
+ return text2 === void 0 ? void 0 : { text: text2, rest };
1707
+ }
1708
+ function unsendLatest(hold) {
1709
+ if (hold.length === 0) return void 0;
1710
+ return { text: hold[hold.length - 1], rest: hold.slice(0, -1) };
1711
+ }
1712
+ function unsendAll(hold) {
1713
+ if (hold.length === 0) return void 0;
1714
+ return { text: hold.join("\n"), rest: EMPTY_HOLD };
1715
+ }
1716
+ function aheadOfDraft(text2, draft) {
1717
+ return draft ? `${text2}
1718
+ ${draft}` : text2;
1719
+ }
1720
+
1721
+ // src/conversation/turnGate.ts
1722
+ var NO_TURN = { open: null, stopped: null };
1723
+ var TURN_STREAM = /* @__PURE__ */ new Set([
1724
+ "planner_text_delta",
1725
+ "planner_thinking_delta",
1726
+ "planner_text_retracted",
1727
+ "planner_message",
1728
+ "plan_token",
1729
+ "research_step",
1730
+ "research_step_done",
1731
+ "subagent_started",
1732
+ "subagent_finished",
1733
+ "planner_turn_ended"
1734
+ ]);
1735
+ function cutOff(gate, input) {
1736
+ if (gate.stopped === null || !TURN_STREAM.has(input.type)) return false;
1737
+ const turnId = "turnId" in input ? input.turnId : void 0;
1738
+ return turnId === void 0 || turnId === gate.stopped;
1739
+ }
1740
+ function withGate(live, gate) {
1741
+ return gate.open === live.gate.open && gate.stopped === live.gate.stopped ? live : { ...live, gate };
1742
+ }
1743
+ function followTurn(view, gate, input) {
1744
+ const live = { view, gate };
1745
+ if (input.type === "planner_turn_started") {
1746
+ return withGate({ view: reduceConversation(view, input), gate }, { open: input.turnId, stopped: null });
1747
+ }
1748
+ if (cutOff(gate, input)) {
1749
+ return input.type === "planner_turn_ended" ? withGate(live, { ...gate, stopped: null }) : live;
1750
+ }
1751
+ const next = { view: reduceConversation(view, input), gate };
1752
+ return input.type === "planner_turn_ended" && input.turnId === gate.open ? withGate(next, { ...gate, open: null }) : next;
1753
+ }
1754
+ function stopTurn(view, gate) {
1755
+ if (gate.open === null) return { view, gate };
1756
+ return {
1757
+ view: reduceConversation(view, { type: "planner_turn_ended", turnId: gate.open, outcome: "stopped" }),
1758
+ gate: { open: null, stopped: gate.open }
1759
+ };
1760
+ }
1761
+
1762
+ // src/conversation/detail.ts
1763
+ function hasHiddenDetail(blocks) {
1764
+ return blocks.some((b) => b.type === "thinking" || b.type === "tool" || b.type === "subagent");
1765
+ }
1766
+
1767
+ // src/conversation/notices.ts
1768
+ function taskStartedNotice(title, runner) {
1769
+ return runner ? `Started "${title}" \xB7 ${runner}` : `Started "${title}"`;
1770
+ }
1771
+
921
1772
  export {
1773
+ partedPromptUsage,
1774
+ addUsage,
1775
+ addPlannerUsage,
1776
+ isMeasured,
1777
+ usageLine,
1778
+ plannerContextFill,
922
1779
  effectiveAllowlist,
923
1780
  filterModelsForPrompt,
924
1781
  clampThinkingEffort,
@@ -927,6 +1784,8 @@ export {
927
1784
  taskOpsProtocol,
928
1785
  textHasTaskOps,
929
1786
  parseTaskOpsJson,
1787
+ taskOpRefs,
1788
+ refMatchesTask,
930
1789
  canMergeTasks,
931
1790
  dependentsOf,
932
1791
  dependencyCandidates,
@@ -935,11 +1794,31 @@ export {
935
1794
  applyTaskOps,
936
1795
  summarizeToolCall,
937
1796
  classifyOutcome,
1797
+ flattenTerminalOutput,
1798
+ renderTerminalOutput,
1799
+ renderCleanCapture,
938
1800
  serializeTask,
939
1801
  serializeTaskStatus,
940
1802
  serializePlan,
941
1803
  executionSummary,
942
1804
  CHECKPOINT_TRUNCATE_LENGTH,
943
- truncateCheckpointSummary
1805
+ truncateCheckpointSummary,
1806
+ toolHeadline,
1807
+ outputLines,
1808
+ outputPreview,
1809
+ EMPTY_CONVERSATION,
1810
+ reduceConversation,
1811
+ fromTranscript,
1812
+ EMPTY_HOLD,
1813
+ holdPrompt,
1814
+ drainNext,
1815
+ unsendLatest,
1816
+ unsendAll,
1817
+ aheadOfDraft,
1818
+ NO_TURN,
1819
+ followTurn,
1820
+ stopTurn,
1821
+ hasHiddenDetail,
1822
+ taskStartedNotice
944
1823
  };
945
- //# sourceMappingURL=chunk-GWPIYDQW.mjs.map
1824
+ //# sourceMappingURL=chunk-KLN7ELXO.mjs.map