omnius 1.0.452 → 1.0.454

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 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 call shape: todo_write({"todos":[{"id":"p1","content":"Implement feature","status":"in_progress"},{"id":"c1","parentId":"p1","content":"Inspect files","status":"in_progress"},{"id":"c2","parentId":"p1","content":"Make changes","status":"pending"},{"id":"c3","parentId":"p1","content":"Verify results","status":"pending"}]})`;
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");
@@ -574296,6 +574333,10 @@ function updateGlobalIndex(paths, runIndex) {
574296
574333
  schemaVersion: 1,
574297
574334
  updatedAt: now2,
574298
574335
  root: paths.root,
574336
+ runCount: 0,
574337
+ latestRun: null,
574338
+ diagnoses: {},
574339
+ anchors: [],
574299
574340
  runs: []
574300
574341
  };
574301
574342
  next.updatedAt = now2;
@@ -574315,8 +574356,35 @@ function updateGlobalIndex(paths, runIndex) {
574315
574356
  entry,
574316
574357
  ...next.runs.filter((item) => item.runId !== runIndex.runId)
574317
574358
  ].slice(0, 100);
574359
+ next.runCount = next.runs.length;
574360
+ next.latestRun = {
574361
+ runId: runIndex.runId,
574362
+ sessionId: runIndex.sessionId,
574363
+ cwd: runIndex.cwd,
574364
+ updatedAt: runIndex.updatedAt,
574365
+ eventCount: runIndex.summary.eventCount,
574366
+ failureCount: runIndex.summary.failureCount,
574367
+ focusBlockCount: runIndex.summary.focusBlockCount,
574368
+ suspiciousShellCount: runIndex.summary.suspiciousShellCount,
574369
+ readmePath: runIndex.readmePath,
574370
+ indexPath: runIndex.indexPath
574371
+ };
574372
+ next.diagnoses = aggregateGlobalDiagnoses(next.runs);
574373
+ next.anchors = buildAnchors(runIndex.cwd, runIndex.runId, paths);
574318
574374
  writeFileSync49(paths.globalIndexPath, JSON.stringify(next, null, 2), "utf-8");
574319
574375
  }
574376
+ function aggregateGlobalDiagnoses(runs) {
574377
+ const totals = {};
574378
+ for (const run2 of runs) {
574379
+ const index = readJson2(run2.indexPath);
574380
+ if (!index?.diagnoses)
574381
+ continue;
574382
+ for (const [name10, count] of Object.entries(index.diagnoses)) {
574383
+ totals[name10] = (totals[name10] ?? 0) + count;
574384
+ }
574385
+ }
574386
+ return Object.fromEntries(Object.entries(totals).sort((a2, b) => b[1] - a2[1] || a2[0].localeCompare(b[0])));
574387
+ }
574320
574388
  function buildAnchors(cwd4, runId, paths, extra = []) {
574321
574389
  const omniusDir = join112(cwd4, ".omnius");
574322
574390
  const raw = [
@@ -574701,14 +574769,13 @@ function resolveFocusSupervisorMode(configured, envValue = process.env["OMNIUS_F
574701
574769
  function violatesDirective(directive, input) {
574702
574770
  if (input.toolName === "task_complete") {
574703
574771
  const completionStatus = normalizeCompletionStatus(input.completionStatus ?? input.args?.["status"] ?? input.args?.["completion_status"] ?? input.args?.["completionStatus"]);
574704
- const reportsDegradedCompletion = completionStatus === "blocked" || completionStatus === "incomplete" || completionStatus === "needs_input";
574705
- if (directive.requiredNextAction === "use_cached_evidence") {
574706
- return false;
574707
- }
574708
- if (reportsDegradedCompletion && (directive.requiredNextAction === "read_authoritative_target" || directive.requiredNextAction === "report_blocked" || directive.requiredNextAction === "report_incomplete")) {
574709
- return false;
574772
+ const summaryText = typeof input.args?.["summary"] === "string" ? input.args["summary"] : "";
574773
+ const summaryReportsDegraded = /^\s*(BLOCKED|INCOMPLETE|NEEDS[_ -]?INPUT)\b\s*:?/i.test(summaryText);
574774
+ const reportsDegradedCompletion = completionStatus === "blocked" || completionStatus === "incomplete" || completionStatus === "needs_input" || summaryReportsDegraded;
574775
+ if (directive.requiredNextAction === "report_blocked" || directive.requiredNextAction === "report_incomplete" || directive.state === "terminal_incomplete") {
574776
+ return !reportsDegradedCompletion;
574710
574777
  }
574711
- return directive.requiredNextAction !== "report_blocked" && directive.requiredNextAction !== "report_incomplete";
574778
+ return false;
574712
574779
  }
574713
574780
  if (input.toolName === "ask_user")
574714
574781
  return false;
@@ -574989,6 +575056,11 @@ var init_focusSupervisor = __esm({
574989
575056
  const family = actionFamily(input.toolName, input.args);
574990
575057
  const prior = this.directive;
574991
575058
  if (prior && violatesDirective(prior, input)) {
575059
+ if (prior.state === "warn") {
575060
+ this.lastDecision = "warn_not_enforced";
575061
+ this.lastReason = prior.reason;
575062
+ return this.pass();
575063
+ }
574992
575064
  const strict = this.shouldStrictlyIntervene(input.context);
574993
575065
  const sameTurnAsDirective = input.turn <= prior.createdTurn;
574994
575066
  const alreadyCountedThisTurn = this.lastIgnoredDirectiveTurn === input.turn;
@@ -575105,6 +575177,10 @@ var init_focusSupervisor = __esm({
575105
575177
  this.clearSatisfiedDirective("mutation landed", input.turn);
575106
575178
  return;
575107
575179
  }
575180
+ if (input.success && input.alreadyApplied) {
575181
+ this.clearSatisfiedDirective("requested edit already applied", input.turn);
575182
+ return;
575183
+ }
575108
575184
  if (input.runtimeAuthored) {
575109
575185
  this.lastDecision = "runtime_authored_not_satisfied";
575110
575186
  this.lastReason = "runtime-authored control result did not execute the requested tool";
@@ -577627,7 +577703,7 @@ function computeTodoReminder(input) {
577627
577703
  if (!input.todos || input.todos.length === 0) {
577628
577704
  if (input.elicitCreateOnEmptyTodos) {
577629
577705
  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 ordered steps, mark the first step 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.
577706
+ 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
577707
  </system-reminder>`;
577632
577708
  return { shouldInject: true, content: content2, reason: "elicit_create" };
577633
577709
  }
@@ -577647,9 +577723,9 @@ No todo plan exists yet. Consider using the todo_write tool to create a plan for
577647
577723
  return { shouldInject: false, content: null, reason: "recent_reminder" };
577648
577724
  }
577649
577725
  }
577650
- const todoItems = input.todos.slice(0, 12).map((t2, i2) => `${i2 + 1}. [${t2.status}] ${t2.content}`).join("\n");
577726
+ const todoItems = formatTodoReminderItems(input.todos, 12);
577651
577727
  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 it in_progress. When you complete a task, mark it completed immediately — don't batch completions. If the list is stale, clean it up. Make sure that you NEVER mention this reminder to the user.
577728
+ 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
577729
 
577654
577730
  Here are the existing contents of your todo list:
577655
577731
 
