@ordewell/core 0.10.4 → 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 (49) hide show
  1. package/dist/{IRunner-D_UkkMbJ.d.ts → IFileSystem-C4_mpfze.d.ts} +159 -15
  2. package/dist/{IRunner-NtTHQgLR.d.mts → IFileSystem-DUgeWWQN.d.mts} +159 -15
  3. package/dist/{ModeResolver-wnTFsDnF.d.mts → ModeResolver-4qNjxcDs.d.mts} +1 -1
  4. package/dist/{ModeResolver-Dy3Ef6p-.d.ts → ModeResolver-DGK2rWHE.d.ts} +1 -1
  5. package/dist/{Task-DZs9eKgg.d.mts → Task-C0o4i3Nn.d.mts} +114 -13
  6. package/dist/{Task-DZs9eKgg.d.ts → Task-C0o4i3Nn.d.ts} +114 -13
  7. package/dist/{chunk-FH6M5QZG.mjs → chunk-DMG4ISUG.mjs} +1008 -49
  8. package/dist/chunk-DMG4ISUG.mjs.map +1 -0
  9. package/dist/{chunk-SM6BV6XS.mjs → chunk-EEE2GBLG.mjs} +116 -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-645FALZX.mjs → chunk-LTHKFBKM.mjs} +4 -4
  14. package/dist/chunk-LTHKFBKM.mjs.map +1 -0
  15. package/dist/{chunk-OYUSADFM.mjs → chunk-NJGID6BG.mjs} +3 -1
  16. package/dist/chunk-NJGID6BG.mjs.map +1 -0
  17. package/dist/index.d.mts +498 -1689
  18. package/dist/index.d.ts +498 -1689
  19. package/dist/index.js +4108 -2082
  20. package/dist/index.js.map +1 -1
  21. package/dist/index.mjs +3380 -1639
  22. package/dist/index.mjs.map +1 -1
  23. package/dist/parsing.d.mts +2 -2
  24. package/dist/parsing.d.ts +2 -2
  25. package/dist/parsing.js +231 -75
  26. package/dist/parsing.js.map +1 -1
  27. package/dist/parsing.mjs +3 -3
  28. package/dist/plan-utils.d.mts +20 -4
  29. package/dist/plan-utils.d.ts +20 -4
  30. package/dist/plan-utils.js +335 -88
  31. package/dist/plan-utils.js.map +1 -1
  32. package/dist/plan-utils.mjs +43 -19
  33. package/dist/{plan-utils-CtKceSsQ.d.mts → runSettingsText-BgOmLxdw.d.mts} +2242 -224
  34. package/dist/{plan-utils-POIz5d8z.d.ts → runSettingsText-BgXvajj2.d.ts} +2242 -224
  35. package/dist/testing.d.mts +5 -3
  36. package/dist/testing.d.ts +5 -3
  37. package/dist/testing.js +7 -0
  38. package/dist/testing.js.map +1 -1
  39. package/dist/testing.mjs +7 -2
  40. package/dist/testing.mjs.map +1 -1
  41. package/package.json +1 -1
  42. package/dist/IFileSystem-_effm8-b.d.ts +0 -78
  43. package/dist/IFileSystem-vyqMdL-x.d.mts +0 -78
  44. package/dist/chunk-645FALZX.mjs.map +0 -1
  45. package/dist/chunk-A57ITQE7.mjs +0 -1378
  46. package/dist/chunk-A57ITQE7.mjs.map +0 -1
  47. package/dist/chunk-FH6M5QZG.mjs.map +0 -1
  48. package/dist/chunk-OYUSADFM.mjs.map +0 -1
  49. package/dist/chunk-SM6BV6XS.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,
