@ordewell/core 0.11.3 → 0.12.1
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/AUTHORS.md +3 -1
- package/dist/{ModeResolver-DyXeZ9ib.d.ts → ModeResolver-B64aUZXJ.d.ts} +1 -1
- package/dist/{ModeResolver-BDAgouuE.d.mts → ModeResolver-CA2fUU9h.d.mts} +1 -1
- package/dist/{Task-BL4Idm9r.d.mts → Task-CxGgN6I0.d.mts} +801 -39
- package/dist/{Task-BL4Idm9r.d.ts → Task-CxGgN6I0.d.ts} +801 -39
- package/dist/{chunk-YAFNYNFX.mjs → chunk-2IFKPYPO.mjs} +453 -17
- package/dist/chunk-2IFKPYPO.mjs.map +1 -0
- package/dist/{chunk-MYXMIVWA.mjs → chunk-FX33UKAD.mjs} +8 -6
- package/dist/chunk-FX33UKAD.mjs.map +1 -0
- package/dist/{chunk-QTZ5XTBY.mjs → chunk-PKJTN2PD.mjs} +458 -13
- package/dist/chunk-PKJTN2PD.mjs.map +1 -0
- package/dist/{chunk-7WNLN63J.mjs → chunk-RZ23BMVR.mjs} +599 -124
- package/dist/chunk-RZ23BMVR.mjs.map +1 -0
- package/dist/chunk-UDUATSCJ.mjs +48 -0
- package/dist/chunk-UDUATSCJ.mjs.map +1 -0
- package/dist/{IRunner-DOMtDTVt.d.ts → eventStore-CTCSKS9E.d.ts} +976 -145
- package/dist/{IRunner-ihalYfTo.d.mts → eventStore-CcB8yELZ.d.mts} +976 -145
- package/dist/index.d.mts +905 -164
- package/dist/index.d.ts +905 -164
- package/dist/index.js +12496 -3308
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +10830 -2919
- 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 +277 -21
- package/dist/parsing.js.map +1 -1
- package/dist/parsing.mjs +3 -3
- package/dist/plan-utils.d.mts +8 -5
- package/dist/plan-utils.d.ts +8 -5
- package/dist/plan-utils.js +262 -33
- package/dist/plan-utils.js.map +1 -1
- package/dist/plan-utils.mjs +39 -3
- package/dist/{runSettingsText-DVOd7vKC.d.ts → runSettingsText-DFVpe6aU.d.mts} +1996 -895
- package/dist/{runSettingsText-BuLVBlXS.d.mts → runSettingsText-lKLDsyli.d.ts} +1996 -895
- package/dist/testing.d.mts +99 -4
- package/dist/testing.d.ts +99 -4
- package/dist/testing.js +213 -8
- package/dist/testing.js.map +1 -1
- package/dist/testing.mjs +193 -8
- package/dist/testing.mjs.map +1 -1
- package/docker/task.Dockerfile +22 -0
- package/package.json +3 -1
- package/skills/diagnose/SKILL.md +2 -2
- package/skills/explore/SKILL.md +1 -1
- package/dist/chunk-7WNLN63J.mjs.map +0 -1
- package/dist/chunk-MYXMIVWA.mjs.map +0 -1
- package/dist/chunk-QTZ5XTBY.mjs.map +0 -1
- package/dist/chunk-YAFNYNFX.mjs.map +0 -1
package/dist/plan-utils.js
CHANGED
|
@@ -32,6 +32,7 @@ var plan_utils_exports = {};
|
|
|
32
32
|
__export(plan_utils_exports, {
|
|
33
33
|
CHECKPOINT_TRUNCATE_LENGTH: () => CHECKPOINT_TRUNCATE_LENGTH,
|
|
34
34
|
DEFAULT_RUNNERS: () => DEFAULT_RUNNERS,
|
|
35
|
+
DELEGATION_OFFERED: () => DELEGATION_OFFERED,
|
|
35
36
|
EMPTY_CONVERSATION: () => EMPTY_CONVERSATION,
|
|
36
37
|
EMPTY_HOLD: () => EMPTY_HOLD,
|
|
37
38
|
EMPTY_RUN: () => EMPTY_RUN,
|
|
@@ -43,6 +44,8 @@ __export(plan_utils_exports, {
|
|
|
43
44
|
PLANNED_WITH_LABEL: () => PLANNED_WITH_LABEL,
|
|
44
45
|
REPORT_PREVIEW_LINES: () => REPORT_PREVIEW_LINES,
|
|
45
46
|
SEVERITY_LABEL: () => SEVERITY_LABEL,
|
|
47
|
+
STALLED_LABEL: () => STALLED_LABEL,
|
|
48
|
+
STOPPING_LABEL: () => STOPPING_LABEL,
|
|
46
49
|
SUPERVISOR_LEVEL_LABEL: () => SUPERVISOR_LEVEL_LABEL,
|
|
47
50
|
WAITS_FOR_APPROVAL_LABEL: () => WAITS_FOR_APPROVAL_LABEL,
|
|
48
51
|
accountLimitPercentText: () => accountLimitPercentText,
|
|
@@ -50,6 +53,7 @@ __export(plan_utils_exports, {
|
|
|
50
53
|
accountLimitsOf: () => accountLimitsOf,
|
|
51
54
|
accountLimitsText: () => accountLimitsText,
|
|
52
55
|
accountLimitsTitle: () => accountLimitsTitle,
|
|
56
|
+
activityLabel: () => activityLabel,
|
|
53
57
|
addAttemptUsage: () => addAttemptUsage,
|
|
54
58
|
addModelUsage: () => addModelUsage,
|
|
55
59
|
addPlannerUsage: () => addPlannerUsage,
|
|
@@ -77,12 +81,14 @@ __export(plan_utils_exports, {
|
|
|
77
81
|
cardEditable: () => cardEditable,
|
|
78
82
|
checkOf: () => checkOf,
|
|
79
83
|
clampThinkingEffort: () => clampThinkingEffort,
|
|
84
|
+
closeTurn: () => closeTurn,
|
|
80
85
|
compactionText: () => compactionText,
|
|
81
86
|
confirmedOverride: () => confirmedOverride,
|
|
82
87
|
contextMeterText: () => contextMeterText,
|
|
83
88
|
contextMeterTitle: () => contextMeterTitle,
|
|
84
89
|
costText: () => costText,
|
|
85
90
|
countedSessionCost: () => countedSessionCost,
|
|
91
|
+
delegatedRowView: () => delegatedRowView,
|
|
86
92
|
dependencyCandidates: () => dependencyCandidates,
|
|
87
93
|
dependentsNotice: () => dependentsNotice,
|
|
88
94
|
dependentsOf: () => dependentsOf,
|
|
@@ -93,10 +99,12 @@ __export(plan_utils_exports, {
|
|
|
93
99
|
diffSummary: () => diffSummary,
|
|
94
100
|
drainNext: () => drainNext,
|
|
95
101
|
editableWhileRunning: () => editableWhileRunning,
|
|
102
|
+
elapsedSince: () => elapsedSince,
|
|
96
103
|
endAttemptUsage: () => endAttemptUsage,
|
|
97
104
|
followTaskLog: () => followTaskLog,
|
|
98
105
|
followTurn: () => followTurn,
|
|
99
106
|
formatCost: () => formatCost,
|
|
107
|
+
formatElapsed: () => formatElapsed,
|
|
100
108
|
formatTokenCount: () => formatTokenCount,
|
|
101
109
|
fromTranscript: () => fromTranscript,
|
|
102
110
|
handoffBaseLine: () => handoffBaseLine,
|
|
@@ -107,6 +115,7 @@ __export(plan_utils_exports, {
|
|
|
107
115
|
hasAccountLimits: () => hasAccountLimits,
|
|
108
116
|
hasHiddenDetail: () => hasHiddenDetail,
|
|
109
117
|
hasLongReport: () => hasLongReport,
|
|
118
|
+
heldWords: () => heldWords,
|
|
110
119
|
holdLabel: () => holdLabel,
|
|
111
120
|
holdPrompt: () => holdPrompt,
|
|
112
121
|
isFileEditTool: () => isFileEditTool,
|
|
@@ -130,10 +139,12 @@ __export(plan_utils_exports, {
|
|
|
130
139
|
markdownHtml: () => markdownHtml,
|
|
131
140
|
markdownTokens: () => markdownTokens,
|
|
132
141
|
mergeOutcome: () => mergeOutcome,
|
|
142
|
+
mergePastChecksConfirmation: () => mergePastChecksConfirmation,
|
|
133
143
|
modelCostTitle: () => modelCostTitle,
|
|
134
144
|
namedRepos: () => namedRepos,
|
|
135
145
|
newTaskFields: () => newTaskFields,
|
|
136
146
|
noExecutorRefusal: () => noExecutorRefusal,
|
|
147
|
+
onOneLine: () => onOneLine,
|
|
137
148
|
opsEditable: () => opsEditable,
|
|
138
149
|
outOfRounds: () => outOfRounds,
|
|
139
150
|
outputLines: () => outputLines,
|
|
@@ -152,6 +163,7 @@ __export(plan_utils_exports, {
|
|
|
152
163
|
reconcileApprovals: () => reconcileApprovals,
|
|
153
164
|
reduceConversation: () => reduceConversation,
|
|
154
165
|
reduceTaskLog: () => reduceTaskLog,
|
|
166
|
+
repairWaitLabel: () => repairWaitLabel,
|
|
155
167
|
repairedLanded: () => repairedLanded,
|
|
156
168
|
repairedNotice: () => repairedNotice,
|
|
157
169
|
repeatingChecks: () => repeatingChecks,
|
|
@@ -163,6 +175,9 @@ __export(plan_utils_exports, {
|
|
|
163
175
|
resumeLabel: () => resumeLabel,
|
|
164
176
|
resumeTime: () => resumeTime,
|
|
165
177
|
resumedSessionWindow: () => resumedSessionWindow,
|
|
178
|
+
revertEffect: () => revertEffect,
|
|
179
|
+
revertListLine: () => revertListLine,
|
|
180
|
+
revertTaskRef: () => revertTaskRef,
|
|
166
181
|
runHoldsEditors: () => runHoldsEditors,
|
|
167
182
|
runnerToolSubject: () => runnerToolSubject,
|
|
168
183
|
savedPatchView: () => savedPatchView,
|
|
@@ -171,13 +186,16 @@ __export(plan_utils_exports, {
|
|
|
171
186
|
severityLabel: () => severityLabel,
|
|
172
187
|
skillTokens: () => skillTokens,
|
|
173
188
|
skippedLabel: () => skippedLabel,
|
|
189
|
+
spentTokens: () => spentTokens,
|
|
174
190
|
startAttemptUsage: () => startAttemptUsage,
|
|
175
191
|
stopTurn: () => stopTurn,
|
|
176
192
|
subagentCostTitle: () => subagentCostTitle,
|
|
177
193
|
subtreeIds: () => subtreeIds,
|
|
194
|
+
subtreeView: () => subtreeView,
|
|
178
195
|
summarizeToolCall: () => summarizeToolCall,
|
|
179
196
|
takeAt: () => takeAt,
|
|
180
197
|
taskActionCommand: () => taskActionCommand,
|
|
198
|
+
taskActivity: () => taskActivity,
|
|
181
199
|
taskChatAvailable: () => taskChatAvailable,
|
|
182
200
|
taskLogCommands: () => taskLogCommands,
|
|
183
201
|
taskLogHeaderView: () => taskLogHeaderView,
|
|
@@ -390,9 +408,11 @@ function taskStatusKind(task) {
|
|
|
390
408
|
if (!isTaskRunning(task)) return "todo";
|
|
391
409
|
return task.status === "in_progress" && task.idleSince ? "quiet" : "running";
|
|
392
410
|
}
|
|
411
|
+
var STALLED_LABEL = "Stalled";
|
|
393
412
|
var AWAITING_LABELS = {
|
|
394
413
|
input: "Waiting for your input",
|
|
395
414
|
checkpoint: "Checkpoint",
|
|
415
|
+
"question-lost": "Question lost in a restart",
|
|
396
416
|
conflict: "Merge conflict",
|
|
397
417
|
"files-changed": "Changed tracked files",
|
|
398
418
|
"usage-limit": "Paused on a usage limit"
|
|
@@ -400,6 +420,14 @@ var AWAITING_LABELS = {
|
|
|
400
420
|
function awaitingLabel(task) {
|
|
401
421
|
return task.status === "awaiting_user" && task.awaitingReason ? AWAITING_LABELS[task.awaitingReason] : null;
|
|
402
422
|
}
|
|
423
|
+
var REPAIR_WAIT_LABELS = {
|
|
424
|
+
slot: "Repair waits for a free slot",
|
|
425
|
+
planner: "Repair waits for the planner's turn to end",
|
|
426
|
+
"usage-limit": "Repair waits for its runner's usage limit to reset"
|
|
427
|
+
};
|
|
428
|
+
function repairWaitLabel(wait) {
|
|
429
|
+
return REPAIR_WAIT_LABELS[wait];
|
|
430
|
+
}
|
|
403
431
|
function blockedByLabel(refs) {
|
|
404
432
|
return `Blocked by ${refs.join(", ")}`;
|
|
405
433
|
}
|
|
@@ -569,10 +597,25 @@ function loopRemovalRefusal(task) {
|
|
|
569
597
|
return task.loop ? `"${task.title}" is a loop's check: remove its body tasks first, or drop its loop ("loop": null), so they do not run on their own` : null;
|
|
570
598
|
}
|
|
571
599
|
function loopReshapeRefusal(tasks, target, action) {
|
|
600
|
+
if (target.type === "delegated") return `"${target.title}" is a delegated task and cannot be ${action}: remove it and add what should replace it`;
|
|
572
601
|
if (target.loop) return `"${target.title}" is a loop's check and cannot be ${action}: drop its loop first ("loop": null)`;
|
|
573
602
|
return checkOf(tasks, target.id) ? `"${target.title}" is in a loop's body and cannot be ${action}: take it out of the loop first` : null;
|
|
574
603
|
}
|
|
575
604
|
|
|
605
|
+
// src/models/lineBreaks.ts
|
|
606
|
+
var BREAKS = "\\n\\v\\f\\r\\u0085\\u2028\\u2029";
|
|
607
|
+
var LINE_BREAK = new RegExp(`\\r\\n|[${BREAKS}]`);
|
|
608
|
+
var ONE_LINE = new RegExp(`^[^${BREAKS}]*$`);
|
|
609
|
+
function splitLines(text2) {
|
|
610
|
+
return text2.split(LINE_BREAK);
|
|
611
|
+
}
|
|
612
|
+
function quotedLine(text2) {
|
|
613
|
+
return JSON.stringify(text2).replace(/[\u0085\u2028\u2029]/g, (char) => `\\u${char.charCodeAt(0).toString(16).padStart(4, "0")}`);
|
|
614
|
+
}
|
|
615
|
+
function onOneLine(text2) {
|
|
616
|
+
return ONE_LINE.test(text2) ? text2 : quotedLine(text2);
|
|
617
|
+
}
|
|
618
|
+
|
|
576
619
|
// src/services/PlannedTask.ts
|
|
577
620
|
function findCycle(tasks) {
|
|
578
621
|
return findDependencyCycle(tasks);
|
|
@@ -1023,7 +1066,8 @@ function truncateCheckpointSummary(summary) {
|
|
|
1023
1066
|
|
|
1024
1067
|
// src/services/conflictFiles.ts
|
|
1025
1068
|
function capConflictFiles(files, max = 5) {
|
|
1026
|
-
|
|
1069
|
+
const named = files.map(onOneLine);
|
|
1070
|
+
return named.length <= max ? named.join(", ") : `${named.slice(0, max).join(", ")}, +${named.length - max} more`;
|
|
1027
1071
|
}
|
|
1028
1072
|
|
|
1029
1073
|
// src/services/mergeResultNotice.ts
|
|
@@ -1171,10 +1215,33 @@ function handoffBaseLine(handoff, length) {
|
|
|
1171
1215
|
function repoResultLines(handoff) {
|
|
1172
1216
|
return handoff.repos.map(({ path, landed }) => `${path}: ${landed.length === 0 ? "nothing to merge" : `${landed.length} task${landed.length === 1 ? "" : "s"} landed`}`);
|
|
1173
1217
|
}
|
|
1218
|
+
function mergePastChecksConfirmation(checks) {
|
|
1219
|
+
return `This merges work no check has passed: ${checks.join(", ")} ${checks.length === 1 ? "has" : "have"} not.`;
|
|
1220
|
+
}
|
|
1174
1221
|
|
|
1175
1222
|
// src/services/runSettingsText.ts
|
|
1176
1223
|
var SUPERVISOR_LEVEL_LABEL = { off: "Off", watch: "Watch", act: "Act" };
|
|
1177
1224
|
var PLANNED_WITH_LABEL = "Planned-with line in commits Ordewell writes";
|
|
1225
|
+
var DELEGATION_ENV = "ORDEWELL_DELEGATION";
|
|
1226
|
+
function delegationSwitchedOn({ env, moduleDir, exists }) {
|
|
1227
|
+
if (env !== "1" || moduleDir === null) return false;
|
|
1228
|
+
const parts = moduleDir.split(/[\\/]/);
|
|
1229
|
+
if (parts.includes("node_modules")) return false;
|
|
1230
|
+
const packages = parts.lastIndexOf("packages");
|
|
1231
|
+
if (packages < 1) return false;
|
|
1232
|
+
const root = parts.slice(0, packages).join("/");
|
|
1233
|
+
return exists(`${root}/.git`) && exists(`${root}/packages/core/package.json`);
|
|
1234
|
+
}
|
|
1235
|
+
function placeHere(variable) {
|
|
1236
|
+
const fs = typeof process === "undefined" ? void 0 : process.getBuiltinModule?.("fs");
|
|
1237
|
+
if (!fs) return { env: void 0, moduleDir: null, exists: () => false };
|
|
1238
|
+
const file = typeof __filename !== "undefined" ? __filename : new URL(
|
|
1239
|
+
// @ts-expect-error - import.meta is only valid under an ESM module setting; see builtinSkills.ts
|
|
1240
|
+
__filename
|
|
1241
|
+
).pathname;
|
|
1242
|
+
return { env: process.env[variable], moduleDir: file.replace(/[\\/][^\\/]*$/, ""), exists: (path) => fs.existsSync(path) };
|
|
1243
|
+
}
|
|
1244
|
+
var DELEGATION_OFFERED = delegationSwitchedOn(placeHere(DELEGATION_ENV));
|
|
1178
1245
|
function parseCount(arg, min) {
|
|
1179
1246
|
if (arg === void 0 || !/^\d+$/.test(arg)) return null;
|
|
1180
1247
|
const n = Number(arg);
|
|
@@ -1183,18 +1250,21 @@ function parseCount(arg, min) {
|
|
|
1183
1250
|
|
|
1184
1251
|
// src/models/Usage.ts
|
|
1185
1252
|
function partedPromptUsage(parts) {
|
|
1186
|
-
const
|
|
1253
|
+
const reported2 = [parts.uncached, parts.cacheRead, parts.cacheWrite].filter((n) => n !== void 0);
|
|
1187
1254
|
return {
|
|
1188
|
-
...
|
|
1255
|
+
...reported2.length > 0 ? { inputTokens: reported2.reduce((a, b) => a + b, 0) } : {},
|
|
1189
1256
|
...parts.cacheRead !== void 0 ? { cachedInputTokens: parts.cacheRead } : {}
|
|
1190
1257
|
};
|
|
1191
1258
|
}
|
|
1192
1259
|
var TOKEN_FIELDS = ["inputTokens", "outputTokens", "cachedInputTokens"];
|
|
1260
|
+
function spentTokens({ inputTokens, outputTokens }) {
|
|
1261
|
+
return (inputTokens ?? 0) + (outputTokens ?? 0);
|
|
1262
|
+
}
|
|
1193
1263
|
function addUsage(totals, record) {
|
|
1194
1264
|
const next = { ...totals };
|
|
1195
1265
|
for (const field of TOKEN_FIELDS) {
|
|
1196
|
-
const
|
|
1197
|
-
if (
|
|
1266
|
+
const reported2 = record[field];
|
|
1267
|
+
if (reported2 !== void 0) next[field] = (totals[field] ?? 0) + reported2;
|
|
1198
1268
|
}
|
|
1199
1269
|
if (record.reportedCost) {
|
|
1200
1270
|
const { amount, currency } = record.reportedCost;
|
|
@@ -1338,7 +1408,7 @@ function planUsage(tasks) {
|
|
|
1338
1408
|
function taskUsageSummary(task) {
|
|
1339
1409
|
const attempts = task.attemptUsage ?? [];
|
|
1340
1410
|
const latest = attempts.at(-1);
|
|
1341
|
-
const contextFill = latest ? plannerContextFill(latest) : void 0;
|
|
1411
|
+
const contextFill = latest && task.type !== "delegated" ? plannerContextFill(latest) : void 0;
|
|
1342
1412
|
return {
|
|
1343
1413
|
totals: attempts.reduce((sum, attempt) => addUsageTotals(sum, attempt.totals), {}),
|
|
1344
1414
|
attempts: attempts.length,
|
|
@@ -2176,17 +2246,17 @@ function answered(block, decision, note) {
|
|
|
2176
2246
|
function decideApproval2(view, { approvalId, decision, note }) {
|
|
2177
2247
|
return settleApproval2(view, approvalId, (block) => answered(block, decision, note));
|
|
2178
2248
|
}
|
|
2179
|
-
function startTurn(view, { message, messageId, from, forced }) {
|
|
2249
|
+
function startTurn(view, { message, messageId, from, forced, startedAt }) {
|
|
2180
2250
|
const queued = messageId ? view.queued.filter((m) => m.id !== messageId) : view.queued;
|
|
2181
|
-
const working = { ...view, queued, working: true, latestText: void 0 };
|
|
2251
|
+
const working = { ...view, queued, working: true, turnStartedAt: startedAt, latestText: void 0 };
|
|
2182
2252
|
return message ? append(working, (id) => ({ ...sentMessage(id, message, from), ...forced ? { forced: true } : {} })) : working;
|
|
2183
2253
|
}
|
|
2184
2254
|
function sentMessage(id, text2, from) {
|
|
2185
2255
|
return from === "ordewell" ? settledMessage(id, "system", `Ordewell: ${text2}`) : settledMessage(id, "user", text2);
|
|
2186
2256
|
}
|
|
2187
|
-
function startCommand(view, { name, args, messageId }) {
|
|
2257
|
+
function startCommand(view, { name, args, messageId, startedAt }) {
|
|
2188
2258
|
const queued = messageId ? view.queued.filter((m) => m.id !== messageId) : view.queued;
|
|
2189
|
-
return append({ ...view, queued, working: true, latestText: void 0 }, (id) => ({
|
|
2259
|
+
return append({ ...view, queued, working: true, turnStartedAt: startedAt, latestText: void 0 }, (id) => ({
|
|
2190
2260
|
type: "command",
|
|
2191
2261
|
id,
|
|
2192
2262
|
name,
|
|
@@ -2221,7 +2291,7 @@ function endTurn2(view, { reason }) {
|
|
|
2221
2291
|
const i = runningCommand(view);
|
|
2222
2292
|
const command = view.blocks[i];
|
|
2223
2293
|
const settled = command?.type === "command" ? { ...view, blocks: replaceAt(view.blocks, i, { ...command, status: COMMAND_END[reason] }) } : view;
|
|
2224
|
-
const closed = closeOpenBlocks({ ...settled, working: false, lastTurnEnd: reason, streams: {}, latestText: void 0 }, CUT[reason]);
|
|
2294
|
+
const closed = closeOpenBlocks({ ...settled, working: false, turnStartedAt: void 0, lastTurnEnd: reason, streams: {}, latestText: void 0 }, CUT[reason]);
|
|
2225
2295
|
return reason === "interrupted" ? append(closed, (id) => settledMessage(id, "system", "Interrupted.")) : closed;
|
|
2226
2296
|
}
|
|
2227
2297
|
function queueMessage(view, { messageId, text: text2, forced, from }) {
|
|
@@ -2271,7 +2341,7 @@ function endScriptStep(view, event) {
|
|
|
2271
2341
|
const passed = event.code === 0 && !event.signal && event.error === void 0;
|
|
2272
2342
|
const i = runningScriptStep(view);
|
|
2273
2343
|
const block = view.blocks[i];
|
|
2274
|
-
const ended = { ...view, working: false };
|
|
2344
|
+
const ended = { ...view, working: false, turnStartedAt: void 0 };
|
|
2275
2345
|
if (block?.type !== "tool") return append(ended, (id) => settledMessage(id, "system", status));
|
|
2276
2346
|
const output = block.output.trim() ? `${block.output.replace(/\n+$/, "")}
|
|
2277
2347
|
${status}` : status;
|
|
@@ -2368,7 +2438,7 @@ function reduceTaskLog(view, event) {
|
|
|
2368
2438
|
case "handoff":
|
|
2369
2439
|
return showHandoff(view, event);
|
|
2370
2440
|
case "runner_ended":
|
|
2371
|
-
return closeOpenBlocks({ ...endOpenCalls(view), working: false, streams: {}, latestText: void 0 }, "stopped");
|
|
2441
|
+
return closeOpenBlocks({ ...endOpenCalls(view), working: false, turnStartedAt: void 0, streams: {}, latestText: void 0 }, "stopped");
|
|
2372
2442
|
default:
|
|
2373
2443
|
return view;
|
|
2374
2444
|
}
|
|
@@ -2377,6 +2447,61 @@ function replayTaskLog(events, from = EMPTY_TASK_LOG) {
|
|
|
2377
2447
|
return events.reduce(reduceTaskLog, from);
|
|
2378
2448
|
}
|
|
2379
2449
|
|
|
2450
|
+
// src/conversation/activity.ts
|
|
2451
|
+
function activityLabel(view) {
|
|
2452
|
+
for (let i = view.blocks.length - 1; i >= 0; i--) {
|
|
2453
|
+
const label = openLabel(view.blocks[i], view);
|
|
2454
|
+
if (label) return label;
|
|
2455
|
+
}
|
|
2456
|
+
return "Working\u2026";
|
|
2457
|
+
}
|
|
2458
|
+
function isAtWork(view) {
|
|
2459
|
+
if (view.working !== false) return true;
|
|
2460
|
+
if (view.blocks.some((b) => b.type === "subagent" && b.status === "running")) return true;
|
|
2461
|
+
return view.lastTurnEnd === void 0 && view.blocks.some((b) => openLabel(b, view) !== null);
|
|
2462
|
+
}
|
|
2463
|
+
function openLabel(block, view) {
|
|
2464
|
+
switch (block.type) {
|
|
2465
|
+
case "thinking":
|
|
2466
|
+
return block.streaming ? "Thinking\u2026" : null;
|
|
2467
|
+
case "message":
|
|
2468
|
+
return block.streaming ? "Writing\u2026" : null;
|
|
2469
|
+
case "tool": {
|
|
2470
|
+
if (block.status !== "pending") return null;
|
|
2471
|
+
const { name, keyArg } = block.headline;
|
|
2472
|
+
return keyArg ? `Running ${name}(${keyArg})\u2026` : `Running ${name}\u2026`;
|
|
2473
|
+
}
|
|
2474
|
+
case "subagent": {
|
|
2475
|
+
if (block.status !== "running") return null;
|
|
2476
|
+
const running = view.blocks.filter((b) => b.type === "subagent" && b.status === "running");
|
|
2477
|
+
return running.length > 1 ? `${running.length} subagents running\u2026` : `Subagent: ${block.brief}\u2026`;
|
|
2478
|
+
}
|
|
2479
|
+
default:
|
|
2480
|
+
return null;
|
|
2481
|
+
}
|
|
2482
|
+
}
|
|
2483
|
+
function taskActivity(view, task) {
|
|
2484
|
+
if (!isTaskRunning(task) || view.archived) return null;
|
|
2485
|
+
if (task.awaitingApproval || view.blocks.some((b) => b.type === "approval" && b.status === "pending")) return null;
|
|
2486
|
+
const since = view.turnStartedAt ? { since: view.turnStartedAt } : {};
|
|
2487
|
+
if (taskStatusKind(task) === "quiet") return { label: STALLED_LABEL, busy: false, ...since };
|
|
2488
|
+
if (!isAtWork(view)) return null;
|
|
2489
|
+
return { label: activityLabel(view), busy: true, ...since };
|
|
2490
|
+
}
|
|
2491
|
+
|
|
2492
|
+
// src/conversation/elapsed.ts
|
|
2493
|
+
function formatElapsed(ms) {
|
|
2494
|
+
if (!Number.isFinite(ms) || ms < 0) return "";
|
|
2495
|
+
const seconds = Math.floor(ms / 1e3);
|
|
2496
|
+
if (seconds < 60) return `${seconds}s`;
|
|
2497
|
+
const minutes = Math.floor(seconds / 60);
|
|
2498
|
+
if (minutes < 60) return `${minutes}m ${String(seconds % 60).padStart(2, "0")}s`;
|
|
2499
|
+
return `${Math.floor(minutes / 60)}h ${String(minutes % 60).padStart(2, "0")}m`;
|
|
2500
|
+
}
|
|
2501
|
+
function elapsedSince(startedAt, now) {
|
|
2502
|
+
return startedAt === void 0 ? "" : formatElapsed(now - Date.parse(startedAt));
|
|
2503
|
+
}
|
|
2504
|
+
|
|
2380
2505
|
// src/models/Handoff.ts
|
|
2381
2506
|
var SEVERITY_LABEL = {
|
|
2382
2507
|
blocker: "Blocker",
|
|
@@ -2395,16 +2520,23 @@ function worstSeverity(findings) {
|
|
|
2395
2520
|
}
|
|
2396
2521
|
return worst;
|
|
2397
2522
|
}
|
|
2523
|
+
var ROOT_NODE = "root";
|
|
2524
|
+
function nodeText(node) {
|
|
2525
|
+
return node.startsWith(`${ROOT_NODE}/`) ? node.slice(ROOT_NODE.length + 1) : node;
|
|
2526
|
+
}
|
|
2527
|
+
function findingRefText(task, ref) {
|
|
2528
|
+
return `${task}${ref.attempt !== void 0 ? `@${ref.attempt}` : ""}${ref.finding ? `/${ref.finding}` : ""}`;
|
|
2529
|
+
}
|
|
2398
2530
|
function handoffReferenceText(ref, taskName = () => void 0) {
|
|
2399
2531
|
switch (ref.kind) {
|
|
2400
2532
|
case "file":
|
|
2401
|
-
return `${ref.line !== void 0 ? `${ref.path}:${ref.line}` : ref.path}${ref.resolved === true ? "" : " (unresolved)"}`;
|
|
2533
|
+
return `${onOneLine(ref.line !== void 0 ? `${ref.path}:${ref.line}` : ref.path)}${ref.resolved === true ? "" : " (unresolved)"}`;
|
|
2402
2534
|
case "commit":
|
|
2403
|
-
return `commit ${ref.sha}${ref.repo ? ` in ${ref.repo}` : ""}${ref.resolved === true ? "" : " (unresolved)"}`;
|
|
2535
|
+
return `commit ${ref.sha}${ref.repo ? ` in ${onOneLine(ref.repo)}` : ""}${ref.resolved === true ? "" : " (unresolved)"}`;
|
|
2404
2536
|
case "task":
|
|
2405
|
-
return
|
|
2537
|
+
return onOneLine(findingRefText(ref.label !== void 0 ? `${nodeText(ref.node ?? ROOT_NODE)}:${ref.label}` : taskName(ref.task) ?? ref.task, ref));
|
|
2406
2538
|
case "url":
|
|
2407
|
-
return ref.url;
|
|
2539
|
+
return onOneLine(ref.url);
|
|
2408
2540
|
case "patch":
|
|
2409
2541
|
return patchText(ref);
|
|
2410
2542
|
}
|
|
@@ -2424,7 +2556,7 @@ function byteSize(bytes) {
|
|
|
2424
2556
|
}
|
|
2425
2557
|
function patchFlagText(flag) {
|
|
2426
2558
|
const more = flag.count - flag.paths.length;
|
|
2427
|
-
return `${FLAG_WORDS[flag.kind]}: ${counted(flag.count, "file")}${flag.paths.length ? ` (${flag.paths.join(", ")}${more > 0 ? `, +${more} more` : ""})` : ""}`;
|
|
2559
|
+
return `${FLAG_WORDS[flag.kind]}: ${counted(flag.count, "file")}${flag.paths.length ? ` (${flag.paths.map(onOneLine).join(", ")}${more > 0 ? `, +${more} more` : ""})` : ""}`;
|
|
2428
2560
|
}
|
|
2429
2561
|
function patchChangesText(patch) {
|
|
2430
2562
|
const binary = patch.binary > 0 ? `, ${patch.binary} binary` : "";
|
|
@@ -2455,6 +2587,9 @@ function savedPatchViews(handoff) {
|
|
|
2455
2587
|
function savedPatchView(handoff) {
|
|
2456
2588
|
return savedPatchViews(handoff)[0] ?? null;
|
|
2457
2589
|
}
|
|
2590
|
+
function heldWords(text2) {
|
|
2591
|
+
return splitLines(text2).map((line) => line ? ` ${line}` : line);
|
|
2592
|
+
}
|
|
2458
2593
|
|
|
2459
2594
|
// src/conversation/labels.ts
|
|
2460
2595
|
var APPROVAL_KIND_TEXT = {
|
|
@@ -2579,18 +2714,18 @@ function cutOff(gate, input) {
|
|
|
2579
2714
|
return turnId === void 0 || turnId === gate.stopped;
|
|
2580
2715
|
}
|
|
2581
2716
|
function withGate(live2, gate) {
|
|
2582
|
-
return gate.open === live2.gate.open && gate.stopped === live2.gate.stopped ? live2 : { ...live2, gate };
|
|
2717
|
+
return gate.open === live2.gate.open && gate.stopped === live2.gate.stopped && gate.openedAt === live2.gate.openedAt ? live2 : { ...live2, gate };
|
|
2583
2718
|
}
|
|
2584
2719
|
function followTurn(view, gate, input) {
|
|
2585
2720
|
const live2 = { view, gate };
|
|
2586
2721
|
if (input.type === "planner_turn_started") {
|
|
2587
|
-
return withGate({ view: reduceConversation(view, input), gate }, { open: input.turnId, stopped: null });
|
|
2722
|
+
return withGate({ view: reduceConversation(view, input), gate }, { open: input.turnId, stopped: null, ...input.startedAt ? { openedAt: input.startedAt } : {} });
|
|
2588
2723
|
}
|
|
2589
2724
|
if (cutOff(gate, input)) {
|
|
2590
2725
|
return input.type === "planner_turn_ended" ? withGate(live2, { ...gate, stopped: null }) : live2;
|
|
2591
2726
|
}
|
|
2592
2727
|
const next = { view: reduceConversation(view, input), gate };
|
|
2593
|
-
return input.type === "planner_turn_ended" && input.turnId === gate.open ? withGate(next, {
|
|
2728
|
+
return input.type === "planner_turn_ended" && input.turnId === gate.open ? withGate(next, { open: null, stopped: gate.stopped }) : next;
|
|
2594
2729
|
}
|
|
2595
2730
|
function stopTurn(view, gate) {
|
|
2596
2731
|
if (gate.open === null) return { view, gate };
|
|
@@ -2599,9 +2734,16 @@ function stopTurn(view, gate) {
|
|
|
2599
2734
|
gate: { open: null, stopped: gate.open }
|
|
2600
2735
|
};
|
|
2601
2736
|
}
|
|
2737
|
+
function closeTurn(gate) {
|
|
2738
|
+
return gate.open === null ? gate : { open: null, stopped: gate.stopped };
|
|
2739
|
+
}
|
|
2602
2740
|
|
|
2603
2741
|
// src/services/WakePolicy.ts
|
|
2604
2742
|
var REPORT_LEAD = ", whose result you asked for, has ended.";
|
|
2743
|
+
var RIDE_ALONG_CHARS = 120;
|
|
2744
|
+
var LEFT_OUT_EVENTS = 8;
|
|
2745
|
+
var LEFT_OUT_ROOM = 100 + LEFT_OUT_EVENTS * (RIDE_ALONG_CHARS + 1);
|
|
2746
|
+
var UNKNOWN_CACHE_TTL_MS = 5 * 6e4;
|
|
2605
2747
|
|
|
2606
2748
|
// src/conversation/wakeUp.ts
|
|
2607
2749
|
var DIGEST_HEAD = "Run update:";
|
|
@@ -2755,8 +2897,9 @@ var PAUSED = (t) => t.status === "awaiting_user" && t.awaitingReason === "usage-
|
|
|
2755
2897
|
var RESUMES = (t) => PAUSED(t) && !!t.resumeAt;
|
|
2756
2898
|
var RESUMABLE = (t) => PAUSED(t) && t.continuable === true;
|
|
2757
2899
|
var HOLDS_UP = (t) => t.status === "failed" || t.status === "blocked" || t.status === "awaiting_user";
|
|
2900
|
+
var STOPPABLE = (t) => t.status === "in_progress" || !!t.repairWaits;
|
|
2758
2901
|
var TASK_RULES = [
|
|
2759
|
-
["cancel",
|
|
2902
|
+
["cancel", STOPPABLE],
|
|
2760
2903
|
["resume-now", RESUMABLE],
|
|
2761
2904
|
["cancel-resume", RESUMES],
|
|
2762
2905
|
["skip", HOLDS_UP],
|
|
@@ -2767,7 +2910,7 @@ var TASK_RULES = [
|
|
|
2767
2910
|
["uncomplete", (t) => t.status === "completed"]
|
|
2768
2911
|
];
|
|
2769
2912
|
var SUBTASK_RULES = [
|
|
2770
|
-
["cancel",
|
|
2913
|
+
["cancel", STOPPABLE],
|
|
2771
2914
|
["resume-now", RESUMABLE],
|
|
2772
2915
|
["cancel-resume", RESUMES],
|
|
2773
2916
|
["complete", (t) => t.status === "in_progress" && t.type === "ai"],
|
|
@@ -2818,11 +2961,11 @@ function opsEditable(task) {
|
|
|
2818
2961
|
|
|
2819
2962
|
// src/services/AssignmentScope.ts
|
|
2820
2963
|
function assignedRunnerOf(task) {
|
|
2821
|
-
return task.type === "ai" ? task.assignedRunner || void 0 : void 0;
|
|
2964
|
+
return task.type === "ai" || task.type === "delegated" ? task.assignedRunner || void 0 : void 0;
|
|
2822
2965
|
}
|
|
2823
2966
|
var OVER = /* @__PURE__ */ new Set(["completed", "skipped"]);
|
|
2824
2967
|
function assignmentIssue(task, scope) {
|
|
2825
|
-
if (task.type !== "ai" || OVER.has(task.status)) return null;
|
|
2968
|
+
if (task.type !== "ai" && task.type !== "delegated" || OVER.has(task.status)) return null;
|
|
2826
2969
|
if (!scope.enabledRunners.includes(task.assignedRunner)) return { kind: "runner-off", runner: task.assignedRunner };
|
|
2827
2970
|
const model = task.assignedModel;
|
|
2828
2971
|
const allowed = effectiveAllowlist(scope.allowlist[task.assignedRunner], task.assignedRunner, scope.models);
|
|
@@ -2844,6 +2987,54 @@ function assignmentConsequence({ status, awaitingReason, resumeAt }) {
|
|
|
2844
2987
|
return "runs as assigned unless moved";
|
|
2845
2988
|
}
|
|
2846
2989
|
|
|
2990
|
+
// src/taskRow/delegated.ts
|
|
2991
|
+
var STOPPING_LABEL = "Stopping: its child plan is still winding down.";
|
|
2992
|
+
function countsText({ completed, running, waiting, pending, failed, skipped }) {
|
|
2993
|
+
const total = completed + running + waiting + pending + failed + skipped;
|
|
2994
|
+
const said = [[running, "running"], [waiting, "waiting"], [failed, "failed"], [skipped, "skipped"]];
|
|
2995
|
+
return [`${completed} of ${total} done`, ...said.filter(([n]) => n > 0).map(([n, word]) => `${n} ${word}`)].join(", ");
|
|
2996
|
+
}
|
|
2997
|
+
function reported(handoff) {
|
|
2998
|
+
const counts = handoff?.subtree?.counts;
|
|
2999
|
+
return counts && { completed: counts.done, running: 0, waiting: 0, pending: counts.blocked, failed: counts.failed, skipped: counts.skipped };
|
|
3000
|
+
}
|
|
3001
|
+
function delegatedRowView(task) {
|
|
3002
|
+
if (task.type !== "delegated") return null;
|
|
3003
|
+
const { delegation } = task;
|
|
3004
|
+
const counts = delegation?.tasks ?? reported(task.handoff);
|
|
3005
|
+
return {
|
|
3006
|
+
goal: task.goal?.trim() || null,
|
|
3007
|
+
tokens: delegation?.tokens ? `${formatTokenCount(delegation.tokens.left)} of ${formatTokenCount(delegation.tokens.budget)} tokens left` : null,
|
|
3008
|
+
counts: counts ? countsText(counts) : null,
|
|
3009
|
+
stopping: delegation?.stopping ? STOPPING_LABEL : null
|
|
3010
|
+
};
|
|
3011
|
+
}
|
|
3012
|
+
var SEVERITIES = ["blocker", "major", "minor", "info"];
|
|
3013
|
+
function itemView({ ref, finding }) {
|
|
3014
|
+
return {
|
|
3015
|
+
reference: ref ? handoffReferenceText(ref) : null,
|
|
3016
|
+
heading: `${finding.id} \xB7 ${severityLabel(finding.severity)} \xB7 ${onOneLine(finding.title)}`,
|
|
3017
|
+
...finding.detail ? { detail: finding.detail } : {}
|
|
3018
|
+
};
|
|
3019
|
+
}
|
|
3020
|
+
function subtreeView(subtree) {
|
|
3021
|
+
const { counts, findings, outsideScope } = subtree;
|
|
3022
|
+
const ran = [["done", counts.done], ["failed", counts.failed], ["blocked", counts.blocked], ["skipped", counts.skipped]].filter(([, n]) => n > 0).map(([word, n]) => `${n} ${word}`).join(", ");
|
|
3023
|
+
const found = SEVERITIES.filter((severity) => findings[severity] > 0).map((severity) => `${findings[severity]} ${severity}`).join(", ");
|
|
3024
|
+
const summary = [
|
|
3025
|
+
ran || "nothing ran",
|
|
3026
|
+
...counts.commits > 0 ? [`${counts.commits} commit${counts.commits === 1 ? "" : "s"}`] : [],
|
|
3027
|
+
`${formatTokenCount(counts.tokens)} tokens`,
|
|
3028
|
+
found ? `${found} finding${SEVERITIES.reduce((n, s) => n + findings[s], 0) === 1 ? "" : "s"} below` : "no findings below"
|
|
3029
|
+
].join(" \xB7 ");
|
|
3030
|
+
return {
|
|
3031
|
+
summary,
|
|
3032
|
+
outsideScope: outsideScope && outsideScope.count > 0 ? `Changed outside its declared scope: ${outsideScope.paths.map(onOneLine).join(", ")}${outsideScope.count > outsideScope.paths.length ? ` (+${outsideScope.count - outsideScope.paths.length} more)` : ""}` : null,
|
|
3033
|
+
open: subtree.open.map(itemView),
|
|
3034
|
+
promoted: subtree.promoted.map(itemView)
|
|
3035
|
+
};
|
|
3036
|
+
}
|
|
3037
|
+
|
|
2847
3038
|
// src/taskRow/loop.ts
|
|
2848
3039
|
function loopCheckState(check, goesOn) {
|
|
2849
3040
|
switch (check.status) {
|
|
@@ -2914,17 +3105,23 @@ function blockedBy(task, reading) {
|
|
|
2914
3105
|
if (!reading || !NOT_STARTED.has(task.status)) return [];
|
|
2915
3106
|
return reading.blocks.blocked.get(task.id) ?? [];
|
|
2916
3107
|
}
|
|
3108
|
+
function strandedDetail(check, dependencies, reading) {
|
|
3109
|
+
const status = (id) => reading?.tasks.find((t) => t.id === id)?.status;
|
|
3110
|
+
const landed = reading && check.loop.body.every((id) => status(id) === "completed");
|
|
3111
|
+
const finished = dependencies.every((id) => [void 0, "completed", "skipped"].includes(status(id)));
|
|
3112
|
+
return landed && finished ? `Nothing runs it now: start it for round ${loopRoundOf(check) + 1} of ${check.loop.maxRounds}` : "Nothing runs it now: execute the plan and the loop goes on";
|
|
3113
|
+
}
|
|
2917
3114
|
function loopOf(task, reading) {
|
|
2918
3115
|
const tasks = reading?.tasks;
|
|
2919
3116
|
if (task.loop) {
|
|
2920
3117
|
const check2 = { id: task.id, status: task.status, loop: task.loop, loopRound: task.loopRound, ...task.verdict ? { verdict: task.verdict } : {} };
|
|
2921
|
-
const state = loopCheckState(check2, reading ? reading.blocks.repeating.has(task.id) : true);
|
|
3118
|
+
const state = loopCheckState(check2, !task.loopStranded && (reading ? reading.blocks.repeating.has(task.id) : true));
|
|
2922
3119
|
const body = refsOf(task.loop.body, tasks);
|
|
2923
3120
|
const halted = reading ? task.loop.body.filter((id) => {
|
|
2924
3121
|
const status = reading.tasks.find((t) => t.id === id)?.status;
|
|
2925
3122
|
return status === "failed" || status === "skipped" || reading.blocks.blocked.has(id);
|
|
2926
3123
|
}) : [];
|
|
2927
|
-
const detail = state === "repeating" ? `Found problems: runs again once ${body.join(", ")} ${body.length === 1 ? "has" : "have"} landed` : state === "stopped" ? `${refsOf(halted, tasks).join(", ")} did not pass: retry ${halted.length === 1 ? "it" : "them"} and the loop goes on` : null;
|
|
3124
|
+
const detail = state === "repeating" ? `Found problems: runs again once ${body.join(", ")} ${body.length === 1 ? "has" : "have"} landed` : state === "stopped" ? task.loopStranded ? strandedDetail(check2, task.dependencies, reading) : `${refsOf(halted, tasks).join(", ")} did not pass: retry ${halted.length === 1 ? "it" : "them"} and the loop goes on` : null;
|
|
2928
3125
|
return { role: "check", state, label: loopCheckLabel(check2, state), detail, body };
|
|
2929
3126
|
}
|
|
2930
3127
|
const owner = reading && checkOf(reading.tasks, task.id);
|
|
@@ -2958,9 +3155,10 @@ function taskRowView(task, context = {}) {
|
|
|
2958
3155
|
const blocked = blockedBy(task, reading);
|
|
2959
3156
|
const loop = loopOf(task, reading);
|
|
2960
3157
|
return {
|
|
3158
|
+
delegated: delegatedRowView(task),
|
|
2961
3159
|
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,
|
|
2962
3160
|
orderLabel: taskOrderLabel(task, parent),
|
|
2963
|
-
kind: task.type === "user" ? "user" : task.type === "script" ? "script" : task.ops ? "ops" : "ai",
|
|
3161
|
+
kind: task.type === "user" ? "user" : task.type === "script" ? "script" : task.type === "delegated" ? "delegated" : task.ops ? "ops" : "ai",
|
|
2964
3162
|
// Between rounds a check waits for its fix as a task waits for its dependencies, and is no failure (ADR-0045 L3).
|
|
2965
3163
|
status: blocked.length > 0 ? "blocked" : loop?.role === "check" && loop.state === "repeating" ? "todo" : taskStatusKind(task),
|
|
2966
3164
|
running: isTaskRunning(task),
|
|
@@ -2977,7 +3175,8 @@ function taskRowView(task, context = {}) {
|
|
|
2977
3175
|
...flagOf(task, context.runnerScope),
|
|
2978
3176
|
autonomous: task.type === "ai" && context.modes?.find((m) => m.id === task.taskMode)?.autonomous === true,
|
|
2979
3177
|
repos: namedRepos(isolation?.repos),
|
|
2980
|
-
conflict: isolation?.state === "conflict" ? { repo: namedRepo(isolation.conflictRepo), files: filesOf(isolation.conflictFiles) } : null,
|
|
3178
|
+
conflict: isolation?.state === "conflict" && !isolation.repairWaits ? { repo: namedRepo(isolation.conflictRepo), files: filesOf(isolation.conflictFiles), resolver: isolation.resolver ? refsOf([isolation.resolver], context.tasks)[0] : null } : null,
|
|
3179
|
+
repairWaiting: isolation?.state === "conflict" && isolation.repairWaits ? { label: repairWaitLabel(isolation.repairWaits), files: filesOf(isolation.conflictFiles) } : null,
|
|
2981
3180
|
repairing: isolation?.state === "repairing" ? { files: filesOf(isolation.conflictFiles), attempt: isolation.repair ?? null } : null,
|
|
2982
3181
|
repaired: isolation?.repairedFiles?.length ? { files: capConflictFiles(isolation.repairedFiles), landed: isolation.state === "integrated" } : null,
|
|
2983
3182
|
mergeGate: task.mergeGate?.length ? refsOf(task.mergeGate, context.tasks) : null,
|
|
@@ -2989,7 +3188,9 @@ function taskRowView(task, context = {}) {
|
|
|
2989
3188
|
handoff: handoffOf(task),
|
|
2990
3189
|
dependencies: refsOf(task.dependencies, context.tasks),
|
|
2991
3190
|
// A block read off the plan offers what a stored one does: Skip among them.
|
|
2992
|
-
actions: taskRowActions(blocked.length > 0 ? {
|
|
3191
|
+
actions: taskRowActions({ ...task, ...blocked.length > 0 ? { status: "blocked" } : {}, ...isolation?.repairWaits ? { repairWaits: isolation.repairWaits } : {} }, context.placement ?? (parent ? "subtask" : "task")),
|
|
3192
|
+
// Read off the mark itself: a task with merges left and no record has state `none`.
|
|
3193
|
+
revertible: task.isolation?.revertible === true,
|
|
2993
3194
|
mark: markAction(task),
|
|
2994
3195
|
opsEditable: opsEditable(task)
|
|
2995
3196
|
};
|
|
@@ -3005,7 +3206,7 @@ var STATE_LABEL = {
|
|
|
3005
3206
|
done: "Done",
|
|
3006
3207
|
failed: "Failed",
|
|
3007
3208
|
running: "Running",
|
|
3008
|
-
quiet:
|
|
3209
|
+
quiet: STALLED_LABEL,
|
|
3009
3210
|
awaiting: "Waiting for your input",
|
|
3010
3211
|
blocked: "Blocked",
|
|
3011
3212
|
skipped: "Skipped",
|
|
@@ -3022,6 +3223,7 @@ function stateOf(task, follow, approvals) {
|
|
|
3022
3223
|
return { kind: task.awaitingReason === "checkpoint" ? "checkpoint" : "awaiting", label: awaitingLabel(task) ?? STATE_LABEL.awaiting };
|
|
3023
3224
|
}
|
|
3024
3225
|
if (task.status === "blocked") return { kind: "blocked", label: STATE_LABEL.blocked };
|
|
3226
|
+
if (task.repairWaits) return { kind: "todo", label: repairWaitLabel(task.repairWaits) };
|
|
3025
3227
|
if (follow.view.lastTurnEnd === "failed") return { kind: "failed", label: "Turn failed" };
|
|
3026
3228
|
if (follow.view.lastTurnEnd === "interrupted") return { kind: "todo", label: "Interrupted" };
|
|
3027
3229
|
const kind = taskStatusKind(task);
|
|
@@ -3063,7 +3265,8 @@ function taskLogCommands(view) {
|
|
|
3063
3265
|
}
|
|
3064
3266
|
function logContinues(task) {
|
|
3065
3267
|
const finished = task.status === "completed" || task.status === "failed" || task.status === "skipped";
|
|
3066
|
-
|
|
3268
|
+
const childLeft = task.type === "delegated" && (task.status === "pending" || task.awaitingReason === "question-lost");
|
|
3269
|
+
return task.continuable === true && (finished || childLeft || task.status === "awaiting_user" && task.awaitingReason === "usage-limit");
|
|
3067
3270
|
}
|
|
3068
3271
|
function logResumes(task) {
|
|
3069
3272
|
return task.continuable === true && task.status === "awaiting_user" && task.awaitingReason === "usage-limit";
|
|
@@ -3101,6 +3304,14 @@ function pastGateConfirmation(unmerged, subject = "This task") {
|
|
|
3101
3304
|
function manualOverrideConfirmation(direction, label) {
|
|
3102
3305
|
return direction === "complete" ? `Mark ${label} complete? You vouch for its work although no passing verdict said it was done. Any changes it kept may land in your run, and the tasks that depend on it are released to start on a future run.` : `Mark ${label} not done? This clears its completion and holds it until you retry or start it. The work it did stays where it is, and tasks that already ran on its result are not undone.`;
|
|
3103
3306
|
}
|
|
3307
|
+
var revertEffect = "Its landed work comes off the integration branch, newest first, and each task listed is held as not started until you retry it. Nothing in your own branch changes.";
|
|
3308
|
+
function revertTaskRef(task) {
|
|
3309
|
+
return task.ref ?? `#${task.order}`;
|
|
3310
|
+
}
|
|
3311
|
+
function revertListLine(task) {
|
|
3312
|
+
const repos = task.repos.length === 1 && task.repos[0] === "." ? "" : ` (${task.repos.join(", ")})`;
|
|
3313
|
+
return `${revertTaskRef(task)} ${task.title}${repos}${task.dependent ? " (goes with it)" : ""}`;
|
|
3314
|
+
}
|
|
3104
3315
|
function manualOverrideStopFirst(direction, label) {
|
|
3105
3316
|
return `${label.charAt(0).toUpperCase()}${label.slice(1)} cannot be marked ${direction === "complete" ? "complete" : "not done"} while the plan is starting, running or waiting to resume, because the run could still move it on. Stop the run first, and mark it once everything has stopped.`;
|
|
3106
3317
|
}
|
|
@@ -3114,7 +3325,7 @@ function noExecutorRefusal(type, manual, script) {
|
|
|
3114
3325
|
}
|
|
3115
3326
|
|
|
3116
3327
|
// src/services/runView.ts
|
|
3117
|
-
var EMPTY_RUN = { tasks: [], runMerge: null, handoff: null, mergeResult: null, activity: IDLE_ACTIVITY };
|
|
3328
|
+
var EMPTY_RUN = { tasks: [], runMerge: null, handoff: null, mergeResult: null, activity: IDLE_ACTIVITY, escalations: [] };
|
|
3118
3329
|
|
|
3119
3330
|
// src/models/AccountLimits.ts
|
|
3120
3331
|
function hasAccountLimits(snapshot) {
|
|
@@ -3169,6 +3380,7 @@ function accountLimitsTitle(snapshot, time) {
|
|
|
3169
3380
|
0 && (module.exports = {
|
|
3170
3381
|
CHECKPOINT_TRUNCATE_LENGTH,
|
|
3171
3382
|
DEFAULT_RUNNERS,
|
|
3383
|
+
DELEGATION_OFFERED,
|
|
3172
3384
|
EMPTY_CONVERSATION,
|
|
3173
3385
|
EMPTY_HOLD,
|
|
3174
3386
|
EMPTY_RUN,
|
|
@@ -3180,6 +3392,8 @@ function accountLimitsTitle(snapshot, time) {
|
|
|
3180
3392
|
PLANNED_WITH_LABEL,
|
|
3181
3393
|
REPORT_PREVIEW_LINES,
|
|
3182
3394
|
SEVERITY_LABEL,
|
|
3395
|
+
STALLED_LABEL,
|
|
3396
|
+
STOPPING_LABEL,
|
|
3183
3397
|
SUPERVISOR_LEVEL_LABEL,
|
|
3184
3398
|
WAITS_FOR_APPROVAL_LABEL,
|
|
3185
3399
|
accountLimitPercentText,
|
|
@@ -3187,6 +3401,7 @@ function accountLimitsTitle(snapshot, time) {
|
|
|
3187
3401
|
accountLimitsOf,
|
|
3188
3402
|
accountLimitsText,
|
|
3189
3403
|
accountLimitsTitle,
|
|
3404
|
+
activityLabel,
|
|
3190
3405
|
addAttemptUsage,
|
|
3191
3406
|
addModelUsage,
|
|
3192
3407
|
addPlannerUsage,
|
|
@@ -3214,12 +3429,14 @@ function accountLimitsTitle(snapshot, time) {
|
|
|
3214
3429
|
cardEditable,
|
|
3215
3430
|
checkOf,
|
|
3216
3431
|
clampThinkingEffort,
|
|
3432
|
+
closeTurn,
|
|
3217
3433
|
compactionText,
|
|
3218
3434
|
confirmedOverride,
|
|
3219
3435
|
contextMeterText,
|
|
3220
3436
|
contextMeterTitle,
|
|
3221
3437
|
costText,
|
|
3222
3438
|
countedSessionCost,
|
|
3439
|
+
delegatedRowView,
|
|
3223
3440
|
dependencyCandidates,
|
|
3224
3441
|
dependentsNotice,
|
|
3225
3442
|
dependentsOf,
|
|
@@ -3230,10 +3447,12 @@ function accountLimitsTitle(snapshot, time) {
|
|
|
3230
3447
|
diffSummary,
|
|
3231
3448
|
drainNext,
|
|
3232
3449
|
editableWhileRunning,
|
|
3450
|
+
elapsedSince,
|
|
3233
3451
|
endAttemptUsage,
|
|
3234
3452
|
followTaskLog,
|
|
3235
3453
|
followTurn,
|
|
3236
3454
|
formatCost,
|
|
3455
|
+
formatElapsed,
|
|
3237
3456
|
formatTokenCount,
|
|
3238
3457
|
fromTranscript,
|
|
3239
3458
|
handoffBaseLine,
|
|
@@ -3244,6 +3463,7 @@ function accountLimitsTitle(snapshot, time) {
|
|
|
3244
3463
|
hasAccountLimits,
|
|
3245
3464
|
hasHiddenDetail,
|
|
3246
3465
|
hasLongReport,
|
|
3466
|
+
heldWords,
|
|
3247
3467
|
holdLabel,
|
|
3248
3468
|
holdPrompt,
|
|
3249
3469
|
isFileEditTool,
|
|
@@ -3267,10 +3487,12 @@ function accountLimitsTitle(snapshot, time) {
|
|
|
3267
3487
|
markdownHtml,
|
|
3268
3488
|
markdownTokens,
|
|
3269
3489
|
mergeOutcome,
|
|
3490
|
+
mergePastChecksConfirmation,
|
|
3270
3491
|
modelCostTitle,
|
|
3271
3492
|
namedRepos,
|
|
3272
3493
|
newTaskFields,
|
|
3273
3494
|
noExecutorRefusal,
|
|
3495
|
+
onOneLine,
|
|
3274
3496
|
opsEditable,
|
|
3275
3497
|
outOfRounds,
|
|
3276
3498
|
outputLines,
|
|
@@ -3289,6 +3511,7 @@ function accountLimitsTitle(snapshot, time) {
|
|
|
3289
3511
|
reconcileApprovals,
|
|
3290
3512
|
reduceConversation,
|
|
3291
3513
|
reduceTaskLog,
|
|
3514
|
+
repairWaitLabel,
|
|
3292
3515
|
repairedLanded,
|
|
3293
3516
|
repairedNotice,
|
|
3294
3517
|
repeatingChecks,
|
|
@@ -3300,6 +3523,9 @@ function accountLimitsTitle(snapshot, time) {
|
|
|
3300
3523
|
resumeLabel,
|
|
3301
3524
|
resumeTime,
|
|
3302
3525
|
resumedSessionWindow,
|
|
3526
|
+
revertEffect,
|
|
3527
|
+
revertListLine,
|
|
3528
|
+
revertTaskRef,
|
|
3303
3529
|
runHoldsEditors,
|
|
3304
3530
|
runnerToolSubject,
|
|
3305
3531
|
savedPatchView,
|
|
@@ -3308,13 +3534,16 @@ function accountLimitsTitle(snapshot, time) {
|
|
|
3308
3534
|
severityLabel,
|
|
3309
3535
|
skillTokens,
|
|
3310
3536
|
skippedLabel,
|
|
3537
|
+
spentTokens,
|
|
3311
3538
|
startAttemptUsage,
|
|
3312
3539
|
stopTurn,
|
|
3313
3540
|
subagentCostTitle,
|
|
3314
3541
|
subtreeIds,
|
|
3542
|
+
subtreeView,
|
|
3315
3543
|
summarizeToolCall,
|
|
3316
3544
|
takeAt,
|
|
3317
3545
|
taskActionCommand,
|
|
3546
|
+
taskActivity,
|
|
3318
3547
|
taskChatAvailable,
|
|
3319
3548
|
taskLogCommands,
|
|
3320
3549
|
taskLogHeaderView,
|