pentesting 0.70.3 → 0.70.5

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.
Files changed (2) hide show
  1. package/dist/main.js +290 -266
  2. package/package.json +1 -1
package/dist/main.js CHANGED
@@ -120,7 +120,7 @@ var ICONS = {
120
120
  };
121
121
 
122
122
  // src/shared/utils/debug/debug-logger.ts
123
- import { appendFileSync, writeFileSync } from "fs";
123
+ import { appendFileSync, writeFileSync, statSync, readFileSync } from "fs";
124
124
  import { join } from "path";
125
125
 
126
126
  // src/shared/utils/file-ops/file-utils.ts
@@ -275,10 +275,14 @@ var FILE_PATTERNS = {
275
275
  };
276
276
 
277
277
  // src/shared/utils/debug/debug-logger.ts
278
+ var ROTATE_BYTES = 5 * 1024 * 1024;
279
+ var WIPE_BYTES = 20 * 1024 * 1024;
280
+ var ROTATE_CHECK_INTERVAL = 500;
278
281
  var DebugLogger = class _DebugLogger {
279
282
  static instance;
280
283
  logPath;
281
284
  initialized = false;
285
+ writeCount = 0;
282
286
  constructor(clearOnInit = false) {
283
287
  const debugDir = WORKSPACE.DEBUG;
284
288
  try {
@@ -306,6 +310,31 @@ var DebugLogger = class _DebugLogger {
306
310
  _DebugLogger.instance = new _DebugLogger(clearOnInit);
307
311
  return _DebugLogger.instance;
308
312
  }
313
+ /**
314
+ * Rotate or wipe debug.log if it exceeds size thresholds.
315
+ * Called every ROTATE_CHECK_INTERVAL writes to amortize statSync cost.
316
+ *
317
+ * Policy:
318
+ * > 20 MB → wipe entirely (too much data, disk pressure)
319
+ * > 5 MB → keep latest half (recent logs more useful than old ones)
320
+ */
321
+ rotateIfNeeded() {
322
+ try {
323
+ const size = statSync(this.logPath).size;
324
+ if (size > WIPE_BYTES) {
325
+ writeFileSync(this.logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] [GENERAL] === LOG WIPED (exceeded ${Math.round(WIPE_BYTES / 1024 / 1024)}MB) ===
326
+ `);
327
+ } else if (size > ROTATE_BYTES) {
328
+ const content = readFileSync(this.logPath, "utf-8");
329
+ const half = content.slice(Math.floor(content.length / 2));
330
+ const firstNewline = half.indexOf("\n");
331
+ const trimmed = firstNewline >= 0 ? half.slice(firstNewline + 1) : half;
332
+ writeFileSync(this.logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] [GENERAL] === LOG ROTATED (exceeded ${Math.round(ROTATE_BYTES / 1024 / 1024)}MB, kept latest half) ===
333
+ ` + trimmed);
334
+ }
335
+ } catch {
336
+ }
337
+ }
309
338
  log(category, message, data) {
310
339
  if (!this.initialized || !this.logPath) return;
311
340
  try {
@@ -316,6 +345,9 @@ var DebugLogger = class _DebugLogger {
316
345
  }
317
346
  logLine += "\n";
318
347
  appendFileSync(this.logPath, logLine);
348
+ if (++this.writeCount % ROTATE_CHECK_INTERVAL === 0) {
349
+ this.rotateIfNeeded();
350
+ }
319
351
  } catch (e) {
320
352
  console.error("[DebugLogger] Write error:", e);
321
353
  }
@@ -329,6 +361,9 @@ ${raw}
329
361
  ---
330
362
  `;
331
363
  appendFileSync(this.logPath, logLine);
364
+ if (++this.writeCount % ROTATE_CHECK_INTERVAL === 0) {
365
+ this.rotateIfNeeded();
366
+ }
332
367
  } catch (e) {
333
368
  console.error("[DebugLogger] Write error:", e);
334
369
  }
@@ -727,7 +762,7 @@ var INPUT_PROMPT_PATTERNS = [
727
762
 
728
763
  // src/shared/constants/agent.ts
729
764
  var APP_NAME = "Pentest AI";
730
- var APP_VERSION = "0.70.3";
765
+ var APP_VERSION = "0.70.5";
731
766
  var APP_DESCRIPTION = "Autonomous Penetration Testing AI Agent";
732
767
  var LLM_ROLES = {
733
768
  SYSTEM: "system",
@@ -782,7 +817,7 @@ import { render } from "ink";
782
817
  import chalk from "chalk";
783
818
 
784
819
  // src/platform/tui/app.tsx
785
- import { useState as useState9, useCallback as useCallback11, useRef as useRef10 } from "react";
820
+ import { useState as useState7, useCallback as useCallback11, useRef as useRef10 } from "react";
786
821
  import { Box as Box19, useApp, useStdout as useStdout4 } from "ink";
787
822
 
788
823
  // src/platform/tui/hooks/useAgent.ts
@@ -2458,7 +2493,7 @@ var EpisodicMemory = class {
2458
2493
  };
2459
2494
 
2460
2495
  // src/shared/utils/agent-memory/persistent-memory.ts
2461
- import { existsSync as existsSync2, readFileSync, writeFileSync as writeFileSync2, unlinkSync } from "fs";
2496
+ import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2, unlinkSync } from "fs";
2462
2497
  import { join as join2 } from "path";
2463
2498
 
2464
2499
  // src/shared/utils/agent-memory/similarity.ts
@@ -2634,7 +2669,7 @@ var PersistentMemory = class {
2634
2669
  loadSessionSnapshot() {
2635
2670
  try {
2636
2671
  if (existsSync2(SNAPSHOT_FILE)) {
2637
- return JSON.parse(readFileSync(SNAPSHOT_FILE, "utf-8"));
2672
+ return JSON.parse(readFileSync2(SNAPSHOT_FILE, "utf-8"));
2638
2673
  }
2639
2674
  } catch {
2640
2675
  }
@@ -2670,7 +2705,7 @@ var PersistentMemory = class {
2670
2705
  load() {
2671
2706
  try {
2672
2707
  if (existsSync2(MEMORY_FILE)) {
2673
- const data = JSON.parse(readFileSync(MEMORY_FILE, "utf-8"));
2708
+ const data = JSON.parse(readFileSync2(MEMORY_FILE, "utf-8"));
2674
2709
  return {
2675
2710
  ...data,
2676
2711
  exploitChains: data.exploitChains ?? []
@@ -4555,7 +4590,7 @@ Suggestion: ${torLeak.suggestion}`
4555
4590
  }
4556
4591
 
4557
4592
  // src/engine/tools-base/file-operations.ts
4558
- import { readFileSync as readFileSync2, existsSync as existsSync3, writeFileSync as writeFileSync3 } from "fs";
4593
+ import { readFileSync as readFileSync3, existsSync as existsSync3, writeFileSync as writeFileSync3 } from "fs";
4559
4594
  import { dirname } from "path";
4560
4595
  import { join as join3 } from "path";
4561
4596
  import { tmpdir } from "os";
@@ -4575,7 +4610,7 @@ async function readFileContent(filePath) {
4575
4610
  error: `File not found: ${filePath}`
4576
4611
  };
4577
4612
  }
4578
- const content = readFileSync2(filePath, "utf-8");
4613
+ const content = readFileSync3(filePath, "utf-8");
4579
4614
  return {
4580
4615
  success: true,
4581
4616
  output: content
@@ -4679,7 +4714,7 @@ function startBackgroundProcess(command, options = {}) {
4679
4714
  }
4680
4715
 
4681
4716
  // src/engine/process/process-interaction.ts
4682
- import { existsSync as existsSync4, readFileSync as readFileSync3, appendFileSync as appendFileSync2 } from "fs";
4717
+ import { existsSync as existsSync4, readFileSync as readFileSync4, appendFileSync as appendFileSync2 } from "fs";
4683
4718
  async function sendToProcess(processId, input, waitMs = SYSTEM_LIMITS.DEFAULT_WAIT_MS_INTERACT) {
4684
4719
  const proc = getProcess(processId);
4685
4720
  if (!proc) return { success: false, output: `Process ${processId} not found`, newOutput: "" };
@@ -4688,7 +4723,7 @@ async function sendToProcess(processId, input, waitMs = SYSTEM_LIMITS.DEFAULT_WA
4688
4723
  let currentLen = 0;
4689
4724
  try {
4690
4725
  if (existsSync4(proc.stdoutFile)) {
4691
- currentLen = readFileSync3(proc.stdoutFile, "utf-8").length;
4726
+ currentLen = readFileSync4(proc.stdoutFile, "utf-8").length;
4692
4727
  }
4693
4728
  } catch {
4694
4729
  }
@@ -4702,7 +4737,7 @@ async function sendToProcess(processId, input, waitMs = SYSTEM_LIMITS.DEFAULT_WA
4702
4737
  let fullStdout = "";
4703
4738
  try {
4704
4739
  if (existsSync4(proc.stdoutFile)) {
4705
- fullStdout = readFileSync3(proc.stdoutFile, "utf-8");
4740
+ fullStdout = readFileSync4(proc.stdoutFile, "utf-8");
4706
4741
  }
4707
4742
  } catch {
4708
4743
  }
@@ -4724,7 +4759,7 @@ function promoteToShell(processId, description) {
4724
4759
  }
4725
4760
 
4726
4761
  // src/engine/process/process-monitor.ts
4727
- import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
4762
+ import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
4728
4763
  function isProcessRunning(processId) {
4729
4764
  const proc = getProcess(processId);
4730
4765
  if (!proc) return false;
@@ -4738,7 +4773,7 @@ function isProcessRunning(processId) {
4738
4773
  if (proc.role === PROCESS_ROLES.LISTENER) {
4739
4774
  try {
4740
4775
  if (existsSync5(proc.stdoutFile)) {
4741
- const stdout = readFileSync4(proc.stdoutFile, "utf-8");
4776
+ const stdout = readFileSync5(proc.stdoutFile, "utf-8");
4742
4777
  if (detectConnection(stdout)) {
4743
4778
  promoteToShell(processId, "Reverse shell connected (auto-detected)");
4744
4779
  logEvent(processId, PROCESS_EVENTS.CONNECTION_DETECTED, `Connection detected on port ${proc.listeningPort}`);
@@ -4757,7 +4792,7 @@ function getProcessOutput(processId) {
4757
4792
  let stderr = "";
4758
4793
  try {
4759
4794
  if (existsSync5(proc.stdoutFile)) {
4760
- const content = readFileSync4(proc.stdoutFile, "utf-8");
4795
+ const content = readFileSync5(proc.stdoutFile, "utf-8");
4761
4796
  stdout = content.length > SYSTEM_LIMITS.MAX_STDOUT_SLICE ? `... [truncated ${content.length - SYSTEM_LIMITS.MAX_STDOUT_SLICE} chars] ...
4762
4797
  ` + content.slice(-SYSTEM_LIMITS.MAX_STDOUT_SLICE) : content;
4763
4798
  }
@@ -4765,7 +4800,7 @@ function getProcessOutput(processId) {
4765
4800
  }
4766
4801
  try {
4767
4802
  if (existsSync5(proc.stderrFile)) {
4768
- const content = readFileSync4(proc.stderrFile, "utf-8");
4803
+ const content = readFileSync5(proc.stderrFile, "utf-8");
4769
4804
  stderr = content.length > SYSTEM_LIMITS.MAX_STDERR_SLICE ? `... [truncated ${content.length - SYSTEM_LIMITS.MAX_STDERR_SLICE} chars] ...
4770
4805
  ` + content.slice(-SYSTEM_LIMITS.MAX_STDERR_SLICE) : content;
4771
4806
  }
@@ -4938,7 +4973,7 @@ async function cleanupAllProcesses() {
4938
4973
  }
4939
4974
 
4940
4975
  // src/engine/process/resource-summary.ts
4941
- import { existsSync as existsSync6, readFileSync as readFileSync5 } from "fs";
4976
+ import { existsSync as existsSync6, readFileSync as readFileSync6 } from "fs";
4942
4977
  function getResourceSummary() {
4943
4978
  const procs = listBackgroundProcesses();
4944
4979
  const running = procs.filter((p) => p.isRunning);
@@ -4958,7 +4993,7 @@ function getResourceSummary() {
4958
4993
  let lastOutput = "";
4959
4994
  try {
4960
4995
  if (p.stdoutFile && existsSync6(p.stdoutFile)) {
4961
- const content = readFileSync5(p.stdoutFile, "utf-8");
4996
+ const content = readFileSync6(p.stdoutFile, "utf-8");
4962
4997
  const outputLines = content.trim().split("\n");
4963
4998
  lastOutput = outputLines.slice(-SYSTEM_LIMITS.RECENT_OUTPUT_LINES).join(" | ").replace(/\n/g, " ");
4964
4999
  }
@@ -5203,7 +5238,7 @@ BLOCKED (leak real IP): ping, traceroute, dig, nslookup, nmap -sU`
5203
5238
  };
5204
5239
 
5205
5240
  // src/engine/state/persistence/saver.ts
5206
- import { writeFileSync as writeFileSync5, readdirSync, statSync, unlinkSync as unlinkSync5 } from "fs";
5241
+ import { writeFileSync as writeFileSync5, readdirSync, statSync as statSync2, unlinkSync as unlinkSync5 } from "fs";
5207
5242
  import { join as join4 } from "path";
5208
5243
  function saveState(state) {
5209
5244
  const sessionsDir = WORKSPACE.SESSIONS;
@@ -5236,7 +5271,7 @@ function pruneOldSessions(sessionsDir) {
5236
5271
  return {
5237
5272
  name: f,
5238
5273
  path: filePath,
5239
- mtime: statSync(filePath).mtimeMs
5274
+ mtime: statSync2(filePath).mtimeMs
5240
5275
  };
5241
5276
  }).sort((a, b) => b.mtime - a.mtime);
5242
5277
  const toDelete = sessionFiles.slice(AGENT_LIMITS.MAX_SESSION_FILES);
@@ -5248,7 +5283,7 @@ function pruneOldSessions(sessionsDir) {
5248
5283
  }
5249
5284
 
5250
5285
  // src/engine/state/persistence/loader.ts
5251
- import { readFileSync as readFileSync6, existsSync as existsSync7 } from "fs";
5286
+ import { readFileSync as readFileSync7, existsSync as existsSync7 } from "fs";
5252
5287
  import { join as join5 } from "path";
5253
5288
  function loadState(state) {
5254
5289
  const latestFile = join5(WORKSPACE.SESSIONS, "latest.json");
@@ -5256,7 +5291,7 @@ function loadState(state) {
5256
5291
  return false;
5257
5292
  }
5258
5293
  try {
5259
- const raw = readFileSync6(latestFile, "utf-8");
5294
+ const raw = readFileSync7(latestFile, "utf-8");
5260
5295
  const snapshot = JSON.parse(raw);
5261
5296
  if (snapshot.version !== 1) {
5262
5297
  debugLog("general", `Unknown snapshot version: ${snapshot.version}`);
@@ -10357,7 +10392,7 @@ function mutatePayload(request) {
10357
10392
  }
10358
10393
 
10359
10394
  // src/domains/exploit/tools.ts
10360
- import { existsSync as existsSync10, statSync as statSync2, readdirSync as readdirSync2 } from "fs";
10395
+ import { existsSync as existsSync10, statSync as statSync3, readdirSync as readdirSync2 } from "fs";
10361
10396
  import { join as join10 } from "path";
10362
10397
  var hashCrackTool = {
10363
10398
  name: TOOL_NAMES.HASH_CRACK,
@@ -10516,7 +10551,7 @@ Returns: All available wordlists with their paths, sizes, and categories.`,
10516
10551
  const processFile = (fullPath, fileName) => {
10517
10552
  const ext = fileName.split(".").pop()?.toLowerCase();
10518
10553
  if (!WORDLIST_EXTENSIONS.has(ext || "")) return;
10519
- const stats = statSync2(fullPath);
10554
+ const stats = statSync3(fullPath);
10520
10555
  if (stats.size < minSize) return;
10521
10556
  if (!matchesCategory(fullPath)) return;
10522
10557
  if (!matchesSearch(fullPath, fileName)) return;
@@ -13135,7 +13170,7 @@ var PHASE_TECHNIQUE_MAP = {
13135
13170
  };
13136
13171
 
13137
13172
  // src/agents/prompt-builder/prompt-loader.ts
13138
- import { readFileSync as readFileSync7, existsSync as existsSync11 } from "fs";
13173
+ import { readFileSync as readFileSync8, existsSync as existsSync11 } from "fs";
13139
13174
  import { join as join12, dirname as dirname4 } from "path";
13140
13175
  import { fileURLToPath as fileURLToPath2 } from "url";
13141
13176
  var __dirname2 = dirname4(fileURLToPath2(import.meta.url));
@@ -13143,13 +13178,13 @@ var PROMPTS_DIR = join12(__dirname2, "../prompts");
13143
13178
  var TECHNIQUES_DIR = join12(PROMPTS_DIR, PROMPT_PATHS.TECHNIQUES_DIR);
13144
13179
  function loadPromptFile(filename) {
13145
13180
  const path2 = join12(PROMPTS_DIR, filename);
13146
- return existsSync11(path2) ? readFileSync7(path2, PROMPT_CONFIG.ENCODING) : "";
13181
+ return existsSync11(path2) ? readFileSync8(path2, PROMPT_CONFIG.ENCODING) : "";
13147
13182
  }
13148
13183
  function loadTechniqueFile(techniqueName) {
13149
13184
  const filePath = join12(TECHNIQUES_DIR, `${techniqueName}.md`);
13150
13185
  try {
13151
13186
  if (!existsSync11(filePath)) return "";
13152
- return readFileSync7(filePath, PROMPT_CONFIG.ENCODING);
13187
+ return readFileSync8(filePath, PROMPT_CONFIG.ENCODING);
13153
13188
  } catch {
13154
13189
  return "";
13155
13190
  }
@@ -13294,11 +13329,11 @@ ${lines.join("\n")}
13294
13329
  }
13295
13330
 
13296
13331
  // src/shared/utils/journal/reader.ts
13297
- import { readFileSync as readFileSync8, existsSync as existsSync13 } from "fs";
13332
+ import { readFileSync as readFileSync9, existsSync as existsSync13 } from "fs";
13298
13333
  import { join as join14 } from "path";
13299
13334
 
13300
13335
  // src/shared/utils/journal/rotation.ts
13301
- import { existsSync as existsSync12, readdirSync as readdirSync3, statSync as statSync3, rmSync as rmSync2 } from "fs";
13336
+ import { existsSync as existsSync12, readdirSync as readdirSync3, statSync as statSync4, rmSync as rmSync2 } from "fs";
13302
13337
  import { join as join13 } from "path";
13303
13338
  function parseTurnNumbers(turnsDir) {
13304
13339
  if (!existsSync12(turnsDir)) return [];
@@ -13308,7 +13343,7 @@ function rotateTurnRecords() {
13308
13343
  try {
13309
13344
  const turnsDir = WORKSPACE.TURNS;
13310
13345
  if (!existsSync12(turnsDir)) return;
13311
- const turnDirs = parseTurnNumbers(turnsDir).map((n) => `${TURN_FOLDER_PREFIX}${n}`).filter((e) => statSync3(join13(turnsDir, e)).isDirectory()).sort((a, b) => Number(a.slice(TURN_FOLDER_PREFIX.length)) - Number(b.slice(TURN_FOLDER_PREFIX.length)));
13346
+ const turnDirs = parseTurnNumbers(turnsDir).map((n) => `${TURN_FOLDER_PREFIX}${n}`).filter((e) => statSync4(join13(turnsDir, e)).isDirectory()).sort((a, b) => Number(a.slice(TURN_FOLDER_PREFIX.length)) - Number(b.slice(TURN_FOLDER_PREFIX.length)));
13312
13347
  if (turnDirs.length > MEMORY_LIMITS.MAX_TURN_ENTRIES) {
13313
13348
  const dirsToDel = turnDirs.slice(0, turnDirs.length - MEMORY_LIMITS.MAX_TURN_ENTRIES);
13314
13349
  for (const dir of dirsToDel) {
@@ -13334,7 +13369,7 @@ function readJournalSummary() {
13334
13369
  for (const turn of turnDirs) {
13335
13370
  const summaryPath = join14(WORKSPACE.turnPath(turn), TURN_FILES.SUMMARY);
13336
13371
  if (existsSync13(summaryPath)) {
13337
- return readFileSync8(summaryPath, "utf-8");
13372
+ return readFileSync9(summaryPath, "utf-8");
13338
13373
  }
13339
13374
  }
13340
13375
  return "";
@@ -13351,7 +13386,7 @@ function getRecentEntries(count = MEMORY_LIMITS.MAX_TURN_ENTRIES) {
13351
13386
  try {
13352
13387
  const filePath = join14(WORKSPACE.turnPath(turn), TURN_FILES.STRUCTURED);
13353
13388
  if (existsSync13(filePath)) {
13354
- const raw = readFileSync8(filePath, "utf-8");
13389
+ const raw = readFileSync9(filePath, "utf-8");
13355
13390
  entries.push(JSON.parse(raw));
13356
13391
  }
13357
13392
  } catch {
@@ -14073,7 +14108,7 @@ function formatForPrompt(directive, isStale = false) {
14073
14108
  }
14074
14109
 
14075
14110
  // src/agents/strategist/prompt-loader.ts
14076
- import { readFileSync as readFileSync9, existsSync as existsSync14 } from "fs";
14111
+ import { readFileSync as readFileSync10, existsSync as existsSync14 } from "fs";
14077
14112
  import { join as join16, dirname as dirname5 } from "path";
14078
14113
  import { fileURLToPath as fileURLToPath3 } from "url";
14079
14114
  var __dirname3 = dirname5(fileURLToPath3(import.meta.url));
@@ -14081,7 +14116,7 @@ var STRATEGIST_PROMPT_PATH = join16(__dirname3, "../prompts", "strategist-system
14081
14116
  function loadSystemPrompt() {
14082
14117
  try {
14083
14118
  if (existsSync14(STRATEGIST_PROMPT_PATH)) {
14084
- return readFileSync9(STRATEGIST_PROMPT_PATH, "utf-8");
14119
+ return readFileSync10(STRATEGIST_PROMPT_PATH, "utf-8");
14085
14120
  }
14086
14121
  } catch {
14087
14122
  }
@@ -14477,7 +14512,7 @@ async function processReflection(toolJournal, memo14, phase, reflector) {
14477
14512
  }
14478
14513
 
14479
14514
  // src/agents/main-agent/turn-recorder.ts
14480
- import { writeFileSync as writeFileSync10, existsSync as existsSync15, readFileSync as readFileSync10 } from "fs";
14515
+ import { writeFileSync as writeFileSync10, existsSync as existsSync15, readFileSync as readFileSync11 } from "fs";
14481
14516
  import { join as join17 } from "path";
14482
14517
  async function recordTurn(context) {
14483
14518
  const { turnCounter, phase, toolJournal, memo: memo14, reflections, summaryRegenerator } = context;
@@ -14550,7 +14585,7 @@ async function regenerateSummary(turnCounter, summaryRegenerator, ctx) {
14550
14585
  if (prevTurn >= 1) {
14551
14586
  const prevSummaryPath = join17(WORKSPACE.turnPath(prevTurn), TURN_FILES.SUMMARY);
14552
14587
  if (existsSync15(prevSummaryPath)) {
14553
- existingSummary = readFileSync10(prevSummaryPath, "utf-8");
14588
+ existingSummary = readFileSync11(prevSummaryPath, "utf-8");
14554
14589
  }
14555
14590
  }
14556
14591
  const turnData = formatTurnRecord({
@@ -15202,11 +15237,12 @@ ${firstLine}`);
15202
15237
  }
15203
15238
 
15204
15239
  // src/platform/tui/hooks/useAgentEvents/handlers/input.ts
15205
- function setupInputHandlers(setInputRequest) {
15240
+ function setupInputHandlers(setInputRequest, addMessage) {
15206
15241
  setInputHandler((p) => {
15207
15242
  return new Promise((resolve) => {
15208
15243
  const isPassword = /password|passphrase/i.test(p);
15209
15244
  const inputType = /sudo/i.test(p) ? INPUT_TYPES.SUDO_PASSWORD : isPassword ? INPUT_TYPES.PASSWORD : INPUT_TYPES.TEXT;
15245
+ addMessage("ai", `\u{1F512} ${p.trim()}`);
15210
15246
  setInputRequest({
15211
15247
  status: "active",
15212
15248
  prompt: p.trim(),
@@ -15220,6 +15256,7 @@ function setupInputHandlers(setInputRequest) {
15220
15256
  return new Promise((resolve) => {
15221
15257
  const isPassword = SENSITIVE_INPUT_TYPES.includes(request.type);
15222
15258
  const displayPrompt = buildCredentialPrompt(request);
15259
+ addMessage("ai", `\u{1F512} ${displayPrompt}`);
15223
15260
  setInputRequest({
15224
15261
  status: "active",
15225
15262
  prompt: displayPrompt,
@@ -15287,7 +15324,7 @@ var useAgentEvents = (agent, eventsRef, state) => {
15287
15324
  lastStepTokensRef
15288
15325
  }, reasoningBufferRef);
15289
15326
  const reasoningHandlers = createReasoningHandlers({ addMessage, setCurrentStatus }, reasoningBufferRef);
15290
- const cleanupInput = setupInputHandlers(setInputRequest);
15327
+ const cleanupInput = setupInputHandlers(setInputRequest, addMessage);
15291
15328
  const cleanupCommand = setupCommandHandlers(addMessage);
15292
15329
  const updateStats = () => {
15293
15330
  const s = agent.getState();
@@ -16122,6 +16159,23 @@ var useKeyboardShortcuts = ({
16122
16159
  return { handleCtrlC };
16123
16160
  };
16124
16161
 
16162
+ // src/platform/tui/hooks/useAnimationTick.tsx
16163
+ import { createContext, useContext, useState as useState3, useEffect as useEffect5 } from "react";
16164
+ import { jsx } from "react/jsx-runtime";
16165
+ var ANIM_TICK_MS = 100;
16166
+ var AnimationContext = createContext(0);
16167
+ var AnimationProvider = ({ children }) => {
16168
+ const [tick, setTick] = useState3(0);
16169
+ useEffect5(() => {
16170
+ const timer = setInterval(() => {
16171
+ setTick((t) => t + 1);
16172
+ }, ANIM_TICK_MS);
16173
+ return () => clearInterval(timer);
16174
+ }, []);
16175
+ return /* @__PURE__ */ jsx(AnimationContext.Provider, { value: tick, children });
16176
+ };
16177
+ var useAnimationTick = () => useContext(AnimationContext);
16178
+
16125
16179
  // src/platform/tui/components/MessageList.tsx
16126
16180
  import { memo as memo7, useState as useState4, useCallback as useCallback8, useRef as useRef6 } from "react";
16127
16181
  import { Box as Box8, Text as Text8, useInput as useInput2 } from "ink";
@@ -16129,7 +16183,7 @@ import { Box as Box8, Text as Text8, useInput as useInput2 } from "ink";
16129
16183
  // src/platform/tui/components/messages/ThinkingBlock.tsx
16130
16184
  import { memo } from "react";
16131
16185
  import { Box, Text } from "ink";
16132
- import { jsx, jsxs } from "react/jsx-runtime";
16186
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
16133
16187
  var THINKING_PREVIEW_LINES = 3;
16134
16188
  var ThinkingBlock = memo(({ msg, isExpanded }) => {
16135
16189
  const lines = msg.content.split("\n");
@@ -16139,19 +16193,19 @@ var ThinkingBlock = memo(({ msg, isExpanded }) => {
16139
16193
  const visibleLines = isExpanded ? lines : lines.slice(0, THINKING_PREVIEW_LINES);
16140
16194
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 0, children: [
16141
16195
  /* @__PURE__ */ jsxs(Box, { children: [
16142
- /* @__PURE__ */ jsx(Text, { color: THEME.dimGray, children: " \u25C6 " }),
16143
- /* @__PURE__ */ jsx(Text, { color: THEME.gray, children: "Reasoning" }),
16144
- /* @__PURE__ */ jsx(Text, { color: THEME.dimGray, children: ` (~${estTokens} tokens)` }),
16145
- !isExpanded && hiddenCount > 0 && /* @__PURE__ */ jsx(Text, { color: THEME.dimGray, children: ` [+${hiddenCount} lines \xB7 R]` }),
16146
- isExpanded && /* @__PURE__ */ jsx(Text, { color: THEME.dimGray, children: " [R to collapse]" })
16196
+ /* @__PURE__ */ jsx2(Text, { color: THEME.dimGray, children: " \u25C6 " }),
16197
+ /* @__PURE__ */ jsx2(Text, { color: THEME.gray, children: "Reasoning" }),
16198
+ /* @__PURE__ */ jsx2(Text, { color: THEME.dimGray, children: ` (~${estTokens} tokens)` }),
16199
+ !isExpanded && hiddenCount > 0 && /* @__PURE__ */ jsx2(Text, { color: THEME.dimGray, children: ` [+${hiddenCount} lines \xB7 R]` }),
16200
+ isExpanded && /* @__PURE__ */ jsx2(Text, { color: THEME.dimGray, children: " [R to collapse]" })
16147
16201
  ] }),
16148
16202
  visibleLines.map((line, i) => /* @__PURE__ */ jsxs(Box, { children: [
16149
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: " \u2502 " }),
16150
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: line })
16203
+ /* @__PURE__ */ jsx2(Text, { dimColor: true, children: " \u2502 " }),
16204
+ /* @__PURE__ */ jsx2(Text, { dimColor: true, children: line })
16151
16205
  ] }, i)),
16152
16206
  !isExpanded && hiddenCount > 0 && /* @__PURE__ */ jsxs(Box, { children: [
16153
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: " \u2502 " }),
16154
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "..." })
16207
+ /* @__PURE__ */ jsx2(Text, { dimColor: true, children: " \u2502 " }),
16208
+ /* @__PURE__ */ jsx2(Text, { dimColor: true, children: "..." })
16155
16209
  ] })
16156
16210
  ] });
16157
16211
  });
@@ -16198,7 +16252,7 @@ var MESSAGE_STYLES = {
16198
16252
 
16199
16253
  // src/platform/tui/components/inline-status.tsx
16200
16254
  import { Box as Box2, Text as Text2 } from "ink";
16201
- import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
16255
+ import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
16202
16256
  function formatDuration3(ms) {
16203
16257
  const seconds = Math.floor(ms / 1e3);
16204
16258
  if (seconds < 60) return `${seconds}s`;
@@ -16246,13 +16300,13 @@ function ProcessRow({ proc, isCompact }) {
16246
16300
  const purpose = proc.purpose || proc.description || "";
16247
16301
  const truncatedPurpose = isCompact && purpose.length > TUI_DISPLAY_LIMITS.purposeMaxLength ? purpose.slice(0, TUI_DISPLAY_LIMITS.purposeTruncated) + "..." : purpose;
16248
16302
  return /* @__PURE__ */ jsxs2(Box2, { children: [
16249
- /* @__PURE__ */ jsx2(StatusIndicator, { isRunning: proc.isRunning, exitCode: proc.exitCode }),
16303
+ /* @__PURE__ */ jsx3(StatusIndicator, { isRunning: proc.isRunning, exitCode: proc.exitCode }),
16250
16304
  /* @__PURE__ */ jsxs2(Text2, { color: THEME.gray, children: [
16251
16305
  "[",
16252
16306
  proc.id,
16253
16307
  "]"
16254
16308
  ] }),
16255
- /* @__PURE__ */ jsx2(Text2, { children: " " }),
16309
+ /* @__PURE__ */ jsx3(Text2, { children: " " }),
16256
16310
  /* @__PURE__ */ jsxs2(Text2, { color: getRoleColor(proc.role), bold: true, children: [
16257
16311
  proc.role,
16258
16312
  port
@@ -16263,8 +16317,8 @@ function ProcessRow({ proc, isCompact }) {
16263
16317
  ")"
16264
16318
  ] }),
16265
16319
  truncatedPurpose && /* @__PURE__ */ jsxs2(Fragment, { children: [
16266
- /* @__PURE__ */ jsx2(Text2, { color: THEME.gray, children: " - " }),
16267
- /* @__PURE__ */ jsx2(Text2, { color: THEME.gray, children: truncatedPurpose })
16320
+ /* @__PURE__ */ jsx3(Text2, { color: THEME.gray, children: " - " }),
16321
+ /* @__PURE__ */ jsx3(Text2, { color: THEME.gray, children: truncatedPurpose })
16268
16322
  ] })
16269
16323
  ] });
16270
16324
  }
@@ -16275,7 +16329,7 @@ var InlineStatus = ({
16275
16329
  isCompact = true
16276
16330
  }) => {
16277
16331
  if (processes.length === 0 && zombies.length === 0) {
16278
- return /* @__PURE__ */ jsx2(Box2, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsx2(Text2, { color: THEME.gray, children: "\u2022 No active background processes" }) });
16332
+ return /* @__PURE__ */ jsx3(Box2, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsx3(Text2, { color: THEME.gray, children: "\u2022 No active background processes" }) });
16279
16333
  }
16280
16334
  const running = processes.filter((p) => p.isRunning);
16281
16335
  const stopped = processes.filter((p) => !p.isRunning);
@@ -16292,7 +16346,7 @@ var InlineStatus = ({
16292
16346
  running.length,
16293
16347
  ")"
16294
16348
  ] }),
16295
- running.map((proc) => /* @__PURE__ */ jsx2(ProcessRow, { proc, isCompact }, proc.id))
16349
+ running.map((proc) => /* @__PURE__ */ jsx3(ProcessRow, { proc, isCompact }, proc.id))
16296
16350
  ] }),
16297
16351
  stopped.length > 0 && !isCompact && /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", marginTop: running.length > 0 ? 1 : 0, children: [
16298
16352
  /* @__PURE__ */ jsxs2(Text2, { color: THEME.gray, children: [
@@ -16301,7 +16355,7 @@ var InlineStatus = ({
16301
16355
  stopped.length,
16302
16356
  ")"
16303
16357
  ] }),
16304
- stopped.slice(0, TUI_DISPLAY_LIMITS.maxStoppedProcesses).map((proc) => /* @__PURE__ */ jsx2(ProcessRow, { proc, isCompact }, proc.id)),
16358
+ stopped.slice(0, TUI_DISPLAY_LIMITS.maxStoppedProcesses).map((proc) => /* @__PURE__ */ jsx3(ProcessRow, { proc, isCompact }, proc.id)),
16305
16359
  stopped.length > TUI_DISPLAY_LIMITS.maxStoppedProcesses && /* @__PURE__ */ jsxs2(Text2, { color: THEME.gray, children: [
16306
16360
  " ... and ",
16307
16361
  stopped.length - TUI_DISPLAY_LIMITS.maxStoppedProcesses,
@@ -16331,11 +16385,11 @@ var InlineStatus = ({
16331
16385
  " orphaned children"
16332
16386
  ] })
16333
16387
  ] }, z.processId)),
16334
- /* @__PURE__ */ jsx2(Text2, { color: THEME.gray, children: " Run /cleanup to terminate" })
16388
+ /* @__PURE__ */ jsx3(Text2, { color: THEME.gray, children: " Run /cleanup to terminate" })
16335
16389
  ] }),
16336
16390
  /* @__PURE__ */ jsxs2(Box2, { marginTop: running.length > 0 ? 1 : 0, children: [
16337
- /* @__PURE__ */ jsx2(Text2, { color: THEME.gray, children: "Health: " }),
16338
- /* @__PURE__ */ jsx2(Text2, { color: healthColor, bold: true, children: health.toUpperCase() })
16391
+ /* @__PURE__ */ jsx3(Text2, { color: THEME.gray, children: "Health: " }),
16392
+ /* @__PURE__ */ jsx3(Text2, { color: healthColor, bold: true, children: health.toUpperCase() })
16339
16393
  ] })
16340
16394
  ] });
16341
16395
  };
@@ -16343,7 +16397,7 @@ var InlineStatus = ({
16343
16397
  // src/platform/tui/components/ToolCard.tsx
16344
16398
  import { memo as memo2 } from "react";
16345
16399
  import { Box as Box3, Text as Text3 } from "ink";
16346
- import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
16400
+ import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
16347
16401
  var ARGS_MAX = 72;
16348
16402
  function truncate(s, max) {
16349
16403
  return s.length > max ? s.slice(0, max - 1) + "\u2026" : s;
@@ -16388,12 +16442,12 @@ function parseToolContent(content) {
16388
16442
  var ToolCard = memo2(({ content }) => {
16389
16443
  const { name, args } = parseToolContent(content);
16390
16444
  return /* @__PURE__ */ jsxs3(Box3, { children: [
16391
- /* @__PURE__ */ jsx3(Text3, { color: THEME.primary, children: " \u2295 " }),
16392
- /* @__PURE__ */ jsx3(Text3, { color: THEME.white, bold: true, children: name }),
16445
+ /* @__PURE__ */ jsx4(Text3, { color: THEME.primary, children: " \u2295 " }),
16446
+ /* @__PURE__ */ jsx4(Text3, { color: THEME.white, bold: true, children: name }),
16393
16447
  args && /* @__PURE__ */ jsxs3(Fragment2, { children: [
16394
- /* @__PURE__ */ jsx3(Text3, { color: THEME.dimGray, children: "(" }),
16395
- /* @__PURE__ */ jsx3(Text3, { color: THEME.gray, children: args }),
16396
- /* @__PURE__ */ jsx3(Text3, { color: THEME.dimGray, children: ")" })
16448
+ /* @__PURE__ */ jsx4(Text3, { color: THEME.dimGray, children: "(" }),
16449
+ /* @__PURE__ */ jsx4(Text3, { color: THEME.gray, children: args }),
16450
+ /* @__PURE__ */ jsx4(Text3, { color: THEME.dimGray, children: ")" })
16397
16451
  ] })
16398
16452
  ] });
16399
16453
  });
@@ -16401,7 +16455,7 @@ var ToolCard = memo2(({ content }) => {
16401
16455
  // src/platform/tui/components/MarkdownText.tsx
16402
16456
  import { memo as memo3 } from "react";
16403
16457
  import { Box as Box4, Text as Text4 } from "ink";
16404
- import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
16458
+ import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
16405
16459
  function tokenizeLine(line) {
16406
16460
  const tokens = [];
16407
16461
  let i = 0;
@@ -16425,14 +16479,14 @@ function tokenizeLine(line) {
16425
16479
  }
16426
16480
  return tokens;
16427
16481
  }
16428
- var InlineContent = ({ tokens }) => /* @__PURE__ */ jsx4(Fragment3, { children: tokens.map((tok, i) => {
16482
+ var InlineContent = ({ tokens }) => /* @__PURE__ */ jsx5(Fragment3, { children: tokens.map((tok, i) => {
16429
16483
  if (tok.type === "bold") {
16430
- return /* @__PURE__ */ jsx4(Text4, { bold: true, color: THEME.white, children: tok.value }, i);
16484
+ return /* @__PURE__ */ jsx5(Text4, { bold: true, color: THEME.white, children: tok.value }, i);
16431
16485
  }
16432
16486
  if (tok.type === "code") {
16433
- return /* @__PURE__ */ jsx4(Text4, { color: THEME.cyan, children: `\`${tok.value}\`` }, i);
16487
+ return /* @__PURE__ */ jsx5(Text4, { color: THEME.cyan, children: `\`${tok.value}\`` }, i);
16434
16488
  }
16435
- return /* @__PURE__ */ jsx4(Text4, { color: THEME.white, children: tok.value }, i);
16489
+ return /* @__PURE__ */ jsx5(Text4, { color: THEME.white, children: tok.value }, i);
16436
16490
  }) });
16437
16491
  function parseBlocks(lines) {
16438
16492
  const blocks = [];
@@ -16482,12 +16536,12 @@ function parseBlocks(lines) {
16482
16536
  }
16483
16537
  var BlockRenderer = ({ block, blockIdx }) => {
16484
16538
  if (block.type === "blank") {
16485
- return /* @__PURE__ */ jsx4(Text4, { children: " " }, blockIdx);
16539
+ return /* @__PURE__ */ jsx5(Text4, { children: " " }, blockIdx);
16486
16540
  }
16487
16541
  if (block.type === "heading") {
16488
16542
  const prefixes = { 1: "\u25B8 ", 2: " \u25B9 ", 3: " \xB7 " };
16489
16543
  const colors = { 1: THEME.primary, 2: THEME.cyan, 3: THEME.white };
16490
- return /* @__PURE__ */ jsx4(Box4, { children: /* @__PURE__ */ jsxs4(Text4, { color: colors[block.level], bold: true, children: [
16544
+ return /* @__PURE__ */ jsx5(Box4, { children: /* @__PURE__ */ jsxs4(Text4, { color: colors[block.level], bold: true, children: [
16491
16545
  prefixes[block.level],
16492
16546
  block.content
16493
16547
  ] }) }, blockIdx);
@@ -16499,7 +16553,7 @@ var BlockRenderer = ({ block, blockIdx }) => {
16499
16553
  bullet,
16500
16554
  " "
16501
16555
  ] }),
16502
- /* @__PURE__ */ jsx4(InlineContent, { tokens: tokenizeLine(block.content) })
16556
+ /* @__PURE__ */ jsx5(InlineContent, { tokens: tokenizeLine(block.content) })
16503
16557
  ] }, blockIdx);
16504
16558
  }
16505
16559
  if (block.type === "codeBlock") {
@@ -16512,19 +16566,19 @@ var BlockRenderer = ({ block, blockIdx }) => {
16512
16566
  paddingX: 1,
16513
16567
  marginY: 0,
16514
16568
  children: [
16515
- block.lang && /* @__PURE__ */ jsx4(Text4, { color: THEME.dimGray, children: block.lang }),
16516
- block.lines.map((l, li) => /* @__PURE__ */ jsx4(Text4, { color: THEME.cyan, children: l }, li))
16569
+ block.lang && /* @__PURE__ */ jsx5(Text4, { color: THEME.dimGray, children: block.lang }),
16570
+ block.lines.map((l, li) => /* @__PURE__ */ jsx5(Text4, { color: THEME.cyan, children: l }, li))
16517
16571
  ]
16518
16572
  },
16519
16573
  blockIdx
16520
16574
  );
16521
16575
  }
16522
- return /* @__PURE__ */ jsx4(Box4, { children: /* @__PURE__ */ jsx4(InlineContent, { tokens: tokenizeLine(block.content) }) }, blockIdx);
16576
+ return /* @__PURE__ */ jsx5(Box4, { children: /* @__PURE__ */ jsx5(InlineContent, { tokens: tokenizeLine(block.content) }) }, blockIdx);
16523
16577
  };
16524
16578
  var MarkdownText = memo3(({ content }) => {
16525
16579
  const lines = content.split("\n");
16526
16580
  const blocks = parseBlocks(lines);
16527
- return /* @__PURE__ */ jsx4(Box4, { flexDirection: "column", children: blocks.map((block, i) => /* @__PURE__ */ jsx4(BlockRenderer, { block, blockIdx: i }, i)) });
16581
+ return /* @__PURE__ */ jsx5(Box4, { flexDirection: "column", children: blocks.map((block, i) => /* @__PURE__ */ jsx5(BlockRenderer, { block, blockIdx: i }, i)) });
16528
16582
  });
16529
16583
 
16530
16584
  // src/platform/tui/components/messages/parseStatusContent.ts
@@ -16572,12 +16626,12 @@ function computeResultDisplay(content, isExpanded) {
16572
16626
  }
16573
16627
 
16574
16628
  // src/platform/tui/components/messages/MessageRow.tsx
16575
- import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
16629
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
16576
16630
  var MessageRow = memo4(({ msg, isExpanded }) => {
16577
16631
  if (msg.type === "status") {
16578
16632
  const statusData = parseStatusContent(msg.content);
16579
16633
  if (statusData) {
16580
- return /* @__PURE__ */ jsx5(Box5, { flexDirection: "column", children: /* @__PURE__ */ jsx5(
16634
+ return /* @__PURE__ */ jsx6(Box5, { flexDirection: "column", children: /* @__PURE__ */ jsx6(
16581
16635
  InlineStatus,
16582
16636
  {
16583
16637
  processes: statusData.processes,
@@ -16587,15 +16641,15 @@ var MessageRow = memo4(({ msg, isExpanded }) => {
16587
16641
  ) }, msg.id);
16588
16642
  }
16589
16643
  return /* @__PURE__ */ jsxs5(Box5, { children: [
16590
- /* @__PURE__ */ jsx5(Text5, { dimColor: true, color: THEME.dimGray, children: " \xB7 " }),
16591
- /* @__PURE__ */ jsx5(Text5, { dimColor: true, color: THEME.gray, children: msg.content })
16644
+ /* @__PURE__ */ jsx6(Text5, { dimColor: true, color: THEME.dimGray, children: " \xB7 " }),
16645
+ /* @__PURE__ */ jsx6(Text5, { dimColor: true, color: THEME.gray, children: msg.content })
16592
16646
  ] }, msg.id);
16593
16647
  }
16594
16648
  if (msg.type === "thinking") {
16595
- return /* @__PURE__ */ jsx5(ThinkingBlock, { msg, isExpanded });
16649
+ return /* @__PURE__ */ jsx6(ThinkingBlock, { msg, isExpanded });
16596
16650
  }
16597
16651
  if (msg.type === "tool") {
16598
- return /* @__PURE__ */ jsx5(Box5, { children: /* @__PURE__ */ jsx5(ToolCard, { content: msg.content }) }, msg.id);
16652
+ return /* @__PURE__ */ jsx6(Box5, { children: /* @__PURE__ */ jsx6(ToolCard, { content: msg.content }) }, msg.id);
16599
16653
  }
16600
16654
  if (msg.type === "result") {
16601
16655
  const kind = classifyResult(msg.content);
@@ -16605,19 +16659,19 @@ var MessageRow = memo4(({ msg, isExpanded }) => {
16605
16659
  const isFailure = kind === "failure";
16606
16660
  return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
16607
16661
  /* @__PURE__ */ jsxs5(Box5, { children: [
16608
- /* @__PURE__ */ jsx5(Text5, { color: THEME.dimGray, children: " \u2514 " }),
16609
- /* @__PURE__ */ jsx5(Text5, { color, children: firstLine }),
16610
- hasMore && /* @__PURE__ */ jsx5(Text5, { dimColor: true, color: THEME.dimGray, children: ` [+${hiddenCount - RESULT_PREVIEW_LINES} \xB7 T]` }),
16611
- effectiveExpanded && hiddenCount > RESULT_PREVIEW_LINES && !isFailure && /* @__PURE__ */ jsx5(Text5, { dimColor: true, color: THEME.dimGray, children: " [T \u2193]" })
16662
+ /* @__PURE__ */ jsx6(Text5, { color: THEME.dimGray, children: " \u2514 " }),
16663
+ /* @__PURE__ */ jsx6(Text5, { color, children: firstLine }),
16664
+ hasMore && /* @__PURE__ */ jsx6(Text5, { dimColor: true, color: THEME.dimGray, children: ` [+${hiddenCount - RESULT_PREVIEW_LINES} \xB7 T]` }),
16665
+ effectiveExpanded && hiddenCount > RESULT_PREVIEW_LINES && !isFailure && /* @__PURE__ */ jsx6(Text5, { dimColor: true, color: THEME.dimGray, children: " [T \u2193]" })
16612
16666
  ] }),
16613
16667
  visibleRest.map((line, i) => /* @__PURE__ */ jsxs5(Box5, { children: [
16614
- /* @__PURE__ */ jsx5(Text5, { color: THEME.dimGray, children: " " }),
16615
- /* @__PURE__ */ jsx5(Text5, { dimColor: true, color: THEME.gray, children: line })
16668
+ /* @__PURE__ */ jsx6(Text5, { color: THEME.dimGray, children: " " }),
16669
+ /* @__PURE__ */ jsx6(Text5, { dimColor: true, color: THEME.gray, children: line })
16616
16670
  ] }, i))
16617
16671
  ] }, msg.id);
16618
16672
  }
16619
16673
  if (msg.type === "ai" || msg.type === "assistant") {
16620
- return /* @__PURE__ */ jsx5(Box5, { flexDirection: "column", marginBottom: 0, children: /* @__PURE__ */ jsx5(MarkdownText, { content: msg.content }) }, msg.id);
16674
+ return /* @__PURE__ */ jsx6(Box5, { flexDirection: "column", marginBottom: 0, children: /* @__PURE__ */ jsx6(MarkdownText, { content: msg.content }) }, msg.id);
16621
16675
  }
16622
16676
  if (msg.type === "error") {
16623
16677
  const eLines = msg.content.split("\n");
@@ -16625,32 +16679,32 @@ var MessageRow = memo4(({ msg, isExpanded }) => {
16625
16679
  const eHidden = eLines.length - 1;
16626
16680
  return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
16627
16681
  /* @__PURE__ */ jsxs5(Box5, { children: [
16628
- /* @__PURE__ */ jsx5(Text5, { color: THEME.red, children: " \u2717 " }),
16629
- /* @__PURE__ */ jsx5(Text5, { color: THEME.red, children: eFirst }),
16630
- !isExpanded && eHidden > 0 && /* @__PURE__ */ jsx5(Text5, { dimColor: true, color: THEME.dimGray, children: ` [+${eHidden} \xB7 E]` }),
16631
- isExpanded && eHidden > 0 && /* @__PURE__ */ jsx5(Text5, { dimColor: true, color: THEME.dimGray, children: " [E \u2191]" })
16682
+ /* @__PURE__ */ jsx6(Text5, { color: THEME.red, children: " \u2717 " }),
16683
+ /* @__PURE__ */ jsx6(Text5, { color: THEME.red, children: eFirst }),
16684
+ !isExpanded && eHidden > 0 && /* @__PURE__ */ jsx6(Text5, { dimColor: true, color: THEME.dimGray, children: ` [+${eHidden} \xB7 E]` }),
16685
+ isExpanded && eHidden > 0 && /* @__PURE__ */ jsx6(Text5, { dimColor: true, color: THEME.dimGray, children: " [E \u2191]" })
16632
16686
  ] }),
16633
16687
  isExpanded && eLines.slice(1).map((line, i) => /* @__PURE__ */ jsxs5(Box5, { children: [
16634
- /* @__PURE__ */ jsx5(Text5, { color: THEME.dimGray, children: " " }),
16635
- /* @__PURE__ */ jsx5(Text5, { dimColor: true, color: THEME.red, children: line })
16688
+ /* @__PURE__ */ jsx6(Text5, { color: THEME.dimGray, children: " " }),
16689
+ /* @__PURE__ */ jsx6(Text5, { dimColor: true, color: THEME.red, children: line })
16636
16690
  ] }, i))
16637
16691
  ] }, msg.id);
16638
16692
  }
16639
16693
  if (msg.type === "user") {
16640
16694
  return /* @__PURE__ */ jsxs5(Box5, { children: [
16641
- /* @__PURE__ */ jsx5(Text5, { color: THEME.primary, children: "\u276F " }),
16642
- /* @__PURE__ */ jsx5(Text5, { color: THEME.white, bold: true, children: msg.content })
16695
+ /* @__PURE__ */ jsx6(Text5, { color: THEME.primary, children: "\u276F " }),
16696
+ /* @__PURE__ */ jsx6(Text5, { color: THEME.white, bold: true, children: msg.content })
16643
16697
  ] }, msg.id);
16644
16698
  }
16645
16699
  if (msg.type === "system") {
16646
16700
  return /* @__PURE__ */ jsxs5(Box5, { children: [
16647
- /* @__PURE__ */ jsx5(Text5, { dimColor: true, color: THEME.dimGray, children: " \xB7 " }),
16648
- /* @__PURE__ */ jsx5(Text5, { dimColor: true, color: THEME.gray, children: msg.content })
16701
+ /* @__PURE__ */ jsx6(Text5, { dimColor: true, color: THEME.dimGray, children: " \xB7 " }),
16702
+ /* @__PURE__ */ jsx6(Text5, { dimColor: true, color: THEME.gray, children: msg.content })
16649
16703
  ] }, msg.id);
16650
16704
  }
16651
16705
  return /* @__PURE__ */ jsxs5(Box5, { children: [
16652
- /* @__PURE__ */ jsx5(Text5, { dimColor: true, color: THEME.dimGray, children: " \xB7 " }),
16653
- /* @__PURE__ */ jsx5(Text5, { color: MESSAGE_STYLES.colors[msg.type] ?? THEME.gray, children: msg.content })
16706
+ /* @__PURE__ */ jsx6(Text5, { dimColor: true, color: THEME.dimGray, children: " \xB7 " }),
16707
+ /* @__PURE__ */ jsx6(Text5, { color: MESSAGE_STYLES.colors[msg.type] ?? THEME.gray, children: msg.content })
16654
16708
  ] }, msg.id);
16655
16709
  });
16656
16710
 
@@ -16659,60 +16713,38 @@ import { memo as memo6 } from "react";
16659
16713
  import { Box as Box7, Text as Text7 } from "ink";
16660
16714
 
16661
16715
  // src/platform/tui/components/ShimmerBanner.tsx
16662
- import { useState as useState3, useEffect as useEffect5, memo as memo5 } from "react";
16716
+ import { memo as memo5 } from "react";
16663
16717
  import { Box as Box6, Text as Text6 } from "ink";
16664
- import { jsx as jsx6 } from "react/jsx-runtime";
16665
- var FRAME_INTERVAL = 60;
16666
- var WAVE_SPEED = 0.22;
16667
- var CHAR_GAP = 0.18;
16668
- var ROW_GAP = 1.6;
16669
- function waveColor(sin) {
16670
- const t = (sin + 1) / 2;
16671
- const r = Math.round(36 + t * (255 - 36));
16672
- const g = Math.round(150 + t * (255 - 150));
16673
- const b = Math.round(237 + t * (255 - 237));
16674
- return `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`;
16675
- }
16718
+ import { jsx as jsx7 } from "react/jsx-runtime";
16676
16719
  var ShimmerBanner = memo5(({ banner }) => {
16677
- const [tick, setTick] = useState3(0);
16678
- useEffect5(() => {
16679
- const timer = setInterval(() => setTick((t) => t + 1), FRAME_INTERVAL);
16680
- return () => clearInterval(timer);
16681
- }, []);
16682
- const globalPhase = tick * WAVE_SPEED;
16683
16720
  const lines = banner.split("\n").filter((l) => l.length > 0);
16684
- return /* @__PURE__ */ jsx6(Box6, { flexDirection: "column", children: lines.map((line, row) => /* @__PURE__ */ jsx6(Text6, { children: Array.from(line).map((char, col) => {
16685
- const phase = globalPhase - col * CHAR_GAP - row * ROW_GAP;
16686
- const sin = Math.sin(phase);
16687
- const color = char.trim() === "" ? HEX.primary : waveColor(sin);
16688
- return /* @__PURE__ */ jsx6(Text6, { color, children: char }, col);
16689
- }) }, row)) });
16721
+ return /* @__PURE__ */ jsx7(Box6, { flexDirection: "column", children: lines.map((line, row) => /* @__PURE__ */ jsx7(Text6, { color: HEX.primary, children: line }, row)) });
16690
16722
  });
16691
16723
 
16692
16724
  // src/platform/tui/components/messages/EmptyState.tsx
16693
- import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
16725
+ import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
16694
16726
  var EmptyState = memo6(({ modelName, autoApproveMode, version }) => {
16695
16727
  const autoLabel = autoApproveMode ? "ON" : "OFF";
16696
16728
  const autoColor = autoApproveMode ? THEME.primary : THEME.gray;
16697
16729
  return /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", paddingX: 1, paddingY: 1, children: [
16698
- /* @__PURE__ */ jsx7(ShimmerBanner, { banner: ASCII_BANNER }),
16699
- /* @__PURE__ */ jsx7(Text7, { children: " " }),
16730
+ /* @__PURE__ */ jsx8(ShimmerBanner, { banner: ASCII_BANNER }),
16731
+ /* @__PURE__ */ jsx8(Text7, { children: " " }),
16700
16732
  /* @__PURE__ */ jsxs6(Box7, { gap: 2, children: [
16701
- /* @__PURE__ */ jsx7(Text7, { color: THEME.primary, bold: true, children: "\u25C8 Pentesting" }),
16702
- version && /* @__PURE__ */ jsx7(Text7, { color: THEME.dimGray, children: `v${version}` }),
16733
+ /* @__PURE__ */ jsx8(Text7, { color: THEME.primary, bold: true, children: "\u25C8 Pentesting" }),
16734
+ version && /* @__PURE__ */ jsx8(Text7, { color: THEME.dimGray, children: `v${version}` }),
16703
16735
  modelName && /* @__PURE__ */ jsxs6(Text7, { color: THEME.dimGray, children: [
16704
16736
  "\xB7",
16705
16737
  " ",
16706
- /* @__PURE__ */ jsx7(Text7, { color: THEME.gray, children: modelName })
16738
+ /* @__PURE__ */ jsx8(Text7, { color: THEME.gray, children: modelName })
16707
16739
  ] }),
16708
16740
  /* @__PURE__ */ jsxs6(Text7, { color: THEME.dimGray, children: [
16709
16741
  "\xB7",
16710
16742
  " Auto: ",
16711
- /* @__PURE__ */ jsx7(Text7, { color: autoColor, children: autoLabel })
16743
+ /* @__PURE__ */ jsx8(Text7, { color: autoColor, children: autoLabel })
16712
16744
  ] })
16713
16745
  ] }),
16714
- /* @__PURE__ */ jsx7(Text7, { children: " " }),
16715
- /* @__PURE__ */ jsx7(Text7, { color: THEME.gray, children: " Get started:" }),
16746
+ /* @__PURE__ */ jsx8(Text7, { children: " " }),
16747
+ /* @__PURE__ */ jsx8(Text7, { color: THEME.gray, children: " Get started:" }),
16716
16748
  /* @__PURE__ */ jsxs6(Text7, { color: THEME.gray, children: [
16717
16749
  " ",
16718
16750
  " ",
@@ -16725,17 +16757,17 @@ var EmptyState = memo6(({ modelName, autoApproveMode, version }) => {
16725
16757
  /* @__PURE__ */ jsxs6(Text7, { color: THEME.gray, children: [
16726
16758
  " ",
16727
16759
  " ",
16728
- /* @__PURE__ */ jsx7(Text7, { color: THEME.white, children: "/start" }),
16760
+ /* @__PURE__ */ jsx8(Text7, { color: THEME.white, children: "/start" }),
16729
16761
  " \u2014 Begin autonomous pentest"
16730
16762
  ] }),
16731
16763
  /* @__PURE__ */ jsxs6(Text7, { color: THEME.gray, children: [
16732
16764
  " ",
16733
16765
  " ",
16734
- /* @__PURE__ */ jsx7(Text7, { color: THEME.white, children: "/help" }),
16766
+ /* @__PURE__ */ jsx8(Text7, { color: THEME.white, children: "/help" }),
16735
16767
  " \u2014 Show all commands"
16736
16768
  ] }),
16737
- /* @__PURE__ */ jsx7(Text7, { children: " " }),
16738
- /* @__PURE__ */ jsx7(Text7, { color: THEME.dimGray, children: " Or just type a task and press Enter." })
16769
+ /* @__PURE__ */ jsx8(Text7, { children: " " }),
16770
+ /* @__PURE__ */ jsx8(Text7, { color: THEME.dimGray, children: " Or just type a task and press Enter." })
16739
16771
  ] });
16740
16772
  });
16741
16773
 
@@ -16750,7 +16782,7 @@ function computeSlidingWindow(messages, scrollOffset) {
16750
16782
  }
16751
16783
 
16752
16784
  // src/platform/tui/components/MessageList.tsx
16753
- import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
16785
+ import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
16754
16786
  var MessageList = memo7(({ messages, isModalOpen, modelName, autoApproveMode, version, scrollOffset = 0 }) => {
16755
16787
  const [expandedIds, setExpandedIds] = useState4(/* @__PURE__ */ new Set());
16756
16788
  const messagesRef = useRef6(messages);
@@ -16806,7 +16838,7 @@ var MessageList = memo7(({ messages, isModalOpen, modelName, autoApproveMode, ve
16806
16838
  }
16807
16839
  }, []));
16808
16840
  if (messages.length === 0) {
16809
- return /* @__PURE__ */ jsx8(
16841
+ return /* @__PURE__ */ jsx9(
16810
16842
  EmptyState,
16811
16843
  {
16812
16844
  modelName,
@@ -16817,8 +16849,8 @@ var MessageList = memo7(({ messages, isModalOpen, modelName, autoApproveMode, ve
16817
16849
  }
16818
16850
  const { visibleMessages, hiddenAbove, clampedOffset } = computeSlidingWindow(messages, scrollOffset);
16819
16851
  return /* @__PURE__ */ jsxs7(Box8, { flexDirection: "column", children: [
16820
- clampedOffset > 0 && /* @__PURE__ */ jsx8(Box8, { paddingX: 1, children: /* @__PURE__ */ jsx8(Text8, { dimColor: true, color: THEME.dimGray, children: `\u2191 ${hiddenAbove} message${hiddenAbove !== 1 ? "s" : ""} above \xB7 PgDn to scroll down` }) }),
16821
- visibleMessages.map((msg) => /* @__PURE__ */ jsx8(
16852
+ clampedOffset > 0 && /* @__PURE__ */ jsx9(Box8, { paddingX: 1, children: /* @__PURE__ */ jsx9(Text8, { dimColor: true, color: THEME.dimGray, children: `\u2191 ${hiddenAbove} message${hiddenAbove !== 1 ? "s" : ""} above \xB7 PgDn to scroll down` }) }),
16853
+ visibleMessages.map((msg) => /* @__PURE__ */ jsx9(
16822
16854
  MessageRow,
16823
16855
  {
16824
16856
  msg,
@@ -16861,10 +16893,10 @@ var useStatusTimer = (currentStatus, isProcessing) => {
16861
16893
  // src/platform/tui/components/status/RetryView.tsx
16862
16894
  import { Box as Box9, Text as Text10 } from "ink";
16863
16895
 
16864
- // src/platform/tui/components/MusicSpinner.tsx
16865
- import { useState as useState6, useEffect as useEffect7, memo as memo8 } from "react";
16896
+ // src/platform/tui/components/StarSpinner.tsx
16897
+ import { memo as memo8 } from "react";
16866
16898
  import { Text as Text9 } from "ink";
16867
- import { jsx as jsx9 } from "react/jsx-runtime";
16899
+ import { jsx as jsx10 } from "react/jsx-runtime";
16868
16900
  var FRAMES = [
16869
16901
  "\xB7",
16870
16902
  "\u2726",
@@ -16881,27 +16913,21 @@ var FRAMES = [
16881
16913
  "\u2727",
16882
16914
  "\u2726"
16883
16915
  ];
16884
- var INTERVAL = 150;
16885
- var MusicSpinner = memo8(({ color }) => {
16886
- const [index, setIndex] = useState6(0);
16887
- useEffect7(() => {
16888
- const timer = setInterval(() => {
16889
- setIndex((i) => (i + 1) % FRAMES.length);
16890
- }, INTERVAL);
16891
- return () => clearInterval(timer);
16892
- }, []);
16893
- return /* @__PURE__ */ jsx9(Text9, { color: color || "yellow", children: FRAMES[index] });
16916
+ var StarSpinner = memo8(({ color }) => {
16917
+ const tick = useAnimationTick();
16918
+ const index = tick % FRAMES.length;
16919
+ return /* @__PURE__ */ jsx10(Text9, { color: color || "yellow", children: FRAMES[index] });
16894
16920
  });
16895
16921
 
16896
16922
  // src/platform/tui/components/status/RetryView.tsx
16897
- import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
16923
+ import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
16898
16924
  var RetryView = ({ retryState }) => {
16899
16925
  const truncateError = (err) => {
16900
16926
  return err.length > DISPLAY_LIMITS.RETRY_ERROR_PREVIEW ? err.substring(0, DISPLAY_LIMITS.RETRY_ERROR_TRUNCATED) + "..." : err;
16901
16927
  };
16902
16928
  return /* @__PURE__ */ jsxs8(Box9, { flexDirection: "column", height: 2, children: [
16903
16929
  /* @__PURE__ */ jsxs8(Box9, { children: [
16904
- /* @__PURE__ */ jsx10(Text10, { color: THEME.yellow, wrap: "truncate", children: /* @__PURE__ */ jsx10(MusicSpinner, { color: THEME.yellow }) }),
16930
+ /* @__PURE__ */ jsx11(Text10, { color: THEME.yellow, wrap: "truncate", children: /* @__PURE__ */ jsx11(StarSpinner, { color: THEME.yellow }) }),
16905
16931
  /* @__PURE__ */ jsxs8(Text10, { color: THEME.yellow, bold: true, wrap: "truncate", children: [
16906
16932
  " \u29F3 Retry #",
16907
16933
  retryState.attempt,
@@ -16914,7 +16940,7 @@ var RetryView = ({ retryState }) => {
16914
16940
  "s"
16915
16941
  ] })
16916
16942
  ] }),
16917
- /* @__PURE__ */ jsx10(Box9, { children: /* @__PURE__ */ jsxs8(Text10, { color: THEME.gray, wrap: "truncate", children: [
16943
+ /* @__PURE__ */ jsx11(Box9, { children: /* @__PURE__ */ jsxs8(Text10, { color: THEME.gray, wrap: "truncate", children: [
16918
16944
  " ",
16919
16945
  truncateError(retryState.error)
16920
16946
  ] }) })
@@ -16925,11 +16951,10 @@ var RetryView = ({ retryState }) => {
16925
16951
  import { Box as Box10, Text as Text12 } from "ink";
16926
16952
 
16927
16953
  // src/platform/tui/components/ShimmerText.tsx
16928
- import { useState as useState7, useEffect as useEffect8, memo as memo9 } from "react";
16954
+ import { memo as memo9 } from "react";
16929
16955
  import { Text as Text11 } from "ink";
16930
- import { jsx as jsx11 } from "react/jsx-runtime";
16931
- var FRAME_INTERVAL2 = 120;
16932
- var WAVE_SPEED2 = 0.25;
16956
+ import { jsx as jsx12 } from "react/jsx-runtime";
16957
+ var WAVE_SPEED = 0.25 * (120 / ANIM_TICK_MS);
16933
16958
  var CHAR_PHASE_GAP = 0.55;
16934
16959
  function sinToColor(sin) {
16935
16960
  const t = (sin + 1) / 2;
@@ -16938,24 +16963,18 @@ function sinToColor(sin) {
16938
16963
  return `#${hex}${hex}${hex}`;
16939
16964
  }
16940
16965
  var ShimmerText = memo9(({ children, bold, phase = 0 }) => {
16941
- const [tick, setTick] = useState7(0);
16942
- useEffect8(() => {
16943
- const timer = setInterval(() => {
16944
- setTick((t) => t + 1);
16945
- }, FRAME_INTERVAL2);
16946
- return () => clearInterval(timer);
16947
- }, []);
16948
- const globalPhase = tick * WAVE_SPEED2 + phase;
16949
- return /* @__PURE__ */ jsx11(Text11, { bold, children: Array.from(children).map((char, i) => {
16966
+ const tick = useAnimationTick();
16967
+ const globalPhase = tick * WAVE_SPEED + phase;
16968
+ return /* @__PURE__ */ jsx12(Text11, { bold, children: Array.from(children).map((char, i) => {
16950
16969
  const charPhase = globalPhase - i * CHAR_PHASE_GAP;
16951
16970
  const sin = Math.sin(charPhase);
16952
16971
  const color = sinToColor(sin);
16953
- return /* @__PURE__ */ jsx11(Text11, { color, children: char }, i);
16972
+ return /* @__PURE__ */ jsx12(Text11, { color, children: char }, i);
16954
16973
  }) });
16955
16974
  });
16956
16975
 
16957
16976
  // src/platform/tui/components/status/ProcessingView.tsx
16958
- import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
16977
+ import { jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
16959
16978
  var ProcessingView = ({
16960
16979
  statusMain,
16961
16980
  detailText,
@@ -16971,41 +16990,53 @@ var ProcessingView = ({
16971
16990
  return parts.length > 0 ? `(${parts.join(" \xB7 ")})` : "";
16972
16991
  };
16973
16992
  const meta = buildMeta();
16993
+ const parenIdx = statusMain.indexOf("(");
16994
+ const shimmerPart = parenIdx > -1 ? statusMain.slice(0, parenIdx).trimEnd() : statusMain;
16995
+ const staticSuffix = parenIdx > -1 ? " " + statusMain.slice(parenIdx) : "";
16974
16996
  return /* @__PURE__ */ jsxs9(Box10, { flexDirection: "column", height: 2, children: [
16975
16997
  /* @__PURE__ */ jsxs9(Box10, { children: [
16976
- /* @__PURE__ */ jsx12(Text12, { color, wrap: "truncate", children: /* @__PURE__ */ jsx12(MusicSpinner, { color }) }),
16977
- /* @__PURE__ */ jsx12(Text12, { children: " " }),
16978
- /* @__PURE__ */ jsx12(ShimmerText, { bold: true, phase: 0, children: statusMain }),
16998
+ /* @__PURE__ */ jsx13(Text12, { color, wrap: "truncate", children: /* @__PURE__ */ jsx13(StarSpinner, { color }) }),
16999
+ /* @__PURE__ */ jsx13(Text12, { children: " " }),
17000
+ /* @__PURE__ */ jsx13(ShimmerText, { bold: true, phase: 0, children: shimmerPart }),
17001
+ staticSuffix ? /* @__PURE__ */ jsx13(Text12, { color: THEME.dimGray, wrap: "truncate", children: staticSuffix }) : null,
16979
17002
  /* @__PURE__ */ jsxs9(Text12, { color: THEME.dimGray, wrap: "truncate", children: [
16980
17003
  " ",
16981
17004
  meta
16982
17005
  ] })
16983
17006
  ] }),
16984
- /* @__PURE__ */ jsx12(Box10, { children: detailText ? /* @__PURE__ */ jsxs9(Text12, { color: THEME.dimGray, wrap: "truncate", children: [
17007
+ /* @__PURE__ */ jsx13(Box10, { children: detailText ? /* @__PURE__ */ jsxs9(Text12, { color: THEME.dimGray, wrap: "truncate", children: [
16985
17008
  " ",
16986
17009
  detailText
16987
- ] }) : /* @__PURE__ */ jsx12(Text12, { children: " " }) })
17010
+ ] }) : /* @__PURE__ */ jsx13(Text12, { children: " " }) })
16988
17011
  ] });
16989
17012
  };
16990
17013
 
16991
17014
  // src/platform/tui/components/StatusDisplay.tsx
16992
- import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
17015
+ import { jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
16993
17016
  var StatusDisplay = memo10(({
16994
17017
  retryState,
16995
17018
  isProcessing,
16996
17019
  currentStatus,
16997
- currentTokens
17020
+ currentTokens,
17021
+ inputRequest
16998
17022
  }) => {
16999
- const statusElapsed = useStatusTimer(currentStatus, isProcessing);
17023
+ const isWaitingForInput = inputRequest?.status === "active";
17024
+ const statusElapsed = useStatusTimer(currentStatus, isProcessing && !isWaitingForInput);
17000
17025
  if (retryState && retryState.status === "retrying") {
17001
- return /* @__PURE__ */ jsx13(RetryView, { retryState });
17026
+ return /* @__PURE__ */ jsx14(RetryView, { retryState });
17027
+ }
17028
+ if (isProcessing && isWaitingForInput) {
17029
+ return /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", height: 2, children: [
17030
+ /* @__PURE__ */ jsx14(Text13, { children: " " }),
17031
+ /* @__PURE__ */ jsx14(Text13, { children: " " })
17032
+ ] });
17002
17033
  }
17003
17034
  if (isProcessing) {
17004
17035
  const isThinkingStatus = currentStatus.startsWith("Reasoning");
17005
17036
  const statusLines = currentStatus ? currentStatus.split("\n").filter(Boolean) : [];
17006
17037
  const statusMain = statusLines[0] || "Processing...";
17007
17038
  const detailText = isThinkingStatus && statusLines.length > 1 ? statusLines[statusLines.length - 1].slice(0, 120) : "";
17008
- return /* @__PURE__ */ jsx13(
17039
+ return /* @__PURE__ */ jsx14(
17009
17040
  ProcessingView,
17010
17041
  {
17011
17042
  statusMain,
@@ -17017,37 +17048,37 @@ var StatusDisplay = memo10(({
17017
17048
  );
17018
17049
  }
17019
17050
  return /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", height: 2, children: [
17020
- /* @__PURE__ */ jsx13(Text13, { children: " " }),
17021
- /* @__PURE__ */ jsx13(Text13, { children: " " })
17051
+ /* @__PURE__ */ jsx14(Text13, { children: " " }),
17052
+ /* @__PURE__ */ jsx14(Text13, { children: " " })
17022
17053
  ] });
17023
17054
  });
17024
17055
 
17025
17056
  // src/platform/tui/components/ChatInput.tsx
17026
- import { useMemo, useCallback as useCallback9, useRef as useRef8, memo as memo11, useState as useState8, useEffect as useEffect9 } from "react";
17057
+ import { useMemo, useCallback as useCallback9, useRef as useRef8, memo as memo11, useState as useState6, useEffect as useEffect7 } from "react";
17027
17058
  import { Box as Box15, Text as Text17, useInput as useInput3 } from "ink";
17028
17059
 
17029
17060
  // src/platform/tui/components/input/AutocompletePreview.tsx
17030
17061
  import { Box as Box12, Text as Text14 } from "ink";
17031
- import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
17062
+ import { jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
17032
17063
  var AutocompletePreview = ({
17033
17064
  suggestions,
17034
17065
  clampedIdx
17035
17066
  }) => {
17036
- return /* @__PURE__ */ jsx14(Box12, { flexDirection: "column", paddingX: 1, children: suggestions.map((cmd, i) => {
17067
+ return /* @__PURE__ */ jsx15(Box12, { flexDirection: "column", paddingX: 1, children: suggestions.map((cmd, i) => {
17037
17068
  const isSelected = i === clampedIdx;
17038
17069
  const argsText = cmd.args ? ` ${cmd.args}` : "";
17039
17070
  return /* @__PURE__ */ jsxs11(Box12, { children: [
17040
- /* @__PURE__ */ jsx14(Text14, { color: isSelected ? THEME.primary : THEME.dimGray, children: isSelected ? " \u276F " : " " }),
17071
+ /* @__PURE__ */ jsx15(Text14, { color: isSelected ? THEME.primary : THEME.dimGray, children: isSelected ? " \u276F " : " " }),
17041
17072
  /* @__PURE__ */ jsxs11(Text14, { color: isSelected ? THEME.white : THEME.gray, bold: isSelected, children: [
17042
17073
  "/",
17043
17074
  cmd.name
17044
17075
  ] }),
17045
- /* @__PURE__ */ jsx14(Text14, { dimColor: true, color: THEME.gray, children: argsText }),
17076
+ /* @__PURE__ */ jsx15(Text14, { dimColor: true, color: THEME.gray, children: argsText }),
17046
17077
  /* @__PURE__ */ jsxs11(Text14, { dimColor: true, color: THEME.dimGray, children: [
17047
17078
  " \u2014 ",
17048
17079
  cmd.description
17049
17080
  ] }),
17050
- isSelected && cmd.alias && /* @__PURE__ */ jsx14(Text14, { dimColor: true, color: THEME.dimGray, children: ` (/${cmd.alias})` })
17081
+ isSelected && cmd.alias && /* @__PURE__ */ jsx15(Text14, { dimColor: true, color: THEME.dimGray, children: ` (/${cmd.alias})` })
17051
17082
  ] }, cmd.name);
17052
17083
  }) });
17053
17084
  };
@@ -17055,7 +17086,7 @@ var AutocompletePreview = ({
17055
17086
  // src/platform/tui/components/input/SecretInputArea.tsx
17056
17087
  import { Box as Box13, Text as Text15, useStdout } from "ink";
17057
17088
  import TextInput from "ink-text-input";
17058
- import { jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
17089
+ import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
17059
17090
  var OUTER_PADDING = 2;
17060
17091
  var SecretInputArea = ({
17061
17092
  inputRequest,
@@ -17067,34 +17098,28 @@ var SecretInputArea = ({
17067
17098
  const borderWidth = Math.max(10, (stdout?.columns ?? 80) - OUTER_PADDING);
17068
17099
  const borderLine = "\u2501".repeat(borderWidth);
17069
17100
  return /* @__PURE__ */ jsxs12(Box13, { flexDirection: "column", children: [
17070
- /* @__PURE__ */ jsx15(Box13, { children: /* @__PURE__ */ jsx15(Text15, { color: THEME.yellow, children: borderLine }) }),
17071
- /* @__PURE__ */ jsxs12(Box13, { flexDirection: "column", paddingX: 1, children: [
17072
- /* @__PURE__ */ jsxs12(Box13, { children: [
17073
- /* @__PURE__ */ jsx15(Text15, { color: THEME.yellow, bold: true, children: "\u{1F512} " }),
17074
- /* @__PURE__ */ jsx15(Text15, { color: THEME.yellow, children: inputRequest.prompt && inputRequest.prompt.length > 68 ? inputRequest.prompt.slice(0, 68) + "\u2026" : inputRequest.prompt })
17075
- ] }),
17076
- /* @__PURE__ */ jsxs12(Box13, { children: [
17077
- /* @__PURE__ */ jsx15(Text15, { color: THEME.yellow, children: " \u25B8 " }),
17078
- /* @__PURE__ */ jsx15(
17079
- TextInput,
17080
- {
17081
- value: secretInput,
17082
- onChange: setSecretInput,
17083
- onSubmit: onSecretSubmit,
17084
- placeholder: "(type and press Enter)",
17085
- mask: inputRequest.isPassword ? "\u2022" : void 0
17086
- }
17087
- )
17088
- ] })
17101
+ /* @__PURE__ */ jsx16(Box13, { children: /* @__PURE__ */ jsx16(Text15, { color: THEME.yellow, children: borderLine }) }),
17102
+ /* @__PURE__ */ jsxs12(Box13, { paddingX: 1, children: [
17103
+ /* @__PURE__ */ jsx16(Text15, { color: THEME.yellow, bold: true, children: "\u25B8 " }),
17104
+ /* @__PURE__ */ jsx16(
17105
+ TextInput,
17106
+ {
17107
+ value: secretInput,
17108
+ onChange: setSecretInput,
17109
+ onSubmit: onSecretSubmit,
17110
+ placeholder: inputRequest.isPassword ? "(hidden \xB7 press Enter)" : "(type and press Enter)",
17111
+ mask: inputRequest.isPassword ? "\u2022" : void 0
17112
+ }
17113
+ )
17089
17114
  ] }),
17090
- /* @__PURE__ */ jsx15(Box13, { children: /* @__PURE__ */ jsx15(Text15, { color: THEME.yellow, children: borderLine }) })
17115
+ /* @__PURE__ */ jsx16(Box13, { children: /* @__PURE__ */ jsx16(Text15, { color: THEME.yellow, children: borderLine }) })
17091
17116
  ] });
17092
17117
  };
17093
17118
 
17094
17119
  // src/platform/tui/components/input/NormalInputArea.tsx
17095
17120
  import { Box as Box14, Text as Text16, useStdout as useStdout2 } from "ink";
17096
17121
  import TextInput2 from "ink-text-input";
17097
- import { jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
17122
+ import { jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
17098
17123
  var OUTER_PADDING2 = 2;
17099
17124
  var NormalInputArea = ({
17100
17125
  inputKey,
@@ -17107,10 +17132,10 @@ var NormalInputArea = ({
17107
17132
  const borderWidth = Math.max(10, (stdout?.columns ?? 80) - OUTER_PADDING2);
17108
17133
  const borderLine = "\u2500".repeat(borderWidth);
17109
17134
  return /* @__PURE__ */ jsxs13(Box14, { flexDirection: "column", children: [
17110
- /* @__PURE__ */ jsx16(Box14, { children: /* @__PURE__ */ jsx16(Text16, { dimColor: true, color: THEME.dimGray, children: borderLine }) }),
17135
+ /* @__PURE__ */ jsx17(Box14, { children: /* @__PURE__ */ jsx17(Text16, { dimColor: true, color: THEME.dimGray, children: borderLine }) }),
17111
17136
  /* @__PURE__ */ jsxs13(Box14, { paddingX: 1, children: [
17112
- /* @__PURE__ */ jsx16(Text16, { color: THEME.primary, children: "\u276F " }),
17113
- /* @__PURE__ */ jsx16(
17137
+ /* @__PURE__ */ jsx17(Text16, { color: THEME.primary, children: "\u276F " }),
17138
+ /* @__PURE__ */ jsx17(
17114
17139
  TextInput2,
17115
17140
  {
17116
17141
  value,
@@ -17121,12 +17146,12 @@ var NormalInputArea = ({
17121
17146
  inputKey
17122
17147
  )
17123
17148
  ] }),
17124
- /* @__PURE__ */ jsx16(Box14, { children: /* @__PURE__ */ jsx16(Text16, { dimColor: true, color: THEME.dimGray, children: borderLine }) })
17149
+ /* @__PURE__ */ jsx17(Box14, { children: /* @__PURE__ */ jsx17(Text16, { dimColor: true, color: THEME.dimGray, children: borderLine }) })
17125
17150
  ] });
17126
17151
  };
17127
17152
 
17128
17153
  // src/platform/tui/components/ChatInput.tsx
17129
- import { jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
17154
+ import { jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
17130
17155
  var MAX_SUGGESTIONS = 6;
17131
17156
  var ChatInput = memo11(({
17132
17157
  value,
@@ -17146,7 +17171,7 @@ var ChatInput = memo11(({
17146
17171
  return getMatchingCommands(partialCmd).slice(0, MAX_SUGGESTIONS);
17147
17172
  }, [isSlashMode, partialCmd, hasArgs]);
17148
17173
  const showPreview = isSlashMode && !hasArgs && suggestions.length > 0;
17149
- const [selectedIdx, setSelectedIdx] = useState8(0);
17174
+ const [selectedIdx, setSelectedIdx] = useState6(0);
17150
17175
  const clampedIdx = Math.min(selectedIdx, Math.max(0, suggestions.length - 1));
17151
17176
  const selectedIdxRef = useRef8(clampedIdx);
17152
17177
  selectedIdxRef.current = clampedIdx;
@@ -17162,10 +17187,10 @@ var ChatInput = memo11(({
17162
17187
  inputRequestRef.current = inputRequest;
17163
17188
  const onChangeRef = useRef8(onChange);
17164
17189
  onChangeRef.current = onChange;
17165
- const [pastedHint, setPastedHint] = useState8(null);
17190
+ const [pastedHint, setPastedHint] = useState6(null);
17166
17191
  const prevValueRef = useRef8(value);
17167
17192
  const pasteTimerRef = useRef8(null);
17168
- useEffect9(() => {
17193
+ useEffect7(() => {
17169
17194
  const diff = value.length - prevValueRef.current.length;
17170
17195
  if (diff > 20) {
17171
17196
  if (pasteTimerRef.current) clearTimeout(pasteTimerRef.current);
@@ -17177,7 +17202,7 @@ var ChatInput = memo11(({
17177
17202
  if (pasteTimerRef.current) clearTimeout(pasteTimerRef.current);
17178
17203
  };
17179
17204
  }, [value]);
17180
- const [inputKey, setInputKey] = useState8(0);
17205
+ const [inputKey, setInputKey] = useState6(0);
17181
17206
  const completeCommand = useCallback9((idx) => {
17182
17207
  const sug = suggestionsRef.current;
17183
17208
  if (!sug.length) return;
@@ -17226,7 +17251,7 @@ var ChatInput = memo11(({
17226
17251
  }
17227
17252
  }, [completeCommand]));
17228
17253
  return /* @__PURE__ */ jsxs14(Box15, { flexDirection: "column", children: [
17229
- showPreview && /* @__PURE__ */ jsx17(
17254
+ showPreview && /* @__PURE__ */ jsx18(
17230
17255
  AutocompletePreview,
17231
17256
  {
17232
17257
  suggestions,
@@ -17235,7 +17260,7 @@ var ChatInput = memo11(({
17235
17260
  ),
17236
17261
  inputRequest.status === "active" ? (
17237
17262
  /* Active input request — yellow top/bottom border */
17238
- /* @__PURE__ */ jsx17(
17263
+ /* @__PURE__ */ jsx18(
17239
17264
  SecretInputArea,
17240
17265
  {
17241
17266
  inputRequest,
@@ -17246,7 +17271,7 @@ var ChatInput = memo11(({
17246
17271
  )
17247
17272
  ) : (
17248
17273
  /* Normal input — dim top/bottom border */
17249
- /* @__PURE__ */ jsx17(
17274
+ /* @__PURE__ */ jsx18(
17250
17275
  NormalInputArea,
17251
17276
  {
17252
17277
  inputKey,
@@ -17257,14 +17282,14 @@ var ChatInput = memo11(({
17257
17282
  }
17258
17283
  )
17259
17284
  ),
17260
- pastedHint && /* @__PURE__ */ jsx17(Box15, { paddingX: 2, children: /* @__PURE__ */ jsx17(Text17, { dimColor: true, color: THEME.dimGray, children: pastedHint }) })
17285
+ pastedHint && /* @__PURE__ */ jsx18(Box15, { paddingX: 2, children: /* @__PURE__ */ jsx18(Text17, { dimColor: true, color: THEME.dimGray, children: pastedHint }) })
17261
17286
  ] });
17262
17287
  });
17263
17288
 
17264
17289
  // src/platform/tui/components/footer.tsx
17265
17290
  import { memo as memo12 } from "react";
17266
17291
  import { Box as Box16, Text as Text18 } from "ink";
17267
- import { jsx as jsx18, jsxs as jsxs15 } from "react/jsx-runtime";
17292
+ import { jsx as jsx19, jsxs as jsxs15 } from "react/jsx-runtime";
17268
17293
  var CTX_WARN_THRESHOLD = 0.8;
17269
17294
  var MAX_CONTEXT_TOKENS = LLM_LIMITS.streamMaxTokens;
17270
17295
  var formatElapsed = (totalSeconds) => {
@@ -17291,26 +17316,26 @@ var Footer = memo12(({ phase, targets, findings, todo, elapsedTime, isProcessing
17291
17316
  /* @__PURE__ */ jsxs15(Box16, { gap: 2, children: [
17292
17317
  /* @__PURE__ */ jsxs15(Text18, { color: THEME.gray, children: [
17293
17318
  "Phase: ",
17294
- /* @__PURE__ */ jsx18(Text18, { color: THEME.white, children: phase })
17319
+ /* @__PURE__ */ jsx19(Text18, { color: THEME.white, children: phase })
17295
17320
  ] }),
17296
17321
  /* @__PURE__ */ jsxs15(Text18, { color: THEME.gray, children: [
17297
17322
  "Targets: ",
17298
- /* @__PURE__ */ jsx18(Text18, { color: THEME.white, children: targets })
17323
+ /* @__PURE__ */ jsx19(Text18, { color: THEME.white, children: targets })
17299
17324
  ] }),
17300
17325
  /* @__PURE__ */ jsxs15(Text18, { color: THEME.gray, children: [
17301
17326
  "Findings: ",
17302
- /* @__PURE__ */ jsx18(Text18, { color: THEME.white, children: findings })
17327
+ /* @__PURE__ */ jsx19(Text18, { color: THEME.white, children: findings })
17303
17328
  ] }),
17304
17329
  /* @__PURE__ */ jsxs15(Text18, { color: THEME.gray, children: [
17305
17330
  "Tasks: ",
17306
- /* @__PURE__ */ jsx18(Text18, { color: THEME.white, children: todo })
17331
+ /* @__PURE__ */ jsx19(Text18, { color: THEME.white, children: todo })
17307
17332
  ] })
17308
17333
  ] }),
17309
17334
  /* @__PURE__ */ jsxs15(Box16, { gap: 2, children: [
17310
17335
  isProcessing ? /* @__PURE__ */ jsxs15(Box16, { gap: 1, children: [
17311
- /* @__PURE__ */ jsx18(Text18, { dimColor: true, color: THEME.dimGray, children: "[ESC] abort" }),
17312
- /* @__PURE__ */ jsx18(Text18, { dimColor: true, color: THEME.dimGray, children: "[^C\xD72] exit" })
17313
- ] }) : /* @__PURE__ */ jsx18(Text18, { dimColor: true, color: THEME.dimGray, children: "[/help] commands" }),
17336
+ /* @__PURE__ */ jsx19(Text18, { dimColor: true, color: THEME.dimGray, children: "[ESC] abort" }),
17337
+ /* @__PURE__ */ jsx19(Text18, { dimColor: true, color: THEME.dimGray, children: "[^C\xD72] exit" })
17338
+ ] }) : /* @__PURE__ */ jsx19(Text18, { dimColor: true, color: THEME.dimGray, children: "[/help] commands" }),
17314
17339
  turnCount > 0 && /* @__PURE__ */ jsxs15(Text18, { dimColor: true, color: THEME.dimGray, children: [
17315
17340
  "turn:",
17316
17341
  turnCount
@@ -17324,8 +17349,8 @@ var Footer = memo12(({ phase, targets, findings, todo, elapsedTime, isProcessing
17324
17349
  "\u2191",
17325
17350
  formatTokens(totalTokens)
17326
17351
  ] }),
17327
- /* @__PURE__ */ jsx18(Text18, { color: isProcessing ? THEME.primary : THEME.gray, children: isProcessing ? "Running " : "Idle " }),
17328
- /* @__PURE__ */ jsx18(Text18, { color: THEME.white, children: formatElapsed(elapsedTime) })
17352
+ /* @__PURE__ */ jsx19(Text18, { color: isProcessing ? THEME.primary : THEME.gray, children: isProcessing ? "Running " : "Idle " }),
17353
+ /* @__PURE__ */ jsx19(Text18, { color: THEME.white, children: formatElapsed(elapsedTime) })
17329
17354
  ] })
17330
17355
  ]
17331
17356
  }
@@ -17336,7 +17361,7 @@ var footer_default = Footer;
17336
17361
  // src/platform/tui/components/Modal.tsx
17337
17362
  import { useMemo as useMemo2, memo as memo13, useCallback as useCallback10, useRef as useRef9 } from "react";
17338
17363
  import { Box as Box17, Text as Text19, useStdout as useStdout3, useInput as useInput4 } from "ink";
17339
- import { jsx as jsx19, jsxs as jsxs16 } from "react/jsx-runtime";
17364
+ import { jsx as jsx20, jsxs as jsxs16 } from "react/jsx-runtime";
17340
17365
  var MODAL_TITLES = {
17341
17366
  findings: "\u25C8 FINDINGS \u25C8",
17342
17367
  graph: "\u25C8 ATTACK GRAPH \u25C8",
@@ -17387,12 +17412,12 @@ var Modal = memo13(({
17387
17412
  width: terminalWidth,
17388
17413
  height: terminalHeight,
17389
17414
  children: [
17390
- /* @__PURE__ */ jsx19(Box17, { justifyContent: "center", marginBottom: 0, children: /* @__PURE__ */ jsx19(Text19, { color: THEME.cyan, bold: true, children: (() => {
17415
+ /* @__PURE__ */ jsx20(Box17, { justifyContent: "center", marginBottom: 0, children: /* @__PURE__ */ jsx20(Text19, { color: THEME.cyan, bold: true, children: (() => {
17391
17416
  const title = MODAL_TITLES[type];
17392
17417
  const sideWidth = Math.max(3, Math.floor((terminalWidth - title.length - 2) / 2));
17393
17418
  return `${"\u2500".repeat(sideWidth)} ${title} ${"\u2500".repeat(sideWidth)}`;
17394
17419
  })() }) }),
17395
- /* @__PURE__ */ jsx19(
17420
+ /* @__PURE__ */ jsx20(
17396
17421
  Box17,
17397
17422
  {
17398
17423
  flexDirection: "column",
@@ -17403,15 +17428,15 @@ var Modal = memo13(({
17403
17428
  children: visibleLines.map((line, i) => {
17404
17429
  const showScrollbar = totalLines > maxHeight && i >= scrollbarPosition && i < scrollbarPosition + scrollbarHeight;
17405
17430
  return /* @__PURE__ */ jsxs16(Box17, { children: [
17406
- /* @__PURE__ */ jsx19(Text19, { color: THEME.white, wrap: "truncate", children: line }),
17407
- /* @__PURE__ */ jsx19(Box17, { flexGrow: 1 }),
17408
- totalLines > maxHeight && /* @__PURE__ */ jsx19(Text19, { color: showScrollbar ? THEME.cyan : THEME.dimGray, children: showScrollbar ? "\u2588" : "\u2502" })
17431
+ /* @__PURE__ */ jsx20(Text19, { color: THEME.white, wrap: "truncate", children: line }),
17432
+ /* @__PURE__ */ jsx20(Box17, { flexGrow: 1 }),
17433
+ totalLines > maxHeight && /* @__PURE__ */ jsx20(Text19, { color: showScrollbar ? THEME.cyan : THEME.dimGray, children: showScrollbar ? "\u2588" : "\u2502" })
17409
17434
  ] }, i);
17410
17435
  })
17411
17436
  }
17412
17437
  ),
17413
17438
  /* @__PURE__ */ jsxs16(Box17, { justifyContent: "space-between", paddingX: 1, children: [
17414
- /* @__PURE__ */ jsx19(Text19, { dimColor: true, color: THEME.gray, children: "\u2191\u2193/jk: scroll | g/G: top/bottom | ESC/q: close" }),
17439
+ /* @__PURE__ */ jsx20(Text19, { dimColor: true, color: THEME.gray, children: "\u2191\u2193/jk: scroll | g/G: top/bottom | ESC/q: close" }),
17415
17440
  /* @__PURE__ */ jsxs16(Text19, { dimColor: true, color: THEME.cyan, children: [
17416
17441
  startLine,
17417
17442
  "-",
@@ -17427,7 +17452,7 @@ var Modal = memo13(({
17427
17452
 
17428
17453
  // src/platform/tui/components/app/bottom-region.tsx
17429
17454
  import { Box as Box18 } from "ink";
17430
- import { jsx as jsx20, jsxs as jsxs17 } from "react/jsx-runtime";
17455
+ import { jsx as jsx21, jsxs as jsxs17 } from "react/jsx-runtime";
17431
17456
  var BottomRegion = ({
17432
17457
  input,
17433
17458
  setInput,
@@ -17450,19 +17475,19 @@ var BottomRegion = ({
17450
17475
  const hasArgs = isSlashMode && input.includes(" ");
17451
17476
  const suggestionCount = isSlashMode && !hasArgs && inputRequest.status !== "active" ? Math.min(getMatchingCommands(partialCmd).length, MAX_SUGGESTIONS) : 0;
17452
17477
  const previewHeight = suggestionCount;
17453
- const inputExtraHeight = inputRequest.status === "active" ? 1 : 0;
17454
- const bottomMinHeight = 7 + inputExtraHeight;
17478
+ const bottomMinHeight = 7;
17455
17479
  return /* @__PURE__ */ jsxs17(Box18, { flexDirection: "column", minHeight: bottomMinHeight, children: [
17456
- /* @__PURE__ */ jsx20(
17480
+ /* @__PURE__ */ jsx21(
17457
17481
  StatusDisplay,
17458
17482
  {
17459
17483
  retryState,
17460
17484
  isProcessing,
17461
17485
  currentStatus,
17462
- currentTokens
17486
+ currentTokens,
17487
+ inputRequest
17463
17488
  }
17464
17489
  ),
17465
- /* @__PURE__ */ jsx20(
17490
+ /* @__PURE__ */ jsx21(
17466
17491
  ChatInput,
17467
17492
  {
17468
17493
  value: input,
@@ -17475,7 +17500,7 @@ var BottomRegion = ({
17475
17500
  onSecretSubmit: handleSecretSubmit
17476
17501
  }
17477
17502
  ),
17478
- /* @__PURE__ */ jsx20(Box18, { marginTop: 1, children: /* @__PURE__ */ jsx20(
17503
+ /* @__PURE__ */ jsx21(Box18, { marginTop: 1, children: /* @__PURE__ */ jsx21(
17479
17504
  footer_default,
17480
17505
  {
17481
17506
  phase: stats.phase,
@@ -17492,16 +17517,16 @@ var BottomRegion = ({
17492
17517
  };
17493
17518
 
17494
17519
  // src/platform/tui/app.tsx
17495
- import { jsx as jsx21, jsxs as jsxs18 } from "react/jsx-runtime";
17520
+ import { jsx as jsx22, jsxs as jsxs18 } from "react/jsx-runtime";
17496
17521
  var MODEL_NAME = getModel() || DEFAULT_MODEL;
17497
17522
  var App = ({ autoApprove = false, target }) => {
17498
17523
  const { exit } = useApp();
17499
17524
  const { stdout } = useStdout4();
17500
17525
  const terminalWidth = stdout?.columns ?? 80;
17501
- const [input, setInput] = useState9("");
17502
- const [secretInput, setSecretInput] = useState9("");
17503
- const [autoApproveMode, setAutoApproveMode] = useState9(autoApprove);
17504
- const [modal, setModal] = useState9({ type: null, content: "", scrollOffset: 0 });
17526
+ const [input, setInput] = useState7("");
17527
+ const [secretInput, setSecretInput] = useState7("");
17528
+ const [autoApproveMode, setAutoApproveMode] = useState7(autoApprove);
17529
+ const [modal, setModal] = useState7({ type: null, content: "", scrollOffset: 0 });
17505
17530
  const {
17506
17531
  agent,
17507
17532
  messages,
@@ -17534,7 +17559,7 @@ var App = ({ autoApprove = false, target }) => {
17534
17559
  const clearInput = useCallback11(() => {
17535
17560
  setInput("");
17536
17561
  }, []);
17537
- const [historyScrollOffset, setHistoryScrollOffset] = useState9(0);
17562
+ const [historyScrollOffset, setHistoryScrollOffset] = useState7(0);
17538
17563
  const handleScroll = useCallback11((delta) => {
17539
17564
  setHistoryScrollOffset((prev) => Math.max(0, prev - delta));
17540
17565
  }, []);
@@ -17601,9 +17626,8 @@ var App = ({ autoApprove = false, target }) => {
17601
17626
  const handleSecretSubmit = useCallback11((value) => {
17602
17627
  const ir = inputRequestRef.current;
17603
17628
  if (ir.status !== "active") return;
17604
- const displayText = ir.isPassword ? "\u2022".repeat(value.length) : value;
17605
- const promptLabel = ir.prompt || "Input";
17606
- addMessage("system", `\u21B3 ${promptLabel} ${displayText}`);
17629
+ const displayText = ir.isPassword ? "\u2022".repeat(Math.min(value.length, 20)) : value;
17630
+ addMessage("system", `\u21B3 ${displayText}`);
17607
17631
  ir.resolve(value);
17608
17632
  setInputRequest({ status: "inactive" });
17609
17633
  setSecretInput("");
@@ -17621,7 +17645,7 @@ var App = ({ autoApprove = false, target }) => {
17621
17645
  onScroll: handleScroll
17622
17646
  });
17623
17647
  if (modal.type) {
17624
- return /* @__PURE__ */ jsx21(Box19, { flexDirection: "column", paddingX: 1, width: terminalWidth, children: /* @__PURE__ */ jsx21(
17648
+ return /* @__PURE__ */ jsx22(Box19, { flexDirection: "column", paddingX: 1, width: terminalWidth, children: /* @__PURE__ */ jsx22(
17625
17649
  Modal,
17626
17650
  {
17627
17651
  type: modal.type,
@@ -17633,7 +17657,7 @@ var App = ({ autoApprove = false, target }) => {
17633
17657
  ) });
17634
17658
  }
17635
17659
  return /* @__PURE__ */ jsxs18(Box19, { flexDirection: "column", paddingX: 1, width: terminalWidth, children: [
17636
- /* @__PURE__ */ jsx21(Box19, { flexDirection: "column", children: /* @__PURE__ */ jsx21(
17660
+ /* @__PURE__ */ jsx22(Box19, { flexDirection: "column", children: /* @__PURE__ */ jsx22(
17637
17661
  MessageList,
17638
17662
  {
17639
17663
  messages,
@@ -17644,7 +17668,7 @@ var App = ({ autoApprove = false, target }) => {
17644
17668
  scrollOffset: historyScrollOffset
17645
17669
  }
17646
17670
  ) }),
17647
- /* @__PURE__ */ jsx21(
17671
+ /* @__PURE__ */ jsx22(
17648
17672
  BottomRegion,
17649
17673
  {
17650
17674
  input,
@@ -17669,7 +17693,7 @@ var App = ({ autoApprove = false, target }) => {
17669
17693
  var app_default = App;
17670
17694
 
17671
17695
  // src/platform/tui/cli/commands/interactive.tsx
17672
- import { jsx as jsx22 } from "react/jsx-runtime";
17696
+ import { jsx as jsx23 } from "react/jsx-runtime";
17673
17697
  async function interactiveAction(options) {
17674
17698
  const { dangerouslySkipPermissions: skipPermissions = false, target } = options;
17675
17699
  console.clear();
@@ -17678,13 +17702,13 @@ async function interactiveAction(options) {
17678
17702
  console.log(chalk.hex(HEX.red)("[!] All tool executions will be auto-approved!\n"));
17679
17703
  }
17680
17704
  const { waitUntilExit } = render(
17681
- /* @__PURE__ */ jsx22(
17705
+ /* @__PURE__ */ jsx23(AnimationProvider, { children: /* @__PURE__ */ jsx23(
17682
17706
  app_default,
17683
17707
  {
17684
17708
  autoApprove: skipPermissions,
17685
17709
  target
17686
17710
  }
17687
- )
17711
+ ) })
17688
17712
  );
17689
17713
  await waitUntilExit();
17690
17714
  }