@@ -47,6 +48,8 @@ __export(plan_utils_exports, {
47
48
  addUsageTotals: () => addUsageTotals,
48
49
  aheadOfDraft: () => aheadOfDraft,
49
50
  approvalLabel: () => approvalLabel,
51
+ assignmentIssue: () => assignmentIssue,
52
+ assignmentIssueText: () => assignmentIssueText,
50
53
  awaitingLabel: () => awaitingLabel,
51
54
  blockedByLabel: () => blockedByLabel,
52
55
  blockingFailures: () => blockingFailures,
@@ -54,6 +57,8 @@ __export(plan_utils_exports, {
54
57
  canSetDependencies: () => canSetDependencies,
55
58
  canSplitTask: () => canSplitTask,
56
59
  capConflictFiles: () => capConflictFiles,
60
+ clampThinkingEffort: () => clampThinkingEffort,
61
+ countedSessionCost: () => countedSessionCost,
57
62
  dependencyCandidates: () => dependencyCandidates,
58
63
  dependentsNotice: () => dependentsNotice,
59
64
  dependentsOf: () => dependentsOf,
@@ -62,6 +67,7 @@ __export(plan_utils_exports, {
62
67
  diffSummary: () => diffSummary,
63
68
  drainNext: () => drainNext,
64
69
  endAttemptUsage: () => endAttemptUsage,
70
+ followTaskLog: () => followTaskLog,
65
71
  followTurn: () => followTurn,
66
72
  fromTranscript: () => fromTranscript,
67
73
  hasHiddenDetail: () => hasHiddenDetail,
@@ -89,22 +95,27 @@ __export(plan_utils_exports, {
89
95
  reduceTaskLog: () => reduceTaskLog,
90
96
  replayTaskLog: () => replayTaskLog,
91
97
  resolveTaskRef: () => resolveTaskRef,
98
+ resolveUserTaskRef: () => resolveUserTaskRef,
92
99
  resumeLabel: () => resumeLabel,
93
100
  resumeTime: () => resumeTime,
101
+ resumedSessionWindow: () => resumedSessionWindow,
94
102
  runnerToolSubject: () => runnerToolSubject,
95
103
  skillTokens: () => skillTokens,
96
104
  skippedLabel: () => skippedLabel,
97
105
  startAttemptUsage: () => startAttemptUsage,
98
106
  stopTurn: () => stopTurn,
107
+ subtreeIds: () => subtreeIds,
99
108
  summarizeToolCall: () => summarizeToolCall,
100
109
  takeAt: () => takeAt,
101
110
  taskOrderLabel: () => taskOrderLabel,
111
+ taskPlacement: () => taskPlacement,
102
112
  taskRef: () => taskRef,
103
113
  taskRefOf: () => taskRefOf,
104
114
  taskRowActions: () => taskRowActions,
105
115
  taskRowView: () => taskRowView,
106
116
  taskStartedNotice: () => taskStartedNotice,
107
117
  taskStatusKind: () => taskStatusKind,
118
+ taskUsageSummary: () => taskUsageSummary,
108
119
  titledRefs: () => titledRefs,
109
120
  titledTaskRef: () => titledTaskRef,
110
121
  titledTaskRefOf: () => titledTaskRefOf,
@@ -112,7 +123,8 @@ __export(plan_utils_exports, {
112
123
  truncateCheckpointSummary: () => truncateCheckpointSummary,
113
124
  unsendAll: () => unsendAll,
114
125
  unsendLatest: () => unsendLatest,
115
- usageLine: () => usageLine
126
+ usageLine: () => usageLine,
127
+ walkPlan: () => walkPlan
116
128
  });
117
129
  module.exports = __toCommonJS(plan_utils_exports);
118
130
 
@@ -138,6 +150,90 @@ function loadedSkillTokens(text2, loaded) {
138
150
  return skillTokens(text2).filter((t) => loaded.includes(t.name));
139
151
  }
140
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
+
141
237
  // src/services/TaskRefs.ts
142
238
  function taskOrderLabel(task, parent) {
143
239
  return parent ? `${parent.label ?? parent.order}.${task.order}` : String(task.order);
@@ -148,16 +244,8 @@ function taskRef(task, parent) {
148
244
  function titledTaskRef(task, parent) {
149
245
  return `${taskRef(task, parent)} ${task.title}`;
150
246
  }
151
- function* depthFirst(tasks, parent, parentLabel) {
152
- for (const task of tasks) {
153
- const label = taskOrderLabel(task, parent ? { order: parent.order, label: parentLabel } : void 0);
154
- yield { task, parent, label };
155
- yield* depthFirst(task.subtasks ?? [], task, label);
156
- }
157
- }
158
247
  function findTaskRef(tasks, id) {
159
- for (const match of depthFirst(tasks)) if (match.task.id === id) return match;
160
- return void 0;
248
+ return taskPlacement(tasks, id);
161
249
  }
162
250
  function taskRefOf(tasks, id) {
163
251
  const found = findTaskRef(tasks, id);
@@ -170,7 +258,7 @@ function titledTaskRefOf(tasks, id) {
170
258
  function resolveTaskRef(tasks, ref) {
171
259
  const s = String(ref).trim();
172
260
  if (!s) return void 0;
173
- 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;
174
262
  const label = s.startsWith("#") ? s.slice(1) : s;
175
263
  if (/^\d+(\.\d+)*$/.test(label)) {
176
264
  let level = tasks;
@@ -181,9 +269,16 @@ function resolveTaskRef(tasks, ref) {
181
269
  }
182
270
  return found;
183
271
  }
184
- 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;
185
273
  return void 0;
186
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
+ }
187
282
 
188
283
  // src/models/Task.ts
189
284
  var SKILL_NAME = new RegExp(`^${SKILL_NAME_PATTERN}$`);
@@ -230,7 +325,7 @@ function blockedByLabel(refs) {
230
325
  function skippedLabel(reason) {
231
326
  return reason ? `Skipped: ${reason}` : "Skipped";
232
327
  }
233
- var WAITS_FOR_APPROVAL_LABEL = "Waiting for your approval to start";
328
+ var WAITS_FOR_APPROVAL_LABEL = "Waits for your approval";
234
329
  function approvalLabel(count) {
235
330
  if (!count) return null;
236
331
  return count > 1 ? `Waiting for approval (${count})` : "Waiting for approval";
@@ -248,28 +343,43 @@ function resumeLabel(task, now = /* @__PURE__ */ new Date()) {
248
343
 
249
344
  // src/services/PlannedTask.ts
250
345
  var import_uuid2 = require("uuid");
251
- function findCycle(tasks) {
252
- const byId = new Map(tasks.map((t) => [t.id, t]));
253
- const path = [];
254
- const done = /* @__PURE__ */ new Set();
255
- const visit = (id) => {
256
- if (done.has(id)) return null;
257
- const at = path.indexOf(id);
258
- if (at >= 0) return path.slice(at);
259
- path.push(id);
260
- for (const dep of byId.get(id)?.dependencies ?? []) {
261
- const hit = visit(dep);
262
- if (hit) return hit;
263
- }
264
- path.pop();
265
- done.add(id);
266
- return null;
267
- };
268
- for (const t of tasks) {
269
- const hit = visit(t.id);
270
- 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);
271
356
  }
272
- 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);
273
383
  }
274
384
  function detectCycle(tasks) {
275
385
  return findCycle(tasks)?.[0].title ?? null;
@@ -294,28 +404,6 @@ function canMergeTasks(tasks, selectedIds) {
294
404
  if (cycle) return { ok: false, error: `Merging would create a dependency cycle involving "${cycle}"` };
295
405
  return { ok: true };
296
406
  }
297
- function dependentsOf(tasks, taskId) {
298
- return tasks.filter((t) => t.id !== taskId && t.dependencies.includes(taskId));
299
- }
300
- function dependencyCandidates(tasks, taskId) {
301
- if (!taskId) return [...tasks];
302
- const target = tasks.find((t) => t.id === taskId);
303
- return target ? tasks.filter((t) => t.order < target.order) : [];
304
- }
305
- function canSetDependencies(tasks, taskId, dependencies) {
306
- const target = tasks.find((t) => t.id === taskId);
307
- if (!target) return { ok: false, error: "Task not found" };
308
- const allowed = new Set(dependencyCandidates(tasks, taskId).map((t) => t.id));
309
- for (const dep of dependencies) {
310
- if (dep === taskId) return { ok: false, error: `"${target.title}" cannot depend on itself` };
311
- const found = tasks.find((t) => t.id === dep);
312
- if (!found) return { ok: false, error: `Unknown dependency "${dep}"` };
313
- if (!allowed.has(dep)) {
314
- return { ok: false, error: `"${target.title}" cannot depend on "${found.title}", which comes after it in the plan` };
315
- }
316
- }
317
- return { ok: true };
318
- }
319
407
  function canSplitTask(tasks, taskId) {
320
408
  const target = tasks.find((t) => t.id === taskId);
321
409
  if (!target) return { ok: false, error: "Task not found" };
@@ -638,7 +726,7 @@ function planMarker(content) {
638
726
  }
639
727
 
640
728
  // src/services/blocking.ts
641
- var UNSTARTED = /* @__PURE__ */ new Set(["pending", "approved", "blocked"]);
729
+ var UNSTARTED = /* @__PURE__ */ new Set(["pending", "approved"]);
642
730
  function blockingFailures(tasks) {
643
731
  const byId = /* @__PURE__ */ new Map();
644
732
  const index = (list) => {
@@ -764,8 +852,21 @@ function addAttemptUsage(usage, record, now) {
764
852
  const folded = addPlannerUsage(usage, record);
765
853
  return { ...usage, ...folded, lastPromptTokens: folded.lastPromptTokens, contextWindow: folded.contextWindow, wallTimeMs: Math.max(0, Date.parse(now) - Date.parse(usage.startedAt)) };
766
854
  }
767
- function endAttemptUsage(usage, now) {
768
- return { ...usage, endedAt: now, wallTimeMs: Math.max(0, Date.parse(now) - Date.parse(usage.startedAt)) };
855
+ function endAttemptUsage(usage, now, runnerSessionCost, sessionId) {
856
+ return {
857
+ ...usage,
858
+ endedAt: now,
859
+ wallTimeMs: Math.max(0, Date.parse(now) - Date.parse(usage.startedAt)),
860
+ ...sessionId ? { sessionId } : {},
861
+ ...runnerSessionCost ? { runnerSessionCost } : {}
862
+ };
863
+ }
864
+ function countedSessionCost(attempts, sessionId) {
865
+ return [...attempts ?? []].reverse().find((usage) => usage.runnerSessionCost?.sessionId === sessionId)?.runnerSessionCost;
866
+ }
867
+ function resumedSessionWindow(attempts, runner, attempt, sessionId) {
868
+ const last = [...attempts ?? []].reverse().find((usage) => usage.attempt !== attempt && usage.runner === runner && usage.sessionId === sessionId && usage.contextWindow !== void 0);
869
+ return last ? { source: last.source, model: last.model, contextWindow: last.contextWindow } : void 0;
769
870
  }
770
871
  function addUsageTotals(totals, addition) {
771
872
  let next = addUsage(totals, { source: "", inputTokens: addition.inputTokens, outputTokens: addition.outputTokens, cachedInputTokens: addition.cachedInputTokens });
@@ -794,6 +895,16 @@ function planUsage(tasks) {
794
895
  }
795
896
  return result;
796
897
  }
898
+ function taskUsageSummary(task) {
899
+ const attempts = task.attemptUsage ?? [];
900
+ const latest = attempts.at(-1);
901
+ const contextFill = latest ? plannerContextFill(latest) : void 0;
902
+ return {
903
+ totals: attempts.reduce((sum, attempt) => addUsageTotals(sum, attempt.totals), {}),
904
+ attempts: attempts.length,
905
+ ...contextFill ? { contextFill } : {}
906
+ };
907
+ }
797
908
 
798
909
  // src/conversation/lanes.ts
799
910
  function findLastIndex(items, match) {
@@ -990,8 +1101,9 @@ function dropBuildingPlan(view, turnId, segmentId) {
990
1101
  const blocks = view.blocks.filter((b) => !(isBuildingPlan(b, turnId) && (segmentId === void 0 || b.segmentId === segmentId)));
991
1102
  return blocks.length === view.blocks.length ? view : { ...view, blocks };
992
1103
  }
993
- function settleReply(view, { content, turnId, supervisor }) {
1104
+ function settleReply(view, { content, turnId, supervisor, runs }) {
994
1105
  const role = supervisor ? "supervisor" : "planner";
1106
+ if (runs) return settleRuns(view, runs, role, turnId);
995
1107
  if (turnId !== void 0) {
996
1108
  const i = finalSegmentIndex(view.blocks, turnId);
997
1109
  if (i >= 0) {
@@ -1000,6 +1112,25 @@ function settleReply(view, { content, turnId, supervisor }) {
1000
1112
  }
1001
1113
  return append(dropBuildingPlan(view, turnId), (id) => settledMessage(id, role, content, turnId));
1002
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
+ }
1003
1134
  function retractText(view, { turnId, segmentId }) {
1004
1135
  const blocks = view.blocks.filter((b) => !(isUnsettledSegment(b, turnId) && (segmentId === void 0 || b.segmentId === segmentId)));
1005
1136
  return dropBuildingPlan(blocks.length === view.blocks.length ? view : { ...view, blocks }, turnId, segmentId);
@@ -1116,6 +1247,7 @@ function syncTranscript(view, { plan, turnId }) {
1116
1247
  if (isNew && entry.kind === "wake_up") next = takePendingInputs(next, void 0, [entry.content]).view;
1117
1248
  if (isNew && entry.kind === "plan_generated") next = markPlan(next, entry.content, i === committed ? turnId : void 0);
1118
1249
  if (isNew && entry.kind === "system") next = append(next, (id) => settledMessage(id, "system", entry.content));
1250
+ if (isNew && entry.kind === "error") next = append(next, (id) => settledMessage(id, "error", entry.content));
1119
1251
  if (isNew && entry.kind === "compaction") next = markCompaction(next, entry.content);
1120
1252
  if (latest === void 0 || entry.timestamp > latest) latest = entry.timestamp;
1121
1253
  }
@@ -1196,6 +1328,8 @@ function roleOf(entry) {
1196
1328
  return "wake_up";
1197
1329
  case "supervisor":
1198
1330
  return "supervisor";
1331
+ case "error":
1332
+ return "error";
1199
1333
  default:
1200
1334
  return entry.role === "user" ? "user" : "planner";
1201
1335
  }
@@ -1273,7 +1407,7 @@ function fromTranscript(conversationHistory, researchLog, plannerUsage, pendingT
1273
1407
  const kept = compacted ? history.slice(1) : history;
1274
1408
  const cutoff = compacted ? kept[0]?.timestamp ?? compacted.timestamp : "";
1275
1409
  const placed = [
1276
- ...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)) }]),
1277
1411
  ...research(researchLog ?? []).filter((item) => item.at >= cutoff)
1278
1412
  ];
1279
1413
  placed.sort((a, b) => a.at < b.at ? -1 : a.at > b.at ? 1 : a.rank - b.rank);
@@ -1306,7 +1440,7 @@ function sameMessage(a, b) {
1306
1440
 
1307
1441
  // src/conversation/taskLog.ts
1308
1442
  var EMPTY_TASK_LOG = { blocks: [], nextId: 1, queued: [], working: false, streams: {} };
1309
- var TEXT_STREAM = "text";
1443
+ var textStream = (runId) => runId === void 0 ? "text" : `text:${runId}`;
1310
1444
  var thinkingStream = (subagentId) => `thinking:${subagentId ?? ""}`;
1311
1445
  function withoutStream(view, key) {
1312
1446
  if (!(key in view.streams)) return view;
@@ -1323,35 +1457,43 @@ function openStream(view, lane, key) {
1323
1457
  const block = blocks[i];
1324
1458
  return block?.id === id && (block.type === "message" || block.type === "thinking") && block.streaming ? i : -1;
1325
1459
  }
1326
- function streamDelta(view, lane, key, text2, make) {
1327
- 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);
1328
1466
  const open = laneBlocks(view, lane)[i];
1329
1467
  if (open?.type === "message" || open?.type === "thinking") return laneReplace(view, lane, i, { ...open, text: open.text + text2 });
1330
1468
  const next = appendOutput(view, lane, (id) => make(id, blockText(text2)));
1331
1469
  return { ...next, streams: { ...next.streams, [key]: `b${view.nextId}` } };
1332
1470
  }
1333
1471
  function streamWhole(view, lane, key, text2, make) {
1334
- const id = view.streams[key];
1335
- const blocks = laneBlocks(view, lane);
1336
- const i = id === void 0 ? -1 : findLastIndex(blocks, (b) => b.id === id);
1337
- const streamed = blocks[i];
1472
+ const i = streamBlock(view, lane, key);
1473
+ const streamed = laneBlocks(view, lane)[i];
1338
1474
  const next = withoutStream(view, key);
1339
1475
  if (streamed?.type === "message" || streamed?.type === "thinking") {
1340
1476
  return laneReplace(next, lane, i, { ...streamed, text: blockText(text2), streaming: false });
1341
1477
  }
1342
1478
  return appendOutput(next, lane, make);
1343
1479
  }
1344
- function agentText(view, text2) {
1345
- const next = streamWhole(view, null, TEXT_STREAM, text2, (id) => settledMessage(id, "agent", blockText(text2)));
1346
- 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;
1482
+ }
1483
+ function agentText(view, { runId, text: text2 }) {
1484
+ return openedText(view, streamWhole(view, null, textStream(runId), text2, (id) => settledMessage(id, "agent", blockText(text2))));
1347
1485
  }
1348
- function agentTextDelta(view, text2) {
1349
- const next = streamDelta(view, null, TEXT_STREAM, text2, (id, t) => ({ type: "message", id, role: "agent", text: t, streaming: true }));
1350
- return { ...next, latestText: next.streams[TEXT_STREAM] };
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));
1351
1489
  }
1352
1490
  function failTurn(view, message) {
1353
1491
  const repeated = view.blocks.find((b) => b.id === view.latestText);
1354
- 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;
1355
1497
  return appendOutput({ ...settled, latestText: void 0 }, null, (id) => settledMessage(id, "error", message));
1356
1498
  }
1357
1499
  function thinkingBlock(id, text2, streaming, subagentId) {
@@ -1481,6 +1623,12 @@ function commandOutput(view, { text: text2 }) {
1481
1623
  return { ...view, blocks: replaceAt(view.blocks, i, { ...block, output: block.output ? `${block.output}
1482
1624
  ${text2}` : text2 }) };
1483
1625
  }
1626
+ function modelSwitchNotice({ from, to, plan, kept }) {
1627
+ if (!plan) return `Model changed in the runner: ${from.label ?? from.model} \u2192 ${to.label ?? to.model}${kept ? ` (${kept})` : ""}`;
1628
+ const planned = plan.model ? `${plan.model.label ?? plan.model.model}${plan.effort ? `, ${plan.effort}` : ""}` : void 0;
1629
+ if (!kept) return `Model changed in the runner: ${from.label ?? from.model} \u2192 ${to.label ?? to.model}; the plan now says ${planned ?? to.label ?? to.model}`;
1630
+ return `The runner now answers on ${to.label ?? to.model}; ${planned ? `the plan still says ${planned}` : "the plan names no model"} (${kept})`;
1631
+ }
1484
1632
  function appendStep(view, make) {
1485
1633
  const next = append(view, make);
1486
1634
  return sealLane(next, null, findLastIndex(next.blocks, (b) => b.type !== "usage"));
@@ -1526,7 +1674,7 @@ function endCall(block) {
1526
1674
  function endOpenCalls(view) {
1527
1675
  let changed = false;
1528
1676
  const blocks = view.blocks.map((block) => {
1529
- 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;
1530
1678
  if (ended !== block) changed = true;
1531
1679
  return ended;
1532
1680
  });
@@ -1542,6 +1690,8 @@ function reduceTaskLog(view, event) {
1542
1690
  return startCommand(view, event);
1543
1691
  case "command_output":
1544
1692
  return commandOutput(view, event);
1693
+ case "model_switched":
1694
+ return append(view, (id) => settledMessage(id, "system", modelSwitchNotice(event)));
1545
1695
  case "compaction":
1546
1696
  return appendStep(view, (id) => ({
1547
1697
  type: "compaction",
@@ -1555,9 +1705,9 @@ function reduceTaskLog(view, event) {
1555
1705
  case "turn_end":
1556
1706
  return endTurn2(view, event);
1557
1707
  case "text_delta":
1558
- return agentTextDelta(view, event.text);
1708
+ return agentTextDelta(view, event);
1559
1709
  case "text":
1560
- return agentText(view, event.text);
1710
+ return agentText(view, event);
1561
1711
  case "thinking_delta":
1562
1712
  return thinkingDelta(view, event);
1563
1713
  case "thinking":
@@ -1591,7 +1741,7 @@ function reduceTaskLog(view, event) {
1591
1741
  case "approval_withdrawn":
1592
1742
  return settleApproval2(view, event.approvalId, (block) => ({ ...block, status: "withdrawn" }));
1593
1743
  case "runner_ended":
1594
- return endOpenCalls(view);
1744
+ return closeOpenBlocks({ ...endOpenCalls(view), working: false, streams: {}, latestText: void 0 }, "stopped");
1595
1745
  default:
1596
1746
  return view;
1597
1747
  }
@@ -1646,16 +1796,16 @@ function cutOff(gate, input) {
1646
1796
  const turnId = "turnId" in input ? input.turnId : void 0;
1647
1797
  return turnId === void 0 || turnId === gate.stopped;
1648
1798
  }
1649
- function withGate(live, gate) {
1650
- 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 };
1651
1801
  }
1652
1802
  function followTurn(view, gate, input) {
1653
- const live = { view, gate };
1803
+ const live2 = { view, gate };
1654
1804
  if (input.type === "planner_turn_started") {
1655
1805
  return withGate({ view: reduceConversation(view, input), gate }, { open: input.turnId, stopped: null });
1656
1806
  }
1657
1807
  if (cutOff(gate, input)) {
1658
- 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;
1659
1809
  }
1660
1810
  const next = { view: reduceConversation(view, input), gate };
1661
1811
  return input.type === "planner_turn_ended" && input.turnId === gate.open ? withGate(next, { ...gate, open: null }) : next;
@@ -1708,6 +1858,60 @@ function markdownHtml(text2) {
1708
1858
  return md.render(text2);
1709
1859
  }
1710
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
+
1711
1915
  // src/taskRow/actions.ts
1712
1916
  var UNSTARTED_AI = (t) => t.type === "ai" && NOT_STARTED.has(t.status);
1713
1917
  var QUEUED = (t) => t.status === "pending" || t.status === "approved";
@@ -1752,6 +1956,31 @@ function opsEditable(task) {
1752
1956
  return UNSTARTED_AI(task);
1753
1957
  }
1754
1958
 
1959
+ // src/services/AssignmentScope.ts
1960
+ var OVER = /* @__PURE__ */ new Set(["completed", "skipped"]);
1961
+ function assignmentIssue(task, scope) {
1962
+ if (task.type !== "ai" || OVER.has(task.status)) return null;
1963
+ if (!scope.enabledRunners.includes(task.assignedRunner)) return { kind: "runner-off", runner: task.assignedRunner };
1964
+ const model = task.assignedModel;
1965
+ const allowed = effectiveAllowlist(scope.allowlist[task.assignedRunner], task.assignedRunner, scope.models);
1966
+ if (model && allowed && !allowed.includes(model.modelId)) {
1967
+ return { kind: "model-off-list", runner: task.assignedRunner, modelId: model.modelId, modelLabel: model.modelLabel || model.modelId };
1968
+ }
1969
+ return null;
1970
+ }
1971
+ function assignmentIssueText(issue) {
1972
+ return issue.kind === "runner-off" ? `${issue.runner} is switched off` : `${issue.modelLabel} is not in the allowlist`;
1973
+ }
1974
+ function assignmentConsequence({ status, awaitingReason, resumeAt }) {
1975
+ if (status === "failed") return "failed; a retry would run it there unless moved";
1976
+ if (status === "awaiting_user" && awaitingReason === "usage-limit") {
1977
+ return resumeAt ? "paused on a usage limit; resumes there at the reset unless moved" : "paused on a usage limit; a retry would run it there unless moved";
1978
+ }
1979
+ if (status === "awaiting_user" && (awaitingReason === "conflict" || awaitingReason === "files-changed")) return "waiting for the user; what runs next runs there unless moved";
1980
+ if (status === "in_progress" || status === "awaiting_user") return "already running as assigned";
1981
+ return "runs as assigned unless moved";
1982
+ }
1983
+
1755
1984
  // src/taskRow/view.ts
1756
1985
  var refsOf = (ids, tasks) => ids.map((id) => tasks?.length ? taskRefOf(tasks, id) ?? id : id);
1757
1986
  var namedRepo = (repo) => repo && repo !== "." ? repo : null;
@@ -1762,13 +1991,18 @@ function blockedBy(task, tasks) {
1762
1991
  if (!tasks?.length || !NOT_STARTED.has(task.status)) return [];
1763
1992
  return blockingFailures(asBlocking(tasks)).get(task.id) ?? [];
1764
1993
  }
1994
+ function flagOf(task, scope) {
1995
+ const issue = scope && task.assignedRunner !== void 0 ? assignmentIssue({ ...task, assignedRunner: task.assignedRunner }, scope) : null;
1996
+ return issue ? { assignmentFlag: assignmentIssueText(issue), assignmentConsequence: assignmentConsequence(task) } : { assignmentFlag: null, assignmentConsequence: null };
1997
+ }
1765
1998
  function taskRowView(task, context = {}) {
1766
1999
  const parent = context.parent ?? void 0;
1767
2000
  const isolation = task.isolation && task.isolation.state !== "none" ? task.isolation : null;
1768
- const latestUsage = task.attemptUsage?.at(-1);
2001
+ const spend = taskUsageSummary(task);
2002
+ const latestAttempt = task.attemptUsage?.at(-1);
1769
2003
  const blocked = blockedBy(task, context.tasks);
1770
2004
  return {
1771
- usage: latestUsage ? { ...usageLine(latestUsage), attempt: latestUsage.attempt, wallTimeMs: latestUsage.wallTimeMs, byModel: latestUsage.byModel } : task.type === "ai" && ["completed", "failed", "in_progress", "awaiting_user"].includes(task.status) ? { totals: {}, attempt: 0, byModel: [] } : null,
2005
+ usage: latestAttempt ? { totals: spend.totals, ...spend.contextFill ? { contextFill: spend.contextFill } : {}, attempt: latestAttempt.attempt } : task.type === "ai" && ["completed", "failed", "in_progress", "awaiting_user"].includes(task.status) ? { totals: {}, attempt: 0 } : null,
1772
2006
  orderLabel: taskOrderLabel(task, parent),
1773
2007
  kind: task.type === "user" ? "user" : task.ops ? "ops" : "ai",
1774
2008
  status: blocked.length > 0 ? "blocked" : taskStatusKind(task),
@@ -1777,6 +2011,7 @@ function taskRowView(task, context = {}) {
1777
2011
  resumes: resumeLabel(task, context.now),
1778
2012
  approvals: approvalLabel(task.awaitingApproval),
1779
2013
  waitsForApproval: task.waitsForApproval && NOT_STARTED.has(task.status) ? WAITS_FOR_APPROVAL_LABEL : null,
2014
+ ...flagOf(task, context.runnerScope),
1780
2015
  autonomous: task.type === "ai" && context.modes?.find((m) => m.id === task.taskMode)?.autonomous === true,
1781
2016
  repos: namedRepos(isolation?.repos),
1782
2017
  conflict: isolation?.state === "conflict" ? { repo: namedRepo(isolation.conflictRepo), files: filesOf(isolation.conflictFiles) } : null,
@@ -1799,10 +2034,10 @@ function taskRowView(task, context = {}) {
1799
2034
  function titledRefs(ids, tasks) {
1800
2035
  return ids.map((id) => titledTaskRefOf(tasks, id) ?? id);
1801
2036
  }
1802
- function dependentsNotice(dependents) {
2037
+ function dependentsNotice(dependents, tasks = []) {
1803
2038
  if (dependents.length === 0) return null;
1804
2039
  const subject = dependents.length === 1 ? "1 task depends" : `${dependents.length} tasks depend`;
1805
- 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(", ")}.`;
1806
2041
  }
1807
2042
  function pastGateConfirmation(unmerged, subject = "This task") {
1808
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.`;
@@ -1823,6 +2058,7 @@ var EMPTY_RUN = { tasks: [], runMerge: null, handoff: null, mergeResult: null };
1823
2058
  EMPTY_HOLD,
1824
2059
  EMPTY_RUN,
1825
2060
  EMPTY_TASK_LOG,
2061
+ EMPTY_TASK_LOG_FOLLOW,
1826
2062
  NOT_STARTED,
1827
2063
  NO_TURN,
1828
2064
  SUPERVISOR_LEVEL_LABEL,
@@ -1834,6 +2070,8 @@ var EMPTY_RUN = { tasks: [], runMerge: null, handoff: null, mergeResult: null };
1834
2070
  addUsageTotals,
1835
2071
  aheadOfDraft,
1836
2072
  approvalLabel,
2073
+ assignmentIssue,
2074
+ assignmentIssueText,
1837
2075
  awaitingLabel,
1838
2076
  blockedByLabel,
1839
2077
  blockingFailures,
@@ -1841,6 +2079,8 @@ var EMPTY_RUN = { tasks: [], runMerge: null, handoff: null, mergeResult: null };
1841
2079
  canSetDependencies,
1842
2080
  canSplitTask,
1843
2081
  capConflictFiles,
2082
+ clampThinkingEffort,
2083
+ countedSessionCost,
1844
2084
  dependencyCandidates,
1845
2085
  dependentsNotice,
1846
2086
  dependentsOf,
@@ -1849,6 +2089,7 @@ var EMPTY_RUN = { tasks: [], runMerge: null, handoff: null, mergeResult: null };
1849
2089
  diffSummary,
1850
2090
  drainNext,
1851
2091
  endAttemptUsage,
2092
+ followTaskLog,
1852
2093
  followTurn,
1853
2094
  fromTranscript,
1854
2095
  hasHiddenDetail,
@@ -1876,22 +2117,27 @@ var EMPTY_RUN = { tasks: [], runMerge: null, handoff: null, mergeResult: null };
1876
2117
  reduceTaskLog,
1877
2118
  replayTaskLog,
1878
2119
  resolveTaskRef,
2120
+ resolveUserTaskRef,
1879
2121
  resumeLabel,
1880
2122
  resumeTime,
2123
+ resumedSessionWindow,
1881
2124
  runnerToolSubject,
1882
2125
  skillTokens,
1883
2126
  skippedLabel,
1884
2127
  startAttemptUsage,
1885
2128
  stopTurn,
2129
+ subtreeIds,
1886
2130
  summarizeToolCall,
1887
2131
  takeAt,
1888
2132
  taskOrderLabel,
2133
+ taskPlacement,
1889
2134
  taskRef,
1890
2135
  taskRefOf,
1891
2136
  taskRowActions,
1892
2137
  taskRowView,
1893
2138
  taskStartedNotice,
1894
2139
  taskStatusKind,
2140
+ taskUsageSummary,
1895
2141
  titledRefs,
1896
2142
  titledTaskRef,
1897
2143
  titledTaskRefOf,
@@ -1899,6 +2145,7 @@ var EMPTY_RUN = { tasks: [], runMerge: null, handoff: null, mergeResult: null };
1899
2145
  truncateCheckpointSummary,
1900
2146
  unsendAll,
1901
2147
  unsendLatest,
1902
- usageLine
2148
+ usageLine,
2149
+ walkPlan
1903
2150
  });
1904
2151
  //# sourceMappingURL=plan-utils.js.map