omnius 1.0.480 → 1.0.482

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
@@ -576512,16 +576512,16 @@ var init_focusSupervisor = __esm({
576512
576512
  if (prior.requiredNextAction === "read_authoritative_target" && input.cachedResult && (input.duplicateHitCount ?? 0) >= Math.max(1, this.repeatGateMax - 1)) {
576513
576513
  const deadlockDirective = this.setDirective({
576514
576514
  turn: input.turn,
576515
- state: "terminal_incomplete",
576516
- reason: `read target is repeat-gated (${input.duplicateHitCount} hits); directive ${prior.id} cannot be satisfied without fresh reads; report blocked with evidence`,
576517
- requiredNextAction: "report_incomplete",
576515
+ state: "forced_replan",
576516
+ reason: `read target is repeat-gated (${input.duplicateHitCount} hits); directive ${prior.id} cannot be satisfied without fresh reads; TRIAGE instead of stalling — pivot approach or web_search the blocker`,
576517
+ requiredNextAction: "creative_pivot_or_research",
576518
576518
  forbiddenActionFamilies: []
576519
576519
  });
576520
576520
  return this.block(deadlockDirective, [
576521
- "[FOCUS SUPERVISOR: DEADLOCK]",
576521
+ "[FOCUS SUPERVISOR: DEADLOCK — TRIAGE]",
576522
576522
  `Directive ${prior.id} (${prior.requiredNextAction}) requires reading evidence that is repeat-gated (${input.duplicateHitCount} identical reads).`,
576523
- "The model cannot satisfy this directive because the repeat gate blocks re-reads, and other actions are forbidden by the current directive.",
576524
- "Report incomplete/blocked with the concrete evidence you have, and describe what additional access would break the deadlock."
576523
+ "This exact path is blocked, but the task is NOT over. Do not report incomplete.",
576524
+ "TRIAGE: pivot to a fundamentally different approach, or web_search the exact blocker to find another route, then act on it."
576525
576525
  ].join("\n"), false);
576526
576526
  }
576527
576527
  if (strict && prior.ignoredCount >= 1) {
@@ -576533,9 +576533,11 @@ var init_focusSupervisor = __esm({
576533
576533
  }
576534
576534
  const directive = this.setDirective({
576535
576535
  turn: input.turn,
576536
- state: terminal ? "terminal_incomplete" : ignoredManyTimes ? "verify_or_block" : "single_next_action",
576537
- reason: terminal ? `model ignored ${this.ignoredDirectiveStreak} focus directives with no satisfying recovery action; report incomplete with the blocker and evidence` : ignoredManyTimes ? `model ignored ${this.ignoredDirectiveStreak} focus directives; take the required recovery action before trying another variant` : `model ignored prior directive ${prior.id}; ${prior.reason}`,
576538
- requiredNextAction: terminal ? "report_incomplete" : prior.requiredNextAction,
576536
+ // TRIAGE replaces terminal: after many ignored directives the model is
576537
+ // stuck on ONE approach steer it to pivot/research, never to abandon.
576538
+ state: terminal ? "forced_replan" : ignoredManyTimes ? "verify_or_block" : "single_next_action",
576539
+ reason: terminal ? `model ignored ${this.ignoredDirectiveStreak} focus directives; this approach is exhausted — TRIAGE: pivot to a fundamentally different method or web_search the exact blocker, do NOT report incomplete` : ignoredManyTimes ? `model ignored ${this.ignoredDirectiveStreak} focus directives; take the required recovery action before trying another variant` : `model ignored prior directive ${prior.id}; ${prior.reason}`,
576540
+ requiredNextAction: terminal ? "creative_pivot_or_research" : prior.requiredNextAction,
576539
576541
  forbiddenActionFamilies: uniqueLimited(accumulatedFamilies)
576540
576542
  });
576541
576543
  this.lastIgnoredDirectiveTurn = input.turn;
@@ -576544,7 +576546,7 @@ var init_focusSupervisor = __esm({
576544
576546
  `Required next action: ${directive.requiredNextAction}.`,
576545
576547
  `Blocked action family: ${family}.`,
576546
576548
  actionReasonSummary(input.actionReason),
576547
- directive.requiredNextAction === "report_incomplete" ? "Stop trying tool variants. Report incomplete/blocked with the concrete evidence." : "Take the required next action before trying another variant."
576549
+ directive.requiredNextAction === "creative_pivot_or_research" ? "Stop trying variants of what failed. The task is NOT over — pivot to a fundamentally different approach or web_search the exact blocker, then act." : "Take the required next action before trying another variant."
576548
576550
  ].filter(Boolean).join("\n"), false);
576549
576551
  }
576550
576552
  }
@@ -576759,14 +576761,21 @@ var init_focusSupervisor = __esm({
576759
576761
  forbiddenActionFamilies: ["task_complete"]
576760
576762
  });
576761
576763
  }
576764
+ /**
576765
+ * TRIAGE (replaces terminal-incomplete). A task is never abandoned. At the
576766
+ * inflection where the old design would report incomplete, steer the model to
576767
+ * a creative pivot or online research instead: the trajectory that failed is
576768
+ * dead, but the TASK is not. The turn cap remains the ultimate backstop, so
576769
+ * this cannot loop forever. Kept the method name so all callers are unchanged.
576770
+ */
576762
576771
  markTerminalIncomplete(reason, turn) {
576763
576772
  if (!this.enabled)
576764
576773
  return;
576765
576774
  this.setDirective({
576766
576775
  turn,
576767
- state: "terminal_incomplete",
576768
- reason,
576769
- requiredNextAction: "report_incomplete",
576776
+ state: "forced_replan",
576777
+ reason: `${reason} — do NOT report incomplete and do NOT repeat a variant of what failed. TRIAGE: web_search the exact error/blocker to find how it is solved, OR pivot to a fundamentally different approach you have not tried, then act on it.`,
576778
+ requiredNextAction: "creative_pivot_or_research",
576770
576779
  forbiddenActionFamilies: ["brute_force"]
576771
576780
  });
576772
576781
  }
@@ -576989,8 +576998,8 @@ var init_convergence_breaker = __esm({
576989
576998
  tripped: true,
576990
576999
  totalRounds,
576991
577000
  family,
576992
- reason: `failure family "${family}" has not converged after ${totalRounds} rounds (>= ${this.abandonRound}); this trajectory is dead — stop iterating and report incomplete or regenerate from the locked contract${suffix}`,
576993
- recommendedAction: "report_incomplete"
577001
+ reason: `failure family "${family}" has not converged after ${totalRounds} rounds (>= ${this.abandonRound}); this trajectory is dead — do NOT report incomplete and do NOT repeat it. TRIAGE: pivot to a fundamentally different approach, or web_search the exact failure to find another route, then act on it${suffix}`,
577002
+ recommendedAction: "creative_pivot_or_research"
576994
577003
  };
576995
577004
  case "stalled":
576996
577005
  return {
@@ -577345,7 +577354,7 @@ function languageOf(p2) {
577345
577354
  return "typescript";
577346
577355
  return "unknown";
577347
577356
  }
577348
- var JsonConvergenceStore, EDIT_TOOLS, LongHaulComponents, FIELD_STOPWORDS;
577357
+ var JsonConvergenceStore, EDIT_TOOLS, LOCKED_CONTRACT_FILE, LongHaulComponents, FIELD_STOPWORDS;
577349
577358
  var init_longhaul_integration = __esm({
577350
577359
  "packages/orchestrator/dist/longhaul-integration.js"() {
577351
577360
  "use strict";
@@ -577397,6 +577406,7 @@ var init_longhaul_integration = __esm({
577397
577406
  }
577398
577407
  };
577399
577408
  EDIT_TOOLS = /* @__PURE__ */ new Set(["file_edit", "file_patch", "batch_edit"]);
577409
+ LOCKED_CONTRACT_FILE = "locked-contract.json";
577400
577410
  LongHaulComponents = class {
577401
577411
  convergenceBreaker;
577402
577412
  adaptiveEdit;
@@ -577411,7 +577421,10 @@ var init_longhaul_integration = __esm({
577411
577421
  locked = /* @__PURE__ */ new Map();
577412
577422
  /** WO-11: provenance — which file each locked symbol was declared in. */
577413
577423
  lockedSource = /* @__PURE__ */ new Map();
577424
+ /** Persisted contract output path (relative to stateDir). */
577425
+ lockedContractPath;
577414
577426
  constructor(options2) {
577427
+ this.lockedContractPath = path7.join(options2.stateDir, LOCKED_CONTRACT_FILE);
577415
577428
  this.convergenceBreaker = new ConvergenceBreaker({
577416
577429
  ...options2.convergence,
577417
577430
  // Persist the cliff across sessions only when persistence is enabled;
@@ -577483,6 +577496,7 @@ var init_longhaul_integration = __esm({
577483
577496
  this.lockedSource.set(s2.name, input.path);
577484
577497
  }
577485
577498
  }
577499
+ this.persistLockedContract();
577486
577500
  return this.locked.size;
577487
577501
  } catch {
577488
577502
  return this.locked.size;
@@ -577492,6 +577506,22 @@ var init_longhaul_integration = __esm({
577492
577506
  lockedContract() {
577493
577507
  return { symbols: [...this.locked.values()] };
577494
577508
  }
577509
+ /**
577510
+ * Persist the locked contract to `.omnius/locked-contract.json` so sub-agent
577511
+ * fixers can read it as their canonical type reference. Fault-tolerant —
577512
+ * never throws; on error the in-memory contract remains available for
577513
+ * orchestrator-side gates.
577514
+ */
577515
+ persistLockedContract() {
577516
+ try {
577517
+ const contract = this.lockedContract();
577518
+ if (contract.symbols.length === 0)
577519
+ return;
577520
+ fs6.mkdirSync(path7.dirname(this.lockedContractPath), { recursive: true });
577521
+ fs6.writeFileSync(this.lockedContractPath, JSON.stringify(contract, null, 2));
577522
+ } catch {
577523
+ }
577524
+ }
577495
577525
  /** WO-11: map of locked symbol name → declaring file (for per-symbol units). */
577496
577526
  symbolSources() {
577497
577527
  return new Map(this.lockedSource);
@@ -577576,17 +577606,53 @@ var init_longhaul_integration = __esm({
577576
577606
  const symbol3 = top.symbol ? ` symbol \`${top.symbol}\`` : "";
577577
577607
  const kind = top.kind.replace(/_/g, " ");
577578
577608
  const contractHint = top.symbol && this.lockedSource.has(top.symbol) ? ` The locked contract for \`${top.symbol}\` lives in ${this.lockedSource.get(top.symbol)} — match it exactly.` : "";
577609
+ const persistHint = this.locked.size > 0 ? ` The canonical locked contract is at .omnius/${LOCKED_CONTRACT_FILE} — read it before editing and match its type names exactly.` : "";
577579
577610
  return `[DELEGATE — build is feedback, not the task] The build reported a stable diagnostic set. Do NOT re-run the build and do NOT keep editing in this context. Delegate ONE isolated fix to a seeded sub-agent, then re-run the build to test:
577580
577611
  sub_agent({
577581
577612
  subagent_type: "fixer",
577582
577613
  description: "fix ${top.symbol ?? file}",
577583
- prompt: "In ${file}, resolve the ${kind}${symbol3}. Read ONLY ${file} (and the file that declares${symbol3 || " the offending symbol"}). Make the minimal edit to satisfy the contract. Do not touch unrelated files. Report a one-line outcome.${contractHint}"
577614
+ prompt: "In ${file}, resolve the ${kind}${symbol3}. Read ONLY ${file} (and the file that declares${symbol3 || " the offending symbol"}). Make the minimal edit to satisfy the contract. Do not touch unrelated files. Report a one-line outcome.${contractHint}${persistHint}"
577584
577615
  })
577585
577616
  The sub-agent works in its own small context; when it folds back, run the build once to verify the diagnostic count dropped, then delegate the next one. This is fan-out/converge — keep THIS context on trajectory, not on the raw fix.`;
577586
577617
  } catch {
577587
577618
  return null;
577588
577619
  }
577589
577620
  }
577621
+ /**
577622
+ * B/auto-delegation: the STRUCTURED form of buildDelegationDirective. Returns
577623
+ * the exact args for a `sub_agent(fixer)` call scoped to the top diagnostic, so
577624
+ * the orchestrator can dispatch the delegation ITSELF when the model refuses to
577625
+ * (measured: 0 sub_agent calls across 89 frames of a live run despite the
577626
+ * directive firing). Returns null when the output names no concrete unit.
577627
+ */
577628
+ buildDelegationCall(output) {
577629
+ try {
577630
+ const diags = parseCompilerDiagnostics(String(output || ""));
577631
+ const structural = diags.filter((d2) => d2.kind === "signature_mismatch" || d2.kind === "duplicate_definition" || d2.kind === "unknown_member" || d2.kind === "unknown_symbol" || d2.kind === "type_error");
577632
+ const top = structural.find((d2) => d2.file && d2.symbol) ?? structural.find((d2) => d2.file) ?? diags.find((d2) => d2.file) ?? structural[0] ?? diags[0];
577633
+ if (!top || !top.file)
577634
+ return null;
577635
+ const file = top.file;
577636
+ const symbol3 = top.symbol;
577637
+ const kind = top.kind.replace(/_/g, " ");
577638
+ const declSrc = symbol3 ? this.lockedSource.get(symbol3) : void 0;
577639
+ const focusFiles = [
577640
+ file,
577641
+ ...declSrc && declSrc !== file ? [declSrc] : []
577642
+ ];
577643
+ const lockedRef = this.locked.size > 0 ? ` Also read .omnius/${LOCKED_CONTRACT_FILE} for the canonical type contract and match it exactly.` : "";
577644
+ const prompt = `In ${file}, resolve the ${kind}${symbol3 ? ` for \`${symbol3}\`` : ""}. Read ONLY ${focusFiles.join(" and ")}. Make the minimal edit to satisfy the contract. Build once to verify the error is gone. Report a one-line outcome.` + (declSrc ? ` The contract for \`${symbol3}\` lives in ${declSrc} — match it exactly.` : "") + lockedRef;
577645
+ return {
577646
+ description: `fix ${symbol3 ?? file}`,
577647
+ prompt,
577648
+ focusFiles,
577649
+ exitCriterion: `${file} compiles${symbol3 ? ` and \`${symbol3}\` matches the contract` : ""}.`,
577650
+ symbol: symbol3
577651
+ };
577652
+ } catch {
577653
+ return null;
577654
+ }
577655
+ }
577590
577656
  diagnosticGuidance(output) {
577591
577657
  try {
577592
577658
  const diags = parseCompilerDiagnostics(String(output || ""));
@@ -577621,7 +577687,10 @@ The sub-agent works in its own small context; when it folds back, run the build
577621
577687
  try {
577622
577688
  return decideCompaction(input);
577623
577689
  } catch {
577624
- return { compact: input.pressureRatio >= 0.85, reason: "fallback threshold" };
577690
+ return {
577691
+ compact: input.pressureRatio >= 0.85,
577692
+ reason: "fallback threshold"
577693
+ };
577625
577694
  }
577626
577695
  }
577627
577696
  /** WO-5: validate a compaction preserved pinned invariants (Slipstream). */
@@ -579682,7 +579751,7 @@ RECOVERY: cd to the directory containing '${file}', run a plain install with no
579682
579751
 
579683
579752
  // packages/orchestrator/dist/agenticRunner.js
579684
579753
  import { existsSync as _fsExistsSync, readFileSync as _fsReadFileSync, writeFileSync as _fsWriteFileSync, appendFileSync as _fsAppendFileSync, unlinkSync as _fsUnlinkSync, mkdirSync as _fsMkdirSync, statSync as _fsStatSync, readdirSync as _fsReaddirSync } from "node:fs";
579685
- import { execFile as _execFile, spawn as _spawn } from "node:child_process";
579754
+ import { execFile as _execFile, execSync as _execSync, spawn as _spawn } from "node:child_process";
579686
579755
  import { createHash as _createHash } from "node:crypto";
579687
579756
  import { join as _pathJoin, relative as _pathRelative, resolve as _pathResolve } from "node:path";
579688
579757
  import { tmpdir as _osTmpdir } from "node:os";
@@ -580535,9 +580604,7 @@ var init_agenticRunner = __esm({
580535
580604
  "web_fetch",
580536
580605
  "tool_search"
580537
580606
  ]);
580538
- STATE_UPDATE_ACTION_REASON_SYNTHESIS_TOOLS = /* @__PURE__ */ new Set([
580539
- "todo_write"
580540
- ]);
580607
+ STATE_UPDATE_ACTION_REASON_SYNTHESIS_TOOLS = /* @__PURE__ */ new Set(["todo_write"]);
580541
580608
  TOOL_ACTION_REASON_SCHEMA = {
580542
580609
  type: "object",
580543
580610
  description: "Compact public action contract for this exact tool call. Do not include hidden chain-of-thought; use concise task-state facts.",
@@ -580564,13 +580631,7 @@ var init_agenticRunner = __esm({
580564
580631
  description: "Classify the action scope. Use targeted_patch for constrained edits; full_file_rewrite only for deliberate whole-file replacement."
580565
580632
  }
580566
580633
  },
580567
- required: [
580568
- "task_anchor",
580569
- "intent",
580570
- "evidence",
580571
- "expected_result",
580572
- "scope"
580573
- ]
580634
+ required: ["task_anchor", "intent", "evidence", "expected_result", "scope"]
580574
580635
  };
580575
580636
  SYSTEM_PROMPT = loadPrompt("agentic/system-large.md");
580576
580637
  SYSTEM_PROMPT_MEDIUM = loadPrompt("agentic/system-medium.md");
@@ -581074,6 +581135,14 @@ var init_agenticRunner = __esm({
581074
581135
  _longHaul = null;
581075
581136
  /** WO-11: decomposition modules (files) stashed for contract-enriched todo trees. */
581076
581137
  _decompModules = [];
581138
+ /** Auto-delegation: last failing build/verify output, for parsing the top unit. */
581139
+ _lastBuildOutput = null;
581140
+ /** Convergence gate: pre-fold error count for verifying fixer progress. */
581141
+ _preFoldErrorCount = null;
581142
+ /** Convergence gate: the fixer description being gated (for status messages). */
581143
+ _preFoldFixerDescription = null;
581144
+ /** Auto-delegation: directive ids we've already auto-delegated for (once each). */
581145
+ _autoDelegatedDirectiveIds = /* @__PURE__ */ new Set();
581077
581146
  _focusTerminalLedgerRecorded = false;
581078
581147
  // Generic, cross-session failure→resolution learning: learns the token-level
581079
581148
  // change that turned a failed command into a working one (e.g. python→python3)
@@ -581457,9 +581526,13 @@ ${parts.join("\n")}
581457
581526
  return "file_patch, batch_edit, file_edit, or hash-guarded file_write on a different supported target";
581458
581527
  case "run_verification":
581459
581528
  return "shell running the verification/runtime command";
581529
+ case "delegate_isolated_fix":
581530
+ return "sub_agent(subagent_type='fixer', ...) delegating the top diagnostic to an isolated worker";
581531
+ case "creative_pivot_or_research":
581532
+ return "a FUNDAMENTALLY different approach: web_search the exact error/blocker to find how it is solved, or pivot to a method you have NOT tried — not a variant of what failed, and NOT task_complete";
581460
581533
  case "report_blocked":
581461
581534
  case "report_incomplete":
581462
- return "task_complete with the concrete blocker/incomplete evidence";
581535
+ return "a fundamentally different approach or web_search the blocker — do not report incomplete";
581463
581536
  default:
581464
581537
  return "choose the narrowest tool that advances the current card";
581465
581538
  }
@@ -588573,41 +588646,27 @@ TASK: ${scrubbedTask}` : scrubbedTask;
588573
588646
  "Evidence:",
588574
588647
  evidenceFeedback
588575
588648
  ].join("\n");
588576
- this._completionIncompleteVerification = {
588577
- reason,
588578
- summary: incompleteSummary
588579
- };
588649
+ void incompleteSummary;
588580
588650
  this._focusSupervisor?.markTerminalIncomplete(reason, turn);
588581
- const terminalDirective = this._focusSupervisor?.snapshot().directive;
588582
- if (terminalDirective) {
588651
+ const triageDirective = this._focusSupervisor?.snapshot().directive;
588652
+ if (triageDirective) {
588583
588653
  this._emitFocusSupervisorEvent({
588584
- decision: "terminal_incomplete",
588585
- state: terminalDirective.state,
588586
- directiveId: terminalDirective.id,
588587
- reason: terminalDirective.reason,
588588
- requiredNextAction: terminalDirective.requiredNextAction,
588654
+ decision: triageDirective.state,
588655
+ state: triageDirective.state,
588656
+ directiveId: triageDirective.id,
588657
+ reason: triageDirective.reason,
588658
+ requiredNextAction: triageDirective.requiredNextAction,
588589
588659
  blockedTool: "task_complete",
588590
588660
  turn
588591
588661
  });
588592
588662
  }
588593
588663
  messages2.push({
588594
588664
  role: "system",
588595
- content: `[INCOMPLETE VERIFICATION TERMINAL STATE] task_complete was held ${this._completionHoldState.count} times by the same completion gate without new evidence. The run is ending as incomplete_verification, not completed. Report the missing evidence plainly.`
588665
+ content: `[TRIAGE] task_complete was held ${this._completionHoldState.count} times without new evidence you keep claiming done but cannot prove it. Do NOT report incomplete. The task is not over: get the missing evidence a DIFFERENT way — web_search the exact blocker (${reason.slice(0, 160)}), or pivot to an approach you have not tried, then produce the concrete proof and only THEN call task_complete.`
588596
588666
  });
588597
588667
  this.emit({
588598
588668
  type: "status",
588599
- content: `completion gates ended run as incomplete_verification after ${this._completionHoldState.count} repeated holds: ${reason}`,
588600
- turn,
588601
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
588602
- });
588603
- this.emit({
588604
- type: "adversary_reaction",
588605
- adversary: {
588606
- class: "guidance",
588607
- shortText: "Completion gate terminal incomplete",
588608
- confidence: 0.9,
588609
- details: `Same completion gate held task_complete ${this._completionHoldState.count}x; ending incomplete_verification instead of completing.`
588610
- },
588669
+ content: `[TRIAGE] completion gate held task_complete ${this._completionHoldState.count}x without evidence — steering to pivot/research instead of ending incomplete: ${reason.slice(0, 120)}`,
588611
588670
  turn,
588612
588671
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
588613
588672
  });
@@ -591488,7 +591547,8 @@ ${cachedResult}`,
591488
591547
  blockedTool: focusDecision.kind === "block_tool_call" ? tc.name : void 0,
591489
591548
  turn
591490
591549
  });
591491
- if (focusDecision.kind === "inject_guidance") {
591550
+ if (focusDecision.kind === "block_tool_call" && this._maybeAutoDelegate(tc, focusDecision.directive, messages2, turn)) {
591551
+ } else if (focusDecision.kind === "inject_guidance") {
591492
591552
  pushSoftInjection("system", focusDecision.message);
591493
591553
  } else if (!repeatShortCircuit) {
591494
591554
  repeatShortCircuit = {
@@ -593041,6 +593101,74 @@ Evidence: ${evidencePreview}`.slice(0, 500);
593041
593101
  });
593042
593102
  }
593043
593103
  }
593104
+ if ((tc.name === "sub_agent" || tc.name === "agent") && result.success) {
593105
+ const foldRaw = String(result.output ?? "").replace(/\s+/g, " ").trim();
593106
+ this.emit({
593107
+ type: "status",
593108
+ content: `[CONVERGE] isolated worker folded back${foldRaw ? `: ${foldRaw.slice(0, 200)}` : ""} — orchestrator resumes trajectory (verify with a build).`,
593109
+ turn,
593110
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
593111
+ });
593112
+ }
593113
+ if ((tc.name === "sub_agent" || tc.name === "agent") && result.success && this._preFoldErrorCount != null && this._preFoldFixerDescription) {
593114
+ const desc = this._preFoldFixerDescription;
593115
+ const preCount = this._preFoldErrorCount;
593116
+ const foldOutput = String(result.output ?? result.error ?? "");
593117
+ const postSignal = failureProgressSignal(foldOutput);
593118
+ const cwd4 = this.authoritativeWorkingDirectory();
593119
+ let accepted = false;
593120
+ if (postSignal == null) {
593121
+ accepted = /\b(?:verified|clean|passed|succeeded|0\s*error)\b/i.test(foldOutput);
593122
+ } else {
593123
+ accepted = postSignal < preCount;
593124
+ }
593125
+ if (accepted) {
593126
+ try {
593127
+ _execSync("git stash drop", {
593128
+ cwd: cwd4,
593129
+ stdio: "pipe",
593130
+ timeout: 5e3
593131
+ });
593132
+ } catch {
593133
+ }
593134
+ this.emit({
593135
+ type: "status",
593136
+ content: `[CONVERGE-ACCEPT] fixer for "${desc}" — errors ${preCount}→${postSignal != null ? postSignal : "0"}, changes kept`,
593137
+ turn,
593138
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
593139
+ });
593140
+ } else {
593141
+ try {
593142
+ _execSync("git checkout -- .", {
593143
+ cwd: cwd4,
593144
+ stdio: "pipe",
593145
+ timeout: 1e4
593146
+ });
593147
+ _execSync("git clean -fd", {
593148
+ cwd: cwd4,
593149
+ stdio: "pipe",
593150
+ timeout: 1e4
593151
+ });
593152
+ } catch {
593153
+ }
593154
+ try {
593155
+ _execSync("git stash pop", {
593156
+ cwd: cwd4,
593157
+ stdio: "pipe",
593158
+ timeout: 1e4
593159
+ });
593160
+ } catch {
593161
+ }
593162
+ this.emit({
593163
+ type: "status",
593164
+ content: `[CONVERGE-REJECT] fixer for "${desc}" — errors ${preCount}→${postSignal != null ? postSignal : "?"}, rolled back`,
593165
+ turn,
593166
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
593167
+ });
593168
+ }
593169
+ this._preFoldErrorCount = null;
593170
+ this._preFoldFixerDescription = null;
593171
+ }
593044
593172
  try {
593045
593173
  const lh = this._longHaul;
593046
593174
  if (lh) {
@@ -593068,7 +593196,10 @@ ${rec.guidance}` : rec.guidance;
593068
593196
 
593069
593197
  ${dir}` : dir;
593070
593198
  }
593071
- lh.maybeLockContract({ path: editPath, content: writtenContent });
593199
+ lh.maybeLockContract({
593200
+ path: editPath,
593201
+ content: writtenContent
593202
+ });
593072
593203
  const specDir = lh.specGateGuidance({
593073
593204
  path: editPath,
593074
593205
  content: writtenContent
@@ -593080,6 +593211,9 @@ ${specDir}` : specDir;
593080
593211
  }
593081
593212
  }
593082
593213
  if (!result.success) {
593214
+ if (isVerificationCommand(tc.name, result.output ?? result.error ?? "")) {
593215
+ this._lastBuildOutput = result.output ?? result.error ?? "";
593216
+ }
593083
593217
  const diag = lh.diagnosticGuidance(result.output ?? result.error ?? "");
593084
593218
  if (diag) {
593085
593219
  runtimeSystemGuidance = runtimeSystemGuidance ? `${runtimeSystemGuidance}
@@ -596838,6 +596972,67 @@ Actions: (1) list_directory on the parent directory to see what's there, (2) Che
596838
596972
  * Replaces both assistant messages AND their associated tool-result
596839
596973
  * messages in the turn range [startTurn, currentTurn].
596840
596974
  */
596975
+ /**
596976
+ * AUTO-DELEGATION — make the fan-out actually happen.
596977
+ *
596978
+ * The model will not emit `sub_agent` on its own even when the focus supervisor
596979
+ * requires delegation: on a live run we measured 0 sub_agent calls across 89
596980
+ * frames while the `delegate_isolated_fix` directive was firing every stuck
596981
+ * build. A directive TELLS; it does not DO. So when a delegate directive blocks
596982
+ * the model's call, the ORCHESTRATOR dispatches the fixer itself: it rewrites
596983
+ * the blocked call into the synthesized `sub_agent(fixer)` for the top
596984
+ * diagnostic, which then executes through the normal path — the isolated child
596985
+ * runs in its own small curated frame and folds a one-line result back. Guarded
596986
+ * to once per directive id, so one stuck build produces exactly one delegation,
596987
+ * never a spawn storm.
596988
+ *
596989
+ * Emits a [FAN-OUT] status marking the context switch (main frame size -> the
596990
+ * curated worker frame) so the operator can observe the isolation boundary.
596991
+ *
596992
+ * Returns true if it rewrote `tc` (the caller must let it EXECUTE, not noop it).
596993
+ */
596994
+ _maybeAutoDelegate(tc, directive, messages2, turn) {
596995
+ if (directive.requiredNextAction !== "delegate_isolated_fix")
596996
+ return false;
596997
+ if (tc.name === "sub_agent" || tc.name === "agent")
596998
+ return false;
596999
+ if (!this._longHaul || !this._lastBuildOutput)
597000
+ return false;
597001
+ if (this._autoDelegatedDirectiveIds.has(directive.id))
597002
+ return false;
597003
+ if (!this.tools.has("sub_agent"))
597004
+ return false;
597005
+ const call = this._longHaul.buildDelegationCall(this._lastBuildOutput);
597006
+ if (!call)
597007
+ return false;
597008
+ this._preFoldErrorCount = failureProgressSignal(this._lastBuildOutput) ?? null;
597009
+ this._preFoldFixerDescription = call.description;
597010
+ try {
597011
+ _execSync('git stash push -m "pre-fixer" --include-untracked', {
597012
+ cwd: this.authoritativeWorkingDirectory(),
597013
+ stdio: "pipe",
597014
+ timeout: 1e4
597015
+ });
597016
+ } catch {
597017
+ }
597018
+ this._autoDelegatedDirectiveIds.add(directive.id);
597019
+ const parentTok = estimateMessagesTokens2(messages2);
597020
+ this.emit({
597021
+ type: "status",
597022
+ content: `[FAN-OUT] model did not delegate — orchestrator auto-dispatching an isolated fixer for "${call.description}". Main context ~${parentTok.toLocaleString()} tok -> curated worker frame (${call.focusFiles.length} focus file(s): ${call.focusFiles.join(", ")}).`,
597023
+ turn,
597024
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
597025
+ });
597026
+ tc.name = "sub_agent";
597027
+ tc.arguments = {
597028
+ subagent_type: "fixer",
597029
+ description: call.description,
597030
+ prompt: call.prompt,
597031
+ relevant_files: call.focusFiles,
597032
+ exit_criterion: call.exitCriterion
597033
+ };
597034
+ return true;
597035
+ }
596841
597036
  /**
596842
597037
  * Staleness-based evidence retirement (WO-4 realized; operator's microcompaction
596843
597038
  * goal). The sibling `_evictCompletedTodoMessages` only fires when a todo
@@ -596864,7 +597059,7 @@ Actions: (1) list_directory on the parent directory to see what's there, (2) Che
596864
597059
  * evidence remains on disk (`.omnius/tool-results/`) and re-materialisable.
596865
597060
  */
596866
597061
  _retireStaleEvidenceInPlace(messages2, currentTurn) {
596867
- if (process.env["OMNIUS_EVIDENCE_RETIREMENT"] !== "1")
597062
+ if (process.env["OMNIUS_DISABLE_EVIDENCE_RETIREMENT"] === "1")
596868
597063
  return;
596869
597064
  const keepRecent = Math.max(0, Number(process.env["OMNIUS_EVIDENCE_KEEP_TURNS"] ?? 2));
596870
597065
  const minChars = Math.max(512, Number(process.env["OMNIUS_EVIDENCE_MIN_CHARS"] ?? 2e3));
@@ -607577,7 +607772,7 @@ var init_subagent_prompt = __esm({
607577
607772
  "If the fix requires touching more than 2 files, STOP and report that the",
607578
607773
  "unit is larger than one fixer — the orchestrator will re-decompose it."
607579
607774
  ],
607580
- foldFormat: 'task_complete(summary="<file>: <what you changed> — build <verified|still failing on: X>")',
607775
+ foldFormat: 'task_complete(summary="<file>: <what you changed> — build <verified|still failing on: X> — contract <matched|diverged on: Y>")',
607581
607776
  mutates: true
607582
607777
  },
607583
607778
  explore: {
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.480",
3
+ "version": "1.0.482",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "omnius",
9
- "version": "1.0.480",
9
+ "version": "1.0.482",
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.480",
3
+ "version": "1.0.482",
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",