@@ -577657,6 +577733,40 @@ ${todoItems}
577657
577733
  </system-reminder>`;
577658
577734
  return { shouldInject: true, content, reason: "injected" };
577659
577735
  }
577736
+ function formatTodoReminderItems(todos, maxRows) {
577737
+ const byId = new Map(todos.filter((todo) => typeof todo.id === "string" && todo.id.trim().length > 0).map((todo) => [todo.id, todo]));
577738
+ const byParent = /* @__PURE__ */ new Map();
577739
+ const roots = [];
577740
+ for (const todo of todos) {
577741
+ if (todo.parentId && byId.has(todo.parentId)) {
577742
+ const siblings = byParent.get(todo.parentId) ?? [];
577743
+ siblings.push(todo);
577744
+ byParent.set(todo.parentId, siblings);
577745
+ } else {
577746
+ roots.push(todo);
577747
+ }
577748
+ }
577749
+ const rows = [];
577750
+ const seen = /* @__PURE__ */ new Set();
577751
+ const visit = (todo, depth) => {
577752
+ if (rows.length >= maxRows || seen.has(todo))
577753
+ return;
577754
+ seen.add(todo);
577755
+ const indent2 = " ".repeat(Math.min(depth, 4));
577756
+ rows.push(`${indent2}- [${todo.status}] ${todo.content}`);
577757
+ if (!todo.id)
577758
+ return;
577759
+ for (const child of byParent.get(todo.id) ?? [])
577760
+ visit(child, depth + 1);
577761
+ };
577762
+ for (const root of roots)
577763
+ visit(root, 0);
577764
+ for (const todo of todos)
577765
+ visit(todo, 0);
577766
+ if (todos.length > rows.length)
577767
+ rows.push(`... +${todos.length - rows.length} more`);
577768
+ return rows.join("\n");
577769
+ }
577660
577770
  function stripThinkBlocks(s2) {
577661
577771
  if (!s2)
577662
577772
  return s2;
@@ -577946,6 +578056,7 @@ var init_agenticRunner = __esm({
577946
578056
  init_context_compressor();
577947
578057
  init_reflectionBuffer();
577948
578058
  init_taskHandoff();
578059
+ init_artifactQuality();
577949
578060
  init_messageLog();
577950
578061
  init_contextTree();
577951
578062
  init_codeGraphLink();
@@ -578844,16 +578955,21 @@ ${parts.join("\n")}
578844
578955
  lines.push("implementation_state=mutation evidence is already recorded; do not treat discovery as the active phase");
578845
578956
  }
578846
578957
  }
578847
- const todos = this.readSessionTodos() ?? [];
578958
+ const todos = this._normalizeTodosForPrompt(this.readSessionTodos() ?? []);
578848
578959
  if (todos.length > 0) {
578849
- const inProgress = todos.filter((todo) => todo.status === "in_progress");
578850
- const pending2 = todos.filter((todo) => todo.status === "pending");
578851
- const blocked = todos.filter((todo) => todo.status === "blocked");
578852
- lines.push(`todo_counts=in_progress:${inProgress.length} pending:${pending2.length} blocked:${blocked.length}`);
578853
- if (inProgress[0]) {
578854
- lines.push(`todo_current=${inProgress[0].content.slice(0, 180)}`);
578960
+ const index = this._todoTreeIndex(todos);
578961
+ const leaves = this._todoLeaves(todos, index);
578962
+ const active = this._activeTodoForPrompt(todos, index);
578963
+ const inProgress = leaves.filter((todo) => todo.status === "in_progress");
578964
+ const pending2 = leaves.filter((todo) => todo.status === "pending");
578965
+ const blocked = leaves.filter((todo) => todo.status === "blocked");
578966
+ const completed = leaves.filter((todo) => todo.status === "completed");
578967
+ lines.push(`todo_leaf_counts=completed:${completed.length} in_progress:${inProgress.length} pending:${pending2.length} blocked:${blocked.length}`);
578968
+ if (active) {
578969
+ const branch = this._todoPath(active, index).map((todo) => todo.content.slice(0, 64)).join(" > ");
578970
+ lines.push(`todo_active_branch=${branch.slice(0, 220)}`);
578855
578971
  } else if (pending2.length > 0) {
578856
- lines.push("todo_contract=mark exactly one pending todo in_progress before using the checklist as progress");
578972
+ lines.push("todo_contract=mark one pending leaf todo in_progress before using the checklist as progress");
578857
578973
  }
578858
578974
  }
578859
578975
  if (lines.length === 2)
@@ -578863,7 +578979,7 @@ ${parts.join("\n")}
578863
578979
  }
578864
578980
  _workboardTargetCardId(snapshot, toolName, result, meta = {}) {
578865
578981
  const byId = new Map(snapshot.cards.map((card) => [card.id, card]));
578866
- if (this._isProjectEditTool(toolName) && this._isRealProjectMutation(toolName, result)) {
578982
+ if (this._isProjectEditTool(toolName) && (this._isRealProjectMutation(toolName, result) || result?.alreadyApplied === true)) {
578867
578983
  return byId.has("implement-repair") ? "implement-repair" : null;
578868
578984
  }
578869
578985
  if (toolName === "shell" && meta.shellFilesystemMutation === true) {
@@ -578889,9 +579005,9 @@ ${parts.join("\n")}
578889
579005
  const dir = this._workboardDir();
578890
579006
  let current = snapshot;
578891
579007
  const byId = () => new Map(current.cards.map((card) => [card.id, card]));
578892
- const editMutation = this._isProjectEditTool(toolName) && this._isRealProjectMutation(toolName, result) || toolName === "shell" && result?.success === true && meta.shellFilesystemMutation === true;
579008
+ const editEvidence = this._isProjectEditTool(toolName) && (this._isRealProjectMutation(toolName, result) || result?.alreadyApplied === true) || toolName === "shell" && result?.success === true && meta.shellFilesystemMutation === true;
578893
579009
  try {
578894
- if (editMutation) {
579010
+ if (editEvidence) {
578895
579011
  let cards = byId();
578896
579012
  const discovery = cards.get("discover-current-state");
578897
579013
  if (discovery && discovery.status !== "verified" && discovery.evidence.length > 0) {
@@ -578924,7 +579040,7 @@ ${parts.join("\n")}
578924
579040
  cardId: implementation2.id,
578925
579041
  actor,
578926
579042
  updates: { status: "in_progress", lane: "worker" },
578927
- decisionReason: "Real project mutation landed; implementation is now the active phase."
579043
+ 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
579044
  });
578929
579045
  }
578930
579046
  }
@@ -578961,7 +579077,7 @@ ${parts.join("\n")}
578961
579077
  return;
578962
579078
  if (meta.focusDecisionKind === "block_tool_call")
578963
579079
  return;
578964
- if (result?.success === true && this._isProjectEditTool(toolName) && !this._isRealProjectMutation(toolName, result)) {
579080
+ if (result?.success === true && this._isProjectEditTool(toolName) && !this._isRealProjectMutation(toolName, result) && result.alreadyApplied !== true) {
578965
579081
  return;
578966
579082
  }
578967
579083
  const dir = this._workboardDir();
@@ -580430,6 +580546,127 @@ Pick the SMALLEST concrete deliverable from the spec — typically the project e
580430
580546
  return null;
580431
580547
  }
580432
580548
  }
580549
+ _normalizeTodosForPrompt(todos) {
580550
+ return todos.map((todo, index) => {
580551
+ const rawId = todo.id;
580552
+ const id2 = typeof rawId === "string" && rawId.trim().length > 0 ? rawId.trim() : `prompt-${index}`;
580553
+ const rawParentId = todo.parentId;
580554
+ const parentId = typeof rawParentId === "string" && rawParentId.trim().length > 0 ? rawParentId.trim() : void 0;
580555
+ const createdAt = typeof todo.createdAt === "number" ? todo.createdAt : 0;
580556
+ const updatedAt = typeof todo.updatedAt === "number" ? todo.updatedAt : createdAt;
580557
+ return {
580558
+ ...todo,
580559
+ id: id2,
580560
+ ...parentId ? { parentId } : {},
580561
+ createdAt,
580562
+ updatedAt
580563
+ };
580564
+ });
580565
+ }
580566
+ _todoTreeIndex(todos) {
580567
+ const byId = new Map(todos.map((todo) => [todo.id, todo]));
580568
+ const byParent = /* @__PURE__ */ new Map();
580569
+ const roots = [];
580570
+ for (const todo of todos) {
580571
+ if (todo.parentId && byId.has(todo.parentId)) {
580572
+ const siblings = byParent.get(todo.parentId) ?? [];
580573
+ siblings.push(todo);
580574
+ byParent.set(todo.parentId, siblings);
580575
+ } else {
580576
+ roots.push(todo);
580577
+ }
580578
+ }
580579
+ return { byId, byParent, roots };
580580
+ }
580581
+ _todoDisplayStatus(todo, index, seen = /* @__PURE__ */ new Set()) {
580582
+ if (seen.has(todo.id))
580583
+ return todo.status;
580584
+ seen.add(todo.id);
580585
+ const children2 = index.byParent.get(todo.id) ?? [];
580586
+ if (children2.length === 0)
580587
+ return todo.status;
580588
+ const childStatuses = children2.map((child) => this._todoDisplayStatus(child, index, new Set(seen)));
580589
+ if (childStatuses.some((status) => status === "blocked"))
580590
+ return "blocked";
580591
+ if (childStatuses.some((status) => status === "in_progress"))
580592
+ return "in_progress";
580593
+ if (childStatuses.every((status) => status === "completed"))
580594
+ return "completed";
580595
+ if (todo.status === "completed")
580596
+ return "in_progress";
580597
+ return todo.status;
580598
+ }
580599
+ _todoLeafStats(todo, index) {
580600
+ const children2 = index.byParent.get(todo.id) ?? [];
580601
+ if (children2.length === 0)
580602
+ return null;
580603
+ let completed = 0;
580604
+ let total = 0;
580605
+ const seen = /* @__PURE__ */ new Set();
580606
+ const visit = (node) => {
580607
+ if (seen.has(node.id))
580608
+ return;
580609
+ seen.add(node.id);
580610
+ const nested = index.byParent.get(node.id) ?? [];
580611
+ if (nested.length === 0) {
580612
+ total++;
580613
+ if (node.status === "completed")
580614
+ completed++;
580615
+ return;
580616
+ }
580617
+ for (const child of nested)
580618
+ visit(child);
580619
+ };
580620
+ for (const child of children2)
580621
+ visit(child);
580622
+ return { completed, total };
580623
+ }
580624
+ _todoLeaves(todos, index = this._todoTreeIndex(todos)) {
580625
+ const leaves = todos.filter((todo) => (index.byParent.get(todo.id) ?? []).length === 0);
580626
+ return leaves.length > 0 ? leaves : todos;
580627
+ }
580628
+ _todoPath(todo, index) {
580629
+ const path12 = [todo];
580630
+ const seen = /* @__PURE__ */ new Set([todo.id]);
580631
+ let cursor = todo;
580632
+ while (cursor?.parentId && index.byId.has(cursor.parentId)) {
580633
+ const parent = index.byId.get(cursor.parentId);
580634
+ if (!parent || seen.has(parent.id))
580635
+ break;
580636
+ path12.unshift(parent);
580637
+ seen.add(parent.id);
580638
+ cursor = parent;
580639
+ }
580640
+ return path12;
580641
+ }
580642
+ _activeTodoForPrompt(todos, index = this._todoTreeIndex(todos)) {
580643
+ const leaves = this._todoLeaves(todos, index);
580644
+ 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;
580645
+ }
580646
+ _orderedTodosForPrompt(todos) {
580647
+ const index = this._todoTreeIndex(todos);
580648
+ const out = [];
580649
+ const seen = /* @__PURE__ */ new Set();
580650
+ const visit = (todo, depth) => {
580651
+ if (seen.has(todo.id))
580652
+ return;
580653
+ seen.add(todo.id);
580654
+ out.push({
580655
+ todo,
580656
+ depth: Math.min(depth, 4),
580657
+ displayStatus: this._todoDisplayStatus(todo, index),
580658
+ childStats: this._todoLeafStats(todo, index)
580659
+ });
580660
+ for (const child of index.byParent.get(todo.id) ?? []) {
580661
+ visit(child, depth + 1);
580662
+ }
580663
+ };
580664
+ for (const root of index.roots)
580665
+ visit(root, 0);
580666
+ for (const todo of todos)
580667
+ visit(todo, 0);
580668
+ return out;
580669
+ }
580433
580670
  _normalizeCommandForValidationMatch(command) {
580434
580671
  return normalizeShellCommand(command);
580435
580672
  }
@@ -580584,7 +580821,9 @@ ${modelVisible}` : modelVisible || result.error || displayOutput || "";
580584
580821
  const realFileMutation = input.realFileMutation ?? this._isRealProjectMutation(input.toolName, input.result);
