omnius 1.0.88 → 1.0.90

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
@@ -3373,8 +3373,9 @@ function hashMismatchMessage(filePath, expectedHash, actualHash) {
3373
3373
  function fileContextHeader(filePath, content, range) {
3374
3374
  const totalLines = content.split("\n").length;
3375
3375
  const hash = contentHash(content);
3376
- const shown = range && (range.offset !== void 0 || range.limit !== void 0) ? ` showing=${range.offset ?? 1}-${range.limit ? (range.offset ?? 1) + range.limit - 1 : "end"}` : "";
3377
- return `[FILE CONTEXT path=${filePath} sha256=${hash} lines=${totalLines}${shown}]`;
3376
+ const shortHash2 = hash.slice(0, 12);
3377
+ const scope = range && (range.offset !== void 0 || range.limit !== void 0) ? `lines ${range.offset ?? 1}-${range.limit ? (range.offset ?? 1) + range.limit - 1 : totalLines} of ${totalLines}` : `${totalLines} lines`;
3378
+ return `[FILE CONTEXT | ${filePath} | ${scope} | sha256:${shortHash2}]`;
3378
3379
  }
3379
3380
  var init_edit_metadata = __esm({
3380
3381
  "packages/execution/dist/tools/edit-metadata.js"() {
@@ -544514,9 +544515,6 @@ ${memoryLines.join("\n")}`
544514
544515
  const churnBlock = this._renderWriteChurnBlock(turn);
544515
544516
  if (churnBlock)
544516
544517
  _injections.push(churnBlock);
544517
- const progressBlock = this._renderProgressNudgeBlock(turn);
544518
- if (progressBlock)
544519
- _injections.push(progressBlock);
544520
544518
  const knowledgeBlock = this._renderKnowledgeBlock(recentToolResults);
544521
544519
  if (knowledgeBlock)
544522
544520
  _injections.push(knowledgeBlock);
@@ -545062,55 +545060,6 @@ ${memoryLines.join("\n")}`
545062
545060
  return { tc, output: _decomp2Block };
545063
545061
  }
545064
545062
  }
545065
- const PROGRESS_GATE_BYPASS_TOOLS = /* @__PURE__ */ new Set([
545066
- "todo_write",
545067
- "todo_read",
545068
- "task_complete",
545069
- "ask_user",
545070
- "phase_recall"
545071
- // useful for the agent to consult prior phase state before updating
545072
- ]);
545073
- if (this._progressGateActive && !PROGRESS_GATE_BYPASS_TOOLS.has(tc.name)) {
545074
- this.emit({
545075
- type: "tool_call",
545076
- toolName: tc.name,
545077
- toolArgs: tc.arguments,
545078
- turn,
545079
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
545080
- });
545081
- const recentWrites = [];
545082
- for (const [path12, info] of this._worldFacts.files) {
545083
- if ((info.writeCount ?? 0) > 0 && (info.lastWriteTurn ?? -1) >= 0 && turn - (info.lastWriteTurn ?? 0) <= 8) {
545084
- recentWrites.push({ path: path12, turn: info.lastWriteTurn ?? 0 });
545085
- }
545086
- }
545087
- recentWrites.sort((a2, b) => b.turn - a2.turn);
545088
- const showWrites = recentWrites.slice(0, 16);
545089
- const gateMsg = [
545090
- `[PROGRESS GATE — call todo_write FIRST before any other tool]`,
545091
- ``,
545092
- `You have completed ${this._writesSinceLastTodoWrite} file modification${this._writesSinceLastTodoWrite === 1 ? "" : "s"} since your last todo_write call.`,
545093
- `The next tool call MUST be todo_write to mark progress. This is enforced — non-todo tool calls are intercepted until plan state is updated.`,
545094
- ``,
545095
- `Recent file modifications (use these to decide what's done):`,
545096
- ...showWrites.map((w) => ` • ${w.path} (turn ${w.turn})`),
545097
- recentWrites.length > showWrites.length ? ` • ... +${recentWrites.length - showWrites.length} more` : "",
545098
- ``,
545099
- `Required action: call todo_write with the updated todo array — mark anything completed that these writes satisfy, advance the next item to in_progress, keep the rest pending.`,
545100
- `After todo_write succeeds, this gate releases and you can continue normal work.`,
545101
- ``,
545102
- `Why this exists: without the explicit progress update, your next turn will see the same in_progress todo, re-plan the same work, and re-emit identical tool calls (the "plan replay" failure mode that causes byte-identical writes to appear twice).`
545103
- ].filter(Boolean).join("\n");
545104
- this.emit({
545105
- type: "tool_result",
545106
- toolName: tc.name,
545107
- success: false,
545108
- content: gateMsg.slice(0, 120),
545109
- turn,
545110
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
545111
- });
545112
- return { tc, output: gateMsg };
545113
- }
545114
545063
  const _argsKeyForBudget = `${tc.name}:${argsKey}`;
545115
545064
  const _isCachedHit = recentToolResults.has(_argsKeyForBudget);
545116
545065
  const budgetRemaining = toolCallBudget.get(tc.name);
@@ -548147,6 +548096,60 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
548147
548096
  fs11.appendFileSync(path12.join(trajDir, `trajectories.jsonl`), JSON.stringify(trajectory) + "\n", "utf-8");
548148
548097
  } catch {
548149
548098
  }
548099
+ let filesEdited;
548100
+ let testsRun;
548101
+ let provenanceAnchors;
548102
+ try {
548103
+ filesEdited = [...this._taskState.modifiedFiles.keys()].slice(0, 32);
548104
+ } catch {
548105
+ }
548106
+ try {
548107
+ const shellCommands = [];
548108
+ const provText = [];
548109
+ for (const entry of toolCallLog) {
548110
+ if (entry.name === "shell" || entry.name === "background_run") {
548111
+ const m2 = entry.argsKey.match(/(?:^|,)command=([^,]*)/);
548112
+ if (m2 && m2[1])
548113
+ shellCommands.push(m2[1]);
548114
+ }
548115
+ if (entry.outputPreview)
548116
+ provText.push(entry.outputPreview);
548117
+ }
548118
+ const testRunners = [
548119
+ /\b(?:pnpm|npm|yarn)\s+(?:run\s+)?(?:test|test:[\w-]+|typecheck|lint)\b[^&|;]*/,
548120
+ /\bvitest\s+(?:run\s+)?[\w\-/.@\s]*/,
548121
+ /\bjest\s+[\w\-/.@\s]*/,
548122
+ /\bpytest\s+[\w\-/.@\s]*/,
548123
+ /\bmocha\s+[\w\-/.@\s]*/,
548124
+ /\bgo\s+test\s+[\w./\s-]+/,
548125
+ /\bcargo\s+test\b[\w\s-]*/
548126
+ ];
548127
+ const tests = /* @__PURE__ */ new Set();
548128
+ for (const cmd of shellCommands) {
548129
+ for (const re of testRunners) {
548130
+ const m2 = cmd.match(re);
548131
+ if (m2) {
548132
+ const label = m2[0].replace(/\s+/g, " ").trim();
548133
+ if (label && label.length <= 80)
548134
+ tests.add(label);
548135
+ }
548136
+ }
548137
+ }
548138
+ if (tests.size > 0)
548139
+ testsRun = [...tests].slice(0, 16);
548140
+ const anchorRe = /(urn:omnius:[^\s"'<>)]+|aiwg-prov:[^\s"'<>)]+)/g;
548141
+ const anchors = /* @__PURE__ */ new Set();
548142
+ for (const text of provText) {
548143
+ for (const m2 of text.matchAll(anchorRe)) {
548144
+ const a2 = m2[0];
548145
+ if (a2.length <= 120)
548146
+ anchors.add(a2);
548147
+ }
548148
+ }
548149
+ if (anchors.size > 0)
548150
+ provenanceAnchors = [...anchors].slice(0, 16);
548151
+ } catch {
548152
+ }
548150
548153
  return {
548151
548154
  completed,
548152
548155
  turns: messages2.filter((m2) => m2.role === "assistant").length,
@@ -548156,7 +548159,10 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
548156
548159
  completionTokens,
548157
548160
  estimatedTokens,
548158
548161
  summary,
548159
- durationMs
548162
+ durationMs,
548163
+ filesEdited,
548164
+ testsRun,
548165
+ provenanceAnchors
548160
548166
  };
548161
548167
  }
548162
548168
  // -------------------------------------------------------------------------
@@ -562109,6 +562115,615 @@ var init_command_registry = __esm({
562109
562115
  }
562110
562116
  });
562111
562117
 
562118
+ // packages/cli/src/tui/text-selection.ts
562119
+ var text_selection_exports = {};
562120
+ __export(text_selection_exports, {
562121
+ SEL_END: () => SEL_END,
562122
+ SEL_START: () => SEL_START,
562123
+ TextSelection: () => TextSelection,
562124
+ computeHeaderButtons: () => computeHeaderButtons,
562125
+ copyText: () => copyText,
562126
+ hitTestHeaderButton: () => hitTestHeaderButton,
562127
+ pasteText: () => pasteText,
562128
+ renderHeaderButtons: () => renderHeaderButtons,
562129
+ setHoveredButton: () => setHoveredButton,
562130
+ setPressedButton: () => setPressedButton,
562131
+ setUpdateBadgeRegion: () => setUpdateBadgeRegion,
562132
+ stripAnsi: () => stripAnsi,
562133
+ visibleLength: () => visibleLength
562134
+ });
562135
+ import { execSync as execSync47 } from "node:child_process";
562136
+ function stripAnsi(s2) {
562137
+ return s2.replace(/\x1B\[[0-9;]*[A-Za-z]|\x1B\].*?(?:\x07|\x1B\\)/g, "");
562138
+ }
562139
+ function visibleLength(s2) {
562140
+ return stripAnsi(s2).length;
562141
+ }
562142
+ function copyText(text) {
562143
+ try {
562144
+ const platform7 = process.platform;
562145
+ if (platform7 === "darwin") {
562146
+ execSync47("pbcopy", { input: text, timeout: 3e3 });
562147
+ return true;
562148
+ }
562149
+ if (platform7 === "win32") {
562150
+ execSync47("clip", { input: text, timeout: 3e3 });
562151
+ return true;
562152
+ }
562153
+ for (const tool of ["xclip -selection clipboard", "xsel --clipboard --input", "wl-copy"]) {
562154
+ try {
562155
+ execSync47(tool, { input: text, timeout: 3e3 });
562156
+ return true;
562157
+ } catch {
562158
+ continue;
562159
+ }
562160
+ }
562161
+ if (!_clipboardAutoInstallAttempted) {
562162
+ _clipboardAutoInstallAttempted = true;
562163
+ try {
562164
+ execSync47("which apt-get", { timeout: 2e3, stdio: "pipe" });
562165
+ try {
562166
+ execSync47("sudo -n apt-get install -y xclip 2>/dev/null", { timeout: 15e3, stdio: "pipe" });
562167
+ execSync47("xclip -selection clipboard", { input: text, timeout: 3e3 });
562168
+ return true;
562169
+ } catch {
562170
+ }
562171
+ } catch {
562172
+ }
562173
+ }
562174
+ } catch {
562175
+ }
562176
+ try {
562177
+ const b64 = Buffer.from(text).toString("base64");
562178
+ process.stdout.write(`\x1B]52;c;${b64}\x07`);
562179
+ return true;
562180
+ } catch {
562181
+ }
562182
+ return false;
562183
+ }
562184
+ function pasteText() {
562185
+ try {
562186
+ const platform7 = process.platform;
562187
+ if (platform7 === "darwin") {
562188
+ return execSync47("pbpaste", { timeout: 3e3, encoding: "utf8" }).trimEnd();
562189
+ }
562190
+ if (platform7 === "win32") {
562191
+ return execSync47("powershell -command Get-Clipboard", { timeout: 3e3, encoding: "utf8" }).trimEnd();
562192
+ }
562193
+ for (const tool of [
562194
+ { cmd: "xclip", args: ["-selection", "clipboard", "-o"] },
562195
+ { cmd: "xsel", args: ["--clipboard", "--output"] },
562196
+ { cmd: "wl-paste", args: [] }
562197
+ ]) {
562198
+ try {
562199
+ const result = execSync47(`${tool.cmd} ${tool.args.join(" ")}`, { timeout: 3e3, encoding: "utf8" });
562200
+ return result.trimEnd();
562201
+ } catch {
562202
+ continue;
562203
+ }
562204
+ }
562205
+ } catch {
562206
+ }
562207
+ return null;
562208
+ }
562209
+ function computeHeaderButtons(_termWidth) {
562210
+ return [];
562211
+ }
562212
+ function setHoveredButton(cmd) {
562213
+ _hoveredButtonCmd = cmd;
562214
+ }
562215
+ function setPressedButton(cmd) {
562216
+ _pressedButtonCmd = cmd;
562217
+ }
562218
+ function renderHeaderButtons(_termWidth) {
562219
+ return "";
562220
+ }
562221
+ function setUpdateBadgeRegion(active, startCol, length4) {
562222
+ _updateBadgeActive = active;
562223
+ _updateBadgeCol = startCol;
562224
+ _updateBadgeLen = length4;
562225
+ }
562226
+ function hitTestHeaderButton(row, col, termWidth) {
562227
+ if (_updateBadgeActive && row === 1 && col >= _updateBadgeCol && col < _updateBadgeCol + _updateBadgeLen) {
562228
+ return "/update";
562229
+ }
562230
+ const hdrRow = layout().headerContent;
562231
+ if (row === hdrRow) {
562232
+ if (col <= 3) return "header-prev";
562233
+ if (col >= termWidth - 3) return "header-next";
562234
+ const btnDefs = [
562235
+ { cmd: "/help", label: " help " },
562236
+ { cmd: "/voice", label: " voice " },
562237
+ { cmd: "/model", label: " model " },
562238
+ { cmd: "/cohere", label: " cohere " }
562239
+ ];
562240
+ let btnEnd = termWidth - 4;
562241
+ for (let i2 = btnDefs.length - 1; i2 >= 0; i2--) {
562242
+ const btn = btnDefs[i2];
562243
+ const btnStart = btnEnd - btn.label.length;
562244
+ if (col >= btnStart && col <= btnEnd) return btn.cmd;
562245
+ btnEnd = btnStart - 1;
562246
+ }
562247
+ }
562248
+ return null;
562249
+ }
562250
+ var SEL_BG, SEL_FG, SEL_START, SEL_END, TextSelection, _clipboardAutoInstallAttempted, _hoveredButtonCmd, _pressedButtonCmd, _updateBadgeActive, _updateBadgeCol, _updateBadgeLen;
562251
+ var init_text_selection = __esm({
562252
+ "packages/cli/src/tui/text-selection.ts"() {
562253
+ "use strict";
562254
+ init_layout2();
562255
+ SEL_BG = 37;
562256
+ SEL_FG = 30;
562257
+ SEL_START = `\x1B[${SEL_FG}m\x1B[48;5;${SEL_BG}m`;
562258
+ SEL_END = `\x1B[0m`;
562259
+ TextSelection = class {
562260
+ _selection = null;
562261
+ _active = false;
562262
+ // true while mouse button is held
562263
+ _blockModeArmed = false;
562264
+ // Ctrl+Shift+B pressed, next click starts block select
562265
+ _provider;
562266
+ constructor(provider) {
562267
+ this._provider = provider;
562268
+ }
562269
+ /** Whether a selection currently exists */
562270
+ get hasSelection() {
562271
+ return this._selection !== null;
562272
+ }
562273
+ /** Whether we're actively dragging */
562274
+ get isDragging() {
562275
+ return this._active;
562276
+ }
562277
+ /** Get the current selection range (or null) */
562278
+ get selection() {
562279
+ return this._selection;
562280
+ }
562281
+ /** Arm block selection mode — next click starts rectangular select */
562282
+ armBlockMode() {
562283
+ this._blockModeArmed = true;
562284
+ }
562285
+ /** Clear the current selection */
562286
+ clear() {
562287
+ this._selection = null;
562288
+ this._active = false;
562289
+ this._blockModeArmed = false;
562290
+ }
562291
+ /**
562292
+ * Handle mouse press (button 0, M suffix in SGR).
562293
+ * Starts a new selection from the click position.
562294
+ */
562295
+ onMousePress(row, col) {
562296
+ const mode = this._blockModeArmed ? "block" : "line";
562297
+ this._blockModeArmed = false;
562298
+ this._selection = {
562299
+ anchor: { row, col },
562300
+ current: { row, col },
562301
+ mode
562302
+ };
562303
+ this._active = true;
562304
+ }
562305
+ /**
562306
+ * Handle mouse drag (button 32, M suffix in SGR).
562307
+ * Extends the selection to the current cursor position.
562308
+ */
562309
+ onMouseDrag(row, col) {
562310
+ if (!this._active || !this._selection) return;
562311
+ this._selection.current = { row, col };
562312
+ }
562313
+ /**
562314
+ * Handle mouse release (button 0, m suffix in SGR).
562315
+ * Finalizes the selection.
562316
+ */
562317
+ onMouseRelease(row, col) {
562318
+ if (!this._active || !this._selection) return;
562319
+ this._selection.current = { row, col };
562320
+ this._active = false;
562321
+ if (this._selection.anchor.row === this._selection.current.row && this._selection.anchor.col === this._selection.current.col) {
562322
+ this._selection = null;
562323
+ }
562324
+ }
562325
+ /**
562326
+ * Compute which content buffer indices and column ranges are selected.
562327
+ * Returns an array of { bufferIdx, startCol, endCol } for each selected line.
562328
+ * Columns are 0-based visible character positions.
562329
+ */
562330
+ getSelectedRanges() {
562331
+ if (!this._selection) return [];
562332
+ const { anchor, current, mode } = this._selection;
562333
+ const top = this._provider.getScrollRegionTop();
562334
+ const height = this._provider.getContentHeight();
562335
+ const offset = this._provider.getScrollOffset();
562336
+ const totalLines = this._provider.getContentLines().length;
562337
+ const startIdx = Math.max(0, totalLines - height - offset);
562338
+ const anchorBufIdx = startIdx + (anchor.row - top);
562339
+ const currentBufIdx = startIdx + (current.row - top);
562340
+ const minRow = Math.min(anchorBufIdx, currentBufIdx);
562341
+ const maxRow = Math.max(anchorBufIdx, currentBufIdx);
562342
+ const minCol = Math.min(anchor.col, current.col);
562343
+ const maxCol = Math.max(anchor.col, current.col);
562344
+ const ranges = [];
562345
+ if (mode === "block") {
562346
+ for (let idx = minRow; idx <= maxRow; idx++) {
562347
+ if (idx >= 0 && idx < totalLines) {
562348
+ ranges.push({ bufferIdx: idx, startCol: minCol - 1, endCol: maxCol - 1 });
562349
+ }
562350
+ }
562351
+ } else {
562352
+ const isForward = anchorBufIdx < currentBufIdx || anchorBufIdx === currentBufIdx && anchor.col <= current.col;
562353
+ const startR = isForward ? anchorBufIdx : currentBufIdx;
562354
+ const endR = isForward ? currentBufIdx : anchorBufIdx;
562355
+ const startC = isForward ? anchor.col - 1 : current.col - 1;
562356
+ const endC = isForward ? current.col - 1 : anchor.col - 1;
562357
+ for (let idx = startR; idx <= endR; idx++) {
562358
+ if (idx < 0 || idx >= totalLines) continue;
562359
+ const lineLen = visibleLength(this._provider.getContentLines()[idx] ?? "");
562360
+ if (idx === startR && idx === endR) {
562361
+ ranges.push({ bufferIdx: idx, startCol: startC, endCol: endC });
562362
+ } else if (idx === startR) {
562363
+ ranges.push({ bufferIdx: idx, startCol: startC, endCol: Math.max(lineLen, startC) });
562364
+ } else if (idx === endR) {
562365
+ ranges.push({ bufferIdx: idx, startCol: 0, endCol: endC });
562366
+ } else {
562367
+ ranges.push({ bufferIdx: idx, startCol: 0, endCol: lineLen });
562368
+ }
562369
+ }
562370
+ }
562371
+ return ranges;
562372
+ }
562373
+ /**
562374
+ * Apply selection highlighting to a content line for rendering.
562375
+ * Takes the original ANSI line and returns it with selection highlight applied.
562376
+ *
562377
+ * @param line Original content line (with ANSI codes)
562378
+ * @param startCol 0-based visible start column to highlight
562379
+ * @param endCol 0-based visible end column to highlight (inclusive)
562380
+ * @returns Line with selection highlight overlay
562381
+ */
562382
+ static applyHighlight(line, startCol, endCol) {
562383
+ const plain = stripAnsi(line);
562384
+ if (startCol > plain.length || endCol < 0 || startCol > endCol) return line;
562385
+ const sc = Math.max(0, startCol);
562386
+ const ec = Math.min(plain.length - 1, endCol);
562387
+ let result = "";
562388
+ let visPos = 0;
562389
+ let i2 = 0;
562390
+ let inHighlight = false;
562391
+ while (i2 < line.length) {
562392
+ const escMatch = line.slice(i2).match(/^(\x1B\[[0-9;]*[A-Za-z]|\x1B\].*?(?:\x07|\x1B\\))/);
562393
+ if (escMatch) {
562394
+ if (inHighlight) {
562395
+ result += SEL_END + escMatch[0] + SEL_START;
562396
+ } else {
562397
+ result += escMatch[0];
562398
+ }
562399
+ i2 += escMatch[0].length;
562400
+ continue;
562401
+ }
562402
+ if (visPos === sc && !inHighlight) {
562403
+ result += SEL_START;
562404
+ inHighlight = true;
562405
+ }
562406
+ result += line[i2];
562407
+ if (visPos === ec && inHighlight) {
562408
+ result += SEL_END;
562409
+ inHighlight = false;
562410
+ }
562411
+ visPos++;
562412
+ i2++;
562413
+ }
562414
+ if (inHighlight) result += SEL_END;
562415
+ return result;
562416
+ }
562417
+ /**
562418
+ * Get the selected text content (plain text, no ANSI codes).
562419
+ * For block mode, each line is joined with newline.
562420
+ * For line mode, text flows continuously with newlines between lines.
562421
+ */
562422
+ getSelectedText() {
562423
+ const ranges = this.getSelectedRanges();
562424
+ if (ranges.length === 0) return "";
562425
+ const lines = this._provider.getContentLines();
562426
+ const parts = [];
562427
+ for (const { bufferIdx, startCol, endCol } of ranges) {
562428
+ const raw = lines[bufferIdx] ?? "";
562429
+ const plain = stripAnsi(raw);
562430
+ const selected = plain.slice(
562431
+ Math.max(0, startCol),
562432
+ Math.min(plain.length, endCol + 1)
562433
+ );
562434
+ parts.push(selected);
562435
+ }
562436
+ return parts.join("\n");
562437
+ }
562438
+ /**
562439
+ * Copy current selection to system clipboard.
562440
+ * Tries platform commands first, falls back to OSC 52.
562441
+ * Returns true if copy succeeded.
562442
+ */
562443
+ copyToClipboard() {
562444
+ const text = this.getSelectedText();
562445
+ if (!text) return false;
562446
+ return copyText(text);
562447
+ }
562448
+ };
562449
+ _clipboardAutoInstallAttempted = false;
562450
+ _hoveredButtonCmd = null;
562451
+ _pressedButtonCmd = null;
562452
+ _updateBadgeActive = false;
562453
+ _updateBadgeCol = 0;
562454
+ _updateBadgeLen = 0;
562455
+ }
562456
+ });
562457
+
562458
+ // packages/cli/src/tui/task-complete-box.ts
562459
+ var task_complete_box_exports = {};
562460
+ __export(task_complete_box_exports, {
562461
+ buildBoxLines: () => buildBoxLines,
562462
+ deriveTitle: () => deriveTitle,
562463
+ detectProvenanceAnchors: () => detectProvenanceAnchors,
562464
+ detectTestRuns: () => detectTestRuns,
562465
+ renderTaskCompleteBox: () => renderTaskCompleteBox
562466
+ });
562467
+ function deriveTitle(task) {
562468
+ if (!task || !task.trim()) return "Task Complete";
562469
+ const cleaned = task.replace(/```[\s\S]*?```/g, " ").replace(/`[^`]+`/g, " ").replace(/\([^)]*\)/g, " ").replace(/[\r\n]+/g, " ").replace(/\s+/g, " ").trim();
562470
+ if (!cleaned) return "Task Complete";
562471
+ const firstSentence = cleaned.split(/(?<=[.!?:])\s/)[0] ?? cleaned;
562472
+ const words = firstSentence.split(/\s+/).filter((w) => w.length > 0);
562473
+ if (words.length === 0) return "Task Complete";
562474
+ if (words.length <= 10) return words.join(" ");
562475
+ return words.slice(0, 10).join(" ") + "…";
562476
+ }
562477
+ function formatDuration2(ms) {
562478
+ if (ms < 1e3) return `${ms}ms`;
562479
+ if (ms < 6e4) return `${(ms / 1e3).toFixed(1)}s`;
562480
+ const m2 = Math.floor(ms / 6e4);
562481
+ const s2 = Math.floor(ms % 6e4 / 1e3);
562482
+ return `${m2}m${s2.toString().padStart(2, "0")}s`;
562483
+ }
562484
+ function formatTokenCount(t2) {
562485
+ const n2 = t2.total > 0 ? t2.total : t2.estimated;
562486
+ if (n2 <= 0) return "";
562487
+ if (n2 < 1e3) return `${n2} tok`;
562488
+ if (n2 < 1e6) return `${(n2 / 1e3).toFixed(1)}k tok`;
562489
+ return `${(n2 / 1e6).toFixed(2)}M tok`;
562490
+ }
562491
+ function buildMetricsChip(data) {
562492
+ const parts = [];
562493
+ parts.push(`${data.turns} turn${data.turns === 1 ? "" : "s"}`);
562494
+ parts.push(`${data.toolCalls} call${data.toolCalls === 1 ? "" : "s"}`);
562495
+ if (data.tokens && data.durationMs > 0) {
562496
+ const total = data.tokens.total > 0 ? data.tokens.total : data.tokens.estimated;
562497
+ if (total > 0) {
562498
+ const tps = total / (data.durationMs / 1e3);
562499
+ if (tps >= 1) parts.push(`${tps.toFixed(0)} tps`);
562500
+ }
562501
+ }
562502
+ parts.push(formatDuration2(data.durationMs));
562503
+ if (data.tokens) {
562504
+ const tok = formatTokenCount(data.tokens);
562505
+ if (tok) parts.push(tok);
562506
+ }
562507
+ return parts.join(" · ");
562508
+ }
562509
+ function wrapToWidth(text, width) {
562510
+ if (width <= 0) return [text];
562511
+ const out = [];
562512
+ for (const paragraph of text.split(/\n/)) {
562513
+ if (paragraph.length === 0) {
562514
+ out.push("");
562515
+ continue;
562516
+ }
562517
+ let remaining = paragraph;
562518
+ while (remaining.length > width) {
562519
+ let breakAt = remaining.lastIndexOf(" ", width);
562520
+ if (breakAt <= 0) breakAt = width;
562521
+ out.push(remaining.slice(0, breakAt).trimEnd());
562522
+ remaining = remaining.slice(breakAt).trimStart();
562523
+ }
562524
+ out.push(remaining);
562525
+ }
562526
+ return out;
562527
+ }
562528
+ function wrapListItems(items, width) {
562529
+ if (items.length === 0) return [];
562530
+ const sep4 = " · ";
562531
+ const lines = [];
562532
+ let current = "";
562533
+ for (const item of items) {
562534
+ const candidate = current === "" ? item : current + sep4 + item;
562535
+ if (stripAnsi(candidate).length <= width) {
562536
+ current = candidate;
562537
+ } else {
562538
+ if (current) lines.push(current);
562539
+ if (stripAnsi(item).length > width) {
562540
+ const chunks = wrapToWidth(item, width);
562541
+ lines.push(...chunks.slice(0, -1));
562542
+ current = chunks[chunks.length - 1] ?? "";
562543
+ } else {
562544
+ current = item;
562545
+ }
562546
+ }
562547
+ }
562548
+ if (current) lines.push(current);
562549
+ return lines;
562550
+ }
562551
+ function buildTopBorder(title, metrics2, width) {
562552
+ const inner = Math.max(4, width - 2);
562553
+ const titleVisible = stripAnsi(title);
562554
+ const metricsVisible = stripAnsi(metrics2);
562555
+ const titleChip = ` ${titleVisible} `;
562556
+ const titleSpan = titleChip.length + 2;
562557
+ const metricsChip = metricsVisible ? ` ${metricsVisible} ` : "";
562558
+ const metricsSpan = metricsChip.length > 0 ? metricsChip.length + 2 : 0;
562559
+ let titleSegment;
562560
+ let metricsSegment;
562561
+ let fillerWidth;
562562
+ if (titleSpan + metricsSpan + 4 <= inner) {
562563
+ titleSegment = `${FG_BORDER}[${FG_TITLE}${titleChip}${RESET}${FG_BORDER}]`;
562564
+ metricsSegment = metricsChip ? `${FG_BORDER}[${FG_METRIC}${metricsChip}${RESET}${FG_BORDER}]` : "";
562565
+ fillerWidth = inner - titleSpan - metricsSpan - 2;
562566
+ } else if (titleSpan + 4 <= inner) {
562567
+ titleSegment = `${FG_BORDER}[${FG_TITLE}${titleChip}${RESET}${FG_BORDER}]`;
562568
+ metricsSegment = "";
562569
+ fillerWidth = inner - titleSpan - 2;
562570
+ } else {
562571
+ const room = Math.max(3, inner - 8);
562572
+ const truncated = titleVisible.length > room ? titleVisible.slice(0, Math.max(1, room - 1)) + "…" : titleVisible;
562573
+ titleSegment = `${FG_BORDER}[${FG_TITLE} ${truncated} ${RESET}${FG_BORDER}]`;
562574
+ metricsSegment = "";
562575
+ fillerWidth = Math.max(0, inner - (truncated.length + 4) - 2);
562576
+ }
562577
+ const leadDash = `${FG_BORDER}${BOX_H}`;
562578
+ const trailDash = `${FG_BORDER}${BOX_H}${RESET}`;
562579
+ const filler = fillerWidth > 0 ? `${FG_BORDER}${BOX_H.repeat(fillerWidth)}` : "";
562580
+ return `${FG_BORDER}${BOX_TL}${leadDash}${titleSegment}${filler}${metricsSegment}${trailDash}${FG_BORDER}${BOX_TR}${RESET}`;
562581
+ }
562582
+ function buildBottomBorder(width) {
562583
+ const inner = Math.max(0, width - 2);
562584
+ return `${FG_BORDER}${BOX_BL}${BOX_H.repeat(inner)}${BOX_BR}${RESET}`;
562585
+ }
562586
+ function buildInnerDivider(width) {
562587
+ const inner = Math.max(0, width - 2);
562588
+ return `${FG_BORDER}${BOX_TJ_L}${BOX_H.repeat(inner)}${BOX_TJ_R}${RESET}`;
562589
+ }
562590
+ function buildContentRow(content, width) {
562591
+ const innerWidth = Math.max(1, width - 4);
562592
+ const visible = stripAnsi(content);
562593
+ let padded = content;
562594
+ if (visible.length < innerWidth) {
562595
+ padded = content + " ".repeat(innerWidth - visible.length);
562596
+ } else if (visible.length > innerWidth) {
562597
+ padded = content;
562598
+ }
562599
+ return `${FG_BORDER}${BOX_V}${RESET} ${padded} ${FG_BORDER}${BOX_V}${RESET}`;
562600
+ }
562601
+ function buildEmptyRow(width) {
562602
+ return buildContentRow("", width);
562603
+ }
562604
+ function buildLabeledFooterLines(label, items, width) {
562605
+ if (items.length === 0) return [];
562606
+ const innerWidth = Math.max(8, width - 4);
562607
+ const labelText = `${FG_LABEL}${label}:${RESET} `;
562608
+ const labelVisible = `${label}: `.length;
562609
+ const continuation = " ".repeat(labelVisible);
562610
+ const itemListWidth = Math.max(8, innerWidth - labelVisible);
562611
+ const wrapped = wrapListItems(items, itemListWidth);
562612
+ if (wrapped.length === 0) return [];
562613
+ const lines = [];
562614
+ lines.push(buildContentRow(`${labelText}${wrapped[0]}`, width));
562615
+ for (let i2 = 1; i2 < wrapped.length; i2++) {
562616
+ lines.push(buildContentRow(`${continuation}${wrapped[i2]}`, width));
562617
+ }
562618
+ return lines;
562619
+ }
562620
+ function buildBoxLines(data, width) {
562621
+ const w = Math.max(40, width);
562622
+ const title = deriveTitle(data.task);
562623
+ const metrics2 = buildMetricsChip(data);
562624
+ const lines = [];
562625
+ lines.push(buildTopBorder(`${GREEN}✔${RESET} ${title}`, metrics2, w));
562626
+ const innerWidth = Math.max(1, w - 4);
562627
+ const bodyText = (data.summary ?? "").trim();
562628
+ if (bodyText) {
562629
+ lines.push(buildEmptyRow(w));
562630
+ for (const para of bodyText.split(/\n/)) {
562631
+ const wrapped = wrapToWidth(para, innerWidth);
562632
+ for (const line of wrapped) {
562633
+ lines.push(buildContentRow(line, w));
562634
+ }
562635
+ }
562636
+ lines.push(buildEmptyRow(w));
562637
+ }
562638
+ const hasFooter = (data.testsRun?.length ?? 0) > 0 || (data.filesEdited?.length ?? 0) > 0 || (data.provenanceAnchors?.length ?? 0) > 0;
562639
+ if (hasFooter) {
562640
+ lines.push(buildInnerDivider(w));
562641
+ if (data.testsRun?.length) {
562642
+ lines.push(...buildLabeledFooterLines("Tests", data.testsRun, w));
562643
+ }
562644
+ if (data.filesEdited?.length) {
562645
+ lines.push(...buildLabeledFooterLines("Files", data.filesEdited, w));
562646
+ }
562647
+ if (data.provenanceAnchors?.length) {
562648
+ lines.push(...buildLabeledFooterLines("Provenance", data.provenanceAnchors, w));
562649
+ }
562650
+ }
562651
+ lines.push(buildBottomBorder(w));
562652
+ return lines;
562653
+ }
562654
+ function renderTaskCompleteBox(host, data) {
562655
+ const blockId = `task-complete-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
562656
+ const frozen = {
562657
+ task: data.task,
562658
+ summary: data.summary,
562659
+ turns: data.turns,
562660
+ toolCalls: data.toolCalls,
562661
+ durationMs: data.durationMs,
562662
+ tokens: data.tokens ?? null,
562663
+ filesEdited: data.filesEdited ? [...data.filesEdited] : [],
562664
+ testsRun: data.testsRun ? [...data.testsRun] : [],
562665
+ provenanceAnchors: data.provenanceAnchors ? [...data.provenanceAnchors] : []
562666
+ };
562667
+ host.registerDynamicBlock(blockId, (width) => buildBoxLines(frozen, width));
562668
+ host.appendDynamicBlock(blockId);
562669
+ return blockId;
562670
+ }
562671
+ function detectTestRuns(shellCommands) {
562672
+ const out = /* @__PURE__ */ new Set();
562673
+ const runners = [
562674
+ /\b(?:pnpm|npm|yarn)\s+(?:run\s+)?(test|test:[\w-]+|typecheck|lint)\b/,
562675
+ /\bvitest\s+(?:run\s+)?[\w-/.@]*/,
562676
+ /\bjest\s+[\w-/.@]*/,
562677
+ /\bpytest\s+[\w-/.@]*/,
562678
+ /\bmocha\s+[\w-/.@]*/,
562679
+ /\bgo\s+test\s+[\w./]+/,
562680
+ /\bcargo\s+test\b[\w\s-]*/
562681
+ ];
562682
+ for (const cmd of shellCommands) {
562683
+ for (const re of runners) {
562684
+ const m2 = cmd.match(re);
562685
+ if (m2) {
562686
+ const label = m2[0].replace(/\s+/g, " ").trim();
562687
+ if (label.length <= 80) out.add(label);
562688
+ }
562689
+ }
562690
+ }
562691
+ return [...out].slice(0, 16);
562692
+ }
562693
+ function detectProvenanceAnchors(toolOutputs) {
562694
+ const out = /* @__PURE__ */ new Set();
562695
+ const re = /(urn:omnius:[^\s"'<>)]+|aiwg-prov:[^\s"'<>)]+)/g;
562696
+ for (const out_ of toolOutputs) {
562697
+ if (!out_) continue;
562698
+ for (const match of out_.matchAll(re)) {
562699
+ const anchor = match[0];
562700
+ if (anchor.length <= 120) out.add(anchor);
562701
+ }
562702
+ }
562703
+ return [...out].slice(0, 16);
562704
+ }
562705
+ var BOX_TL, BOX_TR, BOX_BL, BOX_BR, BOX_H, BOX_V, BOX_TJ_L, BOX_TJ_R, RESET, GREEN, FG_BORDER, FG_TITLE, FG_METRIC, FG_LABEL;
562706
+ var init_task_complete_box = __esm({
562707
+ "packages/cli/src/tui/task-complete-box.ts"() {
562708
+ "use strict";
562709
+ init_text_selection();
562710
+ BOX_TL = "╭";
562711
+ BOX_TR = "╮";
562712
+ BOX_BL = "╰";
562713
+ BOX_BR = "╯";
562714
+ BOX_H = "─";
562715
+ BOX_V = "│";
562716
+ BOX_TJ_L = "├";
562717
+ BOX_TJ_R = "┤";
562718
+ RESET = "\x1B[0m";
562719
+ GREEN = "\x1B[38;5;114m";
562720
+ FG_BORDER = "\x1B[38;5;245m";
562721
+ FG_TITLE = "\x1B[1;38;5;117m";
562722
+ FG_METRIC = "\x1B[38;5;222m";
562723
+ FG_LABEL = "\x1B[38;5;147m";
562724
+ }
562725
+ });
562726
+
562112
562727
  // packages/cli/src/tui/render.ts
562113
562728
  var render_exports = {};
562114
562729
  __export(render_exports, {
@@ -562355,16 +562970,16 @@ function renderToolResult(toolName, success, output, verbose) {
562355
562970
  `);
562356
562971
  return;
562357
562972
  }
562358
- renderCodePreview(output, prefix, maxW, 6);
562973
+ renderCodePreview(output, prefix, maxW, 10);
562359
562974
  return;
562360
562975
  }
562361
562976
  case "shell":
562362
562977
  case "background_run": {
562363
- renderShellOutput(output, success, prefix, maxW, 8);
562978
+ renderShellOutput(output, success, prefix, maxW, 10);
562364
562979
  return;
562365
562980
  }
562366
562981
  case "grep_search": {
562367
- renderShellOutput(output, success, prefix, maxW, 6);
562982
+ renderShellOutput(output, success, prefix, maxW, 10);
562368
562983
  return;
562369
562984
  }
562370
562985
  case "task_complete": {
@@ -562513,18 +563128,40 @@ function highlightToolOutput(line) {
562513
563128
  if (formatted !== line) return formatted;
562514
563129
  return c3.dim(line);
562515
563130
  }
562516
- function renderTaskComplete(summary, turns, toolCalls, durationMs, tokens) {
562517
- const duration = formatDuration2(durationMs);
562518
- const tokenStr = tokens ? ` ${formatTokenCount(tokens)}` : "";
563131
+ function renderTaskComplete(arg1, turns, toolCalls, durationMs, tokens) {
563132
+ const opts = typeof arg1 === "string" ? {
563133
+ summary: arg1,
563134
+ turns: turns ?? 0,
563135
+ toolCalls: toolCalls ?? 0,
563136
+ durationMs: durationMs ?? 0,
563137
+ tokens
563138
+ } : arg1;
563139
+ if (opts.host) {
563140
+ const { renderTaskCompleteBox: renderTaskCompleteBox2 } = (init_task_complete_box(), __toCommonJS(task_complete_box_exports));
563141
+ renderTaskCompleteBox2(opts.host, {
563142
+ task: opts.task ?? "",
563143
+ summary: opts.summary,
563144
+ turns: opts.turns,
563145
+ toolCalls: opts.toolCalls,
563146
+ durationMs: opts.durationMs,
563147
+ tokens: opts.tokens ?? null,
563148
+ filesEdited: opts.filesEdited,
563149
+ testsRun: opts.testsRun,
563150
+ provenanceAnchors: opts.provenanceAnchors
563151
+ });
563152
+ return;
563153
+ }
563154
+ const duration = formatDuration3(opts.durationMs);
563155
+ const tokenStr = opts.tokens ? ` ${formatTokenCount2(opts.tokens)}` : "";
562519
563156
  process.stdout.write(`
562520
- ${c3.green("✔")} ${c3.bold("Task completed")} ${c3.dim(`(${turns} turns, ${toolCalls} tool calls, ${duration})`)}
563157
+ ${c3.green("✔")} ${c3.bold("Task completed")} ${c3.dim(`(${opts.turns} turns, ${opts.toolCalls} tool calls, ${duration})`)}
562521
563158
  `);
562522
563159
  if (tokenStr) {
562523
563160
  process.stdout.write(` ${c3.dim(tokenStr)}
562524
563161
  `);
562525
563162
  }
562526
- if (summary) {
562527
- const formatted = formatMarkdownBlock(wrapTaskCompleteSummary(summary));
563163
+ if (opts.summary) {
563164
+ const formatted = formatMarkdownBlock(wrapTaskCompleteSummary(opts.summary));
562528
563165
  const lines = formatted.split("\n");
562529
563166
  for (const line of lines) {
562530
563167
  process.stdout.write(` ${line}
@@ -562579,8 +563216,8 @@ function hangingIndentForPlainLine(line, width) {
562579
563216
  return capped(line.match(/^\s*/)?.[0].length ?? 0);
562580
563217
  }
562581
563218
  function renderTaskIncomplete(turns, toolCalls, durationMs, tokens) {
562582
- const duration = formatDuration2(durationMs);
562583
- const tokenStr = tokens ? ` ${formatTokenCount(tokens)}` : "";
563219
+ const duration = formatDuration3(durationMs);
563220
+ const tokenStr = tokens ? ` ${formatTokenCount2(tokens)}` : "";
562584
563221
  process.stdout.write(`
562585
563222
  ${c3.yellow("⚠")} ${c3.bold("Task incomplete")} ${c3.dim(`(${turns} turns, ${toolCalls} tool calls, ${duration})`)}
562586
563223
  `);
@@ -562590,7 +563227,7 @@ ${c3.yellow("⚠")} ${c3.bold("Task incomplete")} ${c3.dim(`(${turns} turns, ${t
562590
563227
  }
562591
563228
  process.stdout.write("\n");
562592
563229
  }
562593
- function formatTokenCount(tokens) {
563230
+ function formatTokenCount2(tokens) {
562594
563231
  if (tokens.total > 0) {
562595
563232
  return `Tokens: ${tokens.total.toLocaleString()}`;
562596
563233
  }
@@ -562890,7 +563527,7 @@ function formatToolArgs(toolName, args, verbose) {
562890
563527
  function truncStr(s2, max) {
562891
563528
  return s2.length > max ? s2.slice(0, max) + "..." : s2;
562892
563529
  }
562893
- function formatDuration2(ms) {
563530
+ function formatDuration3(ms) {
562894
563531
  if (ms < 1e3) return `${ms}ms`;
562895
563532
  const totalSecs = ms / 1e3;
562896
563533
  if (totalSecs < 60) return `${totalSecs.toFixed(1)}s`;
@@ -563164,7 +563801,7 @@ var init_render = __esm({
563164
563801
 
563165
563802
  // packages/cli/src/tui/voice-session.ts
563166
563803
  import { createServer as createServer4 } from "node:http";
563167
- import { spawn as spawn23, execSync as execSync47 } from "node:child_process";
563804
+ import { spawn as spawn23, execSync as execSync48 } from "node:child_process";
563168
563805
  import { EventEmitter as EventEmitter6 } from "node:events";
563169
563806
  function generateFrontendHTML() {
563170
563807
  return `<!DOCTYPE html>
@@ -570251,346 +570888,6 @@ var init_system_metrics = __esm({
570251
570888
  }
570252
570889
  });
570253
570890
 
570254
- // packages/cli/src/tui/text-selection.ts
570255
- var text_selection_exports = {};
570256
- __export(text_selection_exports, {
570257
- SEL_END: () => SEL_END,
570258
- SEL_START: () => SEL_START,
570259
- TextSelection: () => TextSelection,
570260
- computeHeaderButtons: () => computeHeaderButtons,
570261
- copyText: () => copyText,
570262
- hitTestHeaderButton: () => hitTestHeaderButton,
570263
- pasteText: () => pasteText,
570264
- renderHeaderButtons: () => renderHeaderButtons,
570265
- setHoveredButton: () => setHoveredButton,
570266
- setPressedButton: () => setPressedButton,
570267
- setUpdateBadgeRegion: () => setUpdateBadgeRegion,
570268
- stripAnsi: () => stripAnsi,
570269
- visibleLength: () => visibleLength
570270
- });
570271
- import { execSync as execSync48 } from "node:child_process";
570272
- function stripAnsi(s2) {
570273
- return s2.replace(/\x1B\[[0-9;]*[A-Za-z]|\x1B\].*?(?:\x07|\x1B\\)/g, "");
570274
- }
570275
- function visibleLength(s2) {
570276
- return stripAnsi(s2).length;
570277
- }
570278
- function copyText(text) {
570279
- try {
570280
- const platform7 = process.platform;
570281
- if (platform7 === "darwin") {
570282
- execSync48("pbcopy", { input: text, timeout: 3e3 });
570283
- return true;
570284
- }
570285
- if (platform7 === "win32") {
570286
- execSync48("clip", { input: text, timeout: 3e3 });
570287
- return true;
570288
- }
570289
- for (const tool of ["xclip -selection clipboard", "xsel --clipboard --input", "wl-copy"]) {
570290
- try {
570291
- execSync48(tool, { input: text, timeout: 3e3 });
570292
- return true;
570293
- } catch {
570294
- continue;
570295
- }
570296
- }
570297
- if (!_clipboardAutoInstallAttempted) {
570298
- _clipboardAutoInstallAttempted = true;
570299
- try {
570300
- execSync48("which apt-get", { timeout: 2e3, stdio: "pipe" });
570301
- try {
570302
- execSync48("sudo -n apt-get install -y xclip 2>/dev/null", { timeout: 15e3, stdio: "pipe" });
570303
- execSync48("xclip -selection clipboard", { input: text, timeout: 3e3 });
570304
- return true;
570305
- } catch {
570306
- }
570307
- } catch {
570308
- }
570309
- }
570310
- } catch {
570311
- }
570312
- try {
570313
- const b64 = Buffer.from(text).toString("base64");
570314
- process.stdout.write(`\x1B]52;c;${b64}\x07`);
570315
- return true;
570316
- } catch {
570317
- }
570318
- return false;
570319
- }
570320
- function pasteText() {
570321
- try {
570322
- const platform7 = process.platform;
570323
- if (platform7 === "darwin") {
570324
- return execSync48("pbpaste", { timeout: 3e3, encoding: "utf8" }).trimEnd();
570325
- }
570326
- if (platform7 === "win32") {
570327
- return execSync48("powershell -command Get-Clipboard", { timeout: 3e3, encoding: "utf8" }).trimEnd();
570328
- }
570329
- for (const tool of [
570330
- { cmd: "xclip", args: ["-selection", "clipboard", "-o"] },
570331
- { cmd: "xsel", args: ["--clipboard", "--output"] },
570332
- { cmd: "wl-paste", args: [] }
570333
- ]) {
570334
- try {
570335
- const result = execSync48(`${tool.cmd} ${tool.args.join(" ")}`, { timeout: 3e3, encoding: "utf8" });
570336
- return result.trimEnd();
570337
- } catch {
570338
- continue;
570339
- }
570340
- }
570341
- } catch {
570342
- }
570343
- return null;
570344
- }
570345
- function computeHeaderButtons(_termWidth) {
570346
- return [];
570347
- }
570348
- function setHoveredButton(cmd) {
570349
- _hoveredButtonCmd = cmd;
570350
- }
570351
- function setPressedButton(cmd) {
570352
- _pressedButtonCmd = cmd;
570353
- }
570354
- function renderHeaderButtons(_termWidth) {
570355
- return "";
570356
- }
570357
- function setUpdateBadgeRegion(active, startCol, length4) {
570358
- _updateBadgeActive = active;
570359
- _updateBadgeCol = startCol;
570360
- _updateBadgeLen = length4;
570361
- }
570362
- function hitTestHeaderButton(row, col, termWidth) {
570363
- if (_updateBadgeActive && row === 1 && col >= _updateBadgeCol && col < _updateBadgeCol + _updateBadgeLen) {
570364
- return "/update";
570365
- }
570366
- const hdrRow = layout().headerContent;
570367
- if (row === hdrRow) {
570368
- if (col <= 3) return "header-prev";
570369
- if (col >= termWidth - 3) return "header-next";
570370
- const btnDefs = [
570371
- { cmd: "/help", label: " help " },
570372
- { cmd: "/voice", label: " voice " },
570373
- { cmd: "/model", label: " model " },
570374
- { cmd: "/cohere", label: " cohere " }
570375
- ];
570376
- let btnEnd = termWidth - 4;
570377
- for (let i2 = btnDefs.length - 1; i2 >= 0; i2--) {
570378
- const btn = btnDefs[i2];
570379
- const btnStart = btnEnd - btn.label.length;
570380
- if (col >= btnStart && col <= btnEnd) return btn.cmd;
570381
- btnEnd = btnStart - 1;
570382
- }
570383
- }
570384
- return null;
570385
- }
570386
- var SEL_BG, SEL_FG, SEL_START, SEL_END, TextSelection, _clipboardAutoInstallAttempted, _hoveredButtonCmd, _pressedButtonCmd, _updateBadgeActive, _updateBadgeCol, _updateBadgeLen;
570387
- var init_text_selection = __esm({
570388
- "packages/cli/src/tui/text-selection.ts"() {
570389
- "use strict";
570390
- init_layout2();
570391
- SEL_BG = 37;
570392
- SEL_FG = 30;
570393
- SEL_START = `\x1B[${SEL_FG}m\x1B[48;5;${SEL_BG}m`;
570394
- SEL_END = `\x1B[0m`;
570395
- TextSelection = class {
570396
- _selection = null;
570397
- _active = false;
570398
- // true while mouse button is held
570399
- _blockModeArmed = false;
570400
- // Ctrl+Shift+B pressed, next click starts block select
570401
- _provider;
570402
- constructor(provider) {
570403
- this._provider = provider;
570404
- }
570405
- /** Whether a selection currently exists */
570406
- get hasSelection() {
570407
- return this._selection !== null;
570408
- }
570409
- /** Whether we're actively dragging */
570410
- get isDragging() {
570411
- return this._active;
570412
- }
570413
- /** Get the current selection range (or null) */
570414
- get selection() {
570415
- return this._selection;
570416
- }
570417
- /** Arm block selection mode — next click starts rectangular select */
570418
- armBlockMode() {
570419
- this._blockModeArmed = true;
570420
- }
570421
- /** Clear the current selection */
570422
- clear() {
570423
- this._selection = null;
570424
- this._active = false;
570425
- this._blockModeArmed = false;
570426
- }
570427
- /**
570428
- * Handle mouse press (button 0, M suffix in SGR).
570429
- * Starts a new selection from the click position.
570430
- */
570431
- onMousePress(row, col) {
570432
- const mode = this._blockModeArmed ? "block" : "line";
570433
- this._blockModeArmed = false;
570434
- this._selection = {
570435
- anchor: { row, col },
570436
- current: { row, col },
570437
- mode
570438
- };
570439
- this._active = true;
570440
- }
570441
- /**
570442
- * Handle mouse drag (button 32, M suffix in SGR).
570443
- * Extends the selection to the current cursor position.
570444
- */
570445
- onMouseDrag(row, col) {
570446
- if (!this._active || !this._selection) return;
570447
- this._selection.current = { row, col };
570448
- }
570449
- /**
570450
- * Handle mouse release (button 0, m suffix in SGR).
570451
- * Finalizes the selection.
570452
- */
570453
- onMouseRelease(row, col) {
570454
- if (!this._active || !this._selection) return;
570455
- this._selection.current = { row, col };
570456
- this._active = false;
570457
- if (this._selection.anchor.row === this._selection.current.row && this._selection.anchor.col === this._selection.current.col) {
570458
- this._selection = null;
570459
- }
570460
- }
570461
- /**
570462
- * Compute which content buffer indices and column ranges are selected.
570463
- * Returns an array of { bufferIdx, startCol, endCol } for each selected line.
570464
- * Columns are 0-based visible character positions.
570465
- */
570466
- getSelectedRanges() {
570467
- if (!this._selection) return [];
570468
- const { anchor, current, mode } = this._selection;
570469
- const top = this._provider.getScrollRegionTop();
570470
- const height = this._provider.getContentHeight();
570471
- const offset = this._provider.getScrollOffset();
570472
- const totalLines = this._provider.getContentLines().length;
570473
- const startIdx = Math.max(0, totalLines - height - offset);
570474
- const anchorBufIdx = startIdx + (anchor.row - top);
570475
- const currentBufIdx = startIdx + (current.row - top);
570476
- const minRow = Math.min(anchorBufIdx, currentBufIdx);
570477
- const maxRow = Math.max(anchorBufIdx, currentBufIdx);
570478
- const minCol = Math.min(anchor.col, current.col);
570479
- const maxCol = Math.max(anchor.col, current.col);
570480
- const ranges = [];
570481
- if (mode === "block") {
570482
- for (let idx = minRow; idx <= maxRow; idx++) {
570483
- if (idx >= 0 && idx < totalLines) {
570484
- ranges.push({ bufferIdx: idx, startCol: minCol - 1, endCol: maxCol - 1 });
570485
- }
570486
- }
570487
- } else {
570488
- const isForward = anchorBufIdx < currentBufIdx || anchorBufIdx === currentBufIdx && anchor.col <= current.col;
570489
- const startR = isForward ? anchorBufIdx : currentBufIdx;
570490
- const endR = isForward ? currentBufIdx : anchorBufIdx;
570491
- const startC = isForward ? anchor.col - 1 : current.col - 1;
570492
- const endC = isForward ? current.col - 1 : anchor.col - 1;
570493
- for (let idx = startR; idx <= endR; idx++) {
570494
- if (idx < 0 || idx >= totalLines) continue;
570495
- const lineLen = visibleLength(this._provider.getContentLines()[idx] ?? "");
570496
- if (idx === startR && idx === endR) {
570497
- ranges.push({ bufferIdx: idx, startCol: startC, endCol: endC });
570498
- } else if (idx === startR) {
570499
- ranges.push({ bufferIdx: idx, startCol: startC, endCol: Math.max(lineLen, startC) });
570500
- } else if (idx === endR) {
570501
- ranges.push({ bufferIdx: idx, startCol: 0, endCol: endC });
570502
- } else {
570503
- ranges.push({ bufferIdx: idx, startCol: 0, endCol: lineLen });
570504
- }
570505
- }
570506
- }
570507
- return ranges;
570508
- }
570509
- /**
570510
- * Apply selection highlighting to a content line for rendering.
570511
- * Takes the original ANSI line and returns it with selection highlight applied.
570512
- *
570513
- * @param line Original content line (with ANSI codes)
570514
- * @param startCol 0-based visible start column to highlight
570515
- * @param endCol 0-based visible end column to highlight (inclusive)
570516
- * @returns Line with selection highlight overlay
570517
- */
570518
- static applyHighlight(line, startCol, endCol) {
570519
- const plain = stripAnsi(line);
570520
- if (startCol > plain.length || endCol < 0 || startCol > endCol) return line;
570521
- const sc = Math.max(0, startCol);
570522
- const ec = Math.min(plain.length - 1, endCol);
570523
- let result = "";
570524
- let visPos = 0;
570525
- let i2 = 0;
570526
- let inHighlight = false;
570527
- while (i2 < line.length) {
570528
- const escMatch = line.slice(i2).match(/^(\x1B\[[0-9;]*[A-Za-z]|\x1B\].*?(?:\x07|\x1B\\))/);
570529
- if (escMatch) {
570530
- if (inHighlight) {
570531
- result += SEL_END + escMatch[0] + SEL_START;
570532
- } else {
570533
- result += escMatch[0];
570534
- }
570535
- i2 += escMatch[0].length;
570536
- continue;
570537
- }
570538
- if (visPos === sc && !inHighlight) {
570539
- result += SEL_START;
570540
- inHighlight = true;
570541
- }
570542
- result += line[i2];
570543
- if (visPos === ec && inHighlight) {
570544
- result += SEL_END;
570545
- inHighlight = false;
570546
- }
570547
- visPos++;
570548
- i2++;
570549
- }
570550
- if (inHighlight) result += SEL_END;
570551
- return result;
570552
- }
570553
- /**
570554
- * Get the selected text content (plain text, no ANSI codes).
570555
- * For block mode, each line is joined with newline.
570556
- * For line mode, text flows continuously with newlines between lines.
570557
- */
570558
- getSelectedText() {
570559
- const ranges = this.getSelectedRanges();
570560
- if (ranges.length === 0) return "";
570561
- const lines = this._provider.getContentLines();
570562
- const parts = [];
570563
- for (const { bufferIdx, startCol, endCol } of ranges) {
570564
- const raw = lines[bufferIdx] ?? "";
570565
- const plain = stripAnsi(raw);
570566
- const selected = plain.slice(
570567
- Math.max(0, startCol),
570568
- Math.min(plain.length, endCol + 1)
570569
- );
570570
- parts.push(selected);
570571
- }
570572
- return parts.join("\n");
570573
- }
570574
- /**
570575
- * Copy current selection to system clipboard.
570576
- * Tries platform commands first, falls back to OSC 52.
570577
- * Returns true if copy succeeded.
570578
- */
570579
- copyToClipboard() {
570580
- const text = this.getSelectedText();
570581
- if (!text) return false;
570582
- return copyText(text);
570583
- }
570584
- };
570585
- _clipboardAutoInstallAttempted = false;
570586
- _hoveredButtonCmd = null;
570587
- _pressedButtonCmd = null;
570588
- _updateBadgeActive = false;
570589
- _updateBadgeCol = 0;
570590
- _updateBadgeLen = 0;
570591
- }
570592
- });
570593
-
570594
570891
  // packages/cli/src/tui/daemon-registry.ts
570595
570892
  var DaemonRegistry, registry2;
570596
570893
  var init_daemon_registry = __esm({
@@ -571003,16 +571300,16 @@ function buildTodoProgressBar(todos, maxWidth) {
571003
571300
  for (let i2 = 0; i2 < cells; i2++) {
571004
571301
  const t2 = todos[i2];
571005
571302
  if (t2.status === "completed") {
571006
- out += `\x1B[1m${DONE_Y}█${RESET}`;
571303
+ out += `\x1B[1m${DONE_Y}█${RESET2}`;
571007
571304
  } else if (i2 === inIdx) {
571008
- out += `${INPROG}▒${RESET}`;
571305
+ out += `${INPROG}▒${RESET2}`;
571009
571306
  } else if (i2 === nextIdx && inIdx >= 0) {
571010
- out += `${NEXT}▒${RESET}`;
571307
+ out += `${NEXT}▒${RESET2}`;
571011
571308
  } else {
571012
- out += `${PEND}░${RESET}`;
571309
+ out += `${PEND}░${RESET2}`;
571013
571310
  }
571014
571311
  }
571015
- if (truncated && maxWidth > 0) out += `${DIM_LABEL}…${RESET}`;
571312
+ if (truncated && maxWidth > 0) out += `${DIM_LABEL}…${RESET2}`;
571016
571313
  return out;
571017
571314
  }
571018
571315
  function render() {
@@ -571034,7 +571331,7 @@ function render() {
571034
571331
  const total = _lastTodos.length;
571035
571332
  const headerColor = ACCENT;
571036
571333
  const lines = [];
571037
- const headerPrefix = `tasks ${headerColor}${completed}/${total}${RESET} `;
571334
+ const headerPrefix = `tasks ${headerColor}${completed}/${total}${RESET2} `;
571038
571335
  const headerPrefixWidth = visualLen(headerPrefix);
571039
571336
  const maxBarWidth = Math.max(0, cols - 2 - headerPrefixWidth);
571040
571337
  const progressBar = buildTodoProgressBar(_lastTodos, maxBarWidth);
@@ -571046,11 +571343,11 @@ function render() {
571046
571343
  const contentWidth = Math.max(4, cols - 8);
571047
571344
  const contentText = t2.content + (t2.blocker ? ` (blocked: ${t2.blocker})` : "");
571048
571345
  const truncated = truncate2(contentText, contentWidth);
571049
- lines.push(`${color}${mark}${RESET} ${color}${truncated}${RESET}`);
571346
+ lines.push(`${color}${mark}${RESET2} ${color}${truncated}${RESET2}`);
571050
571347
  }
571051
571348
  if (_lastTodos.length > visible.length) {
571052
571349
  const more = _lastTodos.length - visible.length;
571053
- lines[lines.length - 1] = `${DIM_LABEL}… +${more} more${RESET}`;
571350
+ lines[lines.length - 1] = `${DIM_LABEL}… +${more} more${RESET2}`;
571054
571351
  }
571055
571352
  let out = HIDE + SAVE;
571056
571353
  const newTop = L.tasksTop;
@@ -571067,7 +571364,7 @@ function render() {
571067
571364
  for (let i2 = 0; i2 < lines.length; i2++) {
571068
571365
  const row = L.tasksTop + i2;
571069
571366
  if (row > L.tasksBottom) break;
571070
- out += `\x1B[${row};1H${CLEAR_LINE}${BG}${" ".repeat(cols)}\x1B[${row};2H${lines[i2]}${RESET}`;
571367
+ out += `\x1B[${row};1H${CLEAR_LINE}${BG}${" ".repeat(cols)}\x1B[${row};2H${lines[i2]}${RESET2}`;
571071
571368
  }
571072
571369
  out += RESTORE + SHOW;
571073
571370
  try {
@@ -571095,7 +571392,7 @@ function clearLastPaintedRows() {
571095
571392
  _lastPaintedTop = -1;
571096
571393
  _lastPaintedBottom = -1;
571097
571394
  }
571098
- var chromeWrite, _activeSessionId, _watcher, _lastTodos, _enabled, _redrawScheduled, _onResizeChange, _scopeOverlayActive, _scopeMainViewActive, _scopeNeovimActive, _scopePagerActive, _lastPaintedTop, _lastPaintedBottom, MAX_VISIBLE_ROWS, SAVE, RESTORE, HIDE, SHOW, CLEAR_LINE, RESET, BG, DIM_LABEL, ACCENT, DONE2, PENDING, BLOCKED;
571395
+ var chromeWrite, _activeSessionId, _watcher, _lastTodos, _enabled, _redrawScheduled, _onResizeChange, _scopeOverlayActive, _scopeMainViewActive, _scopeNeovimActive, _scopePagerActive, _lastPaintedTop, _lastPaintedBottom, MAX_VISIBLE_ROWS, SAVE, RESTORE, HIDE, SHOW, CLEAR_LINE, RESET2, BG, DIM_LABEL, ACCENT, DONE2, PENDING, BLOCKED;
571099
571396
  var init_tui_tasks_renderer = __esm({
571100
571397
  "packages/cli/src/tui/tui-tasks-renderer.ts"() {
571101
571398
  "use strict";
@@ -571122,7 +571419,7 @@ var init_tui_tasks_renderer = __esm({
571122
571419
  HIDE = "\x1B[?25l";
571123
571420
  SHOW = "\x1B[?25h";
571124
571421
  CLEAR_LINE = "\x1B[2K";
571125
- RESET = "\x1B[0m";
571422
+ RESET2 = "\x1B[0m";
571126
571423
  BG = tuiBgSeq();
571127
571424
  DIM_LABEL = "";
571128
571425
  ACCENT = "";
@@ -571169,7 +571466,7 @@ function setTerminalTitle(task, version4) {
571169
571466
  const title = task ? `${task.slice(0, 60)} · ${ver}` : ver;
571170
571467
  process.stdout.write(`\x1B]2;${title}\x07`);
571171
571468
  }
571172
- var EXPERT_TOOL_BASELINES, CONTEXT_SWITCH_OVERHEAD, TURN_PLANNING_OVERHEAD, DEFAULT_TOOL_BASELINE, CODE_READ_CHARS_PER_SEC, PROSE_READ_CHARS_PER_SEC, MIN_CONTENT_FOR_READING, CODE_CONTENT_TOOLS, PROSE_CONTENT_TOOLS, HumanSpeedTracker, PANEL_BG_SEQ, CONTENT_BG_SEQ, BOX_FG, TEXT_PRIMARY, TEXT_DIM, NO_SUB_AGENTS_HEADER_LABEL, BOX_TL, BOX_TR, BOX_BL, BOX_BR, BOX_H, BOX_V, _globalFooterLock, RESET2, CURSOR_BLINK_BLOCK, _isWindows, StatusBar;
571469
+ var EXPERT_TOOL_BASELINES, CONTEXT_SWITCH_OVERHEAD, TURN_PLANNING_OVERHEAD, DEFAULT_TOOL_BASELINE, CODE_READ_CHARS_PER_SEC, PROSE_READ_CHARS_PER_SEC, MIN_CONTENT_FOR_READING, CODE_CONTENT_TOOLS, PROSE_CONTENT_TOOLS, HumanSpeedTracker, PANEL_BG_SEQ, CONTENT_BG_SEQ, BOX_FG, TEXT_PRIMARY, TEXT_DIM, NO_SUB_AGENTS_HEADER_LABEL, BOX_TL2, BOX_TR2, BOX_BL2, BOX_BR2, BOX_H2, BOX_V2, _globalFooterLock, RESET3, CURSOR_BLINK_BLOCK, _isWindows, StatusBar;
571173
571470
  var init_status_bar = __esm({
571174
571471
  "packages/cli/src/tui/status-bar.ts"() {
571175
571472
  "use strict";
@@ -571348,14 +571645,14 @@ var init_status_bar = __esm({
571348
571645
  TEXT_PRIMARY = tuiTextPrimary() < 0 ? 252 : tuiTextPrimary();
571349
571646
  TEXT_DIM = tuiTextDim();
571350
571647
  NO_SUB_AGENTS_HEADER_LABEL = " no sub-agents ";
571351
- BOX_TL = "╭";
571352
- BOX_TR = "╮";
571353
- BOX_BL = "╰";
571354
- BOX_BR = "╯";
571355
- BOX_H = "─";
571356
- BOX_V = "│";
571648
+ BOX_TL2 = "╭";
571649
+ BOX_TR2 = "╮";
571650
+ BOX_BL2 = "╰";
571651
+ BOX_BR2 = "╯";
571652
+ BOX_H2 = "─";
571653
+ BOX_V2 = "│";
571357
571654
  _globalFooterLock = false;
571358
- RESET2 = "\x1B[0m";
571655
+ RESET3 = "\x1B[0m";
571359
571656
  CURSOR_BLINK_BLOCK = "\x1B[1 q";
571360
571657
  _isWindows = process.platform === "win32";
571361
571658
  StatusBar = class _StatusBar {
@@ -571401,6 +571698,22 @@ var init_status_bar = __esm({
571401
571698
  _contentScrollOffset = 0;
571402
571699
  // 0 = live (bottom), >0 = scrolled back
571403
571700
  _contentMaxLines = 1e4;
571701
+ /**
571702
+ * Dynamic content blocks — width-aware regions that re-render themselves
571703
+ * when the terminal resizes. The renderer registered here is called from
571704
+ * the scrollback reflow path: when a sentinel line of the form
571705
+ * `\x01DYNBLOCK:<id>\x01` is encountered, the registered fn is invoked
571706
+ * with the current terminal width and its returned lines replace the
571707
+ * sentinel in the reflowed output. This is how the Task Complete box
571708
+ * stays geometrically correct under SIGWINCH-driven resize.
571709
+ *
571710
+ * Keep the renderer cheap (pure data → strings) — it runs every full
571711
+ * repaint, including selection updates and scroll events.
571712
+ */
571713
+ _dynamicBlocks = /* @__PURE__ */ new Map();
571714
+ /** Sentinel marker — used both for scrollback storage and reflow detection. */
571715
+ DYNAMIC_BLOCK_MARK_PREFIX = "DYNBLOCK:";
571716
+ DYNAMIC_BLOCK_MARK_SUFFIX = "";
571404
571717
  // Partial-line accumulator for the buffered-write layer. Stream output
571405
571718
  // arrives in chunks (one per syntax-highlighted token) and a single
571406
571719
  // logical line can span many writes. If we naively push each chunk to
@@ -571511,10 +571824,54 @@ var init_status_bar = __esm({
571511
571824
  syncEnd() {
571512
571825
  this.termWrite("\x1B[?2026l");
571513
571826
  }
571514
- /** Force a complete footer redraw (public wrapper for renderFooterAndPositionInput) */
571827
+ /**
571828
+ * Register (or replace) a dynamic content block. Returns the sentinel
571829
+ * line the caller should push into the scrollback to make the block
571830
+ * appear there. The block's renderer is invoked on every repaint and
571831
+ * given the current terminal width; its returned lines are spliced in
571832
+ * place of the sentinel during reflow. Callers MUST also call
571833
+ * `appendDynamicBlock(id)` to actually place the block in scrollback.
571834
+ *
571835
+ * The sentinel is opaque — never write it directly to stdout; route
571836
+ * through `appendDynamicBlock` which also triggers a repaint so the
571837
+ * block becomes visible immediately.
571838
+ */
571839
+ registerDynamicBlock(id, render2) {
571840
+ this._dynamicBlocks.set(id, render2);
571841
+ return `${this.DYNAMIC_BLOCK_MARK_PREFIX}${id}${this.DYNAMIC_BLOCK_MARK_SUFFIX}`;
571842
+ }
571843
+ /** Unregister a dynamic block. Existing sentinels in scrollback become inert (rendered as empty). */
571844
+ unregisterDynamicBlock(id) {
571845
+ this._dynamicBlocks.delete(id);
571846
+ }
571847
+ /**
571848
+ * Append a previously-registered dynamic block's sentinel to scrollback
571849
+ * and trigger a repaint. The block's renderer fires immediately at the
571850
+ * current terminal width and again on every subsequent SIGWINCH (because
571851
+ * `_handleResizeImmediate` already calls `repaintContent`).
571852
+ */
571853
+ appendDynamicBlock(id) {
571854
+ if (!this._dynamicBlocks.has(id)) return;
571855
+ const sentinel = `${this.DYNAMIC_BLOCK_MARK_PREFIX}${id}${this.DYNAMIC_BLOCK_MARK_SUFFIX}`;
571856
+ this._contentLines.push(sentinel);
571857
+ if (this._contentLines.length > this._contentMaxLines) {
571858
+ this._contentLines.splice(0, this._contentLines.length - this._contentMaxLines);
571859
+ }
571860
+ if (this.active) this.repaintContent();
571861
+ }
571862
+ /** Force a complete footer redraw (public wrapper for renderFooterAndPositionInput).
571863
+ *
571864
+ * IMPORTANT: do NOT call `updateFooterHeight()` here. The inner render
571865
+ * function captures `oldFooterTop` from the CURRENT `_currentFooterHeight`
571866
+ * BEFORE updating it, so it can detect height changes and clear the
571867
+ * rows that the old (taller) footer used to occupy. Pre-calling
571868
+ * `updateFooterHeight` here would mutate the height to the new value
571869
+ * first, leaving the inner render to think nothing changed and skipping
571870
+ * the transition-row clear — which is exactly what caused stale prompt
571871
+ * text to remain on the input box's top unicode border after submitting
571872
+ * a multi-line input. */
571515
571873
  redrawFooter() {
571516
571874
  if (!this.active) return;
571517
- this.updateFooterHeight();
571518
571875
  this.renderFooterAndPositionInput();
571519
571876
  }
571520
571877
  /** Callback to get available slash commands for suggestion matching */
@@ -571638,7 +571995,7 @@ var init_status_bar = __esm({
571638
571995
  const segment = segments[i2];
571639
571996
  if (i2 > 0) {
571640
571997
  separatorOffsets.push(width);
571641
- text += `${BOX_FG}${BOX_V}${RESET2}${PANEL_BG_SEQ}`;
571998
+ text += `${BOX_FG}${BOX_V2}${RESET3}${PANEL_BG_SEQ}`;
571642
571999
  width += 1;
571643
572000
  }
571644
572001
  text += `\x1B[1;38;5;${TEXT_PRIMARY}m${PANEL_BG_SEQ}${segment}`;
@@ -571820,7 +572177,7 @@ var init_status_bar = __esm({
571820
572177
  const sysSeparatorOffset = sysItems.reduce((sum, item) => sum + item.w, 0);
571821
572178
  this._sysSeparatorOffset = sysSeparatorOffset;
571822
572179
  sysItems.push({
571823
- render: () => `${BOX_FG}│${RESET2}${PANEL_BG_SEQ} `,
572180
+ render: () => `${BOX_FG}│${RESET3}${PANEL_BG_SEQ} `,
571824
572181
  w: 2
571825
572182
  });
571826
572183
  const voiceLabel = this._voiceActive ? ` ${this._voiceModelId || "voice"} ` : " voice ";
@@ -572017,7 +572374,7 @@ var init_status_bar = __esm({
572017
572374
  const hdrRow = layout().headerContent;
572018
572375
  let buf = "\x1B7";
572019
572376
  buf += `\x1B[${hdrRow};1H${PANEL_BG_SEQ}\x1B[2K`;
572020
- buf += `${BOX_FG}│${RESET2}${PANEL_BG_SEQ}`;
572377
+ buf += `${BOX_FG}│${RESET3}${PANEL_BG_SEQ}`;
572021
572378
  if (chrome.showPrev) {
572022
572379
  buf += leftArrow;
572023
572380
  buf += ` `;
@@ -572028,7 +572385,7 @@ var init_status_bar = __esm({
572028
572385
  buf += `\x1B[${hdrRow};${w - 1}H`;
572029
572386
  buf += rightArrow;
572030
572387
  }
572031
- buf += `\x1B[${hdrRow};${w}H${BOX_FG}│${RESET2}${PANEL_BG_SEQ}`;
572388
+ buf += `\x1B[${hdrRow};${w}H${BOX_FG}│${RESET3}${PANEL_BG_SEQ}`;
572032
572389
  buf += "\x1B8";
572033
572390
  this.termWrite(buf);
572034
572391
  }
@@ -573231,11 +573588,11 @@ var init_status_bar = __esm({
573231
573588
  for (let i2 = 0; i2 < inputWrap.lines.length; i2++) {
573232
573589
  const row = pos.inputStartRow + i2;
573233
573590
  const prefix = i2 === 0 ? this.promptText : " ".repeat(this.promptWidth);
573234
- buf += `\x1B[${row};1H${PANEL_BG_SEQ}\x1B[2K${prefix}${inputWrap.lines[i2]}${RESET2}${PANEL_BG_SEQ}`;
573591
+ buf += `\x1B[${row};1H${PANEL_BG_SEQ}\x1B[2K${prefix}${inputWrap.lines[i2]}${RESET3}${PANEL_BG_SEQ}`;
573235
573592
  }
573236
573593
  const boxInnerP = w - 2;
573237
- buf += `\x1B[${pos.bufferRow};1H${PANEL_BG_SEQ}\x1B[2K${BOX_FG}${BOX_BL}${BOX_H.repeat(Math.max(0, boxInnerP))}${BOX_BR}${RESET2}${PANEL_BG_SEQ}`;
573238
- buf += `\x1B[${pos.metricsRow};1H${PANEL_BG_SEQ}\x1B[2K${this.buildMetricsLine()}${RESET2}${PANEL_BG_SEQ}\x1B[?7h\x1B[${pos.inputStartRow};1H`;
573594
+ buf += `\x1B[${pos.bufferRow};1H${PANEL_BG_SEQ}\x1B[2K${BOX_FG}${BOX_BL2}${BOX_H2.repeat(Math.max(0, boxInnerP))}${BOX_BR2}${RESET3}${PANEL_BG_SEQ}`;
573595
+ buf += `\x1B[${pos.metricsRow};1H${PANEL_BG_SEQ}\x1B[2K${this.buildMetricsLine()}${RESET3}${PANEL_BG_SEQ}\x1B[?7h\x1B[${pos.inputStartRow};1H`;
573239
573596
  this.termWrite(buf);
573240
573597
  if (this._bannerRefresh) this._bannerRefresh();
573241
573598
  } else {
@@ -573436,7 +573793,7 @@ ${CONTENT_BG_SEQ}`);
573436
573793
  process.stdout.write = this._origWrite;
573437
573794
  this._origWrite = null;
573438
573795
  }
573439
- process.stdout.write(RESET2);
573796
+ process.stdout.write(RESET3);
573440
573797
  this._brailleSpinner.setMetrics({ isStreaming: false });
573441
573798
  this.renderFooterAndPositionInput();
573442
573799
  this.parkCursorInInput();
@@ -573565,12 +573922,32 @@ ${CONTENT_BG_SEQ}`);
573565
573922
  reflowContentLines(livePartialLine, width) {
573566
573923
  const maxWidth = Math.max(16, width);
573567
573924
  const source = livePartialLine ? [...this._contentLines, livePartialLine] : this._contentLines;
573568
- return source.flatMap(
573569
- (line, idx) => this.reflowContentLine(line, maxWidth).map((segment) => ({
573925
+ return source.flatMap((line, idx) => {
573926
+ if (line.startsWith(this.DYNAMIC_BLOCK_MARK_PREFIX) && line.endsWith(this.DYNAMIC_BLOCK_MARK_SUFFIX)) {
573927
+ const id = line.slice(
573928
+ this.DYNAMIC_BLOCK_MARK_PREFIX.length,
573929
+ line.length - this.DYNAMIC_BLOCK_MARK_SUFFIX.length
573930
+ );
573931
+ const renderer = this._dynamicBlocks.get(id);
573932
+ if (!renderer) return [];
573933
+ let blockLines;
573934
+ try {
573935
+ blockLines = renderer(maxWidth);
573936
+ } catch {
573937
+ return [];
573938
+ }
573939
+ return blockLines.flatMap(
573940
+ (segment) => this.reflowContentLine(segment, maxWidth).map((s2) => ({
573941
+ line: s2,
573942
+ bufferIdx: idx
573943
+ }))
573944
+ );
573945
+ }
573946
+ return this.reflowContentLine(line, maxWidth).map((segment) => ({
573570
573947
  line: segment,
573571
573948
  bufferIdx: idx
573572
- }))
573573
- );
573949
+ }));
573950
+ });
573574
573951
  }
573575
573952
  reflowContentLine(line, width) {
573576
573953
  const visible = stripAnsi(line);
@@ -573630,7 +574007,7 @@ ${CONTENT_BG_SEQ}`);
573630
574007
  const endRaw = this.rawIndexForVisibleColumn(line, end);
573631
574008
  const activeStyle = this.activeSgrAt(line, startRaw);
573632
574009
  const raw = line.slice(startRaw, endRaw);
573633
- return activeStyle ? `${activeStyle}${raw}${RESET2}` : raw;
574010
+ return activeStyle ? `${activeStyle}${raw}${RESET3}` : raw;
573634
574011
  }
573635
574012
  rawIndexForVisibleColumn(line, target) {
573636
574013
  if (target <= 0) return 0;
@@ -573654,7 +574031,7 @@ ${CONTENT_BG_SEQ}`);
573654
574031
  let match;
573655
574032
  while ((match = sgr.exec(line)) && match.index < rawIndex) {
573656
574033
  const seq = match[0];
573657
- if (seq === RESET2 || /\x1B\[(?:0|39|49)(?:;0)?m/.test(seq)) {
574034
+ if (seq === RESET3 || /\x1B\[(?:0|39|49)(?:;0)?m/.test(seq)) {
573658
574035
  active = "";
573659
574036
  } else {
573660
574037
  active += seq;
@@ -574429,21 +574806,21 @@ ${CONTENT_BG_SEQ}`);
574429
574806
  const inputWrap = this.wrapInput(w);
574430
574807
  let buf = "\x1B[?7l";
574431
574808
  const boxInner = w - 2;
574432
- buf += `\x1B[${pos.inputStartRow};1H${PANEL_BG_SEQ}\x1B[2K${BOX_FG}${BOX_TL}${BOX_H.repeat(Math.max(0, boxInner))}${BOX_TR}${RESET2}${PANEL_BG_SEQ}`;
574809
+ buf += `\x1B[${pos.inputStartRow};1H${PANEL_BG_SEQ}\x1B[2K${BOX_FG}${BOX_TL2}${BOX_H2.repeat(Math.max(0, boxInner))}${BOX_TR2}${RESET3}${PANEL_BG_SEQ}`;
574433
574810
  const Lspacer = layout();
574434
574811
  const spacerRow = pos.inputStartRow - 1;
574435
574812
  const tasksOccupiesSpacer = Lspacer.tasksHeight > 0 && spacerRow >= Lspacer.tasksTop && spacerRow <= Lspacer.tasksBottom;
574436
574813
  if (spacerRow >= this.scrollRegionTop && !tasksOccupiesSpacer) {
574437
- buf += `\x1B[${spacerRow};1H${PANEL_BG_SEQ}\x1B[2K${RESET2}`;
574814
+ buf += `\x1B[${spacerRow};1H${PANEL_BG_SEQ}\x1B[2K${RESET3}`;
574438
574815
  }
574439
574816
  for (let i2 = 0; i2 < inputWrap.lines.length; i2++) {
574440
574817
  const row = pos.inputStartRow + 1 + i2;
574441
574818
  const prefix = i2 === 0 ? this.promptText : " ".repeat(this.promptWidth);
574442
574819
  const lineContent = `${prefix}${inputWrap.lines[i2]}`;
574443
574820
  buf += `\x1B[${row};1H${PANEL_BG_SEQ}\x1B[2K`;
574444
- buf += `${BOX_FG}${BOX_V}${RESET2}${PANEL_BG_SEQ}${lineContent}`;
574821
+ buf += `${BOX_FG}${BOX_V2}${RESET3}${PANEL_BG_SEQ}${lineContent}`;
574445
574822
  buf += `${PANEL_BG_SEQ}\x1B[K`;
574446
- buf += `\x1B[${row};${w}H${BOX_FG}${BOX_V}${RESET2}${PANEL_BG_SEQ}`;
574823
+ buf += `\x1B[${row};${w}H${BOX_FG}${BOX_V2}${RESET3}${PANEL_BG_SEQ}`;
574447
574824
  }
574448
574825
  const cursorTermRow = pos.inputStartRow + 1 + inputWrap.cursorRow;
574449
574826
  if (this._suggestions.length > 0 && pos.suggestStartRow > 0) {
@@ -574455,17 +574832,17 @@ ${CONTENT_BG_SEQ}`);
574455
574832
  const fg2 = isHighlighted ? `\x1B[1;38;5;${TEXT_PRIMARY}m` : `\x1B[38;5;${TEXT_PRIMARY}m`;
574456
574833
  const slash = isHighlighted ? `\x1B[38;5;245m` : `\x1B[38;5;${TEXT_DIM}m`;
574457
574834
  const marker = isHighlighted ? `\x1B[38;5;${TEXT_PRIMARY}m› ` : " ";
574458
- buf += `\x1B[${row};1H${PANEL_BG_SEQ}\x1B[2K${BOX_FG}${BOX_V}${RESET2}${PANEL_BG_SEQ}`;
574835
+ buf += `\x1B[${row};1H${PANEL_BG_SEQ}\x1B[2K${BOX_FG}${BOX_V2}${RESET3}${PANEL_BG_SEQ}`;
574459
574836
  buf += `${bg} ${marker}${slash}/${fg2}${cmd}`;
574460
574837
  buf += `${PANEL_BG_SEQ}\x1B[K`;
574461
- buf += `\x1B[${row};${w}H${BOX_FG}${BOX_V}${RESET2}${PANEL_BG_SEQ}`;
574838
+ buf += `\x1B[${row};${w}H${BOX_FG}${BOX_V2}${RESET3}${PANEL_BG_SEQ}`;
574462
574839
  }
574463
574840
  const suggestBottomRow = pos.suggestStartRow + this._suggestions.length;
574464
- buf += `\x1B[${suggestBottomRow};1H${PANEL_BG_SEQ}\x1B[2K${BOX_FG}${BOX_BL}${BOX_H.repeat(Math.max(0, boxInner))}${BOX_BR}${RESET2}${PANEL_BG_SEQ}`;
574841
+ buf += `\x1B[${suggestBottomRow};1H${PANEL_BG_SEQ}\x1B[2K${BOX_FG}${BOX_BL2}${BOX_H2.repeat(Math.max(0, boxInner))}${BOX_BR2}${RESET3}${PANEL_BG_SEQ}`;
574465
574842
  } else {
574466
- buf += `\x1B[${pos.bufferRow};1H${PANEL_BG_SEQ}\x1B[2K${BOX_FG}${BOX_BL}${BOX_H.repeat(Math.max(0, boxInner))}${BOX_BR}${RESET2}${PANEL_BG_SEQ}`;
574843
+ buf += `\x1B[${pos.bufferRow};1H${PANEL_BG_SEQ}\x1B[2K${BOX_FG}${BOX_BL2}${BOX_H2.repeat(Math.max(0, boxInner))}${BOX_BR2}${RESET3}${PANEL_BG_SEQ}`;
574467
574844
  }
574468
- buf += `\x1B[${pos.metricsRow};1H${PANEL_BG_SEQ}\x1B[2K${this.buildMetricsLine()}${RESET2}${PANEL_BG_SEQ}`;
574845
+ buf += `\x1B[${pos.metricsRow};1H${PANEL_BG_SEQ}\x1B[2K${this.buildMetricsLine()}${RESET3}${PANEL_BG_SEQ}`;
574469
574846
  buf += "\x1B[?7h";
574470
574847
  if (this.writeDepth === 0) {
574471
574848
  buf += `\x1B[${cursorTermRow};${inputWrap.cursorCol}H${CURSOR_BLINK_BLOCK}\x1B[?25h`;
@@ -574498,7 +574875,7 @@ ${CONTENT_BG_SEQ}`);
574498
574875
  const pos = this.rowPositions(termRows());
574499
574876
  let buf = "\x1B7\x1B[?7l";
574500
574877
  if (pos.tabBarRow > 0) {
574501
- buf += `\x1B[${pos.tabBarRow};1H${PANEL_BG_SEQ}\x1B[2K${RESET2}`;
574878
+ buf += `\x1B[${pos.tabBarRow};1H${PANEL_BG_SEQ}\x1B[2K${RESET3}`;
574502
574879
  }
574503
574880
  const boxInnerR = w - 2;
574504
574881
  if (this._suggestions.length > 0 && pos.suggestStartRow > 0) {
@@ -574508,14 +574885,14 @@ ${CONTENT_BG_SEQ}`);
574508
574885
  const isHl = si === this._suggestIndex;
574509
574886
  const fg2 = isHl ? `\x1B[1;38;5;${TEXT_PRIMARY}m` : `\x1B[38;5;${TEXT_PRIMARY}m`;
574510
574887
  const marker = isHl ? `\x1B[38;5;${TEXT_PRIMARY}m› ` : " ";
574511
- buf += `\x1B[${row};1H${PANEL_BG_SEQ}\x1B[2K${BOX_FG}${BOX_V}${RESET2}${PANEL_BG_SEQ} ${marker}\x1B[38;5;${TEXT_DIM}m/${fg2}${cmd}`;
574512
- buf += `${PANEL_BG_SEQ}\x1B[K\x1B[${row};${w}H${BOX_FG}${BOX_V}${RESET2}`;
574888
+ buf += `\x1B[${row};1H${PANEL_BG_SEQ}\x1B[2K${BOX_FG}${BOX_V2}${RESET3}${PANEL_BG_SEQ} ${marker}\x1B[38;5;${TEXT_DIM}m/${fg2}${cmd}`;
574889
+ buf += `${PANEL_BG_SEQ}\x1B[K\x1B[${row};${w}H${BOX_FG}${BOX_V2}${RESET3}`;
574513
574890
  }
574514
- buf += `\x1B[${pos.bufferRow};1H${PANEL_BG_SEQ}\x1B[2K${BOX_FG}${BOX_BL}${BOX_H.repeat(Math.max(0, boxInnerR))}${BOX_BR}${RESET2}`;
574891
+ buf += `\x1B[${pos.bufferRow};1H${PANEL_BG_SEQ}\x1B[2K${BOX_FG}${BOX_BL2}${BOX_H2.repeat(Math.max(0, boxInnerR))}${BOX_BR2}${RESET3}`;
574515
574892
  } else {
574516
- buf += `\x1B[${pos.bufferRow};1H${PANEL_BG_SEQ}\x1B[2K${BOX_FG}${BOX_BL}${BOX_H.repeat(Math.max(0, boxInnerR))}${BOX_BR}${RESET2}`;
574893
+ buf += `\x1B[${pos.bufferRow};1H${PANEL_BG_SEQ}\x1B[2K${BOX_FG}${BOX_BL2}${BOX_H2.repeat(Math.max(0, boxInnerR))}${BOX_BR2}${RESET3}`;
574517
574894
  }
574518
- buf += `\x1B[${pos.metricsRow};1H${PANEL_BG_SEQ}\x1B[2K${this.buildMetricsLine()}${RESET2}${PANEL_BG_SEQ}\x1B[?7h\x1B8` + // DEC restore cursor
574895
+ buf += `\x1B[${pos.metricsRow};1H${PANEL_BG_SEQ}\x1B[2K${this.buildMetricsLine()}${RESET3}${PANEL_BG_SEQ}\x1B[?7h\x1B8` + // DEC restore cursor
574519
574896
  (this.writeDepth === 0 ? `${CURSOR_BLINK_BLOCK}\x1B[?25h` : "");
574520
574897
  this.termWrite(buf);
574521
574898
  if (pos.tabBarRow > 0) this.renderAgentTabs();
@@ -574559,12 +574936,12 @@ ${CONTENT_BG_SEQ}`);
574559
574936
  }
574560
574937
  buf += "\x1B[?7l";
574561
574938
  const boxInnerH = w - 2;
574562
- buf += `\x1B[${pos.inputStartRow};1H${PANEL_BG_SEQ}\x1B[2K${BOX_FG}${BOX_TL}${BOX_H.repeat(Math.max(0, boxInnerH))}${BOX_TR}${RESET2}`;
574939
+ buf += `\x1B[${pos.inputStartRow};1H${PANEL_BG_SEQ}\x1B[2K${BOX_FG}${BOX_TL2}${BOX_H2.repeat(Math.max(0, boxInnerH))}${BOX_TR2}${RESET3}`;
574563
574940
  for (let i2 = 0; i2 < inputWrap.lines.length; i2++) {
574564
574941
  const row = pos.inputStartRow + 1 + i2;
574565
574942
  const prefix = i2 === 0 ? this.promptText : " ".repeat(this.promptWidth);
574566
574943
  const lineContent = `${prefix}${inputWrap.lines[i2]}`;
574567
- buf += `\x1B[${row};1H${PANEL_BG_SEQ}\x1B[2K${BOX_FG}${BOX_V}${RESET2}${PANEL_BG_SEQ}${lineContent}${PANEL_BG_SEQ}\x1B[K\x1B[${row};${w}H${BOX_FG}${BOX_V}${RESET2}`;
574944
+ buf += `\x1B[${row};1H${PANEL_BG_SEQ}\x1B[2K${BOX_FG}${BOX_V2}${RESET3}${PANEL_BG_SEQ}${lineContent}${PANEL_BG_SEQ}\x1B[K\x1B[${row};${w}H${BOX_FG}${BOX_V2}${RESET3}`;
574568
574945
  }
574569
574946
  if (this._suggestions.length > 0 && pos.suggestStartRow > 0) {
574570
574947
  for (let si = 0; si < this._suggestions.length; si++) {
@@ -574574,14 +574951,14 @@ ${CONTENT_BG_SEQ}`);
574574
574951
  const bg = isHl ? `\x1B[48;5;235m` : PANEL_BG_SEQ;
574575
574952
  const fg2 = isHl ? `\x1B[1;38;5;${TEXT_PRIMARY}m` : `\x1B[38;5;${TEXT_PRIMARY}m`;
574576
574953
  const marker = isHl ? `\x1B[38;5;${TEXT_PRIMARY}m› ` : " ";
574577
- buf += `\x1B[${row};1H${PANEL_BG_SEQ}\x1B[2K${BOX_FG}${BOX_V}${RESET2}${PANEL_BG_SEQ}`;
574954
+ buf += `\x1B[${row};1H${PANEL_BG_SEQ}\x1B[2K${BOX_FG}${BOX_V2}${RESET3}${PANEL_BG_SEQ}`;
574578
574955
  buf += `${bg} ${marker}\x1B[38;5;${TEXT_DIM}m/${fg2}${cmd}`;
574579
- buf += `${PANEL_BG_SEQ}\x1B[K\x1B[${row};${w}H${BOX_FG}${BOX_V}${RESET2}`;
574956
+ buf += `${PANEL_BG_SEQ}\x1B[K\x1B[${row};${w}H${BOX_FG}${BOX_V2}${RESET3}`;
574580
574957
  }
574581
574958
  }
574582
574959
  const boxInnerS = w - 2;
574583
- buf += `\x1B[${pos.bufferRow};1H${PANEL_BG_SEQ}\x1B[2K${BOX_FG}${BOX_BL}${BOX_H.repeat(Math.max(0, boxInnerS))}${BOX_BR}${RESET2}`;
574584
- buf += `\x1B[${pos.metricsRow};1H${PANEL_BG_SEQ}\x1B[2K${this.buildMetricsLine()}${RESET2}`;
574960
+ buf += `\x1B[${pos.bufferRow};1H${PANEL_BG_SEQ}\x1B[2K${BOX_FG}${BOX_BL2}${BOX_H2.repeat(Math.max(0, boxInnerS))}${BOX_BR2}${RESET3}`;
574961
+ buf += `\x1B[${pos.metricsRow};1H${PANEL_BG_SEQ}\x1B[2K${this.buildMetricsLine()}${RESET3}`;
574585
574962
  buf += "\x1B[?7h";
574586
574963
  buf += "\x1B8";
574587
574964
  if (heightDelta > 0) {
@@ -574599,9 +574976,9 @@ ${CONTENT_BG_SEQ}`);
574599
574976
  const prefix = i2 === 0 ? this.promptText : " ".repeat(this.promptWidth);
574600
574977
  const lineContent = `${prefix}${inputWrap.lines[i2]}`;
574601
574978
  buf += `\x1B[${row};1H${PANEL_BG_SEQ}\x1B[2K`;
574602
- buf += `${BOX_FG}${BOX_V}${RESET2}${PANEL_BG_SEQ}${lineContent}`;
574979
+ buf += `${BOX_FG}${BOX_V2}${RESET3}${PANEL_BG_SEQ}${lineContent}`;
574603
574980
  buf += `${PANEL_BG_SEQ}\x1B[K`;
574604
- buf += `\x1B[${row};${w}H${BOX_FG}${BOX_V}${RESET2}${PANEL_BG_SEQ}`;
574981
+ buf += `\x1B[${row};${w}H${BOX_FG}${BOX_V2}${RESET3}${PANEL_BG_SEQ}`;
574605
574982
  }
574606
574983
  buf += "\x1B[?7h";
574607
574984
  this.termWrite(buf);
@@ -649776,13 +650153,24 @@ When done, either call task_complete with your answer, or use FINAL_VAR(variable
649776
650153
  }
649777
650154
  contentWrite(() => {
649778
650155
  if (result.completed) {
649779
- renderTaskComplete(
649780
- result.summary,
649781
- result.turns,
649782
- result.toolCalls,
649783
- result.durationMs,
649784
- tokens
649785
- );
650156
+ renderTaskComplete({
650157
+ task: effectiveTask,
650158
+ summary: result.summary,
650159
+ turns: result.turns,
650160
+ toolCalls: result.toolCalls,
650161
+ durationMs: result.durationMs,
650162
+ tokens,
650163
+ filesEdited: result.filesEdited,
650164
+ testsRun: result.testsRun,
650165
+ provenanceAnchors: result.provenanceAnchors,
650166
+ // Hand the status bar so the box renders as a resize-aware
650167
+ // dynamic block. When the bar isn't active (tests, headless),
650168
+ // the legacy line-based banner fires instead.
650169
+ host: statusBar?.isActive ? {
650170
+ registerDynamicBlock: (id, render2) => statusBar.registerDynamicBlock(id, render2),
650171
+ appendDynamicBlock: (id) => statusBar.appendDynamicBlock(id)
650172
+ } : void 0
650173
+ });
649786
650174
  if (onComplete)
649787
650175
  onComplete(result.summary, {
649788
650176
  turns: result.turns,
@@ -654588,6 +654976,9 @@ ${result.content.slice(0, 2e3)}${result.content.length > 2e3 ? "\n[truncated]" :
654588
654976
  if (!setupReady) return;
654589
654977
  persistHistoryLine(line);
654590
654978
  const input = line.trim();
654979
+ if (statusBar?.isActive && line.length > 0) {
654980
+ statusBar.redrawFooter();
654981
+ }
654591
654982
  if (!input) {
654592
654983
  if (pasteBuffer.length > 0) {
654593
654984
  if (pasteIndicatorShown) {