omnius 1.0.535 → 1.0.537

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
@@ -6981,7 +6981,7 @@ var init_file_write = __esm({
6981
6981
  init_text_encoding();
6982
6982
  FileWriteTool = class {
6983
6983
  name = "file_write";
6984
- description = "Create new files or deliberately replace small, empty, or placeholder files; use file_edit/file_patch for local changes. For content with heavy quoting, raw JSON, control characters, or large full-file payloads, pass content_base64 instead of shell heredocs/cat/tee.";
6984
+ description = "Create new files or deliberately replace small, empty, or placeholder files; use file_edit/file_patch for local changes. Existing-file replacement requires overwrite=true plus expected_hash from a fresh file_read; never use this as a fallback after a failed targeted edit. For content with heavy quoting, raw JSON, control characters, or large full-file payloads, pass content_base64 instead of shell heredocs/cat/tee.";
6985
6985
  parameters = {
6986
6986
  type: "object",
6987
6987
  properties: {
@@ -296557,8 +296557,8 @@ var init_cron_agent = __esm({
296557
296557
  }
296558
296558
  const lines = [];
296559
296559
  const formatJob = (job, scopeLabel, isThisProject) => {
296560
- const statusIcon = job.status === "active" ? "●" : job.status === "completed" ? "✔" : job.status === "paused" ? "⏸" : "✖";
296561
- lines.push(` ${statusIcon} [${job.id}] ${job.status.toUpperCase()} [${scopeLabel}]`);
296560
+ const statusIcon2 = job.status === "active" ? "●" : job.status === "completed" ? "✔" : job.status === "paused" ? "⏸" : "✖";
296561
+ lines.push(` ${statusIcon2} [${job.id}] ${job.status.toUpperCase()} [${scopeLabel}]`);
296562
296562
  lines.push(` Goal: ${job.goal.slice(0, 80)}${job.goal.length > 80 ? "..." : ""}`);
296563
296563
  lines.push(` Schedule: ${job.scheduleDescription}`);
296564
296564
  lines.push(` Runs: ${job.runCount}${job.maxRuns > 0 ? `/${job.maxRuns}` : ""}`);
@@ -553281,6 +553281,7 @@ function spawnFullSubAgent(task, opts, onOutput, onComplete) {
553281
553281
  child.stderr?.on("data", (chunk) => {
553282
553282
  const text2 = chunk.toString();
553283
553283
  outputBuffer.push(...text2.split("\n").filter((l2) => l2.length > 0));
553284
+ onOutput?.(text2);
553284
553285
  });
553285
553286
  child.on("exit", (code8) => {
553286
553287
  clearInterval(heartbeatTimer);
@@ -567114,13 +567115,103 @@ function normalizeShellCommand(command) {
567114
567115
  function splitConjunctiveVerifyCommand(command) {
567115
567116
  return normalizeShellCommand(command).split(/\s+&&\s+/).map((part) => part.trim()).filter(Boolean);
567116
567117
  }
567118
+ function stripVerifierFallbackSuffix(command) {
567119
+ let quote2 = null;
567120
+ for (let i2 = 0; i2 < command.length - 1; i2++) {
567121
+ const ch = command[i2];
567122
+ if (quote2) {
567123
+ if (ch === quote2 && command[i2 - 1] !== "\\")
567124
+ quote2 = null;
567125
+ continue;
567126
+ }
567127
+ if (ch === "'" || ch === '"') {
567128
+ quote2 = ch;
567129
+ continue;
567130
+ }
567131
+ if (ch === "|" && command[i2 + 1] === "|") {
567132
+ return command.slice(0, i2).trim();
567133
+ }
567134
+ }
567135
+ return command.trim();
567136
+ }
567137
+ function stageHeadProgram(stage2) {
567138
+ const tokens = stage2.trim().split(/\s+/);
567139
+ let i2 = 0;
567140
+ while (i2 < tokens.length) {
567141
+ const token = tokens[i2];
567142
+ if (/^[A-Za-z_][A-Za-z0-9_]*=/.test(token)) {
567143
+ i2++;
567144
+ continue;
567145
+ }
567146
+ const base3 = token.replace(/^["']|["']$/g, "").split("/").pop() ?? token;
567147
+ if (STAGE_PREFIX_PROGRAMS.has(base3)) {
567148
+ i2++;
567149
+ if (base3 === "timeout" && /^[0-9]+[smhd]?$/.test(tokens[i2] ?? ""))
567150
+ i2++;
567151
+ continue;
567152
+ }
567153
+ return base3.toLowerCase();
567154
+ }
567155
+ return null;
567156
+ }
567157
+ function commandIsPureReadOnlyPipeline(command) {
567158
+ const stages = [];
567159
+ let current = "";
567160
+ let quote2 = null;
567161
+ const raw = command.trim();
567162
+ if (!raw)
567163
+ return false;
567164
+ for (let i2 = 0; i2 < raw.length; i2++) {
567165
+ const ch = raw[i2];
567166
+ if (quote2) {
567167
+ current += ch;
567168
+ if (ch === quote2 && raw[i2 - 1] !== "\\")
567169
+ quote2 = null;
567170
+ continue;
567171
+ }
567172
+ if (ch === "'" || ch === '"') {
567173
+ quote2 = ch;
567174
+ current += ch;
567175
+ continue;
567176
+ }
567177
+ if (ch === "&" && raw[i2 + 1] === "&") {
567178
+ stages.push(current);
567179
+ current = "";
567180
+ i2++;
567181
+ continue;
567182
+ }
567183
+ if (ch === "|") {
567184
+ stages.push(current);
567185
+ current = "";
567186
+ if (raw[i2 + 1] === "|")
567187
+ i2++;
567188
+ continue;
567189
+ }
567190
+ if (ch === ";") {
567191
+ stages.push(current);
567192
+ current = "";
567193
+ continue;
567194
+ }
567195
+ if (ch === "$" && raw[i2 + 1] === "(")
567196
+ return false;
567197
+ if (ch === "`")
567198
+ return false;
567199
+ current += ch;
567200
+ }
567201
+ stages.push(current);
567202
+ const meaningful = stages.map((s2) => s2.trim()).filter(Boolean);
567203
+ if (meaningful.length === 0)
567204
+ return false;
567205
+ return meaningful.every((stage2) => {
567206
+ const head = stageHeadProgram(stage2);
567207
+ return head !== null && PURE_READER_PROGRAMS.has(head);
567208
+ });
567209
+ }
567117
567210
  function commandReliablySatisfiesVerifyCommand(observedCommand, verifyCommand) {
567118
567211
  const observed = normalizeShellCommand(observedCommand);
567119
- const expected = normalizeShellCommand(verifyCommand);
567212
+ const expected = normalizeShellCommand(stripVerifierFallbackSuffix(verifyCommand));
567120
567213
  if (!observed || !expected)
567121
567214
  return false;
567122
- if (expected.includes(" || "))
567123
- return false;
567124
567215
  if (observed === expected)
567125
567216
  return true;
567126
567217
  if (observed.startsWith(`${expected} && `) && !observed.includes(" || ")) {
@@ -567141,9 +567232,93 @@ function verifyCommandSatisfiedByShellHistory(verifyCommand, history) {
567141
567232
  return false;
567142
567233
  return parts.every((part) => successful.some((entry) => commandReliablySatisfiesVerifyCommand(entry.command, part)));
567143
567234
  }
567235
+ var PURE_READER_PROGRAMS, STAGE_PREFIX_PROGRAMS;
567144
567236
  var init_verificationCommand = __esm({
567145
567237
  "packages/orchestrator/dist/verificationCommand.js"() {
567146
567238
  "use strict";
567239
+ PURE_READER_PROGRAMS = /* @__PURE__ */ new Set([
567240
+ "cat",
567241
+ "tac",
567242
+ "tail",
567243
+ "head",
567244
+ "less",
567245
+ "more",
567246
+ "grep",
567247
+ "egrep",
567248
+ "fgrep",
567249
+ "rg",
567250
+ "ag",
567251
+ "awk",
567252
+ "gawk",
567253
+ "sed",
567254
+ "gsed",
567255
+ "sort",
567256
+ "uniq",
567257
+ "wc",
567258
+ "cut",
567259
+ "tr",
567260
+ "column",
567261
+ "echo",
567262
+ "printf",
567263
+ "ls",
567264
+ "dir",
567265
+ "find",
567266
+ "fd",
567267
+ "stat",
567268
+ "file",
567269
+ "strings",
567270
+ "hexdump",
567271
+ "xxd",
567272
+ "od",
567273
+ "jq",
567274
+ "yq",
567275
+ "tee",
567276
+ "dirname",
567277
+ "basename",
567278
+ "readlink",
567279
+ "realpath",
567280
+ "pwd",
567281
+ "date",
567282
+ "true",
567283
+ "false",
567284
+ "test",
567285
+ "type",
567286
+ "which",
567287
+ "whoami",
567288
+ "env",
567289
+ "printenv",
567290
+ "sleep",
567291
+ "cd",
567292
+ "diff",
567293
+ "cmp",
567294
+ "md5sum",
567295
+ "sha1sum",
567296
+ "sha256sum",
567297
+ "du",
567298
+ "df",
567299
+ "nl",
567300
+ "paste",
567301
+ "join",
567302
+ "comm",
567303
+ "expand",
567304
+ "unexpand",
567305
+ "fold",
567306
+ "rev",
567307
+ "seq",
567308
+ "xargs"
567309
+ ]);
567310
+ STAGE_PREFIX_PROGRAMS = /* @__PURE__ */ new Set([
567311
+ "sudo",
567312
+ "command",
567313
+ "builtin",
567314
+ "nice",
567315
+ "ionice",
567316
+ "time",
567317
+ "timeout",
567318
+ "nohup",
567319
+ "stdbuf",
567320
+ "unbuffer"
567321
+ ]);
567147
567322
  }
567148
567323
  });
567149
567324
 
@@ -586374,6 +586549,8 @@ var init_agenticRunner = __esm({
586374
586549
  _completionCaveat = null;
586375
586550
  _completionLedger = null;
586376
586551
  _staleEditFamilies = /* @__PURE__ */ new Map();
586552
+ /** Semantic retry counter for blocked full-file writes (payload-independent). */
586553
+ _blockedFullWriteAttempts = /* @__PURE__ */ new Map();
586377
586554
  _lastReadTurnByPathKey = /* @__PURE__ */ new Map();
586378
586555
  _recentSuccessfulReplacements = [];
586379
586556
  // ── WO-AM-01/04/10: Associative memory stores ──
@@ -589283,8 +589460,9 @@ Pick the SMALLEST concrete deliverable from the spec — typically the project e
589283
589460
  return this._declaredVerifierCommand;
589284
589461
  }
589285
589462
  const diagnostics = parseCompilerDiagnostics(output);
589286
- if (diagnostics.length > 0 && this._shellResultLooksLikeVerification({ command: trimmed }, { success: false, output })) {
589287
- return trimmed;
589463
+ if (diagnostics.length > 0 && !commandIsPureReadOnlyPipeline(trimmed)) {
589464
+ const latched = stripVerifierFallbackSuffix(trimmed);
589465
+ return latched || trimmed;
589288
589466
  }
589289
589467
  return null;
589290
589468
  }
@@ -589294,19 +589472,68 @@ Pick the SMALLEST concrete deliverable from the spec — typically the project e
589294
589472
  return false;
589295
589473
  return commandReliablySatisfiesVerifyCommand(command.trim(), state.verifierCommand);
589296
589474
  }
589475
+ /**
589476
+ * When a tool result was triaged for size (full payload saved to
589477
+ * `.omnius/tool-results/<hash>.txt`), append the saved payload so
589478
+ * diagnostics parsing sees the complete output. Without this, a large
589479
+ * failed build's `file:line:col: error:` lines can be cut out of the
589480
+ * triage envelope and the run never registers as a verifier run.
589481
+ * Best effort and bounded — never throws into the loop.
589482
+ */
589483
+ _expandTriagedPayloadForDiagnostics(text2) {
589484
+ if (!text2 || !text2.includes(TRIAGE_SAVED_PATH_MARKER))
589485
+ return text2;
589486
+ const MAX_PAYLOAD_BYTES = 1e6;
589487
+ const MAX_FILES2 = 2;
589488
+ const extras = [];
589489
+ let searchFrom = 0;
589490
+ for (let i2 = 0; i2 < MAX_FILES2; i2++) {
589491
+ const markerAt = text2.indexOf(TRIAGE_SAVED_PATH_MARKER, searchFrom);
589492
+ if (markerAt === -1)
589493
+ break;
589494
+ const pathStart = markerAt + TRIAGE_SAVED_PATH_MARKER.length;
589495
+ const restOfLine = text2.slice(pathStart, text2.indexOf("\n", pathStart) === -1 ? void 0 : text2.indexOf("\n", pathStart));
589496
+ searchFrom = pathStart;
589497
+ const endIdx = (() => {
589498
+ const emDash = restOfLine.indexOf(" — ");
589499
+ if (emDash !== -1)
589500
+ return emDash;
589501
+ const bracket = restOfLine.indexOf("]");
589502
+ return bracket !== -1 ? bracket : restOfLine.length;
589503
+ })();
589504
+ const savedPath = restOfLine.slice(0, endIdx).trim();
589505
+ if (!savedPath)
589506
+ continue;
589507
+ try {
589508
+ if (!_fsExistsSync(savedPath))
589509
+ continue;
589510
+ const stat9 = _fsStatSync(savedPath);
589511
+ if (!stat9.isFile())
589512
+ continue;
589513
+ const raw = _fsReadFileSync(savedPath, "utf8");
589514
+ extras.push(raw.length > MAX_PAYLOAD_BYTES ? raw.slice(0, MAX_PAYLOAD_BYTES) : raw);
589515
+ } catch {
589516
+ }
589517
+ }
589518
+ if (extras.length === 0)
589519
+ return text2;
589520
+ return `${text2}
589521
+ ${extras.join("\n")}`;
589522
+ }
589297
589523
  _observeCompileVerifierResult(input) {
589298
589524
  const diagnostics = rankCompilerDiagnostics(parseCompilerDiagnostics(input.output));
589525
+ const verifierCommand = stripVerifierFallbackSuffix(input.verifierCommand) || input.verifierCommand.trim();
589299
589526
  const previousDiagnostics = this._lastDeclaredVerifierDiagnostics;
589300
- this._declaredVerifierCommand = input.verifierCommand;
589527
+ this._declaredVerifierCommand = verifierCommand;
589301
589528
  this._lastDeclaredVerifierOutput = input.output;
589302
589529
  this._lastDeclaredVerifierDiagnostics = diagnostics;
589303
589530
  if (!this._compileFixLoop && diagnostics.length === 0)
589304
589531
  return null;
589305
- const verifierFingerprint = compileFixVerifierFingerprint(input.verifierCommand);
589532
+ const verifierFingerprint = compileFixVerifierFingerprint(verifierCommand);
589306
589533
  const existingCards = this._compileFixLoop?.cards ?? [];
589307
589534
  const cards = diagnostics.length > 0 ? buildCompileFixCards({
589308
589535
  diagnostics,
589309
- verifierCommand: input.verifierCommand,
589536
+ verifierCommand,
589310
589537
  turn: input.turn,
589311
589538
  existingCards
589312
589539
  }) : existingCards;
@@ -589315,22 +589542,25 @@ Pick the SMALLEST concrete deliverable from the spec — typically the project e
589315
589542
  existingCards,
589316
589543
  observedCards: cards,
589317
589544
  diagnostics,
589318
- verifierCommand: input.verifierCommand,
589545
+ verifierCommand,
589319
589546
  turn: input.turn,
589320
589547
  verifierPassed: input.success && diagnostics.length === 0
589321
589548
  });
589322
589549
  this._compileFixLoop = {
589323
589550
  active: diagnostics.length > 0 || nextCards.some((card) => card.status !== "verified"),
589324
- verifierCommand: input.verifierCommand,
589551
+ verifierCommand,
589325
589552
  verifierFingerprint,
589326
589553
  verifierDirtySinceTurn: null,
589327
589554
  lastVerifierRunTurn: input.turn,
589328
589555
  lastVerifierPassedTurn: input.success && diagnostics.length === 0 ? input.turn : null,
589329
589556
  lastMutationTurn: this._compileFixLoop?.lastMutationTurn ?? null,
589330
- cards: nextCards
589557
+ cards: nextCards,
589558
+ // A live verifier run resolves the gate's demand — the block streak
589559
+ // is over regardless of pass/fail.
589560
+ preflightBlockStreak: 0
589331
589561
  };
589332
589562
  this._mirrorCompileFixCardsToWorkboard(nextCards, {
589333
- command: input.verifierCommand,
589563
+ command: verifierCommand,
589334
589564
  success: input.success && diagnostics.length === 0,
589335
589565
  turn: input.turn,
589336
589566
  beforeDiagnosticCount: previousDiagnostics.length,
@@ -589342,7 +589572,7 @@ Pick the SMALLEST concrete deliverable from the spec — typically the project e
589342
589572
  if (input.success && diagnostics.length === 0) {
589343
589573
  this.emit({
589344
589574
  type: "status",
589345
- content: `compile_error_fix_loop: verifier passed (${input.verifierCommand}); compile cards verified`,
589575
+ content: `compile_error_fix_loop: verifier passed (${verifierCommand}); compile cards verified`,
589346
589576
  turn: input.turn,
589347
589577
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
589348
589578
  });
@@ -589361,7 +589591,7 @@ Pick the SMALLEST concrete deliverable from the spec — typically the project e
589361
589591
  }
589362
589592
  this.emit({
589363
589593
  type: "status",
589364
- content: `compile_error_fix_loop_started: verifierCommand=${input.verifierCommand}; cardId=${top.id}; diagnosticFingerprint=${top.diagnostic.fingerprint}; afterDiagnosticCount=${diagnostics.length}`,
589594
+ content: `compile_error_fix_loop_started: verifierCommand=${verifierCommand}; cardId=${top.id}; diagnosticFingerprint=${top.diagnostic.fingerprint}; afterDiagnosticCount=${diagnostics.length}`,
589365
589595
  turn: input.turn,
589366
589596
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
589367
589597
  });
@@ -589561,14 +589791,7 @@ Pick the SMALLEST concrete deliverable from the spec — typically the project e
589561
589791
  if (!state?.active)
589562
589792
  return;
589563
589793
  const normalized = paths.map((p2) => this._normalizeEvidencePath(p2)).filter(Boolean);
589564
- const owned = state.cards.flatMap((card) => card.ownedFiles);
589565
- const todos = this.readSessionTodos() || [];
589566
- const artifacts = todos.flatMap((todo) => Array.isArray(todo.declaredArtifacts) ? todo.declaredArtifacts.filter((p2) => typeof p2 === "string") : []);
589567
- const relevant = normalized.length === 0 || normalized.some((pathValue) => {
589568
- if (pathValue.startsWith(".omnius/"))
589569
- return false;
589570
- return owned.some((ownedPath) => this._pathsOverlapForVerifier(pathValue, ownedPath)) || artifacts.some((artifactPath) => this._pathsOverlapForVerifier(pathValue, artifactPath)) || /\.(ts|tsx|js|jsx|mjs|cjs|py|go|rs|java|kt|c|cc|cpp|cxx|h|hpp|hh|hxx|ino)$/i.test(pathValue);
589571
- });
589794
+ const relevant = normalized.length === 0 || this._compileFixPathsTouchProjectSources(normalized, state);
589572
589795
  if (!relevant)
589573
589796
  return;
589574
589797
  state.verifierDirtySinceTurn = turn;
@@ -589595,6 +589818,24 @@ Pick the SMALLEST concrete deliverable from the spec — typically the project e
589595
589818
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
589596
589819
  });
589597
589820
  }
589821
+ /**
589822
+ * True when any of the given normalized paths touches project source:
589823
+ * files owned by compile-fix cards, declared todo artifacts, or files
589824
+ * with a source-code extension. Build side effects (logs, artifacts,
589825
+ * `.omnius/` bookkeeping) do not count.
589826
+ */
589827
+ _compileFixPathsTouchProjectSources(normalizedPaths, state) {
589828
+ const owned = state.cards.flatMap((card) => card.ownedFiles);
589829
+ const todos = this.readSessionTodos() || [];
589830
+ const artifacts = todos.flatMap((todo) => Array.isArray(todo.declaredArtifacts) ? todo.declaredArtifacts.filter((p2) => typeof p2 === "string") : []);
589831
+ return normalizedPaths.some((pathValue) => {
589832
+ if (pathValue.startsWith(".omnius/"))
589833
+ return false;
589834
+ return owned.some((ownedPath) => this._pathsOverlapForVerifier(pathValue, ownedPath)) || artifacts.some((artifactPath) => this._pathsOverlapForVerifier(pathValue, artifactPath)) || /\.(ts|tsx|js|jsx|mjs|cjs|py|go|rs|java|kt|c|cc|cpp|cxx|h|hpp|hh|hxx|ino)$/i.test(pathValue);
589835
+ });
589836
+ }
589837
+ /** Consecutive preflight blocks before the gate yields instead of blocking. */
589838
+ static COMPILE_FIX_GATE_YIELD_AFTER = 3;
589598
589839
  _compileFixLoopPreflightBlock(toolName, args, turn, shellLikelyMutatesFilesystem) {
589599
589840
  const state = this._compileFixLoop;
589600
589841
  if (!state?.active)
@@ -589605,29 +589846,62 @@ Pick the SMALLEST concrete deliverable from the spec — typically the project e
589605
589846
  if (toolName === "shell") {
589606
589847
  const command = String(args["command"] ?? args["cmd"] ?? "").trim();
589607
589848
  if (commandReliablySatisfiesVerifyCommand(command, state.verifierCommand)) {
589849
+ state.preflightBlockStreak = 0;
589608
589850
  return null;
589609
589851
  }
589610
589852
  if (!shellLikelyMutatesFilesystem)
589611
589853
  return null;
589854
+ const extraction = extractShellMutationPaths(command, {
589855
+ workingDir: this.authoritativeWorkingDirectory()
589856
+ });
589857
+ const mutationPaths = extraction.paths.map((p2) => this._normalizeEvidencePath(p2)).filter(Boolean);
589858
+ if (mutationPaths.length === 0 || !this._compileFixPathsTouchProjectSources(mutationPaths, state)) {
589859
+ return null;
589860
+ }
589612
589861
  } else if (!this._isProjectEditTool(toolName)) {
589613
589862
  return null;
589614
589863
  }
589864
+ const yieldAfter = _AgenticRunner.COMPILE_FIX_GATE_YIELD_AFTER;
589865
+ const streak = (state.preflightBlockStreak ?? 0) + 1;
589866
+ if (streak > yieldAfter) {
589867
+ state.preflightBlockStreak = 0;
589868
+ this.emit({
589869
+ type: "status",
589870
+ content: `compile_error_verifier_dirty: gate yielded to ${toolName} after ${yieldAfter} consecutive blocks at turn ${turn}`,
589871
+ turn,
589872
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
589873
+ });
589874
+ return {
589875
+ kind: "yield",
589876
+ notice: [
589877
+ `[COMPILE FIX GATE YIELDED — verifier still required]`,
589878
+ `The verifier-required gate blocked ${yieldAfter} consecutive tool calls and is yielding so work can continue.`,
589879
+ `Verifier evidence is still stale. Run the verifier as your next evidence step:`,
589880
+ ` ${state.verifierCommand}`,
589881
+ `Any real build/test command whose output shows current compiler diagnostics is also accepted as the live verifier.`,
589882
+ `task_complete remains blocked until a verifier run passes after the last mutation.`
589883
+ ].join("\n")
589884
+ };
589885
+ }
589886
+ state.preflightBlockStreak = streak;
589615
589887
  const message2 = [
589616
589888
  `[COMPILE ERROR FIX LOOP BLOCKED — declared verifier required]`,
589617
589889
  `A compile-fix card was patched, so the next mutation/evidence step must be the live verifier.`,
589618
- `verifierCommand: ${state.verifierCommand}`,
589890
+ `Run this now: ${state.verifierCommand}`,
589891
+ `Any real build/test command whose output shows current compiler diagnostics is also accepted.`,
589619
589892
  `dirtySinceTurn: ${state.verifierDirtySinceTurn}`,
589620
589893
  `lastMutationTurn: ${state.lastMutationTurn}`,
589621
589894
  `lastVerifierRunTurn: ${state.lastVerifierRunTurn}`,
589622
- `blockedTool: ${toolName}`
589895
+ `blockedTool: ${toolName}`,
589896
+ `consecutiveBlocks: ${streak}/${yieldAfter} (gate yields after ${yieldAfter})`
589623
589897
  ].join("\n");
589624
589898
  this.emit({
589625
589899
  type: "status",
589626
- content: `compile_error_verifier_dirty: blocked ${toolName} at turn ${turn}`,
589900
+ content: `compile_error_verifier_dirty: blocked ${toolName} at turn ${turn} (${streak}/${yieldAfter})`,
589627
589901
  turn,
589628
589902
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
589629
589903
  });
589630
- return message2;
589904
+ return { kind: "block", message: message2 };
589631
589905
  }
589632
589906
  _compileFixLoopCompletionBlocker(turn) {
589633
589907
  const state = this._compileFixLoop;
@@ -589985,6 +590259,8 @@ ${modelVisible}` : modelVisible || result.error || displayOutput || "";
589985
590259
  if (!command.trim())
589986
590260
  return false;
589987
590261
  void result;
590262
+ if (commandIsPureReadOnlyPipeline(command))
590263
+ return false;
589988
590264
  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(command);
589989
590265
  }
589990
590266
  _shouldSuppressCompletionDiscoveryEvidence(toolName, result, targetPaths) {
@@ -594502,6 +594778,7 @@ Respond with your assessment, then take action.`;
594502
594778
  this._lastDeclaredVerifierOutput = null;
594503
594779
  this._lastDeclaredVerifierDiagnostics = [];
594504
594780
  this._staleEditFamilies.clear();
594781
+ this._blockedFullWriteAttempts.clear();
594505
594782
  this._lastReadTurnByPathKey.clear();
594506
594783
  this._recentSuccessfulReplacements = [];
594507
594784
  this._lastWorldStateTurn = -1;
@@ -595882,7 +596159,7 @@ Respond with EXACTLY this structure before your next tool call:
595882
596159
  PICK: <number 1-3>
595883
596160
  WHY: <one sentence>
595884
596161
  FALSIFICATION: <observable signal that would refute the pick>
595885
- NEXT ACTION: <a single creative edit — file_write / file_edit / batch_edit>`;
596162
+ NEXT ACTION: <a single targeted edit — file_edit / file_patch / batch_edit; file_write only for a verified-new file>`;
595886
596163
  messages2.push({ role: "system", content: _replan60 });
595887
596164
  stagnationCooldownUntilTurn = turn + REG60_COOLDOWN_TURNS;
595888
596165
  const _tel60 = this._describeTopClusterTelemetry();
@@ -596143,7 +596420,7 @@ If this matches your current shape, try it before continuing.`
596143
596420
  ] : [
596144
596421
  `Pick ONE of these for your next response:`,
596145
596422
  ``,
596146
- ` (a) PRODUCE: emit a file_write / file_edit / file_patch that creates or changes project content. Even a partial draft of the next planned file is progress. Use shell only for commands/tests/system operations, not as a workaround for failed edit-tool encoding.`,
596423
+ ` (a) PRODUCE: emit a targeted file_edit / file_patch / batch_edit that creates or changes project content. Use file_write only after verifying the target is new/placeholder and never as recovery for a blocked existing-file write. Use shell only for commands/tests/system operations, not as a workaround for failed edit-tool encoding.`,
596147
596424
  ``,
596148
596425
  ` (b) ERROR-INFORMED LOCAL TRIAGE: anchor on the freshest local failure, identify the implicated file/path/symbol/command, then make one targeted local move instead of broad exploration.`,
596149
596426
  ``,
@@ -597859,7 +598136,7 @@ Corrective action: try a different approach first: read relevant files, adjust a
597859
598136
  `A REG-61 FIRST-EDIT NUDGE was issued earlier and has not yet been satisfied. The directive asks you to prioritize a creative edit. You issued '${tc.name}' instead, which is a read/explore/shell call.`,
597860
598137
  ``,
597861
598138
  `This call was ALLOWED through (needed context should never be blocked), but try to make a creative edit next:`,
597862
- ` • file_write — create a new file`,
598139
+ ` • file_write — create a verified-new file only (never use it to repair an existing target)`,
597863
598140
  ` • file_edit — modify an existing file (find/replace)`,
597864
598141
  ` • batch_edit — multiple find/replace edits in one call`,
597865
598142
  ` • file_patch — apply a version-checked line-range patch`,
@@ -598024,7 +598301,7 @@ Read the current file if needed, make a different concrete edit, or move to veri
598024
598301
  systemGuidance: staleBlockOutput
598025
598302
  };
598026
598303
  }
598027
- const staleRewriteBlock = this.staleEditOverwritePreflightBlock(tc.name, tc.arguments ?? {});
598304
+ const staleRewriteBlock = this.staleEditOverwritePreflightBlock(tc.name, tc.arguments ?? {}, turn);
598028
598305
  if (staleRewriteBlock) {
598029
598306
  const focusDecision2 = this._focusSupervisor?.evaluateProposedCall({
598030
598307
  turn,
@@ -598420,8 +598697,10 @@ ${cachedResult}`,
598420
598697
  };
598421
598698
  }
598422
598699
  }
598423
- const compileLoopPreflightBlock = !repeatShortCircuit ? this._compileFixLoopPreflightBlock(tc.name, tc.arguments ?? {}, turn, shellLikelyMutatesFilesystem) : null;
598424
- if (compileLoopPreflightBlock) {
598700
+ const compileLoopPreflight = !repeatShortCircuit ? this._compileFixLoopPreflightBlock(tc.name, tc.arguments ?? {}, turn, shellLikelyMutatesFilesystem) : null;
598701
+ if (compileLoopPreflight?.kind === "yield") {
598702
+ pushSoftInjection("system", compileLoopPreflight.notice);
598703
+ } else if (compileLoopPreflight) {
598425
598704
  this.emit({
598426
598705
  type: "tool_call",
598427
598706
  toolName: tc.name,
@@ -598433,7 +598712,7 @@ ${cachedResult}`,
598433
598712
  type: "tool_result",
598434
598713
  toolName: tc.name,
598435
598714
  success: false,
598436
- content: compileLoopPreflightBlock.slice(0, 120),
598715
+ content: compileLoopPreflight.message.slice(0, 120),
598437
598716
  turn,
598438
598717
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
598439
598718
  });
@@ -598443,9 +598722,9 @@ ${cachedResult}`,
598443
598722
  });
598444
598723
  return {
598445
598724
  tc,
598446
- output: compileLoopPreflightBlock,
598725
+ output: compileLoopPreflight.message,
598447
598726
  success: false,
598448
- systemGuidance: compileLoopPreflightBlock
598727
+ systemGuidance: compileLoopPreflight.message
598449
598728
  };
598450
598729
  }
598451
598730
  this.emit({
@@ -600037,8 +600316,7 @@ ${structuralGuardGuidance}` : structuralGuardGuidance;
600037
600316
  }
600038
600317
  if (tc.name === "shell" && result.runtimeAuthored !== true) {
600039
600318
  const shellCommand = String(tc.arguments?.["command"] ?? tc.arguments?.["cmd"] ?? "");
600040
- const compileOutput = `${result.output ?? ""}
600041
- ${result.error ?? ""}`;
600319
+ const compileOutput = this._expandTriagedPayloadForDiagnostics([result.output, result.llmContent, result.error].filter((part) => typeof part === "string" && part.length > 0).join("\n"));
600042
600320
  const verifierCommand = this._declaredVerifierCommandForShell(shellCommand, compileOutput);
600043
600321
  if (verifierCommand) {
600044
600322
  const compileGuidance = this._observeCompileVerifierResult({
@@ -603032,6 +603310,29 @@ ${marker}` : marker);
603032
603310
  const path16 = this.extractPrimaryToolPath(args);
603033
603311
  if (!path16)
603034
603312
  return null;
603313
+ const pathKey = this.staleEditPathKey(path16);
603314
+ const active = [...this._staleEditFamilies.values()].filter((entry) => entry.pathKey === pathKey).sort((a2, b) => b.lastFailureTurn - a2.lastFailureTurn).find((entry) => {
603315
+ const hasFreshRead = entry.lastReadTurn > entry.lastFailureTurn;
603316
+ const hasFreshMutation = entry.lastMutationTurn > entry.lastFailureTurn;
603317
+ return !hasFreshMutation && (entry.count >= 2 || !hasFreshRead);
603318
+ });
603319
+ if (active) {
603320
+ const tier = this.options.modelTier ?? "large";
603321
+ if (tier !== "small" && tier !== "medium")
603322
+ return null;
603323
+ return [
603324
+ `[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"}).`,
603325
+ `This full-file overwrite was NOT executed. A stale narrow edit must not be repaired by broad file regeneration; preserve a constrained edit path until fresh target evidence is used.`,
603326
+ ``,
603327
+ `Allowed next actions:`,
603328
+ `1. file_read ${active.path} once and construct file_edit from exact current text.`,
603329
+ `2. file_patch/file_edit against the latest file hash or a different target.`,
603330
+ `3. file_write with dry_run=true only to validate a full rewrite proposal without changing disk.`,
603331
+ `4. run verification if the desired change is already present, or report the explicit blocker instead of completing.`,
603332
+ ``,
603333
+ `Stale target preview: ${active.preview}`
603334
+ ].join("\n");
603335
+ }
603035
603336
  let exists2 = false;
603036
603337
  try {
603037
603338
  const st = _fsStatSync(this._absoluteToolPath(path16), {
@@ -603043,6 +603344,15 @@ ${marker}` : marker);
603043
603344
  }
603044
603345
  if (!exists2)
603045
603346
  return null;
603347
+ const overwrite = args["overwrite"] === true || args["overwriteExisting"] === true;
603348
+ if (!overwrite) {
603349
+ return [
603350
+ "[FULL FILE REWRITE CONTRACT]",
603351
+ `file_write would overwrite existing file ${path16}, but overwrite=true is missing.`,
603352
+ "This call was not executed. Prefer file_edit/file_patch for a local change.",
603353
+ "If a deliberate whole-file replacement is truly required, first file_read the current file and retry with overwrite=true and expected_hash equal to that read's sha256."
603354
+ ].join("\n");
603355
+ }
603046
603356
  if (!this._toolCallUsesFreshFileReadEvidence(toolName, args)) {
603047
603357
  const fresh = this._freshReadHashForEditPath(path16);
603048
603358
  return [
@@ -603156,16 +603466,13 @@ ${marker}` : marker);
603156
603466
  }
603157
603467
  return null;
603158
603468
  }
603159
- staleEditOverwritePreflightBlock(toolName, args) {
603469
+ staleEditOverwritePreflightBlock(toolName, args, turn = 0) {
603160
603470
  if (toolName !== "file_write")
603161
603471
  return null;
603162
603472
  if (process.env["OMNIUS_ALLOW_STALE_REPAIR_OVERWRITE"] === "1")
603163
603473
  return null;
603164
603474
  if (args?.["dry_run"] === true || args?.["dryRun"] === true)
603165
603475
  return null;
603166
- const tier = this.options.modelTier ?? "large";
603167
- if (tier !== "small" && tier !== "medium")
603168
- return null;
603169
603476
  const path16 = this.extractPrimaryToolPath(args);
603170
603477
  if (!path16)
603171
603478
  return null;
@@ -603175,19 +603482,49 @@ ${marker}` : marker);
603175
603482
  const hasFreshMutation = entry.lastMutationTurn > entry.lastFailureTurn;
603176
603483
  return !hasFreshMutation && (entry.count >= 2 || !hasFreshRead);
603177
603484
  });
603178
- if (!active)
603485
+ if (active) {
603486
+ const tier = this.options.modelTier ?? "large";
603487
+ if (tier !== "small" && tier !== "medium")
603488
+ return null;
603489
+ return [
603490
+ `[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"}).`,
603491
+ `This full-file overwrite was NOT executed. A stale narrow edit must not be repaired by broad file regeneration; preserve a constrained edit path until fresh target evidence is used.`,
603492
+ ``,
603493
+ `Allowed next actions:`,
603494
+ `1. file_read ${active.path} once and construct file_edit from exact current text.`,
603495
+ `2. file_patch/file_edit against the latest file hash or a different target.`,
603496
+ `3. file_write with dry_run=true only to validate a full rewrite proposal without changing disk.`,
603497
+ `4. run verification if the desired change is already present, or report the explicit blocker instead of completing.`,
603498
+ ``,
603499
+ `Stale target preview: ${active.preview}`
603500
+ ].join("\n");
603501
+ }
603502
+ let exists2 = false;
603503
+ try {
603504
+ const st = _fsStatSync(this._absoluteToolPath(path16), {
603505
+ throwIfNoEntry: false
603506
+ });
603507
+ exists2 = !!st && st.isFile();
603508
+ } catch {
603509
+ exists2 = false;
603510
+ }
603511
+ if (!exists2)
603512
+ return null;
603513
+ const overwrite = args?.["overwrite"] === true || args?.["overwriteExisting"] === true;
603514
+ const hasFreshContract = overwrite && this._toolCallUsesFreshFileReadEvidence(toolName, args ?? {});
603515
+ if (hasFreshContract) {
603516
+ this._blockedFullWriteAttempts.delete(pathKey);
603517
+ return null;
603518
+ }
603519
+ const previous = this._blockedFullWriteAttempts.get(pathKey);
603520
+ const count = (previous?.count ?? 0) + 1;
603521
+ this._blockedFullWriteAttempts.set(pathKey, { count, lastTurn: turn });
603522
+ if (count < 2)
603179
603523
  return null;
603180
603524
  return [
603181
- `[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"}).`,
603182
- `This full-file overwrite was NOT executed. A stale narrow edit must not be repaired by broad file regeneration; preserve a constrained edit path until fresh target evidence is used.`,
603183
- ``,
603184
- `Allowed next actions:`,
603185
- `1. file_read ${active.path} once and construct file_edit from exact current text.`,
603186
- `2. file_patch/file_edit against the latest file hash or a different target.`,
603187
- `3. file_write with dry_run=true only to validate a full rewrite proposal without changing disk.`,
603188
- `4. run verification if the desired change is already present, or report the explicit blocker instead of completing.`,
603189
- ``,
603190
- `Stale target preview: ${active.preview}`
603525
+ `[FULL FILE WRITE LOOP BLOCKED] ${path16} has already received ${count} blocked full-file write attempts.`,
603526
+ `This call was NOT executed, even if the replacement payload changed. Do not call file_write again for this path until a fresh file_read is completed.`,
603527
+ `Next action: use file_read ${path16}, then prefer file_patch/file_edit for the local change. Only an intentional whole-file replacement may use file_write with overwrite=true and expected_hash from that fresh read.`
603191
603528
  ].join("\n");
603192
603529
  }
603193
603530
  editReversalPreflightBlock(toolName, args, turn) {
@@ -603281,7 +603618,9 @@ ${marker}` : marker);
603281
603618
  noteStaleEditGuardOutcome(toolName, args, result, turn) {
603282
603619
  const path16 = this.extractPrimaryToolPath(args);
603283
603620
  const pathKey = path16 ? this.staleEditPathKey(path16) : "";
603284
- if (toolName === "file_read" && path16 && result.success) {
603621
+ const isFreshRead = toolName === "file_read" && path16 && result.success && result.runtimeAuthored !== true;
603622
+ if (isFreshRead) {
603623
+ this._blockedFullWriteAttempts.delete(pathKey);
603285
603624
  for (const entry of this._staleEditFamilies.values()) {
603286
603625
  if (entry.pathKey === pathKey)
603287
603626
  entry.lastReadTurn = turn;
@@ -603289,6 +603628,7 @@ ${marker}` : marker);
603289
603628
  return;
603290
603629
  }
603291
603630
  if (toolName === "file_write" && path16 && this._isRealProjectMutation(toolName, result)) {
603631
+ this._blockedFullWriteAttempts.delete(pathKey);
603292
603632
  for (const [key2, entry] of this._staleEditFamilies) {
603293
603633
  if (entry.pathKey === pathKey)
603294
603634
  this._staleEditFamilies.delete(key2);
@@ -603302,6 +603642,7 @@ ${marker}` : marker);
603302
603642
  return;
603303
603643
  const targetPathKey = this.staleEditPathKey(target.path);
603304
603644
  if (this._isRealProjectMutation(toolName, result) || result.alreadyApplied === true) {
603645
+ this._blockedFullWriteAttempts.delete(targetPathKey);
603305
603646
  for (const [key2, entry] of this._staleEditFamilies) {
603306
603647
  if (entry.pathKey === targetPathKey)
603307
603648
  this._staleEditFamilies.delete(key2);
@@ -640617,6 +640958,50 @@ var init_dist9 = __esm({
640617
640958
  });
640618
640959
 
640619
640960
  // packages/cli/src/tui/stageIndicator.ts
640961
+ function stageForToolName(toolName) {
640962
+ const name10 = String(toolName ?? "").trim().toLowerCase();
640963
+ if (name10 === "file_read" || name10 === "structured_read") return "reading";
640964
+ if (name10 === "grep_search" || name10 === "glob_find" || name10 === "find_files" || name10 === "web_search" || name10 === "web_fetch" || name10 === "web_crawl")
640965
+ return "searching";
640966
+ if (name10 === "file_write" || name10 === "file_edit" || name10 === "file_patch" || name10 === "batch_edit" || name10 === "structured_file")
640967
+ return "writing";
640968
+ if (name10 === "shell" || name10 === "shell_async" || name10 === "run_tests" || name10 === "repl_exec")
640969
+ return "building";
640970
+ return "tool_call";
640971
+ }
640972
+ function stageForAgentEvent(event) {
640973
+ switch (event.type) {
640974
+ case "tool_call":
640975
+ return { stage: stageForToolName(event.toolName), detail: event.toolName };
640976
+ case "tool_result":
640977
+ return event.success === false ? {
640978
+ stage: "failed",
640979
+ detail: event.toolName ? `${event.toolName} failed` : void 0
640980
+ } : {
640981
+ stage: stageForToolName(event.toolName),
640982
+ detail: event.toolName
640983
+ };
640984
+ case "stream_start":
640985
+ case "assistant_text":
640986
+ case "model_response":
640987
+ return { stage: "planning" };
640988
+ case "compaction":
640989
+ return { stage: "compacting" };
640990
+ case "debug_adversary":
640991
+ return { stage: "adversary_audit" };
640992
+ case "complete":
640993
+ return { stage: "completed", detail: "done" };
640994
+ case "error":
640995
+ return {
640996
+ stage: "failed",
640997
+ detail: event.content?.trim().slice(0, 40) || void 0
640998
+ };
640999
+ case "user_interrupt":
641000
+ return { stage: "blocked", detail: "interrupted" };
641001
+ default:
641002
+ return null;
641003
+ }
641004
+ }
640620
641005
  function tri360(x) {
640621
641006
  const t2 = (x % 360 + 360) % 360;
640622
641007
  return t2 < 180 ? t2 / 90 - 1 : 3 - t2 / 90;
@@ -640641,6 +641026,9 @@ function supportsTruecolor() {
640641
641026
  function isSweepingStage(stage2) {
640642
641027
  return SWEEPING_STAGES.has(stage2);
640643
641028
  }
641029
+ function stageLabel2(stage2) {
641030
+ return STAGE_META[stage2].label;
641031
+ }
640644
641032
  function stageBlockNeededWidth(stage2, detail) {
640645
641033
  const meta = STAGE_META[stage2];
640646
641034
  let body = meta.label;
@@ -640790,6 +641178,125 @@ var init_stageIndicator = __esm({
640790
641178
  }
640791
641179
  });
640792
641180
 
641181
+ // packages/cli/src/tui/sub-agent-live-block.ts
641182
+ function stageFallbackColor(stage2) {
641183
+ return STAGE_FALLBACK_COLOR[stage2];
641184
+ }
641185
+ function sanitizeSubAgentActivity(value2) {
641186
+ return value2.replace(ANSI_RE2, "").replace(/[\x00-\x1F\x7F]/g, " ").replace(/\s+/g, " ").trim().slice(0, MAX_ACTIVITY_CHARS);
641187
+ }
641188
+ function appendSubAgentActivity(entry, value2, maxLines = 3) {
641189
+ const line = sanitizeSubAgentActivity(value2);
641190
+ if (!line) return;
641191
+ entry.activity.push(line);
641192
+ if (entry.activity.length > maxLines) {
641193
+ entry.activity.splice(0, entry.activity.length - maxLines);
641194
+ }
641195
+ entry.updatedAt = Date.now();
641196
+ }
641197
+ function buildSubAgentLiveBlockLines(sourceEntries, width, phase, truecolor = supportsTruecolor()) {
641198
+ const entries = Array.from(sourceEntries).slice(-MAX_PREVIEW_AGENTS);
641199
+ if (entries.length === 0) return [];
641200
+ const w = Math.max(48, Math.floor(width));
641201
+ const inner = Math.max(1, w - 4);
641202
+ const primary = entries.find((entry) => entry.status === "running") ?? entries[0];
641203
+ const title = " Sub-agent activity ";
641204
+ const top = `╭─┤${title}├${"─".repeat(Math.max(0, w - 5 - title.length))}╮`;
641205
+ const bottom = `╰${"─".repeat(Math.max(0, w - 2))}╯`;
641206
+ const lines = [paint(top, primary.stage, phase, 0, truecolor)];
641207
+ for (const entry of entries) {
641208
+ const icon = statusIcon(entry.status);
641209
+ const label = entry.label || entry.id;
641210
+ const state = entry.status === "running" ? `${stageLabel2(entry.stage)}${entry.detail ? ` ${entry.detail}` : ""}` : entry.status;
641211
+ const activity = entry.activity.at(-1) ?? "waiting for activity";
641212
+ lines.push(
641213
+ contentRow(
641214
+ `${icon} ${label} · ${state}`,
641215
+ inner,
641216
+ entry.stage,
641217
+ phase,
641218
+ truecolor
641219
+ )
641220
+ );
641221
+ lines.push(
641222
+ contentRow(
641223
+ ` └─ ${activity}`,
641224
+ inner,
641225
+ entry.stage,
641226
+ phase,
641227
+ truecolor
641228
+ )
641229
+ );
641230
+ }
641231
+ lines.push(paint(bottom, primary.stage, phase, 0, truecolor));
641232
+ return lines;
641233
+ }
641234
+ function contentRow(value2, width, stage2, phase, truecolor) {
641235
+ return `│ ${paint(fit2(value2, width), stage2, phase, 1, truecolor)} │`;
641236
+ }
641237
+ function paint(value2, stage2, phase, offset, truecolor) {
641238
+ let out = "";
641239
+ const chars = Array.from(value2);
641240
+ for (let i2 = 0; i2 < chars.length; i2++) {
641241
+ const char = chars[i2];
641242
+ if (truecolor) {
641243
+ const [r2, g, b] = stageGradientRgb(stage2, i2 + offset, phase);
641244
+ out += `\x1B[38;2;${r2};${g};${b}m${char}`;
641245
+ } else {
641246
+ out += `\x1B[38;5;${STAGE_FALLBACK_COLOR[stage2]}m${char}`;
641247
+ }
641248
+ }
641249
+ return `${out}\x1B[0m`;
641250
+ }
641251
+ function fit2(value2, width) {
641252
+ const plain = value2.replace(ANSI_RE2, "").replace(/\s+$/g, "");
641253
+ const chars = Array.from(plain);
641254
+ if (chars.length > width) {
641255
+ return `${chars.slice(0, Math.max(0, width - 1)).join("")}…`;
641256
+ }
641257
+ return plain + " ".repeat(Math.max(0, width - chars.length));
641258
+ }
641259
+ function statusIcon(status) {
641260
+ switch (status) {
641261
+ case "completed":
641262
+ return "✓";
641263
+ case "failed":
641264
+ return "✗";
641265
+ case "paused":
641266
+ case "stopped":
641267
+ return "○";
641268
+ default:
641269
+ return "●";
641270
+ }
641271
+ }
641272
+ var ANSI_RE2, MAX_PREVIEW_AGENTS, MAX_ACTIVITY_CHARS, STAGE_FALLBACK_COLOR;
641273
+ var init_sub_agent_live_block = __esm({
641274
+ "packages/cli/src/tui/sub-agent-live-block.ts"() {
641275
+ init_stageIndicator();
641276
+ ANSI_RE2 = /\x1B\[[0-?]*[ -/]*[@-~]|\x1B\].*?(?:\x07|\x1B\\)/g;
641277
+ MAX_PREVIEW_AGENTS = 4;
641278
+ MAX_ACTIVITY_CHARS = 220;
641279
+ STAGE_FALLBACK_COLOR = {
641280
+ idle: 39,
641281
+ planning: 141,
641282
+ tool_call: 45,
641283
+ reading: 39,
641284
+ searching: 129,
641285
+ editing: 42,
641286
+ writing: 43,
641287
+ testing: 82,
641288
+ building: 220,
641289
+ verifying: 214,
641290
+ reflecting: 177,
641291
+ compacting: 51,
641292
+ adversary_audit: 207,
641293
+ blocked: 208,
641294
+ completed: 46,
641295
+ failed: 196
641296
+ };
641297
+ }
641298
+ });
641299
+
640793
641300
  // packages/cli/src/tui/tui-tasks-renderer.ts
640794
641301
  var tui_tasks_renderer_exports = {};
640795
641302
  __export(tui_tasks_renderer_exports, {
@@ -643427,6 +643934,7 @@ __export(status_bar_exports, {
643427
643934
  refreshThemeVars: () => refreshThemeVars,
643428
643935
  setTermTitleWriter: () => setTermTitleWriter,
643429
643936
  setTerminalTitle: () => setTerminalTitle,
643937
+ stripSubAgentPrefix: () => stripSubAgentPrefix,
643430
643938
  unlockFooterRedraws: () => unlockFooterRedraws
643431
643939
  });
643432
643940
  import { basename as basename30, dirname as dirname44 } from "node:path";
@@ -643451,7 +643959,8 @@ function headerTelegramFg() {
643451
643959
  return themeMode() === "system" ? "\x1B[39m" : "\x1B[38;5;45m";
643452
643960
  }
643453
643961
  function stripSubAgentPrefix(label) {
643454
- const stripped = label.replace(/^\s*sub[-\s]?agents?\b[\s:_–—-]*/i, "").trim();
643962
+ let stripped = label.replace(/^\s*sub[-\s]?agents?\b[\s:_–—-]*/i, "").trim();
643963
+ stripped = stripped.replace(/^omnius-/i, "").trim();
643455
643964
  return stripped.length > 0 ? stripped : label.trim();
643456
643965
  }
643457
643966
  function xterm256ToRgb2(i2) {
@@ -643549,6 +644058,7 @@ var init_status_bar = __esm({
643549
644058
  "packages/cli/src/tui/status-bar.ts"() {
643550
644059
  init_render();
643551
644060
  init_stageIndicator();
644061
+ init_sub_agent_live_block();
643552
644062
  init_tui_tasks_renderer();
643553
644063
  init_braille_spinner();
643554
644064
  init_project_context();
@@ -643789,6 +644299,8 @@ var init_status_bar = __esm({
643789
644299
  _activeViewId = "main";
643790
644300
  _headerExpanded = false;
643791
644301
  // toggles sub-agent / scroll info below header
644302
+ _subAgentLiveBlockId = "sub-agent-live-preview";
644303
+ _subAgentLiveBlockAppended = false;
643792
644304
  // Virtual scrollback buffer — stores content lines for Page Up/Down scrolling.
643793
644305
  // Since we're in alternate screen buffer, there's no native scrollback.
643794
644306
  // NOTE: _contentLines is now a reference to the ACTIVE view's buffer.
@@ -644401,6 +644913,46 @@ var init_status_bar = __esm({
644401
644913
  * - Category A: Version + menu buttons (help/voice/model/endpoint/sponsor)
644402
644914
  * - Category B: Systems (agents/voice status/nexus status)
644403
644915
  * Each category paginates independently across N pages. */
644916
+ /** Filled header button whose hue band follows the child agent's current action. */
644917
+ paintAgentButton(content, stage2, active) {
644918
+ const useTruecolor = supportsTruecolor();
644919
+ const chars = Array.from(content);
644920
+ let body = "";
644921
+ for (let i2 = 0; i2 < chars.length; i2++) {
644922
+ const char = chars[i2];
644923
+ if (useTruecolor) {
644924
+ const [r2, g, b] = stageGradientRgb(stage2, i2, this._stagePhase);
644925
+ const luma = 0.299 * r2 + 0.587 * g + 0.114 * b;
644926
+ const fg2 = luma >= 140 ? "\x1B[38;2;16;16;16m" : "\x1B[38;2;255;255;255m";
644927
+ body += `${active ? "\x1B[1m" : ""}${fg2}\x1B[48;2;${r2};${g};${b}m${char}\x1B[0m`;
644928
+ } else {
644929
+ const fallback = stageFallbackColor(stage2);
644930
+ body += `${active ? "\x1B[1m" : ""}\x1B[38;5;${contrastTextColor(fallback)}m\x1B[48;5;${fallback}m${char}\x1B[0m`;
644931
+ }
644932
+ }
644933
+ const [lr, lg, lb] = stageGradientRgb(stage2, 0, this._stagePhase);
644934
+ const leftBorder = useTruecolor ? `\x1B[38;2;${lr};${lg};${lb}m` : `\x1B[38;5;${stageFallbackColor(stage2)}m`;
644935
+ const [rr, rg, rb] = stageGradientRgb(
644936
+ stage2,
644937
+ Math.max(0, chars.length - 1),
644938
+ this._stagePhase
644939
+ );
644940
+ const rightBorder = useTruecolor ? `\x1B[38;2;${rr};${rg};${rb}m` : `\x1B[38;5;${stageFallbackColor(stage2)}m`;
644941
+ return `${leftBorder}${HEADER_BUTTON_LEFT}${RESET4}` + body + `${RESET4}${PANEL_BG_SEQ}${rightBorder}${HEADER_BUTTON_RIGHT}${RESET4}${PANEL_BG_SEQ}`;
644942
+ }
644943
+ paintAgentText(value2, stage2, offset = 0) {
644944
+ const chars = Array.from(value2);
644945
+ let out = "";
644946
+ for (let i2 = 0; i2 < chars.length; i2++) {
644947
+ if (supportsTruecolor()) {
644948
+ const [r2, g, b] = stageGradientRgb(stage2, i2 + offset, this._stagePhase);
644949
+ out += `\x1B[38;2;${r2};${g};${b}m${chars[i2]}`;
644950
+ } else {
644951
+ out += `\x1B[38;5;${stageFallbackColor(stage2)}m${chars[i2]}`;
644952
+ }
644953
+ }
644954
+ return `${out}${RESET4}`;
644955
+ }
644404
644956
  _rebuildHeaderPanels() {
644405
644957
  this._headerPanels = [];
644406
644958
  const savedIdx = this._headerPanelIndex;
@@ -644412,12 +644964,6 @@ var init_status_bar = __esm({
644412
644964
  const decorateMenuButton = (cmd, label) => {
644413
644965
  return `${HEADER_BUTTON_GLYPH_FG}${HEADER_BUTTON_LEFT}\x1B[0m${HEADER_BUTTON_BG}${HEADER_BUTTON_FG}${label}\x1B[0m${PANEL_BG_SEQ}${HEADER_BUTTON_GLYPH_FG}${HEADER_BUTTON_RIGHT}\x1B[0m${PANEL_BG_SEQ}`;
644414
644966
  };
644415
- const decorateAgentButton = (content, color, active) => {
644416
- const bg = `\x1B[48;5;${color}m`;
644417
- const fg2 = `\x1B[38;5;${contrastTextColor(color)}m`;
644418
- const weight = active ? "\x1B[1m" : "";
644419
- return `\x1B[38;5;${color}m${HEADER_BUTTON_LEFT}\x1B[0m${weight}${fg2}${bg}${content}\x1B[0m${PANEL_BG_SEQ}\x1B[38;5;${color}m${HEADER_BUTTON_RIGHT}\x1B[0m${PANEL_BG_SEQ}`;
644420
- };
644421
644967
  const renderBtn = (cmd, label) => {
644422
644968
  return linkify(cmd, decorateMenuButton(cmd, label));
644423
644969
  };
@@ -644505,9 +645051,8 @@ var init_status_bar = __esm({
644505
645051
  if (view.id === "main" && this._activeViewId === "main") continue;
644506
645052
  const icon = view.status === "running" ? "●" : view.status === "completed" ? "✓" : view.status === "failed" ? "✗" : "○";
644507
645053
  const content = ` ${trunc3(view.label)} ${icon} `;
644508
- const viewColor = view.colorCode ?? (view.type === "telegram" ? 45 : 213);
644509
645054
  const active = view.id === this._activeViewId;
644510
- const btn = decorateAgentButton(content, viewColor, active);
645055
+ const btn = this.paintAgentButton(content, view.stage, active);
644511
645056
  sysItems.push({
644512
645057
  render: () => linkify(`view:${view.id}`, btn) + " ",
644513
645058
  w: content.length + 2 + 1
@@ -644758,10 +645303,24 @@ var init_status_bar = __esm({
644758
645303
  buf += `\x1B[${subRow};1H${PANEL_BG_SEQ}\x1B[2K`;
644759
645304
  buf += `${BOX_FG}│${RESET4}${PANEL_BG_SEQ}`;
644760
645305
  buf += `\x1B[38;5;${TEXT_DIM}m${PANEL_BG_SEQ}`;
644761
- const subAgents = this._agentViews.size > 1 ? Array.from(this._agentViews.values()).filter((v) => v.id !== "main").map(
644762
- (v) => `${v.status === "running" ? "●" : v.status === "completed" ? "✓" : "○"} ${v.label}`
644763
- ).join(" ") : "no sub-agents";
644764
- buf += ` ${subAgents.substring(0, w - 4)}`;
645306
+ if (this._agentViews.size > 1) {
645307
+ let used = 1;
645308
+ for (const view of Array.from(this._agentViews.values()).filter(
645309
+ (candidate) => candidate.id !== "main"
645310
+ )) {
645311
+ const icon = view.status === "running" ? "●" : view.status === "completed" ? "✓" : view.status === "failed" ? "✗" : "○";
645312
+ const raw = `${icon} ${view.label}`;
645313
+ const gap = used > 1 ? " " : " ";
645314
+ const remaining = Math.max(0, w - 2 - used);
645315
+ if (remaining <= 0) break;
645316
+ const clipped = raw.length > remaining ? `${raw.slice(0, Math.max(0, remaining - 1))}…` : raw;
645317
+ buf += `${PANEL_BG_SEQ}${this.paintAgentText(`${gap}${clipped}`, view.stage, used)}`;
645318
+ used += gap.length + clipped.length;
645319
+ if (clipped !== raw) break;
645320
+ }
645321
+ } else {
645322
+ buf += ` ${NO_SUB_AGENTS_HEADER_LABEL.trim()}`;
645323
+ }
644765
645324
  buf += `\x1B[${subRow};${w}H${BOX_FG}│${RESET4}${PANEL_BG_SEQ}`;
644766
645325
  const scrollRow = subRow + 1;
644767
645326
  let expandedBottom = `${BOX_BL3}${BOX_H3.repeat(w - 2)}${BOX_BR3}`;
@@ -644902,6 +645461,9 @@ var init_status_bar = __esm({
644902
645461
  this.advanceStagePhase();
644903
645462
  this.renderFooterPreserveCursor();
644904
645463
  refreshTuiTasksAnimationFrame();
645464
+ if (this._agentViews.size > 1 && (String(this.currentHeaderPanel).startsWith("sys-") || this._headerExpanded)) {
645465
+ this.refreshHeaderContent();
645466
+ }
644905
645467
  }, _StatusBar.FOOTER_ANIMATION_INTERVAL_MS);
644906
645468
  this._footerAnimationTimer.unref?.();
644907
645469
  }
@@ -645478,9 +646040,13 @@ var init_status_bar = __esm({
645478
646040
  scrollOffset: 0,
645479
646041
  status: "running",
645480
646042
  taskSummary: "",
645481
- startedAt: Date.now()
646043
+ startedAt: Date.now(),
646044
+ stage: "idle",
646045
+ activity: [],
646046
+ updatedAt: Date.now()
645482
646047
  });
645483
646048
  }
646049
+ if (this._agentViews.size > 1) this.ensureSubAgentLiveBlock();
645484
646050
  setTermSize(process.stdout.rows ?? 24, process.stdout.columns ?? 80);
645485
646051
  setFooterMetricsVisible(this._footerMetricsVisible);
645486
646052
  this._prevTermRows = termRows();
@@ -646094,8 +646660,101 @@ var init_status_bar = __esm({
646094
646660
  }, 1500);
646095
646661
  }
646096
646662
  // ── Agent View Management (WO-NA1) ────────────────────────────
646663
+ /** Keep one compact, live child-agent preview in the MAIN view. */
646664
+ ensureSubAgentLiveBlock() {
646665
+ if (!this.active || !this._agentViews.has("main") || this._agentViews.size <= 1)
646666
+ return;
646667
+ if (this._subAgentLiveBlockAppended) return;
646668
+ this.registerDynamicBlock(
646669
+ this._subAgentLiveBlockId,
646670
+ (width) => buildSubAgentLiveBlockLines(
646671
+ Array.from(this._agentViews.values()).filter((view) => view.id !== "main"),
646672
+ width,
646673
+ this._stagePhase
646674
+ )
646675
+ );
646676
+ this.appendDynamicBlockToAgentView("main", this._subAgentLiveBlockId);
646677
+ this._subAgentLiveBlockAppended = true;
646678
+ }
646679
+ removeSubAgentLiveBlock() {
646680
+ if (!this._subAgentLiveBlockAppended) return;
646681
+ const main2 = this._agentViews.get("main");
646682
+ const marker = `${this.DYNAMIC_BLOCK_MARK_PREFIX}${this._subAgentLiveBlockId}${this.DYNAMIC_BLOCK_MARK_SUFFIX}`;
646683
+ if (main2) {
646684
+ for (let i2 = main2.contentLines.length - 1; i2 >= 0; i2--) {
646685
+ if (main2.contentLines[i2] === marker) main2.contentLines.splice(i2, 1);
646686
+ }
646687
+ }
646688
+ this.unregisterDynamicBlock(this._subAgentLiveBlockId);
646689
+ this._subAgentLiveBlockAppended = false;
646690
+ if (this.active && this._activeViewId === "main") {
646691
+ this.markContentMutated();
646692
+ this.repaintContent();
646693
+ }
646694
+ }
646695
+ /** Update a child-agent's action state and rolling live preview line. */
646696
+ updateAgentViewActivity(id2, stage2, detail, activity) {
646697
+ const view = this._agentViews.get(id2);
646698
+ if (!view || view.id === "main") return;
646699
+ view.stage = stage2;
646700
+ view.stageDetail = detail?.trim() || void 0;
646701
+ view.updatedAt = Date.now();
646702
+ if (activity) appendSubAgentActivity(view, activity);
646703
+ this.ensureSubAgentLiveBlock();
646704
+ if (this.active) {
646705
+ this.renderAgentTabs();
646706
+ if (this._headerExpanded) this.refreshHeaderContent();
646707
+ this.refreshDynamicBlocks();
646708
+ }
646709
+ }
646710
+ /** Structured-event adapter used by in-process child runners. */
646711
+ updateAgentViewEvent(id2, event, activity) {
646712
+ const view = this._agentViews.get(id2);
646713
+ if (!view) return;
646714
+ const transition = stageForAgentEvent(event);
646715
+ this.updateAgentViewActivity(
646716
+ id2,
646717
+ transition?.stage ?? view.stage,
646718
+ transition?.detail ?? view.stageDetail,
646719
+ activity
646720
+ );
646721
+ }
646722
+ /** Forward a raw full-sub-agent stdout chunk into the same state model. */
646723
+ recordAgentOutput(id2, text2) {
646724
+ const line = text2.replace(/\x1B\[[0-?]*[ -/]*[@-~]/g, "").split(/\r?\n/).map((value2) => value2.trim()).filter(Boolean).at(-1);
646725
+ if (!line) {
646726
+ this.writeToAgentView(id2, text2);
646727
+ return;
646728
+ }
646729
+ const lower = line.toLowerCase();
646730
+ let stage2 = "tool_call";
646731
+ if (/\b(error|failed|failure|exception|blocked)\b/.test(lower)) stage2 = "failed";
646732
+ else if (/\b(complete|completed|done|success|succeeded)\b/.test(lower)) stage2 = "completed";
646733
+ else if (/\b(file_read|read|grep|search|find)\b/.test(lower)) stage2 = "reading";
646734
+ else if (/\b(file_write|file_edit|file_patch|batch_edit|write|edit|patch)\b/.test(lower)) stage2 = "writing";
646735
+ else if (/\b(shell|build|test|compile|npm|pnpm|pio)\b/.test(lower)) stage2 = "building";
646736
+ this.updateAgentViewActivity(id2, stage2, line.slice(0, 40), line);
646737
+ this.writeToAgentView(id2, text2);
646738
+ }
646097
646739
  /** Register a new sub-agent view with its own content buffer */
646098
646740
  registerAgentView(id2, label, type, taskSummary) {
646741
+ const existing = this._agentViews.get(id2);
646742
+ if (existing) {
646743
+ if (existing.id !== "main") {
646744
+ const cleanExistingLabel = stripSubAgentPrefix(existing.label);
646745
+ existing.label = cleanExistingLabel || stripSubAgentPrefix(label);
646746
+ }
646747
+ existing.taskSummary = taskSummary ?? existing.taskSummary;
646748
+ existing.status = "running";
646749
+ existing.updatedAt = Date.now();
646750
+ this.ensureSubAgentLiveBlock();
646751
+ if (this.active) {
646752
+ this._rebuildHeaderPanels?.();
646753
+ this.renderFooterAndPositionInput();
646754
+ this.refreshHeaderContent();
646755
+ }
646756
+ return;
646757
+ }
646099
646758
  this._agentViews.set(id2, {
646100
646759
  id: id2,
646101
646760
  label: stripSubAgentPrefix(label),
@@ -646105,9 +646764,14 @@ var init_status_bar = __esm({
646105
646764
  status: "running",
646106
646765
  taskSummary: taskSummary ?? "",
646107
646766
  startedAt: Date.now(),
646108
- colorCode: type === "telegram" ? 45 : this.nextAgentColor()
646767
+ colorCode: type === "telegram" ? 45 : this.nextAgentColor(),
646768
+ stage: "planning",
646769
+ stageDetail: "spawn",
646770
+ activity: ["spawned; waiting for first action"],
646771
+ updatedAt: Date.now()
646109
646772
  });
646110
646773
  if (this.active) {
646774
+ this.ensureSubAgentLiveBlock();
646111
646775
  this.applyScrollRegion();
646112
646776
  this._rebuildHeaderPanels?.();
646113
646777
  this.renderFooterAndPositionInput();
@@ -646117,6 +646781,7 @@ var init_status_bar = __esm({
646117
646781
  /** Remove a sub-agent view */
646118
646782
  unregisterAgentView(id2) {
646119
646783
  this._agentViews.delete(id2);
646784
+ if (this._agentViews.size <= 1) this.removeSubAgentLiveBlock();
646120
646785
  if (this._activeViewId === id2) this.switchToView("main");
646121
646786
  if (this.active) {
646122
646787
  this.applyScrollRegion();
@@ -646130,9 +646795,27 @@ var init_status_bar = __esm({
646130
646795
  const view = this._agentViews.get(id2);
646131
646796
  if (!view) return;
646132
646797
  view.status = status;
646133
- if (status === "completed" || status === "failed")
646798
+ if (status === "completed") {
646134
646799
  view.completedAt = Date.now();
646135
- if (this.active) this.renderAgentTabs();
646800
+ view.stage = "completed";
646801
+ view.stageDetail = "done";
646802
+ appendSubAgentActivity(view, "completed");
646803
+ } else if (status === "failed") {
646804
+ view.completedAt = Date.now();
646805
+ view.stage = "failed";
646806
+ view.stageDetail = "failed";
646807
+ appendSubAgentActivity(view, "failed");
646808
+ } else if (status === "paused" || status === "stopped") {
646809
+ view.stage = "blocked";
646810
+ view.stageDetail = status;
646811
+ appendSubAgentActivity(view, status);
646812
+ }
646813
+ view.updatedAt = Date.now();
646814
+ if (this.active) {
646815
+ this.renderAgentTabs();
646816
+ if (this._headerExpanded) this.refreshHeaderContent();
646817
+ this.refreshDynamicBlocks();
646818
+ }
646136
646819
  }
646137
646820
  /** Switch which agent's content buffer is displayed */
646138
646821
  switchToView(id2) {
@@ -653078,9 +653761,9 @@ function formatExpandedContextDiagnostic(specs, math) {
653078
653761
  memBits.push(`RAM ${fmtGB(specs.availableRamGB)}/${fmtGB(specs.totalRamGB)}${specs.unifiedMemory ? " unified" : ""}`);
653079
653762
  const mem = memBits.join(", ");
653080
653763
  const kv = `KV ${fmtKB(math.kvBytesPerToken)}/tok (${math.kvSource})`;
653081
- const fit3 = `fit ${fmtK(math.memoryFit)}, arch ${math.archCtx !== null ? fmtK(math.archCtx) : "n/a"}, floor ${fmtK(math.floor)}`;
653764
+ const fit4 = `fit ${fmtK(math.memoryFit)}, arch ${math.archCtx !== null ? fmtK(math.archCtx) : "n/a"}, floor ${fmtK(math.floor)}`;
653082
653765
  const limit = `→ ${fmtK(math.numCtx)} (${math.limitedBy === "floor" ? "min floor" : math.limitedBy === "arch" ? "arch-capped" : "memory-fit"})`;
653083
- return `[${mem} | model ${fmtGB(math.modelSizeGB)} | ${kv} | ${fit3} ${limit}]`;
653766
+ return `[${mem} | model ${fmtGB(math.modelSizeGB)} | ${kv} | ${fit4} ${limit}]`;
653084
653767
  }
653085
653768
  async function ensureExpandedContext(modelName, backendUrl2) {
653086
653769
  if (modelName.includes("cloud") || modelName.includes(":cloud")) {
@@ -653359,7 +654042,7 @@ export PATH="${binDir}:$PATH" # Added by omnius for nvim
653359
654042
  } catch {
653360
654043
  }
653361
654044
  }
653362
- var execAsync2, OMNIUS_FIRST_RUN_BANNER, ANSI_RE2, visibleLen2, SETUP_MODEL_VARIANTS, _toolSupportCache, EXPANDED_VARIANT_MIN_NUM_CTX, _cloudflaredInstallPromise;
654045
+ var execAsync2, OMNIUS_FIRST_RUN_BANNER, ANSI_RE3, visibleLen2, SETUP_MODEL_VARIANTS, _toolSupportCache, EXPANDED_VARIANT_MIN_NUM_CTX, _cloudflaredInstallPromise;
653363
654046
  var init_setup = __esm({
653364
654047
  "packages/cli/src/tui/setup.ts"() {
653365
654048
  init_model_picker();
@@ -653378,8 +654061,8 @@ var init_setup = __esm({
653378
654061
  "░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░ ",
653379
654062
  " ░▒▓██████▓▒░░▒▓█▓▒░░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓██████▓▒░░▒▓███████▓▒░ "
653380
654063
  ].join("\n");
653381
- ANSI_RE2 = /\x1B\[[0-?]*[ -/]*[@-~]/g;
653382
- visibleLen2 = (value2) => Array.from(value2.replace(ANSI_RE2, "")).length;
654064
+ ANSI_RE3 = /\x1B\[[0-?]*[ -/]*[@-~]/g;
654065
+ visibleLen2 = (value2) => Array.from(value2.replace(ANSI_RE3, "")).length;
653383
654066
  SETUP_MODEL_VARIANTS = [
653384
654067
  { tag: "robit/ornith:9b", sizeGB: 6.6, label: "9B params (6.6 GB) - recommended minimum", cloud: false },
653385
654068
  { tag: "robit/ornith:35b", sizeGB: 24, label: "35B params (24 GB) - recommended on 32GB+ unified memory/VRAM", cloud: false }
@@ -674050,12 +674733,12 @@ function cad3dFitIcon(score) {
674050
674733
  if (score >= 40) return c3.yellow("△");
674051
674734
  return c3.red("✖");
674052
674735
  }
674053
- function cad3dModelDetail(spec, fit3) {
674736
+ function cad3dModelDetail(spec, fit4) {
674054
674737
  const download = spec.resources.approxDownloadGB ? `~${spec.resources.approxDownloadGB}GB` : "size unknown";
674055
674738
  const vram = spec.resources.recommendedVramGB ? `${spec.resources.recommendedVramGB}GB VRAM rec` : "VRAM varies";
674056
674739
  const license = spec.hf.license ? `license ${spec.hf.license}` : "license unknown";
674057
674740
  const token = spec.deployment.requiresToken ? "requires HF token" : "no token gate";
674058
- return `${fit3.label} · ${spec.backend} · ${download} · ${vram} · ${license} · ${token}`;
674741
+ return `${fit4.label} · ${spec.backend} · ${download} · ${vram} · ${license} · ${token}`;
674059
674742
  }
674060
674743
  async function startCad3dViewerFromCommand(rawPath) {
674061
674744
  const viewer = await startCadModelViewer(
@@ -674071,11 +674754,11 @@ async function showCad3dModelsMenu(ctx3, hasLocal, mode) {
674071
674754
  const active = mode === "cad" ? settings.cadModel : settings.model3dModel;
674072
674755
  const currentViewer2 = getCurrentCadModelViewer();
674073
674756
  const buildItem = (entry) => {
674074
- const fit3 = rateCad3dModelForHardware(entry.spec, specs);
674757
+ const fit4 = rateCad3dModelForHardware(entry.spec, specs);
674075
674758
  return {
674076
674759
  key: `model:${entry.spec.id}`,
674077
- label: `${cad3dFitIcon(fit3.score)} ${String(fit3.score).padStart(3)}/100 ${entry.spec.label}`,
674078
- detail: cad3dModelDetail(entry.spec, fit3)
674760
+ label: `${cad3dFitIcon(fit4.score)} ${String(fit4.score).padStart(3)}/100 ${entry.spec.label}`,
674761
+ detail: cad3dModelDetail(entry.spec, fit4)
674079
674762
  };
674080
674763
  };
674081
674764
  const items = [
@@ -674110,11 +674793,11 @@ async function showCad3dModelsMenu(ctx3, hasLocal, mode) {
674110
674793
  const patch = mode === "cad" ? { cadModel: id2, cadBackend: entry.spec.backend } : { model3dModel: id2, model3dBackend: entry.spec.backend };
674111
674794
  const save3 = hasLocal ? ctx3.saveLocalSettings : ctx3.saveSettings;
674112
674795
  save3(patch);
674113
- const fit3 = rateCad3dModelForHardware(entry.spec, specs);
674796
+ const fit4 = rateCad3dModelForHardware(entry.spec, specs);
674114
674797
  renderInfo(
674115
674798
  `${mode === "cad" ? "CAD" : "3D"} model: ${id2} (${entry.spec.backend})${hasLocal ? " (project-local)" : ""}`
674116
674799
  );
674117
- renderInfo(`Hardware fit: ${fit3.score}/100 ${fit3.label} - ${fit3.note}`);
674800
+ renderInfo(`Hardware fit: ${fit4.score}/100 ${fit4.label} - ${fit4.note}`);
674118
674801
  if (entry.spec.resources.approxDownloadGB) {
674119
674802
  renderInfo(
674120
674803
  `Download estimate: ~${entry.spec.resources.approxDownloadGB}GB in ${unifiedModelStoreDir()}`
@@ -674265,19 +674948,19 @@ async function renderImageModelList(ctx3) {
674265
674948
  renderInfo("");
674266
674949
  renderInfo(c3.bold(category));
674267
674950
  for (const preset of presets) {
674268
- const fit3 = rateImagePresetForHardware(preset, specs);
674951
+ const fit4 = rateImagePresetForHardware(preset, specs);
674269
674952
  const primary = category === "Primary hyper-realistic baseline" ? c3.cyan(" ★") : "";
674270
674953
  const disk = ctx3 ? imageModelDiskStats(ctx3, preset, ollamaSizes) : { downloaded: false, bytes: 0, paths: [] };
674271
674954
  const diskInfo = disk.downloaded ? ` ${c3.green("✓")} ${formatFileSize(disk.bytes)}` : "";
674272
674955
  renderInfo(
674273
- `${imageFitIcon(fit3.score)} ${String(fit3.score).padStart(3)}/100 ${c3.bold(preset.label)}${primary}${diskInfo}`
674956
+ `${imageFitIcon(fit4.score)} ${String(fit4.score).padStart(3)}/100 ${c3.bold(preset.label)}${primary}${diskInfo}`
674274
674957
  );
674275
674958
  renderInfo(` id: ${preset.id}`);
674276
674959
  renderInfo(
674277
- ` type: ${preset.backend} · ${preset.sizeClass ?? "unknown size"} · ${fit3.label}`
674960
+ ` type: ${preset.backend} · ${preset.sizeClass ?? "unknown size"} · ${fit4.label}`
674278
674961
  );
674279
674962
  renderImagePresetDetail(" quality: ", preset.quality ?? preset.note);
674280
- renderImagePresetDetail(" fit: ", fit3.note);
674963
+ renderImagePresetDetail(" fit: ", fit4.note);
674281
674964
  if (preset.deployment)
674282
674965
  renderImagePresetDetail(" deploy: ", preset.deployment);
674283
674966
  }
@@ -674420,13 +675103,13 @@ async function showImageModelsMenu(ctx3, hasLocal) {
674420
675103
  () => /* @__PURE__ */ new Map()
674421
675104
  );
674422
675105
  const buildModelItem = (preset) => {
674423
- const fit3 = rateImagePresetForHardware(preset, specs);
675106
+ const fit4 = rateImagePresetForHardware(preset, specs);
674424
675107
  const disk = imageModelDiskStats(ctx3, preset, ollamaSizes);
674425
675108
  const downloaded = disk.downloaded ? `${c3.green("✓")} ` : "";
674426
675109
  return {
674427
675110
  key: `model:${preset.id}`,
674428
- label: `${downloaded}${imageFitIcon(fit3.score)} ${String(fit3.score).padStart(3)}/100 ${preset.label}`,
674429
- detail: `${fit3.score}/100 ${fit3.label} · ${preset.category ?? preset.backend} · ${preset.sizeClass ?? preset.id}${downloadedModelSuffix(disk)}`
675111
+ label: `${downloaded}${imageFitIcon(fit4.score)} ${String(fit4.score).padStart(3)}/100 ${preset.label}`,
675112
+ detail: `${fit4.score}/100 ${fit4.label} · ${preset.category ?? preset.backend} · ${preset.sizeClass ?? preset.id}${downloadedModelSuffix(disk)}`
674430
675113
  };
674431
675114
  };
674432
675115
  const items = [
@@ -674511,9 +675194,9 @@ async function showImageModelsMenu(ctx3, hasLocal) {
674511
675194
  renderInfo(
674512
675195
  `Image model: ${model} (${backend})${hasLocal ? " (project-local)" : ""}`
674513
675196
  );
674514
- const fit3 = preset ? rateImagePresetForHardware(preset, specs) : void 0;
674515
- if (fit3)
674516
- renderInfo(`Hardware fit: ${fit3.score}/100 ${fit3.label} — ${fit3.note}`);
675197
+ const fit4 = preset ? rateImagePresetForHardware(preset, specs) : void 0;
675198
+ if (fit4)
675199
+ renderInfo(`Hardware fit: ${fit4.score}/100 ${fit4.label} — ${fit4.note}`);
674517
675200
  if (preset?.install) renderInfo(`Prewarm command: ${preset.install}`);
674518
675201
  await prewarmImageModel(ctx3, model, backend);
674519
675202
  }
@@ -674829,19 +675512,19 @@ async function renderVideoModelList(ctx3) {
674829
675512
  renderInfo("");
674830
675513
  renderInfo(c3.bold(category));
674831
675514
  for (const preset of presets) {
674832
- const fit3 = rateVideoPresetForHardware(preset, specs);
675515
+ const fit4 = rateVideoPresetForHardware(preset, specs);
674833
675516
  const disk = videoModelDiskStats(ctx3, preset);
674834
675517
  const diskInfo = disk.downloaded ? ` ${c3.green("✓")} ${formatFileSize(disk.bytes)}` : "";
674835
675518
  renderInfo(
674836
- `${imageFitIcon(fit3.score)} ${String(fit3.score).padStart(3)}/100 ${c3.bold(preset.label)}${diskInfo}`
675519
+ `${imageFitIcon(fit4.score)} ${String(fit4.score).padStart(3)}/100 ${c3.bold(preset.label)}${diskInfo}`
674837
675520
  );
674838
675521
  renderInfo(` id: ${preset.id}`);
674839
675522
  renderInfo(
674840
- ` type: ${preset.backend} · ${preset.sizeClass} · ${preset.kinds.join("/")} · ${fit3.label}`
675523
+ ` type: ${preset.backend} · ${preset.sizeClass} · ${preset.kinds.join("/")} · ${fit4.label}`
674841
675524
  );
674842
675525
  renderImagePresetDetail(" quality: ", preset.quality);
674843
675526
  renderImagePresetDetail(" output: ", preset.output);
674844
- renderImagePresetDetail(" fit: ", fit3.note);
675527
+ renderImagePresetDetail(" fit: ", fit4.note);
674845
675528
  renderImagePresetDetail(" deploy: ", preset.deployment);
674846
675529
  if (preset.licenseNote)
674847
675530
  renderImagePresetDetail(" license: ", preset.licenseNote);
@@ -674852,13 +675535,13 @@ async function showVideoModelsMenu(ctx3, hasLocal) {
674852
675535
  const settings = resolveSettings(ctx3.repoRoot);
674853
675536
  const specs = await detectSystemSpecsAsync();
674854
675537
  const buildModelItem = (preset) => {
674855
- const fit3 = rateVideoPresetForHardware(preset, specs);
675538
+ const fit4 = rateVideoPresetForHardware(preset, specs);
674856
675539
  const disk = videoModelDiskStats(ctx3, preset);
674857
675540
  const downloaded = disk.downloaded ? `${c3.green("✓")} ` : "";
674858
675541
  return {
674859
675542
  key: `model:${preset.id}`,
674860
- label: `${downloaded}${imageFitIcon(fit3.score)} ${String(fit3.score).padStart(3)}/100 ${preset.label}`,
674861
- detail: `${fit3.label} · ${preset.category} · ${preset.kinds.join("/")}${downloadedModelSuffix(disk)}`
675543
+ label: `${downloaded}${imageFitIcon(fit4.score)} ${String(fit4.score).padStart(3)}/100 ${preset.label}`,
675544
+ detail: `${fit4.label} · ${preset.category} · ${preset.kinds.join("/")}${downloadedModelSuffix(disk)}`
674862
675545
  };
674863
675546
  };
674864
675547
  const items = [
@@ -674937,8 +675620,8 @@ async function showVideoModelsMenu(ctx3, hasLocal) {
674937
675620
  `Video model: ${model} (${backend})${hasLocal ? " (project-local)" : ""}`
674938
675621
  );
674939
675622
  if (preset) {
674940
- const fit3 = rateVideoPresetForHardware(preset, specs);
674941
- renderInfo(`Hardware fit: ${fit3.score}/100 ${fit3.label} — ${fit3.note}`);
675623
+ const fit4 = rateVideoPresetForHardware(preset, specs);
675624
+ renderInfo(`Hardware fit: ${fit4.score}/100 ${fit4.label} — ${fit4.note}`);
674942
675625
  if (preset.licenseNote) renderInfo(`License: ${preset.licenseNote}`);
674943
675626
  if (preset.install) renderInfo(`Prewarm command: ${preset.install}`);
674944
675627
  }
@@ -675200,19 +675883,19 @@ async function renderAudioModelList(ctx3, kind) {
675200
675883
  renderInfo("");
675201
675884
  renderInfo(c3.bold(category));
675202
675885
  for (const preset of presets) {
675203
- const fit3 = rateAudioPresetForHardware(preset, specs);
675886
+ const fit4 = rateAudioPresetForHardware(preset, specs);
675204
675887
  const disk = audioModelDiskStats(ctx3, preset);
675205
675888
  const diskInfo = disk.downloaded ? ` ${c3.green("✓")} ${formatFileSize(disk.bytes)}` : "";
675206
675889
  renderInfo(
675207
- `${audioFitIcon(fit3.score)} ${String(fit3.score).padStart(3)}/100 ${c3.bold(preset.label)}${diskInfo}`
675890
+ `${audioFitIcon(fit4.score)} ${String(fit4.score).padStart(3)}/100 ${c3.bold(preset.label)}${diskInfo}`
675208
675891
  );
675209
675892
  renderInfo(` id: ${preset.id}`);
675210
675893
  renderInfo(
675211
- ` type: ${preset.backend} · ${preset.sizeClass} · ${fit3.label}`
675894
+ ` type: ${preset.backend} · ${preset.sizeClass} · ${fit4.label}`
675212
675895
  );
675213
675896
  renderImagePresetDetail(" quality: ", preset.quality);
675214
675897
  renderImagePresetDetail(" output: ", preset.output);
675215
- renderImagePresetDetail(" fit: ", fit3.note);
675898
+ renderImagePresetDetail(" fit: ", fit4.note);
675216
675899
  renderImagePresetDetail(" deploy: ", preset.deployment);
675217
675900
  }
675218
675901
  }
@@ -675237,13 +675920,13 @@ async function showAudioGenerationMenu(ctx3, hasLocal, kind) {
675237
675920
  const activeModel = activeAudioModel(settings, kind);
675238
675921
  const title = kind === "music" ? "Music Generation" : "Sound Generation";
675239
675922
  const buildModelItem = (preset) => {
675240
- const fit3 = rateAudioPresetForHardware(preset, specs);
675923
+ const fit4 = rateAudioPresetForHardware(preset, specs);
675241
675924
  const disk = audioModelDiskStats(ctx3, preset);
675242
675925
  const downloaded = disk.downloaded ? `${c3.green("✓")} ` : "";
675243
675926
  return {
675244
675927
  key: `model:${preset.id}`,
675245
- label: `${downloaded}${audioFitIcon(fit3.score)} ${String(fit3.score).padStart(3)}/100 ${preset.label}`,
675246
- detail: `${fit3.label} · ${preset.category} · ${preset.sizeClass}${downloadedModelSuffix(disk)}`
675928
+ label: `${downloaded}${audioFitIcon(fit4.score)} ${String(fit4.score).padStart(3)}/100 ${preset.label}`,
675929
+ detail: `${fit4.label} · ${preset.category} · ${preset.sizeClass}${downloadedModelSuffix(disk)}`
675247
675930
  };
675248
675931
  };
675249
675932
  const setupItems = kind === "music" ? [
@@ -675364,8 +676047,8 @@ async function showAudioGenerationMenu(ctx3, hasLocal, kind) {
675364
676047
  `${kind === "music" ? "Music" : "Sound"} model: ${model} (${backend})${hasLocal ? " (project-local)" : ""}`
675365
676048
  );
675366
676049
  if (preset) {
675367
- const fit3 = rateAudioPresetForHardware(preset, specs);
675368
- renderInfo(`Hardware fit: ${fit3.score}/100 ${fit3.label} - ${fit3.note}`);
676050
+ const fit4 = rateAudioPresetForHardware(preset, specs);
676051
+ renderInfo(`Hardware fit: ${fit4.score}/100 ${fit4.label} - ${fit4.note}`);
675369
676052
  renderInfo(`Prewarm command: ${preset.install}`);
675370
676053
  }
675371
676054
  await prewarmAudioModel(ctx3, kind, model, backend);
@@ -700701,10 +701384,10 @@ ${message2}`)
700701
701384
  telegramModelMenuItems(generation) {
700702
701385
  return this.telegramGenerationModelDescriptors(generation).map((model) => {
700703
701386
  const cached = model.cachedBytes > 0 ? `cached ${formatModelBytes(model.cachedBytes)}` : "not downloaded";
700704
- const fit3 = model.recommendedVramGB ? `${model.recommendedVramGB}GB VRAM rec` : model.minVramGB ? `${model.minVramGB}GB VRAM min` : "VRAM n/a";
701387
+ const fit4 = model.recommendedVramGB ? `${model.recommendedVramGB}GB VRAM rec` : model.minVramGB ? `${model.minVramGB}GB VRAM min` : "VRAM n/a";
700705
701388
  return {
700706
701389
  label: model.label,
700707
- description: `${model.backend} - ${model.category} - ${fit3} - ${cached}`,
701390
+ description: `${model.backend} - ${model.category} - ${fit4} - ${cached}`,
700708
701391
  action: {
700709
701392
  type: "model_detail",
700710
701393
  generation,
@@ -714814,17 +715497,17 @@ function buildShellLiveBlockLines(state, width) {
714814
715497
  const body = visibleLines.slice(-state.maxRows);
714815
715498
  const rows = [
714816
715499
  top,
714817
- contentRow(`$ ${state.command}`, inner),
714818
- contentRow("", inner)
715500
+ contentRow2(`$ ${state.command}`, inner),
715501
+ contentRow2("", inner)
714819
715502
  ];
714820
715503
  if (hidden > 0)
714821
715504
  rows.push(
714822
- contentRow(`... ${hidden} earlier line${hidden === 1 ? "" : "s"}`, inner)
715505
+ contentRow2(`... ${hidden} earlier line${hidden === 1 ? "" : "s"}`, inner)
714823
715506
  );
714824
715507
  if (body.length === 0) {
714825
- rows.push(contentRow("(waiting for output)", inner));
715508
+ rows.push(contentRow2("(waiting for output)", inner));
714826
715509
  } else {
714827
- for (const line of body) rows.push(contentRow(line, inner));
715510
+ for (const line of body) rows.push(contentRow2(line, inner));
714828
715511
  }
714829
715512
  rows.push(bottom);
714830
715513
  return rows;
@@ -714836,10 +715519,10 @@ function pushShellLiveLine(state, line) {
714836
715519
  state.lines.splice(0, state.lines.length - maxStored);
714837
715520
  }
714838
715521
  }
714839
- function contentRow(value2, inner) {
714840
- return `│ ${fit2(value2, inner)} │`;
715522
+ function contentRow2(value2, inner) {
715523
+ return `│ ${fit3(value2, inner)} │`;
714841
715524
  }
714842
- function fit2(value2, width) {
715525
+ function fit3(value2, width) {
714843
715526
  const plain = value2.replace(ANSI_OR_OSC_RE, "").replace(/\s+$/g, "");
714844
715527
  const chars = Array.from(plain);
714845
715528
  if (chars.length > width) {
@@ -748668,6 +749351,8 @@ function appendSubAgentNoteBox(statusBar, agentId, event, title, metrics2, conte
748668
749351
  );
748669
749352
  }
748670
749353
  function writeSubAgentEventForView(statusBar, agentId, event, verbose = false) {
749354
+ const previewLine = formatSubAgentEventForView(event);
749355
+ statusBar.updateAgentViewEvent(agentId, event, previewLine ?? event.type);
748671
749356
  switch (event.type) {
748672
749357
  case "tool_call": {
748673
749358
  subAgentPendingToolCalls.set(agentId, {
@@ -748751,7 +749436,7 @@ function writeSubAgentEventForView(statusBar, agentId, event, verbose = false) {
748751
749436
  return true;
748752
749437
  }
748753
749438
  default: {
748754
- const line = formatSubAgentEventForView(event);
749439
+ const line = previewLine;
748755
749440
  if (line) statusBar.writeToAgentView(agentId, line);
748756
749441
  return Boolean(line);
748757
749442
  }
@@ -750374,7 +751059,7 @@ ${content}
750374
751059
  });
750375
751060
  statusBar.ensureMonitorTimer();
750376
751061
  },
750377
- onViewWrite: (id2, text2) => statusBar.writeToAgentView(id2, text2),
751062
+ onViewWrite: (id2, text2) => statusBar.recordAgentOutput(id2, text2),
750378
751063
  onViewEvent: (id2, event) => writeSubAgentEventForView(statusBar, id2, event, config.verbose),
750379
751064
  onViewStatus: (id2, status) => {
750380
751065
  statusBar.updateAgentViewStatus(id2, status);
@@ -750954,40 +751639,9 @@ ${entry.fullContent}`
750954
751639
  };
750955
751640
  runner.onEvent((event) => {
750956
751641
  emotionEngine?.appraise(event);
750957
- switch (event.type) {
750958
- case "tool_call": {
750959
- const tn = event.toolName ?? "";
750960
- if (tn === "file_read" || tn === "structured_read")
750961
- setStage("reading", tn);
750962
- else if (tn === "grep_search" || tn === "glob_find" || tn === "web_search" || tn === "web_fetch" || tn === "web_crawl")
750963
- setStage("searching", tn);
750964
- else if (tn === "file_write" || tn === "file_edit" || tn === "file_patch" || tn === "batch_edit" || tn === "structured_file")
750965
- setStage("writing", tn);
750966
- else if (tn === "shell" || tn === "shell_async" || tn === "run_tests" || tn === "repl_exec")
750967
- setStage("building", tn);
750968
- else setStage("tool_call", tn);
750969
- break;
750970
- }
750971
- case "stream_start":
750972
- setStage("planning");
750973
- break;
750974
- case "compaction":
750975
- setStage("compacting");
750976
- break;
750977
- case "debug_adversary":
750978
- setStage("adversary_audit");
750979
- break;
750980
- case "complete":
750981
- setStage("completed");
750982
- break;
750983
- case "error":
750984
- setStage("failed", event.content?.slice(0, 40));
750985
- break;
750986
- case "user_interrupt":
750987
- setStage("blocked");
750988
- break;
750989
- default:
750990
- break;
751642
+ const stageTransition = stageForAgentEvent(event);
751643
+ if (stageTransition) {
751644
+ setStage(stageTransition.stage, stageTransition.detail);
750991
751645
  }
750992
751646
  switch (event.type) {
750993
751647
  case "tool_call":
@@ -752406,7 +753060,7 @@ async function startInteractive(config, repoPath2) {
752406
753060
  });
752407
753061
  statusBar.ensureMonitorTimer();
752408
753062
  },
752409
- onViewWrite: (id2, text2) => statusBar.writeToAgentView(id2, text2),
753063
+ onViewWrite: (id2, text2) => statusBar.recordAgentOutput(id2, text2),
752410
753064
  onViewStatus: (id2, status) => {
752411
753065
  statusBar.updateAgentViewStatus(id2, status);
752412
753066
  const agent = registry2.subAgents.get(id2);
@@ -752447,7 +753101,7 @@ async function startInteractive(config, repoPath2) {
752447
753101
  });
752448
753102
  statusBar.ensureMonitorTimer();
752449
753103
  },
752450
- onViewWrite: (id2, text2) => statusBar.writeToAgentView(id2, text2),
753104
+ onViewWrite: (id2, text2) => statusBar.recordAgentOutput(id2, text2),
752451
753105
  onViewEvent: (id2, event) => writeSubAgentEventForView(statusBar, id2, event, config.verbose),
752452
753106
  onViewStatus: (id2, status) => {
752453
753107
  statusBar.updateAgentViewStatus(id2, status);
@@ -752661,7 +753315,7 @@ ${result.summary}`
752661
753315
  },
752662
753316
  // Stream the full sub-agent's stdout into its toolbar view so the
752663
753317
  // clickable tab shows live output instead of staying empty.
752664
- (text2) => statusBar.writeToAgentView(opts.id, text2),
753318
+ (text2) => statusBar.recordAgentOutput(opts.id, text2),
752665
753319
  (id2, exitCode) => statusBar.updateAgentViewStatus(
752666
753320
  opts.id,
752667
753321
  exitCode === 0 ? "completed" : "failed"
@@ -755250,7 +755904,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
755250
755904
  );
755251
755905
  statusBar.ensureMonitorTimer();
755252
755906
  },
755253
- onWrite: (id2, text2) => statusBar.writeToAgentView(id2, text2),
755907
+ onWrite: (id2, text2) => statusBar.recordAgentOutput(id2, text2),
755254
755908
  onStatus: (id2, status) => {
755255
755909
  statusBar.updateAgentViewStatus(id2, status);
755256
755910
  const agent = registry2.subAgents.get(id2);