580585
580822
  const attemptedTargetPaths = this._extractToolTargetPaths(input.toolName, input.args, input.result);
580586
580823
  const realMutationPaths = input.realMutationPaths ?? (realFileMutation ? attemptedTargetPaths : []);
580587
- if (input.result.success === true && this._isProjectEditTool(input.toolName) && !realFileMutation) {
580824
+ const shellVerification = input.toolName === "shell" && input.result.runtimeAuthored !== true && this._shellResultLooksLikeVerification(input.args, input.result);
580825
+ const shellVerificationFamily = shellVerification ? this._shellVerificationFamily(input.args) : "";
580826
+ if (input.result.success === true && this._isProjectEditTool(input.toolName) && !realFileMutation && input.result.alreadyApplied !== true) {
580588
580827
  return;
580589
580828
  }
580590
580829
  if (this._shouldSuppressCompletionDiscoveryEvidence(input.toolName, input.result, attemptedTargetPaths)) {
@@ -580596,9 +580835,9 @@ ${modelVisible}` : modelVisible || result.error || displayOutput || "";
580596
580835
  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
580836
  argsKey: input.argsKey.slice(0, 300),
580598
580837
  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),
580838
+ role: input.result.completionEvidenceRole ?? (input.result.alreadyApplied === true ? "mutation" : realFileMutation ? "mutation" : input.result.runtimeAuthored === true ? "blocker" : shellVerification ? "verification" : void 0),
580839
+ family: input.result.completionEvidenceFamily ?? (input.result.runtimeAuthored === true ? "runtime_control" : shellVerification ? shellVerificationFamily : void 0),
580840
+ verificationImpact: input.result.completionVerificationImpact ?? (input.result.alreadyApplied === true ? "neutral" : realFileMutation ? "invalidates" : void 0),
580602
580841
  metrics: input.result.completionEvidenceMetrics
580603
580842
  });
580604
580843
  if (realFileMutation && realMutationPaths.length > 0) {
@@ -580617,6 +580856,20 @@ ${modelVisible}` : modelVisible || result.error || displayOutput || "";
580617
580856
  }
580618
580857
  this._saveCompletionLedgerSafe();
580619
580858
  }
