omnius 1.0.487 → 1.0.488

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
@@ -616964,6 +616964,147 @@ reason=${decision2.reason} confidence=${decision2.confidence.toFixed(2)} source=
616964
616964
  }
616965
616965
  });
616966
616966
 
616967
+ // packages/cli/src/tui/conversation-context.ts
616968
+ import { statfsSync as statfsSync7 } from "node:fs";
616969
+ function buildConversationRuntimeContext(now2 = /* @__PURE__ */ new Date(), repoRoot) {
616970
+ const date = new Intl.DateTimeFormat("en-US", {
616971
+ weekday: "long",
616972
+ year: "numeric",
616973
+ month: "long",
616974
+ day: "numeric"
616975
+ }).format(now2);
616976
+ const time = new Intl.DateTimeFormat("en-US", {
616977
+ hour: "numeric",
616978
+ minute: "2-digit",
616979
+ second: "2-digit",
616980
+ timeZoneName: "short"
616981
+ }).format(now2);
616982
+ const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone || process.env["TZ"] || "system";
616983
+ let diskLine = "";
616984
+ if (repoRoot) {
616985
+ try {
616986
+ const stats = statfsSync7(repoRoot);
616987
+ const totalBytes = Number(stats.blocks) * Number(stats.bsize);
616988
+ const freeBytes = Number(stats.bavail) * Number(stats.bsize);
616989
+ const usedBytes = totalBytes - freeBytes;
616990
+ const totalGB = Math.round(totalBytes / 1024 ** 3);
616991
+ const freeGB = Math.round(freeBytes / 1024 ** 3);
616992
+ const usedGB = Math.round(usedBytes / 1024 ** 3);
616993
+ const usedPct = totalBytes > 0 ? Math.round(usedBytes / totalBytes * 100) : 0;
616994
+ diskLine = `Disk: disk_available_gb=${freeGB} disk_used_gb=${usedGB} disk_total_gb=${totalGB} disk_used_pct=${usedPct} path=${repoRoot}`;
616995
+ } catch {
616996
+ }
616997
+ }
616998
+ return [
616999
+ `Current date: ${date}`,
617000
+ `Current time: ${time}`,
617001
+ `Current ISO timestamp: ${now2.toISOString()}`,
617002
+ `Timezone: ${timezone}`,
617003
+ repoRoot ? `Working directory: ${repoRoot}` : "",
617004
+ diskLine
617005
+ ].filter(Boolean).join("\n");
617006
+ }
617007
+ function quoteConversationBlock(value2, maxChars = 2400) {
617008
+ const text2 = String(value2 ?? "").replace(/\r\n/g, "\n").trim();
617009
+ if (!text2) return "> (empty)";
617010
+ const clipped = text2.length > maxChars ? `${text2.slice(0, Math.max(0, maxChars - 1))}...` : text2;
617011
+ return clipped.split("\n").map((line) => `> ${line}`).join("\n");
617012
+ }
617013
+ function buildScopedConversationMessages(turns, options2) {
617014
+ const pinned = [];
617015
+ const dynamic = [];
617016
+ let latestContextFrame = null;
617017
+ for (const turn of turns) {
617018
+ if (options2.isPinnedSystemTurn(turn) && !pinned.some((p2) => p2.content === turn.content)) {
617019
+ pinned.push(turn);
617020
+ } else if (options2.isContextFrameTurn?.(turn)) {
617021
+ latestContextFrame = turn;
617022
+ } else {
617023
+ dynamic.push(turn);
617024
+ }
617025
+ }
617026
+ if (latestContextFrame) {
617027
+ if (options2.placeContextFrameBeforeLastUser !== false) {
617028
+ let lastUserIdx = -1;
617029
+ for (let i2 = dynamic.length - 1; i2 >= 0; i2--) {
617030
+ if (dynamic[i2].role === "user") {
617031
+ lastUserIdx = i2;
617032
+ break;
617033
+ }
617034
+ }
617035
+ if (lastUserIdx >= 0) dynamic.splice(lastUserIdx, 0, latestContextFrame);
617036
+ else dynamic.push(latestContextFrame);
617037
+ } else {
617038
+ dynamic.push(latestContextFrame);
617039
+ }
617040
+ }
617041
+ const available = Math.max(0, options2.maxMessages - pinned.length);
617042
+ let windowed = dynamic.slice(-available);
617043
+ if (latestContextFrame && available > 0 && !windowed.includes(latestContextFrame)) {
617044
+ windowed = [latestContextFrame, ...windowed.slice(-(available - 1))];
617045
+ }
617046
+ return [...pinned, ...windowed];
617047
+ }
617048
+ function buildVoiceSessionContext(args) {
617049
+ const maxTranscriptTurns = Math.max(1, args.maxTranscriptTurns ?? 8);
617050
+ const voiceLines = (args.voiceTranscript ?? []).slice(-maxTranscriptTurns).map((turn) => `${formatClock(turn.ts)} ${turn.role}: ${singleLine(turn.content, 360)}`);
617051
+ const relayLines = (args.relayTranscript ?? []).slice(-maxTranscriptTurns).map((turn) => {
617052
+ const dir = turn.dir === "toMain" ? "voice->main" : "main->voice";
617053
+ return `${formatClock(turn.ts)} ${dir}: ${singleLine(turn.content, 360)}`;
617054
+ });
617055
+ const taskLine = args.activeTask ? `active=${args.activeTask.active ? "yes" : "no"} tool_calls=${args.activeTask.toolCalls ?? 0} files_touched=${args.activeTask.filesTouched ?? 0}` : "active=unknown";
617056
+ const sections = [
617057
+ `## Runtime Context
617058
+
617059
+ ${buildConversationRuntimeContext(/* @__PURE__ */ new Date(), args.repoRoot)}`,
617060
+ [
617061
+ "## Voice/Live Session Contract",
617062
+ "",
617063
+ `surface=voicechat session_id=${args.sessionId} turn=${args.turnCount}`,
617064
+ `main_agent_task=${taskLine}`,
617065
+ "Latest user utterance remains the active request. Earlier ASR transcript turns are conversational history, not new instructions.",
617066
+ "ASR text can be noisy. Prefer consensus-filtered final turns, resolve pronouns from recent context, and ask for clarification rather than filling gaps.",
617067
+ "Live perception is evidence for the current reply, not a topic to narrate unless the user asks about it."
617068
+ ].join("\n")
617069
+ ];
617070
+ if (voiceLines.length > 0) {
617071
+ sections.push(`## Recent Voice Conversation
617072
+
617073
+ ${quoteConversationBlock(voiceLines.join("\n"))}`);
617074
+ }
617075
+ if (relayLines.length > 0) {
617076
+ sections.push(`## Main Agent Relay Stream
617077
+
617078
+ ${quoteConversationBlock(relayLines.join("\n"))}`);
617079
+ }
617080
+ if (args.liveContext?.trim()) {
617081
+ sections.push(`## Live Context Frame
617082
+
617083
+ ${args.liveContext.trim()}`);
617084
+ }
617085
+ return sections.join("\n\n");
617086
+ }
617087
+ function singleLine(value2, maxChars) {
617088
+ const clean5 = value2.replace(/\s+/g, " ").trim();
617089
+ return clean5.length > maxChars ? `${clean5.slice(0, Math.max(0, maxChars - 1))}...` : clean5;
617090
+ }
617091
+ function formatClock(ts) {
617092
+ try {
617093
+ return new Date(ts).toLocaleTimeString("en-US", {
617094
+ hour: "2-digit",
617095
+ minute: "2-digit",
617096
+ second: "2-digit"
617097
+ });
617098
+ } catch {
617099
+ return "unknown-time";
617100
+ }
617101
+ }
617102
+ var init_conversation_context = __esm({
617103
+ "packages/cli/src/tui/conversation-context.ts"() {
617104
+ "use strict";
617105
+ }
617106
+ });
617107
+
616967
617108
  // packages/cli/src/tui/generative-progress.ts
