@ordewell/core 0.10.5 → 0.10.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 (44) hide show
  1. package/dist/{IRunner-Crkt3tHD.d.ts → IFileSystem-C4_mpfze.d.ts} +97 -14
  2. package/dist/{IRunner-lMQIa5Wc.d.mts → IFileSystem-DUgeWWQN.d.mts} +97 -14
  3. package/dist/{ModeResolver-B4hhABNf.d.mts → ModeResolver-4qNjxcDs.d.mts} +1 -1
  4. package/dist/{ModeResolver-CUR5jCSU.d.ts → ModeResolver-DGK2rWHE.d.ts} +1 -1
  5. package/dist/{Task-D4QHjdGv.d.mts → Task-C0o4i3Nn.d.mts} +23 -4
  6. package/dist/{Task-D4QHjdGv.d.ts → Task-C0o4i3Nn.d.ts} +23 -4
  7. package/dist/{chunk-6LEA6WAM.mjs → chunk-DMG4ISUG.mjs} +923 -45
  8. package/dist/chunk-DMG4ISUG.mjs.map +1 -0
  9. package/dist/{chunk-RT4NQ2BZ.mjs → chunk-EEE2GBLG.mjs} +114 -27
  10. package/dist/chunk-EEE2GBLG.mjs.map +1 -0
  11. package/dist/chunk-H7QX32BH.mjs +647 -0
  12. package/dist/chunk-H7QX32BH.mjs.map +1 -0
  13. package/dist/{chunk-F3KIX7WR.mjs → chunk-LTHKFBKM.mjs} +4 -4
  14. package/dist/chunk-LTHKFBKM.mjs.map +1 -0
  15. package/dist/index.d.mts +278 -1701
  16. package/dist/index.d.ts +278 -1701
  17. package/dist/index.js +2729 -1903
  18. package/dist/index.js.map +1 -1
  19. package/dist/index.mjs +2171 -1523
  20. package/dist/index.mjs.map +1 -1
  21. package/dist/parsing.d.mts +2 -2
  22. package/dist/parsing.d.ts +2 -2
  23. package/dist/parsing.js +231 -75
  24. package/dist/parsing.js.map +1 -1
  25. package/dist/parsing.mjs +3 -3
  26. package/dist/plan-utils.d.mts +20 -4
  27. package/dist/plan-utils.d.ts +20 -4
  28. package/dist/plan-utils.js +255 -97
  29. package/dist/plan-utils.js.map +1 -1
  30. package/dist/plan-utils.mjs +33 -19
  31. package/dist/{plan-utils-wI8MuDBC.d.mts → runSettingsText-BgOmLxdw.d.mts} +1941 -108
  32. package/dist/{plan-utils-BVJCzNvm.d.ts → runSettingsText-BgXvajj2.d.ts} +1941 -108
  33. package/dist/testing.d.mts +2 -3
  34. package/dist/testing.d.ts +2 -3
  35. package/dist/testing.js.map +1 -1
  36. package/dist/testing.mjs +1 -1
  37. package/package.json +1 -1
  38. package/dist/IFileSystem-ClBdp59f.d.ts +0 -78
  39. package/dist/IFileSystem-Db34maxC.d.mts +0 -78
  40. package/dist/chunk-4QLFM73A.mjs +0 -1407
  41. package/dist/chunk-4QLFM73A.mjs.map +0 -1
  42. package/dist/chunk-6LEA6WAM.mjs.map +0 -1
  43. package/dist/chunk-F3KIX7WR.mjs.map +0 -1
  44. package/dist/chunk-RT4NQ2BZ.mjs.map +0 -1
