reasonix 0.5.6 → 0.5.8

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/cli/index.js CHANGED
@@ -2570,9 +2570,79 @@ function formatLoopError(err) {
2570
2570
  }
2571
2571
 
2572
2572
  // src/at-mentions.ts
2573
- import { existsSync as existsSync4, readFileSync as readFileSync5, statSync as statSync2 } from "fs";
2574
- import { isAbsolute, relative, resolve } from "path";
2573
+ import { existsSync as existsSync4, readFileSync as readFileSync5, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
2574
+ import { isAbsolute, join as join5, relative, resolve } from "path";
2575
2575
  var DEFAULT_AT_MENTION_MAX_BYTES = 64 * 1024;
2576
+ var DEFAULT_PICKER_IGNORE_DIRS = [
2577
+ "node_modules",
2578
+ ".git",
2579
+ "dist",
2580
+ "build",
2581
+ ".next",
2582
+ "out",
2583
+ "coverage",
2584
+ ".cache",
2585
+ ".vscode",
2586
+ ".idea",
2587
+ "target",
2588
+ ".venv",
2589
+ "venv",
2590
+ "__pycache__"
2591
+ ];
2592
+ function listFilesSync(root, opts = {}) {
2593
+ const maxResults = Math.max(1, opts.maxResults ?? 500);
2594
+ const ignore = new Set(opts.ignoreDirs ?? DEFAULT_PICKER_IGNORE_DIRS);
2595
+ const rootAbs = resolve(root);
2596
+ const out = [];
2597
+ const walk2 = (dirAbs, dirRel) => {
2598
+ if (out.length >= maxResults) return;
2599
+ let entries;
2600
+ try {
2601
+ entries = readdirSync2(dirAbs, { withFileTypes: true });
2602
+ } catch {
2603
+ return;
2604
+ }
2605
+ entries.sort((a, b) => a.name.localeCompare(b.name));
2606
+ for (const ent of entries) {
2607
+ if (out.length >= maxResults) return;
2608
+ const relPath = dirRel ? `${dirRel}/${ent.name}` : ent.name;
2609
+ if (ent.isDirectory()) {
2610
+ if (ent.name.startsWith(".") || ignore.has(ent.name)) continue;
2611
+ walk2(join5(dirAbs, ent.name), relPath);
2612
+ } else if (ent.isFile()) {
2613
+ out.push(relPath);
2614
+ }
2615
+ }
2616
+ };
2617
+ walk2(rootAbs, "");
2618
+ return out;
2619
+ }
2620
+ var AT_PICKER_PREFIX = /(?:^|\s)@([a-zA-Z0-9_./\\-]*)$/;
2621
+ function detectAtPicker(input) {
2622
+ const m = AT_PICKER_PREFIX.exec(input);
2623
+ if (!m) return null;
2624
+ const query = m[1] ?? "";
2625
+ const atOffset = input.length - query.length - 1;
2626
+ return { query, atOffset };
2627
+ }
2628
+ function rankPickerCandidates(files, query, limit = 40) {
2629
+ if (!query) return files.slice(0, limit);
2630
+ const needle = query.toLowerCase();
2631
+ const scored = [];
2632
+ for (const f of files) {
2633
+ const lower = f.toLowerCase();
2634
+ const hit = lower.indexOf(needle);
2635
+ if (hit < 0) continue;
2636
+ const slash = lower.lastIndexOf("/");
2637
+ const base = slash >= 0 ? lower.slice(slash + 1) : lower;
2638
+ let score = 2;
2639
+ if (base.startsWith(needle)) score = 0;
2640
+ else if (lower.startsWith(needle)) score = 1;
2641
+ scored.push({ path: f, score: score * 1e4 + hit });
2642
+ }
2643
+ scored.sort((a, b) => a.score - b.score);
2644
+ return scored.slice(0, limit).map((s) => s.path);
2645
+ }
2576
2646
  var AT_MENTION_PATTERN = /(?<=^|\s)@([a-zA-Z0-9_./\\-]+)/g;
2577
2647
  function expandAtMentions(text, rootDir, opts = {}) {
2578
2648
  const maxBytes = opts.maxBytes ?? DEFAULT_AT_MENTION_MAX_BYTES;
@@ -5309,7 +5379,7 @@ function sep() {
5309
5379
  // src/version.ts
5310
5380
  import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as readFileSync9, writeFileSync as writeFileSync4 } from "fs";
5311
5381
  import { homedir as homedir4 } from "os";
5312
- import { dirname as dirname6, join as join6 } from "path";
5382
+ import { dirname as dirname6, join as join7 } from "path";
5313
5383
  import { fileURLToPath as fileURLToPath2 } from "url";
5314
5384
  var REGISTRY_URL = "https://registry.npmjs.org/reasonix/latest";
5315
5385
  var LATEST_CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
@@ -5318,7 +5388,7 @@ function readPackageVersion() {
5318
5388
  try {
5319
5389
  let dir = dirname6(fileURLToPath2(import.meta.url));
5320
5390
  for (let i = 0; i < 6; i++) {
5321
- const p = join6(dir, "package.json");
5391
+ const p = join7(dir, "package.json");
5322
5392
  if (existsSync7(p)) {
5323
5393
  const pkg = JSON.parse(readFileSync9(p, "utf8"));
5324
5394
  if (pkg?.name === "reasonix" && typeof pkg.version === "string") {
@@ -5335,7 +5405,7 @@ function readPackageVersion() {
5335
5405
  }
5336
5406
  var VERSION = readPackageVersion();
5337
5407
  function cachePath(homeDirOverride) {
5338
- return join6(homeDirOverride ?? homedir4(), ".reasonix", "version-cache.json");
5408
+ return join7(homeDirOverride ?? homedir4(), ".reasonix", "version-cache.json");
5339
5409
  }
5340
5410
  function readCache(homeDirOverride) {
5341
5411
  try {
@@ -5410,9 +5480,9 @@ function isNpxInstall() {
5410
5480
  // src/usage.ts
5411
5481
  import { appendFileSync as appendFileSync2, existsSync as existsSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync10, statSync as statSync4 } from "fs";
5412
5482
  import { homedir as homedir5 } from "os";
5413
- import { dirname as dirname7, join as join7 } from "path";
5483
+ import { dirname as dirname7, join as join8 } from "path";
5414
5484
  function defaultUsageLogPath(homeDirOverride) {
5415
- return join7(homeDirOverride ?? homedir5(), ".reasonix", "usage.jsonl");
5485
+ return join8(homeDirOverride ?? homedir5(), ".reasonix", "usage.jsonl");
5416
5486
  }
5417
5487
  function appendUsage(input) {
5418
5488
  const record = {
@@ -5536,11 +5606,11 @@ function formatLogSize(path = defaultUsageLogPath()) {
5536
5606
  // src/cli/commands/chat.tsx
5537
5607
  import { existsSync as existsSync10, statSync as statSync6 } from "fs";
5538
5608
  import { render } from "ink";
5539
- import React15, { useState as useState7 } from "react";
5609
+ import React16, { useState as useState7 } from "react";
5540
5610
 
5541
5611
  // src/cli/ui/App.tsx
5542
- import { Box as Box11, Static, Text as Text11, useApp, useInput as useInput4 } from "ink";
5543
- import React12, { useCallback, useEffect as useEffect2, useMemo, useRef as useRef2, useState as useState5 } from "react";
5612
+ import { Box as Box12, Static, Text as Text12, useApp, useInput as useInput4 } from "ink";
5613
+ import React13, { useCallback, useEffect as useEffect2, useMemo, useRef as useRef2, useState as useState5 } from "react";
5544
5614
 
5545
5615
  // src/tools/skills.ts
5546
5616
  function registerSkillTools(registry, opts = {}) {
@@ -5611,13 +5681,44 @@ ${skill.body}${argsBlock}`;
5611
5681
  return registry;
5612
5682
  }
5613
5683
 
5684
+ // src/cli/ui/AtMentionSuggestions.tsx
5685
+ import { Box, Text } from "ink";
5686
+ import React from "react";
5687
+ function AtMentionSuggestions({
5688
+ matches,
5689
+ selectedIndex,
5690
+ query
5691
+ }) {
5692
+ if (matches === null) return null;
5693
+ if (matches.length === 0) {
5694
+ return /* @__PURE__ */ React.createElement(Box, { paddingX: 1 }, /* @__PURE__ */ React.createElement(Text, { color: "yellow" }, 'no files match "@', query, '"'), /* @__PURE__ */ React.createElement(Text, { dimColor: true }, " ", "\u2014 keep typing, or Backspace to edit. Paths resolve from the code root."));
5695
+ }
5696
+ const MAX = 8;
5697
+ const total = matches.length;
5698
+ const windowStart = total <= MAX ? 0 : Math.max(0, Math.min(selectedIndex - Math.floor(MAX / 2), total - MAX));
5699
+ const shown = matches.slice(windowStart, windowStart + MAX);
5700
+ const hiddenAbove = windowStart;
5701
+ const hiddenBelow = total - windowStart - shown.length;
5702
+ return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", paddingX: 1 }, hiddenAbove > 0 ? /* @__PURE__ */ React.createElement(Text, { dimColor: true }, " \u2191 ", hiddenAbove, " more above") : null, shown.map((path, i) => /* @__PURE__ */ React.createElement(FileRow, { key: path, path, isSelected: windowStart + i === selectedIndex })), hiddenBelow > 0 ? /* @__PURE__ */ React.createElement(Text, { dimColor: true }, " \u2193 ", hiddenBelow, " more below") : null, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, " [\u2191\u2193] navigate \xB7 [Tab]/[Enter] pick \xB7 file content inlined on send"));
5703
+ }
5704
+ function FileRow({ path, isSelected }) {
5705
+ const marker = isSelected ? "\u25B8" : " ";
5706
+ const slash = path.lastIndexOf("/");
5707
+ const dir = slash >= 0 ? `${path.slice(0, slash)}/` : "";
5708
+ const base = slash >= 0 ? path.slice(slash + 1) : path;
5709
+ if (isSelected) {
5710
+ return /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { bold: true, color: "cyan" }, marker, " ", base), /* @__PURE__ */ React.createElement(Text, { color: "cyan" }, dir ? ` ${dir}` : ""));
5711
+ }
5712
+ return /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, marker, " ", base, dir ? ` ${dir}` : ""));
5713
+ }
5714
+
5614
5715
  // src/cli/ui/EventLog.tsx
5615
- import { Box as Box3, Text as Text3, useStdout } from "ink";
5616
- import React4 from "react";
5716
+ import { Box as Box4, Text as Text4, useStdout } from "ink";
5717
+ import React5 from "react";
5617
5718
 
5618
5719
  // src/cli/ui/PlanStateBlock.tsx
5619
- import { Box, Text } from "ink";
5620
- import React from "react";
5720
+ import { Box as Box2, Text as Text2 } from "ink";
5721
+ import React2 from "react";
5621
5722
  function PlanStateBlock({ planState }) {
5622
5723
  const fields = [];
5623
5724
  if (planState.subgoals.length) fields.push(["subgoals", planState.subgoals, "cyan", false]);
@@ -5628,14 +5729,14 @@ function PlanStateBlock({ planState }) {
5628
5729
  if (planState.rejectedPaths.length)
5629
5730
  fields.push(["rejected", planState.rejectedPaths, "red", true]);
5630
5731
  if (fields.length === 0) return null;
5631
- return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginBottom: 1 }, fields.map(([label, items, color, dim]) => /* @__PURE__ */ React.createElement(Text, { key: label }, /* @__PURE__ */ React.createElement(Text, { color, bold: true, dimColor: dim }, "\u2039 ", label), /* @__PURE__ */ React.createElement(Text, { dimColor: true }, ` (${items.length})`), /* @__PURE__ */ React.createElement(Text, null, `: ${items.join(" \xB7 ")}`))));
5732
+ return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", marginBottom: 1 }, fields.map(([label, items, color, dim]) => /* @__PURE__ */ React2.createElement(Text2, { key: label }, /* @__PURE__ */ React2.createElement(Text2, { color, bold: true, dimColor: dim }, "\u2039 ", label), /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, ` (${items.length})`), /* @__PURE__ */ React2.createElement(Text2, null, `: ${items.join(" \xB7 ")}`))));
5632
5733
  }
5633
5734
 
5634
5735
  // src/cli/ui/markdown.tsx
5635
5736
  import { readFileSync as readFileSync11, statSync as statSync5 } from "fs";
5636
- import { isAbsolute as isAbsolute4, join as join8 } from "path";
5637
- import { Box as Box2, Text as Text2 } from "ink";
5638
- import React2 from "react";
5737
+ import { isAbsolute as isAbsolute4, join as join9 } from "path";
5738
+ import { Box as Box3, Text as Text3 } from "ink";
5739
+ import React3 from "react";
5639
5740
  var SUPERSCRIPT = {
5640
5741
  "0": "\u2070",
5641
5742
  "1": "\xB9",
@@ -5711,7 +5812,7 @@ function parseCitationUrl(url) {
5711
5812
  function validateCitation(url, projectRoot) {
5712
5813
  const parts = parseCitationUrl(url);
5713
5814
  if (!parts || !parts.path) return { ok: false, reason: "empty path" };
5714
- const fullPath = isAbsolute4(parts.path) ? parts.path : join8(projectRoot, parts.path);
5815
+ const fullPath = isAbsolute4(parts.path) ? parts.path : join9(projectRoot, parts.path);
5715
5816
  let stat;
5716
5817
  try {
5717
5818
  stat = statSync5(fullPath);
@@ -5759,57 +5860,57 @@ function InlineMd({
5759
5860
  for (const m of text.matchAll(INLINE_RE)) {
5760
5861
  const start = m.index ?? 0;
5761
5862
  if (start > last) {
5762
- parts.push(/* @__PURE__ */ React2.createElement(Text2, { key: `t${idx++}` }, text.slice(last, start)));
5863
+ parts.push(/* @__PURE__ */ React3.createElement(Text3, { key: `t${idx++}` }, text.slice(last, start)));
5763
5864
  }
5764
5865
  if (m[2] !== void 0 && m[3] !== void 0) {
5765
5866
  const linkText = m[2];
5766
5867
  const url = m[3];
5767
5868
  if (isExternalUrl(url)) {
5768
5869
  parts.push(
5769
- /* @__PURE__ */ React2.createElement(Text2, { key: `l${idx++}`, color: "blue", underline: true }, linkText)
5870
+ /* @__PURE__ */ React3.createElement(Text3, { key: `l${idx++}`, color: "blue", underline: true }, linkText)
5770
5871
  );
5771
5872
  } else {
5772
5873
  const status = citations?.get(url);
5773
5874
  if (status && !status.ok) {
5774
5875
  parts.push(
5775
- /* @__PURE__ */ React2.createElement(Text2, { key: `l${idx++}`, color: "red", strikethrough: true }, `${linkText} \u2717`)
5876
+ /* @__PURE__ */ React3.createElement(Text3, { key: `l${idx++}`, color: "red", strikethrough: true }, `${linkText} \u2717`)
5776
5877
  );
5777
5878
  } else {
5778
5879
  parts.push(
5779
- /* @__PURE__ */ React2.createElement(Text2, { key: `l${idx++}`, color: "cyan", underline: true }, linkText)
5880
+ /* @__PURE__ */ React3.createElement(Text3, { key: `l${idx++}`, color: "cyan", underline: true }, linkText)
5780
5881
  );
5781
5882
  }
5782
5883
  }
5783
5884
  } else if (m[4] !== void 0) {
5784
5885
  parts.push(
5785
- /* @__PURE__ */ React2.createElement(Text2, { key: `b${idx++}`, bold: true }, m[4])
5886
+ /* @__PURE__ */ React3.createElement(Text3, { key: `b${idx++}`, bold: true }, m[4])
5786
5887
  );
5787
5888
  } else if (m[5] !== void 0) {
5788
5889
  const stripped = m[5].replace(/^(\w+)\s+/, "");
5789
5890
  parts.push(
5790
- /* @__PURE__ */ React2.createElement(Text2, { key: `c${idx++}`, color: "yellow" }, stripped)
5891
+ /* @__PURE__ */ React3.createElement(Text3, { key: `c${idx++}`, color: "yellow" }, stripped)
5791
5892
  );
5792
5893
  } else if (m[6] !== void 0) {
5793
5894
  parts.push(
5794
- /* @__PURE__ */ React2.createElement(Text2, { key: `c${idx++}`, color: "yellow" }, m[6])
5895
+ /* @__PURE__ */ React3.createElement(Text3, { key: `c${idx++}`, color: "yellow" }, m[6])
5795
5896
  );
5796
5897
  } else if (m[7] !== void 0) {
5797
5898
  parts.push(
5798
- /* @__PURE__ */ React2.createElement(Text2, { key: `i${idx++}`, italic: true }, m[7])
5899
+ /* @__PURE__ */ React3.createElement(Text3, { key: `i${idx++}`, italic: true }, m[7])
5799
5900
  );
5800
5901
  }
5801
5902
  last = start + m[0].length;
5802
5903
  }
5803
5904
  if (last < text.length) {
5804
- parts.push(/* @__PURE__ */ React2.createElement(Text2, { key: `t${idx++}` }, text.slice(last)));
5905
+ parts.push(/* @__PURE__ */ React3.createElement(Text3, { key: `t${idx++}` }, text.slice(last)));
5805
5906
  }
5806
5907
  if (padTo !== void 0) {
5807
5908
  const seen = visibleWidth(text);
5808
5909
  if (seen < padTo) {
5809
- parts.push(/* @__PURE__ */ React2.createElement(Text2, { key: `pad${idx++}` }, " ".repeat(padTo - seen)));
5910
+ parts.push(/* @__PURE__ */ React3.createElement(Text3, { key: `pad${idx++}` }, " ".repeat(padTo - seen)));
5810
5911
  }
5811
5912
  }
5812
- return /* @__PURE__ */ React2.createElement(Text2, null, parts);
5913
+ return /* @__PURE__ */ React3.createElement(Text3, null, parts);
5813
5914
  }
5814
5915
  function stripInlineMarkup(s) {
5815
5916
  return s.replace(/\[([^\]\n]+)\]\(([^)\n]+)\)/g, "$1").replace(/\*\*([^*\n]+?)\*\*/g, "$1").replace(/```([^\n]+?)```/g, (_m, c) => c.replace(/^(\w+)\s+/, "")).replace(/`([^`\n]+?)`/g, "$1").replace(/(?<![*\w])\*([^*\n]+?)\*(?!\w)/g, "$1");
@@ -6005,19 +6106,19 @@ function parseBlocks(raw) {
6005
6106
  function BlockView({ block, citations }) {
6006
6107
  switch (block.kind) {
6007
6108
  case "heading":
6008
- return /* @__PURE__ */ React2.createElement(Text2, { bold: true, color: "cyan" }, /* @__PURE__ */ React2.createElement(InlineMd, { text: block.text, citations }));
6109
+ return /* @__PURE__ */ React3.createElement(Text3, { bold: true, color: "cyan" }, /* @__PURE__ */ React3.createElement(InlineMd, { text: block.text, citations }));
6009
6110
  case "paragraph":
6010
- return /* @__PURE__ */ React2.createElement(InlineMd, { text: block.text, citations });
6111
+ return /* @__PURE__ */ React3.createElement(InlineMd, { text: block.text, citations });
6011
6112
  case "bullet":
6012
- return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column" }, block.items.map((item, i) => /* @__PURE__ */ React2.createElement(Box2, { key: `${i}-${item.slice(0, 24)}` }, /* @__PURE__ */ React2.createElement(Text2, { color: "cyan" }, block.ordered ? ` ${block.start + i}. ` : " \u2022 "), /* @__PURE__ */ React2.createElement(InlineMd, { text: item, citations }))));
6113
+ return /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column" }, block.items.map((item, i) => /* @__PURE__ */ React3.createElement(Box3, { key: `${i}-${item.slice(0, 24)}` }, /* @__PURE__ */ React3.createElement(Text3, { color: "cyan" }, block.ordered ? ` ${block.start + i}. ` : " \u2022 "), /* @__PURE__ */ React3.createElement(InlineMd, { text: item, citations }))));
6013
6114
  case "code":
6014
- return /* @__PURE__ */ React2.createElement(Box2, { borderStyle: "single", borderColor: "gray", paddingX: 1 }, /* @__PURE__ */ React2.createElement(Text2, { color: "yellow" }, block.text));
6115
+ return /* @__PURE__ */ React3.createElement(Box3, { borderStyle: "single", borderColor: "gray", paddingX: 1 }, /* @__PURE__ */ React3.createElement(Text3, { color: "yellow" }, block.text));
6015
6116
  case "edit-block":
6016
- return /* @__PURE__ */ React2.createElement(EditBlockRow, { block });
6117
+ return /* @__PURE__ */ React3.createElement(EditBlockRow, { block });
6017
6118
  case "table":
6018
- return /* @__PURE__ */ React2.createElement(TableBlockRow, { block, citations });
6119
+ return /* @__PURE__ */ React3.createElement(TableBlockRow, { block, citations });
6019
6120
  case "hr":
6020
- return /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
6121
+ return /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
6021
6122
  }
6022
6123
  }
6023
6124
  function splitTableRow(line) {
@@ -6035,14 +6136,14 @@ function TableBlockRow({ block, citations }) {
6035
6136
  widths.push(Math.min(40, Math.max(3, ...cellLengths)));
6036
6137
  }
6037
6138
  const separator = widths.map((w) => "\u2500".repeat(w)).join("\u2500\u253C\u2500");
6038
- return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column" }, /* @__PURE__ */ React2.createElement(Box2, null, block.header.map((cell, ci) => (
6139
+ return /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column" }, /* @__PURE__ */ React3.createElement(Box3, null, block.header.map((cell, ci) => (
6039
6140
  // biome-ignore lint/suspicious/noArrayIndexKey: table columns never reorder — derived from a static header array
6040
- /* @__PURE__ */ React2.createElement(Text2, { key: `h-${ci}`, bold: true, color: "cyan" }, /* @__PURE__ */ React2.createElement(InlineMd, { text: cell, padTo: widths[ci] ?? 3, citations }), ci < colCount - 1 ? " \u2502 " : "")
6041
- ))), /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, separator), block.rows.map((row2, ri) => (
6141
+ /* @__PURE__ */ React3.createElement(Text3, { key: `h-${ci}`, bold: true, color: "cyan" }, /* @__PURE__ */ React3.createElement(InlineMd, { text: cell, padTo: widths[ci] ?? 3, citations }), ci < colCount - 1 ? " \u2502 " : "")
6142
+ ))), /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, separator), block.rows.map((row2, ri) => (
6042
6143
  // biome-ignore lint/suspicious/noArrayIndexKey: table rows render in source order and don't reorder
6043
- /* @__PURE__ */ React2.createElement(Box2, { key: `r-${ri}` }, Array.from({ length: colCount }).map((_, ci) => (
6144
+ /* @__PURE__ */ React3.createElement(Box3, { key: `r-${ri}` }, Array.from({ length: colCount }).map((_, ci) => (
6044
6145
  // biome-ignore lint/suspicious/noArrayIndexKey: same — column axis is fixed by the table shape
6045
- /* @__PURE__ */ React2.createElement(Text2, { key: `c-${ri}-${ci}` }, /* @__PURE__ */ React2.createElement(InlineMd, { text: row2[ci] ?? "", padTo: widths[ci] ?? 3, citations }), ci < colCount - 1 ? " \u2502 " : "")
6146
+ /* @__PURE__ */ React3.createElement(Text3, { key: `c-${ri}-${ci}` }, /* @__PURE__ */ React3.createElement(InlineMd, { text: row2[ci] ?? "", padTo: widths[ci] ?? 3, citations }), ci < colCount - 1 ? " \u2502 " : "")
6046
6147
  )))
6047
6148
  )));
6048
6149
  }
@@ -6062,28 +6163,28 @@ function EditBlockRow({ block }) {
6062
6163
  const isNewFile = block.search.length === 0;
6063
6164
  const searchLines = block.search.split("\n");
6064
6165
  const replaceLines = block.replace.split("\n");
6065
- return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React2.createElement(Box2, null, /* @__PURE__ */ React2.createElement(Text2, { bold: true, color: "cyan" }, block.filename), isNewFile ? /* @__PURE__ */ React2.createElement(Text2, { color: "green", bold: true }, " (new file)") : null), isNewFile ? null : /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", marginTop: 1 }, searchLines.map((line, i) => /* @__PURE__ */ React2.createElement(Text2, { key: `s-${i}-${line.length}`, color: "red" }, `- ${line}`))), /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", marginTop: isNewFile ? 1 : 0 }, replaceLines.map((line, i) => /* @__PURE__ */ React2.createElement(Text2, { key: `r-${i}-${line.length}`, color: "green" }, `+ ${line}`))));
6166
+ return /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React3.createElement(Box3, null, /* @__PURE__ */ React3.createElement(Text3, { bold: true, color: "cyan" }, block.filename), isNewFile ? /* @__PURE__ */ React3.createElement(Text3, { color: "green", bold: true }, " (new file)") : null), isNewFile ? null : /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", marginTop: 1 }, searchLines.map((line, i) => /* @__PURE__ */ React3.createElement(Text3, { key: `s-${i}-${line.length}`, color: "red" }, `- ${line}`))), /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", marginTop: isNewFile ? 1 : 0 }, replaceLines.map((line, i) => /* @__PURE__ */ React3.createElement(Text3, { key: `r-${i}-${line.length}`, color: "green" }, `+ ${line}`))));
6066
6167
  }
6067
6168
  function Markdown({ text, projectRoot }) {
6068
6169
  const cleaned = stripMath(text);
6069
6170
  const root = projectRoot ?? process.cwd();
6070
- const citations = React2.useMemo(() => collectCitations(cleaned, root), [cleaned, root]);
6071
- const blocks = React2.useMemo(() => parseBlocks(cleaned), [cleaned]);
6171
+ const citations = React3.useMemo(() => collectCitations(cleaned, root), [cleaned, root]);
6172
+ const blocks = React3.useMemo(() => parseBlocks(cleaned), [cleaned]);
6072
6173
  const broken = [];
6073
6174
  for (const [url, status] of citations) {
6074
6175
  if (!status.ok) broken.push({ url, reason: status.reason });
6075
6176
  }
6076
- return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", gap: 1 }, blocks.map((b, i) => /* @__PURE__ */ React2.createElement(BlockView, { key: `${i}-${b.kind}`, block: b, citations })), broken.length > 0 ? /* @__PURE__ */ React2.createElement(BrokenCitationsBlock, { items: broken }) : null);
6177
+ return /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", gap: 1 }, blocks.map((b, i) => /* @__PURE__ */ React3.createElement(BlockView, { key: `${i}-${b.kind}`, block: b, citations })), broken.length > 0 ? /* @__PURE__ */ React3.createElement(BrokenCitationsBlock, { items: broken }) : null);
6077
6178
  }
6078
6179
  function BrokenCitationsBlock({ items }) {
6079
- return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", borderStyle: "round", borderColor: "red", paddingX: 1 }, /* @__PURE__ */ React2.createElement(Text2, { color: "red", bold: true }, `\u26A0 ${items.length} broken citation${items.length > 1 ? "s" : ""} \u2014 the model referenced paths or lines that don't exist`), items.map((b, i) => (
6180
+ return /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", borderStyle: "round", borderColor: "red", paddingX: 1 }, /* @__PURE__ */ React3.createElement(Text3, { color: "red", bold: true }, `\u26A0 ${items.length} broken citation${items.length > 1 ? "s" : ""} \u2014 the model referenced paths or lines that don't exist`), items.map((b, i) => (
6080
6181
  // biome-ignore lint/suspicious/noArrayIndexKey: list is derived from a Map iteration order, stable per render
6081
- /* @__PURE__ */ React2.createElement(Text2, { key: `bc-${i}`, color: "red" }, ` \u2717 ${b.url} \u2192 ${b.reason}`)
6182
+ /* @__PURE__ */ React3.createElement(Text3, { key: `bc-${i}`, color: "red" }, ` \u2717 ${b.url} \u2192 ${b.reason}`)
6082
6183
  )));
6083
6184
  }
6084
6185
 
6085
6186
  // src/cli/ui/ticker.tsx
6086
- import React3, { createContext, useContext, useEffect, useState } from "react";
6187
+ import React4, { createContext, useContext, useEffect, useState } from "react";
6087
6188
  var TICK_MS = 120;
6088
6189
  var TickContext = createContext(0);
6089
6190
  function TickerProvider({ children, disabled }) {
@@ -6093,7 +6194,7 @@ function TickerProvider({ children, disabled }) {
6093
6194
  const id = setInterval(() => setTick((t) => t + 1), TICK_MS);
6094
6195
  return () => clearInterval(id);
6095
6196
  }, [disabled]);
6096
- return /* @__PURE__ */ React3.createElement(TickContext.Provider, { value: tick }, children);
6197
+ return /* @__PURE__ */ React4.createElement(TickContext.Provider, { value: tick }, children);
6097
6198
  }
6098
6199
  function useTick() {
6099
6200
  return useContext(TickContext);
@@ -6119,18 +6220,18 @@ function RoleGlyph({
6119
6220
  glyph,
6120
6221
  color
6121
6222
  }) {
6122
- return /* @__PURE__ */ React4.createElement(Text3, { color, bold: true }, glyph);
6223
+ return /* @__PURE__ */ React5.createElement(Text4, { color, bold: true }, glyph);
6123
6224
  }
6124
- var EventRow = React4.memo(function EventRow2({
6225
+ var EventRow = React5.memo(function EventRow2({
6125
6226
  event,
6126
6227
  projectRoot
6127
6228
  }) {
6128
6229
  if (event.role === "user") {
6129
- return /* @__PURE__ */ React4.createElement(Box3, { marginTop: event.leadSeparator ? 1 : 0 }, /* @__PURE__ */ React4.createElement(RoleGlyph, { glyph: ROLE_GLYPH.user, color: "cyan" }), /* @__PURE__ */ React4.createElement(Text3, null, " ", event.text));
6230
+ return /* @__PURE__ */ React5.createElement(Box4, { marginTop: event.leadSeparator ? 1 : 0 }, /* @__PURE__ */ React5.createElement(RoleGlyph, { glyph: ROLE_GLYPH.user, color: "cyan" }), /* @__PURE__ */ React5.createElement(Text4, null, " ", event.text));
6130
6231
  }
6131
6232
  if (event.role === "assistant") {
6132
- if (event.streaming) return /* @__PURE__ */ React4.createElement(StreamingAssistant, { event });
6133
- return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React4.createElement(Box3, null, /* @__PURE__ */ React4.createElement(RoleGlyph, { glyph: ROLE_GLYPH.assistant, color: "green" }), event.stats ? /* @__PURE__ */ React4.createElement(Text3, { dimColor: true }, ` ${event.stats.model}`) : null), /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", paddingLeft: 2, marginTop: 1 }, event.branch ? /* @__PURE__ */ React4.createElement(BranchBlock, { branch: event.branch }) : null, event.reasoning ? /* @__PURE__ */ React4.createElement(ReasoningBlock, { reasoning: event.reasoning }) : null, !isPlanStateEmpty(event.planState) ? /* @__PURE__ */ React4.createElement(PlanStateBlock, { planState: event.planState }) : null, event.text ? /* @__PURE__ */ React4.createElement(Markdown, { text: event.text, projectRoot }) : /* @__PURE__ */ React4.createElement(Text3, { dimColor: true }, "(no content)"), event.stats ? /* @__PURE__ */ React4.createElement(StatsLine, { stats: event.stats }) : null, event.repair ? /* @__PURE__ */ React4.createElement(Text3, { color: "magenta" }, event.repair) : null));
6233
+ if (event.streaming) return /* @__PURE__ */ React5.createElement(StreamingAssistant, { event });
6234
+ return /* @__PURE__ */ React5.createElement(Box4, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React5.createElement(Box4, null, /* @__PURE__ */ React5.createElement(RoleGlyph, { glyph: ROLE_GLYPH.assistant, color: "green" }), event.stats ? /* @__PURE__ */ React5.createElement(Text4, { dimColor: true }, ` ${event.stats.model}`) : null), /* @__PURE__ */ React5.createElement(Box4, { flexDirection: "column", paddingLeft: 2, marginTop: 1 }, event.branch ? /* @__PURE__ */ React5.createElement(BranchBlock, { branch: event.branch }) : null, event.reasoning ? /* @__PURE__ */ React5.createElement(ReasoningBlock, { reasoning: event.reasoning }) : null, !isPlanStateEmpty(event.planState) ? /* @__PURE__ */ React5.createElement(PlanStateBlock, { planState: event.planState }) : null, event.text ? /* @__PURE__ */ React5.createElement(Markdown, { text: event.text, projectRoot }) : /* @__PURE__ */ React5.createElement(Text4, { dimColor: true }, "(no content)"), event.stats ? /* @__PURE__ */ React5.createElement(StatsLine, { stats: event.stats }) : null, event.repair ? /* @__PURE__ */ React5.createElement(Text4, { color: "magenta" }, event.repair) : null));
6134
6235
  }
6135
6236
  if (event.role === "tool") {
6136
6237
  const isError = event.text.startsWith("ERROR:");
@@ -6138,31 +6239,31 @@ var EventRow = React4.memo(function EventRow2({
6138
6239
  const glyph = isError ? ROLE_GLYPH.toolErr : ROLE_GLYPH.toolOk;
6139
6240
  const marker = isError ? "\u2717" : "\u2192";
6140
6241
  const isEditFile = (event.toolName === "edit_file" || event.toolName?.endsWith("_edit_file")) && !isError;
6141
- return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React4.createElement(Box3, null, /* @__PURE__ */ React4.createElement(RoleGlyph, { glyph, color }), /* @__PURE__ */ React4.createElement(Text3, { color, bold: true }, ` ${event.toolName ?? "?"}`), /* @__PURE__ */ React4.createElement(Text3, { color, dimColor: true }, ` ${marker}`)), /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", paddingLeft: 2, marginTop: 1 }, isEditFile ? /* @__PURE__ */ React4.createElement(EditFileDiff, { text: event.text }) : /* @__PURE__ */ React4.createElement(Text3, { color: isError ? "red" : void 0, dimColor: !isError }, truncate2(event.text, 400))));
6242
+ return /* @__PURE__ */ React5.createElement(Box4, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React5.createElement(Box4, null, /* @__PURE__ */ React5.createElement(RoleGlyph, { glyph, color }), /* @__PURE__ */ React5.createElement(Text4, { color, bold: true }, ` ${event.toolName ?? "?"}`), /* @__PURE__ */ React5.createElement(Text4, { color, dimColor: true }, ` ${marker}`)), /* @__PURE__ */ React5.createElement(Box4, { flexDirection: "column", paddingLeft: 2, marginTop: 1 }, isEditFile ? /* @__PURE__ */ React5.createElement(EditFileDiff, { text: event.text }) : /* @__PURE__ */ React5.createElement(Text4, { color: isError ? "red" : void 0, dimColor: !isError }, truncate2(event.text, 400))));
6142
6243
  }
6143
6244
  if (event.role === "error") {
6144
- return /* @__PURE__ */ React4.createElement(Box3, { marginTop: 1 }, /* @__PURE__ */ React4.createElement(RoleGlyph, { glyph: ROLE_GLYPH.error, color: "red" }), /* @__PURE__ */ React4.createElement(Text3, { color: "red" }, " ", event.text));
6245
+ return /* @__PURE__ */ React5.createElement(Box4, { marginTop: 1 }, /* @__PURE__ */ React5.createElement(RoleGlyph, { glyph: ROLE_GLYPH.error, color: "red" }), /* @__PURE__ */ React5.createElement(Text4, { color: "red" }, " ", event.text));
6145
6246
  }
6146
6247
  if (event.role === "info") {
6147
- return /* @__PURE__ */ React4.createElement(Box3, null, /* @__PURE__ */ React4.createElement(Text3, { dimColor: true }, event.text));
6248
+ return /* @__PURE__ */ React5.createElement(Box4, null, /* @__PURE__ */ React5.createElement(Text4, { dimColor: true }, event.text));
6148
6249
  }
6149
6250
  if (event.role === "warning") {
6150
- return /* @__PURE__ */ React4.createElement(Box3, null, /* @__PURE__ */ React4.createElement(RoleGlyph, { glyph: ROLE_GLYPH.warning, color: "yellow" }), /* @__PURE__ */ React4.createElement(Text3, { color: "yellow" }, " ", event.text));
6251
+ return /* @__PURE__ */ React5.createElement(Box4, null, /* @__PURE__ */ React5.createElement(RoleGlyph, { glyph: ROLE_GLYPH.warning, color: "yellow" }), /* @__PURE__ */ React5.createElement(Text4, { color: "yellow" }, " ", event.text));
6151
6252
  }
6152
- return /* @__PURE__ */ React4.createElement(Box3, null, /* @__PURE__ */ React4.createElement(Text3, null, event.text));
6253
+ return /* @__PURE__ */ React5.createElement(Box4, null, /* @__PURE__ */ React5.createElement(Text4, null, event.text));
6153
6254
  });
6154
6255
  function EditFileDiff({ text }) {
6155
6256
  const lines = text.split(/\r?\n/);
6156
6257
  const [statusHeader, hunkHeader, ...body] = lines;
6157
- return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column" }, /* @__PURE__ */ React4.createElement(Text3, { dimColor: true }, ` ${statusHeader ?? ""}`), hunkHeader !== void 0 ? /* @__PURE__ */ React4.createElement(Text3, { color: "cyan", bold: true }, hunkHeader) : null, body.map((line, i) => {
6258
+ return /* @__PURE__ */ React5.createElement(Box4, { flexDirection: "column" }, /* @__PURE__ */ React5.createElement(Text4, { dimColor: true }, ` ${statusHeader ?? ""}`), hunkHeader !== void 0 ? /* @__PURE__ */ React5.createElement(Text4, { color: "cyan", bold: true }, hunkHeader) : null, body.map((line, i) => {
6158
6259
  const key = `${i}-${line.slice(0, 32)}`;
6159
6260
  if (line.startsWith("- ")) {
6160
- return /* @__PURE__ */ React4.createElement(Text3, { key, color: "red" }, line);
6261
+ return /* @__PURE__ */ React5.createElement(Text4, { key, color: "red" }, line);
6161
6262
  }
6162
6263
  if (line.startsWith("+ ")) {
6163
- return /* @__PURE__ */ React4.createElement(Text3, { key, color: "green" }, line);
6264
+ return /* @__PURE__ */ React5.createElement(Text4, { key, color: "green" }, line);
6164
6265
  }
6165
- return /* @__PURE__ */ React4.createElement(Text3, { key, dimColor: true }, line);
6266
+ return /* @__PURE__ */ React5.createElement(Text4, { key, dimColor: true }, line);
6166
6267
  }));
6167
6268
  }
6168
6269
  function BranchBlock({ branch }) {
@@ -6171,33 +6272,33 @@ function BranchBlock({ branch }) {
6171
6272
  const t = (branch.temperatures[i] ?? 0).toFixed(1);
6172
6273
  return `${marker} #${i} T=${t} u=${u}`;
6173
6274
  }).join(" ");
6174
- return /* @__PURE__ */ React4.createElement(Box3, null, /* @__PURE__ */ React4.createElement(Text3, { color: "blue" }, "\u2387 branched ", /* @__PURE__ */ React4.createElement(Text3, { bold: true }, branch.budget), ` samples \u2192 picked #${branch.chosenIndex} `, /* @__PURE__ */ React4.createElement(Text3, { dimColor: true }, per)));
6275
+ return /* @__PURE__ */ React5.createElement(Box4, null, /* @__PURE__ */ React5.createElement(Text4, { color: "blue" }, "\u2387 branched ", /* @__PURE__ */ React5.createElement(Text4, { bold: true }, branch.budget), ` samples \u2192 picked #${branch.chosenIndex} `, /* @__PURE__ */ React5.createElement(Text4, { dimColor: true }, per)));
6175
6276
  }
6176
6277
  function ReasoningBlock({ reasoning }) {
6177
6278
  const max = 260;
6178
6279
  const flat = reasoning.replace(/\s+/g, " ").trim();
6179
6280
  const preview = flat.length <= max ? flat : `\u2026 (+${flat.length - max} earlier chars) ${flat.slice(-max)}`;
6180
- return /* @__PURE__ */ React4.createElement(Box3, { marginBottom: 1 }, /* @__PURE__ */ React4.createElement(Text3, { dimColor: true }, "\u258F "), /* @__PURE__ */ React4.createElement(Text3, { dimColor: true, italic: true }, "thinking ", preview));
6281
+ return /* @__PURE__ */ React5.createElement(Box4, { marginBottom: 1 }, /* @__PURE__ */ React5.createElement(Text4, { dimColor: true }, "\u258F "), /* @__PURE__ */ React5.createElement(Text4, { dimColor: true, italic: true }, "thinking ", preview));
6181
6282
  }
6182
6283
  function Elapsed() {
6183
6284
  const s = useElapsedSeconds();
6184
6285
  const mm = String(Math.floor(s / 60)).padStart(2, "0");
6185
6286
  const ss = String(s % 60).padStart(2, "0");
6186
- return /* @__PURE__ */ React4.createElement(Text3, { dimColor: true }, `${mm}:${ss}`);
6287
+ return /* @__PURE__ */ React5.createElement(Text4, { dimColor: true }, `${mm}:${ss}`);
6187
6288
  }
6188
6289
  function PulsingAssistantGlyph() {
6189
6290
  const tick = useTick();
6190
6291
  const on = Math.floor(tick / 4) % 2 === 0;
6191
- return /* @__PURE__ */ React4.createElement(Text3, { color: "green", bold: true }, on ? ROLE_GLYPH.assistant : ROLE_GLYPH.assistantPulse);
6292
+ return /* @__PURE__ */ React5.createElement(Text4, { color: "green", bold: true }, on ? ROLE_GLYPH.assistant : ROLE_GLYPH.assistantPulse);
6192
6293
  }
6193
6294
  function StreamingAssistant({ event }) {
6194
6295
  if (event.branchProgress) {
6195
6296
  const p = event.branchProgress;
6196
6297
  if (p.completed === 0) {
6197
- return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React4.createElement(Box3, null, /* @__PURE__ */ React4.createElement(PulsingAssistantGlyph, null), /* @__PURE__ */ React4.createElement(Text3, { color: "blue" }, " \u2387 launching ", p.total, " parallel samples (R1 thinking in parallel)\u2026 "), /* @__PURE__ */ React4.createElement(Elapsed, null)), /* @__PURE__ */ React4.createElement(Text3, { color: "yellow" }, " ", "spread across T=0.0/0.5/1.0 \xB7 reasoner typically takes 30-90s \u2014 this is normal"));
6298
+ return /* @__PURE__ */ React5.createElement(Box4, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React5.createElement(Box4, null, /* @__PURE__ */ React5.createElement(PulsingAssistantGlyph, null), /* @__PURE__ */ React5.createElement(Text4, { color: "blue" }, " \u2387 launching ", p.total, " parallel samples (R1 thinking in parallel)\u2026 "), /* @__PURE__ */ React5.createElement(Elapsed, null)), /* @__PURE__ */ React5.createElement(Text4, { color: "yellow" }, " ", "spread across T=0.0/0.5/1.0 \xB7 reasoner typically takes 30-90s \u2014 this is normal"));
6198
6299
  }
6199
6300
  const pct2 = Math.round(p.completed / p.total * 100);
6200
- return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React4.createElement(Box3, null, /* @__PURE__ */ React4.createElement(PulsingAssistantGlyph, null), /* @__PURE__ */ React4.createElement(Text3, { color: "blue" }, " \u2387 branching ", p.completed, "/", p.total, " (", pct2, "%) "), /* @__PURE__ */ React4.createElement(Elapsed, null)), /* @__PURE__ */ React4.createElement(Text3, { dimColor: true }, " latest #", p.latestIndex, " T=", p.latestTemperature.toFixed(1), " u=", p.latestUncertainties, p.completed < p.total ? " \xB7 waiting for other samples\u2026" : " \xB7 selecting winner\u2026"));
6301
+ return /* @__PURE__ */ React5.createElement(Box4, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React5.createElement(Box4, null, /* @__PURE__ */ React5.createElement(PulsingAssistantGlyph, null), /* @__PURE__ */ React5.createElement(Text4, { color: "blue" }, " \u2387 branching ", p.completed, "/", p.total, " (", pct2, "%) "), /* @__PURE__ */ React5.createElement(Elapsed, null)), /* @__PURE__ */ React5.createElement(Text4, { dimColor: true }, " latest #", p.latestIndex, " T=", p.latestTemperature.toFixed(1), " u=", p.latestUncertainties, p.completed < p.total ? " \xB7 waiting for other samples\u2026" : " \xB7 selecting winner\u2026"));
6201
6302
  }
6202
6303
  const tail = lastLine(event.text, 140);
6203
6304
  const reasoningTail = event.reasoning ? lastLine(event.reasoning, 120) : "";
@@ -6225,16 +6326,16 @@ function StreamingAssistant({ event }) {
6225
6326
  label = parts.join(" \xB7 ");
6226
6327
  labelColor = "green";
6227
6328
  }
6228
- return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React4.createElement(Box3, null, /* @__PURE__ */ React4.createElement(PulsingAssistantGlyph, null), /* @__PURE__ */ React4.createElement(Text3, null, " "), /* @__PURE__ */ React4.createElement(Pulse, null), /* @__PURE__ */ React4.createElement(Text3, { color: labelColor }, ` ${label} `), /* @__PURE__ */ React4.createElement(Elapsed, null)), reasoningTail ? /* @__PURE__ */ React4.createElement(Text3, { dimColor: true, italic: true }, "\u21B3 thinking: ", reasoningTail) : null, tail ? /* @__PURE__ */ React4.createElement(Text3, { dimColor: true }, "\u25B8 ", tail) : preFirstByte ? (
6329
+ return /* @__PURE__ */ React5.createElement(Box4, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React5.createElement(Box4, null, /* @__PURE__ */ React5.createElement(PulsingAssistantGlyph, null), /* @__PURE__ */ React5.createElement(Text4, null, " "), /* @__PURE__ */ React5.createElement(Pulse, null), /* @__PURE__ */ React5.createElement(Text4, { color: labelColor }, ` ${label} `), /* @__PURE__ */ React5.createElement(Elapsed, null)), reasoningTail ? /* @__PURE__ */ React5.createElement(Text4, { dimColor: true, italic: true }, "\u21B3 thinking: ", reasoningTail) : null, tail ? /* @__PURE__ */ React5.createElement(Text4, { dimColor: true }, "\u25B8 ", tail) : preFirstByte ? (
6229
6330
  // Non-dim yellow: first-time users misread the dim version as
6230
6331
  // "app frozen". The reassurance has to be VISIBLE to do its job.
6231
- /* @__PURE__ */ React4.createElement(Text3, { color: "yellow", italic: true }, " waiting for first byte \u2014 this is normal, typically 5-60s depending on model + load")
6232
- ) : reasoningOnly ? /* @__PURE__ */ React4.createElement(Text3, { color: "yellow", italic: true }, " R1 is thinking before it speaks \u2014 body text arrives when reasoning finishes (typically 20-90s, this is normal)") : toolCallOnly ? /* @__PURE__ */ React4.createElement(Text3, { color: "magenta", italic: true }, " tool-call arguments streaming \u2014 the model is about to dispatch a tool") : event.reasoning ? /* @__PURE__ */ React4.createElement(Text3, { color: "yellow", italic: true }, " R1 still reasoning \u2014 body text or tool call arrives when thinking finishes") : null);
6332
+ /* @__PURE__ */ React5.createElement(Text4, { color: "yellow", italic: true }, " waiting for first byte \u2014 this is normal, typically 5-60s depending on model + load")
6333
+ ) : reasoningOnly ? /* @__PURE__ */ React5.createElement(Text4, { color: "yellow", italic: true }, " R1 is thinking before it speaks \u2014 body text arrives when reasoning finishes (typically 20-90s, this is normal)") : toolCallOnly ? /* @__PURE__ */ React5.createElement(Text4, { color: "magenta", italic: true }, " tool-call arguments streaming \u2014 the model is about to dispatch a tool") : event.reasoning ? /* @__PURE__ */ React5.createElement(Text4, { color: "yellow", italic: true }, " R1 still reasoning \u2014 body text or tool call arrives when thinking finishes") : null);
6233
6334
  }
6234
6335
  function Pulse() {
6235
6336
  const tick = useTick();
6236
6337
  const frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
6237
- return /* @__PURE__ */ React4.createElement(Text3, { color: "cyan" }, frames[Math.floor(tick / 4) % frames.length]);
6338
+ return /* @__PURE__ */ React5.createElement(Text4, { color: "cyan" }, frames[Math.floor(tick / 4) % frames.length]);
6238
6339
  }
6239
6340
  function lastLine(s, maxChars) {
6240
6341
  const flat = s.replace(/\s+/g, " ").trim();
@@ -6243,7 +6344,7 @@ function lastLine(s, maxChars) {
6243
6344
  }
6244
6345
  function StatsLine({ stats }) {
6245
6346
  const hit = (stats.cacheHitRatio * 100).toFixed(1);
6246
- return /* @__PURE__ */ React4.createElement(Box3, null, /* @__PURE__ */ React4.createElement(Text3, { dimColor: true }, "\u258F "), /* @__PURE__ */ React4.createElement(Text3, { dimColor: true }, "cache ", hit, "% \xB7 tokens ", stats.usage.promptTokens, " \u2192 ", stats.usage.completionTokens, " \xB7 $", stats.cost.toFixed(6)));
6347
+ return /* @__PURE__ */ React5.createElement(Box4, null, /* @__PURE__ */ React5.createElement(Text4, { dimColor: true }, "\u258F "), /* @__PURE__ */ React5.createElement(Text4, { dimColor: true }, "cache ", hit, "% \xB7 tokens ", stats.usage.promptTokens, " \u2192 ", stats.usage.completionTokens, " \xB7 $", stats.cost.toFixed(6)));
6247
6348
  }
6248
6349
  function truncate2(s, max) {
6249
6350
  if (s.length <= max) return s;
@@ -6266,12 +6367,12 @@ ${s.slice(-max)}`;
6266
6367
  }
6267
6368
 
6268
6369
  // src/cli/ui/PlanConfirm.tsx
6269
- import { Box as Box5, Text as Text5 } from "ink";
6270
- import React6 from "react";
6370
+ import { Box as Box6, Text as Text6 } from "ink";
6371
+ import React7 from "react";
6271
6372
 
6272
6373
  // src/cli/ui/Select.tsx
6273
- import { Box as Box4, Text as Text4, useInput } from "ink";
6274
- import React5, { useState as useState2 } from "react";
6374
+ import { Box as Box5, Text as Text5, useInput } from "ink";
6375
+ import React6, { useState as useState2 } from "react";
6275
6376
  function SingleSelect({
6276
6377
  items,
6277
6378
  initialValue,
@@ -6296,7 +6397,7 @@ function SingleSelect({
6296
6397
  onCancel();
6297
6398
  }
6298
6399
  });
6299
- return /* @__PURE__ */ React5.createElement(Box4, { flexDirection: "column" }, items.map((item, i) => /* @__PURE__ */ React5.createElement(
6400
+ return /* @__PURE__ */ React6.createElement(Box5, { flexDirection: "column" }, items.map((item, i) => /* @__PURE__ */ React6.createElement(
6300
6401
  SelectRow,
6301
6402
  {
6302
6403
  key: item.value,
@@ -6304,7 +6405,7 @@ function SingleSelect({
6304
6405
  active: i === index,
6305
6406
  marker: i === index ? "\u25B8" : " "
6306
6407
  }
6307
- )), footer ? /* @__PURE__ */ React5.createElement(Box4, { marginTop: 1 }, /* @__PURE__ */ React5.createElement(Text4, { dimColor: true }, footer)) : null);
6408
+ )), footer ? /* @__PURE__ */ React6.createElement(Box5, { marginTop: 1 }, /* @__PURE__ */ React6.createElement(Text5, { dimColor: true }, footer)) : null);
6308
6409
  }
6309
6410
  function MultiSelect({
6310
6411
  items,
@@ -6339,10 +6440,10 @@ function MultiSelect({
6339
6440
  onCancel();
6340
6441
  }
6341
6442
  });
6342
- return /* @__PURE__ */ React5.createElement(Box4, { flexDirection: "column" }, items.map((item, i) => {
6443
+ return /* @__PURE__ */ React6.createElement(Box5, { flexDirection: "column" }, items.map((item, i) => {
6343
6444
  const checked = selected.has(item.value);
6344
6445
  const marker = checked ? "[x]" : "[ ]";
6345
- return /* @__PURE__ */ React5.createElement(
6446
+ return /* @__PURE__ */ React6.createElement(
6346
6447
  SelectRow,
6347
6448
  {
6348
6449
  key: item.value,
@@ -6351,7 +6452,7 @@ function MultiSelect({
6351
6452
  marker: `${i === index ? "\u25B8" : " "} ${marker}`
6352
6453
  }
6353
6454
  );
6354
- }), footer ? /* @__PURE__ */ React5.createElement(Box4, { marginTop: 1 }, /* @__PURE__ */ React5.createElement(Text4, { dimColor: true }, footer)) : null);
6455
+ }), footer ? /* @__PURE__ */ React6.createElement(Box5, { marginTop: 1 }, /* @__PURE__ */ React6.createElement(Text5, { dimColor: true }, footer)) : null);
6355
6456
  }
6356
6457
  function SelectRow({
6357
6458
  item,
@@ -6359,7 +6460,7 @@ function SelectRow({
6359
6460
  marker
6360
6461
  }) {
6361
6462
  const color = item.disabled ? "gray" : active ? "cyan" : void 0;
6362
- return /* @__PURE__ */ React5.createElement(Box4, { flexDirection: "column" }, /* @__PURE__ */ React5.createElement(Box4, null, /* @__PURE__ */ React5.createElement(Text4, { color }, marker, " ", item.label)), item.hint ? /* @__PURE__ */ React5.createElement(Box4, { paddingLeft: marker.length + 1 }, /* @__PURE__ */ React5.createElement(Text4, { dimColor: true }, item.hint)) : null);
6463
+ return /* @__PURE__ */ React6.createElement(Box5, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Box5, null, /* @__PURE__ */ React6.createElement(Text5, { color }, marker, " ", item.label)), item.hint ? /* @__PURE__ */ React6.createElement(Box5, { paddingLeft: marker.length + 1 }, /* @__PURE__ */ React6.createElement(Text5, { dimColor: true }, item.hint)) : null);
6363
6464
  }
6364
6465
  function findNextEnabled(items, from, step) {
6365
6466
  if (items.length === 0) return 0;
@@ -6380,7 +6481,7 @@ function PlanConfirm({ plan, onChoose, maxRenderedChars, projectRoot }) {
6380
6481
 
6381
6482
  \u2026 (${plan.length - cap} chars truncated \u2014 use /tool to view the full proposal)` : plan;
6382
6483
  const hasOpenQuestions = /^#{1,6}\s*(open[-\s]?questions?|risks?|unknowns?|assumptions?|unclear)/im.test(plan) || /^#{1,6}\s*(待确认|开放问题|风险|未知|假设|不确定)/im.test(plan);
6383
- return /* @__PURE__ */ React6.createElement(Box5, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React6.createElement(Box5, null, /* @__PURE__ */ React6.createElement(Text5, { bold: true, color: "cyan" }, "\u25B8 plan submitted \u2014 awaiting your review")), /* @__PURE__ */ React6.createElement(Box5, null, /* @__PURE__ */ React6.createElement(Text5, { color: "cyan", dimColor: true }, "\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")), /* @__PURE__ */ React6.createElement(Box5, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Markdown, { text: visible, projectRoot })), hasOpenQuestions ? /* @__PURE__ */ React6.createElement(Box5, { marginTop: 1 }, /* @__PURE__ */ React6.createElement(Text5, { color: "yellow" }, "\u25B2 the plan has open questions or flagged risks \u2014 pick", " ", /* @__PURE__ */ React6.createElement(Text5, { bold: true }, "Refine / answer questions"), " to write concrete answers before the model moves on.")) : null, /* @__PURE__ */ React6.createElement(Box5, { marginTop: 1 }, /* @__PURE__ */ React6.createElement(
6484
+ return /* @__PURE__ */ React7.createElement(Box6, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React7.createElement(Box6, null, /* @__PURE__ */ React7.createElement(Text6, { bold: true, color: "cyan" }, "\u25B8 plan submitted \u2014 awaiting your review")), /* @__PURE__ */ React7.createElement(Box6, null, /* @__PURE__ */ React7.createElement(Text6, { color: "cyan", dimColor: true }, "\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")), /* @__PURE__ */ React7.createElement(Box6, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React7.createElement(Markdown, { text: visible, projectRoot })), hasOpenQuestions ? /* @__PURE__ */ React7.createElement(Box6, { marginTop: 1 }, /* @__PURE__ */ React7.createElement(Text6, { color: "yellow" }, "\u25B2 the plan has open questions or flagged risks \u2014 pick", " ", /* @__PURE__ */ React7.createElement(Text6, { bold: true }, "Refine / answer questions"), " to write concrete answers before the model moves on.")) : null, /* @__PURE__ */ React7.createElement(Box6, { marginTop: 1 }, /* @__PURE__ */ React7.createElement(
6384
6485
  SingleSelect,
6385
6486
  {
6386
6487
  initialValue: hasOpenQuestions ? "refine" : "approve",
@@ -6409,8 +6510,8 @@ function PlanConfirm({ plan, onChoose, maxRenderedChars, projectRoot }) {
6409
6510
  }
6410
6511
 
6411
6512
  // src/cli/ui/PlanRefineInput.tsx
6412
- import { Box as Box6, Text as Text6, useInput as useInput2 } from "ink";
6413
- import React7, { useState as useState3 } from "react";
6513
+ import { Box as Box7, Text as Text7, useInput as useInput2 } from "ink";
6514
+ import React8, { useState as useState3 } from "react";
6414
6515
  function PlanRefineInput({ mode, onSubmit, onCancel }) {
6415
6516
  const [value, setValue] = useState3("");
6416
6517
  useInput2((input, key) => {
@@ -6433,12 +6534,12 @@ function PlanRefineInput({ mode, onSubmit, onCancel }) {
6433
6534
  const title = mode === "approve" ? "\u25B8 approving \u2014 any last instructions or answers to open questions?" : "\u25B8 refining \u2014 what should the model change?";
6434
6535
  const hint = mode === "approve" ? "Answer questions the plan raised, add constraints, or just press Enter to approve as-is." : "Describe what's wrong or missing, or answer questions the plan raised.";
6435
6536
  const blankHint = mode === "approve" ? " (Enter with blank = approve without extra instructions.)" : " (Enter with blank = ask the model to list concrete questions.)";
6436
- return /* @__PURE__ */ React7.createElement(Box6, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React7.createElement(Box6, null, /* @__PURE__ */ React7.createElement(Text6, { bold: true, color: "yellow" }, title)), /* @__PURE__ */ React7.createElement(Box6, { marginTop: 1 }, /* @__PURE__ */ React7.createElement(Text6, { dimColor: true }, hint, " Enter to send \xB7 Esc to return to the picker.", value === "" ? blankHint : "")), /* @__PURE__ */ React7.createElement(Box6, { marginTop: 1 }, /* @__PURE__ */ React7.createElement(Text6, null, /* @__PURE__ */ React7.createElement(Text6, { color: "yellow" }, "\u203A "), /* @__PURE__ */ React7.createElement(Text6, null, value || " "), /* @__PURE__ */ React7.createElement(Text6, { color: "yellow" }, "\u258D"))));
6537
+ return /* @__PURE__ */ React8.createElement(Box7, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React8.createElement(Box7, null, /* @__PURE__ */ React8.createElement(Text7, { bold: true, color: "yellow" }, title)), /* @__PURE__ */ React8.createElement(Box7, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(Text7, { dimColor: true }, hint, " Enter to send \xB7 Esc to return to the picker.", value === "" ? blankHint : "")), /* @__PURE__ */ React8.createElement(Box7, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(Text7, null, /* @__PURE__ */ React8.createElement(Text7, { color: "yellow" }, "\u203A "), /* @__PURE__ */ React8.createElement(Text7, null, value || " "), /* @__PURE__ */ React8.createElement(Text7, { color: "yellow" }, "\u258D"))));
6437
6538
  }
6438
6539
 
6439
6540
  // src/cli/ui/PromptInput.tsx
6440
- import { Box as Box7, Text as Text7, useInput as useInput3 } from "ink";
6441
- import React8, { useRef, useState as useState4 } from "react";
6541
+ import { Box as Box8, Text as Text8, useInput as useInput3 } from "ink";
6542
+ import React9, { useRef, useState as useState4 } from "react";
6442
6543
 
6443
6544
  // src/cli/ui/multiline-keys.ts
6444
6545
  var BACKSLASH_SUFFIX = /\\$/;
@@ -6598,13 +6699,13 @@ function PromptInput({
6598
6699
  const lines = value.length > 0 ? value.split("\n") : [""];
6599
6700
  const borderColor = disabled ? "gray" : "cyan";
6600
6701
  const { line: cursorLine, col: cursorCol } = lineAndColumn(value, cursor);
6601
- return /* @__PURE__ */ React8.createElement(Box7, { borderStyle: "round", borderColor, paddingX: 1, flexDirection: "column" }, lines.map((line, i) => {
6702
+ return /* @__PURE__ */ React9.createElement(Box8, { borderStyle: "round", borderColor, paddingX: 1, flexDirection: "column" }, lines.map((line, i) => {
6602
6703
  const isFirst = i === 0;
6603
6704
  const showPlaceholder = isFirst && value.length === 0;
6604
6705
  const isCursorLine = i === cursorLine;
6605
6706
  return (
6606
6707
  // biome-ignore lint/suspicious/noArrayIndexKey: stable by construction — lines are derived from `value.split("\n")` and never reordered
6607
- /* @__PURE__ */ React8.createElement(Box7, { key: i }, isFirst ? /* @__PURE__ */ React8.createElement(Text7, { bold: true, color: borderColor }, "you \u203A", " ") : /* @__PURE__ */ React8.createElement(Text7, { dimColor: true }, " "), showPlaceholder ? /* @__PURE__ */ React8.createElement(React8.Fragment, null, isCursorLine && !disabled ? /* @__PURE__ */ React8.createElement(Text7, { color: borderColor }, showCursor ? "\u258C" : " ") : null, /* @__PURE__ */ React8.createElement(Text7, { dimColor: true }, effectivePlaceholder)) : isCursorLine && !disabled ? /* @__PURE__ */ React8.createElement(
6708
+ /* @__PURE__ */ React9.createElement(Box8, { key: i }, isFirst ? /* @__PURE__ */ React9.createElement(Text8, { bold: true, color: borderColor }, "you \u203A", " ") : /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, " "), showPlaceholder ? /* @__PURE__ */ React9.createElement(React9.Fragment, null, isCursorLine && !disabled ? /* @__PURE__ */ React9.createElement(Text8, { color: borderColor }, showCursor ? "\u258C" : " ") : null, /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, effectivePlaceholder)) : isCursorLine && !disabled ? /* @__PURE__ */ React9.createElement(
6608
6709
  LineWithCursor,
6609
6710
  {
6610
6711
  line,
@@ -6612,7 +6713,7 @@ function PromptInput({
6612
6713
  showCursor,
6613
6714
  borderColor
6614
6715
  }
6615
- ) : /* @__PURE__ */ React8.createElement(Text7, null, line))
6716
+ ) : /* @__PURE__ */ React9.createElement(Text8, null, line))
6616
6717
  );
6617
6718
  }));
6618
6719
  }
@@ -6626,16 +6727,16 @@ function LineWithCursor({
6626
6727
  const atCursor = line.slice(col, col + 1);
6627
6728
  const after = line.slice(col + 1);
6628
6729
  if (atCursor.length === 0) {
6629
- return /* @__PURE__ */ React8.createElement(React8.Fragment, null, /* @__PURE__ */ React8.createElement(Text7, null, before), /* @__PURE__ */ React8.createElement(Text7, { color: borderColor }, showCursor ? "\u258C" : " "));
6730
+ return /* @__PURE__ */ React9.createElement(React9.Fragment, null, /* @__PURE__ */ React9.createElement(Text8, null, before), /* @__PURE__ */ React9.createElement(Text8, { color: borderColor }, showCursor ? "\u258C" : " "));
6630
6731
  }
6631
- return /* @__PURE__ */ React8.createElement(React8.Fragment, null, /* @__PURE__ */ React8.createElement(Text7, null, before), /* @__PURE__ */ React8.createElement(Text7, { inverse: showCursor }, atCursor), /* @__PURE__ */ React8.createElement(Text7, null, after));
6732
+ return /* @__PURE__ */ React9.createElement(React9.Fragment, null, /* @__PURE__ */ React9.createElement(Text8, null, before), /* @__PURE__ */ React9.createElement(Text8, { inverse: showCursor }, atCursor), /* @__PURE__ */ React9.createElement(Text8, null, after));
6632
6733
  }
6633
6734
 
6634
6735
  // src/cli/ui/ShellConfirm.tsx
6635
- import { Box as Box8, Text as Text8 } from "ink";
6636
- import React9 from "react";
6736
+ import { Box as Box9, Text as Text9 } from "ink";
6737
+ import React10 from "react";
6637
6738
  function ShellConfirm({ command, allowPrefix, onChoose }) {
6638
- return /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React9.createElement(Box8, null, /* @__PURE__ */ React9.createElement(Text8, { bold: true, color: "yellow" }, "\u25B8 model wants to run a shell command")), /* @__PURE__ */ React9.createElement(Box8, null, /* @__PURE__ */ React9.createElement(Text8, { color: "yellow", dimColor: true }, "\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")), /* @__PURE__ */ React9.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(Text8, null, /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, "$ "), /* @__PURE__ */ React9.createElement(Text8, { color: "cyan" }, command))), /* @__PURE__ */ React9.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(
6739
+ return /* @__PURE__ */ React10.createElement(Box9, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React10.createElement(Box9, null, /* @__PURE__ */ React10.createElement(Text9, { bold: true, color: "yellow" }, "\u25B8 model wants to run a shell command")), /* @__PURE__ */ React10.createElement(Box9, null, /* @__PURE__ */ React10.createElement(Text9, { color: "yellow", dimColor: true }, "\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")), /* @__PURE__ */ React10.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text9, null, /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, "$ "), /* @__PURE__ */ React10.createElement(Text9, { color: "cyan" }, command))), /* @__PURE__ */ React10.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(
6639
6740
  SingleSelect,
6640
6741
  {
6641
6742
  initialValue: "run_once",
@@ -6692,15 +6793,15 @@ function derivePrefix(command) {
6692
6793
  }
6693
6794
 
6694
6795
  // src/cli/ui/SlashSuggestions.tsx
6695
- import { Box as Box9, Text as Text9 } from "ink";
6696
- import React10 from "react";
6796
+ import { Box as Box10, Text as Text10 } from "ink";
6797
+ import React11 from "react";
6697
6798
  function SlashSuggestions({
6698
6799
  matches,
6699
6800
  selectedIndex
6700
6801
  }) {
6701
6802
  if (matches === null) return null;
6702
6803
  if (matches.length === 0) {
6703
- return /* @__PURE__ */ React10.createElement(Box9, { paddingX: 1 }, /* @__PURE__ */ React10.createElement(Text9, { color: "yellow" }, "no slash command matches that prefix"), /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, " \u2014 Backspace to edit, or /help for the full list"));
6804
+ return /* @__PURE__ */ React11.createElement(Box10, { paddingX: 1 }, /* @__PURE__ */ React11.createElement(Text10, { color: "yellow" }, "no slash command matches that prefix"), /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, " \u2014 Backspace to edit, or /help for the full list"));
6704
6805
  }
6705
6806
  const MAX = 8;
6706
6807
  const total = matches.length;
@@ -6708,21 +6809,21 @@ function SlashSuggestions({
6708
6809
  const shown = matches.slice(windowStart, windowStart + MAX);
6709
6810
  const hiddenAbove = windowStart;
6710
6811
  const hiddenBelow = total - windowStart - shown.length;
6711
- return /* @__PURE__ */ React10.createElement(Box9, { flexDirection: "column", paddingX: 1 }, hiddenAbove > 0 ? /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, " \u2191 ", hiddenAbove, " more above") : null, shown.map((spec, i) => /* @__PURE__ */ React10.createElement(SuggestionRow, { key: spec.cmd, spec, isSelected: windowStart + i === selectedIndex })), hiddenBelow > 0 ? /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, " \u2193 ", hiddenBelow, " more below") : null, /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, " [\u2191\u2193] navigate \xB7 [Tab]/[Enter] pick"));
6812
+ return /* @__PURE__ */ React11.createElement(Box10, { flexDirection: "column", paddingX: 1 }, hiddenAbove > 0 ? /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, " \u2191 ", hiddenAbove, " more above") : null, shown.map((spec, i) => /* @__PURE__ */ React11.createElement(SuggestionRow, { key: spec.cmd, spec, isSelected: windowStart + i === selectedIndex })), hiddenBelow > 0 ? /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, " \u2193 ", hiddenBelow, " more below") : null, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, " [\u2191\u2193] navigate \xB7 [Tab]/[Enter] pick"));
6712
6813
  }
6713
6814
  function SuggestionRow({ spec, isSelected }) {
6714
6815
  const marker = isSelected ? "\u25B8" : " ";
6715
6816
  const name = `/${spec.cmd}`;
6716
6817
  const argsSuffix = spec.argsHint ? ` ${spec.argsHint}` : "";
6717
6818
  if (isSelected) {
6718
- return /* @__PURE__ */ React10.createElement(Box9, null, /* @__PURE__ */ React10.createElement(Text9, { bold: true, color: "cyan" }, marker, " ", name.padEnd(12), argsSuffix.padEnd(16)), /* @__PURE__ */ React10.createElement(Text9, { color: "cyan" }, " ", spec.summary));
6819
+ return /* @__PURE__ */ React11.createElement(Box10, null, /* @__PURE__ */ React11.createElement(Text10, { bold: true, color: "cyan" }, marker, " ", name.padEnd(12), argsSuffix.padEnd(16)), /* @__PURE__ */ React11.createElement(Text10, { color: "cyan" }, " ", spec.summary));
6719
6820
  }
6720
- return /* @__PURE__ */ React10.createElement(Box9, null, /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, marker, " ", name.padEnd(12), argsSuffix.padEnd(16), " ", spec.summary));
6821
+ return /* @__PURE__ */ React11.createElement(Box10, null, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, marker, " ", name.padEnd(12), argsSuffix.padEnd(16), " ", spec.summary));
6721
6822
  }
6722
6823
 
6723
6824
  // src/cli/ui/StatsPanel.tsx
6724
- import { Box as Box10, Text as Text10, useStdout as useStdout2 } from "ink";
6725
- import React11 from "react";
6825
+ import { Box as Box11, Text as Text11, useStdout as useStdout2 } from "ink";
6826
+ import React12 from "react";
6726
6827
  var WORDMARK_STYLES = [
6727
6828
  { ch: "\u25C8", color: "#5eead4", isLogo: true },
6728
6829
  // teal — brand mark
@@ -6748,7 +6849,7 @@ function Wordmark({ busy }) {
6748
6849
  const tick = useTick();
6749
6850
  const period = busy ? 5 : 12;
6750
6851
  const bright = Math.floor(tick / period) % 2 === 0;
6751
- return /* @__PURE__ */ React11.createElement(Text10, null, WORDMARK_STYLES.map((c) => /* @__PURE__ */ React11.createElement(Text10, { key: `${c.ch}-${c.color}`, color: c.color, bold: c.isLogo ? bright : true }, c.ch)));
6852
+ return /* @__PURE__ */ React12.createElement(Text11, null, WORDMARK_STYLES.map((c) => /* @__PURE__ */ React12.createElement(Text11, { key: `${c.ch}-${c.color}`, color: c.color, bold: c.isLogo ? bright : true }, c.ch)));
6752
6853
  }
6753
6854
  var NARROW_BREAKPOINT = 120;
6754
6855
  var COLD_START_TURNS = 3;
@@ -6770,7 +6871,7 @@ function StatsPanel({
6770
6871
  const columns = stdout2?.columns ?? 80;
6771
6872
  const narrow = columns < NARROW_BREAKPOINT;
6772
6873
  const coldStart = summary.turns <= COLD_START_TURNS;
6773
- return /* @__PURE__ */ React11.createElement(Box10, { borderStyle: "round", borderColor: "cyan", flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React11.createElement(
6874
+ return /* @__PURE__ */ React12.createElement(Box11, { borderStyle: "round", borderColor: "cyan", flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React12.createElement(
6774
6875
  Header,
6775
6876
  {
6776
6877
  model,
@@ -6784,7 +6885,7 @@ function StatsPanel({
6784
6885
  narrow,
6785
6886
  busy: busy ?? false
6786
6887
  }
6787
- ), narrow ? /* @__PURE__ */ React11.createElement(
6888
+ ), narrow ? /* @__PURE__ */ React12.createElement(
6788
6889
  StackedMetrics,
6789
6890
  {
6790
6891
  summary,
@@ -6793,7 +6894,7 @@ function StatsPanel({
6793
6894
  balance,
6794
6895
  coldStart
6795
6896
  }
6796
- ) : /* @__PURE__ */ React11.createElement(
6897
+ ) : /* @__PURE__ */ React12.createElement(
6797
6898
  InlineMetrics,
6798
6899
  {
6799
6900
  summary,
@@ -6816,7 +6917,7 @@ function Header({
6816
6917
  narrow,
6817
6918
  busy
6818
6919
  }) {
6819
- return /* @__PURE__ */ React11.createElement(Box10, { justifyContent: "space-between" }, /* @__PURE__ */ React11.createElement(Box10, null, /* @__PURE__ */ React11.createElement(Wordmark, { busy }), /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, ` v${VERSION}`), /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React11.createElement(Text10, { color: "yellow" }, model), narrow ? null : /* @__PURE__ */ React11.createElement(React11.Fragment, null, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, prefixHash)), harvestOn ? /* @__PURE__ */ React11.createElement(Text10, { color: "magenta" }, " \xB7 harvest") : null, branchOn ? /* @__PURE__ */ React11.createElement(Text10, { color: "blue" }, " \xB7 branch", branchBudget) : null, planMode ? /* @__PURE__ */ React11.createElement(Text10, { color: "red", bold: true }, " \xB7 PLAN") : null), /* @__PURE__ */ React11.createElement(Text10, null, updateAvailable ? /* @__PURE__ */ React11.createElement(Text10, { color: "yellow", bold: true }, `update: ${updateAvailable} \xB7 `) : null, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, narrow ? `turn ${turns}` : `turn ${turns} \xB7 /help`)));
6920
+ return /* @__PURE__ */ React12.createElement(Box11, { justifyContent: "space-between" }, /* @__PURE__ */ React12.createElement(Box11, null, /* @__PURE__ */ React12.createElement(Wordmark, { busy }), /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, ` v${VERSION}`), /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React12.createElement(Text11, { color: "yellow" }, model), narrow ? null : /* @__PURE__ */ React12.createElement(React12.Fragment, null, /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, prefixHash)), harvestOn ? /* @__PURE__ */ React12.createElement(Text11, { color: "magenta" }, " \xB7 harvest") : null, branchOn ? /* @__PURE__ */ React12.createElement(Text11, { color: "blue" }, " \xB7 branch", branchBudget) : null, planMode ? /* @__PURE__ */ React12.createElement(Text11, { color: "red", bold: true }, " \xB7 PLAN") : null), /* @__PURE__ */ React12.createElement(Text11, null, updateAvailable ? /* @__PURE__ */ React12.createElement(Text11, { color: "yellow", bold: true }, `update: ${updateAvailable} \xB7 `) : null, /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, narrow ? `turn ${turns}` : `turn ${turns} \xB7 /help`)));
6820
6921
  }
6821
6922
  function InlineMetrics({
6822
6923
  summary,
@@ -6825,7 +6926,7 @@ function InlineMetrics({
6825
6926
  balance,
6826
6927
  coldStart
6827
6928
  }) {
6828
- return /* @__PURE__ */ React11.createElement(Box10, { marginTop: 1, gap: 3 }, /* @__PURE__ */ React11.createElement(ContextCell, { ratio: ctxRatio, promptTokens: summary.lastPromptTokens, ctxMax }), /* @__PURE__ */ React11.createElement(CacheCell, { hitRatio: summary.cacheHitRatio, coldStart, turns: summary.turns }), /* @__PURE__ */ React11.createElement(CostCell, { summary, coldStart }), balance ? /* @__PURE__ */ React11.createElement(BalanceCell, { balance }) : null);
6929
+ return /* @__PURE__ */ React12.createElement(Box11, { marginTop: 1, gap: 3 }, /* @__PURE__ */ React12.createElement(ContextCell, { ratio: ctxRatio, promptTokens: summary.lastPromptTokens, ctxMax }), /* @__PURE__ */ React12.createElement(CacheCell, { hitRatio: summary.cacheHitRatio, coldStart, turns: summary.turns }), /* @__PURE__ */ React12.createElement(CostCell, { summary, coldStart }), balance ? /* @__PURE__ */ React12.createElement(BalanceCell, { balance }) : null);
6829
6930
  }
6830
6931
  function StackedMetrics({
6831
6932
  summary,
@@ -6834,7 +6935,7 @@ function StackedMetrics({
6834
6935
  balance,
6835
6936
  coldStart
6836
6937
  }) {
6837
- return /* @__PURE__ */ React11.createElement(Box10, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React11.createElement(
6938
+ return /* @__PURE__ */ React12.createElement(Box11, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React12.createElement(
6838
6939
  ContextCell,
6839
6940
  {
6840
6941
  ratio: ctxRatio,
@@ -6842,7 +6943,7 @@ function StackedMetrics({
6842
6943
  ctxMax,
6843
6944
  showBar: true
6844
6945
  }
6845
- ), balance ? /* @__PURE__ */ React11.createElement(BalanceCell, { balance }) : null, /* @__PURE__ */ React11.createElement(CacheCell, { hitRatio: summary.cacheHitRatio, coldStart, turns: summary.turns }), /* @__PURE__ */ React11.createElement(CostCell, { summary, coldStart }));
6946
+ ), balance ? /* @__PURE__ */ React12.createElement(BalanceCell, { balance }) : null, /* @__PURE__ */ React12.createElement(CacheCell, { hitRatio: summary.cacheHitRatio, coldStart, turns: summary.turns }), /* @__PURE__ */ React12.createElement(CostCell, { summary, coldStart }));
6846
6947
  }
6847
6948
  function ContextCell({
6848
6949
  ratio,
@@ -6851,11 +6952,11 @@ function ContextCell({
6851
6952
  showBar
6852
6953
  }) {
6853
6954
  if (promptTokens === 0) {
6854
- return /* @__PURE__ */ React11.createElement(Text10, null, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, "ctx "), /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, "\u2014 (no turns yet)"));
6955
+ return /* @__PURE__ */ React12.createElement(Text11, null, /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, "ctx "), /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, "\u2014 (no turns yet)"));
6855
6956
  }
6856
6957
  const color = ratio >= 0.8 ? "red" : ratio >= 0.6 ? "yellow" : "green";
6857
6958
  const pct2 = Math.round(ratio * 100);
6858
- return /* @__PURE__ */ React11.createElement(Text10, null, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, "ctx "), showBar ? /* @__PURE__ */ React11.createElement(Bar, { ratio, color }) : null, showBar ? /* @__PURE__ */ React11.createElement(Text10, null, " ") : null, /* @__PURE__ */ React11.createElement(Text10, { color, bold: true }, formatTokens(promptTokens), "/", formatTokens(ctxMax)), /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, " (", pct2, "%)"), ratio >= 0.8 ? /* @__PURE__ */ React11.createElement(Text10, { color: "red", bold: true }, " \xB7 /compact") : null);
6959
+ return /* @__PURE__ */ React12.createElement(Text11, null, /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, "ctx "), showBar ? /* @__PURE__ */ React12.createElement(Bar, { ratio, color }) : null, showBar ? /* @__PURE__ */ React12.createElement(Text11, null, " ") : null, /* @__PURE__ */ React12.createElement(Text11, { color, bold: true }, formatTokens(promptTokens), "/", formatTokens(ctxMax)), /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, " (", pct2, "%)"), ratio >= 0.8 ? /* @__PURE__ */ React12.createElement(Text11, { color: "red", bold: true }, " \xB7 /compact") : null);
6859
6960
  }
6860
6961
  function CacheCell({
6861
6962
  hitRatio,
@@ -6864,33 +6965,33 @@ function CacheCell({
6864
6965
  }) {
6865
6966
  const pct2 = (hitRatio * 100).toFixed(1);
6866
6967
  if (turns === 0) {
6867
- return /* @__PURE__ */ React11.createElement(Text10, null, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, "cache "), /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, "\u2014"));
6968
+ return /* @__PURE__ */ React12.createElement(Text11, null, /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, "cache "), /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, "\u2014"));
6868
6969
  }
6869
6970
  if (coldStart) {
6870
- return /* @__PURE__ */ React11.createElement(Text10, null, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, "cache "), /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, pct2, "% "), /* @__PURE__ */ React11.createElement(Text10, { dimColor: true, italic: true }, "(cold start)"));
6971
+ return /* @__PURE__ */ React12.createElement(Text11, null, /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, "cache "), /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, pct2, "% "), /* @__PURE__ */ React12.createElement(Text11, { dimColor: true, italic: true }, "(cold start)"));
6871
6972
  }
6872
6973
  const color = hitRatio >= 0.7 ? "green" : hitRatio >= 0.4 ? "yellow" : "red";
6873
- return /* @__PURE__ */ React11.createElement(Text10, null, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, "cache "), /* @__PURE__ */ React11.createElement(Text10, { color, bold: true }, pct2, "%"));
6974
+ return /* @__PURE__ */ React12.createElement(Text11, null, /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, "cache "), /* @__PURE__ */ React12.createElement(Text11, { color, bold: true }, pct2, "%"));
6874
6975
  }
6875
6976
  function CostCell({
6876
6977
  summary,
6877
6978
  coldStart
6878
6979
  }) {
6879
6980
  if (summary.turns === 0) {
6880
- return /* @__PURE__ */ React11.createElement(Text10, null, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, "cost "), /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, "\u2014"));
6981
+ return /* @__PURE__ */ React12.createElement(Text11, null, /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, "cost "), /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, "\u2014"));
6881
6982
  }
6882
6983
  const primaryColor = coldStart ? void 0 : "green";
6883
- return /* @__PURE__ */ React11.createElement(Text10, null, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, "cost "), /* @__PURE__ */ React11.createElement(Text10, { color: primaryColor, bold: !coldStart, dimColor: coldStart }, "$", summary.totalCostUsd.toFixed(6)), /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, " (in ", "$", summary.totalInputCostUsd.toFixed(6), " \xB7 out ", "$", summary.totalOutputCostUsd.toFixed(6), ")"));
6984
+ return /* @__PURE__ */ React12.createElement(Text11, null, /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, "cost "), /* @__PURE__ */ React12.createElement(Text11, { color: primaryColor, bold: !coldStart, dimColor: coldStart }, "$", summary.totalCostUsd.toFixed(6)), /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, " (in ", "$", summary.totalInputCostUsd.toFixed(6), " \xB7 out ", "$", summary.totalOutputCostUsd.toFixed(6), ")"));
6884
6985
  }
6885
6986
  function BalanceCell({ balance }) {
6886
6987
  const color = balance.total < 1 ? "red" : balance.total < 5 ? "yellow" : "green";
6887
- return /* @__PURE__ */ React11.createElement(Text10, null, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, "balance "), /* @__PURE__ */ React11.createElement(Text10, { color, bold: true }, balance.currency === "USD" ? "$" : "", balance.total.toFixed(2), balance.currency !== "USD" ? ` ${balance.currency}` : ""));
6988
+ return /* @__PURE__ */ React12.createElement(Text11, null, /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, "balance "), /* @__PURE__ */ React12.createElement(Text11, { color, bold: true }, balance.currency === "USD" ? "$" : "", balance.total.toFixed(2), balance.currency !== "USD" ? ` ${balance.currency}` : ""));
6888
6989
  }
6889
6990
  function Bar({ ratio, color }) {
6890
6991
  const cells = 10;
6891
6992
  const filled = Math.max(0, Math.min(cells, Math.round(ratio * cells)));
6892
6993
  const bar = "\u2588".repeat(filled) + "\u2591".repeat(cells - filled);
6893
- return /* @__PURE__ */ React11.createElement(Text10, { color }, bar);
6994
+ return /* @__PURE__ */ React12.createElement(Text11, { color }, bar);
6894
6995
  }
6895
6996
  function formatTokens(n) {
6896
6997
  if (n < 1024) return String(n);
@@ -6898,6 +6999,18 @@ function formatTokens(n) {
6898
6999
  return k >= 100 ? `${k.toFixed(0)}K` : `${k.toFixed(1)}K`;
6899
7000
  }
6900
7001
 
7002
+ // src/cli/ui/bang.ts
7003
+ function detectBangCommand(text) {
7004
+ if (!text.startsWith("!")) return null;
7005
+ const body = text.slice(1).trim();
7006
+ if (!body) return null;
7007
+ return body;
7008
+ }
7009
+ function formatBangUserMessage(cmd, output) {
7010
+ return `[!${cmd}]
7011
+ ${output}`;
7012
+ }
7013
+
6901
7014
  // src/cli/ui/slash.ts
6902
7015
  import { spawnSync } from "child_process";
6903
7016
 
@@ -7149,6 +7262,16 @@ function handleSlash(cmd, args, loop, ctx = {}) {
7149
7262
  " /clear clear displayed scrollback only (context kept \u2014 model still sees it)",
7150
7263
  " /exit quit",
7151
7264
  "",
7265
+ "Shell shortcut:",
7266
+ " !<cmd> run <cmd> in the sandbox root; output goes into",
7267
+ " the conversation so the model sees it next turn.",
7268
+ " No allowlist gate \u2014 user-typed = explicit consent.",
7269
+ " Example: !git status !ls src/ !npm test",
7270
+ "",
7271
+ "File references (code mode):",
7272
+ " @path/to/file inline file content under [Referenced files] on send.",
7273
+ " Type `@` to open the picker (\u2191\u2193 navigate, Tab/Enter pick).",
7274
+ "",
7152
7275
  "Presets:",
7153
7276
  " fast deepseek-chat no harvest no branch ~1\xA2/100turns \u2190 default",
7154
7277
  " smart reasoner harvest ~10x cost, slower",
@@ -8051,6 +8174,39 @@ function App({
8051
8174
  return prev;
8052
8175
  });
8053
8176
  }, [slashMatches]);
8177
+ const [atSelected, setAtSelected] = useState5(0);
8178
+ const atFiles = useMemo(() => {
8179
+ if (!codeMode?.rootDir) return [];
8180
+ try {
8181
+ return listFilesSync(codeMode.rootDir, { maxResults: 500 });
8182
+ } catch {
8183
+ return [];
8184
+ }
8185
+ }, [codeMode?.rootDir]);
8186
+ const atPicker = useMemo(() => {
8187
+ if (!codeMode?.rootDir) return null;
8188
+ if (slashMatches !== null) return null;
8189
+ return detectAtPicker(input);
8190
+ }, [codeMode?.rootDir, input, slashMatches]);
8191
+ const atMatches = useMemo(() => {
8192
+ if (!atPicker) return null;
8193
+ return rankPickerCandidates(atFiles, atPicker.query, 40);
8194
+ }, [atPicker, atFiles]);
8195
+ useEffect2(() => {
8196
+ setAtSelected((prev) => {
8197
+ if (!atMatches || atMatches.length === 0) return 0;
8198
+ if (prev >= atMatches.length) return atMatches.length - 1;
8199
+ return prev;
8200
+ });
8201
+ }, [atMatches]);
8202
+ const pickAtMention = useCallback(
8203
+ (chosenPath) => {
8204
+ if (!atPicker) return;
8205
+ const before = input.slice(0, atPicker.atOffset);
8206
+ setInput(`${before}@${chosenPath} `);
8207
+ },
8208
+ [atPicker, input]
8209
+ );
8054
8210
  const loopRef = useRef2(null);
8055
8211
  const subagentSinkRef = useRef2({ current: null });
8056
8212
  const loop = useMemo(() => {
@@ -8220,6 +8376,21 @@ function App({
8220
8376
  }
8221
8377
  if (busy) return;
8222
8378
  if (pendingShell) return;
8379
+ if (atMatches && atMatches.length > 0) {
8380
+ if (key.upArrow) {
8381
+ setAtSelected((i) => Math.max(0, i - 1));
8382
+ return;
8383
+ }
8384
+ if (key.downArrow) {
8385
+ setAtSelected((i) => Math.min(atMatches.length - 1, i + 1));
8386
+ return;
8387
+ }
8388
+ if (key.tab) {
8389
+ const sel = atMatches[atSelected] ?? atMatches[0];
8390
+ if (sel) pickAtMention(sel);
8391
+ return;
8392
+ }
8393
+ }
8223
8394
  if (slashMatches && slashMatches.length > 0) {
8224
8395
  if (key.upArrow) {
8225
8396
  setSlashSelected((i) => Math.max(0, i - 1));
@@ -8305,6 +8476,13 @@ function App({
8305
8476
  async (raw) => {
8306
8477
  let text = raw.trim();
8307
8478
  if (!text || busy) return;
8479
+ if (atMatches && atMatches.length > 0 && atPicker) {
8480
+ const sel = atMatches[atSelected] ?? atMatches[0];
8481
+ if (sel) {
8482
+ pickAtMention(sel);
8483
+ return;
8484
+ }
8485
+ }
8308
8486
  if (text.startsWith("/") && !text.includes(" ")) {
8309
8487
  const typed = text.slice(1).toLowerCase();
8310
8488
  const matches = suggestSlashCommands(typed, !!codeMode);
@@ -8322,6 +8500,49 @@ function App({
8322
8500
  promptHistory.current.push(text);
8323
8501
  return;
8324
8502
  }
8503
+ const bangCmd = detectBangCommand(text);
8504
+ if (bangCmd !== null) {
8505
+ const bangRoot = codeMode?.rootDir ?? process.cwd();
8506
+ promptHistory.current.push(text);
8507
+ setHistorical((prev) => [
8508
+ ...prev,
8509
+ {
8510
+ id: `bang-u-${Date.now()}`,
8511
+ role: "user",
8512
+ text,
8513
+ leadSeparator: prev.length > 0
8514
+ }
8515
+ ]);
8516
+ setBusy(true);
8517
+ try {
8518
+ const result = await runCommand(bangCmd, {
8519
+ cwd: bangRoot,
8520
+ timeoutSec: 60,
8521
+ maxOutputChars: 32e3
8522
+ });
8523
+ const formatted = formatCommandResult(bangCmd, result);
8524
+ setHistorical((prev) => [
8525
+ ...prev,
8526
+ { id: `bang-o-${Date.now()}`, role: "info", text: formatted }
8527
+ ]);
8528
+ loop.log.append({
8529
+ role: "user",
8530
+ content: formatBangUserMessage(bangCmd, formatted)
8531
+ });
8532
+ } catch (err) {
8533
+ setHistorical((prev) => [
8534
+ ...prev,
8535
+ {
8536
+ id: `bang-e-${Date.now()}`,
8537
+ role: "warning",
8538
+ text: `! command failed: ${err.message}`
8539
+ }
8540
+ ]);
8541
+ } finally {
8542
+ setBusy(false);
8543
+ }
8544
+ return;
8545
+ }
8325
8546
  const slash = parseSlash(text);
8326
8547
  if (slash) {
8327
8548
  const result = handleSlash(slash.cmd, slash.args, loop, {
@@ -8659,6 +8880,10 @@ function App({
8659
8880
  planMode,
8660
8881
  session,
8661
8882
  slashSelected,
8883
+ atMatches,
8884
+ atPicker,
8885
+ atSelected,
8886
+ pickAtMention,
8662
8887
  togglePlanMode,
8663
8888
  writeTranscript
8664
8889
  ]
@@ -8809,7 +9034,7 @@ Stay in plan mode \u2014 address the feedback (explore more if needed), then sub
8809
9034
  if (stagedInput?.plan) setPendingPlan(stagedInput.plan);
8810
9035
  setStagedInput(null);
8811
9036
  }, [stagedInput]);
8812
- return /* @__PURE__ */ React12.createElement(TickerProvider, { disabled: PLAIN_UI }, /* @__PURE__ */ React12.createElement(Box11, { flexDirection: "column" }, /* @__PURE__ */ React12.createElement(
9037
+ return /* @__PURE__ */ React13.createElement(TickerProvider, { disabled: PLAIN_UI }, /* @__PURE__ */ React13.createElement(Box12, { flexDirection: "column" }, /* @__PURE__ */ React13.createElement(
8813
9038
  StatsPanel,
8814
9039
  {
8815
9040
  summary,
@@ -8822,21 +9047,21 @@ Stay in plan mode \u2014 address the feedback (explore more if needed), then sub
8822
9047
  busy,
8823
9048
  updateAvailable
8824
9049
  }
8825
- ), /* @__PURE__ */ React12.createElement(Static, { items: historical }, (item) => /* @__PURE__ */ React12.createElement(EventRow, { key: item.id, event: item, projectRoot: hookCwd })), !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && streaming ? /* @__PURE__ */ React12.createElement(Box11, { marginY: 1 }, /* @__PURE__ */ React12.createElement(EventRow, { event: streaming, projectRoot: hookCwd })) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && ongoingTool ? /* @__PURE__ */ React12.createElement(OngoingToolRow, { tool: ongoingTool, progress: toolProgress }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && subagentActivity ? /* @__PURE__ */ React12.createElement(SubagentRow, { activity: subagentActivity }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && !ongoingTool && statusLine ? /* @__PURE__ */ React12.createElement(StatusRow, { text: statusLine }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && busy && !streaming && !ongoingTool && !statusLine ? /* @__PURE__ */ React12.createElement(StatusRow, { text: "processing\u2026" }) : null, stagedInput ? /* @__PURE__ */ React12.createElement(
9050
+ ), /* @__PURE__ */ React13.createElement(Static, { items: historical }, (item) => /* @__PURE__ */ React13.createElement(EventRow, { key: item.id, event: item, projectRoot: hookCwd })), !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && streaming ? /* @__PURE__ */ React13.createElement(Box12, { marginY: 1 }, /* @__PURE__ */ React13.createElement(EventRow, { event: streaming, projectRoot: hookCwd })) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && ongoingTool ? /* @__PURE__ */ React13.createElement(OngoingToolRow, { tool: ongoingTool, progress: toolProgress }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && subagentActivity ? /* @__PURE__ */ React13.createElement(SubagentRow, { activity: subagentActivity }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && !ongoingTool && statusLine ? /* @__PURE__ */ React13.createElement(StatusRow, { text: statusLine }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && busy && !streaming && !ongoingTool && !statusLine ? /* @__PURE__ */ React13.createElement(StatusRow, { text: "processing\u2026" }) : null, stagedInput ? /* @__PURE__ */ React13.createElement(
8826
9051
  PlanRefineInput,
8827
9052
  {
8828
9053
  mode: stagedInput.mode,
8829
9054
  onSubmit: handleStagedInputSubmit,
8830
9055
  onCancel: handleStagedInputCancel
8831
9056
  }
8832
- ) : pendingPlan ? /* @__PURE__ */ React12.createElement(PlanConfirm, { plan: pendingPlan, onChoose: handlePlanConfirm, projectRoot: hookCwd }) : pendingShell ? /* @__PURE__ */ React12.createElement(
9057
+ ) : pendingPlan ? /* @__PURE__ */ React13.createElement(PlanConfirm, { plan: pendingPlan, onChoose: handlePlanConfirm, projectRoot: hookCwd }) : pendingShell ? /* @__PURE__ */ React13.createElement(
8833
9058
  ShellConfirm,
8834
9059
  {
8835
9060
  command: pendingShell,
8836
9061
  allowPrefix: derivePrefix(pendingShell),
8837
9062
  onChoose: handleShellConfirm
8838
9063
  }
8839
- ) : /* @__PURE__ */ React12.createElement(React12.Fragment, null, /* @__PURE__ */ React12.createElement(
9064
+ ) : /* @__PURE__ */ React13.createElement(React13.Fragment, null, /* @__PURE__ */ React13.createElement(
8840
9065
  PromptInput,
8841
9066
  {
8842
9067
  value: input,
@@ -8844,20 +9069,27 @@ Stay in plan mode \u2014 address the feedback (explore more if needed), then sub
8844
9069
  onSubmit: handleSubmit,
8845
9070
  disabled: busy
8846
9071
  }
8847
- ), /* @__PURE__ */ React12.createElement(SlashSuggestions, { matches: slashMatches, selectedIndex: slashSelected }))));
9072
+ ), /* @__PURE__ */ React13.createElement(SlashSuggestions, { matches: slashMatches, selectedIndex: slashSelected }), /* @__PURE__ */ React13.createElement(
9073
+ AtMentionSuggestions,
9074
+ {
9075
+ matches: atMatches,
9076
+ selectedIndex: atSelected,
9077
+ query: atPicker?.query ?? ""
9078
+ }
9079
+ ))));
8848
9080
  }
8849
9081
  var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
8850
9082
  function StatusRow({ text }) {
8851
9083
  const tick = useTick();
8852
9084
  const elapsed = useElapsedSeconds();
8853
- return /* @__PURE__ */ React12.createElement(Box11, { marginY: 1 }, /* @__PURE__ */ React12.createElement(Text11, { color: "magenta" }, SPINNER_FRAMES[tick % SPINNER_FRAMES.length]), /* @__PURE__ */ React12.createElement(Text11, { color: "magenta" }, ` ${text}`), /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, ` ${elapsed}s`));
9085
+ return /* @__PURE__ */ React13.createElement(Box12, { marginY: 1 }, /* @__PURE__ */ React13.createElement(Text12, { color: "magenta" }, SPINNER_FRAMES[tick % SPINNER_FRAMES.length]), /* @__PURE__ */ React13.createElement(Text12, { color: "magenta" }, ` ${text}`), /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, ` ${elapsed}s`));
8854
9086
  }
8855
9087
  function SubagentRow({
8856
9088
  activity
8857
9089
  }) {
8858
9090
  const tick = useTick();
8859
9091
  const seconds = (activity.elapsedMs / 1e3).toFixed(1);
8860
- return /* @__PURE__ */ React12.createElement(Box11, { paddingLeft: 2 }, /* @__PURE__ */ React12.createElement(Text11, { color: "magenta" }, SPINNER_FRAMES[tick % SPINNER_FRAMES.length]), /* @__PURE__ */ React12.createElement(Text11, { color: "magenta" }, ` \u232C subagent: ${activity.task}`), /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, ` \xB7 iter ${activity.iter} \xB7 ${seconds}s`));
9092
+ return /* @__PURE__ */ React13.createElement(Box12, { paddingLeft: 2 }, /* @__PURE__ */ React13.createElement(Text12, { color: "magenta" }, SPINNER_FRAMES[tick % SPINNER_FRAMES.length]), /* @__PURE__ */ React13.createElement(Text12, { color: "magenta" }, ` \u232C subagent: ${activity.task}`), /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, ` \xB7 iter ${activity.iter} \xB7 ${seconds}s`));
8861
9093
  }
8862
9094
  function OngoingToolRow({
8863
9095
  tool,
@@ -8866,7 +9098,7 @@ function OngoingToolRow({
8866
9098
  const tick = useTick();
8867
9099
  const elapsed = useElapsedSeconds();
8868
9100
  const summary = summarizeToolArgs(tool.name, tool.args);
8869
- return /* @__PURE__ */ React12.createElement(Box11, { marginY: 1, flexDirection: "column" }, /* @__PURE__ */ React12.createElement(Box11, null, /* @__PURE__ */ React12.createElement(Text11, { color: "cyan" }, SPINNER_FRAMES[tick % SPINNER_FRAMES.length]), /* @__PURE__ */ React12.createElement(Text11, { color: "yellow" }, ` tool<${tool.name}> running\u2026`), /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, ` ${elapsed}s`)), progress ? /* @__PURE__ */ React12.createElement(Box11, { paddingLeft: 2 }, /* @__PURE__ */ React12.createElement(Text11, { color: "cyan" }, renderProgressLine(progress))) : null, summary ? /* @__PURE__ */ React12.createElement(Box11, { paddingLeft: 2 }, /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, summary)) : null);
9101
+ return /* @__PURE__ */ React13.createElement(Box12, { marginY: 1, flexDirection: "column" }, /* @__PURE__ */ React13.createElement(Box12, null, /* @__PURE__ */ React13.createElement(Text12, { color: "cyan" }, SPINNER_FRAMES[tick % SPINNER_FRAMES.length]), /* @__PURE__ */ React13.createElement(Text12, { color: "yellow" }, ` tool<${tool.name}> running\u2026`), /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, ` ${elapsed}s`)), progress ? /* @__PURE__ */ React13.createElement(Box12, { paddingLeft: 2 }, /* @__PURE__ */ React13.createElement(Text12, { color: "cyan" }, renderProgressLine(progress))) : null, summary ? /* @__PURE__ */ React13.createElement(Box12, { paddingLeft: 2 }, /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, summary)) : null);
8870
9102
  }
8871
9103
  function renderProgressLine(p) {
8872
9104
  const msg = p.message ? ` ${p.message}` : "";
@@ -8962,15 +9194,15 @@ function describeRepair(repair) {
8962
9194
  }
8963
9195
 
8964
9196
  // src/cli/ui/SessionPicker.tsx
8965
- import { Box as Box12, Text as Text12 } from "ink";
8966
- import React13 from "react";
9197
+ import { Box as Box13, Text as Text13 } from "ink";
9198
+ import React14 from "react";
8967
9199
  function SessionPicker({
8968
9200
  sessionName,
8969
9201
  messageCount,
8970
9202
  lastActive,
8971
9203
  onChoose
8972
9204
  }) {
8973
- return /* @__PURE__ */ React13.createElement(Box12, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React13.createElement(Box12, { marginBottom: 1 }, /* @__PURE__ */ React13.createElement(Text12, { bold: true, color: "cyan" }, `Session "${sessionName}" has ${messageCount} prior message${messageCount === 1 ? "" : "s"}`), /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, ` \xB7 last active ${relativeTime(lastActive)}`)), /* @__PURE__ */ React13.createElement(
9205
+ return /* @__PURE__ */ React14.createElement(Box13, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React14.createElement(Box13, { marginBottom: 1 }, /* @__PURE__ */ React14.createElement(Text13, { bold: true, color: "cyan" }, `Session "${sessionName}" has ${messageCount} prior message${messageCount === 1 ? "" : "s"}`), /* @__PURE__ */ React14.createElement(Text13, { dimColor: true }, ` \xB7 last active ${relativeTime(lastActive)}`)), /* @__PURE__ */ React14.createElement(
8974
9206
  SingleSelect,
8975
9207
  {
8976
9208
  initialValue: "new",
@@ -8993,7 +9225,7 @@ function SessionPicker({
8993
9225
  ],
8994
9226
  onSubmit: (v) => onChoose(v)
8995
9227
  }
8996
- ), /* @__PURE__ */ React13.createElement(Box12, { marginTop: 1 }, /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, "\u2191\u2193 to move \xB7 Enter to pick")));
9228
+ ), /* @__PURE__ */ React14.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text13, { dimColor: true }, "\u2191\u2193 to move \xB7 Enter to pick")));
8997
9229
  }
8998
9230
  function relativeTime(date) {
8999
9231
  const ms = Date.now() - date.getTime();
@@ -9009,9 +9241,9 @@ function relativeTime(date) {
9009
9241
  }
9010
9242
 
9011
9243
  // src/cli/ui/Setup.tsx
9012
- import { Box as Box13, Text as Text13, useApp as useApp2 } from "ink";
9244
+ import { Box as Box14, Text as Text14, useApp as useApp2 } from "ink";
9013
9245
  import TextInput from "ink-text-input";
9014
- import React14, { useState as useState6 } from "react";
9246
+ import React15, { useState as useState6 } from "react";
9015
9247
  function Setup({ onReady }) {
9016
9248
  const [value, setValue] = useState6("");
9017
9249
  const [error, setError] = useState6(null);
@@ -9035,7 +9267,7 @@ function Setup({ onReady }) {
9035
9267
  }
9036
9268
  onReady(trimmed);
9037
9269
  };
9038
- return /* @__PURE__ */ React14.createElement(Box13, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React14.createElement(Text13, { bold: true, color: "cyan" }, "Welcome to Reasonix."), /* @__PURE__ */ React14.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text13, null, "Paste your DeepSeek API key to get started.")), /* @__PURE__ */ React14.createElement(Text13, { dimColor: true }, "Get one (free credit on signup): https://platform.deepseek.com/api_keys"), /* @__PURE__ */ React14.createElement(Text13, { dimColor: true }, "Saved locally to ", defaultConfigPath()), /* @__PURE__ */ React14.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text13, { bold: true, color: "cyan" }, "key \u203A "), /* @__PURE__ */ React14.createElement(
9270
+ return /* @__PURE__ */ React15.createElement(Box14, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React15.createElement(Text14, { bold: true, color: "cyan" }, "Welcome to Reasonix."), /* @__PURE__ */ React15.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React15.createElement(Text14, null, "Paste your DeepSeek API key to get started.")), /* @__PURE__ */ React15.createElement(Text14, { dimColor: true }, "Get one (free credit on signup): https://platform.deepseek.com/api_keys"), /* @__PURE__ */ React15.createElement(Text14, { dimColor: true }, "Saved locally to ", defaultConfigPath()), /* @__PURE__ */ React15.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React15.createElement(Text14, { bold: true, color: "cyan" }, "key \u203A "), /* @__PURE__ */ React15.createElement(
9039
9271
  TextInput,
9040
9272
  {
9041
9273
  value,
@@ -9044,7 +9276,7 @@ function Setup({ onReady }) {
9044
9276
  mask: "\u2022",
9045
9277
  placeholder: "sk-..."
9046
9278
  }
9047
- )), error ? /* @__PURE__ */ React14.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text13, { color: "red" }, error)) : value ? /* @__PURE__ */ React14.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text13, { dimColor: true }, "preview: ", redactKey(value))) : null, /* @__PURE__ */ React14.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text13, { dimColor: true }, "(Type /exit to abort.)")));
9279
+ )), error ? /* @__PURE__ */ React15.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React15.createElement(Text14, { color: "red" }, error)) : value ? /* @__PURE__ */ React15.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React15.createElement(Text14, { dimColor: true }, "preview: ", redactKey(value))) : null, /* @__PURE__ */ React15.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React15.createElement(Text14, { dimColor: true }, "(Type /exit to abort.)")));
9048
9280
  }
