@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.
- package/dist/{IRunner-D_UkkMbJ.d.ts → IFileSystem-C4_mpfze.d.ts} +159 -15
- package/dist/{IRunner-NtTHQgLR.d.mts → IFileSystem-DUgeWWQN.d.mts} +159 -15
- package/dist/{ModeResolver-wnTFsDnF.d.mts → ModeResolver-4qNjxcDs.d.mts} +1 -1
- package/dist/{ModeResolver-Dy3Ef6p-.d.ts → ModeResolver-DGK2rWHE.d.ts} +1 -1
- package/dist/{Task-DZs9eKgg.d.mts → Task-C0o4i3Nn.d.mts} +114 -13
- package/dist/{Task-DZs9eKgg.d.ts → Task-C0o4i3Nn.d.ts} +114 -13
- package/dist/{chunk-FH6M5QZG.mjs → chunk-DMG4ISUG.mjs} +1008 -49
- package/dist/chunk-DMG4ISUG.mjs.map +1 -0
- package/dist/{chunk-SM6BV6XS.mjs → chunk-EEE2GBLG.mjs} +116 -27
- package/dist/chunk-EEE2GBLG.mjs.map +1 -0
- package/dist/chunk-H7QX32BH.mjs +647 -0
- package/dist/chunk-H7QX32BH.mjs.map +1 -0
- package/dist/{chunk-645FALZX.mjs → chunk-LTHKFBKM.mjs} +4 -4
- package/dist/chunk-LTHKFBKM.mjs.map +1 -0
- package/dist/{chunk-OYUSADFM.mjs → chunk-NJGID6BG.mjs} +3 -1
- package/dist/chunk-NJGID6BG.mjs.map +1 -0
- package/dist/index.d.mts +498 -1689
- package/dist/index.d.ts +498 -1689
- package/dist/index.js +4108 -2082
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3380 -1639
- package/dist/index.mjs.map +1 -1
- package/dist/parsing.d.mts +2 -2
- package/dist/parsing.d.ts +2 -2
- package/dist/parsing.js +231 -75
- package/dist/parsing.js.map +1 -1
- package/dist/parsing.mjs +3 -3
- package/dist/plan-utils.d.mts +20 -4
- package/dist/plan-utils.d.ts +20 -4
- package/dist/plan-utils.js +335 -88
- package/dist/plan-utils.js.map +1 -1
- package/dist/plan-utils.mjs +43 -19
- package/dist/{plan-utils-CtKceSsQ.d.mts → runSettingsText-BgOmLxdw.d.mts} +2242 -224
- package/dist/{plan-utils-POIz5d8z.d.ts → runSettingsText-BgXvajj2.d.ts} +2242 -224
- package/dist/testing.d.mts +5 -3
- package/dist/testing.d.ts +5 -3
- package/dist/testing.js +7 -0
- package/dist/testing.js.map +1 -1
- package/dist/testing.mjs +7 -2
- package/dist/testing.mjs.map +1 -1
- package/package.json +1 -1
- package/dist/IFileSystem-_effm8-b.d.ts +0 -78
- package/dist/IFileSystem-vyqMdL-x.d.mts +0 -78
- package/dist/chunk-645FALZX.mjs.map +0 -1
- package/dist/chunk-A57ITQE7.mjs +0 -1378
- package/dist/chunk-A57ITQE7.mjs.map +0 -1
- package/dist/chunk-FH6M5QZG.mjs.map +0 -1
- package/dist/chunk-OYUSADFM.mjs.map +0 -1
- package/dist/chunk-SM6BV6XS.mjs.map +0 -1
package/dist/plan-utils.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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
|
|
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 = "
|
|
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
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
for (const
|
|
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
|
-
|
|
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"
|
|
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 {
|
|
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.
|
|
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
|
|
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
|
|
1327
|
-
const
|
|
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
|
|
1335
|
-
const
|
|
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
|
|
1345
|
-
|
|
1346
|
-
|
|
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
|
|
1350
|
-
return
|
|
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) ?
|
|
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
|
|
1708
|
+
return agentTextDelta(view, event);
|
|
1559
1709
|
case "text":
|
|
1560
|
-
return agentText(view, event
|
|
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(
|
|
1650
|
-
return gate.open ===
|
|
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
|
|
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(
|
|
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
|
|
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:
|
|
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
|