616968
617109
  function generationKindForToolName(toolName) {
616969
617110
  if (toolName === "generate_image") return "image";
@@ -628273,7 +628414,7 @@ import { EventEmitter as EventEmitter8 } from "node:events";
628273
628414
  import { randomBytes as randomBytes22, timingSafeEqual } from "node:crypto";
628274
628415
  import { URL as URL2 } from "node:url";
628275
628416
  import { loadavg as loadavg2, cpus as cpus4, totalmem as totalmem7, freemem as freemem6 } from "node:os";
628276
- import { existsSync as existsSync119, readFileSync as readFileSync98, writeFileSync as writeFileSync61, unlinkSync as unlinkSync21, mkdirSync as mkdirSync73, readdirSync as readdirSync39, statSync as statSync47, statfsSync as statfsSync7 } from "node:fs";
628417
+ import { existsSync as existsSync119, readFileSync as readFileSync98, writeFileSync as writeFileSync61, unlinkSync as unlinkSync21, mkdirSync as mkdirSync73, readdirSync as readdirSync39, statSync as statSync47, statfsSync as statfsSync8 } from "node:fs";
628277
628418
  import { join as join133 } from "node:path";
628278
628419
  function cleanForwardHeaders(raw, targetHost) {
628279
628420
  const out = {};
@@ -628543,7 +628684,7 @@ async function collectSystemMetricsAsync() {
628543
628684
  utilization: -1
628544
628685
  };
628545
628686
  try {
628546
- const fs12 = statfsSync7(process.cwd());
628687
+ const fs12 = statfsSync8(process.cwd());
628547
628688
  const totalBytes = fs12.blocks * fs12.bsize;
628548
628689
  const freeBytes = fs12.bavail * fs12.bsize;
628549
628690
  const usedBytes = totalBytes - freeBytes;
@@ -636157,7 +636298,7 @@ function setTerminalTitle(task, version5) {
636157
636298
  process.stdout.write(data);
636158
636299
  }
636159
636300
  }
636160
- 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, HEADER_BUTTON_GLYPH_FG, HEADER_BUTTON_BG, HEADER_BUTTON_FG, HEADER_ACCENT_BOLD_FG, HEADER_TELEGRAM_FG, BOX_TL3, BOX_TR3, BOX_BL3, BOX_BR3, BOX_H3, BOX_V3, BOX_BJ, _globalFooterLock, RESET4, CURSOR_BLINK_BLOCK, _isWindows, HEADER_BUTTON_LEFT, HEADER_BUTTON_RIGHT, SPONSOR_HEADER_LABEL_MAX, _termTitleWriter, StatusBar;
636301
+ 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, HEADER_BUTTON_GLYPH_FG, HEADER_BUTTON_BG, HEADER_BUTTON_FG, HEADER_ACCENT_BOLD_FG, HEADER_TELEGRAM_FG, BOX_TL3, BOX_TR3, BOX_BL3, BOX_BR3, BOX_H3, BOX_V3, BOX_BJ, BOX_TJ, ENHANCE_SEG_INNER, ENHANCE_SPIN_FRAMES, _globalFooterLock, RESET4, CURSOR_BLINK_BLOCK, _isWindows, HEADER_BUTTON_LEFT, HEADER_BUTTON_RIGHT, SPONSOR_HEADER_LABEL_MAX, _termTitleWriter, StatusBar;
636161
636302
  var init_status_bar = __esm({
636162
636303
  "packages/cli/src/tui/status-bar.ts"() {
636163
636304
  "use strict";
@@ -636350,6 +636491,20 @@ var init_status_bar = __esm({
636350
636491
  BOX_H3 = "─";
636351
636492
  BOX_V3 = "│";
636352
636493
  BOX_BJ = "┴";
636494
+ BOX_TJ = "┬";
636495
+ ENHANCE_SEG_INNER = 11;
636496
+ ENHANCE_SPIN_FRAMES = [
636497
+ "⠋",
636498
+ "⠙",
636499
+ "⠹",
636500
+ "⠸",
636501
+ "⠼",
636502
+ "⠴",
636503
+ "⠦",
636504
+ "⠧",
636505
+ "⠇",
636506
+ "⠏"
636507
+ ];
636353
636508
  _globalFooterLock = false;
636354
636509
  RESET4 = "\x1B[0m";
636355
636510
  CURSOR_BLINK_BLOCK = "\x1B[1 q";
@@ -636519,6 +636674,23 @@ var init_status_bar = __esm({
636519
636674
  * own output is suppressed.
636520
636675
  */
636521
636676
  inputStateProvider = null;
636677
+ // ── Input-box "enhance" prompt-expansion button ──────────────────────
636678
+ /** Mutates the underlying input buffer (line + cursor). Wired to DirectInput.setLine. */
636679
+ _inputMutator = null;
636680
+ /** Runs the inference-based prompt expansion. Returns the enhanced prompt or null. */
636681
+ _enhanceHandler = null;
636682
+ /** Current enhance-button lifecycle state. */
636683
+ _enhanceState = "idle";
636684
+ /** The pre-expansion seed text, restored when the user rejects the expansion. */
636685
+ _enhanceOriginal = null;
636686
+ /** Transient press-flash target for visual click feedback. */
636687
+ _enhancePressed = null;
636688
+ /** Spinner animation frame index while state === "busy". */
636689
+ _enhanceSpinFrame = 0;
636690
+ /** Spinner redraw timer while state === "busy". */
636691
+ _enhanceSpinTimer = null;
636692
+ /** Sub-zones for the accept (✔) / reject (✖) confirm glyphs (confirm state only). */
636693
+ _enhanceConfirmZones = null;
636522
636694
  /** Whether microphone is recording (blinking indicator) */
636523
636695
  _recording = false;
636524
636696
  /** Whether speech is currently detected on the mic (from ListenEngine metering) */
@@ -638524,6 +638696,7 @@ var init_status_bar = __esm({
638524
638696
  if (viewId) this.switchToView(viewId);
638525
638697
  return;
638526
638698
  }
638699
+ if (type === "press" && this.handleFooterInputClick(row, col)) return;
638527
638700
  const L = layout();
638528
638701
  const inContent = row >= this.scrollRegionTop && row <= L.contentBottom;
638529
638702
  if (inContent) {
@@ -638802,8 +638975,7 @@ var init_status_bar = __esm({
638802
638975
  for (let row = clearStart; row <= rows; row++) {
638803
638976
  buf += `\x1B[${row};1H\x1B[2K`;
638804
638977
  }
638805
- const boxInnerP = w - 2;
638806
- buf += `\x1B[${pos.inputStartRow};1H${PANEL_BG_SEQ}\x1B[2K${BOX_FG}${BOX_TL3}${BOX_H3.repeat(Math.max(0, boxInnerP))}${BOX_TR3}${RESET4}${PANEL_BG_SEQ}`;
638978
+ buf += `\x1B[${pos.inputStartRow};1H${PANEL_BG_SEQ}\x1B[2K${this.buildInputBoxTop(w)}${PANEL_BG_SEQ}`;
638807
638979
  for (let i2 = 0; i2 < inputWrap.lines.length; i2++) {
638808
638980
  const row = pos.inputStartRow + 1 + i2;
638809
638981
  const prefix = i2 === 0 ? this.promptText : " ".repeat(this.promptWidth);
@@ -638812,7 +638984,12 @@ var init_status_bar = __esm({
638812
638984
  buf += `${BOX_FG}${BOX_V3}${RESET4}${PANEL_BG_SEQ}${lineContent}`;
638813
638985
  buf += `${PANEL_BG_SEQ}\x1B[K\x1B[${row};${w}H${BOX_FG}${BOX_V3}${RESET4}${PANEL_BG_SEQ}`;
638814
638986
  }
638815
- buf += `\x1B[${pos.bufferRow};1H${PANEL_BG_SEQ}\x1B[2K${BOX_FG}${BOX_BL3}${BOX_H3.repeat(Math.max(0, boxInnerP))}${BOX_BR3}${RESET4}${PANEL_BG_SEQ}`;
638987
+ buf += this.buildEnhanceSegment(
638988
+ w,
638989
+ pos.inputStartRow + 1,
638990
+ inputWrap.lines.length
638991
+ );
638992
+ buf += `\x1B[${pos.bufferRow};1H${PANEL_BG_SEQ}\x1B[2K${this.buildInputBoxBottom(w)}${PANEL_BG_SEQ}`;
638816
638993
  if (pos.metricsRow > 0) {
638817
638994
  buf += `\x1B[${pos.metricsRow};1H${PANEL_BG_SEQ}\x1B[2K${this.buildMetricsLine()}${RESET4}${PANEL_BG_SEQ}`;
638818
638995
  }
@@ -640226,9 +640403,268 @@ ${CONTENT_BG_SEQ}`);
640226
640403
  this._brailleSpinner.setMetrics({ contextPct });
640227
640404
  }
640228
640405
  /** Compute how many visual lines the current input text occupies */
640406
+ // ── "enhance" segment geometry ───────────────────────────────────────
640407
+ /** Whether the enhance segment is wired and the terminal is wide enough. */
640408
+ enhanceSegEnabled(termWidth) {
640409
+ if (!this._enhanceHandler) return false;
640410
+ const w = termWidth ?? getTermWidth();
640411
+ return w >= this.promptWidth + ENHANCE_SEG_INNER + 16;
640412
+ }
640413
+ /** Column of the │ divider that separates the input area from the button cell. */
640414
+ enhanceDividerCol(termWidth) {
640415
+ const w = termWidth ?? getTermWidth();
640416
+ return w - 1 - ENHANCE_SEG_INNER;
640417
+ }
640229
640418
  inputTextWidth(termWidth) {
640230
640419
  const w = termWidth ?? getTermWidth();
640231
- return Math.max(1, w - this.promptWidth - 2);
640420
+ const seg = this.enhanceSegEnabled(w) ? ENHANCE_SEG_INNER + 1 : 0;
640421
+ return Math.max(1, w - this.promptWidth - 2 - seg);
640422
+ }
640423
+ /** Box top border with an optional ┬ carving out the enhance segment. */
640424
+ buildInputBoxTop(w) {
640425
+ if (!this.enhanceSegEnabled(w)) {
640426
+ return `${BOX_FG}${BOX_TL3}${BOX_H3.repeat(Math.max(0, w - 2))}${BOX_TR3}${RESET4}`;
640427
+ }
640428
+ const dividerCol = this.enhanceDividerCol(w);
640429
+ const leftDashes = Math.max(0, dividerCol - 2);
640430
+ return `${BOX_FG}${BOX_TL3}${BOX_H3.repeat(leftDashes)}${BOX_TJ}${BOX_H3.repeat(ENHANCE_SEG_INNER)}${BOX_TR3}${RESET4}`;
640431
+ }
640432
+ /** Box bottom border with an optional ┴ closing the enhance segment. */
640433
+ buildInputBoxBottom(w) {
640434
+ if (!this.enhanceSegEnabled(w)) {
640435
+ return `${BOX_FG}${BOX_BL3}${BOX_H3.repeat(Math.max(0, w - 2))}${BOX_BR3}${RESET4}`;
640436
+ }
640437
+ const dividerCol = this.enhanceDividerCol(w);
640438
+ const leftDashes = Math.max(0, dividerCol - 2);
640439
+ return `${BOX_FG}${BOX_BL3}${BOX_H3.repeat(leftDashes)}${BOX_BJ}${BOX_H3.repeat(ENHANCE_SEG_INNER)}${BOX_BR3}${RESET4}`;
640440
+ }
640441
+ /**
640442
+ * Draw the │ divider down each input row plus the enhance/confirm button in
640443
+ * the right-hand cell (button label on the first input row only). Returns an
640444
+ * ANSI overlay string (with CUP moves) that callers append AFTER painting the
640445
+ * input-row content, so it lands on top of the erase-to-EOL fill. Also records
640446
+ * the click zones consumed by handleFooterInputClick().
640447
+ */
640448
+ buildEnhanceSegment(w, firstInputRow, rowCount) {
640449
+ if (!this.enhanceSegEnabled(w) || rowCount < 1) {
640450
+ this._enhanceConfirmZones = null;
640451
+ return "";
640452
+ }
640453
+ const dividerCol = this.enhanceDividerCol(w);
640454
+ const cellStart = dividerCol + 1;
640455
+ const cellEnd = w - 1;
640456
+ let buf = "";
640457
+ for (let i2 = 0; i2 < rowCount; i2++) {
640458
+ const row = firstInputRow + i2;
640459
+ buf += `\x1B[${row};${dividerCol}H${BOX_FG}${BOX_V3}${RESET4}${PANEL_BG_SEQ}`;
640460
+ if (i2 > 0) {
640461
+ buf += `\x1B[${row};${cellStart}H${PANEL_BG_SEQ}${" ".repeat(ENHANCE_SEG_INNER)}`;
640462
+ }
640463
+ }
640464
+ buf += this.buildEnhanceButtonCell(firstInputRow, cellStart);
640465
+ void cellEnd;
640466
+ return buf;
640467
+ }
640468
+ /** Render the button-cell content for the current enhance state (width = ENHANCE_SEG_INNER). */
640469
+ buildEnhanceButtonCell(row, cellStart) {
640470
+ const cup = `\x1B[${row};${cellStart}H`;
640471
+ if (this._enhanceState === "busy") {
640472
+ this._enhanceConfirmZones = null;
640473
+ const frame = ENHANCE_SPIN_FRAMES[this._enhanceSpinFrame % ENHANCE_SPIN_FRAMES.length] ?? "⠋";
640474
+ const pad = Math.floor((ENHANCE_SEG_INNER - 1) / 2);
640475
+ const cell = " ".repeat(pad) + frame + " ".repeat(ENHANCE_SEG_INNER - 1 - pad);
640476
+ return `${cup}${PANEL_BG_SEQ}\x1B[38;5;${TEXT_DIM}m${cell}${RESET4}${PANEL_BG_SEQ}`;
640477
+ }
640478
+ if (this._enhanceState === "confirm") {
640479
+ const rejectIdx = 2;
640480
+ const acceptIdx = ENHANCE_SEG_INNER - 3;
640481
+ const rejectPressed = this._enhancePressed === "reject";
640482
+ const acceptPressed = this._enhancePressed === "accept";
640483
+ const rejectFg = rejectPressed ? "\x1B[1;7;38;5;196m" : "\x1B[1;38;5;196m";
640484
+ const acceptFg = acceptPressed ? "\x1B[1;7;38;5;40m" : "\x1B[1;38;5;40m";
640485
+ let out = `${cup}${PANEL_BG_SEQ}`;
640486
+ for (let i2 = 0; i2 < ENHANCE_SEG_INNER; i2++) {
640487
+ if (i2 === rejectIdx) out += `${rejectFg}✖${RESET4}${PANEL_BG_SEQ}`;
640488
+ else if (i2 === acceptIdx) out += `${acceptFg}✔${RESET4}${PANEL_BG_SEQ}`;
640489
+ else out += " ";
640490
+ }
640491
+ this._enhanceConfirmZones = {
640492
+ reject: { c0: cellStart + rejectIdx, c1: cellStart + rejectIdx },
640493
+ accept: { c0: cellStart + acceptIdx, c1: cellStart + acceptIdx }
640494
+ };
640495
+ return out;
640496
+ }
640497
+ this._enhanceConfirmZones = null;
640498
+ const label = "enhance";
640499
+ const totalPad = ENHANCE_SEG_INNER - label.length;
640500
+ const left = Math.floor(totalPad / 2);
640501
+ const chip = " ".repeat(left) + label + " ".repeat(totalPad - left);
640502
+ const pressed = this._enhancePressed === "enhance";
640503
+ const body = pressed ? `\x1B[7m${HEADER_BUTTON_BG}${HEADER_BUTTON_FG}${chip}${RESET4}` : `${HEADER_BUTTON_BG}${HEADER_BUTTON_FG}${chip}${RESET4}`;
640504
+ return `${cup}${body}${PANEL_BG_SEQ}`;
640505
+ }
640506
+ // ── "enhance" public API + lifecycle ─────────────────────────────────
640507
+ /** Wire the buffer mutator (DirectInput.setLine) so clicks can move the cursor / swap text. */
640508
+ setInputMutator(fn) {
640509
+ this._inputMutator = fn;
640510
+ }
640511
+ /**
640512
+ * Wire the inference-backed prompt-expansion handler. Passing a handler also
640513
+ * enables the enhance segment in the input box. `seed` is the current input
640514
+ * text; resolve with the expanded prompt, or null to abort (no change).
640515
+ */
640516
+ setEnhanceHandler(fn) {
640517
+ this._enhanceHandler = fn;
640518
+ }
640519
+ /** Reset the enhance button to idle (called on submit / escape / new prompt). */
640520
+ resetEnhance() {
640521
+ const wasActive = this._enhanceState !== "idle";
640522
+ this.stopEnhanceSpinner();
640523
+ this._enhanceState = "idle";
640524
+ this._enhanceOriginal = null;
640525
+ this._enhancePressed = null;
640526
+ if (wasActive && this.active && !this._resizing) {
640527
+ this.renderFooterAndPositionInput();
640528
+ }
640529
+ }
640530
+ startEnhanceSpinner() {
640531
+ this.stopEnhanceSpinner();
640532
+ this._enhanceSpinTimer = setInterval(() => {
640533
+ if (this._enhanceState !== "busy") {
640534
+ this.stopEnhanceSpinner();
640535
+ return;
640536
+ }
640537
+ this._enhanceSpinFrame++;
640538
+ if (this.active && !this._resizing && this.writeDepth === 0) {
640539
+ this.renderFooterAndPositionInput();
640540
+ }
640541
+ }, 120);
640542
+ if (typeof this._enhanceSpinTimer.unref === "function") {
640543
+ this._enhanceSpinTimer.unref();
640544
+ }
640545
+ }
640546
+ stopEnhanceSpinner() {
640547
+ if (this._enhanceSpinTimer) {
640548
+ clearInterval(this._enhanceSpinTimer);
640549
+ this._enhanceSpinTimer = null;
640550
+ }
640551
+ }
640552
+ /** Kick off the expansion inference for the current input text. */
640553
+ beginEnhance() {
640554
+ if (this._enhanceState !== "idle" || !this._enhanceHandler) return;
640555
+ const state = this.inputStateProvider?.();
640556
+ const original = state?.line ?? "";
640557
+ const seed = original.trim();
640558
+ if (!seed) return;
640559
+ this._enhanceOriginal = original;
640560
+ this._enhanceState = "busy";
640561
+ this._enhanceSpinFrame = 0;
640562
+ this._enhancePressed = null;
640563
+ this.startEnhanceSpinner();
640564
+ if (this.active && !this._resizing) this.renderFooterAndPositionInput();
640565
+ const handler = this._enhanceHandler;
640566
+ void (async () => {
640567
+ let expanded = null;
640568
+ try {
640569
+ expanded = await handler(seed);
640570
+ } catch {
640571
+ expanded = null;
640572
+ }
640573
+ this.stopEnhanceSpinner();
640574
+ if (this._enhanceState !== "busy") {
640575
+ if (this.active && !this._resizing) this.renderFooterAndPositionInput();
640576
+ return;
640577
+ }
640578
+ const clean5 = (expanded ?? "").trim();
640579
+ if (clean5 && clean5 !== seed) {
640580
+ this._inputMutator?.(clean5, clean5.length);
640581
+ this._enhanceState = "confirm";
640582
+ } else {
640583
+ this._enhanceState = "idle";
640584
+ this._enhanceOriginal = null;
640585
+ }
640586
+ if (this.active && !this._resizing) this.renderFooterAndPositionInput();
640587
+ })();
640588
+ }
640589
+ /** Resolve the confirm state: accept keeps the expansion, reject restores the seed. */
640590
+ resolveEnhance(accept) {
640591
+ if (this._enhanceState !== "confirm") return;
640592
+ if (!accept && this._enhanceOriginal != null) {
640593
+ const orig = this._enhanceOriginal;
640594
+ this._inputMutator?.(orig, orig.length);
640595
+ }
640596
+ this._enhanceState = "idle";
640597
+ this._enhanceOriginal = null;
640598
+ this._enhancePressed = null;
640599
+ if (this.active && !this._resizing) this.renderFooterAndPositionInput();
640600
+ }
640601
+ /** Brief press-flash for click feedback, then repaint. */
640602
+ flashEnhancePress(which3) {
640603
+ this._enhancePressed = which3;
640604
+ if (this.active && !this._resizing) this.renderFooterAndPositionInput();
640605
+ setTimeout(() => {
640606
+ if (this._enhancePressed === which3) {
640607
+ this._enhancePressed = null;
640608
+ if (this.active && !this._resizing) this.renderFooterAndPositionInput();
640609
+ }
640610
+ }, 130);
640611
+ }
640612
+ /**
640613
+ * Handle a press inside the footer input box: the enhance/confirm button,
640614
+ * or a click in the text area to reposition the cursor. Returns true when the
640615
+ * click was consumed.
640616
+ */
640617
+ handleFooterInputClick(row, col) {
640618
+ if (!this.inputStateProvider) return false;
640619
+ const w = getTermWidth();
640620
+ const pos = this.rowPositions(termRows());
640621
+ const inputLines = this.computeInputLineCount(w);
640622
+ const firstInputRow = pos.inputStartRow + 1;
640623
+ const lastInputRow = firstInputRow + inputLines - 1;
640624
+ if (row < firstInputRow || row > lastInputRow) return false;
640625
+ if (this.enhanceSegEnabled(w)) {
640626
+ const dividerCol = this.enhanceDividerCol(w);
640627
+ const cellStart = dividerCol + 1;
640628
+ const cellEnd = w - 1;
640629
+ if (col >= dividerCol && col <= cellEnd) {
640630
+ if (this._enhanceState === "confirm") {
640631
+ const mid = Math.floor((cellStart + cellEnd) / 2);
640632
+ if (col <= mid) {
640633
+ this.flashEnhancePress("reject");
640634
+ this.resolveEnhance(false);
640635
+ } else {
640636
+ this.flashEnhancePress("accept");
640637
+ this.resolveEnhance(true);
640638
+ }
640639
+ return true;
640640
+ }
640641
+ if (this._enhanceState === "idle") {
640642
+ this.flashEnhancePress("enhance");
640643
+ this.beginEnhance();
640644
+ return true;
640645
+ }
640646
+ return true;
640647
+ }
640648
+ if (col >= dividerCol) return false;
640649
+ }
640650
+ const availWidth = this.inputTextWidth(w);
640651
+ const line = this.inputStateProvider().line ?? "";
640652
+ const { rawLines, charPositions } = this.wrapPlainInputText(
640653
+ line,
640654
+ availWidth
640655
+ );
640656
+ const lineIdx = Math.min(
640657
+ Math.max(0, row - firstInputRow),
640658
+ rawLines.length - 1
640659
+ );
640660
+ const rawLine = rawLines[lineIdx] ?? "";
640661
+ let charInLine = col - this.promptWidth - 2;
640662
+ if (charInLine < 0) charInLine = 0;
640663
+ if (charInLine > rawLine.length) charInLine = rawLine.length;
640664
+ const newCursor = (charPositions[lineIdx] ?? 0) + charInLine;
640665
+ this._inputMutator?.(line, Math.min(newCursor, line.length));
640666
+ if (this.active && !this._resizing) this.renderFooterAndPositionInput();
640667
+ return true;
640232
640668
  }
640233
640669
  wrapPlainInputText(text2, availWidth) {
640234
640670
  const width = Math.max(1, availWidth);
@@ -640462,8 +640898,7 @@ ${CONTENT_BG_SEQ}`);
640462
640898
  }
640463
640899
  const inputWrap = this.wrapInput(w);
640464
640900
  let buf = "\x1B[?7l";
640465
- const boxInner = w - 2;
640466
- buf += `\x1B[${pos.inputStartRow};1H${PANEL_BG_SEQ}\x1B[2K${BOX_FG}${BOX_TL3}${BOX_H3.repeat(Math.max(0, boxInner))}${BOX_TR3}${RESET4}${PANEL_BG_SEQ}`;
640901
+ buf += `\x1B[${pos.inputStartRow};1H${PANEL_BG_SEQ}\x1B[2K${this.buildInputBoxTop(w)}${PANEL_BG_SEQ}`;
640467
640902
  const Lspacer = layout();
640468
640903
  const spacerRow = pos.inputStartRow - 1;
640469
640904
  const tasksOccupiesSpacer = Lspacer.tasksHeight > 0 && spacerRow >= Lspacer.tasksTop && spacerRow <= Lspacer.tasksBottom;
@@ -640479,6 +640914,11 @@ ${CONTENT_BG_SEQ}`);
640479
640914
  buf += `${PANEL_BG_SEQ}\x1B[K`;
640480
640915
  buf += `\x1B[${row};${w}H${BOX_FG}${BOX_V3}${RESET4}${PANEL_BG_SEQ}`;
640481
640916
  }
640917
+ buf += this.buildEnhanceSegment(
640918
+ w,
640919
+ pos.inputStartRow + 1,
640920
+ inputWrap.lines.length
640921
+ );
640482
640922
  const cursorTermRow = pos.inputStartRow + 1 + inputWrap.cursorRow;
640483
640923
  if (this._suggestions.length > 0 && pos.suggestStartRow > 0) {
640484
640924
  for (let si = 0; si < this._suggestions.length; si++) {
@@ -640495,9 +640935,9 @@ ${CONTENT_BG_SEQ}`);
640495
640935
  buf += `\x1B[${row};${w}H${BOX_FG}${BOX_V3}${RESET4}${PANEL_BG_SEQ}`;
640496
640936
  }
640497
640937
  const suggestBottomRow = pos.suggestStartRow + this._suggestions.length;
640498
- buf += `\x1B[${suggestBottomRow};1H${PANEL_BG_SEQ}\x1B[2K${BOX_FG}${BOX_BL3}${BOX_H3.repeat(Math.max(0, boxInner))}${BOX_BR3}${RESET4}${PANEL_BG_SEQ}`;
640938
+ buf += `\x1B[${suggestBottomRow};1H${PANEL_BG_SEQ}\x1B[2K${this.buildInputBoxBottom(w)}${PANEL_BG_SEQ}`;
640499
640939
  } else {
640500
- buf += `\x1B[${pos.bufferRow};1H${PANEL_BG_SEQ}\x1B[2K${BOX_FG}${BOX_BL3}${BOX_H3.repeat(Math.max(0, boxInner))}${BOX_BR3}${RESET4}${PANEL_BG_SEQ}`;
640940
+ buf += `\x1B[${pos.bufferRow};1H${PANEL_BG_SEQ}\x1B[2K${this.buildInputBoxBottom(w)}${PANEL_BG_SEQ}`;
640501
640941
  }
640502
640942
  if (pos.metricsRow > 0) {
640503
640943
  buf += `\x1B[${pos.metricsRow};1H${PANEL_BG_SEQ}\x1B[2K${this.buildMetricsLine()}${RESET4}${PANEL_BG_SEQ}`;
@@ -640537,7 +640977,6 @@ ${CONTENT_BG_SEQ}`);
640537
640977
  if (pos.tabBarRow > 0) {
640538
640978
  buf += `\x1B[${pos.tabBarRow};1H${PANEL_BG_SEQ}\x1B[2K${RESET4}`;
640539
640979
  }
640540
- const boxInnerR = w - 2;
640541
640980
  if (this._suggestions.length > 0 && pos.suggestStartRow > 0) {
640542
640981
  for (let si = 0; si < this._suggestions.length; si++) {
640543
640982
  const row = pos.suggestStartRow + si;
@@ -640548,9 +640987,9 @@ ${CONTENT_BG_SEQ}`);
640548
640987
  buf += `\x1B[${row};1H${PANEL_BG_SEQ}\x1B[2K${BOX_FG}${BOX_V3}${RESET4}${PANEL_BG_SEQ} ${marker}\x1B[38;5;${TEXT_DIM}m/${fg2}${cmd}`;
640549
640988
  buf += `${PANEL_BG_SEQ}\x1B[K\x1B[${row};${w}H${BOX_FG}${BOX_V3}${RESET4}`;
640550
640989
  }
640551
- buf += `\x1B[${pos.bufferRow};1H${PANEL_BG_SEQ}\x1B[2K${BOX_FG}${BOX_BL3}${BOX_H3.repeat(Math.max(0, boxInnerR))}${BOX_BR3}${RESET4}`;
640990
+ buf += `\x1B[${pos.bufferRow};1H${PANEL_BG_SEQ}\x1B[2K${this.buildInputBoxBottom(w)}`;
640552
640991
  } else {
640553
- buf += `\x1B[${pos.bufferRow};1H${PANEL_BG_SEQ}\x1B[2K${BOX_FG}${BOX_BL3}${BOX_H3.repeat(Math.max(0, boxInnerR))}${BOX_BR3}${RESET4}`;
640992
+ buf += `\x1B[${pos.bufferRow};1H${PANEL_BG_SEQ}\x1B[2K${this.buildInputBoxBottom(w)}`;
640554
640993
  }
640555
640994
  if (pos.metricsRow > 0) {
640556
640995
  buf += `\x1B[${pos.metricsRow};1H${PANEL_BG_SEQ}\x1B[2K${this.buildMetricsLine()}${RESET4}${PANEL_BG_SEQ}`;
@@ -640604,14 +641043,18 @@ ${CONTENT_BG_SEQ}`);
640604
641043
  }
640605
641044
  }
640606
641045
  buf += "\x1B[?7l";
640607
- const boxInnerH = w - 2;
640608
- buf += `\x1B[${pos.inputStartRow};1H${PANEL_BG_SEQ}\x1B[2K${BOX_FG}${BOX_TL3}${BOX_H3.repeat(Math.max(0, boxInnerH))}${BOX_TR3}${RESET4}`;
641046
+ buf += `\x1B[${pos.inputStartRow};1H${PANEL_BG_SEQ}\x1B[2K${this.buildInputBoxTop(w)}`;
640609
641047
  for (let i2 = 0; i2 < inputWrap.lines.length; i2++) {
640610
641048
  const row = pos.inputStartRow + 1 + i2;
640611
641049
  const prefix = i2 === 0 ? this.promptText : " ".repeat(this.promptWidth);
640612
641050
  const lineContent = `${prefix}${inputWrap.lines[i2]}`;
640613
641051
  buf += `\x1B[${row};1H${PANEL_BG_SEQ}\x1B[2K${BOX_FG}${BOX_V3}${RESET4}${PANEL_BG_SEQ}${lineContent}${PANEL_BG_SEQ}\x1B[K\x1B[${row};${w}H${BOX_FG}${BOX_V3}${RESET4}`;
640614
641052
  }
641053
+ buf += this.buildEnhanceSegment(
641054
+ w,
641055
+ pos.inputStartRow + 1,
641056
+ inputWrap.lines.length
641057
+ );
640615
641058
  if (this._suggestions.length > 0 && pos.suggestStartRow > 0) {
640616
641059
  for (let si = 0; si < this._suggestions.length; si++) {
640617
641060
  const row = pos.suggestStartRow + si;
@@ -640625,8 +641068,7 @@ ${CONTENT_BG_SEQ}`);
640625
641068
  buf += `${PANEL_BG_SEQ}\x1B[K\x1B[${row};${w}H${BOX_FG}${BOX_V3}${RESET4}`;
640626
641069
  }
640627
641070
  }
640628
- const boxInnerS = w - 2;
640629
- buf += `\x1B[${pos.bufferRow};1H${PANEL_BG_SEQ}\x1B[2K${BOX_FG}${BOX_BL3}${BOX_H3.repeat(Math.max(0, boxInnerS))}${BOX_BR3}${RESET4}`;
641071
+ buf += `\x1B[${pos.bufferRow};1H${PANEL_BG_SEQ}\x1B[2K${this.buildInputBoxBottom(w)}`;
640630
641072
  if (pos.metricsRow > 0) {
640631
641073
  buf += `\x1B[${pos.metricsRow};1H${PANEL_BG_SEQ}\x1B[2K${this.buildMetricsLine()}${RESET4}`;
640632
641074
  }
@@ -640643,8 +641085,7 @@ ${CONTENT_BG_SEQ}`);
640643
641085
  if (heightDelta !== 0) this.refreshTasksPanelAfterLayoutChange();
640644
641086
  } else {
640645
641087
  let buf = "\x1B7\x1B[?25l\x1B[?7l";
640646
- const boxInnerH = w - 2;
640647
- buf += `\x1B[${pos.inputStartRow};1H${PANEL_BG_SEQ}\x1B[2K${BOX_FG}${BOX_TL3}${BOX_H3.repeat(Math.max(0, boxInnerH))}${BOX_TR3}${RESET4}${PANEL_BG_SEQ}`;
641088
+ buf += `\x1B[${pos.inputStartRow};1H${PANEL_BG_SEQ}\x1B[2K${this.buildInputBoxTop(w)}${PANEL_BG_SEQ}`;
640648
641089
  for (let i2 = 0; i2 < inputWrap.lines.length; i2++) {
640649
641090
  const row = pos.inputStartRow + 1 + i2;
640650
641091
  const prefix = i2 === 0 ? this.promptText : " ".repeat(this.promptWidth);
@@ -640654,6 +641095,11 @@ ${CONTENT_BG_SEQ}`);
640654
641095
  buf += `${PANEL_BG_SEQ}\x1B[K`;
640655
641096
  buf += `\x1B[${row};${w}H${BOX_FG}${BOX_V3}${RESET4}${PANEL_BG_SEQ}`;
640656
641097
  }
641098
+ buf += this.buildEnhanceSegment(
641099
+ w,
641100
+ pos.inputStartRow + 1,
641101
+ inputWrap.lines.length
641102
+ );
640657
641103
  if (this._suggestions.length > 0 && pos.suggestStartRow > 0) {
640658
641104
  for (let si = 0; si < this._suggestions.length; si++) {
640659
641105
  const row = pos.suggestStartRow + si;
@@ -640667,7 +641113,7 @@ ${CONTENT_BG_SEQ}`);
640667
641113
  buf += `${PANEL_BG_SEQ}\x1B[K\x1B[${row};${w}H${BOX_FG}${BOX_V3}${RESET4}${PANEL_BG_SEQ}`;
640668
641114
  }
640669
641115
  }
640670
- buf += `\x1B[${pos.bufferRow};1H${PANEL_BG_SEQ}\x1B[2K${BOX_FG}${BOX_BL3}${BOX_H3.repeat(Math.max(0, boxInnerH))}${BOX_BR3}${RESET4}${PANEL_BG_SEQ}`;
641116
+ buf += `\x1B[${pos.bufferRow};1H${PANEL_BG_SEQ}\x1B[2K${this.buildInputBoxBottom(w)}${PANEL_BG_SEQ}`;
640671
641117
  if (pos.metricsRow > 0) {
640672
641118
  buf += `\x1B[${pos.metricsRow};1H${PANEL_BG_SEQ}\x1B[2K${this.buildMetricsLine()}${RESET4}${PANEL_BG_SEQ}`;
640673
641119
  }
@@ -684006,147 +684452,6 @@ var init_emotion_engine = __esm({
684006
684452
  }
684007
684453
  });
684008
684454
 
684009
- // packages/cli/src/tui/conversation-context.ts
684010
- import { statfsSync as statfsSync8 } from "node:fs";
684011
- function buildConversationRuntimeContext(now2 = /* @__PURE__ */ new Date(), repoRoot) {
684012
- const date = new Intl.DateTimeFormat("en-US", {
684013
- weekday: "long",
684014
- year: "numeric",
684015
- month: "long",
684016
- day: "numeric"
684017
- }).format(now2);
684018
- const time = new Intl.DateTimeFormat("en-US", {
684019
- hour: "numeric",
684020
- minute: "2-digit",
684021
- second: "2-digit",
684022
- timeZoneName: "short"
684023
- }).format(now2);
684024
- const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone || process.env["TZ"] || "system";
684025
- let diskLine = "";
684026
- if (repoRoot) {
684027
- try {
684028
- const stats = statfsSync8(repoRoot);
684029
- const totalBytes = Number(stats.blocks) * Number(stats.bsize);
684030
- const freeBytes = Number(stats.bavail) * Number(stats.bsize);
684031
- const usedBytes = totalBytes - freeBytes;
684032
- const totalGB = Math.round(totalBytes / 1024 ** 3);
684033
- const freeGB = Math.round(freeBytes / 1024 ** 3);
684034
- const usedGB = Math.round(usedBytes / 1024 ** 3);
684035
- const usedPct = totalBytes > 0 ? Math.round(usedBytes / totalBytes * 100) : 0;
684036
- diskLine = `Disk: disk_available_gb=${freeGB} disk_used_gb=${usedGB} disk_total_gb=${totalGB} disk_used_pct=${usedPct} path=${repoRoot}`;
684037
- } catch {
684038
- }
684039
- }
684040
- return [
684041
- `Current date: ${date}`,
684042
- `Current time: ${time}`,
684043
- `Current ISO timestamp: ${now2.toISOString()}`,
684044
- `Timezone: ${timezone}`,
684045
- repoRoot ? `Working directory: ${repoRoot}` : "",
684046
- diskLine
684047
- ].filter(Boolean).join("\n");
684048
- }
684049
- function quoteConversationBlock(value2, maxChars = 2400) {
684050
- const text2 = String(value2 ?? "").replace(/\r\n/g, "\n").trim();
684051
- if (!text2) return "> (empty)";
684052
- const clipped = text2.length > maxChars ? `${text2.slice(0, Math.max(0, maxChars - 1))}...` : text2;
684053
- return clipped.split("\n").map((line) => `> ${line}`).join("\n");
684054
- }
684055
- function buildScopedConversationMessages(turns, options2) {
684056
- const pinned = [];
684057
- const dynamic = [];
684058
- let latestContextFrame = null;
684059
- for (const turn of turns) {
684060
- if (options2.isPinnedSystemTurn(turn) && !pinned.some((p2) => p2.content === turn.content)) {
684061
- pinned.push(turn);
684062
- } else if (options2.isContextFrameTurn?.(turn)) {
684063
- latestContextFrame = turn;
684064
- } else {
684065
- dynamic.push(turn);
684066
- }
684067
- }
684068
- if (latestContextFrame) {
684069
- if (options2.placeContextFrameBeforeLastUser !== false) {
684070
- let lastUserIdx = -1;
684071
- for (let i2 = dynamic.length - 1; i2 >= 0; i2--) {
684072
- if (dynamic[i2].role === "user") {
684073
- lastUserIdx = i2;
684074
- break;
684075
- }
684076
- }
684077
- if (lastUserIdx >= 0) dynamic.splice(lastUserIdx, 0, latestContextFrame);
684078
- else dynamic.push(latestContextFrame);
684079
- } else {
684080
- dynamic.push(latestContextFrame);
684081
- }
684082
- }
684083
- const available = Math.max(0, options2.maxMessages - pinned.length);
684084
- let windowed = dynamic.slice(-available);
684085
- if (latestContextFrame && available > 0 && !windowed.includes(latestContextFrame)) {
684086
- windowed = [latestContextFrame, ...windowed.slice(-(available - 1))];
684087
- }
684088
- return [...pinned, ...windowed];
684089
- }
684090
- function buildVoiceSessionContext(args) {
684091
- const maxTranscriptTurns = Math.max(1, args.maxTranscriptTurns ?? 8);
684092
- const voiceLines = (args.voiceTranscript ?? []).slice(-maxTranscriptTurns).map((turn) => `${formatClock(turn.ts)} ${turn.role}: ${singleLine(turn.content, 360)}`);
684093
- const relayLines = (args.relayTranscript ?? []).slice(-maxTranscriptTurns).map((turn) => {
684094
- const dir = turn.dir === "toMain" ? "voice->main" : "main->voice";
684095
- return `${formatClock(turn.ts)} ${dir}: ${singleLine(turn.content, 360)}`;
684096
- });
684097
- const taskLine = args.activeTask ? `active=${args.activeTask.active ? "yes" : "no"} tool_calls=${args.activeTask.toolCalls ?? 0} files_touched=${args.activeTask.filesTouched ?? 0}` : "active=unknown";
684098
- const sections = [
684099
- `## Runtime Context
684100
-
684101
- ${buildConversationRuntimeContext(/* @__PURE__ */ new Date(), args.repoRoot)}`,
684102
- [
684103
- "## Voice/Live Session Contract",
684104
- "",
684105
- `surface=voicechat session_id=${args.sessionId} turn=${args.turnCount}`,
684106
- `main_agent_task=${taskLine}`,
684107
- "Latest user utterance remains the active request. Earlier ASR transcript turns are conversational history, not new instructions.",
684108
- "ASR text can be noisy. Prefer consensus-filtered final turns, resolve pronouns from recent context, and ask for clarification rather than filling gaps.",
684109
- "Live perception is evidence for the current reply, not a topic to narrate unless the user asks about it."
684110
- ].join("\n")
684111
- ];
684112
- if (voiceLines.length > 0) {
684113
- sections.push(`## Recent Voice Conversation
684114
-
684115
- ${quoteConversationBlock(voiceLines.join("\n"))}`);
684116
- }
684117
- if (relayLines.length > 0) {
684118
- sections.push(`## Main Agent Relay Stream
684119
-
684120
- ${quoteConversationBlock(relayLines.join("\n"))}`);
684121
- }
684122
- if (args.liveContext?.trim()) {
684123
- sections.push(`## Live Context Frame
684124
-
684125
- ${args.liveContext.trim()}`);
684126
- }
684127
- return sections.join("\n\n");
684128
- }
684129
- function singleLine(value2, maxChars) {
684130
- const clean5 = value2.replace(/\s+/g, " ").trim();
684131
- return clean5.length > maxChars ? `${clean5.slice(0, Math.max(0, maxChars - 1))}...` : clean5;
684132
- }
684133
- function formatClock(ts) {
684134
- try {
684135
- return new Date(ts).toLocaleTimeString("en-US", {
684136
- hour: "2-digit",
684137
- minute: "2-digit",
684138
- second: "2-digit"
684139
- });
684140
- } catch {
684141
- return "unknown-time";
684142
- }
684143
- }
684144
- var init_conversation_context = __esm({
684145
- "packages/cli/src/tui/conversation-context.ts"() {
684146
- "use strict";
684147
- }
684148
- });
684149
-
684150
684455
  // packages/cli/src/tui/telegram-format.ts
684151
684456
  function escapeHtml2(text2) {
684152
684457
  return String(text2 ?? "").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
@@ -745080,6 +745385,118 @@ When done, either call task_complete with your answer, or use FINAL_VAR(variable
745080
745385
  }
745081
745386
  };
745082
745387
  }
745388
+ function extractEnhancedPrompt(raw) {
745389
+ const text2 = raw.trim();
745390
+ if (!text2) return null;
745391
+ const tryParse = (candidate) => {
745392
+ try {
745393
+ const obj = JSON.parse(candidate);
745394
+ const v = obj["enhancedPrompt"] ?? obj["enhanced_prompt"] ?? obj["prompt"] ?? obj["result"];
745395
+ return typeof v === "string" && v.trim() ? v : null;
745396
+ } catch {
745397
+ return null;
745398
+ }
745399
+ };
745400
+ const direct = tryParse(text2);
745401
+ if (direct) return direct;
745402
+ const fenced = text2.match(/```(?:json)?\s*([\s\S]*?)```/i);
745403
+ if (fenced?.[1]) {
745404
+ const f2 = tryParse(fenced[1].trim());
745405
+ if (f2) return f2;
745406
+ }
745407
+ const brace = text2.match(/\{[\s\S]*\}/);
745408
+ if (brace?.[0]) {
745409
+ const b = tryParse(brace[0]);
745410
+ if (b) return b;
745411
+ }
745412
+ const keyed = text2.match(
745413
+ /"enhanced_?[Pp]rompt"\s*:\s*"((?:[^"\\]|\\.)*)"/
745414
+ );
745415
+ if (keyed?.[1]) {
745416
+ try {
745417
+ return JSON.parse('"' + keyed[1] + '"');
745418
+ } catch {
745419
+ return keyed[1];
745420
+ }
745421
+ }
745422
+ if (!text2.startsWith("{") && !text2.startsWith("[")) return text2;
745423
+ return null;
745424
+ }
745425
+ async function enhancePromptViaInference(seed, ctx3) {
745426
+ const seedText = seed.trim();
745427
+ if (!seedText) return null;
745428
+ let backend;
745429
+ try {
745430
+ if (ctx3.config.backendType === "nexus") {
745431
+ const nexusTool = new NexusTool(ctx3.repoRoot);
745432
+ const peer = ctx3.config.backendUrl.startsWith("peer://") ? ctx3.config.backendUrl.slice(7) : void 0;
745433
+ backend = new NexusAgenticBackend(
745434
+ nexusTool.sendCommand.bind(nexusTool),
745435
+ ctx3.config.model,
745436
+ peer,
745437
+ ctx3.config.apiKey
745438
+ );
745439
+ } else {
745440
+ backend = new OllamaAgenticBackend(
745441
+ ctx3.config.backendUrl,
745442
+ ctx3.config.model,
745443
+ ctx3.config.apiKey
745444
+ );
745445
+ }
745446
+ } catch {
745447
+ return null;
745448
+ }
745449
+ const recent = ctx3.recentHistory.filter((h) => h && h.trim()).slice(0, 5).map((h, i2) => ` ${i2 + 1}. ${h.trim().slice(0, 240)}`).join("\n");
745450
+ let runtimeCtx = "";
745451
+ try {
745452
+ runtimeCtx = buildConversationRuntimeContext(/* @__PURE__ */ new Date(), ctx3.repoRoot);
745453
+ } catch {
745454
+ runtimeCtx = "";
745455
+ }
745456
+ const userPrompt = [
745457
+ "Expand the SEED PROMPT below into a comprehensive, precise, self-contained instruction set for an agentic coding assistant.",
745458
+ "Preserve the user's original intent exactly. Do NOT answer or solve it, do NOT invent unrelated scope.",
745459
+ "Clarify the goal, surface implied requirements, relevant constraints, edge cases, and concrete acceptance criteria.",
745460
+ "Fold in only the session context that is actually relevant. Keep it phrased as an instruction in the user's voice.",
745461
+ "Return no preamble and no meta-commentary about the prompt itself.",
745462
+ ctx3.activeGoal ? `
745463
+ Task currently in progress: ${ctx3.activeGoal.slice(0, 400)}` : "",
745464
+ recent ? `
745465
+ Recent prompts this session (newest first):
745466
+ ${recent}` : "",
745467
+ runtimeCtx ? `
745468
+ Session/runtime context:
745469
+ ${runtimeCtx}` : "",
745470
+ `
745471
+ SEED PROMPT:
745472
+ ${seedText}`
745473
+ ].filter(Boolean).join("\n");
745474
+ try {
745475
+ const resp = await backend.chatCompletion({
745476
+ messages: [
745477
+ {
745478
+ role: "system",
745479
+ content: `You are a prompt-expansion engine. You rewrite a user's short seed prompt into a richer, unambiguous instruction that fully captures their intent. Return strict JSON only: {"enhancedPrompt": string}.`
745480
+ },
745481
+ { role: "user", content: userPrompt }
745482
+ ],
745483
+ tools: [],
745484
+ temperature: 0.4,
745485
+ maxTokens: 1400,
745486
+ timeoutMs: 6e4,
745487
+ think: false,
745488
+ responseFormat: { type: "json_object" }
745489
+ });
745490
+ const rawContent2 = resp.choices?.[0]?.message?.content ?? "";
745491
+ if (!rawContent2) return null;
745492
+ const enhanced = extractEnhancedPrompt(rawContent2);
745493
+ if (!enhanced) return null;
745494
+ const clean5 = enhanced.trim();
745495
+ return clean5 && clean5 !== seedText ? clean5 : null;
745496
+ } catch {
745497
+ return null;
745498
+ }
745499
+ }
745083
745500
  async function startInteractive(config, repoPath2) {
745084
745501
  const repoRoot = resolve74(repoPath2 ?? cwd());
745085
745502
  try {
@@ -746664,6 +747081,20 @@ This is an independent background session started from /background.`
746664
747081
  }
746665
747082
  })();
746666
747083
  });
747084
+ statusBar.setInputMutator((line, cursor) => {
747085
+ try {
747086
+ rl.setLine(line, cursor);
747087
+ } catch {
747088
+ }
747089
+ });
747090
+ statusBar.setEnhanceHandler(async (seedPrompt) => {
747091
+ return enhancePromptViaInference(seedPrompt, {
747092
+ config: currentConfig,
747093
+ repoRoot,
747094
+ recentHistory: savedHistory,
747095
+ activeGoal: activeTask ? lastSubmittedPrompt : void 0
747096
+ });
747097
+ });
746667
747098
  if (process.stdin.isTTY && typeof process.stdin.setRawMode === "function") {
746668
747099
  process.stdin.setRawMode(true);
746669
747100
  }
@@ -750180,6 +750611,7 @@ ${result.content.slice(0, 2e3)}${result.content.length > 2e3 ? "\n[truncated]" :
750180
750611
  };
750181
750612
  };
750182
750613
  rl.on("line", (line) => {
750614
+ statusBar.resetEnhance?.();
750183
750615
  if (!setupReady) return;
750184
750616
  idleMemoryMaintenance?.notifyActivity();
750185
750617
  persistHistoryLine(line);
@@ -751172,6 +751604,7 @@ ${c3.dim("(Use /quit to exit)")}
751172
751604
  showPrompt();
751173
751605
  });
751174
751606
  _escapeHandler = () => {
751607
+ statusBar.resetEnhance?.();
751175
751608
  if (!activeTask && statusBar.activeViewId !== "main") {
751176
751609
  statusBar.switchToView("main");
751177
751610
  statusBar.beginContentWrite();
@@ -751682,6 +752115,7 @@ var init_interactive = __esm({
751682
752115
  init_memory_paths();
751683
752116
  init_visual_sensor_guidance();
751684
752117
  init_live_sensors();
752118
+ init_conversation_context();
751685
752119
  init_dist8();
751686
752120
  init_dist8();
751687
752121
  init_dist8();
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.487",
3
+ "version": "1.0.488",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "omnius",
9
- "version": "1.0.487",
9
+ "version": "1.0.488",
10
10
  "bundleDependencies": [
11
11
  "image-to-ascii"
12
12
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.487",
3
+ "version": "1.0.488",
4
4
  "description": "AI coding agent powered by open-source models (Ollama/vLLM) — interactive TUI with agentic tool-calling loop",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",