9049
9281
 
9050
9282
  // src/cli/commands/chat.tsx
@@ -9060,7 +9292,7 @@ function Root({
9060
9292
  const [key, setKey] = useState7(initialKey);
9061
9293
  const [pending, setPending] = useState7(sessionPreview);
9062
9294
  if (!key) {
9063
- return /* @__PURE__ */ React15.createElement(
9295
+ return /* @__PURE__ */ React16.createElement(
9064
9296
  Setup,
9065
9297
  {
9066
9298
  onReady: (k) => {
@@ -9072,7 +9304,7 @@ function Root({
9072
9304
  }
9073
9305
  process.env.DEEPSEEK_API_KEY = key;
9074
9306
  if (pending && appProps.session) {
9075
- return /* @__PURE__ */ React15.createElement(
9307
+ return /* @__PURE__ */ React16.createElement(
9076
9308
  SessionPicker,
9077
9309
  {
9078
9310
  sessionName: appProps.session,
@@ -9087,7 +9319,7 @@ function Root({
9087
9319
  }
9088
9320
  );
9089
9321
  }
9090
- return /* @__PURE__ */ React15.createElement(
9322
+ return /* @__PURE__ */ React16.createElement(
9091
9323
  App,
9092
9324
  {
9093
9325
  model: appProps.model,
@@ -9190,7 +9422,7 @@ async function chatCommand(opts) {
9190
9422
  rewriteSession(opts.session, []);
9191
9423
  }
9192
9424
  const { waitUntilExit } = render(
9193
- /* @__PURE__ */ React15.createElement(
9425
+ /* @__PURE__ */ React16.createElement(
9194
9426
  Root,
9195
9427
  {
9196
9428
  initialKey,
@@ -9253,34 +9485,34 @@ async function codeCommand(opts = {}) {
9253
9485
  import { writeFileSync as writeFileSync5 } from "fs";
9254
9486
  import { basename as basename2 } from "path";
9255
9487
  import { render as render2 } from "ink";
9256
- import React18 from "react";
9488
+ import React19 from "react";
9257
9489
 
9258
9490
  // src/cli/ui/DiffApp.tsx
9259
- import { Box as Box15, Static as Static2, Text as Text15, useApp as useApp3, useInput as useInput5 } from "ink";
9260
- import React17, { useState as useState8 } from "react";
9491
+ import { Box as Box16, Static as Static2, Text as Text16, useApp as useApp3, useInput as useInput5 } from "ink";
9492
+ import React18, { useState as useState8 } from "react";
9261
9493
 
9262
9494
  // src/cli/ui/RecordView.tsx
9263
- import { Box as Box14, Text as Text14 } from "ink";
9264
- import React16 from "react";
9495
+ import { Box as Box15, Text as Text15 } from "ink";
9496
+ import React17 from "react";
9265
9497
  function RecordView({ rec, compact = false }) {
9266
9498
  const toolArgsMax = compact ? 120 : 200;
9267
9499
  const toolContentMax = compact ? 200 : 400;
9268
9500
  if (rec.role === "user") {
9269
- return /* @__PURE__ */ React16.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text14, { bold: true, color: "cyan" }, "you \u203A", " "), /* @__PURE__ */ React16.createElement(Text14, null, rec.content));
9501
+ return /* @__PURE__ */ React17.createElement(Box15, { marginTop: 1 }, /* @__PURE__ */ React17.createElement(Text15, { bold: true, color: "cyan" }, "you \u203A", " "), /* @__PURE__ */ React17.createElement(Text15, null, rec.content));
9270
9502
  }
9271
9503
  if (rec.role === "assistant_final") {
9272
- return /* @__PURE__ */ React16.createElement(Box14, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Text14, { bold: true, color: "green" }, "assistant"), rec.cost !== void 0 ? /* @__PURE__ */ React16.createElement(Text14, { dimColor: true }, " $", rec.cost.toFixed(6)) : null, rec.usage ? /* @__PURE__ */ React16.createElement(CacheBadge, { usage: rec.usage }) : null), rec.planState ? /* @__PURE__ */ React16.createElement(PlanStateBlock, { planState: rec.planState }) : null, rec.content ? /* @__PURE__ */ React16.createElement(Text14, null, rec.content) : /* @__PURE__ */ React16.createElement(Text14, { dimColor: true, italic: true }, "(tool-call response only)"));
9504
+ return /* @__PURE__ */ React17.createElement(Box15, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React17.createElement(Box15, null, /* @__PURE__ */ React17.createElement(Text15, { bold: true, color: "green" }, "assistant"), rec.cost !== void 0 ? /* @__PURE__ */ React17.createElement(Text15, { dimColor: true }, " $", rec.cost.toFixed(6)) : null, rec.usage ? /* @__PURE__ */ React17.createElement(CacheBadge, { usage: rec.usage }) : null), rec.planState ? /* @__PURE__ */ React17.createElement(PlanStateBlock, { planState: rec.planState }) : null, rec.content ? /* @__PURE__ */ React17.createElement(Text15, null, rec.content) : /* @__PURE__ */ React17.createElement(Text15, { dimColor: true, italic: true }, "(tool-call response only)"));
9273
9505
  }
9274
9506
  if (rec.role === "tool") {
9275
- return /* @__PURE__ */ React16.createElement(Box14, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text14, { color: "yellow" }, "tool<", rec.tool ?? "?", ">"), rec.args ? /* @__PURE__ */ React16.createElement(Text14, { dimColor: true }, " args: ", truncate3(rec.args, toolArgsMax)) : null, /* @__PURE__ */ React16.createElement(Text14, { dimColor: true }, " \u2192 ", truncate3(rec.content, toolContentMax)));
9507
+ return /* @__PURE__ */ React17.createElement(Box15, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React17.createElement(Text15, { color: "yellow" }, "tool<", rec.tool ?? "?", ">"), rec.args ? /* @__PURE__ */ React17.createElement(Text15, { dimColor: true }, " args: ", truncate3(rec.args, toolArgsMax)) : null, /* @__PURE__ */ React17.createElement(Text15, { dimColor: true }, " \u2192 ", truncate3(rec.content, toolContentMax)));
9276
9508
  }
9277
9509
  if (rec.role === "error") {
9278
- return /* @__PURE__ */ React16.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text14, { color: "red", bold: true }, "error", " "), /* @__PURE__ */ React16.createElement(Text14, { color: "red" }, rec.error ?? rec.content));
9510
+ return /* @__PURE__ */ React17.createElement(Box15, { marginTop: 1 }, /* @__PURE__ */ React17.createElement(Text15, { color: "red", bold: true }, "error", " "), /* @__PURE__ */ React17.createElement(Text15, { color: "red" }, rec.error ?? rec.content));
9279
9511
  }
9280
9512
  if (rec.role === "done" || rec.role === "assistant_delta") {
9281
9513
  return null;
9282
9514
  }
9283
- return /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Text14, { dimColor: true }, "[", rec.role, "] ", rec.content));
9515
+ return /* @__PURE__ */ React17.createElement(Box15, null, /* @__PURE__ */ React17.createElement(Text15, { dimColor: true }, "[", rec.role, "] ", rec.content));
9284
9516
  }
9285
9517
  function CacheBadge({ usage }) {
9286
9518
  const hit = usage.prompt_cache_hit_tokens ?? 0;
@@ -9289,7 +9521,7 @@ function CacheBadge({ usage }) {
9289
9521
  if (total === 0) return null;
9290
9522
  const pct2 = hit / total * 100;
9291
9523
  const color = pct2 >= 70 ? "green" : pct2 >= 40 ? "yellow" : "red";
9292
- return /* @__PURE__ */ React16.createElement(Text14, null, /* @__PURE__ */ React16.createElement(Text14, { dimColor: true }, " \xB7 cache "), /* @__PURE__ */ React16.createElement(Text14, { color }, pct2.toFixed(1), "%"));
9524
+ return /* @__PURE__ */ React17.createElement(Text15, null, /* @__PURE__ */ React17.createElement(Text15, { dimColor: true }, " \xB7 cache "), /* @__PURE__ */ React17.createElement(Text15, { color }, pct2.toFixed(1), "%"));
9293
9525
  }
9294
9526
  function truncate3(s, max) {
9295
9527
  return s.length <= max ? s : `${s.slice(0, max)}\u2026 (+${s.length - max} chars)`;
@@ -9323,7 +9555,7 @@ function DiffApp({ report }) {
9323
9555
  }
9324
9556
  });
9325
9557
  const pair = report.pairs[idx];
9326
- return /* @__PURE__ */ React17.createElement(Box15, { flexDirection: "column" }, /* @__PURE__ */ React17.createElement(DiffHeader, { report }), /* @__PURE__ */ React17.createElement(Box15, { marginTop: 1, paddingX: 1, justifyContent: "space-between" }, /* @__PURE__ */ React17.createElement(Text15, { color: "cyan", bold: true }, "turn ", pair?.turn ?? "?", " (", idx + 1, " / ", report.pairs.length, ")"), /* @__PURE__ */ React17.createElement(Text15, null, pair ? /* @__PURE__ */ React17.createElement(KindBadge, { kind: pair.kind }) : null)), /* @__PURE__ */ React17.createElement(Box15, { flexDirection: "row", marginTop: 1 }, /* @__PURE__ */ React17.createElement(Pane, { label: report.a.label, headerColor: "blue", records: paneRecords(pair, "a") }), /* @__PURE__ */ React17.createElement(Pane, { label: report.b.label, headerColor: "magenta", records: paneRecords(pair, "b") })), pair?.divergenceNote ? /* @__PURE__ */ React17.createElement(Box15, { marginTop: 1, paddingX: 1 }, /* @__PURE__ */ React17.createElement(Text15, { color: "yellow" }, "\u2605 "), /* @__PURE__ */ React17.createElement(Text15, null, pair.divergenceNote)) : null, /* @__PURE__ */ React17.createElement(Box15, { marginTop: 1, paddingX: 1, borderStyle: "single", borderColor: "gray" }, /* @__PURE__ */ React17.createElement(Text15, { dimColor: true }, /* @__PURE__ */ React17.createElement(Text15, { bold: true }, "j"), "/", /* @__PURE__ */ React17.createElement(Text15, { bold: true }, "\u2193"), " next \xB7 ", /* @__PURE__ */ React17.createElement(Text15, { bold: true }, "k"), "/", /* @__PURE__ */ React17.createElement(Text15, { bold: true }, "\u2191"), " ", "prev \xB7 ", /* @__PURE__ */ React17.createElement(Text15, { bold: true }, "n"), " next-diverge \xB7 ", /* @__PURE__ */ React17.createElement(Text15, { bold: true }, "N"), "/", /* @__PURE__ */ React17.createElement(Text15, { bold: true }, "p"), " ", "prev-diverge \xB7 ", /* @__PURE__ */ React17.createElement(Text15, { bold: true }, "g"), "/", /* @__PURE__ */ React17.createElement(Text15, { bold: true }, "G"), " first/last \xB7 ", /* @__PURE__ */ React17.createElement(Text15, { bold: true }, "q"), " ", "quit")));
9558
+ return /* @__PURE__ */ React18.createElement(Box16, { flexDirection: "column" }, /* @__PURE__ */ React18.createElement(DiffHeader, { report }), /* @__PURE__ */ React18.createElement(Box16, { marginTop: 1, paddingX: 1, justifyContent: "space-between" }, /* @__PURE__ */ React18.createElement(Text16, { color: "cyan", bold: true }, "turn ", pair?.turn ?? "?", " (", idx + 1, " / ", report.pairs.length, ")"), /* @__PURE__ */ React18.createElement(Text16, null, pair ? /* @__PURE__ */ React18.createElement(KindBadge, { kind: pair.kind }) : null)), /* @__PURE__ */ React18.createElement(Box16, { flexDirection: "row", marginTop: 1 }, /* @__PURE__ */ React18.createElement(Pane, { label: report.a.label, headerColor: "blue", records: paneRecords(pair, "a") }), /* @__PURE__ */ React18.createElement(Pane, { label: report.b.label, headerColor: "magenta", records: paneRecords(pair, "b") })), pair?.divergenceNote ? /* @__PURE__ */ React18.createElement(Box16, { marginTop: 1, paddingX: 1 }, /* @__PURE__ */ React18.createElement(Text16, { color: "yellow" }, "\u2605 "), /* @__PURE__ */ React18.createElement(Text16, null, pair.divergenceNote)) : null, /* @__PURE__ */ React18.createElement(Box16, { marginTop: 1, paddingX: 1, borderStyle: "single", borderColor: "gray" }, /* @__PURE__ */ React18.createElement(Text16, { dimColor: true }, /* @__PURE__ */ React18.createElement(Text16, { bold: true }, "j"), "/", /* @__PURE__ */ React18.createElement(Text16, { bold: true }, "\u2193"), " next \xB7 ", /* @__PURE__ */ React18.createElement(Text16, { bold: true }, "k"), "/", /* @__PURE__ */ React18.createElement(Text16, { bold: true }, "\u2191"), " ", "prev \xB7 ", /* @__PURE__ */ React18.createElement(Text16, { bold: true }, "n"), " next-diverge \xB7 ", /* @__PURE__ */ React18.createElement(Text16, { bold: true }, "N"), "/", /* @__PURE__ */ React18.createElement(Text16, { bold: true }, "p"), " ", "prev-diverge \xB7 ", /* @__PURE__ */ React18.createElement(Text16, { bold: true }, "g"), "/", /* @__PURE__ */ React18.createElement(Text16, { bold: true }, "G"), " first/last \xB7 ", /* @__PURE__ */ React18.createElement(Text16, { bold: true }, "q"), " ", "quit")));
9327
9559
  }
9328
9560
  function DiffHeader({ report }) {
9329
9561
  const a = report.a;
@@ -9341,15 +9573,15 @@ function DiffHeader({ report }) {
9341
9573
  } else if (a.stats.prefixHashes[0] && a.stats.prefixHashes[0] === b.stats.prefixHashes[0]) {
9342
9574
  prefixLine = `shared prefix hash ${a.stats.prefixHashes[0].slice(0, 12)}\u2026 \u2014 cache delta attributable to log stability, not prompt change.`;
9343
9575
  }
9344
- return /* @__PURE__ */ React17.createElement(Box15, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React17.createElement(Box15, { justifyContent: "space-between" }, /* @__PURE__ */ React17.createElement(Text15, null, /* @__PURE__ */ React17.createElement(Text15, { color: "cyan", bold: true }, "reasonix diff"), /* @__PURE__ */ React17.createElement(Text15, { dimColor: true }, " \xB7 A="), /* @__PURE__ */ React17.createElement(Text15, { color: "blue" }, a.label), /* @__PURE__ */ React17.createElement(Text15, { dimColor: true }, " vs B="), /* @__PURE__ */ React17.createElement(Text15, { color: "magenta" }, b.label)), /* @__PURE__ */ React17.createElement(Text15, { dimColor: true }, report.pairs.length, " turns aligned")), /* @__PURE__ */ React17.createElement(Box15, { marginTop: 1, gap: 3 }, /* @__PURE__ */ React17.createElement(Text15, null, /* @__PURE__ */ React17.createElement(Text15, { dimColor: true }, "cache "), /* @__PURE__ */ React17.createElement(Text15, null, (a.stats.cacheHitRatio * 100).toFixed(1), "%"), /* @__PURE__ */ React17.createElement(Text15, { dimColor: true }, " \u2192 "), /* @__PURE__ */ React17.createElement(Text15, null, (b.stats.cacheHitRatio * 100).toFixed(1), "%"), /* @__PURE__ */ React17.createElement(Text15, { color: cacheDelta >= 0 ? "green" : "red", bold: true }, " ", cacheDelta >= 0 ? "+" : "", (cacheDelta * 100).toFixed(1), "pp")), /* @__PURE__ */ React17.createElement(Text15, null, /* @__PURE__ */ React17.createElement(Text15, { dimColor: true }, "cost "), /* @__PURE__ */ React17.createElement(Text15, null, "$", a.stats.totalCostUsd.toFixed(6)), /* @__PURE__ */ React17.createElement(Text15, { dimColor: true }, " \u2192 "), /* @__PURE__ */ React17.createElement(Text15, null, "$", b.stats.totalCostUsd.toFixed(6)), /* @__PURE__ */ React17.createElement(Text15, { color: costDelta2 <= 0 ? "green" : "red", bold: true }, " ", costDelta2 >= 0 ? "+" : "", costDelta2.toFixed(1), "%")), /* @__PURE__ */ React17.createElement(Text15, null, /* @__PURE__ */ React17.createElement(Text15, { dimColor: true }, "model calls "), /* @__PURE__ */ React17.createElement(Text15, null, a.stats.turns, " \u2192 ", b.stats.turns))), prefixLine ? /* @__PURE__ */ React17.createElement(Box15, { marginTop: 1 }, /* @__PURE__ */ React17.createElement(Text15, { dimColor: true, italic: true }, prefixLine)) : null);
9576
+ return /* @__PURE__ */ React18.createElement(Box16, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React18.createElement(Box16, { justifyContent: "space-between" }, /* @__PURE__ */ React18.createElement(Text16, null, /* @__PURE__ */ React18.createElement(Text16, { color: "cyan", bold: true }, "reasonix diff"), /* @__PURE__ */ React18.createElement(Text16, { dimColor: true }, " \xB7 A="), /* @__PURE__ */ React18.createElement(Text16, { color: "blue" }, a.label), /* @__PURE__ */ React18.createElement(Text16, { dimColor: true }, " vs B="), /* @__PURE__ */ React18.createElement(Text16, { color: "magenta" }, b.label)), /* @__PURE__ */ React18.createElement(Text16, { dimColor: true }, report.pairs.length, " turns aligned")), /* @__PURE__ */ React18.createElement(Box16, { marginTop: 1, gap: 3 }, /* @__PURE__ */ React18.createElement(Text16, null, /* @__PURE__ */ React18.createElement(Text16, { dimColor: true }, "cache "), /* @__PURE__ */ React18.createElement(Text16, null, (a.stats.cacheHitRatio * 100).toFixed(1), "%"), /* @__PURE__ */ React18.createElement(Text16, { dimColor: true }, " \u2192 "), /* @__PURE__ */ React18.createElement(Text16, null, (b.stats.cacheHitRatio * 100).toFixed(1), "%"), /* @__PURE__ */ React18.createElement(Text16, { color: cacheDelta >= 0 ? "green" : "red", bold: true }, " ", cacheDelta >= 0 ? "+" : "", (cacheDelta * 100).toFixed(1), "pp")), /* @__PURE__ */ React18.createElement(Text16, null, /* @__PURE__ */ React18.createElement(Text16, { dimColor: true }, "cost "), /* @__PURE__ */ React18.createElement(Text16, null, "$", a.stats.totalCostUsd.toFixed(6)), /* @__PURE__ */ React18.createElement(Text16, { dimColor: true }, " \u2192 "), /* @__PURE__ */ React18.createElement(Text16, null, "$", b.stats.totalCostUsd.toFixed(6)), /* @__PURE__ */ React18.createElement(Text16, { color: costDelta2 <= 0 ? "green" : "red", bold: true }, " ", costDelta2 >= 0 ? "+" : "", costDelta2.toFixed(1), "%")), /* @__PURE__ */ React18.createElement(Text16, null, /* @__PURE__ */ React18.createElement(Text16, { dimColor: true }, "model calls "), /* @__PURE__ */ React18.createElement(Text16, null, a.stats.turns, " \u2192 ", b.stats.turns))), prefixLine ? /* @__PURE__ */ React18.createElement(Box16, { marginTop: 1 }, /* @__PURE__ */ React18.createElement(Text16, { dimColor: true, italic: true }, prefixLine)) : null);
9345
9577
  }
9346
9578
  function Pane({
9347
9579
  label,
9348
9580
  headerColor,
9349
9581
  records
9350
9582
  }) {
9351
- return /* @__PURE__ */ React17.createElement(
9352
- Box15,
9583
+ return /* @__PURE__ */ React18.createElement(
9584
+ Box16,
9353
9585
  {
9354
9586
  flexDirection: "column",
9355
9587
  flexGrow: 1,
@@ -9357,21 +9589,21 @@ function Pane({
9357
9589
  borderStyle: "single",
9358
9590
  borderColor: headerColor
9359
9591
  },
9360
- /* @__PURE__ */ React17.createElement(Text15, { color: headerColor, bold: true }, label),
9361
- records.length === 0 ? /* @__PURE__ */ React17.createElement(Box15, { marginTop: 1 }, /* @__PURE__ */ React17.createElement(Text15, { dimColor: true, italic: true }, "(no records on this side for this turn)")) : /* @__PURE__ */ React17.createElement(Static2, { items: records.map((rec, i) => ({ key: `${label}-${i}`, rec })) }, ({ key, rec }) => /* @__PURE__ */ React17.createElement(RecordView, { key, rec, compact: true }))
9592
+ /* @__PURE__ */ React18.createElement(Text16, { color: headerColor, bold: true }, label),
9593
+ records.length === 0 ? /* @__PURE__ */ React18.createElement(Box16, { marginTop: 1 }, /* @__PURE__ */ React18.createElement(Text16, { dimColor: true, italic: true }, "(no records on this side for this turn)")) : /* @__PURE__ */ React18.createElement(Static2, { items: records.map((rec, i) => ({ key: `${label}-${i}`, rec })) }, ({ key, rec }) => /* @__PURE__ */ React18.createElement(RecordView, { key, rec, compact: true }))
9362
9594
  );
9363
9595
  }
9364
9596
  function KindBadge({ kind }) {
9365
9597
  if (kind === "match") {
9366
- return /* @__PURE__ */ React17.createElement(Text15, { color: "green" }, "\u2713 match");
9598
+ return /* @__PURE__ */ React18.createElement(Text16, { color: "green" }, "\u2713 match");
9367
9599
  }
9368
9600
  if (kind === "diverge") {
9369
- return /* @__PURE__ */ React17.createElement(Text15, { color: "yellow" }, "\u2605 diverge");
9601
+ return /* @__PURE__ */ React18.createElement(Text16, { color: "yellow" }, "\u2605 diverge");
9370
9602
  }
9371
9603
  if (kind === "only_in_a") {
9372
- return /* @__PURE__ */ React17.createElement(Text15, { color: "blue" }, "\u2190 only in A");
9604
+ return /* @__PURE__ */ React18.createElement(Text16, { color: "blue" }, "\u2190 only in A");
9373
9605
  }
9374
- return /* @__PURE__ */ React17.createElement(Text15, { color: "magenta" }, "\u2192 only in B");
9606
+ return /* @__PURE__ */ React18.createElement(Text16, { color: "magenta" }, "\u2192 only in B");
9375
9607
  }
9376
9608
  function paneRecords(pair, side) {
9377
9609
  if (!pair) return [];
@@ -9402,7 +9634,7 @@ markdown report written to ${opts.mdPath}`);
9402
9634
  return;
9403
9635
  }
9404
9636
  if (wantTui) {
9405
- const { waitUntilExit } = render2(React18.createElement(DiffApp, { report }), {
9637
+ const { waitUntilExit } = render2(React19.createElement(DiffApp, { report }), {
9406
9638
  exitOnCtrlC: true,
9407
9639
  patchConsole: false
9408
9640
  });
@@ -9543,11 +9775,11 @@ function pad2(s, width) {
9543
9775
 
9544
9776
  // src/cli/commands/replay.ts
9545
9777
  import { render as render3 } from "ink";
9546
- import React20 from "react";
9778
+ import React21 from "react";
9547
9779
 
9548
9780
  // src/cli/ui/ReplayApp.tsx
9549
- import { Box as Box16, Static as Static3, Text as Text16, useApp as useApp4, useInput as useInput6 } from "ink";
9550
- import React19, { useMemo as useMemo2, useState as useState9 } from "react";
9781
+ import { Box as Box17, Static as Static3, Text as Text17, useApp as useApp4, useInput as useInput6 } from "ink";
9782
+ import React20, { useMemo as useMemo2, useState as useState9 } from "react";
9551
9783
  function ReplayApp({ meta, pages }) {
9552
9784
  const { exit } = useApp4();
9553
9785
  const maxIdx = Math.max(0, pages.length - 1);
@@ -9586,14 +9818,14 @@ function ReplayApp({ meta, pages }) {
9586
9818
  const prefixHash = cumStats.prefixHashes.length === 1 ? cumStats.prefixHashes[0].slice(0, 16) : cumStats.prefixHashes.length === 0 ? "(untracked)" : `(churned \xD7${cumStats.prefixHashes.length})`;
9587
9819
  const currentPage = pages[idx];
9588
9820
  const progressLabel = pages.length === 0 ? "empty transcript" : `turn ${idx + 1} / ${pages.length}`;
9589
- return /* @__PURE__ */ React19.createElement(Box16, { flexDirection: "column" }, /* @__PURE__ */ React19.createElement(
9821
+ return /* @__PURE__ */ React20.createElement(Box17, { flexDirection: "column" }, /* @__PURE__ */ React20.createElement(
9590
9822
  StatsPanel,
9591
9823
  {
9592
9824
  summary,
9593
9825
  model: cumStats.models[0] ?? meta?.model ?? "?",
9594
9826
  prefixHash
9595
9827
  }
9596
- ), /* @__PURE__ */ React19.createElement(Box16, { flexDirection: "column", marginTop: 1, paddingX: 1 }, /* @__PURE__ */ React19.createElement(Box16, { justifyContent: "space-between" }, /* @__PURE__ */ React19.createElement(Text16, { color: "cyan", bold: true }, progressLabel), meta ? /* @__PURE__ */ React19.createElement(Text16, { dimColor: true }, meta.source, meta.task ? ` \xB7 ${meta.task}` : "", meta.mode ? ` \xB7 ${meta.mode}` : "") : null), currentPage ? /* @__PURE__ */ React19.createElement(Static3, { items: currentPage.records.map((rec, i) => ({ key: `${idx}-${i}`, rec })) }, ({ key, rec }) => /* @__PURE__ */ React19.createElement(RecordView, { key, rec })) : /* @__PURE__ */ React19.createElement(Text16, { dimColor: true, italic: true }, "no records")), /* @__PURE__ */ React19.createElement(Box16, { marginTop: 1, paddingX: 1, borderStyle: "single", borderColor: "gray" }, /* @__PURE__ */ React19.createElement(Text16, { dimColor: true }, /* @__PURE__ */ React19.createElement(Text16, { bold: true }, "j"), "/", /* @__PURE__ */ React19.createElement(Text16, { bold: true }, "\u2193"), "/", /* @__PURE__ */ React19.createElement(Text16, { bold: true }, "space"), " next \xB7 ", /* @__PURE__ */ React19.createElement(Text16, { bold: true }, "k"), "/", /* @__PURE__ */ React19.createElement(Text16, { bold: true }, "\u2191"), " prev \xB7 ", /* @__PURE__ */ React19.createElement(Text16, { bold: true }, "g"), " first \xB7 ", /* @__PURE__ */ React19.createElement(Text16, { bold: true }, "G"), " last \xB7", " ", /* @__PURE__ */ React19.createElement(Text16, { bold: true }, "q"), " quit")));
9828
+ ), /* @__PURE__ */ React20.createElement(Box17, { flexDirection: "column", marginTop: 1, paddingX: 1 }, /* @__PURE__ */ React20.createElement(Box17, { justifyContent: "space-between" }, /* @__PURE__ */ React20.createElement(Text17, { color: "cyan", bold: true }, progressLabel), meta ? /* @__PURE__ */ React20.createElement(Text17, { dimColor: true }, meta.source, meta.task ? ` \xB7 ${meta.task}` : "", meta.mode ? ` \xB7 ${meta.mode}` : "") : null), currentPage ? /* @__PURE__ */ React20.createElement(Static3, { items: currentPage.records.map((rec, i) => ({ key: `${idx}-${i}`, rec })) }, ({ key, rec }) => /* @__PURE__ */ React20.createElement(RecordView, { key, rec })) : /* @__PURE__ */ React20.createElement(Text17, { dimColor: true, italic: true }, "no records")), /* @__PURE__ */ React20.createElement(Box17, { marginTop: 1, paddingX: 1, borderStyle: "single", borderColor: "gray" }, /* @__PURE__ */ React20.createElement(Text17, { dimColor: true }, /* @__PURE__ */ React20.createElement(Text17, { bold: true }, "j"), "/", /* @__PURE__ */ React20.createElement(Text17, { bold: true }, "\u2193"), "/", /* @__PURE__ */ React20.createElement(Text17, { bold: true }, "space"), " next \xB7 ", /* @__PURE__ */ React20.createElement(Text17, { bold: true }, "k"), "/", /* @__PURE__ */ React20.createElement(Text17, { bold: true }, "\u2191"), " prev \xB7 ", /* @__PURE__ */ React20.createElement(Text17, { bold: true }, "g"), " first \xB7 ", /* @__PURE__ */ React20.createElement(Text17, { bold: true }, "G"), " last \xB7", " ", /* @__PURE__ */ React20.createElement(Text17, { bold: true }, "q"), " quit")));
9597
9829
  }
9598
9830
 
9599
9831
  // src/cli/commands/replay.ts
@@ -9605,7 +9837,7 @@ async function replayCommand(opts) {
9605
9837
  }
9606
9838
  const { parsed } = replayFromFile(opts.path);
9607
9839
  const pages = groupRecordsByTurn(parsed.records);
9608
- const { waitUntilExit } = render3(React20.createElement(ReplayApp, { meta: parsed.meta, pages }), {
9840
+ const { waitUntilExit } = render3(React21.createElement(ReplayApp, { meta: parsed.meta, pages }), {
9609
9841
  exitOnCtrlC: true,
9610
9842
  patchConsole: false
9611
9843
  });
@@ -9910,12 +10142,12 @@ function truncate4(s, max) {
9910
10142
 
9911
10143
  // src/cli/commands/setup.tsx
9912
10144
  import { render as render4 } from "ink";
9913
- import React22 from "react";
10145
+ import React23 from "react";
9914
10146
 
9915
10147
  // src/cli/ui/Wizard.tsx
9916
- import { Box as Box17, Text as Text17, useApp as useApp5, useInput as useInput7 } from "ink";
10148
+ import { Box as Box18, Text as Text18, useApp as useApp5, useInput as useInput7 } from "ink";
9917
10149
  import TextInput2 from "ink-text-input";
9918
- import React21, { useState as useState10 } from "react";
10150
+ import React22, { useState as useState10 } from "react";
9919
10151
 
9920
10152
  // src/cli/ui/presets.ts
9921
10153
  var PRESETS = {
@@ -9954,7 +10186,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
9954
10186
  if (key.escape && step !== "saved" && onCancel) onCancel();
9955
10187
  });
9956
10188
  if (step === "apiKey") {
9957
- return /* @__PURE__ */ React21.createElement(
10189
+ return /* @__PURE__ */ React22.createElement(
9958
10190
  ApiKeyStep,
9959
10191
  {
9960
10192
  onSubmit: (key) => {
@@ -9968,7 +10200,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
9968
10200
  );
9969
10201
  }
9970
10202
  if (step === "preset") {
9971
- return /* @__PURE__ */ React21.createElement(StepFrame, { title: "Pick a preset", step: 1, total: 3 }, /* @__PURE__ */ React21.createElement(
10203
+ return /* @__PURE__ */ React22.createElement(StepFrame, { title: "Pick a preset", step: 1, total: 3 }, /* @__PURE__ */ React22.createElement(
9972
10204
  SingleSelect,
9973
10205
  {
9974
10206
  items: presetItems(),
@@ -9978,10 +10210,10 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
9978
10210
  setStep("mcp");
9979
10211
  }
9980
10212
  }
9981
- ), /* @__PURE__ */ React21.createElement(Box17, { marginTop: 1 }, /* @__PURE__ */ React21.createElement(Text17, { dimColor: true }, "\u2191/\u2193 move \xB7 enter confirm \xB7 esc cancel")));
10213
+ ), /* @__PURE__ */ React22.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React22.createElement(Text18, { dimColor: true }, "\u2191/\u2193 move \xB7 enter confirm \xB7 esc cancel")));
9982
10214
  }
9983
10215
  if (step === "mcp") {
9984
- return /* @__PURE__ */ React21.createElement(StepFrame, { title: "Which MCP servers should Reasonix wire up for you?", step: 2, total: 3 }, /* @__PURE__ */ React21.createElement(
10216
+ return /* @__PURE__ */ React22.createElement(StepFrame, { title: "Which MCP servers should Reasonix wire up for you?", step: 2, total: 3 }, /* @__PURE__ */ React22.createElement(
9985
10217
  MultiSelect,
9986
10218
  {
9987
10219
  items: mcpItems(),
@@ -10006,7 +10238,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
10006
10238
  }
10007
10239
  const currentName = pending[0];
10008
10240
  const entry = CATALOG_BY_NAME.get(currentName);
10009
- return /* @__PURE__ */ React21.createElement(
10241
+ return /* @__PURE__ */ React22.createElement(
10010
10242
  McpArgsStep,
10011
10243
  {
10012
10244
  entry,
@@ -10024,7 +10256,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
10024
10256
  }
10025
10257
  if (step === "review") {
10026
10258
  const specs = data.selectedCatalog.map((name) => buildSpec(name, data.catalogArgs));
10027
- return /* @__PURE__ */ React21.createElement(StepFrame, { title: "Ready to save", step: 3, total: 3 }, /* @__PURE__ */ React21.createElement(Box17, { flexDirection: "column" }, /* @__PURE__ */ React21.createElement(SummaryLine, { label: "API key", value: redactKey(data.apiKey) }), /* @__PURE__ */ React21.createElement(SummaryLine, { label: "Preset", value: data.preset }), /* @__PURE__ */ React21.createElement(
10259
+ return /* @__PURE__ */ React22.createElement(StepFrame, { title: "Ready to save", step: 3, total: 3 }, /* @__PURE__ */ React22.createElement(Box18, { flexDirection: "column" }, /* @__PURE__ */ React22.createElement(SummaryLine, { label: "API key", value: redactKey(data.apiKey) }), /* @__PURE__ */ React22.createElement(SummaryLine, { label: "Preset", value: data.preset }), /* @__PURE__ */ React22.createElement(
10028
10260
  SummaryLine,
10029
10261
  {
10030
10262
  label: "MCP",
@@ -10032,8 +10264,8 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
10032
10264
  }
10033
10265
  ), specs.map((spec, i) => (
10034
10266
  // biome-ignore lint/suspicious/noArrayIndexKey: review-only render, order fixed
10035
- /* @__PURE__ */ React21.createElement(Box17, { key: i, paddingLeft: 14 }, /* @__PURE__ */ React21.createElement(Text17, { dimColor: true }, "\xB7 ", spec))
10036
- )), /* @__PURE__ */ React21.createElement(Box17, { marginTop: 1 }, /* @__PURE__ */ React21.createElement(Text17, null, "Saves to ", defaultConfigPath())), error ? /* @__PURE__ */ React21.createElement(Box17, { marginTop: 1 }, /* @__PURE__ */ React21.createElement(Text17, { color: "red" }, error)) : null, /* @__PURE__ */ React21.createElement(Box17, { marginTop: 1 }, /* @__PURE__ */ React21.createElement(Text17, { dimColor: true }, "enter save \xB7 esc cancel"))), /* @__PURE__ */ React21.createElement(
10267
+ /* @__PURE__ */ React22.createElement(Box18, { key: i, paddingLeft: 14 }, /* @__PURE__ */ React22.createElement(Text18, { dimColor: true }, "\xB7 ", spec))
10268
+ )), /* @__PURE__ */ React22.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React22.createElement(Text18, null, "Saves to ", defaultConfigPath())), error ? /* @__PURE__ */ React22.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React22.createElement(Text18, { color: "red" }, error)) : null, /* @__PURE__ */ React22.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React22.createElement(Text18, { dimColor: true }, "enter save \xB7 esc cancel"))), /* @__PURE__ */ React22.createElement(
10037
10269
  ReviewConfirm,
10038
10270
  {
10039
10271
  onConfirm: () => {
@@ -10059,7 +10291,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
10059
10291
  }
10060
10292
  ));
10061
10293
  }
10062
- return /* @__PURE__ */ React21.createElement(Box17, { flexDirection: "column", borderStyle: "round", borderColor: "green", paddingX: 1 }, /* @__PURE__ */ React21.createElement(Text17, { bold: true, color: "green" }, "\u25B8 Saved."), /* @__PURE__ */ React21.createElement(Box17, { marginTop: 1 }, /* @__PURE__ */ React21.createElement(Text17, null, "Run `reasonix` any time to start chatting \u2014 your settings are remembered.")), /* @__PURE__ */ React21.createElement(Box17, { marginTop: 1 }, /* @__PURE__ */ React21.createElement(Text17, { dimColor: true }, "Press enter to exit.")), /* @__PURE__ */ React21.createElement(ExitOnEnter, { onExit: exit }));
10294
+ return /* @__PURE__ */ React22.createElement(Box18, { flexDirection: "column", borderStyle: "round", borderColor: "green", paddingX: 1 }, /* @__PURE__ */ React22.createElement(Text18, { bold: true, color: "green" }, "\u25B8 Saved."), /* @__PURE__ */ React22.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React22.createElement(Text18, null, "Run `reasonix` any time to start chatting \u2014 your settings are remembered.")), /* @__PURE__ */ React22.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React22.createElement(Text18, { dimColor: true }, "Press enter to exit.")), /* @__PURE__ */ React22.createElement(ExitOnEnter, { onExit: exit }));
10063
10295
  }
10064
10296
  function ApiKeyStep({
10065
10297
  onSubmit,
@@ -10067,7 +10299,7 @@ function ApiKeyStep({
10067
10299
  onError
10068
10300
  }) {
10069
10301
  const [value, setValue] = useState10("");
10070
- return /* @__PURE__ */ React21.createElement(Box17, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React21.createElement(Text17, { bold: true, color: "cyan" }, "Welcome to Reasonix."), /* @__PURE__ */ React21.createElement(Box17, { marginTop: 1 }, /* @__PURE__ */ React21.createElement(Text17, null, "Paste your DeepSeek API key to get started.")), /* @__PURE__ */ React21.createElement(Text17, { dimColor: true }, "Get one (free credit on signup): https://platform.deepseek.com/api_keys"), /* @__PURE__ */ React21.createElement(Text17, { dimColor: true }, "Saved locally to ", defaultConfigPath()), /* @__PURE__ */ React21.createElement(Box17, { marginTop: 1 }, /* @__PURE__ */ React21.createElement(Text17, { bold: true, color: "cyan" }, "key \u203A "), /* @__PURE__ */ React21.createElement(
10302
+ return /* @__PURE__ */ React22.createElement(Box18, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React22.createElement(Text18, { bold: true, color: "cyan" }, "Welcome to Reasonix."), /* @__PURE__ */ React22.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React22.createElement(Text18, null, "Paste your DeepSeek API key to get started.")), /* @__PURE__ */ React22.createElement(Text18, { dimColor: true }, "Get one (free credit on signup): https://platform.deepseek.com/api_keys"), /* @__PURE__ */ React22.createElement(Text18, { dimColor: true }, "Saved locally to ", defaultConfigPath()), /* @__PURE__ */ React22.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React22.createElement(Text18, { bold: true, color: "cyan" }, "key \u203A "), /* @__PURE__ */ React22.createElement(
10071
10303
  TextInput2,
10072
10304
  {
10073
10305
  value,
@@ -10084,7 +10316,7 @@ function ApiKeyStep({
10084
10316
  mask: "\u2022",
10085
10317
  placeholder: "sk-..."
10086
10318
  }
10087
- )), error ? /* @__PURE__ */ React21.createElement(Box17, { marginTop: 1 }, /* @__PURE__ */ React21.createElement(Text17, { color: "red" }, error)) : value ? /* @__PURE__ */ React21.createElement(Box17, { marginTop: 1 }, /* @__PURE__ */ React21.createElement(Text17, { dimColor: true }, "preview: ", redactKey(value))) : null);
10319
+ )), error ? /* @__PURE__ */ React22.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React22.createElement(Text18, { color: "red" }, error)) : value ? /* @__PURE__ */ React22.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React22.createElement(Text18, { dimColor: true }, "preview: ", redactKey(value))) : null);
10088
10320
  }
10089
10321
  function McpArgsStep({
10090
10322
  entry,
@@ -10093,7 +10325,7 @@ function McpArgsStep({
10093
10325
  onError
10094
10326
  }) {
10095
10327
  const [value, setValue] = useState10("");
10096
- return /* @__PURE__ */ React21.createElement(StepFrame, { title: `Configure ${entry.name}`, step: 2, total: 3 }, /* @__PURE__ */ React21.createElement(Box17, { flexDirection: "column" }, /* @__PURE__ */ React21.createElement(Text17, null, entry.summary), entry.note ? /* @__PURE__ */ React21.createElement(Box17, { marginTop: 1 }, /* @__PURE__ */ React21.createElement(Text17, { dimColor: true }, entry.note)) : null, /* @__PURE__ */ React21.createElement(Box17, { marginTop: 1 }, /* @__PURE__ */ React21.createElement(Text17, null, "Required parameter: "), /* @__PURE__ */ React21.createElement(Text17, { bold: true }, entry.userArgs)), /* @__PURE__ */ React21.createElement(Box17, { marginTop: 1 }, /* @__PURE__ */ React21.createElement(Text17, { bold: true, color: "cyan" }, entry.userArgs, " \u203A "), /* @__PURE__ */ React21.createElement(
10328
+ return /* @__PURE__ */ React22.createElement(StepFrame, { title: `Configure ${entry.name}`, step: 2, total: 3 }, /* @__PURE__ */ React22.createElement(Box18, { flexDirection: "column" }, /* @__PURE__ */ React22.createElement(Text18, null, entry.summary), entry.note ? /* @__PURE__ */ React22.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React22.createElement(Text18, { dimColor: true }, entry.note)) : null, /* @__PURE__ */ React22.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React22.createElement(Text18, null, "Required parameter: "), /* @__PURE__ */ React22.createElement(Text18, { bold: true }, entry.userArgs)), /* @__PURE__ */ React22.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React22.createElement(Text18, { bold: true, color: "cyan" }, entry.userArgs, " \u203A "), /* @__PURE__ */ React22.createElement(
10097
10329
  TextInput2,
10098
10330
  {
10099
10331
  value,
@@ -10109,7 +10341,7 @@ function McpArgsStep({
10109
10341
  },
10110
10342
  placeholder: placeholderFor(entry)
10111
10343
  }
10112
- )), error ? /* @__PURE__ */ React21.createElement(Box17, { marginTop: 1 }, /* @__PURE__ */ React21.createElement(Text17, { color: "red" }, error)) : null));
10344
+ )), error ? /* @__PURE__ */ React22.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React22.createElement(Text18, { color: "red" }, error)) : null));
10113
10345
  }
10114
10346
  function ReviewConfirm({ onConfirm }) {
10115
10347
  useInput7((_i, key) => {
@@ -10129,10 +10361,10 @@ function StepFrame({
10129
10361
  total,
10130
10362
  children
10131
10363
  }) {
10132
- return /* @__PURE__ */ React21.createElement(Box17, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React21.createElement(Box17, null, /* @__PURE__ */ React21.createElement(Text17, { dimColor: true }, "Step ", step, "/", total, " \xB7", " "), /* @__PURE__ */ React21.createElement(Text17, { bold: true, color: "cyan" }, title)), /* @__PURE__ */ React21.createElement(Box17, { marginTop: 1, flexDirection: "column" }, children));
10364
+ return /* @__PURE__ */ React22.createElement(Box18, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React22.createElement(Box18, null, /* @__PURE__ */ React22.createElement(Text18, { dimColor: true }, "Step ", step, "/", total, " \xB7", " "), /* @__PURE__ */ React22.createElement(Text18, { bold: true, color: "cyan" }, title)), /* @__PURE__ */ React22.createElement(Box18, { marginTop: 1, flexDirection: "column" }, children));
10133
10365
  }
10134
10366
  function SummaryLine({ label, value }) {
10135
- return /* @__PURE__ */ React21.createElement(Box17, null, /* @__PURE__ */ React21.createElement(Text17, null, label.padEnd(12)), /* @__PURE__ */ React21.createElement(Text17, { bold: true }, value));
10367
+ return /* @__PURE__ */ React22.createElement(Box18, null, /* @__PURE__ */ React22.createElement(Text18, null, label.padEnd(12)), /* @__PURE__ */ React22.createElement(Text18, { bold: true }, value));
10136
10368
  }
10137
10369
  function presetItems() {
10138
10370
  return ["fast", "smart", "max"].map((name) => ({
@@ -10188,7 +10420,7 @@ async function setupCommand(_opts = {}) {
10188
10420
  const existingKey = loadApiKey();
10189
10421
  const existing = readConfig();
10190
10422
  const { waitUntilExit, unmount } = render4(
10191
- /* @__PURE__ */ React22.createElement(
10423
+ /* @__PURE__ */ React23.createElement(
10192
10424
  Wizard,
10193
10425
  {
10194
10426
  existingApiKey: existingKey,