580859
+ _shellVerificationFamily(args) {
580860
+ const command = String(args?.["command"] ?? args?.["cmd"] ?? "").trim();
580861
+ const normalized = normalizeShellCommand(command);
580862
+ return `shell:${(normalized || command || "verification").slice(0, 160)}`;
580863
+ }
580864
+ _shellResultLooksLikeVerification(args, result) {
580865
+ const command = String(args?.["command"] ?? args?.["cmd"] ?? "");
580866
+ if (!command.trim())
580867
+ return false;
580868
+ const text2 = `${command}
580869
+ ${result.output ?? ""}
580870
+ ${result.error ?? ""}`;
580871
+ 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);
580872
+ }
580620
580873
  _shouldSuppressCompletionDiscoveryEvidence(toolName, result, targetPaths) {
580621
580874
  if (result.success !== true)
580622
580875
  return false;
@@ -581097,6 +581350,9 @@ ${context2 ?? ""}`;
581097
581350
  const originalGoal = (this._taskState.originalGoal || this._taskState.goal || "").trim();
581098
581351
  if (!originalGoal)
581099
581352
  return { proceed: true };
581353
+ if (/^\s*(BLOCKED|INCOMPLETE|NEEDS_INPUT)\b\s*:?/i.test(proposedSummary)) {
581354
+ return { proceed: true };
581355
+ }
581100
581356
  const actionable = toolCallLog.some((e2) => e2.mutated || e2.name === "shell" || e2.name === "file_write" || e2.name === "file_edit");
581101
581357
  if (!actionable)
581102
581358
  return { proceed: true };
@@ -581319,6 +581575,9 @@ ${outTail || "(no output captured)"}`,
581319
581575
  const _verify = await this._runCompletionVerifyGate(turn);
581320
581576
  if (!_verify.proceed)
581321
581577
  return _verify;
581578
+ if (this.options.backwardPassReview === false || this.options.disableAdversaryCritic === true) {
581579
+ return { proceed: true };
581580
+ }
581322
581581
  const _resolution = await this._runResolutionGate(turn, proposedSummary, toolCallLog);
581323
581582
  if (!_resolution.proceed) {
581324
581583
  return {
@@ -581662,14 +581921,18 @@ ${_checks}`
581662
581921
  const parts = [];
581663
581922
  const todos = this.readSessionTodos();
581664
581923
  if (todos && todos.length > 0) {
581665
- const current = todos.find((t2) => t2.status === "in_progress");
581666
- const completedN = todos.filter((t2) => t2.status === "completed").length;
581924
+ const index = this._todoTreeIndex(todos);
581925
+ const leaves = this._todoLeaves(todos, index);
581926
+ const current = this._activeTodoForPrompt(todos, index);
581927
+ const completedN = leaves.filter((t2) => t2.status === "completed").length;
581928
+ const totalN = leaves.length;
581667
581929
  if (current) {
581668
- parts.push(`[plan: ${completedN}/${todos.length} complete · currently: ${current.content.slice(0, 80)}]`);
581930
+ const path12 = this._todoPath(current, index).map((todo) => todo.content.slice(0, 64)).join(" > ");
581931
+ parts.push(`[plan: ${completedN}/${totalN} leaf tasks complete · active: ${path12.slice(0, 160)}]`);
581669
581932
  } else {
581670
- const nextPending = todos.find((t2) => t2.status === "pending");
581933
+ const nextPending = leaves.find((t2) => t2.status === "pending");
581671
581934
  if (nextPending) {
581672
- parts.push(`[plan: ${completedN}/${todos.length} complete · next: ${nextPending.content.slice(0, 80)}]`);
581935
+ parts.push(`[plan: ${completedN}/${totalN} leaf tasks complete · next: ${nextPending.content.slice(0, 80)}]`);
581673
581936
  }
581674
581937
  }
581675
581938
  }
@@ -582641,36 +582904,73 @@ ${latest.output || ""}`.trim();
582641
582904
  */
582642
582905
  _renderTodoStateBlock(turn) {
582643
582906
  try {
582644
- const todos = this.readSessionTodos();
582907
+ const todos = this._normalizeTodosForPrompt(this.readSessionTodos() ?? []);
582645
582908
  if (!todos || todos.length === 0)
582646
582909
  return null;
582910
+ const index = this._todoTreeIndex(todos);
582911
+ const leaves = this._todoLeaves(todos, index);
582912
+ const completedLeaves = leaves.filter((t2) => t2.status === "completed");
582913
+ const active = this._activeTodoForPrompt(todos, index);
582914
+ const activePath = active ? this._todoPath(active, index).map((todo) => todo.content.slice(0, 80)).join(" > ") : "";
582647
582915
  const lines = [
582648
- "[CURRENT TODO PLAN — already in your state, no need to call todo_write to see it]"
582916
+ "[CURRENT TODO PLAN — already in your state, no need to call todo_write to see it]",
582917
+ `leaf_progress=${completedLeaves.length}/${leaves.length}`
582649
582918
  ];
582650
- const inProg = todos.filter((t2) => t2.status === "in_progress");
582651
- const pending2 = todos.filter((t2) => t2.status === "pending");
582652
- const done = todos.filter((t2) => t2.status === "completed");
582653
- const blocked = todos.filter((t2) => t2.status === "blocked");
582654
- if (inProg.length > 0) {
582655
- lines.push(`▶ in_progress (${inProg.length}):`);
582656
- for (const t2 of inProg)
582657
- lines.push(` • ${t2.content}`);
582658
- }
582659
- if (pending2.length > 0) {
582660
- lines.push(`◯ pending (${pending2.length}):`);
582661
- for (const t2 of pending2.slice(0, 8))
582662
- lines.push(` • ${t2.content}`);
582663
- if (pending2.length > 8)
582664
- lines.push(` … +${pending2.length - 8} more`);
582919
+ if (activePath)
582920
+ lines.push(`active_branch=${activePath.slice(0, 220)}`);
582921
+ const ordered = this._orderedTodosForPrompt(todos);
582922
+ const activeIndex = active ? ordered.findIndex((entry) => entry.todo.id === active.id) : -1;
582923
+ let visible = ordered;
582924
+ if (ordered.length > 14) {
582925
+ const selected = [];
582926
+ const seen = /* @__PURE__ */ new Set();
582927
+ const add3 = (entry) => {
582928
+ if (!entry || selected.length >= 13 || seen.has(entry.todo.id))
582929
+ return;
582930
+ selected.push(entry);
582931
+ seen.add(entry.todo.id);
582932
+ };
582933
+ if (active && activeIndex >= 0) {
582934
+ const pathIds = new Set(this._todoPath(active, index).map((t2) => t2.id));
582935
+ for (const entry of ordered) {
582936
+ if (pathIds.has(entry.todo.id) && entry.todo.id !== active.id)
582937
+ add3(entry);
582938
+ }
582939
+ const siblings = active.parentId ? index.byParent.get(active.parentId) ?? [] : index.roots;
582940
+ const siblingIndex = siblings.findIndex((t2) => t2.id === active.id);
582941
+ if (siblingIndex > 0) {
582942
+ add3(ordered.find((entry) => entry.todo.id === siblings[siblingIndex - 1]?.id));
582943
+ }
582944
+ add3(ordered[activeIndex]);
582945
+ for (let i2 = siblingIndex + 1; i2 < siblings.length && selected.length < 13; i2++) {
582946
+ add3(ordered.find((entry) => entry.todo.id === siblings[i2]?.id));
582947
+ }
582948
+ for (const child of index.byParent.get(active.id) ?? []) {
582949
+ add3(ordered.find((entry) => entry.todo.id === child.id));
582950
+ }
582951
+ for (let i2 = activeIndex + 1; i2 < ordered.length && selected.length < 13; i2++) {
582952
+ add3(ordered[i2]);
582953
+ }
582954
+ }
582955
+ visible = selected.length > 0 ? selected : ordered.slice(0, 13);
582665
582956
  }
582666
- if (blocked.length > 0) {
582667
- lines.push(`✕ blocked (${blocked.length}):`);
582668
- for (const t2 of blocked)
582669
- lines.push(` • ${t2.content}${t2.blocker ? ` — ${t2.blocker}` : ""}`);
582957
+ const statusMark = {
582958
+ completed: "OK",
582959
+ in_progress: ">>",
582960
+ pending: "--",
582961
+ blocked: "!!"
582962
+ };
582963
+ lines.push("tree:");
582964
+ for (const entry of visible) {
582965
+ const indent2 = " ".repeat(entry.depth);
582966
+ const childSuffix = entry.childStats && entry.childStats.total > 0 ? ` [${entry.childStats.completed}/${entry.childStats.total}]` : "";
582967
+ const blocker = entry.todo.blocker ? ` blocker=${entry.todo.blocker.slice(0, 120)}` : "";
582968
+ lines.push(`${indent2}${statusMark[entry.displayStatus]} ${entry.todo.content.slice(0, 140)}${childSuffix}${blocker}`);
582670
582969
  }
582671
- if (done.length > 0) {
582672
- lines.push(`✓ completed (${done.length}): ${done.map((t2) => t2.content.slice(0, 40)).join(" | ")}`);
582970
+ if (ordered.length > visible.length) {
582971
+ lines.push(`... +${ordered.length - visible.length} more todo node(s)`);
582673
582972
  }
582973
+ 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
582974
  lines.push(`(turn ${turn} — call todo_write ONLY to update state, never to re-read this plan)`);
582675
582975
  return lines.join("\n");
582676
582976
  } catch {
@@ -583217,6 +583517,7 @@ ${chunk.content}`, {
583217
583517
  this._taskState.goal ? `Active task: (see user message above — the goal block defers to the user message as the authoritative source)` : null
583218
583518
  ].filter(Boolean).join("\n\n");
583219
583519
  const filesystemBlock = this._renderFilesystemStateBlock(turn);
583520
+ const artifactContractBlock = this._contractRegistry.format(15);
583220
583521
  const todoBlock = this._renderTodoStateBlock(turn);
583221
583522
  const failureBlock = this._renderRecentFailuresBlock(turn);
583222
583523
  const churnBlock = this._renderWriteChurnBlock(turn);
@@ -583259,6 +583560,13 @@ ${this._lastPprMemoryLines.slice(0, 5).join("\n")}` : null;
583259
583560
  createdTurn: turn,
583260
583561
  ttlTurns: 1
583261
583562
  }),
583563
+ signalFromBlock("known_files", "turn.artifact-contracts", artifactContractBlock, {
583564
+ id: "artifact-contracts",
583565
+ dedupeKey: "turn.artifact-contracts",
583566
+ priority: 86,
583567
+ createdTurn: turn,
583568
+ ttlTurns: 1
583569
+ }),
583262
583570
  signalFromBlock("action_contract", "turn.next-action-contract", actionContractBlock, {
583263
583571
  id: "next-action-contract",
583264
583572
  dedupeKey: "turn.next-action-contract",
@@ -584588,7 +584896,6 @@ Respond with your assessment, then take action.`;
584588
584896
  const hardDeadlineMs = Number.isFinite(taskTimeoutMs) && taskTimeoutMs > 0 ? start2 + taskTimeoutMs : Number.POSITIVE_INFINITY;
584589
584897
  let timedOut = false;
584590
584898
  let timeoutSummary = "";
584591
- let _timeoutAdvisoryInjected = false;
584592
584899
  const remainingTaskMs = () => Number.isFinite(hardDeadlineMs) ? Math.max(0, hardDeadlineMs - Date.now()) : Number.POSITIVE_INFINITY;
584593
584900
  const boundedRequestTimeoutMs = () => {
584594
584901
  const configured = Number.isFinite(this.options.requestTimeoutMs) && this.options.requestTimeoutMs > 0 ? this.options.requestTimeoutMs : 3e5;
@@ -584618,7 +584925,8 @@ Respond with your assessment, then take action.`;
584618
584925
  return false;
584619
584926
  if (Date.now() < hardDeadlineMs)
584620
584927
  return false;
584621
- return !_timeoutAdvisoryInjected;
584928
+ markTaskTimedOut(phase, turn);
584929
+ return true;
584622
584930
  };
584623
584931
  const selfEvalInterval = taskTimeoutMs;
584624
584932
  let nextSelfEval = start2 + selfEvalInterval;
@@ -586647,12 +586955,13 @@ ${_staleSamples.join("\n")}` : ``,
586647
586955
  content: `[TASK DECOMPOSITION — Multi-step task detected]
586648
586956
 
586649
586957
  MANDATORY FIRST ACTION: Call todo_write NOW with the complete plan.
586650
- Each todo item is { content: "what to do", status: "pending" | "in_progress" | "completed" | "blocked" }.
586651
- Mark item 1 as in_progress, the rest as pending.
586958
+ Each todo item is { id, content, status, parentId? } or a parent with children/subtasks. Use stable ids.
586959
+ Represent broad objectives as parent todos and concrete work as child leaf todos. Mark the active leaf in_progress, the rest pending.
586652
586960
  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: "read source files", status: "in_progress"}, {content: "make changes", status: "pending"}, {content: "run tests", status: "pending"}]})
586961
+ 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
586962
 
586655
- After EACH phase finishes, call todo_write AGAIN with item N marked completed and item N+1 marked in_progress.
586963
+ After EACH leaf finishes, call todo_write AGAIN with that leaf completed and the next leaf in_progress.
586964
+ 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
586965
  The user watches this checklist update live in the chat UI. Without it they cannot see your plan or track progress.
586657
586966
 
586658
586967
  Then complete these phases IN ORDER:
@@ -586971,10 +587280,6 @@ ${memoryLines.join("\n")}`
586971
587280
  this.proactivePrune(compacted, turn);
586972
587281
  this.microcompact(compacted, recentToolResults);
586973
587282
  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
587283
  this.gcSystemMessages(compacted);
586979
587284
  let requestMessages = sanitizeHistoryThink(compacted);
586980
587285
  {
@@ -588639,7 +588944,7 @@ Respond with EXACTLY this structure before your next tool call:
588639
588944
  } else if (tc.name === "shell") {
588640
588945
  const cmd = String(tc.arguments?.["command"] ?? "");
588641
588946
  if (/\b(npm|pnpm|yarn)\s+test\b|\bjest\b|\bvitest\b/i.test(cmd)) {
588642
- const passed = /PASS|✓\s*all/i.test(result.output) && !/FAIL|✗/i.test(result.output);
588947
+ const passed = /\b(PASS|pass|passed|success|ok)\b|✓\s*all/i.test(result.output) && !/FAIL|✗/i.test(result.output);
588643
588948
  this._worldFacts.lastTest = {
588644
588949
  passed,
588645
588950
  summary: result.output.slice(0, 200),
@@ -589106,7 +589411,8 @@ Respond with EXACTLY this structure before your next tool call:
589106
589411
  const _shellCmd2 = String(tc.arguments?.["command"] ?? tc.arguments?.["cmd"] ?? "");
589107
589412
  const _declaredVerify = this._matchedDeclaredVerifyCommand(_shellCmd2);
589108
589413
  const _lastVerifier = this._lastVerifierResult;
589109
- const _noTodoDirectValidation = !_declaredVerify && (this.readSessionTodos() || []).length === 0 && this._taskState.modifiedFiles.size > 0 && _lastVerifier?.outcomeClass === "verified";
589414
+ const _directShellValidation = result.success === true && this._shellResultLooksLikeVerification(tc.arguments, result);
589415
+ const _noTodoDirectValidation = !_declaredVerify && (this.readSessionTodos() || []).length === 0 && this._taskState.modifiedFiles.size > 0 && (_lastVerifier?.outcomeClass === "verified" || _directShellValidation);
589110
589416
  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
589417
  if (_declaredVerify || _noTodoDirectValidation || _legacyGenericValidation) {
589112
589418
  this._lastBuildSuccessTurn = turn;
@@ -589281,7 +589587,7 @@ Respond with EXACTLY this structure before your next tool call:
589281
589587
  }
589282
589588
  const cacheableMemoryNoop = tc.name === "memory_write" && result.success && result.noop;
589283
589589
  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) {
589590
+ if (isReadLike && result.success && result.runtimeAuthored !== true || tc.name === "shell" && result.runtimeAuthored !== true || cacheableMemoryNoop || cacheableProjectWriteNoop) {
589285
589591
  recentToolResults.set(toolFingerprint, {
589286
589592
  result: tc.name === "shell" ? this._buildShellCacheResult(tc.arguments, result) : (
589287
589593
  // Read-like results are SERVED BACK to the model when the
@@ -589400,7 +589706,7 @@ Respond with EXACTLY this structure before your next tool call:
589400
589706
  }
589401
589707
  }
589402
589708
  }
589403
- if (!result.success) {
589709
+ if (!result.success && result.runtimeAuthored !== true) {
589404
589710
  this._recentFailures.push({
589405
589711
  tool: tc.name,
589406
589712
  fingerprint: toolFingerprint,
@@ -589638,7 +589944,7 @@ ${bookkeepingGuidance}` : bookkeepingGuidance;
589638
589944
  argsPreview: toolArgsPreview,
589639
589945
  targetPaths: toolTargetPaths,
589640
589946
  family: result.completionEvidenceFamily ?? (result.runtimeAuthored === true ? "runtime_control" : void 0),
589641
- role: result.completionEvidenceRole ?? (realFileMutation || shellFilesystemMutation ? "mutation" : result.runtimeAuthored === true ? "blocker" : void 0),
589947
+ role: result.completionEvidenceRole ?? (result.alreadyApplied === true ? "mutation" : realFileMutation || shellFilesystemMutation ? "mutation" : result.runtimeAuthored === true ? "blocker" : void 0),
589642
589948
  turn
589643
589949
  });
589644
589950
  if (this._toolEvents.length > 200)
@@ -589787,6 +590093,7 @@ Evidence: ${evidencePreview}`.slice(0, 500);
589787
590093
  mutated: realFileMutation || shellFilesystemMutation,
589788
590094
  isReadLike,
589789
590095
  noop: tc.name === "todo_write" ? this._isTodoWriteNoopResult(result) : result.noop,
590096
+ alreadyApplied: result.alreadyApplied === true,
589790
590097
  runtimeAuthored: result.runtimeAuthored === true
589791
590098
  });
589792
590099
  const focusSnapshotAfter = this._focusSupervisor?.snapshot();
@@ -590885,10 +591192,6 @@ ${this.options.maxTurns && this.options.maxTurns > 0 ? `You have ${this.options.
590885
591192
  }
590886
591193
  }