@@ -36,6 +36,7 @@ __export(plan_utils_exports, {
36
36
  EMPTY_HOLD: () => EMPTY_HOLD,
37
37
  EMPTY_RUN: () => EMPTY_RUN,
38
38
  EMPTY_TASK_LOG: () => EMPTY_TASK_LOG,
39
+ EMPTY_TASK_LOG_FOLLOW: () => EMPTY_TASK_LOG_FOLLOW,
39
40
  NOT_STARTED: () => NOT_STARTED,
40
41
  NO_TURN: () => NO_TURN,
41
42
  SUPERVISOR_LEVEL_LABEL: () => SUPERVISOR_LEVEL_LABEL,
@@ -56,6 +57,7 @@ __export(plan_utils_exports, {
56
57
  canSetDependencies: () => canSetDependencies,
57
58
  canSplitTask: () => canSplitTask,
58
59
  capConflictFiles: () => capConflictFiles,
60
+ clampThinkingEffort: () => clampThinkingEffort,
59
61
  countedSessionCost: () => countedSessionCost,
60
62
  dependencyCandidates: () => dependencyCandidates,
61
63
  dependentsNotice: () => dependentsNotice,
@@ -65,6 +67,7 @@ __export(plan_utils_exports, {
65
67
  diffSummary: () => diffSummary,
66
68
  drainNext: () => drainNext,
67
69
  endAttemptUsage: () => endAttemptUsage,
70
+ followTaskLog: () => followTaskLog,
68
71
  followTurn: () => followTurn,
69
72
  fromTranscript: () => fromTranscript,
70
73
  hasHiddenDetail: () => hasHiddenDetail,
@@ -92,6 +95,7 @@ __export(plan_utils_exports, {
92
95
  reduceTaskLog: () => reduceTaskLog,
93
96
  replayTaskLog: () => replayTaskLog,
94
97
  resolveTaskRef: () => resolveTaskRef,
98
+ resolveUserTaskRef: () => resolveUserTaskRef,
95
99
  resumeLabel: () => resumeLabel,
96
100
  resumeTime: () => resumeTime,
97
101
  resumedSessionWindow: () => resumedSessionWindow,
@@ -100,9 +104,11 @@ __export(plan_utils_exports, {
100
104
  skippedLabel: () => skippedLabel,
101
105
  startAttemptUsage: () => startAttemptUsage,
102
106
  stopTurn: () => stopTurn,
107
+ subtreeIds: () => subtreeIds,
103
108
  summarizeToolCall: () => summarizeToolCall,
104
109
  takeAt: () => takeAt,
105
110
  taskOrderLabel: () => taskOrderLabel,
111
+ taskPlacement: () => taskPlacement,
106
112
  taskRef: () => taskRef,
107
113
  taskRefOf: () => taskRefOf,
108
114
  taskRowActions: () => taskRowActions,
@@ -117,7 +123,8 @@ __export(plan_utils_exports, {
117
123
  truncateCheckpointSummary: () => truncateCheckpointSummary,
118
124
  unsendAll: () => unsendAll,
119
125
  unsendLatest: () => unsendLatest,
120
- usageLine: () => usageLine
126
+ usageLine: () => usageLine,
127
+ walkPlan: () => walkPlan
121
128
  });
122
129
  module.exports = __toCommonJS(plan_utils_exports);
123
130
 
@@ -143,6 +150,90 @@ function loadedSkillTokens(text2, loaded) {
143
150
  return skillTokens(text2).filter((t) => loaded.includes(t.name));
144
151
  }
145
152
 
153
+ // src/services/PlanTree.ts
154
+ function* walkPlan(tasks) {
155
+ function* walk(level, ancestors, parentLabel) {
156
+ for (const task of level) {
157
+ const label = parentLabel ? `${parentLabel}.${task.order}` : String(task.order);
158
+ yield { task, parent: ancestors.at(-1), ancestors, siblings: level, label };
159
+ yield* walk(task.subtasks ?? [], [...ancestors, task], label);
160
+ }
161
+ }
162
+ yield* walk(tasks, []);
163
+ }
164
+ function taskPlacement(tasks, id) {
165
+ for (const row of walkPlan(tasks)) if (row.task.id === id) return row;
166
+ return void 0;
167
+ }
168
+ function subtreeIds(tasks, id) {
169
+ const found = taskPlacement(tasks, id);
170
+ return new Set(found ? [...walkPlan([found.task])].map(({ task }) => task.id) : []);
171
+ }
172
+ function dependencyCandidates(tasks, taskId) {
173
+ if (!taskId) return [...tasks];
174
+ const found = taskPlacement(tasks, taskId);
175
+ return found ? found.siblings.filter((t) => t.order < found.task.order) : [];
176
+ }
177
+ function dependentsOf(tasks, taskId) {
178
+ const removed = subtreeIds(tasks, taskId);
179
+ return [...walkPlan(tasks)].map(({ task }) => task).filter((t) => !removed.has(t.id) && t.dependencies.some((id) => removed.has(id)));
180
+ }
181
+ function dependencyTargetErrors(tasks, taskId, dependencies) {
182
+ const found = taskPlacement(tasks, taskId);
183
+ if (!found) return ["Task not found"];
184
+ const descendants = subtreeIds(tasks, taskId);
185
+ const errors = [];
186
+ for (const dep of dependencies) {
187
+ if (dep === taskId) {
188
+ errors.push(`"${found.task.title}" cannot depend on itself`);
189
+ continue;
190
+ }
191
+ const target = taskPlacement(tasks, dep)?.task;
192
+ if (!target) {
193
+ errors.push(`Unknown dependency "${dep}"`);
194
+ continue;
195
+ }
196
+ if (found.ancestors.some((t) => t.id === dep) || descendants.has(dep)) {
197
+ errors.push(`"${found.task.title}" cannot depend on "${target.title}", its ancestor or descendant`);
198
+ }
199
+ }
200
+ return errors;
201
+ }
202
+ function findDependencyCycle(tasks) {
203
+ const byId = new Map([...walkPlan(tasks)].map(({ task }) => [task.id, task]));
204
+ const path = [];
205
+ const done = /* @__PURE__ */ new Set();
206
+ const visit = (id) => {
207
+ if (done.has(id)) return null;
208
+ const at = path.indexOf(id);
209
+ if (at >= 0) return path.slice(at);
210
+ path.push(id);
211
+ for (const dep of byId.get(id)?.dependencies ?? []) {
212
+ const hit = visit(dep);
213
+ if (hit) return hit;
214
+ }
215
+ path.pop();
216
+ done.add(id);
217
+ return null;
218
+ };
219
+ for (const id of byId.keys()) {
220
+ const hit = visit(id);
221
+ if (hit) return hit.map((key) => byId.get(key));
222
+ }
223
+ return null;
224
+ }
225
+ function canSetDependencies(tasks, taskId, dependencies) {
226
+ const [error] = dependencyTargetErrors(tasks, taskId, dependencies);
227
+ if (error) return { ok: false, error };
228
+ const replace = (level) => level.map((t) => ({
229
+ ...t,
230
+ dependencies: t.id === taskId ? dependencies : t.dependencies,
231
+ subtasks: replace(t.subtasks ?? [])
232
+ }));
233
+ const cycle = findDependencyCycle(replace(tasks));
234
+ return cycle ? { ok: false, error: `Dependency cycle detected: ${[...cycle, cycle[0]].map((t) => `"${t.title}"`).join(" \u2192 ")}` } : { ok: true };
235
+ }
236
+
146
237
  // src/services/TaskRefs.ts
147
238
  function taskOrderLabel(task, parent) {
148
239
  return parent ? `${parent.label ?? parent.order}.${task.order}` : String(task.order);
@@ -153,16 +244,8 @@ function taskRef(task, parent) {
153
244
  function titledTaskRef(task, parent) {
154
245
  return `${taskRef(task, parent)} ${task.title}`;
155
246
  }
156
- function* depthFirst(tasks, parent, parentLabel) {
157
- for (const task of tasks) {
158
- const label = taskOrderLabel(task, parent ? { order: parent.order, label: parentLabel } : void 0);
159
- yield { task, parent, label };
160
- yield* depthFirst(task.subtasks ?? [], task, label);
161
- }
162
- }
163
247
  function findTaskRef(tasks, id) {
164
- for (const match of depthFirst(tasks)) if (match.task.id === id) return match;
165
- return void 0;
248
+ return taskPlacement(tasks, id);
166
249
  }
167
250
  function taskRefOf(tasks, id) {
168
251
  const found = findTaskRef(tasks, id);
@@ -175,7 +258,7 @@ function titledTaskRefOf(tasks, id) {
175
258
  function resolveTaskRef(tasks, ref) {
176
259
  const s = String(ref).trim();
177
260
  if (!s) return void 0;
178
- for (const { task } of depthFirst(tasks)) if (task.id === s) return task;
261
+ for (const { task } of walkPlan(tasks)) if (task.id === s) return task;
179
262
  const label = s.startsWith("#") ? s.slice(1) : s;
180
263
  if (/^\d+(\.\d+)*$/.test(label)) {
181
264
  let level = tasks;
@@ -186,9 +269,16 @@ function resolveTaskRef(tasks, ref) {
186
269
  }
187
270
  return found;
188
271
  }
189
- for (const { task } of depthFirst(tasks)) if (task.title === s) return task;
272
+ for (const { task } of walkPlan(tasks)) if (task.title === s) return task;
190
273
  return void 0;
191
274
  }
275
+ function resolveUserTaskRef(tasks, ref) {
276
+ const found = resolveTaskRef(tasks, ref);
277
+ if (found) return found;
278
+ const prefix = String(ref).trim();
279
+ const matches = prefix ? [...walkPlan(tasks)].filter(({ task }) => task.id.startsWith(prefix)) : [];
280
+ return matches.length === 1 ? matches[0].task : void 0;
281
+ }
192
282
 
193
283
  // src/models/Task.ts
194
284
  var SKILL_NAME = new RegExp(`^${SKILL_NAME_PATTERN}$`);
@@ -200,20 +290,6 @@ function pausedOnLimit(task) {
200
290
  // src/services/TaskOps.ts
201
291
  var import_uuid3 = require("uuid");
202
292
 
203
- // src/services/ModelAllowlistResolver.ts
204
- function effectiveAllowlist(allowlist, runner, modelsByRunner) {
205
- if (!allowlist || allowlist.length === 0) return void 0;
206
- if (!modelsByRunner) return allowlist;
207
- const own = new Set((modelsByRunner[runner] ?? []).map((m) => m.modelId));
208
- const elsewhere = /* @__PURE__ */ new Set();
209
- for (const [other, models] of Object.entries(modelsByRunner)) {
210
- if (other === runner) continue;
211
- for (const m of models ?? []) elsewhere.add(m.modelId);
212
- }
213
- const kept = allowlist.filter((id) => own.has(id) || !elsewhere.has(id));
214
- return kept.length > 0 ? kept : void 0;
215
- }
216
-
217
293
  // src/taskRow/status.ts
218
294
  var isTaskRunning = (task) => task.status === "in_progress" || task.status === "running";
219
295
  var NOT_STARTED = /* @__PURE__ */ new Set(["pending", "approved", "blocked"]);
@@ -267,28 +343,43 @@ function resumeLabel(task, now = /* @__PURE__ */ new Date()) {
267
343
 
268
344
  // src/services/PlannedTask.ts
269
345
  var import_uuid2 = require("uuid");
270
- function findCycle(tasks) {
271
- const byId = new Map(tasks.map((t) => [t.id, t]));
272
- const path = [];
273
- const done = /* @__PURE__ */ new Set();
274
- const visit = (id) => {
275
- if (done.has(id)) return null;
276
- const at = path.indexOf(id);
277
- if (at >= 0) return path.slice(at);
278
- path.push(id);
279
- for (const dep of byId.get(id)?.dependencies ?? []) {
280
- const hit = visit(dep);
281
- if (hit) return hit;
282
- }
283
- path.pop();
284
- done.add(id);
285
- return null;
286
- };
287
- for (const t of tasks) {
288
- const hit = visit(t.id);
289
- if (hit) return hit.map((id) => byId.get(id));
346
+
347
+ // src/services/ModelAllowlistResolver.ts
348
+ function effectiveAllowlist(allowlist, runner, modelsByRunner) {
349
+ if (!allowlist || allowlist.length === 0) return void 0;
350
+ if (!modelsByRunner) return allowlist;
351
+ const own = new Set((modelsByRunner[runner] ?? []).map((m) => m.modelId));
352
+ const elsewhere = /* @__PURE__ */ new Set();
353
+ for (const [other, models] of Object.entries(modelsByRunner)) {
354
+ if (other === runner) continue;
355
+ for (const m of models ?? []) elsewhere.add(m.modelId);
290
356
  }
291
- return null;
357
+ const kept = allowlist.filter((id) => own.has(id) || !elsewhere.has(id));
358
+ return kept.length > 0 ? kept : void 0;
359
+ }
360
+ var EFFORT_LADDER = ["none", "minimal", "low", "medium", "high", "xhigh", "max", "ultra"];
361
+ var EFFORT_ALIASES = { disabled: "none", adaptive: "medium" };
362
+ function clampThinkingEffort(effort, variants) {
363
+ if (!effort) return void 0;
364
+ if (variants.length === 0) return void 0;
365
+ const ids = new Set(variants.map((v) => v.id));
366
+ if (ids.has(effort)) return effort;
367
+ const canon = EFFORT_ALIASES[effort] ?? effort;
368
+ if (ids.has(canon)) return canon;
369
+ const idx = EFFORT_LADDER.indexOf(canon);
370
+ if (idx < 0) return void 0;
371
+ for (let d = 1; d < EFFORT_LADDER.length; d++) {
372
+ const lower = EFFORT_LADDER[idx - d];
373
+ if (lower && ids.has(lower)) return lower;
374
+ const higher = EFFORT_LADDER[idx + d];
375
+ if (higher && ids.has(higher)) return higher;
376
+ }
377
+ return void 0;
378
+ }
379
+
380
+ // src/services/PlannedTask.ts
381
+ function findCycle(tasks) {
382
+ return findDependencyCycle(tasks);
292
383
  }
293
384
  function detectCycle(tasks) {
294
385
  return findCycle(tasks)?.[0].title ?? null;
@@ -313,28 +404,6 @@ function canMergeTasks(tasks, selectedIds) {
313
404
  if (cycle) return { ok: false, error: `Merging would create a dependency cycle involving "${cycle}"` };
314
405
  return { ok: true };
315
406
  }
316
- function dependentsOf(tasks, taskId) {
317
- return tasks.filter((t) => t.id !== taskId && t.dependencies.includes(taskId));
318
- }
319
- function dependencyCandidates(tasks, taskId) {
320
- if (!taskId) return [...tasks];
321
- const target = tasks.find((t) => t.id === taskId);
322
- return target ? tasks.filter((t) => t.order < target.order) : [];
323
- }
324
- function canSetDependencies(tasks, taskId, dependencies) {
325
- const target = tasks.find((t) => t.id === taskId);
326
- if (!target) return { ok: false, error: "Task not found" };
327
- const allowed = new Set(dependencyCandidates(tasks, taskId).map((t) => t.id));
328
- for (const dep of dependencies) {
329
- if (dep === taskId) return { ok: false, error: `"${target.title}" cannot depend on itself` };
330
- const found = tasks.find((t) => t.id === dep);
331
- if (!found) return { ok: false, error: `Unknown dependency "${dep}"` };
332
- if (!allowed.has(dep)) {
333
- return { ok: false, error: `"${target.title}" cannot depend on "${found.title}", which comes after it in the plan` };
334
- }
335
- }
336
- return { ok: true };
337
- }
338
407
  function canSplitTask(tasks, taskId) {
339
408
  const target = tasks.find((t) => t.id === taskId);
340
409
  if (!target) return { ok: false, error: "Task not found" };
@@ -657,7 +726,7 @@ function planMarker(content) {
657
726
  }
658
727
 
659
728
  // src/services/blocking.ts
660
- var UNSTARTED = /* @__PURE__ */ new Set(["pending", "approved", "blocked"]);
729
+ var UNSTARTED = /* @__PURE__ */ new Set(["pending", "approved"]);
661
730
  function blockingFailures(tasks) {
662
731
  const byId = /* @__PURE__ */ new Map();
663
732
  const index = (list) => {
@@ -1032,8 +1101,9 @@ function dropBuildingPlan(view, turnId, segmentId) {
1032
1101
  const blocks = view.blocks.filter((b) => !(isBuildingPlan(b, turnId) && (segmentId === void 0 || b.segmentId === segmentId)));
1033
1102
  return blocks.length === view.blocks.length ? view : { ...view, blocks };
1034
1103
  }
1035
- function settleReply(view, { content, turnId, supervisor }) {
1104
+ function settleReply(view, { content, turnId, supervisor, runs }) {
1036
1105
  const role = supervisor ? "supervisor" : "planner";
1106
+ if (runs) return settleRuns(view, runs, role, turnId);
1037
1107
  if (turnId !== void 0) {
1038
1108
  const i = finalSegmentIndex(view.blocks, turnId);
1039
1109
  if (i >= 0) {
@@ -1042,6 +1112,25 @@ function settleReply(view, { content, turnId, supervisor }) {
1042
1112
  }
1043
1113
  return append(dropBuildingPlan(view, turnId), (id) => settledMessage(id, role, content, turnId));
1044
1114
  }
1115
+ function settleRuns(view, runs, role, turnId) {
1116
+ const settled = /* @__PURE__ */ new Map();
1117
+ let turn = turnId;
1118
+ for (const run of runs) {
1119
+ const i = view.blocks.findIndex((b) => b.type === "message" && b.segmentId === run.segmentId && b.turnId !== void 0 && (turnId === void 0 || b.turnId === turnId));
1120
+ const segment = view.blocks[i];
1121
+ if (segment?.type !== "message") continue;
1122
+ settled.set(i, run);
1123
+ turn ??= segment.turnId;
1124
+ }
1125
+ const contained = new Set(runs.map((run) => run.segmentId));
1126
+ const blocks = view.blocks.flatMap((block, i) => {
1127
+ const run = settled.get(i);
1128
+ if (run) return [settledMessage(block.id, role, run.text, turn)];
1129
+ return turn !== void 0 && isUnsettledSegment(block, turn) && !contained.has(block.segmentId) ? [] : [block];
1130
+ });
1131
+ const streamed = new Set(settled.values());
1132
+ return runs.filter((run) => !streamed.has(run)).reduce((next, run) => append(next, (id) => settledMessage(id, role, run.text, turn)), dropBuildingPlan({ ...view, blocks }, turn));
1133
+ }
1045
1134
  function retractText(view, { turnId, segmentId }) {
1046
1135
  const blocks = view.blocks.filter((b) => !(isUnsettledSegment(b, turnId) && (segmentId === void 0 || b.segmentId === segmentId)));
1047
1136
  return dropBuildingPlan(blocks.length === view.blocks.length ? view : { ...view, blocks }, turnId, segmentId);
@@ -1318,7 +1407,7 @@ function fromTranscript(conversationHistory, researchLog, plannerUsage, pendingT
1318
1407
  const kept = compacted ? history.slice(1) : history;
1319
1408
  const cutoff = compacted ? kept[0]?.timestamp ?? compacted.timestamp : "";
1320
1409
  const placed = [
1321
- ...kept.map((entry, i) => ({ at: entry.timestamp, rank: rankOf(entry), build: fromEntry(entry, loadsAfter(kept, i)) })),
1410
+ ...kept.flatMap((entry, i) => entry.runs ? entry.runs.map((run) => ({ at: run.startedAt, rank: SETTLED, build: (id2) => settledMessage(id2(), roleOf(entry), run.text) })) : [{ at: entry.timestamp, rank: rankOf(entry), build: fromEntry(entry, loadsAfter(kept, i)) }]),
1322
1411
  ...research(researchLog ?? []).filter((item) => item.at >= cutoff)
1323
1412
  ];
1324
1413
  placed.sort((a, b) => a.at < b.at ? -1 : a.at > b.at ? 1 : a.rank - b.rank);
@@ -1351,7 +1440,7 @@ function sameMessage(a, b) {
1351
1440
 
1352
1441
  // src/conversation/taskLog.ts
1353
1442
  var EMPTY_TASK_LOG = { blocks: [], nextId: 1, queued: [], working: false, streams: {} };
1354
- var TEXT_STREAM = "text";
1443
+ var textStream = (runId) => runId === void 0 ? "text" : `text:${runId}`;
1355
1444
  var thinkingStream = (subagentId) => `thinking:${subagentId ?? ""}`;
1356
1445
  function withoutStream(view, key) {
1357
1446
  if (!(key in view.streams)) return view;
@@ -1368,35 +1457,43 @@ function openStream(view, lane, key) {
1368
1457
  const block = blocks[i];
1369
1458
  return block?.id === id && (block.type === "message" || block.type === "thinking") && block.streaming ? i : -1;
1370
1459
  }
1371
- function streamDelta(view, lane, key, text2, make) {
1372
- const i = openStream(view, lane, key);
1460
+ function streamBlock(view, lane, key) {
1461
+ const id = view.streams[key];
1462
+ return id === void 0 ? -1 : findLastIndex(laneBlocks(view, lane), (b) => b.id === id);
1463
+ }
1464
+ function streamDelta(view, lane, key, text2, make, anywhere = false) {
1465
+ const i = anywhere ? streamBlock(view, lane, key) : openStream(view, lane, key);
1373
1466
  const open = laneBlocks(view, lane)[i];
1374
1467
  if (open?.type === "message" || open?.type === "thinking") return laneReplace(view, lane, i, { ...open, text: open.text + text2 });
1375
1468
  const next = appendOutput(view, lane, (id) => make(id, blockText(text2)));
1376
1469
  return { ...next, streams: { ...next.streams, [key]: `b${view.nextId}` } };
1377
1470
  }
1378
1471
  function streamWhole(view, lane, key, text2, make) {
1379
- const id = view.streams[key];
1380
- const blocks = laneBlocks(view, lane);
1381
- const i = id === void 0 ? -1 : findLastIndex(blocks, (b) => b.id === id);
1382
- const streamed = blocks[i];
1472
+ const i = streamBlock(view, lane, key);
1473
+ const streamed = laneBlocks(view, lane)[i];
1383
1474
  const next = withoutStream(view, key);
1384
1475
  if (streamed?.type === "message" || streamed?.type === "thinking") {
1385
1476
  return laneReplace(next, lane, i, { ...streamed, text: blockText(text2), streaming: false });
1386
1477
  }
1387
1478
  return appendOutput(next, lane, make);
1388
1479
  }
1389
- function agentText(view, text2) {
1390
- const next = streamWhole(view, null, TEXT_STREAM, text2, (id) => settledMessage(id, "agent", blockText(text2)));
1391
- return { ...next, latestText: next.nextId > view.nextId ? `b${view.nextId}` : view.streams[TEXT_STREAM] };
1480
+ function openedText(view, next) {
1481
+ return next.nextId > view.nextId ? { ...next, latestText: `b${view.nextId}` } : next;
1392
1482
  }
1393
- function agentTextDelta(view, text2) {
1394
- const next = streamDelta(view, null, TEXT_STREAM, text2, (id, t) => ({ type: "message", id, role: "agent", text: t, streaming: true }));
1395
- return { ...next, latestText: next.streams[TEXT_STREAM] };
1483
+ function agentText(view, { runId, text: text2 }) {
1484
+ return openedText(view, streamWhole(view, null, textStream(runId), text2, (id) => settledMessage(id, "agent", blockText(text2))));
1485
+ }
1486
+ function agentTextDelta(view, { runId, text: text2 }) {
1487
+ const make = (id, t) => ({ type: "message", id, role: "agent", text: t, streaming: true });
1488
+ return openedText(view, streamDelta(view, null, textStream(runId), text2, make, runId !== void 0));
1396
1489
  }
1397
1490
  function failTurn(view, message) {
1398
1491
  const repeated = view.blocks.find((b) => b.id === view.latestText);
1399
- const settled = repeated?.type === "message" && repeated.role === "agent" && sameMessage(repeated.text, message) ? withoutStream({ ...view, blocks: view.blocks.filter((b) => b !== repeated) }, TEXT_STREAM) : view;
1492
+ const settled = repeated?.type === "message" && repeated.role === "agent" && sameMessage(repeated.text, message) ? {
1493
+ ...view,
1494
+ blocks: view.blocks.filter((b) => b !== repeated),
1495
+ streams: Object.fromEntries(Object.entries(view.streams).filter(([, id]) => id !== repeated.id))
1496
+ } : view;
1400
1497
  return appendOutput({ ...settled, latestText: void 0 }, null, (id) => settledMessage(id, "error", message));
1401
1498
  }
1402
1499
  function thinkingBlock(id, text2, streaming, subagentId) {
@@ -1577,7 +1674,7 @@ function endCall(block) {
1577
1674
  function endOpenCalls(view) {
1578
1675
  let changed = false;
1579
1676
  const blocks = view.blocks.map((block) => {
1580
- const ended = block.type === "subagent" ? block.children.some((c) => c.type === "tool" && c.status === "pending") ? { ...block, children: block.children.map(endCall) } : block : block.type === "tool" ? endCall(block) : block;
1677
+ const ended = block.type === "subagent" ? block.children.some((c) => c.type === "tool" && c.status === "pending") ? { ...block, children: block.children.map(endCall) } : block : block.type === "tool" ? endCall(block) : block.type === "command" && block.status === "running" ? { ...block, status: "stopped" } : block;
1581
1678
  if (ended !== block) changed = true;
1582
1679
  return ended;
1583
1680
  });
@@ -1608,9 +1705,9 @@ function reduceTaskLog(view, event) {
1608
1705
  case "turn_end":
1609
1706
  return endTurn2(view, event);
1610
1707
  case "text_delta":
1611
- return agentTextDelta(view, event.text);
1708
+ return agentTextDelta(view, event);
1612
1709
  case "text":
1613
- return agentText(view, event.text);
1710
+ return agentText(view, event);
1614
1711
  case "thinking_delta":
1615
1712
  return thinkingDelta(view, event);
1616
1713
  case "thinking":
@@ -1644,7 +1741,7 @@ function reduceTaskLog(view, event) {
1644
1741
  case "approval_withdrawn":
1645
1742
  return settleApproval2(view, event.approvalId, (block) => ({ ...block, status: "withdrawn" }));
1646
1743
  case "runner_ended":
1647
- return endOpenCalls(view);
1744
+ return closeOpenBlocks({ ...endOpenCalls(view), working: false, streams: {}, latestText: void 0 }, "stopped");
1648
1745
  default:
1649
1746
  return view;
1650
1747
  }
@@ -1699,16 +1796,16 @@ function cutOff(gate, input) {
1699
1796
  const turnId = "turnId" in input ? input.turnId : void 0;
1700
1797
  return turnId === void 0 || turnId === gate.stopped;
1701
1798
  }
1702
- function withGate(live, gate) {
1703
- return gate.open === live.gate.open && gate.stopped === live.gate.stopped ? live : { ...live, gate };
1799
+ function withGate(live2, gate) {
1800
+ return gate.open === live2.gate.open && gate.stopped === live2.gate.stopped ? live2 : { ...live2, gate };
1704
1801
  }
1705
1802
  function followTurn(view, gate, input) {
1706
- const live = { view, gate };
1803
+ const live2 = { view, gate };
1707
1804
  if (input.type === "planner_turn_started") {
1708
1805
  return withGate({ view: reduceConversation(view, input), gate }, { open: input.turnId, stopped: null });
1709
1806
  }
1710
1807
  if (cutOff(gate, input)) {
1711
- return input.type === "planner_turn_ended" ? withGate(live, { ...gate, stopped: null }) : live;
1808
+ return input.type === "planner_turn_ended" ? withGate(live2, { ...gate, stopped: null }) : live2;
1712
1809
  }
1713
1810
  const next = { view: reduceConversation(view, input), gate };
1714
1811
  return input.type === "planner_turn_ended" && input.turnId === gate.open ? withGate(next, { ...gate, open: null }) : next;
@@ -1761,6 +1858,60 @@ function markdownHtml(text2) {
1761
1858
  return md.render(text2);
1762
1859
  }
1763
1860
 
1861
+ // src/conversation/taskLogFollow.ts
1862
+ var EMPTY_TASK_LOG_FOLLOW = {
1863
+ view: EMPTY_TASK_LOG,
1864
+ attempts: [],
1865
+ attempt: 0,
1866
+ pending: [],
1867
+ loaded: false,
1868
+ followLatest: true
1869
+ };
1870
+ function covered(position, batch) {
1871
+ return !!position && !!batch.position && position.stream === batch.position.stream && batch.position.seq <= position.seq;
1872
+ }
1873
+ function live(state, batch) {
1874
+ if (batch.attempt <= 0 || batch.attempt < state.attempt) return state;
1875
+ const attempts = state.attempts.includes(batch.attempt) ? state.attempts : [...state.attempts, batch.attempt].sort((a, b) => a - b);
1876
+ if (batch.attempt > state.attempt) {
1877
+ if (!state.followLatest) return attempts === state.attempts ? state : { ...state, attempts };
1878
+ return { ...state, attempts, attempt: batch.attempt, position: void 0, view: batch.events.reduce(reduceTaskLog, EMPTY_TASK_LOG) };
1879
+ }
1880
+ if (covered(state.position, batch)) return state;
1881
+ return { ...state, attempts, view: batch.events.reduce(reduceTaskLog, state.view) };
1882
+ }
1883
+ function followTaskLog(state, input) {
1884
+ switch (input.type) {
1885
+ case "opened":
1886
+ return EMPTY_TASK_LOG_FOLLOW;
1887
+ case "picked":
1888
+ return { ...state, loaded: false, loadingAttempt: input.attempt, followLatest: input.attempt === state.attempts.at(-1) };
1889
+ case "live":
1890
+ return state.loaded ? live(state, input) : { ...state, pending: [...state.pending, input] };
1891
+ case "loaded": {
1892
+ if (state.loaded) return state;
1893
+ if (!input.abandoned && state.loadingAttempt !== void 0 && input.attempt !== state.loadingAttempt) return state;
1894
+ const attempts = [.../* @__PURE__ */ new Set([...input.attempts ?? state.attempts, ...state.pending.map((batch) => batch.attempt)])].filter((attempt) => attempt > 0).sort((a, b) => a - b);
1895
+ let next = {
1896
+ ...state,
1897
+ attempts,
1898
+ loaded: true,
1899
+ pending: [],
1900
+ loadingAttempt: void 0,
1901
+ ...input.abandoned ? {} : { attempt: input.attempt, view: replayTaskLog(input.events), position: input.position }
1902
+ };
1903
+ for (const batch of state.pending) {
1904
+ if (!input.abandoned && batch.attempt === input.attempt) {
1905
+ if (covered(input.position, batch)) continue;
1906
+ if (!input.position && !batch.position) continue;
1907
+ }
1908
+ next = live(next, batch);
1909
+ }
1910
+ return next;
1911
+ }
1912
+ }
1913
+ }
1914
+
1764
1915
  // src/taskRow/actions.ts
1765
1916
  var UNSTARTED_AI = (t) => t.type === "ai" && NOT_STARTED.has(t.status);
1766
1917
  var QUEUED = (t) => t.status === "pending" || t.status === "approved";
@@ -1883,10 +2034,10 @@ function taskRowView(task, context = {}) {
1883
2034
  function titledRefs(ids, tasks) {
1884
2035
  return ids.map((id) => titledTaskRefOf(tasks, id) ?? id);
1885
2036
  }
1886
- function dependentsNotice(dependents) {
2037
+ function dependentsNotice(dependents, tasks = []) {
1887
2038
  if (dependents.length === 0) return null;
1888
2039
  const subject = dependents.length === 1 ? "1 task depends" : `${dependents.length} tasks depend`;
1889
- return `${subject} on it and will lose that dependency: ${dependents.map((t) => titledTaskRef(t)).join(", ")}.`;
2040
+ return `${subject} on it and will lose that dependency: ${dependents.map((t) => (t.id ? titledTaskRefOf(tasks, t.id) : void 0) ?? titledTaskRef(t)).join(", ")}.`;
1890
2041
  }
1891
2042
  function pastGateConfirmation(unmerged, subject = "This task") {
1892
2043
  return `${subject} waits for Merge all: the work of ${unmerged.join(", ")} is not merged into your branch yet, so it would act without it. Starting it now is kept on the task.`;
@@ -1907,6 +2058,7 @@ var EMPTY_RUN = { tasks: [], runMerge: null, handoff: null, mergeResult: null };
1907
2058
  EMPTY_HOLD,
1908
2059
  EMPTY_RUN,
1909
2060
  EMPTY_TASK_LOG,
2061
+ EMPTY_TASK_LOG_FOLLOW,
1910
2062
  NOT_STARTED,
1911
2063
  NO_TURN,
1912
2064
  SUPERVISOR_LEVEL_LABEL,
@@ -1927,6 +2079,7 @@ var EMPTY_RUN = { tasks: [], runMerge: null, handoff: null, mergeResult: null };
1927
2079
  canSetDependencies,
1928
2080
  canSplitTask,
1929
2081
  capConflictFiles,
2082
+ clampThinkingEffort,
1930
2083
  countedSessionCost,
1931
2084
  dependencyCandidates,
1932
2085
  dependentsNotice,
@@ -1936,6 +2089,7 @@ var EMPTY_RUN = { tasks: [], runMerge: null, handoff: null, mergeResult: null };
1936
2089
  diffSummary,
1937
2090
  drainNext,
1938
2091
  endAttemptUsage,
2092
+ followTaskLog,
1939
2093
  followTurn,
1940
2094
  fromTranscript,
1941
2095
  hasHiddenDetail,
@@ -1963,6 +2117,7 @@ var EMPTY_RUN = { tasks: [], runMerge: null, handoff: null, mergeResult: null };
1963
2117
  reduceTaskLog,
1964
2118
  replayTaskLog,
1965
2119
  resolveTaskRef,
2120
+ resolveUserTaskRef,
1966
2121
  resumeLabel,
1967
2122
  resumeTime,
1968
2123
  resumedSessionWindow,
@@ -1971,9 +2126,11 @@ var EMPTY_RUN = { tasks: [], runMerge: null, handoff: null, mergeResult: null };
1971
2126
  skippedLabel,
1972
2127
  startAttemptUsage,
1973
2128
  stopTurn,
2129
+ subtreeIds,
1974
2130
  summarizeToolCall,
1975
2131
  takeAt,
1976
2132
  taskOrderLabel,
2133
+ taskPlacement,
1977
2134
  taskRef,
1978
2135
  taskRefOf,
1979
2136
  taskRowActions,
@@ -1988,6 +2145,7 @@ var EMPTY_RUN = { tasks: [], runMerge: null, handoff: null, mergeResult: null };
1988
2145
  truncateCheckpointSummary,
1989
2146
  unsendAll,
1990
2147
  unsendLatest,
1991
- usageLine
2148
+ usageLine,
2149
+ walkPlan
1992
2150
  });
1993
2151
  //# sourceMappingURL=plan-utils.js.map