omnius 1.0.376 → 1.0.377

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
@@ -559711,13 +559711,6 @@ var init_completionLedger = __esm({
559711
559711
  // packages/orchestrator/dist/completionAutoFinalize.js
559712
559712
  function buildTruthBasedCompletion(input) {
559713
559713
  const maxAge = input.maxValidationAgeTurns ?? 8;
559714
- if (input.todos.length === 0) {
559715
- return { ready: false, reason: "no active todo tree" };
559716
- }
559717
- const open2 = input.todos.filter((todo) => todo.status !== "completed");
559718
- if (open2.length > 0) {
559719
- return { ready: false, reason: `${open2.length} open todo(s)` };
559720
- }
559721
559714
  if (input.verifyFailureCount > 0) {
559722
559715
  return {
559723
559716
  ready: false,
@@ -559735,6 +559728,33 @@ function buildTruthBasedCompletion(input) {
559735
559728
  };
559736
559729
  }
559737
559730
  const files = (input.filesEdited ?? []).filter((file) => file.path.trim().length > 0).slice(0, 12);
559731
+ if (input.todos.length === 0) {
559732
+ if (files.length === 0) {
559733
+ return { ready: false, reason: "no active todo tree or changed files" };
559734
+ }
559735
+ if (typeof input.lastMutationTurn === "number" && input.lastMutationTurn >= 0 && input.lastValidationTurn < input.lastMutationTurn) {
559736
+ return {
559737
+ ready: false,
559738
+ reason: "validation happened before the last mutation"
559739
+ };
559740
+ }
559741
+ const fileLines2 = files.map((file) => `- ${file.action ? `${file.action} ` : ""}${file.path}`).join("\n");
559742
+ const summary2 = [
559743
+ "Completed with direct task evidence.",
559744
+ fileLines2 ? `Files changed:
559745
+ ${fileLines2}` : null,
559746
+ `Validation passed after the last mutation: ${input.lastValidationCommand}`
559747
+ ].filter((line) => Boolean(line)).join("\n\n");
559748
+ return {
559749
+ ready: true,
559750
+ reason: `changed files validated ${age} turn(s) ago`,
559751
+ summary: summary2
559752
+ };
559753
+ }
559754
+ const open2 = input.todos.filter((todo) => todo.status !== "completed");
559755
+ if (open2.length > 0) {
559756
+ return { ready: false, reason: `${open2.length} open todo(s)` };
559757
+ }
559738
559758
  const todoLines = input.todos.slice(0, 12).map((todo) => {
559739
559759
  const id = todo.id ? `${todo.id}: ` : "";
559740
559760
  return `- ${id}${todo.content}`;
@@ -578285,6 +578305,7 @@ TASK: ${scrubbedTask}` : scrubbedTask;
578285
578305
  currentTurn: turn,
578286
578306
  lastValidationTurn: this._lastBuildSuccessTurn,
578287
578307
  lastValidationCommand: this._lastBuildSuccessCommand,
578308
+ lastMutationTurn: this._lastFileWriteTurn,
578288
578309
  verifyFailureCount: this._verifyFailures.size,
578289
578310
  filesEdited: [...this._taskState.modifiedFiles.entries()].map(([path12, action]) => ({ path: path12, action }))
578290
578311
  });
@@ -580568,6 +580589,43 @@ Use the saved fact to continue the promised synthesis or next concrete step, or
580568
580589
  systemGuidance: staleEditBlock
580569
580590
  };
580570
580591
  }
580592
+ const staleRewriteBlock = this.staleEditOverwritePreflightBlock(tc.name, tc.arguments ?? {});
580593
+ if (staleRewriteBlock) {
580594
+ this.emit({
580595
+ type: "tool_call",
580596
+ toolName: tc.name,
580597
+ toolArgs: tc.arguments,
580598
+ turn,
580599
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
580600
+ });
580601
+ this.emit({
580602
+ type: "tool_result",
580603
+ toolName: tc.name,
580604
+ success: false,
580605
+ content: staleRewriteBlock.slice(0, 120),
580606
+ turn,
580607
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
580608
+ });
580609
+ this._tagSyntheticFailure({
580610
+ mode: "step_repetition",
580611
+ rationale: "full-file overwrite attempted while a stale narrow-edit repair lock is active"
580612
+ });
580613
+ if (this._completionLedger) {
580614
+ this._completionLedger = recordToolEvidence(this._completionLedger, {
580615
+ name: tc.name,
580616
+ success: false,
580617
+ outputPreview: staleRewriteBlock.slice(0, 500),
580618
+ argsKey: tc.arguments ? JSON.stringify(tc.arguments).slice(0, 300) : ""
580619
+ });
580620
+ this._saveCompletionLedgerSafe();
580621
+ }
580622
+ return {
580623
+ tc,
580624
+ output: staleRewriteBlock,
580625
+ success: false,
580626
+ systemGuidance: staleRewriteBlock
580627
+ };
580628
+ }
580571
580629
  const baseIsReadLike = ![
580572
580630
  "file_write",
580573
580631
  "file_edit",
@@ -581517,8 +581575,10 @@ Respond with EXACTLY this structure before your next tool call:
581517
581575
  if (tc.name === "shell") {
581518
581576
  const _shellCmd2 = String(tc.arguments?.["command"] ?? tc.arguments?.["cmd"] ?? "");
581519
581577
  const _declaredVerify = this._matchedDeclaredVerifyCommand(_shellCmd2);
581578
+ const _lastVerifier = this._lastVerifierResult;
581579
+ const _noTodoDirectValidation = !_declaredVerify && (this.readSessionTodos() || []).length === 0 && this._taskState.modifiedFiles.size > 0 && _lastVerifier?.outcomeClass === "verified";
581520
581580
  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);
581521
- if (_declaredVerify || _legacyGenericValidation) {
581581
+ if (_declaredVerify || _noTodoDirectValidation || _legacyGenericValidation) {
581522
581582
  this._lastBuildSuccessTurn = turn;
581523
581583
  this._lastBuildSuccessCommand = (_declaredVerify || _shellCmd2).slice(0, 200);
581524
581584
  this._truthAutoCompleteBlockedValidationTurn = -1;
@@ -584544,15 +584604,32 @@ ${marker}` : marker);
584544
584604
  return "stale_old_string";
584545
584605
  return null;
584546
584606
  }
584547
- staleEditFamilyKey(toolName, path12, errorKind, targetHash) {
584548
- return toolName + ":" + path12 + ":" + errorKind + ":" + targetHash;
584607
+ staleEditPathKey(path12) {
584608
+ const trimmed = path12.trim();
584609
+ if (!trimmed)
584610
+ return "";
584611
+ try {
584612
+ return _pathResolve(this._workingDirectory || process.cwd(), trimmed).replace(/\\/g, "/");
584613
+ } catch {
584614
+ return trimmed.replace(/\\/g, "/").replace(/^\.\/+/, "");
584615
+ }
584616
+ }
584617
+ staleEditFamilyKey(toolName, pathKey, errorKind, targetHash, latestFileHash) {
584618
+ return [
584619
+ toolName,
584620
+ pathKey || "(unknown)",
584621
+ errorKind,
584622
+ targetHash,
584623
+ latestFileHash || "unknown-file-hash"
584624
+ ].join(":");
584549
584625
  }
584550
584626
  staleEditPreflightBlock(toolName, args) {
584551
584627
  const target = this.staleEditTarget(toolName, args);
584552
584628
  if (!target)
584553
584629
  return null;
584630
+ const pathKey = this.staleEditPathKey(target.path);
584554
584631
  for (const entry of this._staleEditFamilies.values()) {
584555
- if (entry.tool !== toolName || entry.path !== target.path || entry.targetHash !== target.targetHash)
584632
+ if (entry.tool !== toolName || entry.pathKey !== pathKey || entry.targetHash !== target.targetHash)
584556
584633
  continue;
584557
584634
  const hasFreshRead = entry.lastReadTurn > entry.lastFailureTurn;
584558
584635
  const hasFreshMutation = entry.lastMutationTurn > entry.lastFailureTurn;
@@ -584569,23 +584646,65 @@ ${marker}` : marker);
584569
584646
  }
584570
584647
  return null;
584571
584648
  }
584649
+ staleEditOverwritePreflightBlock(toolName, args) {
584650
+ if (toolName !== "file_write")
584651
+ return null;
584652
+ if (process.env["OMNIUS_ALLOW_STALE_REPAIR_OVERWRITE"] === "1")
584653
+ return null;
584654
+ if (this.options.modelTier !== "small" && this.options.modelTier !== "medium")
584655
+ return null;
584656
+ if (args?.["dry_run"] === true || args?.["dryRun"] === true)
584657
+ return null;
584658
+ const path12 = this.extractPrimaryToolPath(args);
584659
+ if (!path12)
584660
+ return null;
584661
+ const pathKey = this.staleEditPathKey(path12);
584662
+ const active = [...this._staleEditFamilies.values()].filter((entry) => entry.pathKey === pathKey).sort((a2, b) => b.lastFailureTurn - a2.lastFailureTurn).find((entry) => {
584663
+ const hasFreshRead = entry.lastReadTurn > entry.lastFailureTurn;
584664
+ const hasFreshMutation = entry.lastMutationTurn > entry.lastFailureTurn;
584665
+ return !hasFreshMutation && (entry.count >= 2 || !hasFreshRead);
584666
+ });
584667
+ if (!active)
584668
+ return null;
584669
+ return [
584670
+ `[EDIT REPAIR LOCK] A recent narrow edit to ${active.path} failed because the model-visible target diverged from disk (${active.errorKind}; latest_file_hash=${active.latestFileHash || "unknown"}).`,
584671
+ `This full-file overwrite was NOT executed. A stale narrow edit must not be repaired by broad file regeneration on ${this.options.modelTier ?? "unknown"} tier models.`,
584672
+ ``,
584673
+ `Allowed next actions:`,
584674
+ `1. file_read ${active.path} once and construct file_edit from exact current text.`,
584675
+ `2. file_patch/file_edit against the latest file hash or a different target.`,
584676
+ `3. file_write with dry_run=true only to validate a full rewrite proposal without changing disk.`,
584677
+ `4. run verification if the desired change is already present, or report the explicit blocker instead of completing.`,
584678
+ ``,
584679
+ `Stale target preview: ${active.preview}`
584680
+ ].join("\n");
584681
+ }
584572
584682
  noteStaleEditGuardOutcome(toolName, args, result, turn) {
584573
584683
  const path12 = this.extractPrimaryToolPath(args);
584684
+ const pathKey = path12 ? this.staleEditPathKey(path12) : "";
584574
584685
  if (toolName === "file_read" && path12 && result.success) {
584575
584686
  for (const entry of this._staleEditFamilies.values()) {
584576
- if (entry.path === path12)
584687
+ if (entry.pathKey === pathKey)
584577
584688
  entry.lastReadTurn = turn;
584578
584689
  }
584579
584690
  return;
584580
584691
  }
584692
+ if (toolName === "file_write" && path12 && result.success && result.mutated !== false) {
584693
+ for (const [key2, entry] of this._staleEditFamilies) {
584694
+ if (entry.pathKey === pathKey)
584695
+ this._staleEditFamilies.delete(key2);
584696
+ }
584697
+ return;
584698
+ }
584581
584699
  if (!this.isEditToolName(toolName))
584582
584700
  return;
584583
584701
  const target = this.staleEditTarget(toolName, args);
584584
584702
  if (!target)
584585
584703
  return;
584704
+ const targetPathKey = this.staleEditPathKey(target.path);
584586
584705
  if (result.success && result.mutated !== false) {
584587
584706
  for (const [key2, entry] of this._staleEditFamilies) {
584588
- if (entry.path === target.path)
584707
+ if (entry.pathKey === targetPathKey)
584589
584708
  this._staleEditFamilies.delete(key2);
584590
584709
  }
584591
584710
  return;
@@ -584593,14 +584712,17 @@ ${marker}` : marker);
584593
584712
  const errorKind = this.classifyStaleEditFailure(toolName, result);
584594
584713
  if (!errorKind)
584595
584714
  return;
584596
- const key = this.staleEditFamilyKey(toolName, target.path, errorKind, target.targetHash);
584715
+ const latestFileHash = typeof result.beforeHash === "string" && result.beforeHash.trim() ? result.beforeHash.trim() : typeof result.afterHash === "string" && result.afterHash.trim() ? result.afterHash.trim() : "unknown-file-hash";
584716
+ const key = this.staleEditFamilyKey(toolName, targetPathKey, errorKind, target.targetHash, latestFileHash);
584597
584717
  const existing = this._staleEditFamilies.get(key);
584598
584718
  this._staleEditFamilies.set(key, {
584599
584719
  count: (existing?.count ?? 0) + 1,
584600
584720
  path: target.path,
584721
+ pathKey: targetPathKey,
584601
584722
  tool: toolName,
584602
584723
  errorKind,
584603
584724
  targetHash: target.targetHash,
584725
+ latestFileHash,
584604
584726
  lastFailureTurn: turn,
584605
584727
  lastReadTurn: existing?.lastReadTurn ?? -1,
584606
584728
  lastMutationTurn: existing?.lastMutationTurn ?? -1,
@@ -652150,7 +652272,7 @@ function getModelTier(modelName) {
652150
652272
  if (sizeMatch) {
652151
652273
  const size = parseInt(sizeMatch[1], 10);
652152
652274
  if (size >= 30) return "large";
652153
- if (size >= 8) return "medium";
652275
+ if (size >= 14) return "medium";
652154
652276
  return "small";
652155
652277
  }
652156
652278
  if (/\b(small|mini|nano|tiny)\b/.test(m2)) return "small";
@@ -725784,6 +725906,7 @@ async function runCommand2(opts, config) {
725784
725906
  await runJson(opts.task, mergedConfig, opts.repoPath);
725785
725907
  } else {
725786
725908
  await runWithTUI(opts.task, mergedConfig, opts.repoPath);
725909
+ if (shouldForceSingleRunExit()) process.exit(0);
725787
725910
  }
725788
725911
  } else {
725789
725912
  await startInteractive(mergedConfig, opts.repoPath);
@@ -725883,6 +726006,12 @@ function shouldForceJsonExit() {
725883
726006
  return false;
725884
726007
  return true;
725885
726008
  }
726009
+ function shouldForceSingleRunExit() {
726010
+ if (process.env["OMNIUS_SINGLE_RUN_NO_FORCE_EXIT"] === "1") return false;
726011
+ if (process.env["VITEST"] === "true" || process.env["NODE_ENV"] === "test")
726012
+ return false;
726013
+ return true;
726014
+ }
725886
726015
  function extractSummary(captured) {
725887
726016
  const all2 = captured.join("");
725888
726017
  const match = all2.match(/task_complete.*?summary[:\s]*["']?([^"'\n]+)/i);
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.376",
3
+ "version": "1.0.377",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "omnius",
9
- "version": "1.0.376",
9
+ "version": "1.0.377",
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.376",
3
+ "version": "1.0.377",
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",