pentesting 0.70.8 → 0.70.10

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/main.js CHANGED
@@ -82,9 +82,9 @@ var THEME = {
82
82
  spinner: COLORS.primary
83
83
  };
84
84
  var ASCII_BANNER = `
85
- \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510
86
- \u2502 P E N T E S T I N G A G E N T \u2502
87
- \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
85
+ \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510
86
+ \u2502 P E N T E S T I N G A G E N T \u2502
87
+ \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
88
88
  `;
89
89
  var ICONS = {
90
90
  // Status
@@ -421,7 +421,7 @@ function isZaiProvider() {
421
421
  return baseUrl.includes("z.ai");
422
422
  }
423
423
  function isThinkingEnabled() {
424
- return process.env[ENV_KEYS.THINKING] === "true";
424
+ return process.env[ENV_KEYS.THINKING] !== "false";
425
425
  }
426
426
  function getThinkingBudget() {
427
427
  const val = parseInt(process.env[ENV_KEYS.THINKING_BUDGET] || "", 10);
@@ -759,7 +759,7 @@ var INPUT_PROMPT_PATTERNS = [
759
759
 
760
760
  // src/shared/constants/agent.ts
761
761
  var APP_NAME = "Pentest AI";
762
- var APP_VERSION = "0.70.8";
762
+ var APP_VERSION = "0.70.10";
763
763
  var APP_DESCRIPTION = "Autonomous Penetration Testing AI Agent";
764
764
  var LLM_ROLES = {
765
765
  SYSTEM: "system",
@@ -814,8 +814,8 @@ import { render } from "ink";
814
814
  import chalk from "chalk";
815
815
 
816
816
  // src/platform/tui/app.tsx
817
- import { useState as useState6, useCallback as useCallback9, useRef as useRef8 } from "react";
818
- import { Box as Box19, useApp, useStdout as useStdout4 } from "ink";
817
+ import { useState as useState7, useCallback as useCallback9, useRef as useRef9 } from "react";
818
+ import { Box as Box20, useApp, useStdout as useStdout4 } from "ink";
819
819
 
820
820
  // src/platform/tui/hooks/useAgent.ts
821
821
  import { useState as useState2, useEffect as useEffect2, useCallback as useCallback2, useRef as useRef3 } from "react";
@@ -1026,7 +1026,8 @@ var NOISE_CLASSIFICATION = {
1026
1026
  "set_scope",
1027
1027
  "bg_status",
1028
1028
  "bg_cleanup",
1029
- "health_check"
1029
+ "health_check",
1030
+ "ask_user"
1030
1031
  ]
1031
1032
  };
1032
1033
 
@@ -1173,7 +1174,9 @@ var EVENT_TYPES = {
1173
1174
  USAGE_UPDATE: "usage_update",
1174
1175
  INPUT_REQUEST: "input_request",
1175
1176
  FLAG_FOUND: "flag_found",
1176
- NOTIFICATION: "notification"
1177
+ NOTIFICATION: "notification",
1178
+ AUXILIARY_WORK_START: "auxiliary_work_start",
1179
+ AUXILIARY_WORK_END: "auxiliary_work_end"
1177
1180
  };
1178
1181
  var COMMAND_EVENT_TYPES = {
1179
1182
  TOOL_MISSING: "tool_missing",
@@ -3395,11 +3398,25 @@ var SharedState = class {
3395
3398
  * 이 필드로 turn N의 reflection → turn N+1 prompt 레이어(epistemic-check)에 주입된다.
3396
3399
  */
3397
3400
  lastReflection = null;
3401
+ /**
3402
+ * Artifacts for CTF / Non-Network tasks (e.g., .bin files, source code).
3403
+ */
3404
+ artifacts = [];
3405
+ /**
3406
+ * Current objective for flexible task management.
3407
+ */
3408
+ currentObjective = null;
3398
3409
  constructor() {
3399
3410
  this.targetState = new TargetState(this.attackGraph);
3400
3411
  this.findingState = new FindingState();
3401
3412
  this.lootState = new LootState();
3402
3413
  }
3414
+ /**
3415
+ * Checks if the agent has a valid target, artifact, or general objective to work on.
3416
+ */
3417
+ hasActiveEngagement() {
3418
+ return this.targetState.getAll().length > 0 || this.artifacts.length > 0 || this.currentObjective !== null;
3419
+ }
3403
3420
  reset() {
3404
3421
  this.targetState.clear();
3405
3422
  this.findingState.clear();
@@ -3413,6 +3430,8 @@ var SharedState = class {
3413
3430
  this.episodicMemory.clear();
3414
3431
  this.dynamicTechniques.clear();
3415
3432
  this.lastReflection = null;
3433
+ this.artifacts = [];
3434
+ this.currentObjective = null;
3416
3435
  }
3417
3436
  // Delegation to MissionState
3418
3437
  setMissionSummary(summary) {
@@ -5108,6 +5127,7 @@ var StateSerializer = class {
5108
5127
  static toPrompt(state) {
5109
5128
  const lines = [];
5110
5129
  this.formatContextAndMission(state, lines);
5130
+ this.formatArtifactsAndObjectives(state, lines);
5111
5131
  this.formatTargets(state, lines);
5112
5132
  this.formatFindings(state, lines);
5113
5133
  this.formatLoot(state, lines);
@@ -5118,6 +5138,17 @@ var StateSerializer = class {
5118
5138
  lines.push(`Phase: ${state.getPhase()}`);
5119
5139
  return lines.join("\n");
5120
5140
  }
5141
+ static formatArtifactsAndObjectives(state, lines) {
5142
+ if (state.currentObjective) {
5143
+ lines.push(`Current Objective: ${state.currentObjective}`);
5144
+ }
5145
+ if (state.artifacts && state.artifacts.length > 0) {
5146
+ lines.push(`Artifacts (${state.artifacts.length}):`);
5147
+ for (const a of state.artifacts) {
5148
+ lines.push(` [${a.type}] ${a.id}: ${a.description}`);
5149
+ }
5150
+ }
5151
+ }
5121
5152
  static formatContextAndMission(state, lines) {
5122
5153
  const engagement = state.getEngagement();
5123
5154
  const scope = state.getScope();
@@ -12567,16 +12598,16 @@ function extractHypothesizedReason(failureLine) {
12567
12598
  }
12568
12599
 
12569
12600
  // src/shared/utils/context-digest/formatters.ts
12570
- function formatContextForLLM(memo14) {
12601
+ function formatContextForLLM(memo15) {
12571
12602
  const compact = {};
12572
- if (memo14.keyFindings.length > 0) compact.findings = memo14.keyFindings;
12573
- if (memo14.credentials.length > 0) compact.credentials = memo14.credentials;
12574
- if (memo14.attackVectors.length > 0) compact.attackVectors = memo14.attackVectors;
12575
- if (memo14.failures.length > 0) compact.failures = memo14.failures;
12576
- if (memo14.suspicions.length > 0) compact.suspicions = memo14.suspicions;
12577
- if (memo14.nextSteps.length > 0) compact.nextSteps = memo14.nextSteps;
12578
- compact.attackValue = memo14.attackValue;
12579
- if (memo14.reflection) compact.reflection = memo14.reflection;
12603
+ if (memo15.keyFindings.length > 0) compact.findings = memo15.keyFindings;
12604
+ if (memo15.credentials.length > 0) compact.credentials = memo15.credentials;
12605
+ if (memo15.attackVectors.length > 0) compact.attackVectors = memo15.attackVectors;
12606
+ if (memo15.failures.length > 0) compact.failures = memo15.failures;
12607
+ if (memo15.suspicions.length > 0) compact.suspicions = memo15.suspicions;
12608
+ if (memo15.nextSteps.length > 0) compact.nextSteps = memo15.nextSteps;
12609
+ compact.attackValue = memo15.attackValue;
12610
+ if (memo15.reflection) compact.reflection = memo15.reflection;
12580
12611
  return JSON.stringify(compact);
12581
12612
  }
12582
12613
  function formatAnalystDigest(digest, filePath, originalChars) {
@@ -12634,15 +12665,15 @@ async function digestToolOutput(output, toolName, toolInput, analystFn) {
12634
12665
  try {
12635
12666
  const context = `Tool: ${toolName}${toolInput ? ` | Input: ${toolInput}` : ""}`;
12636
12667
  const rawAnalystResponse = await analystFn(preprocessed, context);
12637
- const memo14 = parseAnalystMemo(rawAnalystResponse);
12668
+ const memo15 = parseAnalystMemo(rawAnalystResponse);
12638
12669
  const formatted = formatAnalystDigest(rawAnalystResponse, savedOutputPath, originalLength);
12639
- const contextForLLM = formatContextForLLM(memo14);
12670
+ const contextForLLM = formatContextForLLM(memo15);
12640
12671
  return {
12641
12672
  digestedOutput: formatted,
12642
12673
  contextForLLM,
12643
12674
  fullOutputPath: savedOutputPath,
12644
12675
  analystUsed: true,
12645
- memo: memo14,
12676
+ memo: memo15,
12646
12677
  originalLength,
12647
12678
  digestedLength: formatted.length,
12648
12679
  compressionRatio: formatted.length / originalLength
@@ -13597,7 +13628,7 @@ function buildSummaryFromEntries(entries) {
13597
13628
 
13598
13629
  // src/shared/utils/journal/formatters/record.ts
13599
13630
  function formatTurnRecord(input) {
13600
- const { turn, timestamp, phase, tools, memo: memo14, reflection } = input;
13631
+ const { turn, timestamp, phase, tools, memo: memo15, reflection } = input;
13601
13632
  const time = timestamp.slice(0, 19).replace("T", " ");
13602
13633
  const sections = [];
13603
13634
  sections.push(`# Turn ${turn} | ${time} | Phase: ${phase}`);
@@ -13614,25 +13645,25 @@ function formatTurnRecord(input) {
13614
13645
  }
13615
13646
  sections.push("");
13616
13647
  sections.push(`## ${TURN_SECTIONS.KEY_INSIGHTS}`);
13617
- if (memo14.keyFindings.length > 0) {
13618
- for (const f of memo14.keyFindings) sections.push(`- ${INSIGHT_TAGS.DISCOVERED}: ${f}`);
13648
+ if (memo15.keyFindings.length > 0) {
13649
+ for (const f of memo15.keyFindings) sections.push(`- ${INSIGHT_TAGS.DISCOVERED}: ${f}`);
13619
13650
  }
13620
- if (memo14.credentials.length > 0) {
13621
- for (const c of memo14.credentials) sections.push(`- ${INSIGHT_TAGS.CREDENTIAL}: ${c}`);
13651
+ if (memo15.credentials.length > 0) {
13652
+ for (const c of memo15.credentials) sections.push(`- ${INSIGHT_TAGS.CREDENTIAL}: ${c}`);
13622
13653
  }
13623
- if (memo14.attackVectors.length > 0) {
13624
- for (const v of memo14.attackVectors) sections.push(`- ${INSIGHT_TAGS.CONFIRMED}: ${v}`);
13654
+ if (memo15.attackVectors.length > 0) {
13655
+ for (const v of memo15.attackVectors) sections.push(`- ${INSIGHT_TAGS.CONFIRMED}: ${v}`);
13625
13656
  }
13626
- if (memo14.failures.length > 0) {
13627
- for (const f of memo14.failures) sections.push(`- ${INSIGHT_TAGS.DEAD_END}: ${f}`);
13657
+ if (memo15.failures.length > 0) {
13658
+ for (const f of memo15.failures) sections.push(`- ${INSIGHT_TAGS.DEAD_END}: ${f}`);
13628
13659
  }
13629
- if (memo14.suspicions.length > 0) {
13630
- for (const s of memo14.suspicions) sections.push(`- ${INSIGHT_TAGS.SUSPICIOUS}: ${s}`);
13660
+ if (memo15.suspicions.length > 0) {
13661
+ for (const s of memo15.suspicions) sections.push(`- ${INSIGHT_TAGS.SUSPICIOUS}: ${s}`);
13631
13662
  }
13632
- if (memo14.nextSteps.length > 0) {
13633
- for (const n of memo14.nextSteps) sections.push(`- ${INSIGHT_TAGS.NEXT}: ${n}`);
13663
+ if (memo15.nextSteps.length > 0) {
13664
+ for (const n of memo15.nextSteps) sections.push(`- ${INSIGHT_TAGS.NEXT}: ${n}`);
13634
13665
  }
13635
- if (memo14.keyFindings.length === 0 && memo14.failures.length === 0 && memo14.credentials.length === 0) {
13666
+ if (memo15.keyFindings.length === 0 && memo15.failures.length === 0 && memo15.credentials.length === 0) {
13636
13667
  sections.push(`- ${TURN_EMPTY_MESSAGES.NO_INSIGHTS}`);
13637
13668
  }
13638
13669
  sections.push("");
@@ -13644,7 +13675,7 @@ function formatTurnRecord(input) {
13644
13675
 
13645
13676
  // src/shared/utils/journal/formatters/reflection.ts
13646
13677
  function formatReflectionInput(input) {
13647
- const { tools, memo: memo14, phase } = input;
13678
+ const { tools, memo: memo15, phase } = input;
13648
13679
  const parts = [
13649
13680
  `\uD604\uC7AC Phase: ${phase}`,
13650
13681
  "",
@@ -13662,12 +13693,12 @@ function formatReflectionInput(input) {
13662
13693
  }
13663
13694
  parts.push("");
13664
13695
  parts.push("Analyst \uCD94\uCD9C \uBA54\uBAA8:");
13665
- if (memo14) {
13666
- if (memo14.keyFindings.length > 0) parts.push(` \uBC1C\uACAC: ${memo14.keyFindings.join(", ")}`);
13667
- if (memo14.credentials.length > 0) parts.push(` \uD06C\uB808\uB374\uC15C: ${memo14.credentials.join(", ")}`);
13668
- if (memo14.failures.length > 0) parts.push(` \uC2E4\uD328: ${memo14.failures.join(", ")}`);
13669
- if (memo14.suspicions.length > 0) parts.push(` \uC758\uC2EC: ${memo14.suspicions.join(", ")}`);
13670
- parts.push(` \uACF5\uACA9 \uAC00\uCE58: ${memo14.attackValue}`);
13696
+ if (memo15) {
13697
+ if (memo15.keyFindings.length > 0) parts.push(` \uBC1C\uACAC: ${memo15.keyFindings.join(", ")}`);
13698
+ if (memo15.credentials.length > 0) parts.push(` \uD06C\uB808\uB374\uC15C: ${memo15.credentials.join(", ")}`);
13699
+ if (memo15.failures.length > 0) parts.push(` \uC2E4\uD328: ${memo15.failures.join(", ")}`);
13700
+ if (memo15.suspicions.length > 0) parts.push(` \uC758\uC2EC: ${memo15.suspicions.join(", ")}`);
13701
+ parts.push(` \uACF5\uACA9 \uAC00\uCE58: ${memo15.attackValue}`);
13671
13702
  } else {
13672
13703
  parts.push(" (\uBD84\uC11D \uACB0\uACFC \uC5C6\uC74C)");
13673
13704
  }
@@ -14561,13 +14592,13 @@ ${extraction.extractedContext}
14561
14592
  }
14562
14593
  return false;
14563
14594
  }
14564
- async function processReflection(toolJournal, memo14, phase, reflector) {
14595
+ async function processReflection(toolJournal, memo15, phase, reflector) {
14565
14596
  if (toolJournal.length === 0) {
14566
14597
  return null;
14567
14598
  }
14568
14599
  const reflection = await reflector.execute({
14569
14600
  tools: toolJournal,
14570
- memo: memo14,
14601
+ memo: memo15,
14571
14602
  phase
14572
14603
  });
14573
14604
  if (reflection.success && reflection.reflection) {
@@ -14580,7 +14611,7 @@ async function processReflection(toolJournal, memo14, phase, reflector) {
14580
14611
  import { writeFileSync as writeFileSync10, existsSync as existsSync15, readFileSync as readFileSync11 } from "fs";
14581
14612
  import { join as join16 } from "path";
14582
14613
  async function recordTurn(context) {
14583
- const { turnCounter, phase, toolJournal, memo: memo14, reflections, summaryRegenerator } = context;
14614
+ const { turnCounter, phase, toolJournal, memo: memo15, reflections, summaryRegenerator } = context;
14584
14615
  if (toolJournal.length === 0) {
14585
14616
  return turnCounter;
14586
14617
  }
@@ -14590,10 +14621,10 @@ async function recordTurn(context) {
14590
14621
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
14591
14622
  phase,
14592
14623
  tools: toolJournal,
14593
- memo: memo14,
14594
- reflection: reflections.length > 0 ? reflections.join(" | ") : memo14.nextSteps.join("; ")
14624
+ memo: memo15,
14625
+ reflection: reflections.length > 0 ? reflections.join(" | ") : memo15.nextSteps.join("; ")
14595
14626
  };
14596
- const entryCtx = { entry, journalTools: toolJournal, memo: memo14, phase, reflections };
14627
+ const entryCtx = { entry, journalTools: toolJournal, memo: memo15, phase, reflections };
14597
14628
  await createTurnArchive(turnCounter, entryCtx);
14598
14629
  await regenerateSummary(turnCounter, summaryRegenerator, entryCtx);
14599
14630
  rotateTurnRecords();
@@ -14602,7 +14633,7 @@ async function recordTurn(context) {
14602
14633
  return turnCounter + 1;
14603
14634
  }
14604
14635
  async function createTurnArchive(turnCounter, ctx) {
14605
- const { entry, journalTools, memo: memo14, phase } = ctx;
14636
+ const { entry, journalTools, memo: memo15, phase } = ctx;
14606
14637
  try {
14607
14638
  const turnDir = WORKSPACE.turnPath(turnCounter);
14608
14639
  const toolsDir = WORKSPACE.turnToolsPath(turnCounter);
@@ -14613,35 +14644,35 @@ async function createTurnArchive(turnCounter, ctx) {
14613
14644
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
14614
14645
  phase,
14615
14646
  tools: journalTools,
14616
- memo: memo14,
14647
+ memo: memo15,
14617
14648
  reflection: entry.reflection
14618
14649
  });
14619
14650
  writeFileSync10(join16(turnDir, TURN_FILES.RECORD), turnContent, "utf-8");
14620
14651
  writeFileSync10(join16(turnDir, TURN_FILES.STRUCTURED), JSON.stringify(entry, null, 2), "utf-8");
14621
- writeAnalystFile(turnDir, memo14);
14652
+ writeAnalystFile(turnDir, memo15);
14622
14653
  } catch {
14623
14654
  }
14624
14655
  }
14625
- function writeAnalystFile(turnDir, memo14) {
14656
+ function writeAnalystFile(turnDir, memo15) {
14626
14657
  const memoLines = [];
14627
- if (memo14.keyFindings.length > 0) memoLines.push("## Key Findings", ...memo14.keyFindings.map((f) => `- ${f}`), "");
14628
- if (memo14.credentials.length > 0) memoLines.push("## Credentials", ...memo14.credentials.map((c) => `- ${c}`), "");
14629
- if (memo14.attackVectors.length > 0) memoLines.push("## Attack Vectors", ...memo14.attackVectors.map((v) => `- ${v}`), "");
14630
- if (memo14.failures.length > 0) memoLines.push("## Failures", ...memo14.failures.map((f) => `- ${f}`), "");
14631
- if (memo14.suspicions.length > 0) memoLines.push("## Suspicious", ...memo14.suspicions.map((s) => `- ${s}`), "");
14632
- if (memo14.nextSteps.length > 0) memoLines.push("## Next Steps", ...memo14.nextSteps.map((n) => `- ${n}`), "");
14658
+ if (memo15.keyFindings.length > 0) memoLines.push("## Key Findings", ...memo15.keyFindings.map((f) => `- ${f}`), "");
14659
+ if (memo15.credentials.length > 0) memoLines.push("## Credentials", ...memo15.credentials.map((c) => `- ${c}`), "");
14660
+ if (memo15.attackVectors.length > 0) memoLines.push("## Attack Vectors", ...memo15.attackVectors.map((v) => `- ${v}`), "");
14661
+ if (memo15.failures.length > 0) memoLines.push("## Failures", ...memo15.failures.map((f) => `- ${f}`), "");
14662
+ if (memo15.suspicions.length > 0) memoLines.push("## Suspicious", ...memo15.suspicions.map((s) => `- ${s}`), "");
14663
+ if (memo15.nextSteps.length > 0) memoLines.push("## Next Steps", ...memo15.nextSteps.map((n) => `- ${n}`), "");
14633
14664
  if (memoLines.length > 0) {
14634
14665
  writeFileSync10(join16(turnDir, TURN_FILES.ANALYST), memoLines.join("\n"), "utf-8");
14635
14666
  flowLog(
14636
14667
  "\u2462Analyst",
14637
14668
  "\u2192",
14638
14669
  `archive/turn-${turnDir.split("/").pop()}/analyst.md`,
14639
- `findings:${memo14.keyFindings.length} creds:${memo14.credentials.length} vectors:${memo14.attackVectors.length} failures:${memo14.failures.length}`
14670
+ `findings:${memo15.keyFindings.length} creds:${memo15.credentials.length} vectors:${memo15.attackVectors.length} failures:${memo15.failures.length}`
14640
14671
  );
14641
14672
  }
14642
14673
  }
14643
14674
  async function regenerateSummary(turnCounter, summaryRegenerator, ctx) {
14644
- const { entry, journalTools, memo: memo14, phase } = ctx;
14675
+ const { entry, journalTools, memo: memo15, phase } = ctx;
14645
14676
  try {
14646
14677
  const turnDir = WORKSPACE.turnPath(turnCounter);
14647
14678
  const summaryPath = join16(turnDir, TURN_FILES.SUMMARY);
@@ -14658,7 +14689,7 @@ async function regenerateSummary(turnCounter, summaryRegenerator, ctx) {
14658
14689
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
14659
14690
  phase,
14660
14691
  tools: journalTools,
14661
- memo: memo14,
14692
+ memo: memo15,
14662
14693
  reflection: entry.reflection
14663
14694
  });
14664
14695
  const summaryResult = await summaryRegenerator.execute({
@@ -14759,6 +14790,9 @@ var MainAgent = class extends CoreAgent {
14759
14790
  }
14760
14791
  async execute(userInput) {
14761
14792
  this.userInput = userInput;
14793
+ if (!this.state.hasActiveEngagement() && userInput.trim().length > 0) {
14794
+ this.state.currentObjective = userInput.trim();
14795
+ }
14762
14796
  emitStart(this.events, userInput, this.state);
14763
14797
  initializeTask(this.state);
14764
14798
  try {
@@ -14790,8 +14824,30 @@ var MainAgent = class extends CoreAgent {
14790
14824
  const turnToolJournal = this.getTurnToolJournal();
14791
14825
  const turnMemo = this.getTurnMemo();
14792
14826
  const turnReflections = [];
14827
+ this.events.emit({
14828
+ type: "auxiliary_work_start",
14829
+ timestamp: Date.now(),
14830
+ data: { type: "context_extraction" }
14831
+ });
14832
+ const extStart = Date.now();
14793
14833
  await processContextExtraction(messages, this.contextExtractor);
14834
+ this.events.emit({
14835
+ type: "auxiliary_work_end",
14836
+ timestamp: Date.now(),
14837
+ data: { type: "context_extraction", durationMs: Date.now() - extStart, success: true }
14838
+ });
14839
+ this.events.emit({
14840
+ type: "auxiliary_work_start",
14841
+ timestamp: Date.now(),
14842
+ data: { type: "reflection" }
14843
+ });
14844
+ const refStart = Date.now();
14794
14845
  const reflection = await processReflection(turnToolJournal, turnMemo, this.state.getPhase(), this.reflector);
14846
+ this.events.emit({
14847
+ type: "auxiliary_work_end",
14848
+ timestamp: Date.now(),
14849
+ data: { type: "reflection", durationMs: Date.now() - refStart, success: !!reflection }
14850
+ });
14795
14851
  if (reflection) {
14796
14852
  turnReflections.push(reflection);
14797
14853
  this.state.lastReflection = reflection;
@@ -14995,7 +15051,13 @@ var TUI_DISPLAY_LIMITS = {
14995
15051
  * sessions accumulate thousands of messages and RAM grows without bound.
14996
15052
  * Oldest messages are pruned first; all content is preserved in the disk archive.
14997
15053
  */
14998
- MAX_MESSAGES: 500
15054
+ MAX_MESSAGES: 500,
15055
+ /** Fallback terminal row count when stdout.rows is unavailable */
15056
+ TERMINAL_DEFAULT_ROWS: 24,
15057
+ /** Reserved rows for modal chrome (header + borders + padding + footer) */
15058
+ MODAL_CHROME_HEIGHT: 6,
15059
+ /** Max chars shown for masked password in message history */
15060
+ PASSWORD_MASK_MAX: 20
14999
15061
  };
15000
15062
 
15001
15063
  // src/platform/tui/hooks/useAgentState.ts
@@ -15009,6 +15071,8 @@ var useAgentState = () => {
15009
15071
  const [inputRequest, setInputRequest] = useState({ status: "inactive" });
15010
15072
  const [stats, setStats] = useState({ phase: DEFAULTS.INIT_PHASE, targets: 0, findings: 0, todo: 0 });
15011
15073
  const [turnCount, setTurnCount] = useState(0);
15074
+ const [liveReasoning, setLiveReasoning] = useState("");
15075
+ const [isReasoning, setIsReasoning] = useState(false);
15012
15076
  const lastResponseMetaRef = useRef(null);
15013
15077
  const startTimeRef = useRef(0);
15014
15078
  const timerRef = useRef(null);
@@ -15076,19 +15140,24 @@ var useAgentState = () => {
15076
15140
  setStats,
15077
15141
  turnCount,
15078
15142
  setTurnCount,
15079
- // Refs
15143
+ liveReasoning,
15144
+ setLiveReasoning,
15145
+ isReasoning,
15146
+ setIsReasoning,
15147
+ // Refs (external consumers only)
15080
15148
  lastResponseMetaRef,
15081
- timerRef,
15082
15149
  retryCountdownRef,
15083
15150
  retryCountRef,
15084
15151
  tokenAccumRef,
15085
15152
  lastStepTokensRef,
15153
+ toolStartedAtRef,
15154
+ // WHY timerRef excluded: internal to manageTimer/clearAllTimers only,
15155
+ // no external consumer exists.
15086
15156
  // Helpers
15087
15157
  addMessage,
15088
15158
  resetCumulativeCounters,
15089
15159
  manageTimer,
15090
- clearAllTimers,
15091
- toolStartedAtRef
15160
+ clearAllTimers
15092
15161
  };
15093
15162
  };
15094
15163
 
@@ -15267,6 +15336,13 @@ function createLifecycleHandlers(agent, state, _reasoningBufferRef) {
15267
15336
  const prefix = e.data.level === "error" ? "\u274C" : e.data.level === "warning" ? "\u26A0\uFE0F" : e.data.level === "success" ? "\u2705" : "\u{1F514}";
15268
15337
  addMessage("system", `${prefix} [${e.data.title}] ${e.data.message}`);
15269
15338
  };
15339
+ const onAuxiliaryWorkStart = (e) => {
15340
+ const msg = e.data.type === "context_extraction" ? "Compressing context..." : "Reflecting on actions...";
15341
+ setCurrentStatus(msg);
15342
+ };
15343
+ const onAuxiliaryWorkEnd = () => {
15344
+ setCurrentStatus("");
15345
+ };
15270
15346
  return {
15271
15347
  onComplete,
15272
15348
  onRetry,
@@ -15276,19 +15352,24 @@ function createLifecycleHandlers(agent, state, _reasoningBufferRef) {
15276
15352
  onUsageUpdate,
15277
15353
  onFlagFound,
15278
15354
  onPhaseChange,
15279
- onNotification
15355
+ onNotification,
15356
+ onAuxiliaryWorkStart,
15357
+ onAuxiliaryWorkEnd
15280
15358
  };
15281
15359
  }
15282
15360
 
15283
15361
  // src/platform/tui/hooks/useAgentEvents/handlers/reasoning.ts
15284
15362
  function createReasoningHandlers(state, reasoningBufferRef) {
15285
- const { addMessage, setCurrentStatus } = state;
15363
+ const { addMessage, setCurrentStatus, setLiveReasoning, setIsReasoning } = state;
15286
15364
  const onStart = () => {
15287
15365
  reasoningBufferRef.current = "";
15366
+ setLiveReasoning("");
15367
+ setIsReasoning(true);
15288
15368
  setCurrentStatus("Reasoning\u2026");
15289
15369
  };
15290
15370
  const onDelta = (e) => {
15291
15371
  reasoningBufferRef.current += e.data.content;
15372
+ setLiveReasoning(reasoningBufferRef.current);
15292
15373
  const chars = reasoningBufferRef.current.length;
15293
15374
  const estTokens = Math.round(chars / LLM_LIMITS.charsPerTokenEstimate);
15294
15375
  const firstLine = reasoningBufferRef.current.split("\n")[0]?.slice(0, TUI_DISPLAY_LIMITS.reasoningPreviewChars) || "";
@@ -15298,6 +15379,8 @@ ${firstLine}`);
15298
15379
  const onEnd = () => {
15299
15380
  const text = reasoningBufferRef.current.trim();
15300
15381
  reasoningBufferRef.current = "";
15382
+ setIsReasoning(false);
15383
+ setLiveReasoning("");
15301
15384
  setCurrentStatus("");
15302
15385
  if (text) {
15303
15386
  addMessage("thinking", text);
@@ -15392,7 +15475,9 @@ var useAgentEvents = (agent, eventsRef, state) => {
15392
15475
  tokenAccumRef,
15393
15476
  lastStepTokensRef,
15394
15477
  lastResponseMetaRef,
15395
- setCurrentTokens
15478
+ setCurrentTokens,
15479
+ setLiveReasoning,
15480
+ setIsReasoning
15396
15481
  } = state;
15397
15482
  const reasoningBufferRef = useRef2("");
15398
15483
  useEffect(() => {
@@ -15410,7 +15495,10 @@ var useAgentEvents = (agent, eventsRef, state) => {
15410
15495
  tokenAccumRef,
15411
15496
  lastStepTokensRef
15412
15497
  }, reasoningBufferRef);
15413
- const reasoningHandlers = createReasoningHandlers({ addMessage, setCurrentStatus }, reasoningBufferRef);
15498
+ const reasoningHandlers = createReasoningHandlers(
15499
+ { addMessage, setCurrentStatus, setLiveReasoning, setIsReasoning },
15500
+ reasoningBufferRef
15501
+ );
15414
15502
  const cleanupInput = setupInputHandlers(setInputRequest, addMessage);
15415
15503
  const cleanupCommand = setupCommandHandlers(addMessage, setCurrentStatus);
15416
15504
  const updateStats = () => {
@@ -15432,6 +15520,8 @@ var useAgentEvents = (agent, eventsRef, state) => {
15432
15520
  events.on(EVENT_TYPES.FLAG_FOUND, lifecycleHandlers.onFlagFound);
15433
15521
  events.on(EVENT_TYPES.PHASE_CHANGE, lifecycleHandlers.onPhaseChange);
15434
15522
  events.on(EVENT_TYPES.NOTIFICATION, lifecycleHandlers.onNotification);
15523
+ events.on(EVENT_TYPES.AUXILIARY_WORK_START, lifecycleHandlers.onAuxiliaryWorkStart);
15524
+ events.on(EVENT_TYPES.AUXILIARY_WORK_END, lifecycleHandlers.onAuxiliaryWorkEnd);
15435
15525
  events.on(EVENT_TYPES.STATE_CHANGE, updateStats);
15436
15526
  events.on(EVENT_TYPES.START, updateStats);
15437
15527
  events.on(EVENT_TYPES.REASONING_START, reasoningHandlers.onStart);
@@ -15460,7 +15550,9 @@ var useAgentEvents = (agent, eventsRef, state) => {
15460
15550
  lastStepTokensRef,
15461
15551
  clearAllTimers,
15462
15552
  toolStartedAtRef,
15463
- eventsRef
15553
+ eventsRef,
15554
+ setLiveReasoning,
15555
+ setIsReasoning
15464
15556
  ]);
15465
15557
  };
15466
15558
 
@@ -15488,7 +15580,9 @@ var useAgent = (shouldAutoApprove, target) => {
15488
15580
  manageTimer,
15489
15581
  resetCumulativeCounters,
15490
15582
  turnCount,
15491
- setTurnCount
15583
+ setTurnCount,
15584
+ liveReasoning,
15585
+ isReasoning
15492
15586
  } = state;
15493
15587
  useEffect2(() => {
15494
15588
  if (target) {
@@ -15499,30 +15593,46 @@ var useAgent = (shouldAutoApprove, target) => {
15499
15593
  useAgentEvents(agent, eventsRef, state);
15500
15594
  const abortedRef = useRef3(false);
15501
15595
  const executeTask = useCallback2(async (task) => {
15502
- abortedRef.current = false;
15503
- setTurnCount((n) => n + 1);
15504
- setIsProcessing(true);
15505
- manageTimer("start");
15506
- setCurrentStatus("Thinking");
15507
- resetCumulativeCounters();
15508
- try {
15509
- const response = await agent.execute(task);
15510
- if (abortedRef.current) return;
15511
- const meta = lastResponseMetaRef.current;
15512
- const suffix = meta ? ` ${formatMeta(meta.durationMs || 0, (meta.tokens?.input || 0) + (meta.tokens?.output || 0))}` : "";
15513
- addMessage("ai", response + suffix);
15514
- } catch (e) {
15515
- if (!abortedRef.current) {
15596
+ let currentTask = task;
15597
+ while (true) {
15598
+ abortedRef.current = false;
15599
+ setTurnCount((n) => n + 1);
15600
+ setIsProcessing(true);
15601
+ manageTimer("start");
15602
+ setCurrentStatus("Thinking");
15603
+ resetCumulativeCounters();
15604
+ try {
15605
+ const response = await agent.execute(currentTask);
15606
+ if (abortedRef.current) {
15607
+ if (agent.hasPendingUserInput()) {
15608
+ currentTask = "";
15609
+ continue;
15610
+ }
15611
+ return;
15612
+ }
15613
+ const meta = lastResponseMetaRef.current;
15614
+ const suffix = meta ? ` ${formatMeta(meta.durationMs || 0, (meta.tokens?.input || 0) + (meta.tokens?.output || 0))}` : "";
15615
+ addMessage("ai", response + suffix);
15616
+ break;
15617
+ } catch (e) {
15618
+ if (abortedRef.current) {
15619
+ if (agent.hasPendingUserInput()) {
15620
+ currentTask = "";
15621
+ continue;
15622
+ }
15623
+ return;
15624
+ }
15516
15625
  addMessage("error", e instanceof Error ? e.message : String(e));
15517
- }
15518
- } finally {
15519
- if (!abortedRef.current) {
15520
- manageTimer("stop");
15521
- setIsProcessing(false);
15522
- setCurrentStatus("");
15626
+ break;
15627
+ } finally {
15628
+ if (!abortedRef.current) {
15629
+ manageTimer("stop");
15630
+ setIsProcessing(false);
15631
+ setCurrentStatus("");
15632
+ }
15523
15633
  }
15524
15634
  }
15525
- }, [agent, addMessage, manageTimer, resetCumulativeCounters, setIsProcessing, lastResponseMetaRef, setCurrentStatus]);
15635
+ }, [agent, addMessage, manageTimer, resetCumulativeCounters, setIsProcessing, lastResponseMetaRef, setCurrentStatus, setTurnCount]);
15526
15636
  const abort = useCallback2(() => {
15527
15637
  abortedRef.current = true;
15528
15638
  agent.abort();
@@ -15569,12 +15679,14 @@ var useAgent = (shouldAutoApprove, target) => {
15569
15679
  abort,
15570
15680
  cancelInputRequest,
15571
15681
  addMessage,
15572
- refreshStats
15682
+ refreshStats,
15683
+ liveReasoning,
15684
+ isReasoning
15573
15685
  };
15574
15686
  };
15575
15687
 
15576
15688
  // src/platform/tui/hooks/commands/index.ts
15577
- import { useCallback as useCallback3 } from "react";
15689
+ import { useCallback as useCallback3, useMemo } from "react";
15578
15690
 
15579
15691
  // src/platform/tui/constants/commands.ts
15580
15692
  var COMMAND_DEFINITIONS = [
@@ -15681,7 +15793,7 @@ var createTargetCommands = (ctx) => ({
15681
15793
  ctx.addMessage("error", "Usage: /target <ip>");
15682
15794
  return;
15683
15795
  }
15684
- if (ctx.agent.getState().getTargets().size > 0) {
15796
+ if (ctx.agent.getState().hasActiveEngagement()) {
15685
15797
  await ctx.agent.resetSession();
15686
15798
  ctx.addMessage("system", "Previous target data cleared. Starting fresh session for the new target.");
15687
15799
  }
@@ -15703,8 +15815,8 @@ var createTargetCommands = (ctx) => ({
15703
15815
  ctx.addMessage("system", `Target \u2192 ${args[0]}`);
15704
15816
  },
15705
15817
  [UI_COMMANDS.START]: async (args) => {
15706
- if (!ctx.agent.getState().getTargets().size) {
15707
- ctx.addMessage("error", "Set target first: /target <ip>");
15818
+ if (!ctx.agent.getState().hasActiveEngagement()) {
15819
+ ctx.addMessage("error", "Set a target first: /target <ip>, or ask me to perform a specific task.");
15708
15820
  return;
15709
15821
  }
15710
15822
  if (!ctx.autoApproveModeRef.current) {
@@ -15718,8 +15830,8 @@ var createTargetCommands = (ctx) => ({
15718
15830
  await ctx.executeTask(args.join(" ") || `Perform comprehensive penetration testing${targetInfo}`);
15719
15831
  },
15720
15832
  [UI_COMMANDS.START_SHORT]: async (args) => {
15721
- if (!ctx.agent.getState().getTargets().size) {
15722
- ctx.addMessage("error", "Set target first: /target <ip>");
15833
+ if (!ctx.agent.getState().hasActiveEngagement()) {
15834
+ ctx.addMessage("error", "Set a target first: /target <ip>, or ask me to perform a specific task.");
15723
15835
  return;
15724
15836
  }
15725
15837
  if (!ctx.autoApproveModeRef.current) {
@@ -16061,7 +16173,7 @@ var createToggleCommands = (ctx) => ({
16061
16173
 
16062
16174
  // src/platform/tui/hooks/commands/index.ts
16063
16175
  var useCommands = (props) => {
16064
- const ctx = {
16176
+ const ctx = useMemo(() => ({
16065
16177
  agent: props.agent,
16066
16178
  addMessage: props.addMessage,
16067
16179
  showModal: props.showModal,
@@ -16072,13 +16184,24 @@ var useCommands = (props) => {
16072
16184
  handleExit: props.handleExit,
16073
16185
  isProcessingRef: props.isProcessingRef,
16074
16186
  autoApproveModeRef: props.autoApproveModeRef
16075
- };
16076
- const handlers = {
16187
+ }), [
16188
+ props.agent,
16189
+ props.addMessage,
16190
+ props.showModal,
16191
+ props.setMessages,
16192
+ props.executeTask,
16193
+ props.refreshStats,
16194
+ props.setAutoApproveMode,
16195
+ props.handleExit,
16196
+ props.isProcessingRef,
16197
+ props.autoApproveModeRef
16198
+ ]);
16199
+ const handlers = useMemo(() => ({
16077
16200
  ...createSessionCommands(ctx),
16078
16201
  ...createTargetCommands(ctx),
16079
16202
  ...createDisplayCommands(ctx),
16080
16203
  ...createToggleCommands(ctx)
16081
- };
16204
+ }), [ctx]);
16082
16205
  const handleCommand = useCallback3(async (cmd, args) => {
16083
16206
  const handler = handlers[cmd];
16084
16207
  if (handler) {
@@ -16246,41 +16369,58 @@ var AnimationProvider = ({ children }) => {
16246
16369
  var useAnimationTick = () => useContext(AnimationContext);
16247
16370
 
16248
16371
  // src/platform/tui/components/MessageList.tsx
16249
- import { memo as memo7 } from "react";
16250
- import { Box as Box8, Static } from "ink";
16372
+ import { memo as memo8 } from "react";
16373
+ import { Box as Box9, Static } from "ink";
16251
16374
 
16252
16375
  // src/platform/tui/components/messages/ThinkingBlock.tsx
16253
16376
  import { memo } from "react";
16254
16377
  import { Box, Text } from "ink";
16255
16378
  import { jsx as jsx2, jsxs } from "react/jsx-runtime";
16256
- var THINKING_PREVIEW_LINES = 3;
16257
16379
  var ThinkingBlock = memo(({ msg }) => {
16258
16380
  const lines = msg.content.split("\n");
16259
- const charCount = msg.content.length;
16260
- const estTokens = Math.round(charCount / LLM_LIMITS.charsPerTokenEstimate);
16261
- const hiddenCount = lines.length - THINKING_PREVIEW_LINES;
16262
- const visibleLines = lines.slice(0, THINKING_PREVIEW_LINES);
16381
+ const estTokens = Math.round(msg.content.length / LLM_LIMITS.charsPerTokenEstimate);
16263
16382
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 0, children: [
16264
16383
  /* @__PURE__ */ jsxs(Box, { children: [
16265
- /* @__PURE__ */ jsx2(Text, { color: THEME.dimGray, children: " \u25C6 " }),
16266
- /* @__PURE__ */ jsx2(Text, { color: THEME.gray, children: "Reasoning" }),
16267
- /* @__PURE__ */ jsx2(Text, { color: THEME.dimGray, children: ` (~${estTokens} tokens)` }),
16268
- hiddenCount > 0 && /* @__PURE__ */ jsx2(Text, { color: THEME.dimGray, children: ` [+${hiddenCount} lines]` })
16384
+ /* @__PURE__ */ jsx2(Text, { color: THEME.dimGray, children: "\u25C6 " }),
16385
+ /* @__PURE__ */ jsx2(Text, { color: THEME.gray, bold: true, children: "Reasoning" }),
16386
+ /* @__PURE__ */ jsx2(Text, { color: THEME.dimGray, children: ` ~${estTokens} tok ${lines.length} lines` })
16269
16387
  ] }),
16270
- visibleLines.map((line, i) => /* @__PURE__ */ jsxs(Box, { children: [
16271
- /* @__PURE__ */ jsx2(Text, { dimColor: true, children: " \u2502 " }),
16272
- /* @__PURE__ */ jsx2(Text, { dimColor: true, children: line })
16388
+ lines.map((line, i) => /* @__PURE__ */ jsxs(Box, { children: [
16389
+ /* @__PURE__ */ jsx2(Text, { color: THEME.dimGray, children: "\u2502 " }),
16390
+ /* @__PURE__ */ jsx2(Text, { color: THEME.dimGray, wrap: "truncate", children: line || " " })
16273
16391
  ] }, i)),
16274
- hiddenCount > 0 && /* @__PURE__ */ jsxs(Box, { children: [
16275
- /* @__PURE__ */ jsx2(Text, { dimColor: true, children: " \u2502 " }),
16276
- /* @__PURE__ */ jsx2(Text, { dimColor: true, children: "..." })
16392
+ /* @__PURE__ */ jsx2(Box, { children: /* @__PURE__ */ jsx2(Text, { color: THEME.dimGray, children: "\u2575" }) })
16393
+ ] });
16394
+ });
16395
+
16396
+ // src/platform/tui/components/messages/LiveReasoningPanel.tsx
16397
+ import { memo as memo2 } from "react";
16398
+ import { Box as Box2, Text as Text2 } from "ink";
16399
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
16400
+ var LiveReasoningPanel = memo2(({ content, isReasoning }) => {
16401
+ if (!isReasoning) return null;
16402
+ const lines = content.split("\n");
16403
+ const estTokens = Math.round(content.length / LLM_LIMITS.charsPerTokenEstimate);
16404
+ return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", marginY: 0, children: [
16405
+ /* @__PURE__ */ jsxs2(Box2, { children: [
16406
+ /* @__PURE__ */ jsx3(Text2, { color: THEME.yellow, children: "\u27F3 " }),
16407
+ /* @__PURE__ */ jsx3(Text2, { color: THEME.yellow, bold: true, children: "Reasoning" }),
16408
+ /* @__PURE__ */ jsx3(Text2, { color: THEME.dimGray, children: ` ~${estTokens} tok ${lines.length} lines streaming\u2026` })
16409
+ ] }),
16410
+ lines.map((line, i) => /* @__PURE__ */ jsxs2(Box2, { children: [
16411
+ /* @__PURE__ */ jsx3(Text2, { color: THEME.dimGray, children: "\u2502 " }),
16412
+ /* @__PURE__ */ jsx3(Text2, { color: THEME.gray, wrap: "truncate", children: line || " " })
16413
+ ] }, i)),
16414
+ /* @__PURE__ */ jsxs2(Box2, { children: [
16415
+ /* @__PURE__ */ jsx3(Text2, { color: THEME.dimGray, children: "\u2502 " }),
16416
+ /* @__PURE__ */ jsx3(Text2, { color: THEME.yellow, children: "\u258C" })
16277
16417
  ] })
16278
16418
  ] });
16279
16419
  });
16280
16420
 
16281
16421
  // src/platform/tui/components/messages/MessageRow.tsx
16282
- import { memo as memo4 } from "react";
16283
- import { Box as Box5, Text as Text5 } from "ink";
16422
+ import { memo as memo5 } from "react";
16423
+ import { Box as Box6, Text as Text6 } from "ink";
16284
16424
 
16285
16425
  // src/platform/tui/constants/styles.ts
16286
16426
  var MESSAGE_STYLES = {
@@ -16317,10 +16457,16 @@ var MESSAGE_STYLES = {
16317
16457
  // Thinking/reasoning icon
16318
16458
  }
16319
16459
  };
16460
+ var UI_MESSAGES = {
16461
+ /** Shown when user sends a message while agent is processing */
16462
+ QUEUED: "\u{1F4AC} Message queued \u2014 will be processed at next iteration",
16463
+ /** Prefix for masked secret input in message history */
16464
+ SECRET_PREFIX: "\u21B3 "
16465
+ };
16320
16466
 
16321
16467
  // src/platform/tui/components/inline-status.tsx
16322
- import { Box as Box2, Text as Text2 } from "ink";
16323
- import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
16468
+ import { Box as Box3, Text as Text3 } from "ink";
16469
+ import { Fragment, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
16324
16470
  function formatDuration3(ms) {
16325
16471
  const seconds = Math.floor(ms / 1e3);
16326
16472
  if (seconds < 60) return `${seconds}s`;
@@ -16346,18 +16492,18 @@ function getRoleColor(role) {
16346
16492
  }
16347
16493
  function StatusIndicator({ isRunning, exitCode }) {
16348
16494
  if (isRunning) {
16349
- return /* @__PURE__ */ jsxs2(Text2, { color: THEME.primary, children: [
16495
+ return /* @__PURE__ */ jsxs3(Text3, { color: THEME.primary, children: [
16350
16496
  ICONS.running,
16351
16497
  " "
16352
16498
  ] });
16353
16499
  }
16354
16500
  if (exitCode === 0) {
16355
- return /* @__PURE__ */ jsxs2(Text2, { color: THEME.gray, children: [
16501
+ return /* @__PURE__ */ jsxs3(Text3, { color: THEME.gray, children: [
16356
16502
  ICONS.success,
16357
16503
  " "
16358
16504
  ] });
16359
16505
  }
16360
- return /* @__PURE__ */ jsxs2(Text2, { color: THEME.red, children: [
16506
+ return /* @__PURE__ */ jsxs3(Text3, { color: THEME.red, children: [
16361
16507
  ICONS.error,
16362
16508
  " "
16363
16509
  ] });
@@ -16367,26 +16513,26 @@ function ProcessRow({ proc, isCompact }) {
16367
16513
  const port = proc.listeningPort ? `:${proc.listeningPort}` : "";
16368
16514
  const purpose = proc.purpose || proc.description || "";
16369
16515
  const truncatedPurpose = isCompact && purpose.length > TUI_DISPLAY_LIMITS.purposeMaxLength ? purpose.slice(0, TUI_DISPLAY_LIMITS.purposeTruncated) + "..." : purpose;
16370
- return /* @__PURE__ */ jsxs2(Box2, { children: [
16371
- /* @__PURE__ */ jsx3(StatusIndicator, { isRunning: proc.isRunning, exitCode: proc.exitCode }),
16372
- /* @__PURE__ */ jsxs2(Text2, { color: THEME.gray, children: [
16516
+ return /* @__PURE__ */ jsxs3(Box3, { children: [
16517
+ /* @__PURE__ */ jsx4(StatusIndicator, { isRunning: proc.isRunning, exitCode: proc.exitCode }),
16518
+ /* @__PURE__ */ jsxs3(Text3, { color: THEME.gray, children: [
16373
16519
  "[",
16374
16520
  proc.id,
16375
16521
  "]"
16376
16522
  ] }),
16377
- /* @__PURE__ */ jsx3(Text2, { children: " " }),
16378
- /* @__PURE__ */ jsxs2(Text2, { color: getRoleColor(proc.role), bold: true, children: [
16523
+ /* @__PURE__ */ jsx4(Text3, { children: " " }),
16524
+ /* @__PURE__ */ jsxs3(Text3, { color: getRoleColor(proc.role), bold: true, children: [
16379
16525
  proc.role,
16380
16526
  port
16381
16527
  ] }),
16382
- /* @__PURE__ */ jsxs2(Text2, { color: THEME.gray, children: [
16528
+ /* @__PURE__ */ jsxs3(Text3, { color: THEME.gray, children: [
16383
16529
  " (",
16384
16530
  duration,
16385
16531
  ")"
16386
16532
  ] }),
16387
- truncatedPurpose && /* @__PURE__ */ jsxs2(Fragment, { children: [
16388
- /* @__PURE__ */ jsx3(Text2, { color: THEME.gray, children: " - " }),
16389
- /* @__PURE__ */ jsx3(Text2, { color: THEME.gray, children: truncatedPurpose })
16533
+ truncatedPurpose && /* @__PURE__ */ jsxs3(Fragment, { children: [
16534
+ /* @__PURE__ */ jsx4(Text3, { color: THEME.gray, children: " - " }),
16535
+ /* @__PURE__ */ jsx4(Text3, { color: THEME.gray, children: truncatedPurpose })
16390
16536
  ] })
16391
16537
  ] });
16392
16538
  }
@@ -16397,7 +16543,7 @@ var InlineStatus = ({
16397
16543
  isCompact = true
16398
16544
  }) => {
16399
16545
  if (processes.length === 0 && zombies.length === 0) {
16400
- return /* @__PURE__ */ jsx3(Box2, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsx3(Text2, { color: THEME.gray, children: "\u2022 No active background processes" }) });
16546
+ return /* @__PURE__ */ jsx4(Box3, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsx4(Text3, { color: THEME.gray, children: "\u2022 No active background processes" }) });
16401
16547
  }
16402
16548
  const running = processes.filter((p) => p.isRunning);
16403
16549
  const stopped = processes.filter((p) => !p.isRunning);
@@ -16406,66 +16552,66 @@ var InlineStatus = ({
16406
16552
  warning: THEME.yellow,
16407
16553
  critical: THEME.red
16408
16554
  }[health];
16409
- return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", marginBottom: 1, children: [
16410
- running.length > 0 && /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
16411
- /* @__PURE__ */ jsxs2(Text2, { color: THEME.gray, bold: true, children: [
16555
+ return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", marginBottom: 1, children: [
16556
+ running.length > 0 && /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
16557
+ /* @__PURE__ */ jsxs3(Text3, { color: THEME.gray, bold: true, children: [
16412
16558
  ICONS.running,
16413
16559
  " Active (",
16414
16560
  running.length,
16415
16561
  ")"
16416
16562
  ] }),
16417
- running.map((proc) => /* @__PURE__ */ jsx3(ProcessRow, { proc, isCompact }, proc.id))
16563
+ running.map((proc) => /* @__PURE__ */ jsx4(ProcessRow, { proc, isCompact }, proc.id))
16418
16564
  ] }),
16419
- stopped.length > 0 && !isCompact && /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", marginTop: running.length > 0 ? 1 : 0, children: [
16420
- /* @__PURE__ */ jsxs2(Text2, { color: THEME.gray, children: [
16565
+ stopped.length > 0 && !isCompact && /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", marginTop: running.length > 0 ? 1 : 0, children: [
16566
+ /* @__PURE__ */ jsxs3(Text3, { color: THEME.gray, children: [
16421
16567
  ICONS.completed,
16422
16568
  " Completed (",
16423
16569
  stopped.length,
16424
16570
  ")"
16425
16571
  ] }),
16426
- stopped.slice(0, TUI_DISPLAY_LIMITS.maxStoppedProcesses).map((proc) => /* @__PURE__ */ jsx3(ProcessRow, { proc, isCompact }, proc.id)),
16427
- stopped.length > TUI_DISPLAY_LIMITS.maxStoppedProcesses && /* @__PURE__ */ jsxs2(Text2, { color: THEME.gray, children: [
16572
+ stopped.slice(0, TUI_DISPLAY_LIMITS.maxStoppedProcesses).map((proc) => /* @__PURE__ */ jsx4(ProcessRow, { proc, isCompact }, proc.id)),
16573
+ stopped.length > TUI_DISPLAY_LIMITS.maxStoppedProcesses && /* @__PURE__ */ jsxs3(Text3, { color: THEME.gray, children: [
16428
16574
  " ... and ",
16429
16575
  stopped.length - TUI_DISPLAY_LIMITS.maxStoppedProcesses,
16430
16576
  " more"
16431
16577
  ] })
16432
16578
  ] }),
16433
- zombies.length > 0 && /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", marginTop: 1, children: [
16434
- /* @__PURE__ */ jsxs2(Text2, { color: THEME.yellow, children: [
16579
+ zombies.length > 0 && /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", marginTop: 1, children: [
16580
+ /* @__PURE__ */ jsxs3(Text3, { color: THEME.yellow, children: [
16435
16581
  ICONS.warning,
16436
16582
  " Zombie Processes (",
16437
16583
  zombies.length,
16438
16584
  ")"
16439
16585
  ] }),
16440
- zombies.map((z) => /* @__PURE__ */ jsxs2(Box2, { children: [
16441
- /* @__PURE__ */ jsxs2(Text2, { color: THEME.red, children: [
16586
+ zombies.map((z) => /* @__PURE__ */ jsxs3(Box3, { children: [
16587
+ /* @__PURE__ */ jsxs3(Text3, { color: THEME.red, children: [
16442
16588
  " ",
16443
16589
  ICONS.error,
16444
16590
  " "
16445
16591
  ] }),
16446
- /* @__PURE__ */ jsxs2(Text2, { color: THEME.gray, children: [
16592
+ /* @__PURE__ */ jsxs3(Text3, { color: THEME.gray, children: [
16447
16593
  "[",
16448
16594
  z.processId,
16449
16595
  "] "
16450
16596
  ] }),
16451
- /* @__PURE__ */ jsxs2(Text2, { color: THEME.yellow, children: [
16597
+ /* @__PURE__ */ jsxs3(Text3, { color: THEME.yellow, children: [
16452
16598
  z.orphanedChildren.length,
16453
16599
  " orphaned children"
16454
16600
  ] })
16455
16601
  ] }, z.processId)),
16456
- /* @__PURE__ */ jsx3(Text2, { color: THEME.gray, children: " Run /cleanup to terminate" })
16602
+ /* @__PURE__ */ jsx4(Text3, { color: THEME.gray, children: " Run /cleanup to terminate" })
16457
16603
  ] }),
16458
- /* @__PURE__ */ jsxs2(Box2, { marginTop: running.length > 0 ? 1 : 0, children: [
16459
- /* @__PURE__ */ jsx3(Text2, { color: THEME.gray, children: "Health: " }),
16460
- /* @__PURE__ */ jsx3(Text2, { color: healthColor, bold: true, children: health.toUpperCase() })
16604
+ /* @__PURE__ */ jsxs3(Box3, { marginTop: running.length > 0 ? 1 : 0, children: [
16605
+ /* @__PURE__ */ jsx4(Text3, { color: THEME.gray, children: "Health: " }),
16606
+ /* @__PURE__ */ jsx4(Text3, { color: healthColor, bold: true, children: health.toUpperCase() })
16461
16607
  ] })
16462
16608
  ] });
16463
16609
  };
16464
16610
 
16465
16611
  // src/platform/tui/components/ToolCard.tsx
16466
- import { memo as memo2 } from "react";
16467
- import { Box as Box3, Text as Text3 } from "ink";
16468
- import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
16612
+ import { memo as memo3 } from "react";
16613
+ import { Box as Box4, Text as Text4 } from "ink";
16614
+ import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
16469
16615
  var ARGS_MAX = 72;
16470
16616
  function truncate(s, max) {
16471
16617
  return s.length > max ? s.slice(0, max - 1) + "\u2026" : s;
@@ -16507,23 +16653,23 @@ function parseToolContent(content) {
16507
16653
  }
16508
16654
  return { name: content.trim(), args: "" };
16509
16655
  }
16510
- var ToolCard = memo2(({ content }) => {
16656
+ var ToolCard = memo3(({ content }) => {
16511
16657
  const { name, args } = parseToolContent(content);
16512
- return /* @__PURE__ */ jsxs3(Box3, { children: [
16513
- /* @__PURE__ */ jsx4(Text3, { color: THEME.primary, children: " \u2295 " }),
16514
- /* @__PURE__ */ jsx4(Text3, { color: THEME.white, bold: true, children: name }),
16515
- args && /* @__PURE__ */ jsxs3(Fragment2, { children: [
16516
- /* @__PURE__ */ jsx4(Text3, { color: THEME.dimGray, children: "(" }),
16517
- /* @__PURE__ */ jsx4(Text3, { color: THEME.gray, children: args }),
16518
- /* @__PURE__ */ jsx4(Text3, { color: THEME.dimGray, children: ")" })
16658
+ return /* @__PURE__ */ jsxs4(Box4, { children: [
16659
+ /* @__PURE__ */ jsx5(Text4, { color: THEME.primary, children: " \u2295 " }),
16660
+ /* @__PURE__ */ jsx5(Text4, { color: THEME.white, bold: true, children: name }),
16661
+ args && /* @__PURE__ */ jsxs4(Fragment2, { children: [
16662
+ /* @__PURE__ */ jsx5(Text4, { color: THEME.dimGray, children: "(" }),
16663
+ /* @__PURE__ */ jsx5(Text4, { color: THEME.gray, children: args }),
16664
+ /* @__PURE__ */ jsx5(Text4, { color: THEME.dimGray, children: ")" })
16519
16665
  ] })
16520
16666
  ] });
16521
16667
  });
16522
16668
 
16523
16669
  // src/platform/tui/components/MarkdownText.tsx
16524
- import { memo as memo3 } from "react";
16525
- import { Box as Box4, Text as Text4 } from "ink";
16526
- import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
16670
+ import { memo as memo4 } from "react";
16671
+ import { Box as Box5, Text as Text5 } from "ink";
16672
+ import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
16527
16673
  function tokenizeLine(line) {
16528
16674
  const tokens = [];
16529
16675
  let i = 0;
@@ -16547,14 +16693,14 @@ function tokenizeLine(line) {
16547
16693
  }
16548
16694
  return tokens;
16549
16695
  }
16550
- var InlineContent = ({ tokens }) => /* @__PURE__ */ jsx5(Fragment3, { children: tokens.map((tok, i) => {
16696
+ var InlineContent = ({ tokens }) => /* @__PURE__ */ jsx6(Fragment3, { children: tokens.map((tok, i) => {
16551
16697
  if (tok.type === "bold") {
16552
- return /* @__PURE__ */ jsx5(Text4, { bold: true, color: THEME.white, children: tok.value }, i);
16698
+ return /* @__PURE__ */ jsx6(Text5, { bold: true, color: THEME.white, children: tok.value }, i);
16553
16699
  }
16554
16700
  if (tok.type === "code") {
16555
- return /* @__PURE__ */ jsx5(Text4, { color: THEME.cyan, children: `\`${tok.value}\`` }, i);
16701
+ return /* @__PURE__ */ jsx6(Text5, { color: THEME.cyan, children: `\`${tok.value}\`` }, i);
16556
16702
  }
16557
- return /* @__PURE__ */ jsx5(Text4, { color: THEME.white, children: tok.value }, i);
16703
+ return /* @__PURE__ */ jsx6(Text5, { color: THEME.white, children: tok.value }, i);
16558
16704
  }) });
16559
16705
  function parseBlocks(lines) {
16560
16706
  const blocks = [];
@@ -16604,29 +16750,29 @@ function parseBlocks(lines) {
16604
16750
  }
16605
16751
  var BlockRenderer = ({ block, blockIdx }) => {
16606
16752
  if (block.type === "blank") {
16607
- return /* @__PURE__ */ jsx5(Text4, { children: " " }, blockIdx);
16753
+ return /* @__PURE__ */ jsx6(Text5, { children: " " }, blockIdx);
16608
16754
  }
16609
16755
  if (block.type === "heading") {
16610
16756
  const prefixes = { 1: "\u25B8 ", 2: " \u25B9 ", 3: " \xB7 " };
16611
16757
  const colors = { 1: THEME.primary, 2: THEME.cyan, 3: THEME.white };
16612
- return /* @__PURE__ */ jsx5(Box4, { children: /* @__PURE__ */ jsxs4(Text4, { color: colors[block.level], bold: true, children: [
16758
+ return /* @__PURE__ */ jsx6(Box5, { children: /* @__PURE__ */ jsxs5(Text5, { color: colors[block.level], bold: true, children: [
16613
16759
  prefixes[block.level],
16614
16760
  block.content
16615
16761
  ] }) }, blockIdx);
16616
16762
  }
16617
16763
  if (block.type === "listItem") {
16618
16764
  const bullet = block.ordered ? `${block.index}.` : "\u2022";
16619
- return /* @__PURE__ */ jsxs4(Box4, { paddingLeft: 1, children: [
16620
- /* @__PURE__ */ jsxs4(Text4, { color: THEME.dimGray, children: [
16765
+ return /* @__PURE__ */ jsxs5(Box5, { paddingLeft: 1, children: [
16766
+ /* @__PURE__ */ jsxs5(Text5, { color: THEME.dimGray, children: [
16621
16767
  bullet,
16622
16768
  " "
16623
16769
  ] }),
16624
- /* @__PURE__ */ jsx5(InlineContent, { tokens: tokenizeLine(block.content) })
16770
+ /* @__PURE__ */ jsx6(InlineContent, { tokens: tokenizeLine(block.content) })
16625
16771
  ] }, blockIdx);
16626
16772
  }
16627
16773
  if (block.type === "codeBlock") {
16628
- return /* @__PURE__ */ jsxs4(
16629
- Box4,
16774
+ return /* @__PURE__ */ jsxs5(
16775
+ Box5,
16630
16776
  {
16631
16777
  flexDirection: "column",
16632
16778
  borderStyle: "single",
@@ -16634,19 +16780,19 @@ var BlockRenderer = ({ block, blockIdx }) => {
16634
16780
  paddingX: 1,
16635
16781
  marginY: 0,
16636
16782
  children: [
16637
- block.lang && /* @__PURE__ */ jsx5(Text4, { color: THEME.dimGray, children: block.lang }),
16638
- block.lines.map((l, li) => /* @__PURE__ */ jsx5(Text4, { color: THEME.cyan, children: l }, li))
16783
+ block.lang && /* @__PURE__ */ jsx6(Text5, { color: THEME.dimGray, children: block.lang }),
16784
+ block.lines.map((l, li) => /* @__PURE__ */ jsx6(Text5, { color: THEME.cyan, children: l }, li))
16639
16785
  ]
16640
16786
  },
16641
16787
  blockIdx
16642
16788
  );
16643
16789
  }
16644
- return /* @__PURE__ */ jsx5(Box4, { children: /* @__PURE__ */ jsx5(InlineContent, { tokens: tokenizeLine(block.content) }) }, blockIdx);
16790
+ return /* @__PURE__ */ jsx6(Box5, { children: /* @__PURE__ */ jsx6(InlineContent, { tokens: tokenizeLine(block.content) }) }, blockIdx);
16645
16791
  };
16646
- var MarkdownText = memo3(({ content }) => {
16792
+ var MarkdownText = memo4(({ content }) => {
16647
16793
  const lines = content.split("\n");
16648
16794
  const blocks = parseBlocks(lines);
16649
- return /* @__PURE__ */ jsx5(Box4, { flexDirection: "column", children: blocks.map((block, i) => /* @__PURE__ */ jsx5(BlockRenderer, { block, blockIdx: i }, i)) });
16795
+ return /* @__PURE__ */ jsx6(Box5, { flexDirection: "column", children: blocks.map((block, i) => /* @__PURE__ */ jsx6(BlockRenderer, { block, blockIdx: i }, i)) });
16650
16796
  });
16651
16797
 
16652
16798
  // src/platform/tui/components/messages/parseStatusContent.ts
@@ -16693,12 +16839,12 @@ function computeResultDisplay(content) {
16693
16839
  }
16694
16840
 
16695
16841
  // src/platform/tui/components/messages/MessageRow.tsx
16696
- import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
16697
- var MessageRow = memo4(({ msg }) => {
16842
+ import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
16843
+ var MessageRow = memo5(({ msg }) => {
16698
16844
  if (msg.type === "status") {
16699
16845
  const statusData = parseStatusContent(msg.content);
16700
16846
  if (statusData) {
16701
- return /* @__PURE__ */ jsx6(Box5, { flexDirection: "column", children: /* @__PURE__ */ jsx6(
16847
+ return /* @__PURE__ */ jsx7(Box6, { flexDirection: "column", children: /* @__PURE__ */ jsx7(
16702
16848
  InlineStatus,
16703
16849
  {
16704
16850
  processes: statusData.processes,
@@ -16707,147 +16853,150 @@ var MessageRow = memo4(({ msg }) => {
16707
16853
  }
16708
16854
  ) }, msg.id);
16709
16855
  }
16710
- return /* @__PURE__ */ jsxs5(Box5, { children: [
16711
- /* @__PURE__ */ jsx6(Text5, { dimColor: true, color: THEME.dimGray, children: " \xB7 " }),
16712
- /* @__PURE__ */ jsx6(Text5, { dimColor: true, color: THEME.gray, children: msg.content })
16856
+ return /* @__PURE__ */ jsxs6(Box6, { children: [
16857
+ /* @__PURE__ */ jsx7(Text6, { dimColor: true, color: THEME.dimGray, children: " \xB7 " }),
16858
+ /* @__PURE__ */ jsx7(Text6, { dimColor: true, color: THEME.gray, children: msg.content })
16713
16859
  ] }, msg.id);
16714
16860
  }
16715
16861
  if (msg.type === "thinking") {
16716
- return /* @__PURE__ */ jsx6(ThinkingBlock, { msg });
16862
+ return /* @__PURE__ */ jsx7(ThinkingBlock, { msg });
16717
16863
  }
16718
16864
  if (msg.type === "tool") {
16719
- return /* @__PURE__ */ jsx6(Box5, { children: /* @__PURE__ */ jsx6(ToolCard, { content: msg.content }) }, msg.id);
16865
+ return /* @__PURE__ */ jsx7(Box6, { children: /* @__PURE__ */ jsx7(ToolCard, { content: msg.content }) }, msg.id);
16720
16866
  }
16721
16867
  if (msg.type === "result") {
16722
16868
  const kind = classifyResult(msg.content);
16723
16869
  const color = kind === "success" ? THEME.primary : kind === "failure" ? THEME.red : kind === "warning" ? THEME.yellow : THEME.gray;
16724
16870
  const { firstLine, visibleRest, hasMore } = computeResultDisplay(msg.content);
16725
16871
  const hiddenCount = msg.content.split("\n").length - 1;
16726
- return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
16727
- /* @__PURE__ */ jsxs5(Box5, { children: [
16728
- /* @__PURE__ */ jsx6(Text5, { color: THEME.dimGray, children: " \u2514 " }),
16729
- /* @__PURE__ */ jsx6(Text5, { color, children: firstLine }),
16730
- hasMore && /* @__PURE__ */ jsx6(Text5, { dimColor: true, color: THEME.dimGray, children: ` [+${hiddenCount - RESULT_PREVIEW_LINES}]` })
16872
+ return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
16873
+ /* @__PURE__ */ jsxs6(Box6, { children: [
16874
+ /* @__PURE__ */ jsx7(Text6, { color: THEME.dimGray, children: " \u2514 " }),
16875
+ /* @__PURE__ */ jsx7(Text6, { color, children: firstLine }),
16876
+ hasMore && /* @__PURE__ */ jsx7(Text6, { dimColor: true, color: THEME.dimGray, children: ` [+${hiddenCount - RESULT_PREVIEW_LINES}]` })
16731
16877
  ] }),
16732
- visibleRest.map((line, i) => /* @__PURE__ */ jsxs5(Box5, { children: [
16733
- /* @__PURE__ */ jsx6(Text5, { color: THEME.dimGray, children: " " }),
16734
- /* @__PURE__ */ jsx6(Text5, { dimColor: true, color: THEME.gray, children: line })
16878
+ visibleRest.map((line, i) => /* @__PURE__ */ jsxs6(Box6, { children: [
16879
+ /* @__PURE__ */ jsx7(Text6, { color: THEME.dimGray, children: " " }),
16880
+ /* @__PURE__ */ jsx7(Text6, { dimColor: true, color: THEME.gray, children: line })
16735
16881
  ] }, i))
16736
16882
  ] }, msg.id);
16737
16883
  }
16738
16884
  if (msg.type === "ai" || msg.type === "assistant") {
16739
- return /* @__PURE__ */ jsx6(Box5, { flexDirection: "column", marginBottom: 0, children: /* @__PURE__ */ jsx6(MarkdownText, { content: msg.content }) }, msg.id);
16885
+ return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", marginBottom: 0, children: [
16886
+ /* @__PURE__ */ jsxs6(Box6, { children: [
16887
+ /* @__PURE__ */ jsx7(Text6, { color: THEME.primary, children: "\u25B8 " }),
16888
+ /* @__PURE__ */ jsx7(Text6, { color: THEME.gray, bold: true, children: "Response" })
16889
+ ] }),
16890
+ /* @__PURE__ */ jsx7(Box6, { paddingLeft: 2, children: /* @__PURE__ */ jsx7(MarkdownText, { content: msg.content }) })
16891
+ ] }, msg.id);
16740
16892
  }
16741
16893
  if (msg.type === "error") {
16742
16894
  const eLines = msg.content.split("\n");
16743
16895
  const eFirst = eLines[0] || msg.content;
16744
16896
  const eHidden = eLines.length - 1;
16745
- return /* @__PURE__ */ jsx6(Box5, { flexDirection: "column", children: /* @__PURE__ */ jsxs5(Box5, { children: [
16746
- /* @__PURE__ */ jsx6(Text5, { color: THEME.red, children: " \u2717 " }),
16747
- /* @__PURE__ */ jsx6(Text5, { color: THEME.red, children: eFirst }),
16748
- eHidden > 0 && /* @__PURE__ */ jsx6(Text5, { dimColor: true, color: THEME.dimGray, children: ` [+${eHidden}]` })
16897
+ return /* @__PURE__ */ jsx7(Box6, { flexDirection: "column", children: /* @__PURE__ */ jsxs6(Box6, { children: [
16898
+ /* @__PURE__ */ jsx7(Text6, { color: THEME.red, children: " \u2717 " }),
16899
+ /* @__PURE__ */ jsx7(Text6, { color: THEME.red, children: eFirst }),
16900
+ eHidden > 0 && /* @__PURE__ */ jsx7(Text6, { dimColor: true, color: THEME.dimGray, children: ` [+${eHidden}]` })
16749
16901
  ] }) }, msg.id);
16750
16902
  }
16751
16903
  if (msg.type === "user") {
16752
- return /* @__PURE__ */ jsxs5(Box5, { children: [
16753
- /* @__PURE__ */ jsx6(Text5, { color: THEME.primary, children: "\u276F " }),
16754
- /* @__PURE__ */ jsx6(Text5, { color: THEME.white, bold: true, children: msg.content })
16904
+ return /* @__PURE__ */ jsxs6(Box6, { children: [
16905
+ /* @__PURE__ */ jsx7(Text6, { color: THEME.primary, children: "\u276F " }),
16906
+ /* @__PURE__ */ jsx7(Text6, { color: THEME.white, bold: true, children: msg.content })
16755
16907
  ] }, msg.id);
16756
16908
  }
16757
16909
  if (msg.type === "system") {
16758
- return /* @__PURE__ */ jsxs5(Box5, { children: [
16759
- /* @__PURE__ */ jsx6(Text5, { dimColor: true, color: THEME.dimGray, children: " \xB7 " }),
16760
- /* @__PURE__ */ jsx6(Text5, { dimColor: true, color: THEME.gray, children: msg.content })
16910
+ return /* @__PURE__ */ jsxs6(Box6, { children: [
16911
+ /* @__PURE__ */ jsx7(Text6, { dimColor: true, color: THEME.dimGray, children: " \xB7 " }),
16912
+ /* @__PURE__ */ jsx7(Text6, { dimColor: true, color: THEME.gray, children: msg.content })
16761
16913
  ] }, msg.id);
16762
16914
  }
16763
- return /* @__PURE__ */ jsxs5(Box5, { children: [
16764
- /* @__PURE__ */ jsx6(Text5, { dimColor: true, color: THEME.dimGray, children: " \xB7 " }),
16765
- /* @__PURE__ */ jsx6(Text5, { color: MESSAGE_STYLES.colors[msg.type] ?? THEME.gray, children: msg.content })
16915
+ return /* @__PURE__ */ jsxs6(Box6, { children: [
16916
+ /* @__PURE__ */ jsx7(Text6, { dimColor: true, color: THEME.dimGray, children: " \xB7 " }),
16917
+ /* @__PURE__ */ jsx7(Text6, { color: MESSAGE_STYLES.colors[msg.type] ?? THEME.gray, children: msg.content })
16766
16918
  ] }, msg.id);
16767
16919
  });
16768
16920
 
16769
16921
  // src/platform/tui/components/messages/BrandingHeader.tsx
16770
- import { memo as memo6 } from "react";
16771
- import { Box as Box7, Text as Text7 } from "ink";
16922
+ import { memo as memo7 } from "react";
16923
+ import { Box as Box8, Text as Text8 } from "ink";
16772
16924
 
16773
16925
  // src/platform/tui/components/ShimmerBanner.tsx
16774
- import { memo as memo5 } from "react";
16775
- import { Box as Box6, Text as Text6 } from "ink";
16776
- import { jsx as jsx7 } from "react/jsx-runtime";
16777
- var ShimmerBanner = memo5(({ banner }) => {
16926
+ import { memo as memo6 } from "react";
16927
+ import { Box as Box7, Text as Text7 } from "ink";
16928
+ import { jsx as jsx8 } from "react/jsx-runtime";
16929
+ var ShimmerBanner = memo6(({ banner }) => {
16778
16930
  const lines = banner.split("\n").filter((l) => l.length > 0);
16779
- return /* @__PURE__ */ jsx7(Box6, { flexDirection: "column", children: lines.map((line, row) => /* @__PURE__ */ jsx7(Text6, { color: HEX.primary, children: line }, row)) });
16931
+ return /* @__PURE__ */ jsx8(Box7, { flexDirection: "column", children: lines.map((line, row) => /* @__PURE__ */ jsx8(Text7, { color: HEX.primary, children: line }, row)) });
16780
16932
  });
16781
16933
 
16782
16934
  // src/platform/tui/components/messages/BrandingHeader.tsx
16783
- import { Fragment as Fragment4, jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
16784
- var BrandingHeader = memo6(({ modelName, autoApproveMode, version, showGuide = false }) => {
16935
+ import { Fragment as Fragment4, jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
16936
+ var BrandingHeader = memo7(({ modelName, autoApproveMode, version, showGuide = false }) => {
16785
16937
  const autoLabel = autoApproveMode ? "ON" : "OFF";
16786
- const autoColor = autoApproveMode ? THEME.primary : THEME.gray;
16787
- return /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
16788
- /* @__PURE__ */ jsx8(ShimmerBanner, { banner: ASCII_BANNER }),
16789
- /* @__PURE__ */ jsxs6(Box7, { paddingLeft: 2, gap: 2, children: [
16790
- version && /* @__PURE__ */ jsx8(Text7, { color: THEME.dimGray, children: `v${version}` }),
16791
- modelName && /* @__PURE__ */ jsxs6(Text7, { color: THEME.dimGray, children: [
16792
- "\xB7",
16793
- " ",
16794
- /* @__PURE__ */ jsx8(Text7, { color: THEME.gray, children: modelName })
16938
+ const autoColor = autoApproveMode ? THEME.primary : THEME.dimGray;
16939
+ return /* @__PURE__ */ jsxs7(Box8, { flexDirection: "column", paddingBottom: 1, children: [
16940
+ /* @__PURE__ */ jsx9(ShimmerBanner, { banner: ASCII_BANNER }),
16941
+ /* @__PURE__ */ jsxs7(Box8, { gap: 1, paddingLeft: 1, children: [
16942
+ version && /* @__PURE__ */ jsx9(Text8, { color: THEME.dimGray, children: `v${version}` }),
16943
+ modelName && /* @__PURE__ */ jsxs7(Fragment4, { children: [
16944
+ /* @__PURE__ */ jsx9(Text8, { color: THEME.dimGray, children: "\xB7" }),
16945
+ /* @__PURE__ */ jsx9(Text8, { color: THEME.gray, children: modelName })
16795
16946
  ] }),
16796
- /* @__PURE__ */ jsxs6(Text7, { color: THEME.dimGray, children: [
16797
- "\xB7",
16798
- " Auto: ",
16799
- /* @__PURE__ */ jsx8(Text7, { color: autoColor, children: autoLabel })
16800
- ] })
16947
+ /* @__PURE__ */ jsx9(Text8, { color: THEME.dimGray, children: "\xB7" }),
16948
+ /* @__PURE__ */ jsx9(Text8, { color: THEME.dimGray, children: "Auto:" }),
16949
+ /* @__PURE__ */ jsx9(Text8, { color: autoColor, bold: !!autoApproveMode, children: autoLabel })
16801
16950
  ] }),
16802
- showGuide && /* @__PURE__ */ jsxs6(Fragment4, { children: [
16803
- /* @__PURE__ */ jsx8(Text7, { children: " " }),
16804
- /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", paddingLeft: 2, children: [
16805
- /* @__PURE__ */ jsx8(Text7, { color: THEME.gray, children: "Get started:" }),
16806
- /* @__PURE__ */ jsxs6(Text7, { color: THEME.gray, children: [
16807
- " ",
16808
- /* @__PURE__ */ jsxs6(Text7, { color: THEME.white, children: [
16809
- "/target ",
16810
- "<ip>"
16811
- ] }),
16812
- " \u2014 Set target IP or domain"
16951
+ showGuide && /* @__PURE__ */ jsxs7(Box8, { flexDirection: "column", paddingTop: 1, paddingLeft: 1, children: [
16952
+ /* @__PURE__ */ jsx9(Text8, { color: THEME.dimGray, children: "\u2500".repeat(40) }),
16953
+ /* @__PURE__ */ jsxs7(Box8, { flexDirection: "column", paddingTop: 0, children: [
16954
+ /* @__PURE__ */ jsxs7(Box8, { gap: 2, children: [
16955
+ /* @__PURE__ */ jsx9(Text8, { color: THEME.primary, children: "\u276F" }),
16956
+ /* @__PURE__ */ jsx9(Text8, { color: THEME.white, children: "/target <ip>" }),
16957
+ /* @__PURE__ */ jsx9(Text8, { color: THEME.dimGray, children: "Set a network target" })
16813
16958
  ] }),
16814
- /* @__PURE__ */ jsxs6(Text7, { color: THEME.gray, children: [
16815
- " ",
16816
- /* @__PURE__ */ jsx8(Text7, { color: THEME.white, children: "/start" }),
16817
- " \u2014 Begin autonomous pentest"
16959
+ /* @__PURE__ */ jsxs7(Box8, { gap: 2, children: [
16960
+ /* @__PURE__ */ jsx9(Text8, { color: THEME.primary, children: "\u276F" }),
16961
+ /* @__PURE__ */ jsx9(Text8, { color: THEME.white, children: "/start" }),
16962
+ /* @__PURE__ */ jsx9(Text8, { color: THEME.dimGray, children: " Begin autonomous pentest" })
16818
16963
  ] }),
16819
- /* @__PURE__ */ jsxs6(Text7, { color: THEME.gray, children: [
16820
- " ",
16821
- /* @__PURE__ */ jsx8(Text7, { color: THEME.white, children: "/help" }),
16822
- " \u2014 Show all commands"
16964
+ /* @__PURE__ */ jsxs7(Box8, { gap: 2, children: [
16965
+ /* @__PURE__ */ jsx9(Text8, { color: THEME.primary, children: "\u276F" }),
16966
+ /* @__PURE__ */ jsx9(Text8, { color: THEME.white, children: "/help" }),
16967
+ /* @__PURE__ */ jsx9(Text8, { color: THEME.dimGray, children: " Show all commands" })
16823
16968
  ] }),
16824
- /* @__PURE__ */ jsx8(Text7, { children: " " }),
16825
- /* @__PURE__ */ jsx8(Text7, { color: THEME.dimGray, children: "Or just type a task and press Enter." })
16969
+ /* @__PURE__ */ jsx9(Box8, { paddingTop: 1, children: /* @__PURE__ */ jsx9(Text8, { color: THEME.gray, children: 'Or type an objective (e.g. "Solve this python script").' }) })
16826
16970
  ] })
16827
16971
  ] })
16828
16972
  ] });
16829
16973
  });
16830
16974
 
16831
16975
  // src/platform/tui/components/MessageList.tsx
16832
- import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
16833
- var MessageList = memo7(({ messages, modelName, autoApproveMode, version }) => {
16834
- return /* @__PURE__ */ jsxs7(Box8, { flexDirection: "column", children: [
16835
- /* @__PURE__ */ jsx9(
16836
- BrandingHeader,
16837
- {
16838
- modelName,
16839
- autoApproveMode,
16840
- version,
16841
- showGuide: messages.length === 0
16842
- }
16843
- ),
16844
- messages.length > 0 && /* @__PURE__ */ jsx9(Static, { items: messages, children: (msg) => /* @__PURE__ */ jsx9(MessageRow, { msg }, msg.id) })
16845
- ] });
16976
+ import { jsx as jsx10 } from "react/jsx-runtime";
16977
+ var HEADER_ITEM = { id: "__header__", type: "header" };
16978
+ var MessageList = memo8(({ messages, modelName, autoApproveMode, version }) => {
16979
+ const staticItems = [HEADER_ITEM, ...messages];
16980
+ return /* @__PURE__ */ jsx10(Box9, { flexDirection: "column", children: /* @__PURE__ */ jsx10(Static, { items: staticItems, children: (item) => {
16981
+ if (item.type === "header") {
16982
+ return /* @__PURE__ */ jsx10(
16983
+ BrandingHeader,
16984
+ {
16985
+ modelName,
16986
+ autoApproveMode,
16987
+ version,
16988
+ showGuide: messages.length === 0
16989
+ },
16990
+ "__header__"
16991
+ );
16992
+ }
16993
+ return /* @__PURE__ */ jsx10(MessageRow, { msg: item }, item.id);
16994
+ } }) });
16846
16995
  });
16847
16996
 
16848
16997
  // src/platform/tui/components/StatusDisplay.tsx
16849
- import { memo as memo10 } from "react";
16850
- import { Box as Box11, Text as Text12 } from "ink";
16998
+ import { memo as memo11 } from "react";
16999
+ import { Box as Box12, Text as Text13 } from "ink";
16851
17000
 
16852
17001
  // src/platform/tui/hooks/useStatusTimer.ts
16853
17002
  import { useState as useState4, useEffect as useEffect6, useRef as useRef5 } from "react";
@@ -16875,12 +17024,12 @@ var useStatusTimer = (currentStatus, isProcessing) => {
16875
17024
  };
16876
17025
 
16877
17026
  // src/platform/tui/components/status/RetryView.tsx
16878
- import { Box as Box9, Text as Text9 } from "ink";
17027
+ import { Box as Box10, Text as Text10 } from "ink";
16879
17028
 
16880
17029
  // src/platform/tui/components/StarSpinner.tsx
16881
- import { memo as memo8 } from "react";
16882
- import { Text as Text8 } from "ink";
16883
- import { jsx as jsx10 } from "react/jsx-runtime";
17030
+ import { memo as memo9 } from "react";
17031
+ import { Text as Text9 } from "ink";
17032
+ import { jsx as jsx11 } from "react/jsx-runtime";
16884
17033
  var FRAMES = [
16885
17034
  "\xB7",
16886
17035
  "\u2726",
@@ -16897,34 +17046,34 @@ var FRAMES = [
16897
17046
  "\u2727",
16898
17047
  "\u2726"
16899
17048
  ];
16900
- var StarSpinner = memo8(({ color }) => {
17049
+ var StarSpinner = memo9(({ color }) => {
16901
17050
  const tick = useAnimationTick();
16902
17051
  const index = tick % FRAMES.length;
16903
- return /* @__PURE__ */ jsx10(Text8, { color: color || "yellow", children: FRAMES[index] });
17052
+ return /* @__PURE__ */ jsx11(Text9, { color: color || "yellow", children: FRAMES[index] });
16904
17053
  });
16905
17054
 
16906
17055
  // src/platform/tui/components/status/RetryView.tsx
16907
- import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
17056
+ import { jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
16908
17057
  var RetryView = ({ retryState }) => {
16909
17058
  const truncateError = (err) => {
16910
17059
  return err.length > DISPLAY_LIMITS.RETRY_ERROR_PREVIEW ? err.substring(0, DISPLAY_LIMITS.RETRY_ERROR_TRUNCATED) + "..." : err;
16911
17060
  };
16912
- return /* @__PURE__ */ jsxs8(Box9, { flexDirection: "column", height: 2, children: [
16913
- /* @__PURE__ */ jsxs8(Box9, { children: [
16914
- /* @__PURE__ */ jsx11(Text9, { color: THEME.yellow, wrap: "truncate", children: /* @__PURE__ */ jsx11(StarSpinner, { color: THEME.yellow }) }),
16915
- /* @__PURE__ */ jsxs8(Text9, { color: THEME.yellow, bold: true, wrap: "truncate", children: [
17061
+ return /* @__PURE__ */ jsxs8(Box10, { flexDirection: "column", height: 2, children: [
17062
+ /* @__PURE__ */ jsxs8(Box10, { children: [
17063
+ /* @__PURE__ */ jsx12(Text10, { color: THEME.yellow, wrap: "truncate", children: /* @__PURE__ */ jsx12(StarSpinner, { color: THEME.yellow }) }),
17064
+ /* @__PURE__ */ jsxs8(Text10, { color: THEME.yellow, bold: true, wrap: "truncate", children: [
16916
17065
  " \u29F3 Retry #",
16917
17066
  retryState.attempt,
16918
17067
  "/",
16919
17068
  retryState.maxRetries
16920
17069
  ] }),
16921
- /* @__PURE__ */ jsxs8(Text9, { color: THEME.gray, wrap: "truncate", children: [
17070
+ /* @__PURE__ */ jsxs8(Text10, { color: THEME.gray, wrap: "truncate", children: [
16922
17071
  " \u2014 ",
16923
17072
  retryState.countdown,
16924
17073
  "s"
16925
17074
  ] })
16926
17075
  ] }),
16927
- /* @__PURE__ */ jsx11(Box9, { children: /* @__PURE__ */ jsxs8(Text9, { color: THEME.gray, wrap: "truncate", children: [
17076
+ /* @__PURE__ */ jsx12(Box10, { children: /* @__PURE__ */ jsxs8(Text10, { color: THEME.gray, wrap: "truncate", children: [
16928
17077
  " ",
16929
17078
  truncateError(retryState.error)
16930
17079
  ] }) })
@@ -16932,12 +17081,12 @@ var RetryView = ({ retryState }) => {
16932
17081
  };
16933
17082
 
16934
17083
  // src/platform/tui/components/status/ProcessingView.tsx
16935
- import { Box as Box10, Text as Text11 } from "ink";
17084
+ import { Box as Box11, Text as Text12 } from "ink";
16936
17085
 
16937
17086
  // src/platform/tui/components/ShimmerText.tsx
16938
- import { memo as memo9 } from "react";
16939
- import { Text as Text10 } from "ink";
16940
- import { jsx as jsx12 } from "react/jsx-runtime";
17087
+ import { memo as memo10 } from "react";
17088
+ import { Text as Text11 } from "ink";
17089
+ import { jsx as jsx13 } from "react/jsx-runtime";
16941
17090
  var WAVE_SPEED = 0.25 * (120 / ANIM_TICK_MS);
16942
17091
  var CHAR_PHASE_GAP = 0.55;
16943
17092
  function sinToColor(sin) {
@@ -16946,19 +17095,19 @@ function sinToColor(sin) {
16946
17095
  const hex = brightness.toString(16).padStart(2, "0");
16947
17096
  return `#${hex}${hex}${hex}`;
16948
17097
  }
16949
- var ShimmerText = memo9(({ children, bold, phase = 0 }) => {
17098
+ var ShimmerText = memo10(({ children, bold, phase = 0 }) => {
16950
17099
  const tick = useAnimationTick();
16951
17100
  const globalPhase = tick * WAVE_SPEED + phase;
16952
- return /* @__PURE__ */ jsx12(Text10, { bold, children: Array.from(children).map((char, i) => {
17101
+ return /* @__PURE__ */ jsx13(Text11, { bold, children: Array.from(children).map((char, i) => {
16953
17102
  const charPhase = globalPhase - i * CHAR_PHASE_GAP;
16954
17103
  const sin = Math.sin(charPhase);
16955
17104
  const color = sinToColor(sin);
16956
- return /* @__PURE__ */ jsx12(Text10, { color, children: char }, i);
17105
+ return /* @__PURE__ */ jsx13(Text11, { color, children: char }, i);
16957
17106
  }) });
16958
17107
  });
16959
17108
 
16960
17109
  // src/platform/tui/components/status/ProcessingView.tsx
16961
- import { jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
17110
+ import { jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
16962
17111
  var ProcessingView = ({
16963
17112
  statusMain,
16964
17113
  detailText,
@@ -16977,27 +17126,27 @@ var ProcessingView = ({
16977
17126
  const parenIdx = statusMain.indexOf("(");
16978
17127
  const shimmerPart = parenIdx > -1 ? statusMain.slice(0, parenIdx).trimEnd() : statusMain;
16979
17128
  const staticSuffix = parenIdx > -1 ? " " + statusMain.slice(parenIdx) : "";
16980
- return /* @__PURE__ */ jsxs9(Box10, { flexDirection: "column", height: 2, children: [
16981
- /* @__PURE__ */ jsxs9(Box10, { children: [
16982
- /* @__PURE__ */ jsx13(Text11, { color, wrap: "truncate", children: /* @__PURE__ */ jsx13(StarSpinner, { color }) }),
16983
- /* @__PURE__ */ jsx13(Text11, { children: " " }),
16984
- /* @__PURE__ */ jsx13(ShimmerText, { bold: true, phase: 0, children: shimmerPart }),
16985
- staticSuffix ? /* @__PURE__ */ jsx13(Text11, { color: THEME.dimGray, wrap: "truncate", children: staticSuffix }) : null,
16986
- /* @__PURE__ */ jsxs9(Text11, { color: THEME.dimGray, wrap: "truncate", children: [
17129
+ return /* @__PURE__ */ jsxs9(Box11, { flexDirection: "column", height: 2, children: [
17130
+ /* @__PURE__ */ jsxs9(Box11, { children: [
17131
+ /* @__PURE__ */ jsx14(Text12, { color, wrap: "truncate", children: /* @__PURE__ */ jsx14(StarSpinner, { color }) }),
17132
+ /* @__PURE__ */ jsx14(Text12, { children: " " }),
17133
+ /* @__PURE__ */ jsx14(ShimmerText, { bold: true, phase: 0, children: shimmerPart }),
17134
+ staticSuffix ? /* @__PURE__ */ jsx14(Text12, { color: THEME.dimGray, wrap: "truncate", children: staticSuffix }) : null,
17135
+ /* @__PURE__ */ jsxs9(Text12, { color: THEME.dimGray, wrap: "truncate", children: [
16987
17136
  " ",
16988
17137
  meta
16989
17138
  ] })
16990
17139
  ] }),
16991
- /* @__PURE__ */ jsx13(Box10, { children: detailText ? /* @__PURE__ */ jsxs9(Text11, { color: THEME.dimGray, wrap: "truncate", children: [
17140
+ /* @__PURE__ */ jsx14(Box11, { children: detailText ? /* @__PURE__ */ jsxs9(Text12, { color: THEME.dimGray, wrap: "truncate", children: [
16992
17141
  " ",
16993
17142
  detailText
16994
- ] }) : /* @__PURE__ */ jsx13(Text11, { children: " " }) })
17143
+ ] }) : /* @__PURE__ */ jsx14(Text12, { children: " " }) })
16995
17144
  ] });
16996
17145
  };
16997
17146
 
16998
17147
  // src/platform/tui/components/StatusDisplay.tsx
16999
- import { jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
17000
- var StatusDisplay = memo10(({
17148
+ import { jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
17149
+ var StatusDisplay = memo11(({
17001
17150
  retryState,
17002
17151
  isProcessing,
17003
17152
  currentStatus,
@@ -17007,12 +17156,12 @@ var StatusDisplay = memo10(({
17007
17156
  const isWaitingForInput = inputRequest?.status === "active";
17008
17157
  const statusElapsed = useStatusTimer(currentStatus, isProcessing && !isWaitingForInput);
17009
17158
  if (retryState && retryState.status === "retrying") {
17010
- return /* @__PURE__ */ jsx14(RetryView, { retryState });
17159
+ return /* @__PURE__ */ jsx15(RetryView, { retryState });
17011
17160
  }
17012
17161
  if (isProcessing && isWaitingForInput) {
17013
- return /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", height: 2, children: [
17014
- /* @__PURE__ */ jsx14(Text12, { children: " " }),
17015
- /* @__PURE__ */ jsx14(Text12, { children: " " })
17162
+ return /* @__PURE__ */ jsxs10(Box12, { flexDirection: "column", height: 2, children: [
17163
+ /* @__PURE__ */ jsx15(Text13, { children: " " }),
17164
+ /* @__PURE__ */ jsx15(Text13, { children: " " })
17016
17165
  ] });
17017
17166
  }
17018
17167
  if (isProcessing) {
@@ -17020,7 +17169,7 @@ var StatusDisplay = memo10(({
17020
17169
  const statusLines = currentStatus ? currentStatus.split("\n").filter(Boolean) : [];
17021
17170
  const statusMain = statusLines[0] || "Processing...";
17022
17171
  const detailText = isThinkingStatus && statusLines.length > 1 ? statusLines[statusLines.length - 1].slice(0, 120) : "";
17023
- return /* @__PURE__ */ jsx14(
17172
+ return /* @__PURE__ */ jsx15(
17024
17173
  ProcessingView,
17025
17174
  {
17026
17175
  statusMain,
@@ -17031,46 +17180,111 @@ var StatusDisplay = memo10(({
17031
17180
  }
17032
17181
  );
17033
17182
  }
17034
- return /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", height: 2, children: [
17035
- /* @__PURE__ */ jsx14(Text12, { children: " " }),
17036
- /* @__PURE__ */ jsx14(Text12, { children: " " })
17183
+ return /* @__PURE__ */ jsxs10(Box12, { flexDirection: "column", height: 2, children: [
17184
+ /* @__PURE__ */ jsx15(Text13, { children: " " }),
17185
+ /* @__PURE__ */ jsx15(Text13, { children: " " })
17037
17186
  ] });
17038
17187
  });
17039
17188
 
17040
17189
  // src/platform/tui/components/ChatInput.tsx
17041
- import { useMemo, useCallback as useCallback7, useRef as useRef6, memo as memo11, useState as useState5, useEffect as useEffect7 } from "react";
17042
- import { Box as Box15, Text as Text16, useInput as useInput2 } from "ink";
17190
+ import { useMemo as useMemo2, useCallback as useCallback7, useRef as useRef7, memo as memo12, useState as useState6, useEffect as useEffect8 } from "react";
17191
+ import { Box as Box16, Text as Text18, useInput as useInput3 } from "ink";
17043
17192
 
17044
17193
  // src/platform/tui/components/input/AutocompletePreview.tsx
17045
- import { Box as Box12, Text as Text13 } from "ink";
17046
- import { jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
17194
+ import { Box as Box13, Text as Text14 } from "ink";
17195
+ import { jsx as jsx16, jsxs as jsxs11 } from "react/jsx-runtime";
17047
17196
  var AutocompletePreview = ({
17048
17197
  suggestions,
17049
17198
  clampedIdx
17050
17199
  }) => {
17051
- return /* @__PURE__ */ jsx15(Box12, { flexDirection: "column", paddingX: 1, children: suggestions.map((cmd, i) => {
17200
+ return /* @__PURE__ */ jsx16(Box13, { flexDirection: "column", paddingX: 1, children: suggestions.map((cmd, i) => {
17052
17201
  const isSelected = i === clampedIdx;
17053
17202
  const argsText = cmd.args ? ` ${cmd.args}` : "";
17054
- return /* @__PURE__ */ jsxs11(Box12, { children: [
17055
- /* @__PURE__ */ jsx15(Text13, { color: isSelected ? THEME.primary : THEME.dimGray, children: isSelected ? " \u276F " : " " }),
17056
- /* @__PURE__ */ jsxs11(Text13, { color: isSelected ? THEME.white : THEME.gray, bold: isSelected, children: [
17203
+ return /* @__PURE__ */ jsxs11(Box13, { children: [
17204
+ /* @__PURE__ */ jsx16(Text14, { color: isSelected ? THEME.primary : THEME.dimGray, children: isSelected ? " \u276F " : " " }),
17205
+ /* @__PURE__ */ jsxs11(Text14, { color: isSelected ? THEME.white : THEME.gray, bold: isSelected, children: [
17057
17206
  "/",
17058
17207
  cmd.name
17059
17208
  ] }),
17060
- /* @__PURE__ */ jsx15(Text13, { dimColor: true, color: THEME.gray, children: argsText }),
17061
- /* @__PURE__ */ jsxs11(Text13, { dimColor: true, color: THEME.dimGray, children: [
17209
+ /* @__PURE__ */ jsx16(Text14, { dimColor: true, color: THEME.gray, children: argsText }),
17210
+ /* @__PURE__ */ jsxs11(Text14, { dimColor: true, color: THEME.dimGray, children: [
17062
17211
  " \u2014 ",
17063
17212
  cmd.description
17064
17213
  ] }),
17065
- isSelected && cmd.alias && /* @__PURE__ */ jsx15(Text13, { dimColor: true, color: THEME.dimGray, children: ` (/${cmd.alias})` })
17214
+ isSelected && cmd.alias && /* @__PURE__ */ jsx16(Text14, { dimColor: true, color: THEME.dimGray, children: ` (/${cmd.alias})` })
17066
17215
  ] }, cmd.name);
17067
17216
  }) });
17068
17217
  };
17069
17218
 
17070
17219
  // src/platform/tui/components/input/SecretInputArea.tsx
17071
- import { Box as Box13, Text as Text14, useStdout } from "ink";
17072
- import TextInput from "ink-text-input";
17073
- import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
17220
+ import { Box as Box14, Text as Text16, useStdout } from "ink";
17221
+
17222
+ // src/platform/tui/components/input/SimpleTextInput.tsx
17223
+ import { useState as useState5, useEffect as useEffect7, useRef as useRef6 } from "react";
17224
+ import { Text as Text15, useInput as useInput2 } from "ink";
17225
+ import { jsx as jsx17, jsxs as jsxs12 } from "react/jsx-runtime";
17226
+ var SimpleTextInput = ({
17227
+ value,
17228
+ onChange,
17229
+ onSubmit,
17230
+ placeholder,
17231
+ isPassword
17232
+ }) => {
17233
+ const [cursor, setCursor] = useState5(Array.from(value || "").length);
17234
+ const valueRef = useRef6(value || "");
17235
+ valueRef.current = value || "";
17236
+ useEffect7(() => {
17237
+ const len = Array.from(valueRef.current).length;
17238
+ if (cursor > len) setCursor(len);
17239
+ }, [value, cursor]);
17240
+ useInput2((input, key) => {
17241
+ if (key.ctrl && input === "c") return;
17242
+ if (key.upArrow || key.downArrow || key.tab) return;
17243
+ if (key.return) {
17244
+ onSubmit?.(valueRef.current);
17245
+ return;
17246
+ }
17247
+ const chars2 = Array.from(valueRef.current);
17248
+ let c2 = cursor;
17249
+ if (key.leftArrow) {
17250
+ c2 = Math.max(0, c2 - 1);
17251
+ } else if (key.rightArrow) {
17252
+ c2 = Math.min(chars2.length, c2 + 1);
17253
+ } else if (key.backspace || key.delete) {
17254
+ if (c2 > 0) {
17255
+ chars2.splice(c2 - 1, 1);
17256
+ c2--;
17257
+ onChange(chars2.join(""));
17258
+ }
17259
+ } else if (input) {
17260
+ const inputChars = Array.from(input);
17261
+ chars2.splice(c2, 0, ...inputChars);
17262
+ c2 += inputChars.length;
17263
+ onChange(chars2.join(""));
17264
+ }
17265
+ setCursor(c2);
17266
+ }, { isActive: true });
17267
+ const displayValue = isPassword ? "\u2022".repeat(Array.from(valueRef.current).length) : valueRef.current;
17268
+ const chars = Array.from(displayValue);
17269
+ if (chars.length === 0) {
17270
+ return /* @__PURE__ */ jsxs12(Text15, { children: [
17271
+ /* @__PURE__ */ jsx17(Text15, { inverse: true, children: " " }),
17272
+ placeholder ? /* @__PURE__ */ jsx17(Text15, { color: "gray", children: placeholder }) : null
17273
+ ] });
17274
+ }
17275
+ const c = Math.min(cursor, chars.length);
17276
+ const before = chars.slice(0, c).join("");
17277
+ const charAtCursor = c < chars.length ? chars[c] : " ";
17278
+ const after = chars.slice(c + 1).join("");
17279
+ return /* @__PURE__ */ jsxs12(Text15, { children: [
17280
+ before,
17281
+ /* @__PURE__ */ jsx17(Text15, { inverse: true, children: charAtCursor }),
17282
+ after
17283
+ ] });
17284
+ };
17285
+
17286
+ // src/platform/tui/components/input/SecretInputArea.tsx
17287
+ import { jsx as jsx18, jsxs as jsxs13 } from "react/jsx-runtime";
17074
17288
  var OUTER_PADDING = 2;
17075
17289
  var SecretInputArea = ({
17076
17290
  inputRequest,
@@ -17081,29 +17295,28 @@ var SecretInputArea = ({
17081
17295
  const { stdout } = useStdout();
17082
17296
  const borderWidth = Math.max(10, (stdout?.columns ?? 80) - OUTER_PADDING);
17083
17297
  const borderLine = "\u2501".repeat(borderWidth);
17084
- return /* @__PURE__ */ jsxs12(Box13, { flexDirection: "column", children: [
17085
- /* @__PURE__ */ jsx16(Box13, { children: /* @__PURE__ */ jsx16(Text14, { color: THEME.yellow, children: borderLine }) }),
17086
- /* @__PURE__ */ jsxs12(Box13, { paddingX: 1, children: [
17087
- /* @__PURE__ */ jsx16(Text14, { color: THEME.yellow, bold: true, children: "\u25B8 " }),
17088
- /* @__PURE__ */ jsx16(
17089
- TextInput,
17298
+ return /* @__PURE__ */ jsxs13(Box14, { flexDirection: "column", children: [
17299
+ /* @__PURE__ */ jsx18(Box14, { children: /* @__PURE__ */ jsx18(Text16, { color: THEME.yellow, children: borderLine }) }),
17300
+ /* @__PURE__ */ jsxs13(Box14, { paddingX: 1, children: [
17301
+ /* @__PURE__ */ jsx18(Text16, { color: THEME.yellow, bold: true, children: "\u25B8 " }),
17302
+ /* @__PURE__ */ jsx18(
17303
+ SimpleTextInput,
17090
17304
  {
17091
17305
  value: secretInput,
17092
17306
  onChange: setSecretInput,
17093
17307
  onSubmit: onSecretSubmit,
17094
17308
  placeholder: inputRequest.isPassword ? "(hidden \xB7 press Enter)" : "(type and press Enter)",
17095
- mask: inputRequest.isPassword ? "\u2022" : void 0
17309
+ isPassword: inputRequest.isPassword
17096
17310
  }
17097
17311
  )
17098
17312
  ] }),
17099
- /* @__PURE__ */ jsx16(Box13, { children: /* @__PURE__ */ jsx16(Text14, { color: THEME.yellow, children: borderLine }) })
17313
+ /* @__PURE__ */ jsx18(Box14, { children: /* @__PURE__ */ jsx18(Text16, { color: THEME.yellow, children: borderLine }) })
17100
17314
  ] });
17101
17315
  };
17102
17316
 
17103
17317
  // src/platform/tui/components/input/NormalInputArea.tsx
17104
- import { Box as Box14, Text as Text15, useStdout as useStdout2 } from "ink";
17105
- import TextInput2 from "ink-text-input";
17106
- import { jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
17318
+ import { Box as Box15, Text as Text17, useStdout as useStdout2 } from "ink";
17319
+ import { jsx as jsx19, jsxs as jsxs14 } from "react/jsx-runtime";
17107
17320
  var OUTER_PADDING2 = 2;
17108
17321
  var NormalInputArea = ({
17109
17322
  inputKey,
@@ -17115,12 +17328,12 @@ var NormalInputArea = ({
17115
17328
  const { stdout } = useStdout2();
17116
17329
  const borderWidth = Math.max(10, (stdout?.columns ?? 80) - OUTER_PADDING2);
17117
17330
  const borderLine = "\u2500".repeat(borderWidth);
17118
- return /* @__PURE__ */ jsxs13(Box14, { flexDirection: "column", children: [
17119
- /* @__PURE__ */ jsx17(Box14, { children: /* @__PURE__ */ jsx17(Text15, { dimColor: true, color: THEME.dimGray, children: borderLine }) }),
17120
- /* @__PURE__ */ jsxs13(Box14, { paddingX: 1, children: [
17121
- /* @__PURE__ */ jsx17(Text15, { color: THEME.primary, children: "\u276F " }),
17122
- /* @__PURE__ */ jsx17(
17123
- TextInput2,
17331
+ return /* @__PURE__ */ jsxs14(Box15, { flexDirection: "column", children: [
17332
+ /* @__PURE__ */ jsx19(Box15, { children: /* @__PURE__ */ jsx19(Text17, { dimColor: true, color: THEME.dimGray, children: borderLine }) }),
17333
+ /* @__PURE__ */ jsxs14(Box15, { paddingX: 1, children: [
17334
+ /* @__PURE__ */ jsx19(Text17, { color: THEME.primary, children: "\u276F " }),
17335
+ /* @__PURE__ */ jsx19(
17336
+ SimpleTextInput,
17124
17337
  {
17125
17338
  value,
17126
17339
  onChange,
@@ -17130,14 +17343,14 @@ var NormalInputArea = ({
17130
17343
  inputKey
17131
17344
  )
17132
17345
  ] }),
17133
- /* @__PURE__ */ jsx17(Box14, { children: /* @__PURE__ */ jsx17(Text15, { dimColor: true, color: THEME.dimGray, children: borderLine }) })
17346
+ /* @__PURE__ */ jsx19(Box15, { children: /* @__PURE__ */ jsx19(Text17, { dimColor: true, color: THEME.dimGray, children: borderLine }) })
17134
17347
  ] });
17135
17348
  };
17136
17349
 
17137
17350
  // src/platform/tui/components/ChatInput.tsx
17138
- import { jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
17351
+ import { jsx as jsx20, jsxs as jsxs15 } from "react/jsx-runtime";
17139
17352
  var MAX_SUGGESTIONS = 6;
17140
- var ChatInput = memo11(({
17353
+ var ChatInput = memo12(({
17141
17354
  value,
17142
17355
  onChange,
17143
17356
  onSubmit,
@@ -17150,31 +17363,43 @@ var ChatInput = memo11(({
17150
17363
  const isSlashMode = value.startsWith("/");
17151
17364
  const partialCmd = isSlashMode ? value.slice(1).split(" ")[0] : "";
17152
17365
  const hasArgs = isSlashMode && value.includes(" ");
17153
- const suggestions = useMemo(() => {
17366
+ const suggestions = useMemo2(() => {
17154
17367
  if (!isSlashMode || hasArgs) return [];
17155
17368
  return getMatchingCommands(partialCmd).slice(0, MAX_SUGGESTIONS);
17156
17369
  }, [isSlashMode, partialCmd, hasArgs]);
17157
17370
  const showPreview = isSlashMode && !hasArgs && suggestions.length > 0;
17158
- const [selectedIdx, setSelectedIdx] = useState5(0);
17371
+ const [selectedIdx, setSelectedIdx] = useState6(0);
17159
17372
  const clampedIdx = Math.min(selectedIdx, Math.max(0, suggestions.length - 1));
17160
- const selectedIdxRef = useRef6(clampedIdx);
17373
+ const selectedIdxRef = useRef7(clampedIdx);
17161
17374
  selectedIdxRef.current = clampedIdx;
17162
- const suggestionsRef = useRef6(suggestions);
17375
+ const suggestionsRef = useRef7(suggestions);
17163
17376
  suggestionsRef.current = suggestions;
17164
- const isSlashModeRef = useRef6(isSlashMode);
17377
+ const isSlashModeRef = useRef7(isSlashMode);
17165
17378
  isSlashModeRef.current = isSlashMode;
17166
- const hasArgsRef = useRef6(hasArgs);
17379
+ const hasArgsRef = useRef7(hasArgs);
17167
17380
  hasArgsRef.current = hasArgs;
17168
- const showPreviewRef = useRef6(showPreview);
17381
+ const showPreviewRef = useRef7(showPreview);
17169
17382
  showPreviewRef.current = showPreview;
17170
- const inputRequestRef = useRef6(inputRequest);
17383
+ const inputRequestRef = useRef7(inputRequest);
17171
17384
  inputRequestRef.current = inputRequest;
17172
- const onChangeRef = useRef6(onChange);
17385
+ const onChangeRef = useRef7(onChange);
17173
17386
  onChangeRef.current = onChange;
17174
- const [pastedHint, setPastedHint] = useState5(null);
17175
- const prevValueRef = useRef6(value);
17176
- const pasteTimerRef = useRef6(null);
17177
- useEffect7(() => {
17387
+ const latestValueRef = useRef7(value);
17388
+ latestValueRef.current = value;
17389
+ const handleLocalChange = useCallback7((newVal) => {
17390
+ latestValueRef.current = newVal;
17391
+ onChange(newVal);
17392
+ }, [onChange]);
17393
+ const latestSecretRef = useRef7(secretInput);
17394
+ latestSecretRef.current = secretInput;
17395
+ const handleSecretChange = useCallback7((newVal) => {
17396
+ latestSecretRef.current = newVal;
17397
+ setSecretInput(newVal);
17398
+ }, [setSecretInput]);
17399
+ const [pastedHint, setPastedHint] = useState6(null);
17400
+ const prevValueRef = useRef7(value);
17401
+ const pasteTimerRef = useRef7(null);
17402
+ useEffect8(() => {
17178
17403
  const diff = value.length - prevValueRef.current.length;
17179
17404
  if (diff > 20) {
17180
17405
  if (pasteTimerRef.current) clearTimeout(pasteTimerRef.current);
@@ -17186,7 +17411,7 @@ var ChatInput = memo11(({
17186
17411
  if (pasteTimerRef.current) clearTimeout(pasteTimerRef.current);
17187
17412
  };
17188
17413
  }, [value]);
17189
- const [inputKey, setInputKey] = useState5(0);
17414
+ const [inputKey, setInputKey] = useState6(0);
17190
17415
  const completeCommand = useCallback7((idx) => {
17191
17416
  const sug = suggestionsRef.current;
17192
17417
  if (!sug.length) return;
@@ -17197,13 +17422,14 @@ var ChatInput = memo11(({
17197
17422
  setSelectedIdx(0);
17198
17423
  setInputKey((k) => k + 1);
17199
17424
  }, []);
17200
- const onSubmitRef = useRef6(onSubmit);
17425
+ const onSubmitRef = useRef7(onSubmit);
17201
17426
  onSubmitRef.current = onSubmit;
17202
- const wrappedOnSubmit = useCallback7((val) => {
17427
+ const wrappedOnSubmit = useCallback7((_staleVal) => {
17428
+ const finalValue = latestValueRef.current;
17203
17429
  if (showPreviewRef.current) {
17204
17430
  const sug = suggestionsRef.current;
17205
17431
  if (!sug.length) {
17206
- onSubmitRef.current(val);
17432
+ onSubmitRef.current(finalValue);
17207
17433
  return;
17208
17434
  }
17209
17435
  const best = sug[Math.min(selectedIdxRef.current, sug.length - 1)];
@@ -17216,9 +17442,14 @@ var ChatInput = memo11(({
17216
17442
  }
17217
17443
  return;
17218
17444
  }
17219
- onSubmitRef.current(val);
17445
+ onSubmitRef.current(finalValue);
17220
17446
  }, [completeCommand]);
17221
- useInput2(useCallback7((_input, key) => {
17447
+ const onSecretSubmitRef = useRef7(onSecretSubmit);
17448
+ onSecretSubmitRef.current = onSecretSubmit;
17449
+ const wrappedSecretSubmit = useCallback7((_staleVal) => {
17450
+ onSecretSubmitRef.current(latestSecretRef.current);
17451
+ }, []);
17452
+ useInput3(useCallback7((_input, key) => {
17222
17453
  if (inputRequestRef.current.status === "active") return;
17223
17454
  const sug = suggestionsRef.current;
17224
17455
  const visible = showPreviewRef.current;
@@ -17234,8 +17465,8 @@ var ChatInput = memo11(({
17234
17465
  completeCommand(selectedIdxRef.current);
17235
17466
  }
17236
17467
  }, [completeCommand]));
17237
- return /* @__PURE__ */ jsxs14(Box15, { flexDirection: "column", children: [
17238
- showPreview && /* @__PURE__ */ jsx18(
17468
+ return /* @__PURE__ */ jsxs15(Box16, { flexDirection: "column", children: [
17469
+ showPreview && /* @__PURE__ */ jsx20(
17239
17470
  AutocompletePreview,
17240
17471
  {
17241
17472
  suggestions,
@@ -17244,36 +17475,36 @@ var ChatInput = memo11(({
17244
17475
  ),
17245
17476
  inputRequest.status === "active" ? (
17246
17477
  /* Active input request — yellow top/bottom border */
17247
- /* @__PURE__ */ jsx18(
17478
+ /* @__PURE__ */ jsx20(
17248
17479
  SecretInputArea,
17249
17480
  {
17250
17481
  inputRequest,
17251
17482
  secretInput,
17252
- setSecretInput,
17253
- onSecretSubmit
17483
+ setSecretInput: handleSecretChange,
17484
+ onSecretSubmit: wrappedSecretSubmit
17254
17485
  }
17255
17486
  )
17256
17487
  ) : (
17257
17488
  /* Normal input — dim top/bottom border */
17258
- /* @__PURE__ */ jsx18(
17489
+ /* @__PURE__ */ jsx20(
17259
17490
  NormalInputArea,
17260
17491
  {
17261
17492
  inputKey,
17262
17493
  value,
17263
- onChange,
17494
+ onChange: handleLocalChange,
17264
17495
  onSubmit: wrappedOnSubmit,
17265
17496
  placeholder
17266
17497
  }
17267
17498
  )
17268
17499
  ),
17269
- pastedHint && /* @__PURE__ */ jsx18(Box15, { paddingX: 2, children: /* @__PURE__ */ jsx18(Text16, { dimColor: true, color: THEME.dimGray, children: pastedHint }) })
17500
+ pastedHint && /* @__PURE__ */ jsx20(Box16, { paddingX: 2, children: /* @__PURE__ */ jsx20(Text18, { dimColor: true, color: THEME.dimGray, children: pastedHint }) })
17270
17501
  ] });
17271
17502
  });
17272
17503
 
17273
17504
  // src/platform/tui/components/footer.tsx
17274
- import { memo as memo12 } from "react";
17275
- import { Box as Box16, Text as Text17 } from "ink";
17276
- import { jsx as jsx19, jsxs as jsxs15 } from "react/jsx-runtime";
17505
+ import { memo as memo13 } from "react";
17506
+ import { Box as Box17, Text as Text19 } from "ink";
17507
+ import { jsx as jsx21, jsxs as jsxs16 } from "react/jsx-runtime";
17277
17508
  var CTX_WARN_THRESHOLD = 0.8;
17278
17509
  var MAX_CONTEXT_TOKENS = LLM_LIMITS.streamMaxTokens;
17279
17510
  var formatElapsed = (totalSeconds) => {
@@ -17286,55 +17517,55 @@ var formatElapsed = (totalSeconds) => {
17286
17517
  }
17287
17518
  return `${minutes}:${pad(seconds)}`;
17288
17519
  };
17289
- var Footer = memo12(({ phase, targets, findings, todo, elapsedTime, isProcessing, totalTokens, turnCount }) => {
17520
+ var Footer = memo13(({ phase, targets, findings, todo, elapsedTime, isProcessing, totalTokens, turnCount }) => {
17290
17521
  const ctxPct = totalTokens > 0 ? Math.round(totalTokens / MAX_CONTEXT_TOKENS * 100) : 0;
17291
17522
  const ctxColor = ctxPct >= CTX_WARN_THRESHOLD * 100 ? THEME.yellow : THEME.dimGray;
17292
- return /* @__PURE__ */ jsxs15(
17293
- Box16,
17523
+ return /* @__PURE__ */ jsxs16(
17524
+ Box17,
17294
17525
  {
17295
17526
  width: "100%",
17296
17527
  paddingX: 1,
17297
17528
  justifyContent: "space-between",
17298
17529
  overflow: "hidden",
17299
17530
  children: [
17300
- /* @__PURE__ */ jsxs15(Box16, { gap: 2, children: [
17301
- /* @__PURE__ */ jsxs15(Text17, { color: THEME.gray, children: [
17531
+ /* @__PURE__ */ jsxs16(Box17, { gap: 2, children: [
17532
+ /* @__PURE__ */ jsxs16(Text19, { color: THEME.gray, children: [
17302
17533
  "Phase: ",
17303
- /* @__PURE__ */ jsx19(Text17, { color: THEME.white, children: phase })
17534
+ /* @__PURE__ */ jsx21(Text19, { color: THEME.white, children: phase })
17304
17535
  ] }),
17305
- /* @__PURE__ */ jsxs15(Text17, { color: THEME.gray, children: [
17536
+ /* @__PURE__ */ jsxs16(Text19, { color: THEME.gray, children: [
17306
17537
  "Targets: ",
17307
- /* @__PURE__ */ jsx19(Text17, { color: THEME.white, children: targets })
17538
+ /* @__PURE__ */ jsx21(Text19, { color: THEME.white, children: targets })
17308
17539
  ] }),
17309
- /* @__PURE__ */ jsxs15(Text17, { color: THEME.gray, children: [
17540
+ /* @__PURE__ */ jsxs16(Text19, { color: THEME.gray, children: [
17310
17541
  "Findings: ",
17311
- /* @__PURE__ */ jsx19(Text17, { color: THEME.white, children: findings })
17542
+ /* @__PURE__ */ jsx21(Text19, { color: THEME.white, children: findings })
17312
17543
  ] }),
17313
- /* @__PURE__ */ jsxs15(Text17, { color: THEME.gray, children: [
17544
+ /* @__PURE__ */ jsxs16(Text19, { color: THEME.gray, children: [
17314
17545
  "Tasks: ",
17315
- /* @__PURE__ */ jsx19(Text17, { color: THEME.white, children: todo })
17546
+ /* @__PURE__ */ jsx21(Text19, { color: THEME.white, children: todo })
17316
17547
  ] })
17317
17548
  ] }),
17318
- /* @__PURE__ */ jsxs15(Box16, { gap: 2, children: [
17319
- isProcessing ? /* @__PURE__ */ jsxs15(Box16, { gap: 1, children: [
17320
- /* @__PURE__ */ jsx19(Text17, { dimColor: true, color: THEME.dimGray, children: "[ESC] abort" }),
17321
- /* @__PURE__ */ jsx19(Text17, { dimColor: true, color: THEME.dimGray, children: "[^C\xD72] exit" })
17322
- ] }) : /* @__PURE__ */ jsx19(Text17, { dimColor: true, color: THEME.dimGray, children: "[/help] commands" }),
17323
- turnCount > 0 && /* @__PURE__ */ jsxs15(Text17, { dimColor: true, color: THEME.dimGray, children: [
17549
+ /* @__PURE__ */ jsxs16(Box17, { gap: 2, children: [
17550
+ isProcessing ? /* @__PURE__ */ jsxs16(Box17, { gap: 1, children: [
17551
+ /* @__PURE__ */ jsx21(Text19, { dimColor: true, color: THEME.dimGray, children: "[ESC] abort" }),
17552
+ /* @__PURE__ */ jsx21(Text19, { dimColor: true, color: THEME.dimGray, children: "[^C\xD72] exit" })
17553
+ ] }) : /* @__PURE__ */ jsx21(Text19, { dimColor: true, color: THEME.dimGray, children: "[/help] commands" }),
17554
+ turnCount > 0 && /* @__PURE__ */ jsxs16(Text19, { dimColor: true, color: THEME.dimGray, children: [
17324
17555
  "turn:",
17325
17556
  turnCount
17326
17557
  ] }),
17327
- totalTokens > 0 && /* @__PURE__ */ jsxs15(Text17, { dimColor: true, color: ctxColor, children: [
17558
+ totalTokens > 0 && /* @__PURE__ */ jsxs16(Text19, { dimColor: true, color: ctxColor, children: [
17328
17559
  "ctx:",
17329
17560
  ctxPct,
17330
17561
  "%"
17331
17562
  ] }),
17332
- totalTokens > 0 && /* @__PURE__ */ jsxs15(Text17, { dimColor: true, color: THEME.dimGray, children: [
17563
+ totalTokens > 0 && /* @__PURE__ */ jsxs16(Text19, { dimColor: true, color: THEME.dimGray, children: [
17333
17564
  "\u2191",
17334
17565
  formatTokens(totalTokens)
17335
17566
  ] }),
17336
- /* @__PURE__ */ jsx19(Text17, { color: isProcessing ? THEME.primary : THEME.gray, children: isProcessing ? "Running " : "Idle " }),
17337
- /* @__PURE__ */ jsx19(Text17, { color: THEME.white, children: formatElapsed(elapsedTime) })
17567
+ /* @__PURE__ */ jsx21(Text19, { color: isProcessing ? THEME.primary : THEME.gray, children: isProcessing ? "Running " : "Idle " }),
17568
+ /* @__PURE__ */ jsx21(Text19, { color: THEME.white, children: formatElapsed(elapsedTime) })
17338
17569
  ] })
17339
17570
  ]
17340
17571
  }
@@ -17343,36 +17574,36 @@ var Footer = memo12(({ phase, targets, findings, todo, elapsedTime, isProcessing
17343
17574
  var footer_default = Footer;
17344
17575
 
17345
17576
  // src/platform/tui/components/Modal.tsx
17346
- import { useMemo as useMemo2, memo as memo13, useCallback as useCallback8, useRef as useRef7 } from "react";
17347
- import { Box as Box17, Text as Text18, useStdout as useStdout3, useInput as useInput3 } from "ink";
17348
- import { jsx as jsx20, jsxs as jsxs16 } from "react/jsx-runtime";
17577
+ import { useMemo as useMemo3, memo as memo14, useCallback as useCallback8, useRef as useRef8 } from "react";
17578
+ import { Box as Box18, Text as Text20, useStdout as useStdout3, useInput as useInput4 } from "ink";
17579
+ import { jsx as jsx22, jsxs as jsxs17 } from "react/jsx-runtime";
17349
17580
  var MODAL_TITLES = {
17350
17581
  findings: "\u25C8 FINDINGS \u25C8",
17351
17582
  graph: "\u25C8 ATTACK GRAPH \u25C8",
17352
17583
  help: "\u25C8 COMMANDS \u25C8"
17353
17584
  };
17354
- var Modal = memo13(({
17585
+ var Modal = memo14(({
17355
17586
  type,
17356
17587
  content,
17357
17588
  scrollOffset,
17358
17589
  onScroll,
17359
17590
  onClose
17360
17591
  }) => {
17361
- const onScrollRef = useRef7(onScroll);
17592
+ const onScrollRef = useRef8(onScroll);
17362
17593
  onScrollRef.current = onScroll;
17363
- const onCloseRef = useRef7(onClose);
17594
+ const onCloseRef = useRef8(onClose);
17364
17595
  onCloseRef.current = onClose;
17365
17596
  const { stdout } = useStdout3();
17366
17597
  const terminalHeight = stdout?.rows ?? 24;
17367
17598
  const terminalWidth = (stdout?.columns ?? 80) - 4;
17368
17599
  const maxHeight = Math.max(1, terminalHeight - 6);
17369
- const lines = useMemo2(() => content.split("\n"), [content]);
17600
+ const lines = useMemo3(() => content.split("\n"), [content]);
17370
17601
  const totalLines = lines.length;
17371
- const visibleLines = useMemo2(
17602
+ const visibleLines = useMemo3(
17372
17603
  () => lines.slice(scrollOffset, scrollOffset + maxHeight),
17373
17604
  [lines, scrollOffset, maxHeight]
17374
17605
  );
17375
- useInput3(useCallback8((input, key) => {
17606
+ useInput4(useCallback8((input, key) => {
17376
17607
  if (key.escape || input === "q") {
17377
17608
  onCloseRef.current();
17378
17609
  } else if (key.upArrow || input === "k") {
@@ -17389,20 +17620,20 @@ var Modal = memo13(({
17389
17620
  const endLine = Math.min(scrollOffset + maxHeight, totalLines);
17390
17621
  const scrollbarHeight = Math.max(1, Math.floor(maxHeight * (maxHeight / Math.max(totalLines, 1))));
17391
17622
  const scrollbarPosition = totalLines > maxHeight ? Math.floor(scrollOffset / (totalLines - maxHeight) * (maxHeight - scrollbarHeight)) : 0;
17392
- return /* @__PURE__ */ jsxs16(
17393
- Box17,
17623
+ return /* @__PURE__ */ jsxs17(
17624
+ Box18,
17394
17625
  {
17395
17626
  flexDirection: "column",
17396
17627
  width: terminalWidth,
17397
17628
  height: terminalHeight,
17398
17629
  children: [
17399
- /* @__PURE__ */ jsx20(Box17, { justifyContent: "center", marginBottom: 0, children: /* @__PURE__ */ jsx20(Text18, { color: THEME.cyan, bold: true, children: (() => {
17630
+ /* @__PURE__ */ jsx22(Box18, { justifyContent: "center", marginBottom: 0, children: /* @__PURE__ */ jsx22(Text20, { color: THEME.cyan, bold: true, children: (() => {
17400
17631
  const title = MODAL_TITLES[type];
17401
17632
  const sideWidth = Math.max(3, Math.floor((terminalWidth - title.length - 2) / 2));
17402
17633
  return `${"\u2500".repeat(sideWidth)} ${title} ${"\u2500".repeat(sideWidth)}`;
17403
17634
  })() }) }),
17404
- /* @__PURE__ */ jsx20(
17405
- Box17,
17635
+ /* @__PURE__ */ jsx22(
17636
+ Box18,
17406
17637
  {
17407
17638
  flexDirection: "column",
17408
17639
  borderStyle: "round",
@@ -17411,17 +17642,17 @@ var Modal = memo13(({
17411
17642
  flexGrow: 1,
17412
17643
  children: visibleLines.map((line, i) => {
17413
17644
  const showScrollbar = totalLines > maxHeight && i >= scrollbarPosition && i < scrollbarPosition + scrollbarHeight;
17414
- return /* @__PURE__ */ jsxs16(Box17, { children: [
17415
- /* @__PURE__ */ jsx20(Text18, { color: THEME.white, wrap: "truncate", children: line }),
17416
- /* @__PURE__ */ jsx20(Box17, { flexGrow: 1 }),
17417
- totalLines > maxHeight && /* @__PURE__ */ jsx20(Text18, { color: showScrollbar ? THEME.cyan : THEME.dimGray, children: showScrollbar ? "\u2588" : "\u2502" })
17645
+ return /* @__PURE__ */ jsxs17(Box18, { children: [
17646
+ /* @__PURE__ */ jsx22(Text20, { color: THEME.white, wrap: "truncate", children: line }),
17647
+ /* @__PURE__ */ jsx22(Box18, { flexGrow: 1 }),
17648
+ totalLines > maxHeight && /* @__PURE__ */ jsx22(Text20, { color: showScrollbar ? THEME.cyan : THEME.dimGray, children: showScrollbar ? "\u2588" : "\u2502" })
17418
17649
  ] }, i);
17419
17650
  })
17420
17651
  }
17421
17652
  ),
17422
- /* @__PURE__ */ jsxs16(Box17, { justifyContent: "space-between", paddingX: 1, children: [
17423
- /* @__PURE__ */ jsx20(Text18, { dimColor: true, color: THEME.gray, children: "\u2191\u2193/jk: scroll | g/G: top/bottom | ESC/q: close" }),
17424
- /* @__PURE__ */ jsxs16(Text18, { dimColor: true, color: THEME.cyan, children: [
17653
+ /* @__PURE__ */ jsxs17(Box18, { justifyContent: "space-between", paddingX: 1, children: [
17654
+ /* @__PURE__ */ jsx22(Text20, { dimColor: true, color: THEME.gray, children: "\u2191\u2193/jk: scroll | g/G: top/bottom | ESC/q: close" }),
17655
+ /* @__PURE__ */ jsxs17(Text20, { dimColor: true, color: THEME.cyan, children: [
17425
17656
  startLine,
17426
17657
  "-",
17427
17658
  endLine,
@@ -17435,8 +17666,8 @@ var Modal = memo13(({
17435
17666
  });
17436
17667
 
17437
17668
  // src/platform/tui/components/app/bottom-region.tsx
17438
- import { Box as Box18 } from "ink";
17439
- import { jsx as jsx21, jsxs as jsxs17 } from "react/jsx-runtime";
17669
+ import { Box as Box19 } from "ink";
17670
+ import { jsx as jsx23, jsxs as jsxs18 } from "react/jsx-runtime";
17440
17671
  var BottomRegion = ({
17441
17672
  input,
17442
17673
  setInput,
@@ -17460,8 +17691,8 @@ var BottomRegion = ({
17460
17691
  const suggestionCount = isSlashMode && !hasArgs && inputRequest.status !== "active" ? Math.min(getMatchingCommands(partialCmd).length, MAX_SUGGESTIONS) : 0;
17461
17692
  const previewHeight = suggestionCount;
17462
17693
  const bottomMinHeight = 7;
17463
- return /* @__PURE__ */ jsxs17(Box18, { flexDirection: "column", minHeight: bottomMinHeight, children: [
17464
- /* @__PURE__ */ jsx21(
17694
+ return /* @__PURE__ */ jsxs18(Box19, { flexDirection: "column", minHeight: bottomMinHeight, children: [
17695
+ /* @__PURE__ */ jsx23(
17465
17696
  StatusDisplay,
17466
17697
  {
17467
17698
  retryState,
@@ -17471,7 +17702,7 @@ var BottomRegion = ({
17471
17702
  inputRequest
17472
17703
  }
17473
17704
  ),
17474
- /* @__PURE__ */ jsx21(
17705
+ /* @__PURE__ */ jsx23(
17475
17706
  ChatInput,
17476
17707
  {
17477
17708
  value: input,
@@ -17484,7 +17715,7 @@ var BottomRegion = ({
17484
17715
  onSecretSubmit: handleSecretSubmit
17485
17716
  }
17486
17717
  ),
17487
- /* @__PURE__ */ jsx21(Box18, { marginTop: 1, children: /* @__PURE__ */ jsx21(
17718
+ /* @__PURE__ */ jsx23(Box19, { marginTop: 1, children: /* @__PURE__ */ jsx23(
17488
17719
  footer_default,
17489
17720
  {
17490
17721
  phase: stats.phase,
@@ -17501,16 +17732,16 @@ var BottomRegion = ({
17501
17732
  };
17502
17733
 
17503
17734
  // src/platform/tui/app.tsx
17504
- import { jsx as jsx22, jsxs as jsxs18 } from "react/jsx-runtime";
17735
+ import { jsx as jsx24, jsxs as jsxs19 } from "react/jsx-runtime";
17505
17736
  var MODEL_NAME = getModel() || DEFAULT_MODEL;
17506
17737
  var App = ({ autoApprove = false, target }) => {
17507
17738
  const { exit } = useApp();
17508
17739
  const { stdout } = useStdout4();
17509
17740
  const terminalWidth = stdout?.columns ?? 80;
17510
- const [input, setInput] = useState6("");
17511
- const [secretInput, setSecretInput] = useState6("");
17512
- const [autoApproveMode, setAutoApproveMode] = useState6(autoApprove);
17513
- const [modal, setModal] = useState6({ type: null, content: "", scrollOffset: 0 });
17741
+ const [input, setInput] = useState7("");
17742
+ const [secretInput, setSecretInput] = useState7("");
17743
+ const [autoApproveMode, setAutoApproveMode] = useState7(autoApprove);
17744
+ const [modal, setModal] = useState7({ type: null, content: "", scrollOffset: 0 });
17514
17745
  const {
17515
17746
  agent,
17516
17747
  messages,
@@ -17528,17 +17759,19 @@ var App = ({ autoApprove = false, target }) => {
17528
17759
  abort,
17529
17760
  cancelInputRequest,
17530
17761
  addMessage,
17531
- refreshStats
17762
+ refreshStats,
17763
+ liveReasoning,
17764
+ isReasoning
17532
17765
  } = useAgent(autoApproveMode, target);
17533
- const isProcessingRef = useRef8(isProcessing);
17766
+ const isProcessingRef = useRef9(isProcessing);
17534
17767
  isProcessingRef.current = isProcessing;
17535
- const autoApproveModeRef = useRef8(autoApproveMode);
17768
+ const autoApproveModeRef = useRef9(autoApproveMode);
17536
17769
  autoApproveModeRef.current = autoApproveMode;
17537
- const inputRequestRef = useRef8(inputRequest);
17770
+ const inputRequestRef = useRef9(inputRequest);
17538
17771
  inputRequestRef.current = inputRequest;
17539
- const isModalOpenRef = useRef8(!!modal.type);
17772
+ const isModalOpenRef = useRef9(!!modal.type);
17540
17773
  isModalOpenRef.current = !!modal.type;
17541
- const inputRef = useRef8(input);
17774
+ const inputRef = useRef9(input);
17542
17775
  inputRef.current = input;
17543
17776
  const clearInput = useCallback9(() => {
17544
17777
  setInput("");
@@ -17552,7 +17785,7 @@ var App = ({ autoApprove = false, target }) => {
17552
17785
  const handleModalScroll = useCallback9((delta) => {
17553
17786
  setModal((prev) => {
17554
17787
  const lines = prev.content.split("\n");
17555
- const maxHeight = (stdout?.rows ?? 24) - 6;
17788
+ const maxHeight = (stdout?.rows ?? TUI_DISPLAY_LIMITS.TERMINAL_DEFAULT_ROWS) - TUI_DISPLAY_LIMITS.MODAL_CHROME_HEIGHT;
17556
17789
  const maxScroll = Math.max(0, lines.length - maxHeight);
17557
17790
  const newOffset = Math.max(0, Math.min(maxScroll, prev.scrollOffset + delta));
17558
17791
  return { ...prev, scrollOffset: newOffset };
@@ -17581,6 +17814,15 @@ var App = ({ autoApprove = false, target }) => {
17581
17814
  isProcessingRef,
17582
17815
  autoApproveModeRef
17583
17816
  });
17817
+ const handleSecretSubmit = useCallback9((value) => {
17818
+ const ir = inputRequestRef.current;
17819
+ if (ir.status !== "active") return;
17820
+ const displayText = ir.isPassword ? "\u2022".repeat(Math.min(value.length, TUI_DISPLAY_LIMITS.PASSWORD_MASK_MAX)) : value;
17821
+ addMessage("system", `${UI_MESSAGES.SECRET_PREFIX}${displayText}`);
17822
+ ir.resolve(value);
17823
+ setInputRequest({ status: "inactive" });
17824
+ setSecretInput("");
17825
+ }, [addMessage, setInputRequest]);
17584
17826
  const handleSubmit = useCallback9(async (value) => {
17585
17827
  const trimmed = value.trim();
17586
17828
  if (!trimmed) return;
@@ -17589,22 +17831,15 @@ var App = ({ autoApprove = false, target }) => {
17589
17831
  if (trimmed.startsWith("/")) {
17590
17832
  const [cmd, ...args] = trimmed.slice(1).split(" ");
17591
17833
  await handleCommand(cmd, args);
17834
+ } else if (inputRequestRef.current.status === "active") {
17835
+ handleSecretSubmit(trimmed);
17592
17836
  } else if (isProcessingRef.current) {
17593
17837
  agent.enqueueUserInput(trimmed);
17594
- addMessage("system", "\u{1F4AC} Message queued \u2014 will be processed at next iteration");
17838
+ agent.abort();
17595
17839
  } else {
17596
17840
  await executeTask(trimmed);
17597
17841
  }
17598
- }, [agent, addMessage, executeTask, handleCommand]);
17599
- const handleSecretSubmit = useCallback9((value) => {
17600
- const ir = inputRequestRef.current;
17601
- if (ir.status !== "active") return;
17602
- const displayText = ir.isPassword ? "\u2022".repeat(Math.min(value.length, 20)) : value;
17603
- addMessage("system", `\u21B3 ${displayText}`);
17604
- ir.resolve(value);
17605
- setInputRequest({ status: "inactive" });
17606
- setSecretInput("");
17607
- }, [addMessage, setInputRequest]);
17842
+ }, [agent, addMessage, executeTask, handleCommand, handleSecretSubmit]);
17608
17843
  useKeyboardShortcuts({
17609
17844
  addMessage,
17610
17845
  handleExit,
@@ -17617,7 +17852,7 @@ var App = ({ autoApprove = false, target }) => {
17617
17852
  clearInput
17618
17853
  });
17619
17854
  if (modal.type) {
17620
- return /* @__PURE__ */ jsx22(Box19, { flexDirection: "column", paddingX: 1, width: terminalWidth, children: /* @__PURE__ */ jsx22(
17855
+ return /* @__PURE__ */ jsx24(Box20, { flexDirection: "column", paddingX: 1, width: terminalWidth, children: /* @__PURE__ */ jsx24(
17621
17856
  Modal,
17622
17857
  {
17623
17858
  type: modal.type,
@@ -17628,8 +17863,8 @@ var App = ({ autoApprove = false, target }) => {
17628
17863
  }
17629
17864
  ) });
17630
17865
  }
17631
- return /* @__PURE__ */ jsxs18(Box19, { flexDirection: "column", paddingX: 1, width: terminalWidth, children: [
17632
- /* @__PURE__ */ jsx22(Box19, { flexDirection: "column", children: /* @__PURE__ */ jsx22(
17866
+ return /* @__PURE__ */ jsxs19(Box20, { flexDirection: "column", width: terminalWidth, children: [
17867
+ /* @__PURE__ */ jsx24(Box20, { flexDirection: "column", children: /* @__PURE__ */ jsx24(
17633
17868
  MessageList,
17634
17869
  {
17635
17870
  messages,
@@ -17638,7 +17873,14 @@ var App = ({ autoApprove = false, target }) => {
17638
17873
  version: APP_VERSION
17639
17874
  }
17640
17875
  ) }),
17641
- /* @__PURE__ */ jsx22(
17876
+ /* @__PURE__ */ jsx24(
17877
+ LiveReasoningPanel,
17878
+ {
17879
+ content: liveReasoning,
17880
+ isReasoning
17881
+ }
17882
+ ),
17883
+ /* @__PURE__ */ jsx24(AnimationProvider, { children: /* @__PURE__ */ jsx24(
17642
17884
  BottomRegion,
17643
17885
  {
17644
17886
  input,
@@ -17657,13 +17899,13 @@ var App = ({ autoApprove = false, target }) => {
17657
17899
  totalTokens: currentTokens,
17658
17900
  turnCount
17659
17901
  }
17660
- )
17902
+ ) })
17661
17903
  ] });
17662
17904
  };
17663
17905
  var app_default = App;
17664
17906
 
17665
17907
  // src/platform/tui/cli/commands/interactive.tsx
17666
- import { jsx as jsx23 } from "react/jsx-runtime";
17908
+ import { jsx as jsx25 } from "react/jsx-runtime";
17667
17909
  async function interactiveAction(options) {
17668
17910
  const { dangerouslySkipPermissions: skipPermissions = false, target } = options;
17669
17911
  console.clear();
@@ -17672,13 +17914,13 @@ async function interactiveAction(options) {
17672
17914
  console.log(chalk.hex(HEX.red)("[!] All tool executions will be auto-approved!\n"));
17673
17915
  }
17674
17916
  const { waitUntilExit } = render(
17675
- /* @__PURE__ */ jsx23(AnimationProvider, { children: /* @__PURE__ */ jsx23(
17917
+ /* @__PURE__ */ jsx25(
17676
17918
  app_default,
17677
17919
  {
17678
17920
  autoApprove: skipPermissions,
17679
17921
  target
17680
17922
  }
17681
- ) })
17923
+ )
17682
17924
  );
17683
17925
  await waitUntilExit();
17684
17926
  }