omnius 1.0.452 → 1.0.453
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/index.js +542 -125
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -14361,6 +14361,22 @@ var init_file_edit = __esm({
|
|
|
14361
14361
|
}
|
|
14362
14362
|
const occurrences = countOccurrences(content, oldString);
|
|
14363
14363
|
if (occurrences === 0) {
|
|
14364
|
+
const alreadyAppliedLines = newString.length > 0 ? findMatchLines(content, newString) : [];
|
|
14365
|
+
if (alreadyAppliedLines.length > 0) {
|
|
14366
|
+
const lineInfo = alreadyAppliedLines.length === 1 ? `line ${alreadyAppliedLines[0]}` : `${alreadyAppliedLines.length} locations (lines ${alreadyAppliedLines.join(", ")})`;
|
|
14367
|
+
return {
|
|
14368
|
+
success: true,
|
|
14369
|
+
output: `[ALREADY APPLIED — ${filePath} already contains the requested new_string at ${lineInfo}; old_string is absent. No disk changes were made.]`,
|
|
14370
|
+
durationMs: performance.now() - start2,
|
|
14371
|
+
mutated: false,
|
|
14372
|
+
mutatedFiles: [],
|
|
14373
|
+
diff: buildCompactDiff(oldString, newString),
|
|
14374
|
+
noop: true,
|
|
14375
|
+
alreadyApplied: true,
|
|
14376
|
+
beforeHash,
|
|
14377
|
+
afterHash: beforeHash
|
|
14378
|
+
};
|
|
14379
|
+
}
|
|
14364
14380
|
const snippet = findClosestSnippet(content, oldString, 5);
|
|
14365
14381
|
let errorMsg = `old_string not found in ${filePath}.`;
|
|
14366
14382
|
if (snippet) {
|
|
@@ -28439,6 +28455,9 @@ function findMatchOffsetsBatch(haystack, needle) {
|
|
|
28439
28455
|
}
|
|
28440
28456
|
return offsets;
|
|
28441
28457
|
}
|
|
28458
|
+
function findMatchLinesBatch(haystack, needle) {
|
|
28459
|
+
return findMatchOffsetsBatch(haystack, needle).map((offset) => haystack.slice(0, offset).split("\n").length);
|
|
28460
|
+
}
|
|
28442
28461
|
function countOccurrences2(haystack, needle) {
|
|
28443
28462
|
let count = 0;
|
|
28444
28463
|
let pos = 0;
|
|
@@ -28587,6 +28606,7 @@ var init_batch_edit = __esm({
|
|
|
28587
28606
|
}
|
|
28588
28607
|
const results = [];
|
|
28589
28608
|
let successCount = 0;
|
|
28609
|
+
let alreadyAppliedCount = 0;
|
|
28590
28610
|
let failCount = 0;
|
|
28591
28611
|
const pendingWrites = [];
|
|
28592
28612
|
for (const [fullPath, fileEdits] of byFile) {
|
|
@@ -28607,10 +28627,18 @@ var init_batch_edit = __esm({
|
|
|
28607
28627
|
}
|
|
28608
28628
|
const originalContent = content;
|
|
28609
28629
|
let fileSuccessCount = 0;
|
|
28630
|
+
let fileAlreadyAppliedCount = 0;
|
|
28610
28631
|
let fileFailed = false;
|
|
28611
28632
|
for (const edit of fileEdits) {
|
|
28612
28633
|
const occurrences = countOccurrences2(content, edit.old_string);
|
|
28613
28634
|
if (occurrences === 0) {
|
|
28635
|
+
const alreadyAppliedLines = edit.new_string.length > 0 ? findMatchLinesBatch(content, edit.new_string) : [];
|
|
28636
|
+
if (alreadyAppliedLines.length > 0) {
|
|
28637
|
+
const lineInfo = alreadyAppliedLines.length === 1 ? `line ${alreadyAppliedLines[0]}` : `${alreadyAppliedLines.length} locations (lines ${alreadyAppliedLines.join(", ")})`;
|
|
28638
|
+
results.push(`ALREADY_APPLIED: ${edit.relPath} already contains requested new_string at ${lineInfo}; old_string is absent`);
|
|
28639
|
+
fileAlreadyAppliedCount++;
|
|
28640
|
+
continue;
|
|
28641
|
+
}
|
|
28614
28642
|
const snippet = findClosestSnippet(content, edit.old_string, 5);
|
|
28615
28643
|
if (snippet) {
|
|
28616
28644
|
const pct = Math.round(snippet.similarity * 100);
|
|
@@ -28657,6 +28685,8 @@ ${s2.content}`;
|
|
|
28657
28685
|
const afterHash = contentHash(content);
|
|
28658
28686
|
if (afterHash === beforeHash) {
|
|
28659
28687
|
results.push(`NO-OP: ${fileEdits[0].relPath} batch produced no disk changes`);
|
|
28688
|
+
successCount += fileAlreadyAppliedCount;
|
|
28689
|
+
alreadyAppliedCount += fileAlreadyAppliedCount;
|
|
28660
28690
|
continue;
|
|
28661
28691
|
}
|
|
28662
28692
|
pendingWrites.push({
|
|
@@ -28667,7 +28697,8 @@ ${s2.content}`;
|
|
|
28667
28697
|
afterHash,
|
|
28668
28698
|
editCount: fileSuccessCount
|
|
28669
28699
|
});
|
|
28670
|
-
successCount += fileSuccessCount;
|
|
28700
|
+
successCount += fileSuccessCount + fileAlreadyAppliedCount;
|
|
28701
|
+
alreadyAppliedCount += fileAlreadyAppliedCount;
|
|
28671
28702
|
} catch (error) {
|
|
28672
28703
|
results.push(`ERROR: ${fullPath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
28673
28704
|
failCount++;
|
|
@@ -28692,7 +28723,7 @@ ${s2.content}`;
|
|
|
28692
28723
|
].join("\n") : dryRun ? [
|
|
28693
28724
|
`BATCH_VALIDATED_ONLY: ${appliedCount} edit(s) validated, 0 failed across ${byFile.size} file(s).`,
|
|
28694
28725
|
`NO FILES WERE MODIFIED. Call again with dry_run=false to apply this atomic batch.`
|
|
28695
|
-
].join("\n") : `BATCH_COMMITTED: ${appliedCount} edit(s) applied, 0 failed across ${byFile.size} file(s).`;
|
|
28726
|
+
].join("\n") : pendingWrites.length === 0 && alreadyAppliedCount > 0 ? `BATCH_NOOP_ALREADY_APPLIED: ${alreadyAppliedCount} edit(s) already satisfied, 0 failed across ${byFile.size} file(s).` : `BATCH_COMMITTED: ${appliedCount} edit(s) satisfied (${pendingWrites.reduce((sum, write2) => sum + write2.editCount, 0)} applied, ${alreadyAppliedCount} already applied), 0 failed across ${byFile.size} file(s).`;
|
|
28696
28727
|
const detailOutput = failCount === 0 ? dryRun ? results.join("\n") : results.map((line) => line.replace(/^VALIDATED_ONLY:/, "APPLIED:").replace(/ pending atomic commit/g, "")).join("\n") : results.join("\n");
|
|
28697
28728
|
return {
|
|
28698
28729
|
success: failCount === 0,
|
|
@@ -28703,6 +28734,7 @@ ${detailOutput}`,
|
|
|
28703
28734
|
mutated: failCount === 0 && !dryRun && pendingWrites.length > 0,
|
|
28704
28735
|
mutatedFiles: failCount === 0 && !dryRun ? pendingWrites.map((w) => w.relPath) : [],
|
|
28705
28736
|
noop: failCount === 0 && pendingWrites.length === 0,
|
|
28737
|
+
alreadyApplied: failCount === 0 && alreadyAppliedCount > 0,
|
|
28706
28738
|
dryRun: dryRun || void 0,
|
|
28707
28739
|
partial: false,
|
|
28708
28740
|
beforeHash: pendingWrites.length === 1 ? pendingWrites[0].beforeHash : void 0,
|
|
@@ -298462,11 +298494,12 @@ var init_todo_write = __esm({
|
|
|
298462
298494
|
|
|
298463
298495
|
## Nested decomposition
|
|
298464
298496
|
- Use stable ids plus parentId to create subtasks under a parent objective.
|
|
298497
|
+
- Prefer a parent + child leaf todos for any active objective that has multiple concrete actions; the TUI renders the active branch indented for the user and for your next-turn context.
|
|
298465
298498
|
- Work on leaf subtasks; a parent is completed only after every child is completed with evidence.
|
|
298466
298499
|
- When evidence changes the plan, rewrite the tree: add new child todos, block invalidated children with root cause, and keep the parent in_progress/blocked until the child set is truthful.
|
|
298467
298500
|
- If a tool fails for a child, do not mark that child completed. Reconfigure it: re-read/observe current state, choose a different target/tool, or leave it blocked.
|
|
298468
298501
|
|
|
298469
|
-
Mark tasks complete IMMEDIATELY after finishing — don't batch. Never mark completed if tests are failing or implementation is partial. The user watches this list in the chat UI in real time. Canonical
|
|
298502
|
+
Mark tasks complete IMMEDIATELY after finishing — don't batch. Never mark completed if tests are failing or implementation is partial. The user watches this list in the chat UI in real time. Canonical nested shape: todo_write({"todos":[{"id":"p1","content":"Implement feature","status":"in_progress","children":[{"id":"c1","content":"Inspect files","status":"in_progress"},{"id":"c2","content":"Make changes","status":"pending"},{"id":"c3","content":"Verify results","status":"pending"}]}]})`;
|
|
298470
298503
|
parameters = {
|
|
298471
298504
|
type: "object",
|
|
298472
298505
|
required: ["todos"],
|
|
@@ -298643,11 +298676,15 @@ Mark tasks complete IMMEDIATELY after finishing — don't batch. Never mark comp
|
|
|
298643
298676
|
const reminder = "Todos have been modified successfully. Ensure that you continue to use the todo list to track your progress. Mark the current task in_progress and the next task pending. Proceed with the current task.";
|
|
298644
298677
|
const payload = {
|
|
298645
298678
|
reminder,
|
|
298646
|
-
decompositionContract: "Use parentId for sub-todos. Keep parents in_progress/blocked until all children are completed with objective evidence. When tool evidence invalidates a child, rewrite that child as blocked or split it into new children instead of overclaiming completion.",
|
|
298679
|
+
decompositionContract: "Use parentId for sub-todos. Split the active objective into concrete child leaf todos whenever it contains multiple remaining actions. Keep parents in_progress/blocked until all children are completed with objective evidence. When tool evidence invalidates a child, rewrite that child as blocked or split it into new children instead of overclaiming completion.",
|
|
298647
298680
|
oldTodos: result.oldTodos,
|
|
298648
298681
|
newTodos: result.newTodos,
|
|
298649
298682
|
verificationNudgeNeeded
|
|
298650
298683
|
};
|
|
298684
|
+
const hasNestedTodos = incoming.some((todo) => typeof todo.parentId === "string" && todo.parentId.trim().length > 0);
|
|
298685
|
+
if (incoming.length >= 3 && !hasNestedTodos) {
|
|
298686
|
+
payload["decompositionHint"] = "This checklist is still flat. If the current in_progress item expands into multiple actions, rewrite it as a parent with child todos using stable ids and parentId/children so the active branch stays visible.";
|
|
298687
|
+
}
|
|
298651
298688
|
if (repairNotes.length > 0) {
|
|
298652
298689
|
payload["inputRepair"] = Array.from(new Set(repairNotes));
|
|
298653
298690
|
payload["canonicalShape"] = {
|
|
@@ -573482,7 +573519,7 @@ function recordContextWindowDump(input) {
|
|
|
573482
573519
|
const payload = JSON.stringify(record, null, 2);
|
|
573483
573520
|
writeFileSync48(filePath, payload, "utf-8");
|
|
573484
573521
|
writeFileSync48(join111(dir, `latest-${record.agentType}.json`), payload, "utf-8");
|
|
573485
|
-
if (record.agentType === "main") {
|
|
573522
|
+
if (record.agentType === "main" || record.agentType === "sub-agent" || record.agentType === "adversary") {
|
|
573486
573523
|
writeFileSync48(join111(dir, "latest.json"), payload, "utf-8");
|
|
573487
573524
|
}
|
|
573488
573525
|
appendFileSync9(join111(dir, "index.jsonl"), JSON.stringify(toSummary(record, filePath)) + "\n", "utf-8");
|
|
@@ -574701,14 +574738,13 @@ function resolveFocusSupervisorMode(configured, envValue = process.env["OMNIUS_F
|
|
|
574701
574738
|
function violatesDirective(directive, input) {
|
|
574702
574739
|
if (input.toolName === "task_complete") {
|
|
574703
574740
|
const completionStatus = normalizeCompletionStatus(input.completionStatus ?? input.args?.["status"] ?? input.args?.["completion_status"] ?? input.args?.["completionStatus"]);
|
|
574704
|
-
const
|
|
574705
|
-
|
|
574706
|
-
|
|
574741
|
+
const summaryText = typeof input.args?.["summary"] === "string" ? input.args["summary"] : "";
|
|
574742
|
+
const summaryReportsDegraded = /^\s*(BLOCKED|INCOMPLETE|NEEDS[_ -]?INPUT)\b\s*:?/i.test(summaryText);
|
|
574743
|
+
const reportsDegradedCompletion = completionStatus === "blocked" || completionStatus === "incomplete" || completionStatus === "needs_input" || summaryReportsDegraded;
|
|
574744
|
+
if (directive.requiredNextAction === "report_blocked" || directive.requiredNextAction === "report_incomplete" || directive.state === "terminal_incomplete") {
|
|
574745
|
+
return !reportsDegradedCompletion;
|
|
574707
574746
|
}
|
|
574708
|
-
|
|
574709
|
-
return false;
|
|
574710
|
-
}
|
|
574711
|
-
return directive.requiredNextAction !== "report_blocked" && directive.requiredNextAction !== "report_incomplete";
|
|
574747
|
+
return false;
|
|
574712
574748
|
}
|
|
574713
574749
|
if (input.toolName === "ask_user")
|
|
574714
574750
|
return false;
|
|
@@ -574989,6 +575025,11 @@ var init_focusSupervisor = __esm({
|
|
|
574989
575025
|
const family = actionFamily(input.toolName, input.args);
|
|
574990
575026
|
const prior = this.directive;
|
|
574991
575027
|
if (prior && violatesDirective(prior, input)) {
|
|
575028
|
+
if (prior.state === "warn") {
|
|
575029
|
+
this.lastDecision = "warn_not_enforced";
|
|
575030
|
+
this.lastReason = prior.reason;
|
|
575031
|
+
return this.pass();
|
|
575032
|
+
}
|
|
574992
575033
|
const strict = this.shouldStrictlyIntervene(input.context);
|
|
574993
575034
|
const sameTurnAsDirective = input.turn <= prior.createdTurn;
|
|
574994
575035
|
const alreadyCountedThisTurn = this.lastIgnoredDirectiveTurn === input.turn;
|
|
@@ -575105,6 +575146,10 @@ var init_focusSupervisor = __esm({
|
|
|
575105
575146
|
this.clearSatisfiedDirective("mutation landed", input.turn);
|
|
575106
575147
|
return;
|
|
575107
575148
|
}
|
|
575149
|
+
if (input.success && input.alreadyApplied) {
|
|
575150
|
+
this.clearSatisfiedDirective("requested edit already applied", input.turn);
|
|
575151
|
+
return;
|
|
575152
|
+
}
|
|
575108
575153
|
if (input.runtimeAuthored) {
|
|
575109
575154
|
this.lastDecision = "runtime_authored_not_satisfied";
|
|
575110
575155
|
this.lastReason = "runtime-authored control result did not execute the requested tool";
|
|
@@ -577627,7 +577672,7 @@ function computeTodoReminder(input) {
|
|
|
577627
577672
|
if (!input.todos || input.todos.length === 0) {
|
|
577628
577673
|
if (input.elicitCreateOnEmptyTodos) {
|
|
577629
577674
|
const content2 = `<system-reminder>
|
|
577630
|
-
No todo plan exists yet. Consider using the todo_write tool to create a plan for the current task — break the goal into
|
|
577675
|
+
No todo plan exists yet. Consider using the todo_write tool to create a plan for the current task — break the goal into parent objectives and child leaf subtasks when the work has multiple actions, mark the active leaf in_progress, and keep the rest pending. This helps you stay organized and track progress. Make sure that you NEVER mention this reminder to the user.
|
|
577631
577676
|
</system-reminder>`;
|
|
577632
577677
|
return { shouldInject: true, content: content2, reason: "elicit_create" };
|
|
577633
577678
|
}
|
|
@@ -577647,9 +577692,9 @@ No todo plan exists yet. Consider using the todo_write tool to create a plan for
|
|
|
577647
577692
|
return { shouldInject: false, content: null, reason: "recent_reminder" };
|
|
577648
577693
|
}
|
|
577649
577694
|
}
|
|
577650
|
-
const todoItems = input.todos
|
|
577695
|
+
const todoItems = formatTodoReminderItems(input.todos, 12);
|
|
577651
577696
|
const content = `<system-reminder>
|
|
577652
|
-
The todo_write tool hasn't been used recently. Review your todo list below. If you're working on a task, mark
|
|
577697
|
+
The todo_write tool hasn't been used recently. Review your todo list below. If you're working on a task, mark the active leaf in_progress. When you complete a leaf task, mark it completed immediately — don't batch completions. If the current item has multiple remaining actions, decompose it with stable ids and parentId/children instead of flattening the list. If the list is stale, clean it up. Make sure that you NEVER mention this reminder to the user.
|
|
577653
577698
|
|
|
577654
577699
|
Here are the existing contents of your todo list:
|
|
577655
577700
|
|
|
@@ -577657,6 +577702,40 @@ ${todoItems}
|
|
|
577657
577702
|
</system-reminder>`;
|
|
577658
577703
|
return { shouldInject: true, content, reason: "injected" };
|
|
577659
577704
|
}
|
|
577705
|
+
function formatTodoReminderItems(todos, maxRows) {
|
|
577706
|
+
const byId = new Map(todos.filter((todo) => typeof todo.id === "string" && todo.id.trim().length > 0).map((todo) => [todo.id, todo]));
|
|
577707
|
+
const byParent = /* @__PURE__ */ new Map();
|
|
577708
|
+
const roots = [];
|
|
577709
|
+
for (const todo of todos) {
|
|
577710
|
+
if (todo.parentId && byId.has(todo.parentId)) {
|
|
577711
|
+
const siblings = byParent.get(todo.parentId) ?? [];
|
|
577712
|
+
siblings.push(todo);
|
|
577713
|
+
byParent.set(todo.parentId, siblings);
|
|
577714
|
+
} else {
|
|
577715
|
+
roots.push(todo);
|
|
577716
|
+
}
|
|
577717
|
+
}
|
|
577718
|
+
const rows = [];
|
|
577719
|
+
const seen = /* @__PURE__ */ new Set();
|
|
577720
|
+
const visit = (todo, depth) => {
|
|
577721
|
+
if (rows.length >= maxRows || seen.has(todo))
|
|
577722
|
+
return;
|
|
577723
|
+
seen.add(todo);
|
|
577724
|
+
const indent2 = " ".repeat(Math.min(depth, 4));
|
|
577725
|
+
rows.push(`${indent2}- [${todo.status}] ${todo.content}`);
|
|
577726
|
+
if (!todo.id)
|
|
577727
|
+
return;
|
|
577728
|
+
for (const child of byParent.get(todo.id) ?? [])
|
|
577729
|
+
visit(child, depth + 1);
|
|
577730
|
+
};
|
|
577731
|
+
for (const root of roots)
|
|
577732
|
+
visit(root, 0);
|
|
577733
|
+
for (const todo of todos)
|
|
577734
|
+
visit(todo, 0);
|
|
577735
|
+
if (todos.length > rows.length)
|
|
577736
|
+
rows.push(`... +${todos.length - rows.length} more`);
|
|
577737
|
+
return rows.join("\n");
|
|
577738
|
+
}
|
|
577660
577739
|
function stripThinkBlocks(s2) {
|
|
577661
577740
|
if (!s2)
|
|
577662
577741
|
return s2;
|
|
@@ -577946,6 +578025,7 @@ var init_agenticRunner = __esm({
|
|
|
577946
578025
|
init_context_compressor();
|
|
577947
578026
|
init_reflectionBuffer();
|
|
577948
578027
|
init_taskHandoff();
|
|
578028
|
+
init_artifactQuality();
|
|
577949
578029
|
init_messageLog();
|
|
577950
578030
|
init_contextTree();
|
|
577951
578031
|
init_codeGraphLink();
|
|
@@ -578844,16 +578924,21 @@ ${parts.join("\n")}
|
|
|
578844
578924
|
lines.push("implementation_state=mutation evidence is already recorded; do not treat discovery as the active phase");
|
|
578845
578925
|
}
|
|
578846
578926
|
}
|
|
578847
|
-
const todos = this.readSessionTodos() ?? [];
|
|
578927
|
+
const todos = this._normalizeTodosForPrompt(this.readSessionTodos() ?? []);
|
|
578848
578928
|
if (todos.length > 0) {
|
|
578849
|
-
const
|
|
578850
|
-
const
|
|
578851
|
-
const
|
|
578852
|
-
|
|
578853
|
-
|
|
578854
|
-
|
|
578929
|
+
const index = this._todoTreeIndex(todos);
|
|
578930
|
+
const leaves = this._todoLeaves(todos, index);
|
|
578931
|
+
const active = this._activeTodoForPrompt(todos, index);
|
|
578932
|
+
const inProgress = leaves.filter((todo) => todo.status === "in_progress");
|
|
578933
|
+
const pending2 = leaves.filter((todo) => todo.status === "pending");
|
|
578934
|
+
const blocked = leaves.filter((todo) => todo.status === "blocked");
|
|
578935
|
+
const completed = leaves.filter((todo) => todo.status === "completed");
|
|
578936
|
+
lines.push(`todo_leaf_counts=completed:${completed.length} in_progress:${inProgress.length} pending:${pending2.length} blocked:${blocked.length}`);
|
|
578937
|
+
if (active) {
|
|
578938
|
+
const branch = this._todoPath(active, index).map((todo) => todo.content.slice(0, 64)).join(" > ");
|
|
578939
|
+
lines.push(`todo_active_branch=${branch.slice(0, 220)}`);
|
|
578855
578940
|
} else if (pending2.length > 0) {
|
|
578856
|
-
lines.push("todo_contract=mark
|
|
578941
|
+
lines.push("todo_contract=mark one pending leaf todo in_progress before using the checklist as progress");
|
|
578857
578942
|
}
|
|
578858
578943
|
}
|
|
578859
578944
|
if (lines.length === 2)
|
|
@@ -578863,7 +578948,7 @@ ${parts.join("\n")}
|
|
|
578863
578948
|
}
|
|
578864
578949
|
_workboardTargetCardId(snapshot, toolName, result, meta = {}) {
|
|
578865
578950
|
const byId = new Map(snapshot.cards.map((card) => [card.id, card]));
|
|
578866
|
-
if (this._isProjectEditTool(toolName) && this._isRealProjectMutation(toolName, result)) {
|
|
578951
|
+
if (this._isProjectEditTool(toolName) && (this._isRealProjectMutation(toolName, result) || result?.alreadyApplied === true)) {
|
|
578867
578952
|
return byId.has("implement-repair") ? "implement-repair" : null;
|
|
578868
578953
|
}
|
|
578869
578954
|
if (toolName === "shell" && meta.shellFilesystemMutation === true) {
|
|
@@ -578889,9 +578974,9 @@ ${parts.join("\n")}
|
|
|
578889
578974
|
const dir = this._workboardDir();
|
|
578890
578975
|
let current = snapshot;
|
|
578891
578976
|
const byId = () => new Map(current.cards.map((card) => [card.id, card]));
|
|
578892
|
-
const
|
|
578977
|
+
const editEvidence = this._isProjectEditTool(toolName) && (this._isRealProjectMutation(toolName, result) || result?.alreadyApplied === true) || toolName === "shell" && result?.success === true && meta.shellFilesystemMutation === true;
|
|
578893
578978
|
try {
|
|
578894
|
-
if (
|
|
578979
|
+
if (editEvidence) {
|
|
578895
578980
|
let cards = byId();
|
|
578896
578981
|
const discovery = cards.get("discover-current-state");
|
|
578897
578982
|
if (discovery && discovery.status !== "verified" && discovery.evidence.length > 0) {
|
|
@@ -578924,7 +579009,7 @@ ${parts.join("\n")}
|
|
|
578924
579009
|
cardId: implementation2.id,
|
|
578925
579010
|
actor,
|
|
578926
579011
|
updates: { status: "in_progress", lane: "worker" },
|
|
578927
|
-
decisionReason: "Real project mutation landed; implementation is now the active phase."
|
|
579012
|
+
decisionReason: result?.alreadyApplied === true ? "Requested implementation edit was already present on disk; implementation evidence is now active." : "Real project mutation landed; implementation is now the active phase."
|
|
578928
579013
|
});
|
|
578929
579014
|
}
|
|
578930
579015
|
}
|
|
@@ -578961,7 +579046,7 @@ ${parts.join("\n")}
|
|
|
578961
579046
|
return;
|
|
578962
579047
|
if (meta.focusDecisionKind === "block_tool_call")
|
|
578963
579048
|
return;
|
|
578964
|
-
if (result?.success === true && this._isProjectEditTool(toolName) && !this._isRealProjectMutation(toolName, result)) {
|
|
579049
|
+
if (result?.success === true && this._isProjectEditTool(toolName) && !this._isRealProjectMutation(toolName, result) && result.alreadyApplied !== true) {
|
|
578965
579050
|
return;
|
|
578966
579051
|
}
|
|
578967
579052
|
const dir = this._workboardDir();
|
|
@@ -580430,6 +580515,127 @@ Pick the SMALLEST concrete deliverable from the spec — typically the project e
|
|
|
580430
580515
|
return null;
|
|
580431
580516
|
}
|
|
580432
580517
|
}
|
|
580518
|
+
_normalizeTodosForPrompt(todos) {
|
|
580519
|
+
return todos.map((todo, index) => {
|
|
580520
|
+
const rawId = todo.id;
|
|
580521
|
+
const id2 = typeof rawId === "string" && rawId.trim().length > 0 ? rawId.trim() : `prompt-${index}`;
|
|
580522
|
+
const rawParentId = todo.parentId;
|
|
580523
|
+
const parentId = typeof rawParentId === "string" && rawParentId.trim().length > 0 ? rawParentId.trim() : void 0;
|
|
580524
|
+
const createdAt = typeof todo.createdAt === "number" ? todo.createdAt : 0;
|
|
580525
|
+
const updatedAt = typeof todo.updatedAt === "number" ? todo.updatedAt : createdAt;
|
|
580526
|
+
return {
|
|
580527
|
+
...todo,
|
|
580528
|
+
id: id2,
|
|
580529
|
+
...parentId ? { parentId } : {},
|
|
580530
|
+
createdAt,
|
|
580531
|
+
updatedAt
|
|
580532
|
+
};
|
|
580533
|
+
});
|
|
580534
|
+
}
|
|
580535
|
+
_todoTreeIndex(todos) {
|
|
580536
|
+
const byId = new Map(todos.map((todo) => [todo.id, todo]));
|
|
580537
|
+
const byParent = /* @__PURE__ */ new Map();
|
|
580538
|
+
const roots = [];
|
|
580539
|
+
for (const todo of todos) {
|
|
580540
|
+
if (todo.parentId && byId.has(todo.parentId)) {
|
|
580541
|
+
const siblings = byParent.get(todo.parentId) ?? [];
|
|
580542
|
+
siblings.push(todo);
|
|
580543
|
+
byParent.set(todo.parentId, siblings);
|
|
580544
|
+
} else {
|
|
580545
|
+
roots.push(todo);
|
|
580546
|
+
}
|
|
580547
|
+
}
|
|
580548
|
+
return { byId, byParent, roots };
|
|
580549
|
+
}
|
|
580550
|
+
_todoDisplayStatus(todo, index, seen = /* @__PURE__ */ new Set()) {
|
|
580551
|
+
if (seen.has(todo.id))
|
|
580552
|
+
return todo.status;
|
|
580553
|
+
seen.add(todo.id);
|
|
580554
|
+
const children2 = index.byParent.get(todo.id) ?? [];
|
|
580555
|
+
if (children2.length === 0)
|
|
580556
|
+
return todo.status;
|
|
580557
|
+
const childStatuses = children2.map((child) => this._todoDisplayStatus(child, index, new Set(seen)));
|
|
580558
|
+
if (childStatuses.some((status) => status === "blocked"))
|
|
580559
|
+
return "blocked";
|
|
580560
|
+
if (childStatuses.some((status) => status === "in_progress"))
|
|
580561
|
+
return "in_progress";
|
|
580562
|
+
if (childStatuses.every((status) => status === "completed"))
|
|
580563
|
+
return "completed";
|
|
580564
|
+
if (todo.status === "completed")
|
|
580565
|
+
return "in_progress";
|
|
580566
|
+
return todo.status;
|
|
580567
|
+
}
|
|
580568
|
+
_todoLeafStats(todo, index) {
|
|
580569
|
+
const children2 = index.byParent.get(todo.id) ?? [];
|
|
580570
|
+
if (children2.length === 0)
|
|
580571
|
+
return null;
|
|
580572
|
+
let completed = 0;
|
|
580573
|
+
let total = 0;
|
|
580574
|
+
const seen = /* @__PURE__ */ new Set();
|
|
580575
|
+
const visit = (node) => {
|
|
580576
|
+
if (seen.has(node.id))
|
|
580577
|
+
return;
|
|
580578
|
+
seen.add(node.id);
|
|
580579
|
+
const nested = index.byParent.get(node.id) ?? [];
|
|
580580
|
+
if (nested.length === 0) {
|
|
580581
|
+
total++;
|
|
580582
|
+
if (node.status === "completed")
|
|
580583
|
+
completed++;
|
|
580584
|
+
return;
|
|
580585
|
+
}
|
|
580586
|
+
for (const child of nested)
|
|
580587
|
+
visit(child);
|
|
580588
|
+
};
|
|
580589
|
+
for (const child of children2)
|
|
580590
|
+
visit(child);
|
|
580591
|
+
return { completed, total };
|
|
580592
|
+
}
|
|
580593
|
+
_todoLeaves(todos, index = this._todoTreeIndex(todos)) {
|
|
580594
|
+
const leaves = todos.filter((todo) => (index.byParent.get(todo.id) ?? []).length === 0);
|
|
580595
|
+
return leaves.length > 0 ? leaves : todos;
|
|
580596
|
+
}
|
|
580597
|
+
_todoPath(todo, index) {
|
|
580598
|
+
const path12 = [todo];
|
|
580599
|
+
const seen = /* @__PURE__ */ new Set([todo.id]);
|
|
580600
|
+
let cursor = todo;
|
|
580601
|
+
while (cursor?.parentId && index.byId.has(cursor.parentId)) {
|
|
580602
|
+
const parent = index.byId.get(cursor.parentId);
|
|
580603
|
+
if (!parent || seen.has(parent.id))
|
|
580604
|
+
break;
|
|
580605
|
+
path12.unshift(parent);
|
|
580606
|
+
seen.add(parent.id);
|
|
580607
|
+
cursor = parent;
|
|
580608
|
+
}
|
|
580609
|
+
return path12;
|
|
580610
|
+
}
|
|
580611
|
+
_activeTodoForPrompt(todos, index = this._todoTreeIndex(todos)) {
|
|
580612
|
+
const leaves = this._todoLeaves(todos, index);
|
|
580613
|
+
return leaves.find((todo) => todo.status === "in_progress") ?? todos.find((todo) => this._todoDisplayStatus(todo, index) === "in_progress") ?? todos.find((todo) => this._todoDisplayStatus(todo, index) === "blocked") ?? todos.find((todo) => this._todoDisplayStatus(todo, index) === "pending") ?? null;
|
|
580614
|
+
}
|
|
580615
|
+
_orderedTodosForPrompt(todos) {
|
|
580616
|
+
const index = this._todoTreeIndex(todos);
|
|
580617
|
+
const out = [];
|
|
580618
|
+
const seen = /* @__PURE__ */ new Set();
|
|
580619
|
+
const visit = (todo, depth) => {
|
|
580620
|
+
if (seen.has(todo.id))
|
|
580621
|
+
return;
|
|
580622
|
+
seen.add(todo.id);
|
|
580623
|
+
out.push({
|
|
580624
|
+
todo,
|
|
580625
|
+
depth: Math.min(depth, 4),
|
|
580626
|
+
displayStatus: this._todoDisplayStatus(todo, index),
|
|
580627
|
+
childStats: this._todoLeafStats(todo, index)
|
|
580628
|
+
});
|
|
580629
|
+
for (const child of index.byParent.get(todo.id) ?? []) {
|
|
580630
|
+
visit(child, depth + 1);
|
|
580631
|
+
}
|
|
580632
|
+
};
|
|
580633
|
+
for (const root of index.roots)
|
|
580634
|
+
visit(root, 0);
|
|
580635
|
+
for (const todo of todos)
|
|
580636
|
+
visit(todo, 0);
|
|
580637
|
+
return out;
|
|
580638
|
+
}
|
|
580433
580639
|
_normalizeCommandForValidationMatch(command) {
|
|
580434
580640
|
return normalizeShellCommand(command);
|
|
580435
580641
|
}
|
|
@@ -580584,7 +580790,9 @@ ${modelVisible}` : modelVisible || result.error || displayOutput || "";
|
|
|
580584
580790
|
const realFileMutation = input.realFileMutation ?? this._isRealProjectMutation(input.toolName, input.result);
|
|
580585
580791
|
const attemptedTargetPaths = this._extractToolTargetPaths(input.toolName, input.args, input.result);
|
|
580586
580792
|
const realMutationPaths = input.realMutationPaths ?? (realFileMutation ? attemptedTargetPaths : []);
|
|
580587
|
-
|
|
580793
|
+
const shellVerification = input.toolName === "shell" && input.result.runtimeAuthored !== true && this._shellResultLooksLikeVerification(input.args, input.result);
|
|
580794
|
+
const shellVerificationFamily = shellVerification ? this._shellVerificationFamily(input.args) : "";
|
|
580795
|
+
if (input.result.success === true && this._isProjectEditTool(input.toolName) && !realFileMutation && input.result.alreadyApplied !== true) {
|
|
580588
580796
|
return;
|
|
580589
580797
|
}
|
|
580590
580798
|
if (this._shouldSuppressCompletionDiscoveryEvidence(input.toolName, input.result, attemptedTargetPaths)) {
|
|
@@ -580596,9 +580804,9 @@ ${modelVisible}` : modelVisible || result.error || displayOutput || "";
|
|
|
580596
580804
|
outputPreview: (input.outputPreview ?? this._toolEvidencePreview(input.result, void 0, 1200, input.toolName)).toString().slice(0, input.toolName === "audio_analyze" || input.toolName === "video_understand" ? 1200 : 500),
|
|
580597
580805
|
argsKey: input.argsKey.slice(0, 300),
|
|
580598
580806
|
targetPaths: attemptedTargetPaths,
|
|
580599
|
-
role: input.result.completionEvidenceRole ?? (realFileMutation ? "mutation" : input.result.runtimeAuthored === true ? "blocker" : void 0),
|
|
580600
|
-
family: input.result.completionEvidenceFamily ?? (input.result.runtimeAuthored === true ? "runtime_control" : void 0),
|
|
580601
|
-
verificationImpact: input.result.completionVerificationImpact ?? (realFileMutation ? "invalidates" : void 0),
|
|
580807
|
+
role: input.result.completionEvidenceRole ?? (input.result.alreadyApplied === true ? "mutation" : realFileMutation ? "mutation" : input.result.runtimeAuthored === true ? "blocker" : shellVerification ? "verification" : void 0),
|
|
580808
|
+
family: input.result.completionEvidenceFamily ?? (input.result.runtimeAuthored === true ? "runtime_control" : shellVerification ? shellVerificationFamily : void 0),
|
|
580809
|
+
verificationImpact: input.result.completionVerificationImpact ?? (input.result.alreadyApplied === true ? "neutral" : realFileMutation ? "invalidates" : void 0),
|
|
580602
580810
|
metrics: input.result.completionEvidenceMetrics
|
|
580603
580811
|
});
|
|
580604
580812
|
if (realFileMutation && realMutationPaths.length > 0) {
|
|
@@ -580617,6 +580825,20 @@ ${modelVisible}` : modelVisible || result.error || displayOutput || "";
|
|
|
580617
580825
|
}
|
|
580618
580826
|
this._saveCompletionLedgerSafe();
|
|
580619
580827
|
}
|
|
580828
|
+
_shellVerificationFamily(args) {
|
|
580829
|
+
const command = String(args?.["command"] ?? args?.["cmd"] ?? "").trim();
|
|
580830
|
+
const normalized = normalizeShellCommand(command);
|
|
580831
|
+
return `shell:${(normalized || command || "verification").slice(0, 160)}`;
|
|
580832
|
+
}
|
|
580833
|
+
_shellResultLooksLikeVerification(args, result) {
|
|
580834
|
+
const command = String(args?.["command"] ?? args?.["cmd"] ?? "");
|
|
580835
|
+
if (!command.trim())
|
|
580836
|
+
return false;
|
|
580837
|
+
const text2 = `${command}
|
|
580838
|
+
${result.output ?? ""}
|
|
580839
|
+
${result.error ?? ""}`;
|
|
580840
|
+
return /\b(test|tests|vitest|jest|pytest|go test|cargo test|npm test|pnpm test|yarn test|typecheck|tsc|build|verify|verification|check)\b/i.test(text2);
|
|
580841
|
+
}
|
|
580620
580842
|
_shouldSuppressCompletionDiscoveryEvidence(toolName, result, targetPaths) {
|
|
580621
580843
|
if (result.success !== true)
|
|
580622
580844
|
return false;
|
|
@@ -581097,6 +581319,9 @@ ${context2 ?? ""}`;
|
|
|
581097
581319
|
const originalGoal = (this._taskState.originalGoal || this._taskState.goal || "").trim();
|
|
581098
581320
|
if (!originalGoal)
|
|
581099
581321
|
return { proceed: true };
|
|
581322
|
+
if (/^\s*(BLOCKED|INCOMPLETE|NEEDS_INPUT)\b\s*:?/i.test(proposedSummary)) {
|
|
581323
|
+
return { proceed: true };
|
|
581324
|
+
}
|
|
581100
581325
|
const actionable = toolCallLog.some((e2) => e2.mutated || e2.name === "shell" || e2.name === "file_write" || e2.name === "file_edit");
|
|
581101
581326
|
if (!actionable)
|
|
581102
581327
|
return { proceed: true };
|
|
@@ -581319,6 +581544,9 @@ ${outTail || "(no output captured)"}`,
|
|
|
581319
581544
|
const _verify = await this._runCompletionVerifyGate(turn);
|
|
581320
581545
|
if (!_verify.proceed)
|
|
581321
581546
|
return _verify;
|
|
581547
|
+
if (this.options.backwardPassReview === false || this.options.disableAdversaryCritic === true) {
|
|
581548
|
+
return { proceed: true };
|
|
581549
|
+
}
|
|
581322
581550
|
const _resolution = await this._runResolutionGate(turn, proposedSummary, toolCallLog);
|
|
581323
581551
|
if (!_resolution.proceed) {
|
|
581324
581552
|
return {
|
|
@@ -581662,14 +581890,18 @@ ${_checks}`
|
|
|
581662
581890
|
const parts = [];
|
|
581663
581891
|
const todos = this.readSessionTodos();
|
|
581664
581892
|
if (todos && todos.length > 0) {
|
|
581665
|
-
const
|
|
581666
|
-
const
|
|
581893
|
+
const index = this._todoTreeIndex(todos);
|
|
581894
|
+
const leaves = this._todoLeaves(todos, index);
|
|
581895
|
+
const current = this._activeTodoForPrompt(todos, index);
|
|
581896
|
+
const completedN = leaves.filter((t2) => t2.status === "completed").length;
|
|
581897
|
+
const totalN = leaves.length;
|
|
581667
581898
|
if (current) {
|
|
581668
|
-
|
|
581899
|
+
const path12 = this._todoPath(current, index).map((todo) => todo.content.slice(0, 64)).join(" > ");
|
|
581900
|
+
parts.push(`[plan: ${completedN}/${totalN} leaf tasks complete · active: ${path12.slice(0, 160)}]`);
|
|
581669
581901
|
} else {
|
|
581670
|
-
const nextPending =
|
|
581902
|
+
const nextPending = leaves.find((t2) => t2.status === "pending");
|
|
581671
581903
|
if (nextPending) {
|
|
581672
|
-
parts.push(`[plan: ${completedN}/${
|
|
581904
|
+
parts.push(`[plan: ${completedN}/${totalN} leaf tasks complete · next: ${nextPending.content.slice(0, 80)}]`);
|
|
581673
581905
|
}
|
|
581674
581906
|
}
|
|
581675
581907
|
}
|
|
@@ -582641,36 +582873,73 @@ ${latest.output || ""}`.trim();
|
|
|
582641
582873
|
*/
|
|
582642
582874
|
_renderTodoStateBlock(turn) {
|
|
582643
582875
|
try {
|
|
582644
|
-
const todos = this.readSessionTodos();
|
|
582876
|
+
const todos = this._normalizeTodosForPrompt(this.readSessionTodos() ?? []);
|
|
582645
582877
|
if (!todos || todos.length === 0)
|
|
582646
582878
|
return null;
|
|
582879
|
+
const index = this._todoTreeIndex(todos);
|
|
582880
|
+
const leaves = this._todoLeaves(todos, index);
|
|
582881
|
+
const completedLeaves = leaves.filter((t2) => t2.status === "completed");
|
|
582882
|
+
const active = this._activeTodoForPrompt(todos, index);
|
|
582883
|
+
const activePath = active ? this._todoPath(active, index).map((todo) => todo.content.slice(0, 80)).join(" > ") : "";
|
|
582647
582884
|
const lines = [
|
|
582648
|
-
"[CURRENT TODO PLAN — already in your state, no need to call todo_write to see it]"
|
|
582885
|
+
"[CURRENT TODO PLAN — already in your state, no need to call todo_write to see it]",
|
|
582886
|
+
`leaf_progress=${completedLeaves.length}/${leaves.length}`
|
|
582649
582887
|
];
|
|
582650
|
-
|
|
582651
|
-
|
|
582652
|
-
const
|
|
582653
|
-
const
|
|
582654
|
-
|
|
582655
|
-
|
|
582656
|
-
|
|
582657
|
-
|
|
582658
|
-
|
|
582659
|
-
|
|
582660
|
-
|
|
582661
|
-
|
|
582662
|
-
|
|
582663
|
-
|
|
582664
|
-
|
|
582888
|
+
if (activePath)
|
|
582889
|
+
lines.push(`active_branch=${activePath.slice(0, 220)}`);
|
|
582890
|
+
const ordered = this._orderedTodosForPrompt(todos);
|
|
582891
|
+
const activeIndex = active ? ordered.findIndex((entry) => entry.todo.id === active.id) : -1;
|
|
582892
|
+
let visible = ordered;
|
|
582893
|
+
if (ordered.length > 14) {
|
|
582894
|
+
const selected = [];
|
|
582895
|
+
const seen = /* @__PURE__ */ new Set();
|
|
582896
|
+
const add3 = (entry) => {
|
|
582897
|
+
if (!entry || selected.length >= 13 || seen.has(entry.todo.id))
|
|
582898
|
+
return;
|
|
582899
|
+
selected.push(entry);
|
|
582900
|
+
seen.add(entry.todo.id);
|
|
582901
|
+
};
|
|
582902
|
+
if (active && activeIndex >= 0) {
|
|
582903
|
+
const pathIds = new Set(this._todoPath(active, index).map((t2) => t2.id));
|
|
582904
|
+
for (const entry of ordered) {
|
|
582905
|
+
if (pathIds.has(entry.todo.id) && entry.todo.id !== active.id)
|
|
582906
|
+
add3(entry);
|
|
582907
|
+
}
|
|
582908
|
+
const siblings = active.parentId ? index.byParent.get(active.parentId) ?? [] : index.roots;
|
|
582909
|
+
const siblingIndex = siblings.findIndex((t2) => t2.id === active.id);
|
|
582910
|
+
if (siblingIndex > 0) {
|
|
582911
|
+
add3(ordered.find((entry) => entry.todo.id === siblings[siblingIndex - 1]?.id));
|
|
582912
|
+
}
|
|
582913
|
+
add3(ordered[activeIndex]);
|
|
582914
|
+
for (let i2 = siblingIndex + 1; i2 < siblings.length && selected.length < 13; i2++) {
|
|
582915
|
+
add3(ordered.find((entry) => entry.todo.id === siblings[i2]?.id));
|
|
582916
|
+
}
|
|
582917
|
+
for (const child of index.byParent.get(active.id) ?? []) {
|
|
582918
|
+
add3(ordered.find((entry) => entry.todo.id === child.id));
|
|
582919
|
+
}
|
|
582920
|
+
for (let i2 = activeIndex + 1; i2 < ordered.length && selected.length < 13; i2++) {
|
|
582921
|
+
add3(ordered[i2]);
|
|
582922
|
+
}
|
|
582923
|
+
}
|
|
582924
|
+
visible = selected.length > 0 ? selected : ordered.slice(0, 13);
|
|
582665
582925
|
}
|
|
582666
|
-
|
|
582667
|
-
|
|
582668
|
-
|
|
582669
|
-
|
|
582926
|
+
const statusMark = {
|
|
582927
|
+
completed: "OK",
|
|
582928
|
+
in_progress: ">>",
|
|
582929
|
+
pending: "--",
|
|
582930
|
+
blocked: "!!"
|
|
582931
|
+
};
|
|
582932
|
+
lines.push("tree:");
|
|
582933
|
+
for (const entry of visible) {
|
|
582934
|
+
const indent2 = " ".repeat(entry.depth);
|
|
582935
|
+
const childSuffix = entry.childStats && entry.childStats.total > 0 ? ` [${entry.childStats.completed}/${entry.childStats.total}]` : "";
|
|
582936
|
+
const blocker = entry.todo.blocker ? ` blocker=${entry.todo.blocker.slice(0, 120)}` : "";
|
|
582937
|
+
lines.push(`${indent2}${statusMark[entry.displayStatus]} ${entry.todo.content.slice(0, 140)}${childSuffix}${blocker}`);
|
|
582670
582938
|
}
|
|
582671
|
-
if (
|
|
582672
|
-
lines.push(
|
|
582939
|
+
if (ordered.length > visible.length) {
|
|
582940
|
+
lines.push(`... +${ordered.length - visible.length} more todo node(s)`);
|
|
582673
582941
|
}
|
|
582942
|
+
lines.push("decomposition_contract=Use stable ids plus parentId for subtasks. If the active item has multiple remaining actions, rewrite it as a parent with concrete child leaf todos; work leaf-first and do not complete a parent before all children are complete with evidence.");
|
|
582674
582943
|
lines.push(`(turn ${turn} — call todo_write ONLY to update state, never to re-read this plan)`);
|
|
582675
582944
|
return lines.join("\n");
|
|
582676
582945
|
} catch {
|
|
@@ -583217,6 +583486,7 @@ ${chunk.content}`, {
|
|
|
583217
583486
|
this._taskState.goal ? `Active task: (see user message above — the goal block defers to the user message as the authoritative source)` : null
|
|
583218
583487
|
].filter(Boolean).join("\n\n");
|
|
583219
583488
|
const filesystemBlock = this._renderFilesystemStateBlock(turn);
|
|
583489
|
+
const artifactContractBlock = this._contractRegistry.format(15);
|
|
583220
583490
|
const todoBlock = this._renderTodoStateBlock(turn);
|
|
583221
583491
|
const failureBlock = this._renderRecentFailuresBlock(turn);
|
|
583222
583492
|
const churnBlock = this._renderWriteChurnBlock(turn);
|
|
@@ -583259,6 +583529,13 @@ ${this._lastPprMemoryLines.slice(0, 5).join("\n")}` : null;
|
|
|
583259
583529
|
createdTurn: turn,
|
|
583260
583530
|
ttlTurns: 1
|
|
583261
583531
|
}),
|
|
583532
|
+
signalFromBlock("known_files", "turn.artifact-contracts", artifactContractBlock, {
|
|
583533
|
+
id: "artifact-contracts",
|
|
583534
|
+
dedupeKey: "turn.artifact-contracts",
|
|
583535
|
+
priority: 86,
|
|
583536
|
+
createdTurn: turn,
|
|
583537
|
+
ttlTurns: 1
|
|
583538
|
+
}),
|
|
583262
583539
|
signalFromBlock("action_contract", "turn.next-action-contract", actionContractBlock, {
|
|
583263
583540
|
id: "next-action-contract",
|
|
583264
583541
|
dedupeKey: "turn.next-action-contract",
|
|
@@ -584588,7 +584865,6 @@ Respond with your assessment, then take action.`;
|
|
|
584588
584865
|
const hardDeadlineMs = Number.isFinite(taskTimeoutMs) && taskTimeoutMs > 0 ? start2 + taskTimeoutMs : Number.POSITIVE_INFINITY;
|
|
584589
584866
|
let timedOut = false;
|
|
584590
584867
|
let timeoutSummary = "";
|
|
584591
|
-
let _timeoutAdvisoryInjected = false;
|
|
584592
584868
|
const remainingTaskMs = () => Number.isFinite(hardDeadlineMs) ? Math.max(0, hardDeadlineMs - Date.now()) : Number.POSITIVE_INFINITY;
|
|
584593
584869
|
const boundedRequestTimeoutMs = () => {
|
|
584594
584870
|
const configured = Number.isFinite(this.options.requestTimeoutMs) && this.options.requestTimeoutMs > 0 ? this.options.requestTimeoutMs : 3e5;
|
|
@@ -584618,7 +584894,8 @@ Respond with your assessment, then take action.`;
|
|
|
584618
584894
|
return false;
|
|
584619
584895
|
if (Date.now() < hardDeadlineMs)
|
|
584620
584896
|
return false;
|
|
584621
|
-
|
|
584897
|
+
markTaskTimedOut(phase, turn);
|
|
584898
|
+
return true;
|
|
584622
584899
|
};
|
|
584623
584900
|
const selfEvalInterval = taskTimeoutMs;
|
|
584624
584901
|
let nextSelfEval = start2 + selfEvalInterval;
|
|
@@ -586647,12 +586924,13 @@ ${_staleSamples.join("\n")}` : ``,
|
|
|
586647
586924
|
content: `[TASK DECOMPOSITION — Multi-step task detected]
|
|
586648
586925
|
|
|
586649
586926
|
MANDATORY FIRST ACTION: Call todo_write NOW with the complete plan.
|
|
586650
|
-
Each todo item is { content
|
|
586651
|
-
|
|
586927
|
+
Each todo item is { id, content, status, parentId? } or a parent with children/subtasks. Use stable ids.
|
|
586928
|
+
Represent broad objectives as parent todos and concrete work as child leaf todos. Mark the active leaf in_progress, the rest pending.
|
|
586652
586929
|
Only count substantive work phases. Do NOT count observing a tool result, reporting findings, or calling task_complete as todo phases.
|
|
586653
|
-
Example: todo_write({todos: [{content: "
|
|
586930
|
+
Example: todo_write({todos: [{id: "impl", content: "Implement requested change", status: "in_progress", children: [{id: "inspect", content: "Read relevant files", status: "in_progress"}, {id: "edit", content: "Make scoped edits", status: "pending"}, {id: "verify", content: "Run verification", status: "pending"}]}]})
|
|
586654
586931
|
|
|
586655
|
-
After EACH
|
|
586932
|
+
After EACH leaf finishes, call todo_write AGAIN with that leaf completed and the next leaf in_progress.
|
|
586933
|
+
If new work is discovered, decompose the current leaf into children or add siblings under the same parent instead of flattening a long list.
|
|
586656
586934
|
The user watches this checklist update live in the chat UI. Without it they cannot see your plan or track progress.
|
|
586657
586935
|
|
|
586658
586936
|
Then complete these phases IN ORDER:
|
|
@@ -586971,10 +587249,6 @@ ${memoryLines.join("\n")}`
|
|
|
586971
587249
|
this.proactivePrune(compacted, turn);
|
|
586972
587250
|
this.microcompact(compacted, recentToolResults);
|
|
586973
587251
|
this._insertContextFrame(compacted, await this._buildTurnContextFrame(turn, compacted, recentToolResults, environmentBlock));
|
|
586974
|
-
const contractBlock = this._contractRegistry.format(15);
|
|
586975
|
-
if (contractBlock) {
|
|
586976
|
-
compacted.push({ role: "system", content: contractBlock });
|
|
586977
|
-
}
|
|
586978
587252
|
this.gcSystemMessages(compacted);
|
|
586979
587253
|
let requestMessages = sanitizeHistoryThink(compacted);
|
|
586980
587254
|
{
|
|
@@ -588639,7 +588913,7 @@ Respond with EXACTLY this structure before your next tool call:
|
|
|
588639
588913
|
} else if (tc.name === "shell") {
|
|
588640
588914
|
const cmd = String(tc.arguments?.["command"] ?? "");
|
|
588641
588915
|
if (/\b(npm|pnpm|yarn)\s+test\b|\bjest\b|\bvitest\b/i.test(cmd)) {
|
|
588642
|
-
const passed =
|
|
588916
|
+
const passed = /\b(PASS|pass|passed|success|ok)\b|✓\s*all/i.test(result.output) && !/FAIL|✗/i.test(result.output);
|
|
588643
588917
|
this._worldFacts.lastTest = {
|
|
588644
588918
|
passed,
|
|
588645
588919
|
summary: result.output.slice(0, 200),
|
|
@@ -589106,7 +589380,8 @@ Respond with EXACTLY this structure before your next tool call:
|
|
|
589106
589380
|
const _shellCmd2 = String(tc.arguments?.["command"] ?? tc.arguments?.["cmd"] ?? "");
|
|
589107
589381
|
const _declaredVerify = this._matchedDeclaredVerifyCommand(_shellCmd2);
|
|
589108
589382
|
const _lastVerifier = this._lastVerifierResult;
|
|
589109
|
-
const
|
|
589383
|
+
const _directShellValidation = result.success === true && this._shellResultLooksLikeVerification(tc.arguments, result);
|
|
589384
|
+
const _noTodoDirectValidation = !_declaredVerify && (this.readSessionTodos() || []).length === 0 && this._taskState.modifiedFiles.size > 0 && (_lastVerifier?.outcomeClass === "verified" || _directShellValidation);
|
|
589110
589385
|
const _legacyGenericValidation = process.env["OMNIUS_ENABLE_GENERIC_COMPLETION_COMMAND_HEURISTIC"] === "1" && /\b(build|test|run\b|start\b|serve\b|verify|check)\b/i.test(_shellCmd2);
|
|
589111
589386
|
if (_declaredVerify || _noTodoDirectValidation || _legacyGenericValidation) {
|
|
589112
589387
|
this._lastBuildSuccessTurn = turn;
|
|
@@ -589281,7 +589556,7 @@ Respond with EXACTLY this structure before your next tool call:
|
|
|
589281
589556
|
}
|
|
589282
589557
|
const cacheableMemoryNoop = tc.name === "memory_write" && result.success && result.noop;
|
|
589283
589558
|
const cacheableProjectWriteNoop = this._isProjectEditTool(tc.name) && result.success && !this._isRealProjectMutation(tc.name, result) && (result.noop === true || result.mutated === false);
|
|
589284
|
-
if (isReadLike && result.success || tc.name === "shell" || cacheableMemoryNoop || cacheableProjectWriteNoop) {
|
|
589559
|
+
if (isReadLike && result.success && result.runtimeAuthored !== true || tc.name === "shell" && result.runtimeAuthored !== true || cacheableMemoryNoop || cacheableProjectWriteNoop) {
|
|
589285
589560
|
recentToolResults.set(toolFingerprint, {
|
|
589286
589561
|
result: tc.name === "shell" ? this._buildShellCacheResult(tc.arguments, result) : (
|
|
589287
589562
|
// Read-like results are SERVED BACK to the model when the
|
|
@@ -589400,7 +589675,7 @@ Respond with EXACTLY this structure before your next tool call:
|
|
|
589400
589675
|
}
|
|
589401
589676
|
}
|
|
589402
589677
|
}
|
|
589403
|
-
if (!result.success) {
|
|
589678
|
+
if (!result.success && result.runtimeAuthored !== true) {
|
|
589404
589679
|
this._recentFailures.push({
|
|
589405
589680
|
tool: tc.name,
|
|
589406
589681
|
fingerprint: toolFingerprint,
|
|
@@ -589638,7 +589913,7 @@ ${bookkeepingGuidance}` : bookkeepingGuidance;
|
|
|
589638
589913
|
argsPreview: toolArgsPreview,
|
|
589639
589914
|
targetPaths: toolTargetPaths,
|
|
589640
589915
|
family: result.completionEvidenceFamily ?? (result.runtimeAuthored === true ? "runtime_control" : void 0),
|
|
589641
|
-
role: result.completionEvidenceRole ?? (realFileMutation || shellFilesystemMutation ? "mutation" : result.runtimeAuthored === true ? "blocker" : void 0),
|
|
589916
|
+
role: result.completionEvidenceRole ?? (result.alreadyApplied === true ? "mutation" : realFileMutation || shellFilesystemMutation ? "mutation" : result.runtimeAuthored === true ? "blocker" : void 0),
|
|
589642
589917
|
turn
|
|
589643
589918
|
});
|
|
589644
589919
|
if (this._toolEvents.length > 200)
|
|
@@ -589787,6 +590062,7 @@ Evidence: ${evidencePreview}`.slice(0, 500);
|
|
|
589787
590062
|
mutated: realFileMutation || shellFilesystemMutation,
|
|
589788
590063
|
isReadLike,
|
|
589789
590064
|
noop: tc.name === "todo_write" ? this._isTodoWriteNoopResult(result) : result.noop,
|
|
590065
|
+
alreadyApplied: result.alreadyApplied === true,
|
|
589790
590066
|
runtimeAuthored: result.runtimeAuthored === true
|
|
589791
590067
|
});
|
|
589792
590068
|
const focusSnapshotAfter = this._focusSupervisor?.snapshot();
|
|
@@ -590885,10 +591161,6 @@ ${this.options.maxTurns && this.options.maxTurns > 0 ? `You have ${this.options.
|
|
|
590885
591161
|
}
|
|
590886
591162
|
}
|
|
590887
591163
|
this._insertContextFrame(compactedMsgs, await this._buildTurnContextFrame(turn, compactedMsgs, void 0, bfEnvironmentBlock));
|
|
590888
|
-
const bfContractBlock = this._contractRegistry.format(15);
|
|
590889
|
-
if (bfContractBlock) {
|
|
590890
|
-
compactedMsgs.push({ role: "system", content: bfContractBlock });
|
|
590891
|
-
}
|
|
590892
591164
|
this.gcSystemMessages(compactedMsgs);
|
|
590893
591165
|
const modelFacingMessages = sanitizeHistoryThink(compactedMsgs);
|
|
590894
591166
|
const chatRequest = {
|
|
@@ -591431,7 +591703,7 @@ ${this._completionCaveat}` : this._completionCaveat;
|
|
|
591431
591703
|
if (this._completionLedger) {
|
|
591432
591704
|
this._completionLedger = finalizeCompletionLedgerTruth(this._completionLedger);
|
|
591433
591705
|
this._saveCompletionLedgerSafe();
|
|
591434
|
-
if (completed && this._completionLedger.status === "incomplete_verification") {
|
|
591706
|
+
if (completed && this._completionLedger.status === "incomplete_verification" && this.options.backwardPassReview !== false && !this._completionCaveat) {
|
|
591435
591707
|
completed = false;
|
|
591436
591708
|
const unresolvedSummary = this._completionLedger.unresolved.slice(-3).map((item) => item.text).join("; ");
|
|
591437
591709
|
const caveat = unresolvedSummary ? `Incomplete verification: ${unresolvedSummary}` : "Incomplete verification: unresolved evidence remains in the completion ledger.";
|
|
@@ -592093,33 +592365,49 @@ ${caveat}` : caveat;
|
|
|
592093
592365
|
this._saveWorkboard();
|
|
592094
592366
|
await this._hookManager.runSessionHook("session_end", this._sessionId);
|
|
592095
592367
|
try {
|
|
592096
|
-
const
|
|
592097
|
-
|
|
592098
|
-
|
|
592099
|
-
|
|
592100
|
-
|
|
592101
|
-
|
|
592102
|
-
|
|
592103
|
-
|
|
592104
|
-
|
|
592105
|
-
|
|
592106
|
-
|
|
592107
|
-
|
|
592108
|
-
|
|
592109
|
-
|
|
592110
|
-
|
|
592111
|
-
|
|
592112
|
-
|
|
592113
|
-
|
|
592114
|
-
|
|
592115
|
-
|
|
592116
|
-
|
|
592117
|
-
|
|
592118
|
-
|
|
592119
|
-
|
|
592120
|
-
|
|
592121
|
-
|
|
592122
|
-
|
|
592368
|
+
const trajectoryQuality = assessTaskArtifactQuality({
|
|
592369
|
+
artifactMode: this.options.artifactMode,
|
|
592370
|
+
goal: persistentTaskGoal,
|
|
592371
|
+
summary,
|
|
592372
|
+
toolsUsed: toolCallLog.map((tc) => tc.name),
|
|
592373
|
+
filesTouched: [...this._taskState.modifiedFiles.keys()],
|
|
592374
|
+
turns: messages2.filter((m2) => m2.role === "assistant").length
|
|
592375
|
+
});
|
|
592376
|
+
if (!trajectoryQuality.eligible) {
|
|
592377
|
+
this.emit({
|
|
592378
|
+
type: "status",
|
|
592379
|
+
content: `Trajectory log skipped: ${trajectoryQuality.reason ?? "not eligible"}`,
|
|
592380
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
592381
|
+
});
|
|
592382
|
+
} else {
|
|
592383
|
+
const fs11 = await import("node:fs");
|
|
592384
|
+
const path12 = await import("node:path");
|
|
592385
|
+
const trajDir = path12.join(this.omniusStateDir(), "trajectories");
|
|
592386
|
+
fs11.mkdirSync(trajDir, { recursive: true });
|
|
592387
|
+
const trajectory = {
|
|
592388
|
+
id: this._sessionId,
|
|
592389
|
+
// CLEAN task — this file is the prerequisite for ALL future RL/RFT
|
|
592390
|
+
// training. Storing the scaffolded version would teach future models
|
|
592391
|
+
// to reproduce signpost text as part of their task understanding.
|
|
592392
|
+
task: persistentTaskGoal.slice(0, 1e3),
|
|
592393
|
+
outcome: completed ? "pass" : this.aborted ? "aborted" : runStatus === "incomplete_verification" ? "incomplete_verification" : "timeout",
|
|
592394
|
+
model: this.backend.model ?? "unknown",
|
|
592395
|
+
modelTier: this.options.modelTier ?? "large",
|
|
592396
|
+
turns: messages2.filter((m2) => m2.role === "assistant").length,
|
|
592397
|
+
toolCalls: toolCallLog.map((tc) => ({
|
|
592398
|
+
name: tc.name,
|
|
592399
|
+
argsFingerprint: tc.argsKey.slice(0, 100)
|
|
592400
|
+
})),
|
|
592401
|
+
totalToolCalls: toolCallCount,
|
|
592402
|
+
totalTokens,
|
|
592403
|
+
filesModified: [...this._taskState.modifiedFiles.keys()],
|
|
592404
|
+
failedApproaches: this._taskState.failedApproaches,
|
|
592405
|
+
completedSteps: this._taskState.completedSteps,
|
|
592406
|
+
durationMs,
|
|
592407
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
592408
|
+
};
|
|
592409
|
+
fs11.appendFileSync(path12.join(trajDir, `trajectories.jsonl`), JSON.stringify(trajectory) + "\n", "utf-8");
|
|
592410
|
+
}
|
|
592123
592411
|
} catch {
|
|
592124
592412
|
}
|
|
592125
592413
|
let filesEdited;
|
|
@@ -592615,7 +592903,7 @@ ${marker}` : marker);
|
|
|
592615
592903
|
if (!target)
|
|
592616
592904
|
return;
|
|
592617
592905
|
const targetPathKey = this.staleEditPathKey(target.path);
|
|
592618
|
-
if (this._isRealProjectMutation(toolName, result)) {
|
|
592906
|
+
if (this._isRealProjectMutation(toolName, result) || result.alreadyApplied === true) {
|
|
592619
592907
|
for (const [key2, entry] of this._staleEditFamilies) {
|
|
592620
592908
|
if (entry.pathKey === targetPathKey)
|
|
592621
592909
|
this._staleEditFamilies.delete(key2);
|
|
@@ -629489,6 +629777,8 @@ var init_overlay_lock = __esm({
|
|
|
629489
629777
|
// packages/cli/src/tui/tui-tasks-renderer.ts
|
|
629490
629778
|
var tui_tasks_renderer_exports = {};
|
|
629491
629779
|
__export(tui_tasks_renderer_exports, {
|
|
629780
|
+
__testOrderTodosForDisplay: () => __testOrderTodosForDisplay,
|
|
629781
|
+
__testSelectPanelTodoRows: () => __testSelectPanelTodoRows,
|
|
629492
629782
|
getTuiTasksScope: () => getTuiTasksScope,
|
|
629493
629783
|
onTuiTasksHeightChange: () => onTuiTasksHeightChange,
|
|
629494
629784
|
refreshTuiTasks: () => refreshTuiTasks,
|
|
@@ -629646,7 +629936,7 @@ function computeTargetHeight() {
|
|
|
629646
629936
|
if (!_lastTodos || _lastTodos.length === 0) return 0;
|
|
629647
629937
|
const allDone = _lastTodos.every((t2) => t2 && t2.status === "completed");
|
|
629648
629938
|
if (allDone) return 0;
|
|
629649
|
-
const itemRows =
|
|
629939
|
+
const itemRows = selectPanelTodoRows(_lastTodos, MAX_VISIBLE_ROWS - 1).rowCount;
|
|
629650
629940
|
return 1 + itemRows;
|
|
629651
629941
|
}
|
|
629652
629942
|
function applyHeightChange(nextHeight) {
|
|
@@ -629724,9 +630014,9 @@ function buildTodoProgressBar(todos, maxWidth) {
|
|
|
629724
630014
|
if (truncated && maxWidth > 0) out += `${DIM_LABEL}…${RESET3}`;
|
|
629725
630015
|
return out;
|
|
629726
630016
|
}
|
|
629727
|
-
function
|
|
630017
|
+
function buildTodoTreeIndex(todos) {
|
|
629728
630018
|
const byParent = /* @__PURE__ */ new Map();
|
|
629729
|
-
const byId = new
|
|
630019
|
+
const byId = new Map(todos.map((t2) => [t2.id, t2]));
|
|
629730
630020
|
const roots = [];
|
|
629731
630021
|
for (const todo of todos) {
|
|
629732
630022
|
if (todo.parentId && byId.has(todo.parentId)) {
|
|
@@ -629737,20 +630027,146 @@ function orderTodosForDisplay(todos) {
|
|
|
629737
630027
|
roots.push(todo);
|
|
629738
630028
|
}
|
|
629739
630029
|
}
|
|
630030
|
+
return { byId, byParent, roots };
|
|
630031
|
+
}
|
|
630032
|
+
function childLeafStats(todo, index) {
|
|
630033
|
+
const children2 = index.byParent.get(todo.id) ?? [];
|
|
630034
|
+
if (children2.length === 0) return void 0;
|
|
630035
|
+
let completed = 0;
|
|
630036
|
+
let total = 0;
|
|
630037
|
+
const seen = /* @__PURE__ */ new Set();
|
|
630038
|
+
const visit = (node) => {
|
|
630039
|
+
if (seen.has(node.id)) return;
|
|
630040
|
+
seen.add(node.id);
|
|
630041
|
+
const nested = index.byParent.get(node.id) ?? [];
|
|
630042
|
+
if (nested.length === 0) {
|
|
630043
|
+
total++;
|
|
630044
|
+
if (node.status === "completed") completed++;
|
|
630045
|
+
return;
|
|
630046
|
+
}
|
|
630047
|
+
for (const child of nested) visit(child);
|
|
630048
|
+
};
|
|
630049
|
+
for (const child of children2) visit(child);
|
|
630050
|
+
return { completed, total };
|
|
630051
|
+
}
|
|
630052
|
+
function displayStatusFor(todo, index, seen = /* @__PURE__ */ new Set()) {
|
|
630053
|
+
if (seen.has(todo.id)) return todo.status;
|
|
630054
|
+
seen.add(todo.id);
|
|
630055
|
+
const children2 = index.byParent.get(todo.id) ?? [];
|
|
630056
|
+
if (children2.length === 0) return todo.status;
|
|
630057
|
+
const childStatuses = children2.map((child) => displayStatusFor(child, index, new Set(seen)));
|
|
630058
|
+
if (childStatuses.some((status) => status === "blocked")) return "blocked";
|
|
630059
|
+
if (childStatuses.some((status) => status === "in_progress")) return "in_progress";
|
|
630060
|
+
if (childStatuses.every((status) => status === "completed")) return "completed";
|
|
630061
|
+
if (todo.status === "completed") return "in_progress";
|
|
630062
|
+
return todo.status;
|
|
630063
|
+
}
|
|
630064
|
+
function toDisplayTodo(todo, depth, index) {
|
|
630065
|
+
return {
|
|
630066
|
+
...todo,
|
|
630067
|
+
depth: Math.min(depth, 4),
|
|
630068
|
+
displayStatus: displayStatusFor(todo, index),
|
|
630069
|
+
childSummary: childLeafStats(todo, index)
|
|
630070
|
+
};
|
|
630071
|
+
}
|
|
630072
|
+
function orderTodosForDisplay(todos) {
|
|
630073
|
+
const index = buildTodoTreeIndex(todos);
|
|
629740
630074
|
const out = [];
|
|
629741
630075
|
const seen = /* @__PURE__ */ new Set();
|
|
629742
630076
|
const visit = (todo, depth) => {
|
|
629743
630077
|
if (seen.has(todo.id)) return;
|
|
629744
630078
|
seen.add(todo.id);
|
|
629745
|
-
out.push(
|
|
629746
|
-
for (const child of byParent.get(todo.id) ?? []) {
|
|
630079
|
+
out.push(toDisplayTodo(todo, depth, index));
|
|
630080
|
+
for (const child of index.byParent.get(todo.id) ?? []) {
|
|
629747
630081
|
visit(child, depth + 1);
|
|
629748
630082
|
}
|
|
629749
630083
|
};
|
|
629750
|
-
for (const root of roots) visit(root, 0);
|
|
630084
|
+
for (const root of index.roots) visit(root, 0);
|
|
629751
630085
|
for (const todo of todos) visit(todo, 0);
|
|
629752
630086
|
return out;
|
|
629753
630087
|
}
|
|
630088
|
+
function leafTodosForProgress(todos) {
|
|
630089
|
+
const index = buildTodoTreeIndex(todos);
|
|
630090
|
+
const leaves = todos.filter((todo) => (index.byParent.get(todo.id) ?? []).length === 0);
|
|
630091
|
+
return leaves.length > 0 ? leaves : todos;
|
|
630092
|
+
}
|
|
630093
|
+
function activeDisplayIndex(displayTodos) {
|
|
630094
|
+
const inProgressLeaf = displayTodos.findIndex(
|
|
630095
|
+
(todo, index, all2) => todo.status === "in_progress" && !all2.some((candidate) => candidate.parentId === todo.id)
|
|
630096
|
+
);
|
|
630097
|
+
if (inProgressLeaf >= 0) return inProgressLeaf;
|
|
630098
|
+
const inProgress = displayTodos.findIndex((todo) => todo.displayStatus === "in_progress");
|
|
630099
|
+
if (inProgress >= 0) return inProgress;
|
|
630100
|
+
const blocked = displayTodos.findIndex((todo) => todo.displayStatus === "blocked");
|
|
630101
|
+
if (blocked >= 0) return blocked;
|
|
630102
|
+
return displayTodos.findIndex((todo) => todo.displayStatus === "pending");
|
|
630103
|
+
}
|
|
630104
|
+
function selectFocusedTodoItems(todos, maxItems) {
|
|
630105
|
+
const displayTodos = orderTodosForDisplay(todos);
|
|
630106
|
+
if (maxItems <= 0) return [];
|
|
630107
|
+
if (displayTodos.length <= maxItems) return displayTodos;
|
|
630108
|
+
const activeIndex = activeDisplayIndex(displayTodos);
|
|
630109
|
+
if (activeIndex < 0 || activeIndex < maxItems) return displayTodos.slice(0, maxItems);
|
|
630110
|
+
const rawIndex = buildTodoTreeIndex(todos);
|
|
630111
|
+
const displayById = new Map(displayTodos.map((todo) => [todo.id, todo]));
|
|
630112
|
+
const selected = [];
|
|
630113
|
+
const seen = /* @__PURE__ */ new Set();
|
|
630114
|
+
const add3 = (todo) => {
|
|
630115
|
+
if (!todo || selected.length >= maxItems || seen.has(todo.id)) return;
|
|
630116
|
+
selected.push(todo);
|
|
630117
|
+
seen.add(todo.id);
|
|
630118
|
+
};
|
|
630119
|
+
const active = displayTodos[activeIndex];
|
|
630120
|
+
const ancestors = [];
|
|
630121
|
+
let cursor = active;
|
|
630122
|
+
while (cursor?.parentId && rawIndex.byId.has(cursor.parentId)) {
|
|
630123
|
+
const parent = rawIndex.byId.get(cursor.parentId);
|
|
630124
|
+
if (!parent) break;
|
|
630125
|
+
const displayParent = displayById.get(parent.id);
|
|
630126
|
+
if (displayParent) ancestors.unshift(displayParent);
|
|
630127
|
+
cursor = parent;
|
|
630128
|
+
}
|
|
630129
|
+
for (const ancestor of ancestors) add3(ancestor);
|
|
630130
|
+
const siblings = active.parentId ? rawIndex.byParent.get(active.parentId) ?? [] : rawIndex.roots;
|
|
630131
|
+
const activeSiblingIndex = siblings.findIndex((todo) => todo.id === active.id);
|
|
630132
|
+
if (activeSiblingIndex > 0) add3(displayById.get(siblings[activeSiblingIndex - 1].id));
|
|
630133
|
+
add3(active);
|
|
630134
|
+
for (let i2 = activeSiblingIndex + 1; i2 < siblings.length && selected.length < maxItems; i2++) {
|
|
630135
|
+
add3(displayById.get(siblings[i2].id));
|
|
630136
|
+
}
|
|
630137
|
+
const activeChildren = rawIndex.byParent.get(active.id) ?? [];
|
|
630138
|
+
for (const child of activeChildren) add3(displayById.get(child.id));
|
|
630139
|
+
for (let i2 = activeIndex + 1; i2 < displayTodos.length && selected.length < maxItems; i2++) {
|
|
630140
|
+
add3(displayTodos[i2]);
|
|
630141
|
+
}
|
|
630142
|
+
for (let i2 = activeIndex - 1; i2 >= 0 && selected.length < maxItems; i2--) {
|
|
630143
|
+
add3(displayTodos[i2]);
|
|
630144
|
+
}
|
|
630145
|
+
return selected;
|
|
630146
|
+
}
|
|
630147
|
+
function selectPanelTodoRows(todos, maxRows) {
|
|
630148
|
+
const displayTodos = orderTodosForDisplay(todos);
|
|
630149
|
+
if (maxRows <= 0 || displayTodos.length === 0) {
|
|
630150
|
+
return { items: [], omitted: displayTodos.length, rowCount: 0 };
|
|
630151
|
+
}
|
|
630152
|
+
if (displayTodos.length <= maxRows) {
|
|
630153
|
+
return { items: displayTodos, omitted: 0, rowCount: displayTodos.length };
|
|
630154
|
+
}
|
|
630155
|
+
const itemBudget = Math.max(1, maxRows - 1);
|
|
630156
|
+
const items = selectFocusedTodoItems(todos, itemBudget);
|
|
630157
|
+
const omitted = Math.max(0, displayTodos.length - items.length);
|
|
630158
|
+
return {
|
|
630159
|
+
items,
|
|
630160
|
+
omitted,
|
|
630161
|
+
rowCount: Math.min(maxRows, items.length + (omitted > 0 ? 1 : 0))
|
|
630162
|
+
};
|
|
630163
|
+
}
|
|
630164
|
+
function __testOrderTodosForDisplay(todos) {
|
|
630165
|
+
return orderTodosForDisplay(todos);
|
|
630166
|
+
}
|
|
630167
|
+
function __testSelectPanelTodoRows(todos, maxRows) {
|
|
630168
|
+
return selectPanelTodoRows(todos, maxRows);
|
|
630169
|
+
}
|
|
629754
630170
|
function render() {
|
|
629755
630171
|
if (!_enabled) return;
|
|
629756
630172
|
if (!panelEffectivelyVisible()) {
|
|
@@ -629766,29 +630182,30 @@ function render() {
|
|
|
629766
630182
|
}
|
|
629767
630183
|
const L = layout();
|
|
629768
630184
|
const cols = Math.max(20, termCols());
|
|
629769
|
-
const
|
|
629770
|
-
const
|
|
630185
|
+
const progressTodos = leafTodosForProgress(_lastTodos);
|
|
630186
|
+
const completed = progressTodos.filter((t2) => t2.status === "completed").length;
|
|
630187
|
+
const total = progressTodos.length;
|
|
629771
630188
|
const headerColor = ACCENT;
|
|
629772
630189
|
const lines = [];
|
|
629773
630190
|
const headerPrefix = `tasks ${headerColor}${completed}/${total}${RESET3} `;
|
|
629774
630191
|
const headerPrefixWidth = visualLen(headerPrefix);
|
|
629775
630192
|
const maxBarWidth = Math.max(0, cols - 2 - headerPrefixWidth);
|
|
629776
|
-
const progressBar = buildTodoProgressBar(
|
|
630193
|
+
const progressBar = buildTodoProgressBar(progressTodos, maxBarWidth);
|
|
629777
630194
|
const headerText = `${headerPrefix}${progressBar}`;
|
|
629778
630195
|
lines.push(headerText);
|
|
629779
|
-
const
|
|
629780
|
-
const visible =
|
|
630196
|
+
const selection = selectPanelTodoRows(_lastTodos, MAX_VISIBLE_ROWS - 1);
|
|
630197
|
+
const visible = selection.items;
|
|
629781
630198
|
for (const t2 of visible) {
|
|
629782
|
-
const { mark, color } = statusToAnsi(t2.
|
|
630199
|
+
const { mark, color } = statusToAnsi(t2.displayStatus);
|
|
629783
630200
|
const contentWidth = Math.max(4, cols - 8);
|
|
629784
|
-
const indent2 = t2.depth > 0 ? `${" ".repeat(t2.depth
|
|
629785
|
-
const
|
|
630201
|
+
const indent2 = t2.depth > 0 ? `${" ".repeat(t2.depth)}- ` : "";
|
|
630202
|
+
const childSummary = t2.childSummary && t2.childSummary.total > 0 ? ` [${t2.childSummary.completed}/${t2.childSummary.total}]` : "";
|
|
630203
|
+
const contentText = indent2 + t2.content + childSummary + (t2.blocker ? ` (blocked: ${t2.blocker})` : "");
|
|
629786
630204
|
const truncated = truncate2(contentText, contentWidth);
|
|
629787
630205
|
lines.push(`${color}${mark}${RESET3} ${color}${truncated}${RESET3}`);
|
|
629788
630206
|
}
|
|
629789
|
-
if (
|
|
629790
|
-
|
|
629791
|
-
lines[lines.length - 1] = `${DIM_LABEL}… +${more} more${RESET3}`;
|
|
630207
|
+
if (selection.omitted > 0) {
|
|
630208
|
+
lines.push(`${DIM_LABEL}… +${selection.omitted} more${RESET3}`);
|
|
629792
630209
|
}
|
|
629793
630210
|
let out = HIDE + SAVE;
|
|
629794
630211
|
const newTop = L.tasksTop;
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "omnius",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.453",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "omnius",
|
|
9
|
-
"version": "1.0.
|
|
9
|
+
"version": "1.0.453",
|
|
10
10
|
"bundleDependencies": [
|
|
11
11
|
"image-to-ascii"
|
|
12
12
|
],
|
package/package.json
CHANGED