590887
591194
  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
591195
  this.gcSystemMessages(compactedMsgs);
590893
591196
  const modelFacingMessages = sanitizeHistoryThink(compactedMsgs);
590894
591197
  const chatRequest = {
@@ -591431,7 +591734,7 @@ ${this._completionCaveat}` : this._completionCaveat;
591431
591734
  if (this._completionLedger) {
591432
591735
  this._completionLedger = finalizeCompletionLedgerTruth(this._completionLedger);
591433
591736
  this._saveCompletionLedgerSafe();
591434
- if (completed && this._completionLedger.status === "incomplete_verification") {
591737
+ if (completed && this._completionLedger.status === "incomplete_verification" && this.options.backwardPassReview !== false && !this._completionCaveat) {
591435
591738
  completed = false;
591436
591739
  const unresolvedSummary = this._completionLedger.unresolved.slice(-3).map((item) => item.text).join("; ");
591437
591740
  const caveat = unresolvedSummary ? `Incomplete verification: ${unresolvedSummary}` : "Incomplete verification: unresolved evidence remains in the completion ledger.";
@@ -592093,33 +592396,49 @@ ${caveat}` : caveat;
592093
592396
  this._saveWorkboard();
592094
592397
  await this._hookManager.runSessionHook("session_end", this._sessionId);
592095
592398
  try {
592096
- const fs11 = await import("node:fs");
592097
- const path12 = await import("node:path");
592098
- const trajDir = path12.join(this.omniusStateDir(), "trajectories");
592099
- fs11.mkdirSync(trajDir, { recursive: true });
592100
- const trajectory = {
592101
- id: this._sessionId,
592102
- // CLEAN task this file is the prerequisite for ALL future RL/RFT
592103
- // training. Storing the scaffolded version would teach future models
592104
- // to reproduce signpost text as part of their task understanding.
592105
- task: persistentTaskGoal.slice(0, 1e3),
592106
- outcome: completed ? "pass" : this.aborted ? "aborted" : runStatus === "incomplete_verification" ? "incomplete_verification" : "timeout",
592107
- model: this.backend.model ?? "unknown",
592108
- modelTier: this.options.modelTier ?? "large",
592109
- turns: messages2.filter((m2) => m2.role === "assistant").length,
592110
- toolCalls: toolCallLog.map((tc) => ({
592111
- name: tc.name,
592112
- argsFingerprint: tc.argsKey.slice(0, 100)
592113
- })),
592114
- totalToolCalls: toolCallCount,
592115
- totalTokens,
592116
- filesModified: [...this._taskState.modifiedFiles.keys()],
592117
- failedApproaches: this._taskState.failedApproaches,
592118
- completedSteps: this._taskState.completedSteps,
592119
- durationMs,
592120
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
592121
- };
592122
- fs11.appendFileSync(path12.join(trajDir, `trajectories.jsonl`), JSON.stringify(trajectory) + "\n", "utf-8");
592399
+ const trajectoryQuality = assessTaskArtifactQuality({
592400
+ artifactMode: this.options.artifactMode,
592401
+ goal: persistentTaskGoal,
592402
+ summary,
592403
+ toolsUsed: toolCallLog.map((tc) => tc.name),
592404
+ filesTouched: [...this._taskState.modifiedFiles.keys()],
592405
+ turns: messages2.filter((m2) => m2.role === "assistant").length
592406
+ });
592407
+ if (!trajectoryQuality.eligible) {
592408
+ this.emit({
592409
+ type: "status",
592410
+ content: `Trajectory log skipped: ${trajectoryQuality.reason ?? "not eligible"}`,
592411
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
592412
+ });
592413
+ } else {
592414
+ const fs11 = await import("node:fs");
592415
+ const path12 = await import("node:path");
592416
+ const trajDir = path12.join(this.omniusStateDir(), "trajectories");
592417
+ fs11.mkdirSync(trajDir, { recursive: true });
592418
+ const trajectory = {
592419
+ id: this._sessionId,
592420
+ // CLEAN task — this file is the prerequisite for ALL future RL/RFT
592421
+ // training. Storing the scaffolded version would teach future models
592422
+ // to reproduce signpost text as part of their task understanding.
592423
+ task: persistentTaskGoal.slice(0, 1e3),
592424
+ outcome: completed ? "pass" : this.aborted ? "aborted" : runStatus === "incomplete_verification" ? "incomplete_verification" : "timeout",
592425
+ model: this.backend.model ?? "unknown",
592426
+ modelTier: this.options.modelTier ?? "large",
592427
+ turns: messages2.filter((m2) => m2.role === "assistant").length,
592428
+ toolCalls: toolCallLog.map((tc) => ({
592429
+ name: tc.name,
592430
+ argsFingerprint: tc.argsKey.slice(0, 100)
592431
+ })),
592432
+ totalToolCalls: toolCallCount,
592433
+ totalTokens,
592434
+ filesModified: [...this._taskState.modifiedFiles.keys()],
592435
+ failedApproaches: this._taskState.failedApproaches,
592436
+ completedSteps: this._taskState.completedSteps,
592437
+ durationMs,
592438
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
592439
+ };
592440
+ fs11.appendFileSync(path12.join(trajDir, `trajectories.jsonl`), JSON.stringify(trajectory) + "\n", "utf-8");
592441
+ }
592123
592442
  } catch {
592124
592443
  }
592125
592444
  let filesEdited;
@@ -592615,7 +592934,7 @@ ${marker}` : marker);
592615
592934
  if (!target)
592616
592935
  return;
592617
592936
  const targetPathKey = this.staleEditPathKey(target.path);
592618
- if (this._isRealProjectMutation(toolName, result)) {
592937
+ if (this._isRealProjectMutation(toolName, result) || result.alreadyApplied === true) {
592619
592938
  for (const [key2, entry] of this._staleEditFamilies) {
592620
592939
  if (entry.pathKey === targetPathKey)
592621
592940
  this._staleEditFamilies.delete(key2);
@@ -629489,6 +629808,8 @@ var init_overlay_lock = __esm({
629489
629808
  // packages/cli/src/tui/tui-tasks-renderer.ts
629490
629809
  var tui_tasks_renderer_exports = {};
629491
629810
  __export(tui_tasks_renderer_exports, {
629811
+ __testOrderTodosForDisplay: () => __testOrderTodosForDisplay,
629812
+ __testSelectPanelTodoRows: () => __testSelectPanelTodoRows,
629492
629813
  getTuiTasksScope: () => getTuiTasksScope,
629493
629814
  onTuiTasksHeightChange: () => onTuiTasksHeightChange,
629494
629815
  refreshTuiTasks: () => refreshTuiTasks,
@@ -629646,7 +629967,7 @@ function computeTargetHeight() {
629646
629967
  if (!_lastTodos || _lastTodos.length === 0) return 0;
629647
629968
  const allDone = _lastTodos.every((t2) => t2 && t2.status === "completed");
629648
629969
  if (allDone) return 0;
629649
- const itemRows = Math.min(_lastTodos.length, MAX_VISIBLE_ROWS - 1);
629970
+ const itemRows = selectPanelTodoRows(_lastTodos, MAX_VISIBLE_ROWS - 1).rowCount;
629650
629971
  return 1 + itemRows;
629651
629972
  }
629652
629973
  function applyHeightChange(nextHeight) {
@@ -629724,9 +630045,9 @@ function buildTodoProgressBar(todos, maxWidth) {
629724
630045
  if (truncated && maxWidth > 0) out += `${DIM_LABEL}…${RESET3}`;
629725
630046
  return out;
629726
630047
  }
629727
- function orderTodosForDisplay(todos) {
630048
+ function buildTodoTreeIndex(todos) {
629728
630049
  const byParent = /* @__PURE__ */ new Map();
629729
- const byId = new Set(todos.map((t2) => t2.id));
630050
+ const byId = new Map(todos.map((t2) => [t2.id, t2]));
629730
630051
  const roots = [];
629731
630052
  for (const todo of todos) {
629732
630053
  if (todo.parentId && byId.has(todo.parentId)) {
@@ -629737,20 +630058,146 @@ function orderTodosForDisplay(todos) {
629737
630058
  roots.push(todo);
629738
630059
  }
629739
630060
  }
630061
+ return { byId, byParent, roots };
630062
+ }
630063
+ function childLeafStats(todo, index) {
630064
+ const children2 = index.byParent.get(todo.id) ?? [];
630065
+ if (children2.length === 0) return void 0;
630066
+ let completed = 0;
630067
+ let total = 0;
630068
+ const seen = /* @__PURE__ */ new Set();
630069
+ const visit = (node) => {
630070
+ if (seen.has(node.id)) return;
630071
+ seen.add(node.id);
630072
+ const nested = index.byParent.get(node.id) ?? [];
630073
+ if (nested.length === 0) {
630074
+ total++;
630075
+ if (node.status === "completed") completed++;
630076
+ return;
630077
+ }
630078
+ for (const child of nested) visit(child);
630079
+ };
630080
+ for (const child of children2) visit(child);
630081
+ return { completed, total };
630082
+ }
630083
+ function displayStatusFor(todo, index, seen = /* @__PURE__ */ new Set()) {
630084
+ if (seen.has(todo.id)) return todo.status;
630085
+ seen.add(todo.id);
630086
+ const children2 = index.byParent.get(todo.id) ?? [];
630087
+ if (children2.length === 0) return todo.status;
630088
+ const childStatuses = children2.map((child) => displayStatusFor(child, index, new Set(seen)));
630089
+ if (childStatuses.some((status) => status === "blocked")) return "blocked";
630090
+ if (childStatuses.some((status) => status === "in_progress")) return "in_progress";
630091
+ if (childStatuses.every((status) => status === "completed")) return "completed";
630092
+ if (todo.status === "completed") return "in_progress";
630093
+ return todo.status;
630094
+ }
630095
+ function toDisplayTodo(todo, depth, index) {
630096
+ return {
630097
+ ...todo,
630098
+ depth: Math.min(depth, 4),
630099
+ displayStatus: displayStatusFor(todo, index),
630100
+ childSummary: childLeafStats(todo, index)
630101
+ };
630102
+ }
630103
+ function orderTodosForDisplay(todos) {
630104
+ const index = buildTodoTreeIndex(todos);
629740
630105
  const out = [];
629741
630106
  const seen = /* @__PURE__ */ new Set();
629742
630107
  const visit = (todo, depth) => {
629743
630108
  if (seen.has(todo.id)) return;
629744
630109
  seen.add(todo.id);
629745
- out.push({ ...todo, depth: Math.min(depth, 4) });
629746
- for (const child of byParent.get(todo.id) ?? []) {
630110
+ out.push(toDisplayTodo(todo, depth, index));
630111
+ for (const child of index.byParent.get(todo.id) ?? []) {
629747
630112
  visit(child, depth + 1);
629748
630113
  }
629749
630114
  };
629750
- for (const root of roots) visit(root, 0);
630115
+ for (const root of index.roots) visit(root, 0);
629751
630116
  for (const todo of todos) visit(todo, 0);
629752
630117
  return out;
629753
630118
  }
630119
+ function leafTodosForProgress(todos) {
630120
+ const index = buildTodoTreeIndex(todos);
630121
+ const leaves = todos.filter((todo) => (index.byParent.get(todo.id) ?? []).length === 0);
630122
+ return leaves.length > 0 ? leaves : todos;
630123
+ }
630124
+ function activeDisplayIndex(displayTodos) {
630125
+ const inProgressLeaf = displayTodos.findIndex(
630126
+ (todo, index, all2) => todo.status === "in_progress" && !all2.some((candidate) => candidate.parentId === todo.id)
630127
+ );
630128
+ if (inProgressLeaf >= 0) return inProgressLeaf;
630129
+ const inProgress = displayTodos.findIndex((todo) => todo.displayStatus === "in_progress");
630130
+ if (inProgress >= 0) return inProgress;
630131
+ const blocked = displayTodos.findIndex((todo) => todo.displayStatus === "blocked");
630132
+ if (blocked >= 0) return blocked;
630133
+ return displayTodos.findIndex((todo) => todo.displayStatus === "pending");
630134
+ }
630135
+ function selectFocusedTodoItems(todos, maxItems) {
630136
+ const displayTodos = orderTodosForDisplay(todos);
630137
+ if (maxItems <= 0) return [];
630138
+ if (displayTodos.length <= maxItems) return displayTodos;
630139
+ const activeIndex = activeDisplayIndex(displayTodos);
630140
+ if (activeIndex < 0 || activeIndex < maxItems) return displayTodos.slice(0, maxItems);
630141
+ const rawIndex = buildTodoTreeIndex(todos);
630142
+ const displayById = new Map(displayTodos.map((todo) => [todo.id, todo]));
630143
+ const selected = [];
630144
+ const seen = /* @__PURE__ */ new Set();
630145
+ const add3 = (todo) => {
630146
+ if (!todo || selected.length >= maxItems || seen.has(todo.id)) return;
630147
+ selected.push(todo);
630148
+ seen.add(todo.id);
630149
+ };
630150
+ const active = displayTodos[activeIndex];
630151
+ const ancestors = [];
630152
+ let cursor = active;
630153
+ while (cursor?.parentId && rawIndex.byId.has(cursor.parentId)) {
630154
+ const parent = rawIndex.byId.get(cursor.parentId);
630155
+ if (!parent) break;
630156
+ const displayParent = displayById.get(parent.id);
630157
+ if (displayParent) ancestors.unshift(displayParent);
630158
+ cursor = parent;
630159
+ }
630160
+ for (const ancestor of ancestors) add3(ancestor);
630161
+ const siblings = active.parentId ? rawIndex.byParent.get(active.parentId) ?? [] : rawIndex.roots;
630162
+ const activeSiblingIndex = siblings.findIndex((todo) => todo.id === active.id);
630163
+ if (activeSiblingIndex > 0) add3(displayById.get(siblings[activeSiblingIndex - 1].id));
630164
+ add3(active);
630165
+ for (let i2 = activeSiblingIndex + 1; i2 < siblings.length && selected.length < maxItems; i2++) {
630166
+ add3(displayById.get(siblings[i2].id));
630167
+ }
630168
+ const activeChildren = rawIndex.byParent.get(active.id) ?? [];
630169
+ for (const child of activeChildren) add3(displayById.get(child.id));
630170
+ for (let i2 = activeIndex + 1; i2 < displayTodos.length && selected.length < maxItems; i2++) {
630171
+ add3(displayTodos[i2]);
630172
+ }
630173
+ for (let i2 = activeIndex - 1; i2 >= 0 && selected.length < maxItems; i2--) {
630174
+ add3(displayTodos[i2]);
630175
+ }
630176
+ return selected;
630177
+ }
630178
+ function selectPanelTodoRows(todos, maxRows) {
630179
+ const displayTodos = orderTodosForDisplay(todos);
630180
+ if (maxRows <= 0 || displayTodos.length === 0) {
630181
+ return { items: [], omitted: displayTodos.length, rowCount: 0 };
630182
+ }
630183
+ if (displayTodos.length <= maxRows) {
630184
+ return { items: displayTodos, omitted: 0, rowCount: displayTodos.length };
630185
+ }
630186
+ const itemBudget = Math.max(1, maxRows - 1);
630187
+ const items = selectFocusedTodoItems(todos, itemBudget);
630188
+ const omitted = Math.max(0, displayTodos.length - items.length);
630189
+ return {
630190
+ items,
630191
+ omitted,
630192
+ rowCount: Math.min(maxRows, items.length + (omitted > 0 ? 1 : 0))
630193
+ };
630194
+ }
630195
+ function __testOrderTodosForDisplay(todos) {
630196
+ return orderTodosForDisplay(todos);
630197
+ }
630198
+ function __testSelectPanelTodoRows(todos, maxRows) {
630199
+ return selectPanelTodoRows(todos, maxRows);
630200
+ }
629754
630201
  function render() {
629755
630202
  if (!_enabled) return;
629756
630203
  if (!panelEffectivelyVisible()) {
@@ -629766,29 +630213,30 @@ function render() {
629766
630213
  }
629767
630214
  const L = layout();
629768
630215
  const cols = Math.max(20, termCols());
629769
- const completed = _lastTodos.filter((t2) => t2.status === "completed").length;
629770
- const total = _lastTodos.length;
630216
+ const progressTodos = leafTodosForProgress(_lastTodos);
630217
+ const completed = progressTodos.filter((t2) => t2.status === "completed").length;
630218
+ const total = progressTodos.length;
629771
630219
  const headerColor = ACCENT;
629772
630220
  const lines = [];
629773
630221
  const headerPrefix = `tasks ${headerColor}${completed}/${total}${RESET3} `;
629774
630222
  const headerPrefixWidth = visualLen(headerPrefix);
629775
630223
  const maxBarWidth = Math.max(0, cols - 2 - headerPrefixWidth);
629776
- const progressBar = buildTodoProgressBar(_lastTodos, maxBarWidth);
630224
+ const progressBar = buildTodoProgressBar(progressTodos, maxBarWidth);
629777
630225
  const headerText = `${headerPrefix}${progressBar}`;
629778
630226
  lines.push(headerText);
629779
- const displayTodos = orderTodosForDisplay(_lastTodos);
629780
- const visible = displayTodos.slice(0, MAX_VISIBLE_ROWS - 1);
630227
+ const selection = selectPanelTodoRows(_lastTodos, MAX_VISIBLE_ROWS - 1);
630228
+ const visible = selection.items;
629781
630229
  for (const t2 of visible) {
629782
- const { mark, color } = statusToAnsi(t2.status);
630230
+ const { mark, color } = statusToAnsi(t2.displayStatus);
629783
630231
  const contentWidth = Math.max(4, cols - 8);
629784
- const indent2 = t2.depth > 0 ? `${" ".repeat(t2.depth - 1)}- ` : "";
629785
- const contentText = indent2 + t2.content + (t2.blocker ? ` (blocked: ${t2.blocker})` : "");
630232
+ const indent2 = t2.depth > 0 ? `${" ".repeat(t2.depth)}- ` : "";
630233
+ const childSummary = t2.childSummary && t2.childSummary.total > 0 ? ` [${t2.childSummary.completed}/${t2.childSummary.total}]` : "";
630234
+ const contentText = indent2 + t2.content + childSummary + (t2.blocker ? ` (blocked: ${t2.blocker})` : "");
629786
630235
  const truncated = truncate2(contentText, contentWidth);
629787
630236
  lines.push(`${color}${mark}${RESET3} ${color}${truncated}${RESET3}`);
629788
630237
  }
629789
- if (displayTodos.length > visible.length) {
629790
- const more = displayTodos.length - visible.length;
629791
- lines[lines.length - 1] = `${DIM_LABEL}… +${more} more${RESET3}`;
630238
+ if (selection.omitted > 0) {
630239
+ lines.push(`${DIM_LABEL}… +${selection.omitted} more${RESET3}`);
629792
630240
  }
629793
630241
  let out = HIDE + SAVE;
629794
630242
  const newTop = L.tasksTop;
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.452",
3
+ "version": "1.0.454",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "omnius",
9
- "version": "1.0.452",
9
+ "version": "1.0.454",
10
10
  "bundleDependencies": [
11
11
  "image-to-ascii"
12
12
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.452",
3
+ "version": "1.0.454",
4
4
  "description": "AI coding agent powered by open-source models (Ollama/vLLM) — interactive TUI with agentic tool-calling loop",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",