reasonix 0.5.4 → 0.5.7

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
@@ -126,8 +126,8 @@ function computeWait(attempt, initial, cap, retryAfter) {
126
126
  }
127
127
  function sleep(ms, signal) {
128
128
  if (ms <= 0) return Promise.resolve();
129
- return new Promise((resolve6, reject) => {
130
- const timer = setTimeout(resolve6, ms);
129
+ return new Promise((resolve7, reject) => {
130
+ const timer = setTimeout(resolve7, ms);
131
131
  if (signal) {
132
132
  const onAbort = () => {
133
133
  clearTimeout(timer);
@@ -599,7 +599,7 @@ function matchesTool(hook, toolName) {
599
599
  }
600
600
  }
601
601
  function defaultSpawner(input) {
602
- return new Promise((resolve6) => {
602
+ return new Promise((resolve7) => {
603
603
  const child = spawn(input.command, {
604
604
  cwd: input.cwd,
605
605
  shell: true,
@@ -626,7 +626,7 @@ function defaultSpawner(input) {
626
626
  });
627
627
  child.once("error", (err) => {
628
628
  clearTimeout(timer);
629
- resolve6({
629
+ resolve7({
630
630
  exitCode: null,
631
631
  stdout: stdout2,
632
632
  stderr,
@@ -636,7 +636,7 @@ function defaultSpawner(input) {
636
636
  });
637
637
  child.once("close", (code) => {
638
638
  clearTimeout(timer);
639
- resolve6({
639
+ resolve7({
640
640
  exitCode: code,
641
641
  stdout: stdout2.trim(),
642
642
  stderr: stderr.trim(),
@@ -697,7 +697,7 @@ async function runHooks(opts) {
697
697
  }
698
698
 
699
699
  // src/tokenizer.ts
700
- import { readFileSync as readFileSync3 } from "fs";
700
+ import { existsSync as existsSync2, readFileSync as readFileSync3 } from "fs";
701
701
  import { createRequire } from "module";
702
702
  import { dirname as dirname2, join as join3 } from "path";
703
703
  import { fileURLToPath } from "url";
@@ -725,17 +725,24 @@ function buildByteToChar() {
725
725
  var cached = null;
726
726
  function resolveDataPath() {
727
727
  if (process.env.REASONIX_TOKENIZER_PATH) return process.env.REASONIX_TOKENIZER_PATH;
728
+ const candidates = [];
728
729
  try {
729
730
  const here = dirname2(fileURLToPath(import.meta.url));
730
- return join3(here, "..", "data", "deepseek-tokenizer.json.gz");
731
+ candidates.push(join3(here, "..", "data", "deepseek-tokenizer.json.gz"));
732
+ candidates.push(join3(here, "..", "..", "data", "deepseek-tokenizer.json.gz"));
731
733
  } catch {
734
+ }
735
+ try {
732
736
  const req = createRequire(import.meta.url);
733
- return join3(
734
- dirname2(req.resolve("reasonix/package.json")),
735
- "data",
736
- "deepseek-tokenizer.json.gz"
737
+ candidates.push(
738
+ join3(dirname2(req.resolve("reasonix/package.json")), "data", "deepseek-tokenizer.json.gz")
737
739
  );
740
+ } catch {
741
+ }
742
+ for (const p of candidates) {
743
+ if (existsSync2(p)) return p;
738
744
  }
745
+ return candidates[0] ?? join3(process.cwd(), "data", "deepseek-tokenizer.json.gz");
739
746
  }
740
747
  function loadTokenizer() {
741
748
  if (cached) return cached;
@@ -1565,7 +1572,7 @@ function signature2(call) {
1565
1572
  import {
1566
1573
  appendFileSync,
1567
1574
  chmodSync as chmodSync2,
1568
- existsSync as existsSync2,
1575
+ existsSync as existsSync3,
1569
1576
  mkdirSync as mkdirSync2,
1570
1577
  readFileSync as readFileSync4,
1571
1578
  readdirSync,
@@ -1587,7 +1594,7 @@ function sanitizeName(name) {
1587
1594
  }
1588
1595
  function loadSessionMessages(name) {
1589
1596
  const path = sessionPath(name);
1590
- if (!existsSync2(path)) return [];
1597
+ if (!existsSync3(path)) return [];
1591
1598
  try {
1592
1599
  const raw = readFileSync4(path, "utf8");
1593
1600
  const out = [];
@@ -1617,7 +1624,7 @@ function appendSessionMessage(name, message) {
1617
1624
  }
1618
1625
  function listSessions() {
1619
1626
  const dir = sessionsDir();
1620
- if (!existsSync2(dir)) return [];
1627
+ if (!existsSync3(dir)) return [];
1621
1628
  try {
1622
1629
  const files = readdirSync(dir).filter((f) => f.endsWith(".jsonl"));
1623
1630
  return files.map((file) => {
@@ -1813,9 +1820,9 @@ var CacheFirstLoop = class {
1813
1820
  this.sessionName = opts.session ?? null;
1814
1821
  if (this.sessionName) {
1815
1822
  const prior = loadSessionMessages(this.sessionName);
1816
- const { messages, healedCount, healedFrom } = healLoadedMessages(
1823
+ const { messages, healedCount, tokensSaved } = healLoadedMessagesByTokens(
1817
1824
  prior,
1818
- DEFAULT_MAX_RESULT_CHARS
1825
+ DEFAULT_MAX_RESULT_TOKENS
1819
1826
  );
1820
1827
  for (const msg of messages) this.log.append(msg);
1821
1828
  this.resumedMessageCount = messages.length;
@@ -1825,7 +1832,7 @@ var CacheFirstLoop = class {
1825
1832
  } catch {
1826
1833
  }
1827
1834
  process.stderr.write(
1828
- `\u25B8 session "${this.sessionName}": healed ${healedCount} entr${healedCount === 1 ? "y" : "ies"}${healedFrom > 0 ? ` (was ${healedFrom.toLocaleString()} chars oversized)` : " (dropped dangling tool_calls tail)"}. Rewrote session file.
1835
+ `\u25B8 session "${this.sessionName}": healed ${healedCount} entr${healedCount === 1 ? "y" : "ies"}${tokensSaved > 0 ? ` (shrunk ${tokensSaved.toLocaleString()} tokens of oversized tool output)` : " (dropped dangling tool_calls tail)"}. Rewrote session file.
1829
1836
  `
1830
1837
  );
1831
1838
  }
@@ -2094,8 +2101,8 @@ var CacheFirstLoop = class {
2094
2101
  }
2095
2102
  );
2096
2103
  for (let k = 0; k < budget; k++) {
2097
- const sample = queue.shift() ?? await new Promise((resolve6) => {
2098
- waiter = resolve6;
2104
+ const sample = queue.shift() ?? await new Promise((resolve7) => {
2105
+ waiter = resolve7;
2099
2106
  });
2100
2107
  yield {
2101
2108
  turn: this._turn,
@@ -2494,15 +2501,12 @@ function shrinkOversizedToolResultsByTokens(messages, maxTokens) {
2494
2501
  });
2495
2502
  return { messages: out, healedCount, tokensSaved, charsSaved };
2496
2503
  }
2497
- function healLoadedMessages(messages, maxChars) {
2498
- const shrunk = shrinkOversizedToolResults(messages, maxChars);
2499
- let healedCount = shrunk.healedCount;
2504
+ function fixToolCallPairing(messages) {
2500
2505
  const out = [];
2501
- const openCallIds = /* @__PURE__ */ new Set();
2502
2506
  let droppedAssistantCalls = 0;
2503
2507
  let droppedStrayTools = 0;
2504
- for (let i = 0; i < shrunk.messages.length; i++) {
2505
- const msg = shrunk.messages[i];
2508
+ for (let i = 0; i < messages.length; i++) {
2509
+ const msg = messages[i];
2506
2510
  if (msg.role === "assistant" && Array.isArray(msg.tool_calls) && msg.tool_calls.length > 0) {
2507
2511
  const needed = /* @__PURE__ */ new Set();
2508
2512
  for (const call of msg.tool_calls) {
@@ -2510,8 +2514,8 @@ function healLoadedMessages(messages, maxChars) {
2510
2514
  }
2511
2515
  const candidates = [];
2512
2516
  let j = i + 1;
2513
- while (j < shrunk.messages.length && needed.size > 0) {
2514
- const nxt = shrunk.messages[j];
2517
+ while (j < messages.length && needed.size > 0) {
2518
+ const nxt = messages[j];
2515
2519
  if (nxt.role !== "tool") break;
2516
2520
  const id = nxt.tool_call_id ?? "";
2517
2521
  if (!needed.has(id)) break;
@@ -2536,8 +2540,24 @@ function healLoadedMessages(messages, maxChars) {
2536
2540
  }
2537
2541
  out.push(msg);
2538
2542
  }
2539
- healedCount += droppedAssistantCalls + droppedStrayTools;
2540
- return { messages: out, healedCount, healedFrom: shrunk.healedFrom };
2543
+ return { messages: out, droppedAssistantCalls, droppedStrayTools };
2544
+ }
2545
+ function healLoadedMessages(messages, maxChars) {
2546
+ const shrunk = shrinkOversizedToolResults(messages, maxChars);
2547
+ const paired = fixToolCallPairing(shrunk.messages);
2548
+ const healedCount = shrunk.healedCount + paired.droppedAssistantCalls + paired.droppedStrayTools;
2549
+ return { messages: paired.messages, healedCount, healedFrom: shrunk.healedFrom };
2550
+ }
2551
+ function healLoadedMessagesByTokens(messages, maxTokens) {
2552
+ const shrunk = shrinkOversizedToolResultsByTokens(messages, maxTokens);
2553
+ const paired = fixToolCallPairing(shrunk.messages);
2554
+ const healedCount = shrunk.healedCount + paired.droppedAssistantCalls + paired.droppedStrayTools;
2555
+ return {
2556
+ messages: paired.messages,
2557
+ healedCount,
2558
+ tokensSaved: shrunk.tokensSaved,
2559
+ charsSaved: shrunk.charsSaved
2560
+ };
2541
2561
  }
2542
2562
  function formatLoopError(err) {
2543
2563
  const msg = err.message ?? "";
@@ -2549,6 +2569,163 @@ function formatLoopError(err) {
2549
2569
  return msg;
2550
2570
  }
2551
2571
 
2572
+ // src/at-mentions.ts
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
+ 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
+ }
2646
+ var AT_MENTION_PATTERN = /(?<=^|\s)@([a-zA-Z0-9_./\\-]+)/g;
2647
+ function expandAtMentions(text, rootDir, opts = {}) {
2648
+ const maxBytes = opts.maxBytes ?? DEFAULT_AT_MENTION_MAX_BYTES;
2649
+ const fs2 = opts.fs ?? defaultFs;
2650
+ const root = resolve(rootDir);
2651
+ const seen = /* @__PURE__ */ new Map();
2652
+ const expansions = [];
2653
+ for (const match of text.matchAll(AT_MENTION_PATTERN)) {
2654
+ const rawPath = match[1] ?? "";
2655
+ const cleaned = rawPath.replace(/\.+$/, "");
2656
+ if (!cleaned) continue;
2657
+ const token = `@${cleaned}`;
2658
+ if (seen.has(token)) continue;
2659
+ const expansion = resolveMention(cleaned, root, maxBytes, fs2);
2660
+ seen.set(token, expansion);
2661
+ expansions.push(expansion);
2662
+ }
2663
+ if (expansions.length === 0) return { text, expansions };
2664
+ const blocks = [];
2665
+ for (const ex of expansions) {
2666
+ if (ex.ok) {
2667
+ const content = readSafe(root, ex.path, fs2);
2668
+ blocks.push(`<file path="${ex.path}">
2669
+ ${content}
2670
+ </file>`);
2671
+ } else {
2672
+ blocks.push(`<file path="${ex.path}" skipped="${ex.skip}" />`);
2673
+ }
2674
+ }
2675
+ const augmented = `${text}
2676
+
2677
+ [Referenced files]
2678
+ ${blocks.join("\n\n")}`;
2679
+ return { text: augmented, expansions };
2680
+ }
2681
+ function resolveMention(rawPath, root, maxBytes, fs2) {
2682
+ if (isAbsolute(rawPath)) {
2683
+ return { token: `@${rawPath}`, path: rawPath, ok: false, skip: "escape" };
2684
+ }
2685
+ const resolved = resolve(root, rawPath);
2686
+ const rel = relative(root, resolved);
2687
+ if (rel.startsWith("..") || isAbsolute(rel)) {
2688
+ return { token: `@${rawPath}`, path: rawPath, ok: false, skip: "escape" };
2689
+ }
2690
+ if (!fs2.exists(resolved)) {
2691
+ return { token: `@${rawPath}`, path: rawPath, ok: false, skip: "missing" };
2692
+ }
2693
+ if (!fs2.isFile(resolved)) {
2694
+ return { token: `@${rawPath}`, path: rawPath, ok: false, skip: "not-file" };
2695
+ }
2696
+ const size = fs2.size(resolved);
2697
+ if (size > maxBytes) {
2698
+ return { token: `@${rawPath}`, path: rawPath, ok: false, skip: "too-large", bytes: size };
2699
+ }
2700
+ return { token: `@${rawPath}`, path: rawPath, ok: true, bytes: size };
2701
+ }
2702
+ function readSafe(root, rawPath, fs2) {
2703
+ const resolved = resolve(root, rawPath);
2704
+ try {
2705
+ return fs2.read(resolved);
2706
+ } catch {
2707
+ return "(read failed)";
2708
+ }
2709
+ }
2710
+ var defaultFs = {
2711
+ exists: (p) => existsSync4(p),
2712
+ isFile: (p) => {
2713
+ try {
2714
+ return statSync2(p).isFile();
2715
+ } catch {
2716
+ return false;
2717
+ }
2718
+ },
2719
+ size: (p) => {
2720
+ try {
2721
+ return statSync2(p).size;
2722
+ } catch {
2723
+ return 0;
2724
+ }
2725
+ },
2726
+ read: (p) => readFileSync5(p, "utf8")
2727
+ };
2728
+
2552
2729
  // src/tools/filesystem.ts
2553
2730
  import { promises as fs } from "fs";
2554
2731
  import * as pathMod from "path";
@@ -3359,7 +3536,7 @@ function forkRegistryExcluding(parent, exclude) {
3359
3536
 
3360
3537
  // src/tools/shell.ts
3361
3538
  import { spawn as spawn2 } from "child_process";
3362
- import { existsSync as existsSync3, statSync as statSync2 } from "fs";
3539
+ import { existsSync as existsSync5, statSync as statSync3 } from "fs";
3363
3540
  import * as pathMod2 from "path";
3364
3541
  var DEFAULT_TIMEOUT_SEC = 60;
3365
3542
  var DEFAULT_MAX_OUTPUT_CHARS = 32e3;
@@ -3529,7 +3706,7 @@ async function runCommand(cmd, opts) {
3529
3706
  };
3530
3707
  const { bin, args, spawnOverrides } = prepareSpawn(argv);
3531
3708
  const effectiveSpawnOpts = { ...spawnOpts, ...spawnOverrides };
3532
- return await new Promise((resolve6, reject) => {
3709
+ return await new Promise((resolve7, reject) => {
3533
3710
  let child;
3534
3711
  try {
3535
3712
  child = spawn2(bin, args, effectiveSpawnOpts);
@@ -3562,7 +3739,7 @@ async function runCommand(cmd, opts) {
3562
3739
  const output = buf.length > maxChars ? `${buf.slice(0, maxChars)}
3563
3740
 
3564
3741
  [\u2026 truncated ${buf.length - maxChars} chars \u2026]` : buf;
3565
- resolve6({ exitCode: code, output, timedOut });
3742
+ resolve7({ exitCode: code, output, timedOut });
3566
3743
  });
3567
3744
  });
3568
3745
  }
@@ -3587,7 +3764,7 @@ function resolveExecutable(cmd, opts = {}) {
3587
3764
  }
3588
3765
  function defaultIsFile(full) {
3589
3766
  try {
3590
- return existsSync3(full) && statSync2(full).isFile();
3767
+ return existsSync5(full) && statSync3(full).isFile();
3591
3768
  } catch {
3592
3769
  return false;
3593
3770
  }
@@ -3914,12 +4091,12 @@ ${i + 1}. ${r.title}`);
3914
4091
  }
3915
4092
 
3916
4093
  // src/env.ts
3917
- import { readFileSync as readFileSync5 } from "fs";
3918
- import { resolve as resolve3 } from "path";
4094
+ import { readFileSync as readFileSync6 } from "fs";
4095
+ import { resolve as resolve4 } from "path";
3919
4096
  function loadDotenv(path = ".env") {
3920
4097
  let raw;
3921
4098
  try {
3922
- raw = readFileSync5(resolve3(process.cwd(), path), "utf8");
4099
+ raw = readFileSync6(resolve4(process.cwd(), path), "utf8");
3923
4100
  } catch {
3924
4101
  return;
3925
4102
  }
@@ -3938,7 +4115,7 @@ function loadDotenv(path = ".env") {
3938
4115
  }
3939
4116
 
3940
4117
  // src/transcript.ts
3941
- import { createWriteStream, readFileSync as readFileSync6 } from "fs";
4118
+ import { createWriteStream, readFileSync as readFileSync7 } from "fs";
3942
4119
  function recordFromLoopEvent(ev, extra) {
3943
4120
  const rec = {
3944
4121
  ts: (/* @__PURE__ */ new Date()).toISOString(),
@@ -3989,7 +4166,7 @@ function openTranscriptFile(path, meta) {
3989
4166
  return stream;
3990
4167
  }
3991
4168
  function readTranscript(path) {
3992
- const raw = readFileSync6(path, "utf8");
4169
+ const raw = readFileSync7(path, "utf8");
3993
4170
  return parseTranscript(raw);
3994
4171
  }
3995
4172
  function isPlanStateEmptyShape(s) {
@@ -4632,7 +4809,7 @@ var McpClient = class {
4632
4809
  const id = this.nextId++;
4633
4810
  const frame = { jsonrpc: "2.0", id, method, params };
4634
4811
  let abortHandler = null;
4635
- const promise = new Promise((resolve6, reject) => {
4812
+ const promise = new Promise((resolve7, reject) => {
4636
4813
  const timeout = setTimeout(() => {
4637
4814
  this.pending.delete(id);
4638
4815
  if (abortHandler && signal) signal.removeEventListener("abort", abortHandler);
@@ -4641,7 +4818,7 @@ var McpClient = class {
4641
4818
  );
4642
4819
  }, this.requestTimeoutMs);
4643
4820
  this.pending.set(id, {
4644
- resolve: resolve6,
4821
+ resolve: resolve7,
4645
4822
  reject,
4646
4823
  timeout
4647
4824
  });
@@ -4764,12 +4941,12 @@ var StdioTransport = class {
4764
4941
  }
4765
4942
  async send(message) {
4766
4943
  if (this.closed) throw new Error("MCP transport is closed");
4767
- return new Promise((resolve6, reject) => {
4944
+ return new Promise((resolve7, reject) => {
4768
4945
  const line = `${JSON.stringify(message)}
4769
4946
  `;
4770
4947
  this.child.stdin.write(line, "utf8", (err) => {
4771
4948
  if (err) reject(err);
4772
- else resolve6();
4949
+ else resolve7();
4773
4950
  });
4774
4951
  });
4775
4952
  }
@@ -4780,8 +4957,8 @@ var StdioTransport = class {
4780
4957
  continue;
4781
4958
  }
4782
4959
  if (this.closed) return;
4783
- const next = await new Promise((resolve6) => {
4784
- this.waiters.push(resolve6);
4960
+ const next = await new Promise((resolve7) => {
4961
+ this.waiters.push(resolve7);
4785
4962
  });
4786
4963
  if (next === null) return;
4787
4964
  yield next;
@@ -4847,8 +5024,8 @@ var SseTransport = class {
4847
5024
  constructor(opts) {
4848
5025
  this.url = opts.url;
4849
5026
  this.headers = opts.headers ?? {};
4850
- this.endpointReady = new Promise((resolve6, reject) => {
4851
- this.resolveEndpoint = resolve6;
5027
+ this.endpointReady = new Promise((resolve7, reject) => {
5028
+ this.resolveEndpoint = resolve7;
4852
5029
  this.rejectEndpoint = reject;
4853
5030
  });
4854
5031
  this.endpointReady.catch(() => void 0);
@@ -4875,8 +5052,8 @@ var SseTransport = class {
4875
5052
  continue;
4876
5053
  }
4877
5054
  if (this.closed) return;
4878
- const next = await new Promise((resolve6) => {
4879
- this.waiters.push(resolve6);
5055
+ const next = await new Promise((resolve7) => {
5056
+ this.waiters.push(resolve7);
4880
5057
  });
4881
5058
  if (next === null) return;
4882
5059
  yield next;
@@ -5075,8 +5252,8 @@ async function trySection(load) {
5075
5252
  }
5076
5253
 
5077
5254
  // src/code/edit-blocks.ts
5078
- import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync7, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "fs";
5079
- import { dirname as dirname5, resolve as resolve4 } from "path";
5255
+ import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync8, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "fs";
5256
+ import { dirname as dirname5, resolve as resolve5 } from "path";
5080
5257
  var BLOCK_RE = /^(\S[^\n]*)\n<{7} SEARCH\n([\s\S]*?)\n?={7}\n([\s\S]*?)\n?>{7} REPLACE/gm;
5081
5258
  function parseEditBlocks(text) {
5082
5259
  const out = [];
@@ -5094,8 +5271,8 @@ function parseEditBlocks(text) {
5094
5271
  return out;
5095
5272
  }
5096
5273
  function applyEditBlock(block, rootDir) {
5097
- const absRoot = resolve4(rootDir);
5098
- const absTarget = resolve4(absRoot, block.path);
5274
+ const absRoot = resolve5(rootDir);
5275
+ const absTarget = resolve5(absRoot, block.path);
5099
5276
  if (absTarget !== absRoot && !absTarget.startsWith(`${absRoot}${sep()}`)) {
5100
5277
  return {
5101
5278
  path: block.path,
@@ -5104,7 +5281,7 @@ function applyEditBlock(block, rootDir) {
5104
5281
  };
5105
5282
  }
5106
5283
  const searchEmpty = block.search.length === 0;
5107
- const exists = existsSync4(absTarget);
5284
+ const exists = existsSync6(absTarget);
5108
5285
  try {
5109
5286
  if (!exists) {
5110
5287
  if (!searchEmpty) {
@@ -5118,7 +5295,7 @@ function applyEditBlock(block, rootDir) {
5118
5295
  writeFileSync3(absTarget, block.replace, "utf8");
5119
5296
  return { path: block.path, status: "created" };
5120
5297
  }
5121
- const content = readFileSync7(absTarget, "utf8");
5298
+ const content = readFileSync8(absTarget, "utf8");
5122
5299
  if (searchEmpty) {
5123
5300
  return {
5124
5301
  path: block.path,
@@ -5145,19 +5322,19 @@ function applyEditBlocks(blocks, rootDir) {
5145
5322
  return blocks.map((b) => applyEditBlock(b, rootDir));
5146
5323
  }
5147
5324
  function snapshotBeforeEdits(blocks, rootDir) {
5148
- const absRoot = resolve4(rootDir);
5325
+ const absRoot = resolve5(rootDir);
5149
5326
  const seen = /* @__PURE__ */ new Set();
5150
5327
  const snapshots = [];
5151
5328
  for (const b of blocks) {
5152
5329
  if (seen.has(b.path)) continue;
5153
5330
  seen.add(b.path);
5154
- const abs = resolve4(absRoot, b.path);
5155
- if (!existsSync4(abs)) {
5331
+ const abs = resolve5(absRoot, b.path);
5332
+ if (!existsSync6(abs)) {
5156
5333
  snapshots.push({ path: b.path, prevContent: null });
5157
5334
  continue;
5158
5335
  }
5159
5336
  try {
5160
- snapshots.push({ path: b.path, prevContent: readFileSync7(abs, "utf8") });
5337
+ snapshots.push({ path: b.path, prevContent: readFileSync8(abs, "utf8") });
5161
5338
  } catch {
5162
5339
  snapshots.push({ path: b.path, prevContent: null });
5163
5340
  }
@@ -5165,9 +5342,9 @@ function snapshotBeforeEdits(blocks, rootDir) {
5165
5342
  return snapshots;
5166
5343
  }
5167
5344
  function restoreSnapshots(snapshots, rootDir) {
5168
- const absRoot = resolve4(rootDir);
5345
+ const absRoot = resolve5(rootDir);
5169
5346
  return snapshots.map((snap) => {
5170
- const abs = resolve4(absRoot, snap.path);
5347
+ const abs = resolve5(absRoot, snap.path);
5171
5348
  if (abs !== absRoot && !abs.startsWith(`${absRoot}${sep()}`)) {
5172
5349
  return {
5173
5350
  path: snap.path,
@@ -5177,7 +5354,7 @@ function restoreSnapshots(snapshots, rootDir) {
5177
5354
  }
5178
5355
  try {
5179
5356
  if (snap.prevContent === null) {
5180
- if (existsSync4(abs)) unlinkSync2(abs);
5357
+ if (existsSync6(abs)) unlinkSync2(abs);
5181
5358
  return {
5182
5359
  path: snap.path,
5183
5360
  status: "applied",
@@ -5200,9 +5377,9 @@ function sep() {
5200
5377
  }
5201
5378
 
5202
5379
  // src/version.ts
5203
- import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync8, writeFileSync as writeFileSync4 } from "fs";
5380
+ import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as readFileSync9, writeFileSync as writeFileSync4 } from "fs";
5204
5381
  import { homedir as homedir4 } from "os";
5205
- import { dirname as dirname6, join as join6 } from "path";
5382
+ import { dirname as dirname6, join as join7 } from "path";
5206
5383
  import { fileURLToPath as fileURLToPath2 } from "url";
5207
5384
  var REGISTRY_URL = "https://registry.npmjs.org/reasonix/latest";
5208
5385
  var LATEST_CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
@@ -5211,9 +5388,9 @@ function readPackageVersion() {
5211
5388
  try {
5212
5389
  let dir = dirname6(fileURLToPath2(import.meta.url));
5213
5390
  for (let i = 0; i < 6; i++) {
5214
- const p = join6(dir, "package.json");
5215
- if (existsSync5(p)) {
5216
- const pkg = JSON.parse(readFileSync8(p, "utf8"));
5391
+ const p = join7(dir, "package.json");
5392
+ if (existsSync7(p)) {
5393
+ const pkg = JSON.parse(readFileSync9(p, "utf8"));
5217
5394
  if (pkg?.name === "reasonix" && typeof pkg.version === "string") {
5218
5395
  return pkg.version;
5219
5396
  }
@@ -5228,11 +5405,11 @@ function readPackageVersion() {
5228
5405
  }
5229
5406
  var VERSION = readPackageVersion();
5230
5407
  function cachePath(homeDirOverride) {
5231
- return join6(homeDirOverride ?? homedir4(), ".reasonix", "version-cache.json");
5408
+ return join7(homeDirOverride ?? homedir4(), ".reasonix", "version-cache.json");
5232
5409
  }
5233
5410
  function readCache(homeDirOverride) {
5234
5411
  try {
5235
- const raw = readFileSync8(cachePath(homeDirOverride), "utf8");
5412
+ const raw = readFileSync9(cachePath(homeDirOverride), "utf8");
5236
5413
  const parsed = JSON.parse(raw);
5237
5414
  if (parsed && typeof parsed.version === "string" && typeof parsed.checkedAt === "number") {
5238
5415
  return parsed;
@@ -5301,11 +5478,11 @@ function isNpxInstall() {
5301
5478
  }
5302
5479
 
5303
5480
  // src/usage.ts
5304
- import { appendFileSync as appendFileSync2, existsSync as existsSync6, mkdirSync as mkdirSync5, readFileSync as readFileSync9, statSync as statSync3 } from "fs";
5481
+ import { appendFileSync as appendFileSync2, existsSync as existsSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync10, statSync as statSync4 } from "fs";
5305
5482
  import { homedir as homedir5 } from "os";
5306
- import { dirname as dirname7, join as join7 } from "path";
5483
+ import { dirname as dirname7, join as join8 } from "path";
5307
5484
  function defaultUsageLogPath(homeDirOverride) {
5308
- return join7(homeDirOverride ?? homedir5(), ".reasonix", "usage.jsonl");
5485
+ return join8(homeDirOverride ?? homedir5(), ".reasonix", "usage.jsonl");
5309
5486
  }
5310
5487
  function appendUsage(input) {
5311
5488
  const record = {
@@ -5329,10 +5506,10 @@ function appendUsage(input) {
5329
5506
  return record;
5330
5507
  }
5331
5508
  function readUsageLog(path = defaultUsageLogPath()) {
5332
- if (!existsSync6(path)) return [];
5509
+ if (!existsSync8(path)) return [];
5333
5510
  let raw;
5334
5511
  try {
5335
- raw = readFileSync9(path, "utf8");
5512
+ raw = readFileSync10(path, "utf8");
5336
5513
  } catch {
5337
5514
  return [];
5338
5515
  }
@@ -5414,9 +5591,9 @@ function aggregateUsage(records, opts = {}) {
5414
5591
  };
5415
5592
  }
5416
5593
  function formatLogSize(path = defaultUsageLogPath()) {
5417
- if (!existsSync6(path)) return "";
5594
+ if (!existsSync8(path)) return "";
5418
5595
  try {
5419
- const s = statSync3(path);
5596
+ const s = statSync4(path);
5420
5597
  const bytes = s.size;
5421
5598
  if (bytes < 1024) return `${bytes} B`;
5422
5599
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
@@ -5427,13 +5604,13 @@ function formatLogSize(path = defaultUsageLogPath()) {
5427
5604
  }
5428
5605
 
5429
5606
  // src/cli/commands/chat.tsx
5430
- import { existsSync as existsSync8, statSync as statSync5 } from "fs";
5607
+ import { existsSync as existsSync10, statSync as statSync6 } from "fs";
5431
5608
  import { render } from "ink";
5432
- import React15, { useState as useState7 } from "react";
5609
+ import React16, { useState as useState7 } from "react";
5433
5610
 
5434
5611
  // src/cli/ui/App.tsx
5435
- import { Box as Box11, Static, Text as Text11, useApp, useInput as useInput4 } from "ink";
5436
- 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";
5437
5614
 
5438
5615
  // src/tools/skills.ts
5439
5616
  function registerSkillTools(registry, opts = {}) {
@@ -5504,13 +5681,44 @@ ${skill.body}${argsBlock}`;
5504
5681
  return registry;
5505
5682
  }
5506
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
+
5507
5715
  // src/cli/ui/EventLog.tsx
5508
- import { Box as Box3, Text as Text3, useStdout } from "ink";
5509
- import React4 from "react";
5716
+ import { Box as Box4, Text as Text4, useStdout } from "ink";
5717
+ import React5 from "react";
5510
5718
 
5511
5719
  // src/cli/ui/PlanStateBlock.tsx
5512
- import { Box, Text } from "ink";
5513
- import React from "react";
5720
+ import { Box as Box2, Text as Text2 } from "ink";
5721
+ import React2 from "react";
5514
5722
  function PlanStateBlock({ planState }) {
5515
5723
  const fields = [];
5516
5724
  if (planState.subgoals.length) fields.push(["subgoals", planState.subgoals, "cyan", false]);
@@ -5521,14 +5729,14 @@ function PlanStateBlock({ planState }) {
5521
5729
  if (planState.rejectedPaths.length)
5522
5730
  fields.push(["rejected", planState.rejectedPaths, "red", true]);
5523
5731
  if (fields.length === 0) return null;
5524
- 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 ")}`))));
5525
5733
  }
5526
5734
 
5527
5735
  // src/cli/ui/markdown.tsx
5528
- import { readFileSync as readFileSync10, statSync as statSync4 } from "fs";
5529
- import { isAbsolute as isAbsolute3, join as join8 } from "path";
5530
- import { Box as Box2, Text as Text2 } from "ink";
5531
- import React2 from "react";
5736
+ import { readFileSync as readFileSync11, statSync as statSync5 } from "fs";
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";
5532
5740
  var SUPERSCRIPT = {
5533
5741
  "0": "\u2070",
5534
5742
  "1": "\xB9",
@@ -5604,10 +5812,10 @@ function parseCitationUrl(url) {
5604
5812
  function validateCitation(url, projectRoot) {
5605
5813
  const parts = parseCitationUrl(url);
5606
5814
  if (!parts || !parts.path) return { ok: false, reason: "empty path" };
5607
- const fullPath = isAbsolute3(parts.path) ? parts.path : join8(projectRoot, parts.path);
5815
+ const fullPath = isAbsolute4(parts.path) ? parts.path : join9(projectRoot, parts.path);
5608
5816
  let stat;
5609
5817
  try {
5610
- stat = statSync4(fullPath);
5818
+ stat = statSync5(fullPath);
5611
5819
  } catch {
5612
5820
  return { ok: false, reason: "file not found" };
5613
5821
  }
@@ -5615,7 +5823,7 @@ function validateCitation(url, projectRoot) {
5615
5823
  if (parts.startLine === void 0) return { ok: true };
5616
5824
  let lineCount;
5617
5825
  try {
5618
- lineCount = readFileSync10(fullPath, "utf8").split("\n").length;
5826
+ lineCount = readFileSync11(fullPath, "utf8").split("\n").length;
5619
5827
  } catch {
5620
5828
  return { ok: false, reason: "unreadable" };
5621
5829
  }
@@ -5652,57 +5860,57 @@ function InlineMd({
5652
5860
  for (const m of text.matchAll(INLINE_RE)) {
5653
5861
  const start = m.index ?? 0;
5654
5862
  if (start > last) {
5655
- 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)));
5656
5864
  }
5657
5865
  if (m[2] !== void 0 && m[3] !== void 0) {
5658
5866
  const linkText = m[2];
5659
5867
  const url = m[3];
5660
5868
  if (isExternalUrl(url)) {
5661
5869
  parts.push(
5662
- /* @__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)
5663
5871
  );
5664
5872
  } else {
5665
5873
  const status = citations?.get(url);
5666
5874
  if (status && !status.ok) {
5667
5875
  parts.push(
5668
- /* @__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`)
5669
5877
  );
5670
5878
  } else {
5671
5879
  parts.push(
5672
- /* @__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)
5673
5881
  );
5674
5882
  }
5675
5883
  }
5676
5884
  } else if (m[4] !== void 0) {
5677
5885
  parts.push(
5678
- /* @__PURE__ */ React2.createElement(Text2, { key: `b${idx++}`, bold: true }, m[4])
5886
+ /* @__PURE__ */ React3.createElement(Text3, { key: `b${idx++}`, bold: true }, m[4])
5679
5887
  );
5680
5888
  } else if (m[5] !== void 0) {
5681
5889
  const stripped = m[5].replace(/^(\w+)\s+/, "");
5682
5890
  parts.push(
5683
- /* @__PURE__ */ React2.createElement(Text2, { key: `c${idx++}`, color: "yellow" }, stripped)
5891
+ /* @__PURE__ */ React3.createElement(Text3, { key: `c${idx++}`, color: "yellow" }, stripped)
5684
5892
  );
5685
5893
  } else if (m[6] !== void 0) {
5686
5894
  parts.push(
5687
- /* @__PURE__ */ React2.createElement(Text2, { key: `c${idx++}`, color: "yellow" }, m[6])
5895
+ /* @__PURE__ */ React3.createElement(Text3, { key: `c${idx++}`, color: "yellow" }, m[6])
5688
5896
  );
5689
5897
  } else if (m[7] !== void 0) {
5690
5898
  parts.push(
5691
- /* @__PURE__ */ React2.createElement(Text2, { key: `i${idx++}`, italic: true }, m[7])
5899
+ /* @__PURE__ */ React3.createElement(Text3, { key: `i${idx++}`, italic: true }, m[7])
5692
5900
  );
5693
5901
  }
5694
5902
  last = start + m[0].length;
5695
5903
  }
5696
5904
  if (last < text.length) {
5697
- 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)));
5698
5906
  }
5699
5907
  if (padTo !== void 0) {
5700
5908
  const seen = visibleWidth(text);
5701
5909
  if (seen < padTo) {
5702
- 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)));
5703
5911
  }
5704
5912
  }
5705
- return /* @__PURE__ */ React2.createElement(Text2, null, parts);
5913
+ return /* @__PURE__ */ React3.createElement(Text3, null, parts);
5706
5914
  }
5707
5915
  function stripInlineMarkup(s) {
5708
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");
@@ -5898,19 +6106,19 @@ function parseBlocks(raw) {
5898
6106
  function BlockView({ block, citations }) {
5899
6107
  switch (block.kind) {
5900
6108
  case "heading":
5901
- 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 }));
5902
6110
  case "paragraph":
5903
- return /* @__PURE__ */ React2.createElement(InlineMd, { text: block.text, citations });
6111
+ return /* @__PURE__ */ React3.createElement(InlineMd, { text: block.text, citations });
5904
6112
  case "bullet":
5905
- 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 }))));
5906
6114
  case "code":
5907
- 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));
5908
6116
  case "edit-block":
5909
- return /* @__PURE__ */ React2.createElement(EditBlockRow, { block });
6117
+ return /* @__PURE__ */ React3.createElement(EditBlockRow, { block });
5910
6118
  case "table":
5911
- return /* @__PURE__ */ React2.createElement(TableBlockRow, { block, citations });
6119
+ return /* @__PURE__ */ React3.createElement(TableBlockRow, { block, citations });
5912
6120
  case "hr":
5913
- 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");
5914
6122
  }
5915
6123
  }
5916
6124
  function splitTableRow(line) {
@@ -5928,14 +6136,14 @@ function TableBlockRow({ block, citations }) {
5928
6136
  widths.push(Math.min(40, Math.max(3, ...cellLengths)));
5929
6137
  }
5930
6138
  const separator = widths.map((w) => "\u2500".repeat(w)).join("\u2500\u253C\u2500");
5931
- 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) => (
5932
6140
  // biome-ignore lint/suspicious/noArrayIndexKey: table columns never reorder — derived from a static header array
5933
- /* @__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 " : "")
5934
- ))), /* @__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) => (
5935
6143
  // biome-ignore lint/suspicious/noArrayIndexKey: table rows render in source order and don't reorder
5936
- /* @__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) => (
5937
6145
  // biome-ignore lint/suspicious/noArrayIndexKey: same — column axis is fixed by the table shape
5938
- /* @__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 " : "")
5939
6147
  )))
5940
6148
  )));
5941
6149
  }
@@ -5955,28 +6163,28 @@ function EditBlockRow({ block }) {
5955
6163
  const isNewFile = block.search.length === 0;
5956
6164
  const searchLines = block.search.split("\n");
5957
6165
  const replaceLines = block.replace.split("\n");
5958
- 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}`))));
5959
6167
  }
5960
6168
  function Markdown({ text, projectRoot }) {
5961
6169
  const cleaned = stripMath(text);
5962
6170
  const root = projectRoot ?? process.cwd();
5963
- const citations = React2.useMemo(() => collectCitations(cleaned, root), [cleaned, root]);
5964
- 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]);
5965
6173
  const broken = [];
5966
6174
  for (const [url, status] of citations) {
5967
6175
  if (!status.ok) broken.push({ url, reason: status.reason });
5968
6176
  }
5969
- 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);
5970
6178
  }
5971
6179
  function BrokenCitationsBlock({ items }) {
5972
- 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) => (
5973
6181
  // biome-ignore lint/suspicious/noArrayIndexKey: list is derived from a Map iteration order, stable per render
5974
- /* @__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}`)
5975
6183
  )));
5976
6184
  }
5977
6185
 
5978
6186
  // src/cli/ui/ticker.tsx
5979
- import React3, { createContext, useContext, useEffect, useState } from "react";
6187
+ import React4, { createContext, useContext, useEffect, useState } from "react";
5980
6188
  var TICK_MS = 120;
5981
6189
  var TickContext = createContext(0);
5982
6190
  function TickerProvider({ children, disabled }) {
@@ -5986,7 +6194,7 @@ function TickerProvider({ children, disabled }) {
5986
6194
  const id = setInterval(() => setTick((t) => t + 1), TICK_MS);
5987
6195
  return () => clearInterval(id);
5988
6196
  }, [disabled]);
5989
- return /* @__PURE__ */ React3.createElement(TickContext.Provider, { value: tick }, children);
6197
+ return /* @__PURE__ */ React4.createElement(TickContext.Provider, { value: tick }, children);
5990
6198
  }
5991
6199
  function useTick() {
5992
6200
  return useContext(TickContext);
@@ -6012,18 +6220,18 @@ function RoleGlyph({
6012
6220
  glyph,
6013
6221
  color
6014
6222
  }) {
6015
- return /* @__PURE__ */ React4.createElement(Text3, { color, bold: true }, glyph);
6223
+ return /* @__PURE__ */ React5.createElement(Text4, { color, bold: true }, glyph);
6016
6224
  }
6017
- var EventRow = React4.memo(function EventRow2({
6225
+ var EventRow = React5.memo(function EventRow2({
6018
6226
  event,
6019
6227
  projectRoot
6020
6228
  }) {
6021
6229
  if (event.role === "user") {
6022
- 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));
6023
6231
  }
6024
6232
  if (event.role === "assistant") {
6025
- if (event.streaming) return /* @__PURE__ */ React4.createElement(StreamingAssistant, { event });
6026
- 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));
6027
6235
  }
6028
6236
  if (event.role === "tool") {
6029
6237
  const isError = event.text.startsWith("ERROR:");
@@ -6031,31 +6239,31 @@ var EventRow = React4.memo(function EventRow2({
6031
6239
  const glyph = isError ? ROLE_GLYPH.toolErr : ROLE_GLYPH.toolOk;
6032
6240
  const marker = isError ? "\u2717" : "\u2192";
6033
6241
  const isEditFile = (event.toolName === "edit_file" || event.toolName?.endsWith("_edit_file")) && !isError;
6034
- 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))));
6035
6243
  }
6036
6244
  if (event.role === "error") {
6037
- 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));
6038
6246
  }
6039
6247
  if (event.role === "info") {
6040
- 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));
6041
6249
  }
6042
6250
  if (event.role === "warning") {
6043
- 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));
6044
6252
  }
6045
- 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));
6046
6254
  });
6047
6255
  function EditFileDiff({ text }) {
6048
6256
  const lines = text.split(/\r?\n/);
6049
6257
  const [statusHeader, hunkHeader, ...body] = lines;
6050
- 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) => {
6051
6259
  const key = `${i}-${line.slice(0, 32)}`;
6052
6260
  if (line.startsWith("- ")) {
6053
- return /* @__PURE__ */ React4.createElement(Text3, { key, color: "red" }, line);
6261
+ return /* @__PURE__ */ React5.createElement(Text4, { key, color: "red" }, line);
6054
6262
  }
6055
6263
  if (line.startsWith("+ ")) {
6056
- return /* @__PURE__ */ React4.createElement(Text3, { key, color: "green" }, line);
6264
+ return /* @__PURE__ */ React5.createElement(Text4, { key, color: "green" }, line);
6057
6265
  }
6058
- return /* @__PURE__ */ React4.createElement(Text3, { key, dimColor: true }, line);
6266
+ return /* @__PURE__ */ React5.createElement(Text4, { key, dimColor: true }, line);
6059
6267
  }));
6060
6268
  }
6061
6269
  function BranchBlock({ branch }) {
@@ -6064,33 +6272,33 @@ function BranchBlock({ branch }) {
6064
6272
  const t = (branch.temperatures[i] ?? 0).toFixed(1);
6065
6273
  return `${marker} #${i} T=${t} u=${u}`;
6066
6274
  }).join(" ");
6067
- 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)));
6068
6276
  }
6069
6277
  function ReasoningBlock({ reasoning }) {
6070
6278
  const max = 260;
6071
6279
  const flat = reasoning.replace(/\s+/g, " ").trim();
6072
6280
  const preview = flat.length <= max ? flat : `\u2026 (+${flat.length - max} earlier chars) ${flat.slice(-max)}`;
6073
- 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));
6074
6282
  }
6075
6283
  function Elapsed() {
6076
6284
  const s = useElapsedSeconds();
6077
6285
  const mm = String(Math.floor(s / 60)).padStart(2, "0");
6078
6286
  const ss = String(s % 60).padStart(2, "0");
6079
- return /* @__PURE__ */ React4.createElement(Text3, { dimColor: true }, `${mm}:${ss}`);
6287
+ return /* @__PURE__ */ React5.createElement(Text4, { dimColor: true }, `${mm}:${ss}`);
6080
6288
  }
6081
6289
  function PulsingAssistantGlyph() {
6082
6290
  const tick = useTick();
6083
6291
  const on = Math.floor(tick / 4) % 2 === 0;
6084
- 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);
6085
6293
  }
6086
6294
  function StreamingAssistant({ event }) {
6087
6295
  if (event.branchProgress) {
6088
6296
  const p = event.branchProgress;
6089
6297
  if (p.completed === 0) {
6090
- 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"));
6091
6299
  }
6092
6300
  const pct2 = Math.round(p.completed / p.total * 100);
6093
- 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"));
6094
6302
  }
6095
6303
  const tail = lastLine(event.text, 140);
6096
6304
  const reasoningTail = event.reasoning ? lastLine(event.reasoning, 120) : "";
@@ -6118,16 +6326,16 @@ function StreamingAssistant({ event }) {
6118
6326
  label = parts.join(" \xB7 ");
6119
6327
  labelColor = "green";
6120
6328
  }
6121
- 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 ? (
6122
6330
  // Non-dim yellow: first-time users misread the dim version as
6123
6331
  // "app frozen". The reassurance has to be VISIBLE to do its job.
6124
- /* @__PURE__ */ React4.createElement(Text3, { color: "yellow", italic: true }, " waiting for first byte \u2014 this is normal, typically 5-60s depending on model + load")
6125
- ) : 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);
6126
6334
  }
6127
6335
  function Pulse() {
6128
6336
  const tick = useTick();
6129
6337
  const frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
6130
- 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]);
6131
6339
  }
6132
6340
  function lastLine(s, maxChars) {
6133
6341
  const flat = s.replace(/\s+/g, " ").trim();
@@ -6136,7 +6344,7 @@ function lastLine(s, maxChars) {
6136
6344
  }
6137
6345
  function StatsLine({ stats }) {
6138
6346
  const hit = (stats.cacheHitRatio * 100).toFixed(1);
6139
- 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)));
6140
6348
  }
6141
6349
  function truncate2(s, max) {
6142
6350
  if (s.length <= max) return s;
@@ -6159,12 +6367,12 @@ ${s.slice(-max)}`;
6159
6367
  }
6160
6368
 
6161
6369
  // src/cli/ui/PlanConfirm.tsx
6162
- import { Box as Box5, Text as Text5 } from "ink";
6163
- import React6 from "react";
6370
+ import { Box as Box6, Text as Text6 } from "ink";
6371
+ import React7 from "react";
6164
6372
 
6165
6373
  // src/cli/ui/Select.tsx
6166
- import { Box as Box4, Text as Text4, useInput } from "ink";
6167
- 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";
6168
6376
  function SingleSelect({
6169
6377
  items,
6170
6378
  initialValue,
@@ -6189,7 +6397,7 @@ function SingleSelect({
6189
6397
  onCancel();
6190
6398
  }
6191
6399
  });
6192
- 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(
6193
6401
  SelectRow,
6194
6402
  {
6195
6403
  key: item.value,
@@ -6197,7 +6405,7 @@ function SingleSelect({
6197
6405
  active: i === index,
6198
6406
  marker: i === index ? "\u25B8" : " "
6199
6407
  }
6200
- )), 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);
6201
6409
  }
6202
6410
  function MultiSelect({
6203
6411
  items,
@@ -6232,10 +6440,10 @@ function MultiSelect({
6232
6440
  onCancel();
6233
6441
  }
6234
6442
  });
6235
- return /* @__PURE__ */ React5.createElement(Box4, { flexDirection: "column" }, items.map((item, i) => {
6443
+ return /* @__PURE__ */ React6.createElement(Box5, { flexDirection: "column" }, items.map((item, i) => {
6236
6444
  const checked = selected.has(item.value);
6237
6445
  const marker = checked ? "[x]" : "[ ]";
6238
- return /* @__PURE__ */ React5.createElement(
6446
+ return /* @__PURE__ */ React6.createElement(
6239
6447
  SelectRow,
6240
6448
  {
6241
6449
  key: item.value,
@@ -6244,7 +6452,7 @@ function MultiSelect({
6244
6452
  marker: `${i === index ? "\u25B8" : " "} ${marker}`
6245
6453
  }
6246
6454
  );
6247
- }), 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);
6248
6456
  }
6249
6457
  function SelectRow({
6250
6458
  item,
@@ -6252,7 +6460,7 @@ function SelectRow({
6252
6460
  marker
6253
6461
  }) {
6254
6462
  const color = item.disabled ? "gray" : active ? "cyan" : void 0;
6255
- 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);
6256
6464
  }
6257
6465
  function findNextEnabled(items, from, step) {
6258
6466
  if (items.length === 0) return 0;
@@ -6273,7 +6481,7 @@ function PlanConfirm({ plan, onChoose, maxRenderedChars, projectRoot }) {
6273
6481
 
6274
6482
  \u2026 (${plan.length - cap} chars truncated \u2014 use /tool to view the full proposal)` : plan;
6275
6483
  const hasOpenQuestions = /^#{1,6}\s*(open[-\s]?questions?|risks?|unknowns?|assumptions?|unclear)/im.test(plan) || /^#{1,6}\s*(待确认|开放问题|风险|未知|假设|不确定)/im.test(plan);
6276
- 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(
6277
6485
  SingleSelect,
6278
6486
  {
6279
6487
  initialValue: hasOpenQuestions ? "refine" : "approve",
@@ -6302,8 +6510,8 @@ function PlanConfirm({ plan, onChoose, maxRenderedChars, projectRoot }) {
6302
6510
  }
6303
6511
 
6304
6512
  // src/cli/ui/PlanRefineInput.tsx
6305
- import { Box as Box6, Text as Text6, useInput as useInput2 } from "ink";
6306
- 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";
6307
6515
  function PlanRefineInput({ mode, onSubmit, onCancel }) {
6308
6516
  const [value, setValue] = useState3("");
6309
6517
  useInput2((input, key) => {
@@ -6326,12 +6534,12 @@ function PlanRefineInput({ mode, onSubmit, onCancel }) {
6326
6534
  const title = mode === "approve" ? "\u25B8 approving \u2014 any last instructions or answers to open questions?" : "\u25B8 refining \u2014 what should the model change?";
6327
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.";
6328
6536
  const blankHint = mode === "approve" ? " (Enter with blank = approve without extra instructions.)" : " (Enter with blank = ask the model to list concrete questions.)";
6329
- 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"))));
6330
6538
  }
6331
6539
 
6332
6540
  // src/cli/ui/PromptInput.tsx
6333
- import { Box as Box7, Text as Text7, useInput as useInput3 } from "ink";
6334
- 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";
6335
6543
 
6336
6544
  // src/cli/ui/multiline-keys.ts
6337
6545
  var BACKSLASH_SUFFIX = /\\$/;
@@ -6491,13 +6699,13 @@ function PromptInput({
6491
6699
  const lines = value.length > 0 ? value.split("\n") : [""];
6492
6700
  const borderColor = disabled ? "gray" : "cyan";
6493
6701
  const { line: cursorLine, col: cursorCol } = lineAndColumn(value, cursor);
6494
- 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) => {
6495
6703
  const isFirst = i === 0;
6496
6704
  const showPlaceholder = isFirst && value.length === 0;
6497
6705
  const isCursorLine = i === cursorLine;
6498
6706
  return (
6499
6707
  // biome-ignore lint/suspicious/noArrayIndexKey: stable by construction — lines are derived from `value.split("\n")` and never reordered
6500
- /* @__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(
6501
6709
  LineWithCursor,
6502
6710
  {
6503
6711
  line,
@@ -6505,7 +6713,7 @@ function PromptInput({
6505
6713
  showCursor,
6506
6714
  borderColor
6507
6715
  }
6508
- ) : /* @__PURE__ */ React8.createElement(Text7, null, line))
6716
+ ) : /* @__PURE__ */ React9.createElement(Text8, null, line))
6509
6717
  );
6510
6718
  }));
6511
6719
  }
@@ -6519,16 +6727,16 @@ function LineWithCursor({
6519
6727
  const atCursor = line.slice(col, col + 1);
6520
6728
  const after = line.slice(col + 1);
6521
6729
  if (atCursor.length === 0) {
6522
- 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" : " "));
6523
6731
  }
6524
- 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));
6525
6733
  }
6526
6734
 
6527
6735
  // src/cli/ui/ShellConfirm.tsx
6528
- import { Box as Box8, Text as Text8 } from "ink";
6529
- import React9 from "react";
6736
+ import { Box as Box9, Text as Text9 } from "ink";
6737
+ import React10 from "react";
6530
6738
  function ShellConfirm({ command, allowPrefix, onChoose }) {
6531
- 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(
6532
6740
  SingleSelect,
6533
6741
  {
6534
6742
  initialValue: "run_once",
@@ -6585,15 +6793,15 @@ function derivePrefix(command) {
6585
6793
  }
6586
6794
 
6587
6795
  // src/cli/ui/SlashSuggestions.tsx
6588
- import { Box as Box9, Text as Text9 } from "ink";
6589
- import React10 from "react";
6796
+ import { Box as Box10, Text as Text10 } from "ink";
6797
+ import React11 from "react";
6590
6798
  function SlashSuggestions({
6591
6799
  matches,
6592
6800
  selectedIndex
6593
6801
  }) {
6594
6802
  if (matches === null) return null;
6595
6803
  if (matches.length === 0) {
6596
- 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"));
6597
6805
  }
6598
6806
  const MAX = 8;
6599
6807
  const total = matches.length;
@@ -6601,21 +6809,21 @@ function SlashSuggestions({
6601
6809
  const shown = matches.slice(windowStart, windowStart + MAX);
6602
6810
  const hiddenAbove = windowStart;
6603
6811
  const hiddenBelow = total - windowStart - shown.length;
6604
- 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"));
6605
6813
  }
6606
6814
  function SuggestionRow({ spec, isSelected }) {
6607
6815
  const marker = isSelected ? "\u25B8" : " ";
6608
6816
  const name = `/${spec.cmd}`;
6609
6817
  const argsSuffix = spec.argsHint ? ` ${spec.argsHint}` : "";
6610
6818
  if (isSelected) {
6611
- 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));
6612
6820
  }
6613
- 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));
6614
6822
  }
6615
6823
 
6616
6824
  // src/cli/ui/StatsPanel.tsx
6617
- import { Box as Box10, Text as Text10, useStdout as useStdout2 } from "ink";
6618
- import React11 from "react";
6825
+ import { Box as Box11, Text as Text11, useStdout as useStdout2 } from "ink";
6826
+ import React12 from "react";
6619
6827
  var WORDMARK_STYLES = [
6620
6828
  { ch: "\u25C8", color: "#5eead4", isLogo: true },
6621
6829
  // teal — brand mark
@@ -6641,7 +6849,7 @@ function Wordmark({ busy }) {
6641
6849
  const tick = useTick();
6642
6850
  const period = busy ? 5 : 12;
6643
6851
  const bright = Math.floor(tick / period) % 2 === 0;
6644
- 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)));
6645
6853
  }
6646
6854
  var NARROW_BREAKPOINT = 120;
6647
6855
  var COLD_START_TURNS = 3;
@@ -6663,7 +6871,7 @@ function StatsPanel({
6663
6871
  const columns = stdout2?.columns ?? 80;
6664
6872
  const narrow = columns < NARROW_BREAKPOINT;
6665
6873
  const coldStart = summary.turns <= COLD_START_TURNS;
6666
- 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(
6667
6875
  Header,
6668
6876
  {
6669
6877
  model,
@@ -6677,7 +6885,7 @@ function StatsPanel({
6677
6885
  narrow,
6678
6886
  busy: busy ?? false
6679
6887
  }
6680
- ), narrow ? /* @__PURE__ */ React11.createElement(
6888
+ ), narrow ? /* @__PURE__ */ React12.createElement(
6681
6889
  StackedMetrics,
6682
6890
  {
6683
6891
  summary,
@@ -6686,7 +6894,7 @@ function StatsPanel({
6686
6894
  balance,
6687
6895
  coldStart
6688
6896
  }
6689
- ) : /* @__PURE__ */ React11.createElement(
6897
+ ) : /* @__PURE__ */ React12.createElement(
6690
6898
  InlineMetrics,
6691
6899
  {
6692
6900
  summary,
@@ -6709,7 +6917,7 @@ function Header({
6709
6917
  narrow,
6710
6918
  busy
6711
6919
  }) {
6712
- 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`)));
6713
6921
  }
6714
6922
  function InlineMetrics({
6715
6923
  summary,
@@ -6718,7 +6926,7 @@ function InlineMetrics({
6718
6926
  balance,
6719
6927
  coldStart
6720
6928
  }) {
6721
- 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);
6722
6930
  }
6723
6931
  function StackedMetrics({
6724
6932
  summary,
@@ -6727,7 +6935,7 @@ function StackedMetrics({
6727
6935
  balance,
6728
6936
  coldStart
6729
6937
  }) {
6730
- 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(
6731
6939
  ContextCell,
6732
6940
  {
6733
6941
  ratio: ctxRatio,
@@ -6735,7 +6943,7 @@ function StackedMetrics({
6735
6943
  ctxMax,
6736
6944
  showBar: true
6737
6945
  }
6738
- ), 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 }));
6739
6947
  }
6740
6948
  function ContextCell({
6741
6949
  ratio,
@@ -6744,11 +6952,11 @@ function ContextCell({
6744
6952
  showBar
6745
6953
  }) {
6746
6954
  if (promptTokens === 0) {
6747
- 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)"));
6748
6956
  }
6749
6957
  const color = ratio >= 0.8 ? "red" : ratio >= 0.6 ? "yellow" : "green";
6750
6958
  const pct2 = Math.round(ratio * 100);
6751
- 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);
6752
6960
  }
6753
6961
  function CacheCell({
6754
6962
  hitRatio,
@@ -6757,33 +6965,33 @@ function CacheCell({
6757
6965
  }) {
6758
6966
  const pct2 = (hitRatio * 100).toFixed(1);
6759
6967
  if (turns === 0) {
6760
- 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"));
6761
6969
  }
6762
6970
  if (coldStart) {
6763
- 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)"));
6764
6972
  }
6765
6973
  const color = hitRatio >= 0.7 ? "green" : hitRatio >= 0.4 ? "yellow" : "red";
6766
- 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, "%"));
6767
6975
  }
6768
6976
  function CostCell({
6769
6977
  summary,
6770
6978
  coldStart
6771
6979
  }) {
6772
6980
  if (summary.turns === 0) {
6773
- 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"));
6774
6982
  }
6775
6983
  const primaryColor = coldStart ? void 0 : "green";
6776
- 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), ")"));
6777
6985
  }
6778
6986
  function BalanceCell({ balance }) {
6779
6987
  const color = balance.total < 1 ? "red" : balance.total < 5 ? "yellow" : "green";
6780
- 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}` : ""));
6781
6989
  }
6782
6990
  function Bar({ ratio, color }) {
6783
6991
  const cells = 10;
6784
6992
  const filled = Math.max(0, Math.min(cells, Math.round(ratio * cells)));
6785
6993
  const bar = "\u2588".repeat(filled) + "\u2591".repeat(cells - filled);
6786
- return /* @__PURE__ */ React11.createElement(Text10, { color }, bar);
6994
+ return /* @__PURE__ */ React12.createElement(Text11, { color }, bar);
6787
6995
  }
6788
6996
  function formatTokens(n) {
6789
6997
  if (n < 1024) return String(n);
@@ -6795,7 +7003,7 @@ function formatTokens(n) {
6795
7003
  import { spawnSync } from "child_process";
6796
7004
 
6797
7005
  // src/cli/commands/stats.ts
6798
- import { existsSync as existsSync7, readFileSync as readFileSync11 } from "fs";
7006
+ import { existsSync as existsSync9, readFileSync as readFileSync12 } from "fs";
6799
7007
  function statsCommand(opts) {
6800
7008
  if (opts.transcript) {
6801
7009
  transcriptSummary(opts.transcript);
@@ -6804,11 +7012,11 @@ function statsCommand(opts) {
6804
7012
  dashboard(opts);
6805
7013
  }
6806
7014
  function transcriptSummary(path) {
6807
- if (!existsSync7(path)) {
7015
+ if (!existsSync9(path)) {
6808
7016
  console.error(`no such transcript: ${path}`);
6809
7017
  process.exit(1);
6810
7018
  }
6811
- const lines = readFileSync11(path, "utf8").split(/\r?\n/).filter(Boolean);
7019
+ const lines = readFileSync12(path, "utf8").split(/\r?\n/).filter(Boolean);
6812
7020
  let assistantTurns = 0;
6813
7021
  let toolCalls = 0;
6814
7022
  let lastTurn = 0;
@@ -7944,6 +8152,39 @@ function App({
7944
8152
  return prev;
7945
8153
  });
7946
8154
  }, [slashMatches]);
8155
+ const [atSelected, setAtSelected] = useState5(0);
8156
+ const atFiles = useMemo(() => {
8157
+ if (!codeMode?.rootDir) return [];
8158
+ try {
8159
+ return listFilesSync(codeMode.rootDir, { maxResults: 500 });
8160
+ } catch {
8161
+ return [];
8162
+ }
8163
+ }, [codeMode?.rootDir]);
8164
+ const atPicker = useMemo(() => {
8165
+ if (!codeMode?.rootDir) return null;
8166
+ if (slashMatches !== null) return null;
8167
+ return detectAtPicker(input);
8168
+ }, [codeMode?.rootDir, input, slashMatches]);
8169
+ const atMatches = useMemo(() => {
8170
+ if (!atPicker) return null;
8171
+ return rankPickerCandidates(atFiles, atPicker.query, 40);
8172
+ }, [atPicker, atFiles]);
8173
+ useEffect2(() => {
8174
+ setAtSelected((prev) => {
8175
+ if (!atMatches || atMatches.length === 0) return 0;
8176
+ if (prev >= atMatches.length) return atMatches.length - 1;
8177
+ return prev;
8178
+ });
8179
+ }, [atMatches]);
8180
+ const pickAtMention = useCallback(
8181
+ (chosenPath) => {
8182
+ if (!atPicker) return;
8183
+ const before = input.slice(0, atPicker.atOffset);
8184
+ setInput(`${before}@${chosenPath} `);
8185
+ },
8186
+ [atPicker, input]
8187
+ );
7947
8188
  const loopRef = useRef2(null);
7948
8189
  const subagentSinkRef = useRef2({ current: null });
7949
8190
  const loop = useMemo(() => {
@@ -8113,6 +8354,21 @@ function App({
8113
8354
  }
8114
8355
  if (busy) return;
8115
8356
  if (pendingShell) return;
8357
+ if (atMatches && atMatches.length > 0) {
8358
+ if (key.upArrow) {
8359
+ setAtSelected((i) => Math.max(0, i - 1));
8360
+ return;
8361
+ }
8362
+ if (key.downArrow) {
8363
+ setAtSelected((i) => Math.min(atMatches.length - 1, i + 1));
8364
+ return;
8365
+ }
8366
+ if (key.tab) {
8367
+ const sel = atMatches[atSelected] ?? atMatches[0];
8368
+ if (sel) pickAtMention(sel);
8369
+ return;
8370
+ }
8371
+ }
8116
8372
  if (slashMatches && slashMatches.length > 0) {
8117
8373
  if (key.upArrow) {
8118
8374
  setSlashSelected((i) => Math.max(0, i - 1));
@@ -8198,6 +8454,13 @@ function App({
8198
8454
  async (raw) => {
8199
8455
  let text = raw.trim();
8200
8456
  if (!text || busy) return;
8457
+ if (atMatches && atMatches.length > 0 && atPicker) {
8458
+ const sel = atMatches[atSelected] ?? atMatches[0];
8459
+ if (sel) {
8460
+ pickAtMention(sel);
8461
+ return;
8462
+ }
8463
+ }
8201
8464
  if (text.startsWith("/") && !text.includes(" ")) {
8202
8465
  const typed = text.slice(1).toLowerCase();
8203
8466
  const matches = suggestSlashCommands(typed, !!codeMode);
@@ -8342,8 +8605,26 @@ function App({
8342
8605
  });
8343
8606
  };
8344
8607
  const timer = PLAIN_UI ? null : setInterval(flush, FLUSH_INTERVAL_MS);
8608
+ let modelInput = text;
8609
+ if (codeMode?.rootDir) {
8610
+ const expanded = expandAtMentions(text, codeMode.rootDir);
8611
+ if (expanded.expansions.length > 0) {
8612
+ modelInput = expanded.text;
8613
+ const inlined = expanded.expansions.filter((ex) => ex.ok).map((ex) => `${ex.path} (${(ex.bytes ?? 0).toLocaleString()} bytes)`);
8614
+ const skipped = expanded.expansions.filter((ex) => !ex.ok).map((ex) => `${ex.path} (${ex.skip})`);
8615
+ const parts = [];
8616
+ if (inlined.length > 0) parts.push(`inlined ${inlined.join(", ")}`);
8617
+ if (skipped.length > 0) parts.push(`skipped ${skipped.join(", ")}`);
8618
+ if (parts.length > 0) {
8619
+ setHistorical((prev) => [
8620
+ ...prev,
8621
+ { id: `at-${Date.now()}`, role: "info", text: `\u25B8 @mentions: ${parts.join("; ")}` }
8622
+ ]);
8623
+ }
8624
+ }
8625
+ }
8345
8626
  try {
8346
- for await (const ev of loop.step(text)) {
8627
+ for await (const ev of loop.step(modelInput)) {
8347
8628
  writeTranscript(ev);
8348
8629
  if (ev.role !== "status") {
8349
8630
  setStatusLine((cur) => cur ? null : cur);
@@ -8534,6 +8815,10 @@ function App({
8534
8815
  planMode,
8535
8816
  session,
8536
8817
  slashSelected,
8818
+ atMatches,
8819
+ atPicker,
8820
+ atSelected,
8821
+ pickAtMention,
8537
8822
  togglePlanMode,
8538
8823
  writeTranscript
8539
8824
  ]
@@ -8684,7 +8969,7 @@ Stay in plan mode \u2014 address the feedback (explore more if needed), then sub
8684
8969
  if (stagedInput?.plan) setPendingPlan(stagedInput.plan);
8685
8970
  setStagedInput(null);
8686
8971
  }, [stagedInput]);
8687
- return /* @__PURE__ */ React12.createElement(TickerProvider, { disabled: PLAIN_UI }, /* @__PURE__ */ React12.createElement(Box11, { flexDirection: "column" }, /* @__PURE__ */ React12.createElement(
8972
+ return /* @__PURE__ */ React13.createElement(TickerProvider, { disabled: PLAIN_UI }, /* @__PURE__ */ React13.createElement(Box12, { flexDirection: "column" }, /* @__PURE__ */ React13.createElement(
8688
8973
  StatsPanel,
8689
8974
  {
8690
8975
  summary,
@@ -8697,21 +8982,21 @@ Stay in plan mode \u2014 address the feedback (explore more if needed), then sub
8697
8982
  busy,
8698
8983
  updateAvailable
8699
8984
  }
8700
- ), /* @__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(
8985
+ ), /* @__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(
8701
8986
  PlanRefineInput,
8702
8987
  {
8703
8988
  mode: stagedInput.mode,
8704
8989
  onSubmit: handleStagedInputSubmit,
8705
8990
  onCancel: handleStagedInputCancel
8706
8991
  }
8707
- ) : pendingPlan ? /* @__PURE__ */ React12.createElement(PlanConfirm, { plan: pendingPlan, onChoose: handlePlanConfirm, projectRoot: hookCwd }) : pendingShell ? /* @__PURE__ */ React12.createElement(
8992
+ ) : pendingPlan ? /* @__PURE__ */ React13.createElement(PlanConfirm, { plan: pendingPlan, onChoose: handlePlanConfirm, projectRoot: hookCwd }) : pendingShell ? /* @__PURE__ */ React13.createElement(
8708
8993
  ShellConfirm,
8709
8994
  {
8710
8995
  command: pendingShell,
8711
8996
  allowPrefix: derivePrefix(pendingShell),
8712
8997
  onChoose: handleShellConfirm
8713
8998
  }
8714
- ) : /* @__PURE__ */ React12.createElement(React12.Fragment, null, /* @__PURE__ */ React12.createElement(
8999
+ ) : /* @__PURE__ */ React13.createElement(React13.Fragment, null, /* @__PURE__ */ React13.createElement(
8715
9000
  PromptInput,
8716
9001
  {
8717
9002
  value: input,
@@ -8719,20 +9004,27 @@ Stay in plan mode \u2014 address the feedback (explore more if needed), then sub
8719
9004
  onSubmit: handleSubmit,
8720
9005
  disabled: busy
8721
9006
  }
8722
- ), /* @__PURE__ */ React12.createElement(SlashSuggestions, { matches: slashMatches, selectedIndex: slashSelected }))));
9007
+ ), /* @__PURE__ */ React13.createElement(SlashSuggestions, { matches: slashMatches, selectedIndex: slashSelected }), /* @__PURE__ */ React13.createElement(
9008
+ AtMentionSuggestions,
9009
+ {
9010
+ matches: atMatches,
9011
+ selectedIndex: atSelected,
9012
+ query: atPicker?.query ?? ""
9013
+ }
9014
+ ))));
8723
9015
  }
8724
9016
  var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
8725
9017
  function StatusRow({ text }) {
8726
9018
  const tick = useTick();
8727
9019
  const elapsed = useElapsedSeconds();
8728
- 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`));
9020
+ 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`));
8729
9021
  }
8730
9022
  function SubagentRow({
8731
9023
  activity
8732
9024
  }) {
8733
9025
  const tick = useTick();
8734
9026
  const seconds = (activity.elapsedMs / 1e3).toFixed(1);
8735
- 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`));
9027
+ 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`));
8736
9028
  }
8737
9029
  function OngoingToolRow({
8738
9030
  tool,
@@ -8741,7 +9033,7 @@ function OngoingToolRow({
8741
9033
  const tick = useTick();
8742
9034
  const elapsed = useElapsedSeconds();
8743
9035
  const summary = summarizeToolArgs(tool.name, tool.args);
8744
- 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);
9036
+ 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);
8745
9037
  }
8746
9038
  function renderProgressLine(p) {
8747
9039
  const msg = p.message ? ` ${p.message}` : "";
@@ -8837,15 +9129,15 @@ function describeRepair(repair) {
8837
9129
  }
8838
9130
 
8839
9131
  // src/cli/ui/SessionPicker.tsx
8840
- import { Box as Box12, Text as Text12 } from "ink";
8841
- import React13 from "react";
9132
+ import { Box as Box13, Text as Text13 } from "ink";
9133
+ import React14 from "react";
8842
9134
  function SessionPicker({
8843
9135
  sessionName,
8844
9136
  messageCount,
8845
9137
  lastActive,
8846
9138
  onChoose
8847
9139
  }) {
8848
- 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(
9140
+ 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(
8849
9141
  SingleSelect,
8850
9142
  {
8851
9143
  initialValue: "new",
@@ -8868,7 +9160,7 @@ function SessionPicker({
8868
9160
  ],
8869
9161
  onSubmit: (v) => onChoose(v)
8870
9162
  }
8871
- ), /* @__PURE__ */ React13.createElement(Box12, { marginTop: 1 }, /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, "\u2191\u2193 to move \xB7 Enter to pick")));
9163
+ ), /* @__PURE__ */ React14.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text13, { dimColor: true }, "\u2191\u2193 to move \xB7 Enter to pick")));
8872
9164
  }
8873
9165
  function relativeTime(date) {
8874
9166
  const ms = Date.now() - date.getTime();
@@ -8884,9 +9176,9 @@ function relativeTime(date) {
8884
9176
  }
8885
9177
 
8886
9178
  // src/cli/ui/Setup.tsx
8887
- import { Box as Box13, Text as Text13, useApp as useApp2 } from "ink";
9179
+ import { Box as Box14, Text as Text14, useApp as useApp2 } from "ink";
8888
9180
  import TextInput from "ink-text-input";
8889
- import React14, { useState as useState6 } from "react";
9181
+ import React15, { useState as useState6 } from "react";
8890
9182
  function Setup({ onReady }) {
8891
9183
  const [value, setValue] = useState6("");
8892
9184
  const [error, setError] = useState6(null);
@@ -8910,7 +9202,7 @@ function Setup({ onReady }) {
8910
9202
  }
8911
9203
  onReady(trimmed);
8912
9204
  };
8913
- 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(
9205
+ 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(
8914
9206
  TextInput,
8915
9207
  {
8916
9208
  value,
@@ -8919,7 +9211,7 @@ function Setup({ onReady }) {
8919
9211
  mask: "\u2022",
8920
9212
  placeholder: "sk-..."
8921
9213
  }
8922
- )), 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.)")));
9214
+ )), 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.)")));
8923
9215
  }
8924
9216
 
8925
9217
  // src/cli/commands/chat.tsx
@@ -8935,7 +9227,7 @@ function Root({
8935
9227
  const [key, setKey] = useState7(initialKey);
8936
9228
  const [pending, setPending] = useState7(sessionPreview);
8937
9229
  if (!key) {
8938
- return /* @__PURE__ */ React15.createElement(
9230
+ return /* @__PURE__ */ React16.createElement(
8939
9231
  Setup,
8940
9232
  {
8941
9233
  onReady: (k) => {
@@ -8947,7 +9239,7 @@ function Root({
8947
9239
  }
8948
9240
  process.env.DEEPSEEK_API_KEY = key;
8949
9241
  if (pending && appProps.session) {
8950
- return /* @__PURE__ */ React15.createElement(
9242
+ return /* @__PURE__ */ React16.createElement(
8951
9243
  SessionPicker,
8952
9244
  {
8953
9245
  sessionName: appProps.session,
@@ -8962,7 +9254,7 @@ function Root({
8962
9254
  }
8963
9255
  );
8964
9256
  }
8965
- return /* @__PURE__ */ React15.createElement(
9257
+ return /* @__PURE__ */ React16.createElement(
8966
9258
  App,
8967
9259
  {
8968
9260
  model: appProps.model,
@@ -9058,14 +9350,14 @@ async function chatCommand(opts) {
9058
9350
  const prior = loadSessionMessages(opts.session);
9059
9351
  if (prior.length > 0) {
9060
9352
  const p = sessionPath(opts.session);
9061
- const mtime = existsSync8(p) ? statSync5(p).mtime : /* @__PURE__ */ new Date();
9353
+ const mtime = existsSync10(p) ? statSync6(p).mtime : /* @__PURE__ */ new Date();
9062
9354
  sessionPreview = { messageCount: prior.length, lastActive: mtime };
9063
9355
  }
9064
9356
  } else if (opts.session && opts.forceNew) {
9065
9357
  rewriteSession(opts.session, []);
9066
9358
  }
9067
9359
  const { waitUntilExit } = render(
9068
- /* @__PURE__ */ React15.createElement(
9360
+ /* @__PURE__ */ React16.createElement(
9069
9361
  Root,
9070
9362
  {
9071
9363
  initialKey,
@@ -9089,10 +9381,10 @@ async function chatCommand(opts) {
9089
9381
  }
9090
9382
 
9091
9383
  // src/cli/commands/code.tsx
9092
- import { basename, resolve as resolve5 } from "path";
9384
+ import { basename, resolve as resolve6 } from "path";
9093
9385
  async function codeCommand(opts = {}) {
9094
9386
  const { codeSystemPrompt: codeSystemPrompt2 } = await import("./prompt-75XLIUTO.js");
9095
- const rootDir = resolve5(opts.dir ?? process.cwd());
9387
+ const rootDir = resolve6(opts.dir ?? process.cwd());
9096
9388
  const session = opts.noSession ? void 0 : `code-${sanitizeName(basename(rootDir))}`;
9097
9389
  const tools = new ToolRegistry();
9098
9390
  registerFilesystemTools(tools, { rootDir });
@@ -9128,34 +9420,34 @@ async function codeCommand(opts = {}) {
9128
9420
  import { writeFileSync as writeFileSync5 } from "fs";
9129
9421
  import { basename as basename2 } from "path";
9130
9422
  import { render as render2 } from "ink";
9131
- import React18 from "react";
9423
+ import React19 from "react";
9132
9424
 
9133
9425
  // src/cli/ui/DiffApp.tsx
9134
- import { Box as Box15, Static as Static2, Text as Text15, useApp as useApp3, useInput as useInput5 } from "ink";
9135
- import React17, { useState as useState8 } from "react";
9426
+ import { Box as Box16, Static as Static2, Text as Text16, useApp as useApp3, useInput as useInput5 } from "ink";
9427
+ import React18, { useState as useState8 } from "react";
9136
9428
 
9137
9429
  // src/cli/ui/RecordView.tsx
9138
- import { Box as Box14, Text as Text14 } from "ink";
9139
- import React16 from "react";
9430
+ import { Box as Box15, Text as Text15 } from "ink";
9431
+ import React17 from "react";
9140
9432
  function RecordView({ rec, compact = false }) {
9141
9433
  const toolArgsMax = compact ? 120 : 200;
9142
9434
  const toolContentMax = compact ? 200 : 400;
9143
9435
  if (rec.role === "user") {
9144
- return /* @__PURE__ */ React16.createElement(Box14, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text14, { bold: true, color: "cyan" }, "you \u203A", " "), /* @__PURE__ */ React16.createElement(Text14, null, rec.content));
9436
+ return /* @__PURE__ */ React17.createElement(Box15, { marginTop: 1 }, /* @__PURE__ */ React17.createElement(Text15, { bold: true, color: "cyan" }, "you \u203A", " "), /* @__PURE__ */ React17.createElement(Text15, null, rec.content));
9145
9437
  }
9146
9438
  if (rec.role === "assistant_final") {
9147
- 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)"));
9439
+ 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)"));
9148
9440
  }
9149
9441
  if (rec.role === "tool") {
9150
- 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)));
9442
+ 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)));
9151
9443
  }
9152
9444
  if (rec.role === "error") {
9153
- 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));
9445
+ 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));
9154
9446
  }
9155
9447
  if (rec.role === "done" || rec.role === "assistant_delta") {
9156
9448
  return null;
9157
9449
  }
9158
- return /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Text14, { dimColor: true }, "[", rec.role, "] ", rec.content));
9450
+ return /* @__PURE__ */ React17.createElement(Box15, null, /* @__PURE__ */ React17.createElement(Text15, { dimColor: true }, "[", rec.role, "] ", rec.content));
9159
9451
  }
9160
9452
  function CacheBadge({ usage }) {
9161
9453
  const hit = usage.prompt_cache_hit_tokens ?? 0;
@@ -9164,7 +9456,7 @@ function CacheBadge({ usage }) {
9164
9456
  if (total === 0) return null;
9165
9457
  const pct2 = hit / total * 100;
9166
9458
  const color = pct2 >= 70 ? "green" : pct2 >= 40 ? "yellow" : "red";
9167
- return /* @__PURE__ */ React16.createElement(Text14, null, /* @__PURE__ */ React16.createElement(Text14, { dimColor: true }, " \xB7 cache "), /* @__PURE__ */ React16.createElement(Text14, { color }, pct2.toFixed(1), "%"));
9459
+ return /* @__PURE__ */ React17.createElement(Text15, null, /* @__PURE__ */ React17.createElement(Text15, { dimColor: true }, " \xB7 cache "), /* @__PURE__ */ React17.createElement(Text15, { color }, pct2.toFixed(1), "%"));
9168
9460
  }
9169
9461
  function truncate3(s, max) {
9170
9462
  return s.length <= max ? s : `${s.slice(0, max)}\u2026 (+${s.length - max} chars)`;
@@ -9198,7 +9490,7 @@ function DiffApp({ report }) {
9198
9490
  }
9199
9491
  });
9200
9492
  const pair = report.pairs[idx];
9201
- 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")));
9493
+ 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")));
9202
9494
  }
9203
9495
  function DiffHeader({ report }) {
9204
9496
  const a = report.a;
@@ -9216,15 +9508,15 @@ function DiffHeader({ report }) {
9216
9508
  } else if (a.stats.prefixHashes[0] && a.stats.prefixHashes[0] === b.stats.prefixHashes[0]) {
9217
9509
  prefixLine = `shared prefix hash ${a.stats.prefixHashes[0].slice(0, 12)}\u2026 \u2014 cache delta attributable to log stability, not prompt change.`;
9218
9510
  }
9219
- 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);
9511
+ 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);
9220
9512
  }
9221
9513
  function Pane({
9222
9514
  label,
9223
9515
  headerColor,
9224
9516
  records
9225
9517
  }) {
9226
- return /* @__PURE__ */ React17.createElement(
9227
- Box15,
9518
+ return /* @__PURE__ */ React18.createElement(
9519
+ Box16,
9228
9520
  {
9229
9521
  flexDirection: "column",
9230
9522
  flexGrow: 1,
@@ -9232,21 +9524,21 @@ function Pane({
9232
9524
  borderStyle: "single",
9233
9525
  borderColor: headerColor
9234
9526
  },
9235
- /* @__PURE__ */ React17.createElement(Text15, { color: headerColor, bold: true }, label),
9236
- 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 }))
9527
+ /* @__PURE__ */ React18.createElement(Text16, { color: headerColor, bold: true }, label),
9528
+ 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 }))
9237
9529
  );
9238
9530
  }
9239
9531
  function KindBadge({ kind }) {
9240
9532
  if (kind === "match") {
9241
- return /* @__PURE__ */ React17.createElement(Text15, { color: "green" }, "\u2713 match");
9533
+ return /* @__PURE__ */ React18.createElement(Text16, { color: "green" }, "\u2713 match");
9242
9534
  }
9243
9535
  if (kind === "diverge") {
9244
- return /* @__PURE__ */ React17.createElement(Text15, { color: "yellow" }, "\u2605 diverge");
9536
+ return /* @__PURE__ */ React18.createElement(Text16, { color: "yellow" }, "\u2605 diverge");
9245
9537
  }
9246
9538
  if (kind === "only_in_a") {
9247
- return /* @__PURE__ */ React17.createElement(Text15, { color: "blue" }, "\u2190 only in A");
9539
+ return /* @__PURE__ */ React18.createElement(Text16, { color: "blue" }, "\u2190 only in A");
9248
9540
  }
9249
- return /* @__PURE__ */ React17.createElement(Text15, { color: "magenta" }, "\u2192 only in B");
9541
+ return /* @__PURE__ */ React18.createElement(Text16, { color: "magenta" }, "\u2192 only in B");
9250
9542
  }
9251
9543
  function paneRecords(pair, side) {
9252
9544
  if (!pair) return [];
@@ -9277,7 +9569,7 @@ markdown report written to ${opts.mdPath}`);
9277
9569
  return;
9278
9570
  }
9279
9571
  if (wantTui) {
9280
- const { waitUntilExit } = render2(React18.createElement(DiffApp, { report }), {
9572
+ const { waitUntilExit } = render2(React19.createElement(DiffApp, { report }), {
9281
9573
  exitOnCtrlC: true,
9282
9574
  patchConsole: false
9283
9575
  });
@@ -9418,11 +9710,11 @@ function pad2(s, width) {
9418
9710
 
9419
9711
  // src/cli/commands/replay.ts
9420
9712
  import { render as render3 } from "ink";
9421
- import React20 from "react";
9713
+ import React21 from "react";
9422
9714
 
9423
9715
  // src/cli/ui/ReplayApp.tsx
9424
- import { Box as Box16, Static as Static3, Text as Text16, useApp as useApp4, useInput as useInput6 } from "ink";
9425
- import React19, { useMemo as useMemo2, useState as useState9 } from "react";
9716
+ import { Box as Box17, Static as Static3, Text as Text17, useApp as useApp4, useInput as useInput6 } from "ink";
9717
+ import React20, { useMemo as useMemo2, useState as useState9 } from "react";
9426
9718
  function ReplayApp({ meta, pages }) {
9427
9719
  const { exit } = useApp4();
9428
9720
  const maxIdx = Math.max(0, pages.length - 1);
@@ -9461,14 +9753,14 @@ function ReplayApp({ meta, pages }) {
9461
9753
  const prefixHash = cumStats.prefixHashes.length === 1 ? cumStats.prefixHashes[0].slice(0, 16) : cumStats.prefixHashes.length === 0 ? "(untracked)" : `(churned \xD7${cumStats.prefixHashes.length})`;
9462
9754
  const currentPage = pages[idx];
9463
9755
  const progressLabel = pages.length === 0 ? "empty transcript" : `turn ${idx + 1} / ${pages.length}`;
9464
- return /* @__PURE__ */ React19.createElement(Box16, { flexDirection: "column" }, /* @__PURE__ */ React19.createElement(
9756
+ return /* @__PURE__ */ React20.createElement(Box17, { flexDirection: "column" }, /* @__PURE__ */ React20.createElement(
9465
9757
  StatsPanel,
9466
9758
  {
9467
9759
  summary,
9468
9760
  model: cumStats.models[0] ?? meta?.model ?? "?",
9469
9761
  prefixHash
9470
9762
  }
9471
- ), /* @__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")));
9763
+ ), /* @__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")));
9472
9764
  }
9473
9765
 
9474
9766
  // src/cli/commands/replay.ts
@@ -9480,7 +9772,7 @@ async function replayCommand(opts) {
9480
9772
  }
9481
9773
  const { parsed } = replayFromFile(opts.path);
9482
9774
  const pages = groupRecordsByTurn(parsed.records);
9483
- const { waitUntilExit } = render3(React20.createElement(ReplayApp, { meta: parsed.meta, pages }), {
9775
+ const { waitUntilExit } = render3(React21.createElement(ReplayApp, { meta: parsed.meta, pages }), {
9484
9776
  exitOnCtrlC: true,
9485
9777
  patchConsole: false
9486
9778
  });
@@ -9785,12 +10077,12 @@ function truncate4(s, max) {
9785
10077
 
9786
10078
  // src/cli/commands/setup.tsx
9787
10079
  import { render as render4 } from "ink";
9788
- import React22 from "react";
10080
+ import React23 from "react";
9789
10081
 
9790
10082
  // src/cli/ui/Wizard.tsx
9791
- import { Box as Box17, Text as Text17, useApp as useApp5, useInput as useInput7 } from "ink";
10083
+ import { Box as Box18, Text as Text18, useApp as useApp5, useInput as useInput7 } from "ink";
9792
10084
  import TextInput2 from "ink-text-input";
9793
- import React21, { useState as useState10 } from "react";
10085
+ import React22, { useState as useState10 } from "react";
9794
10086
 
9795
10087
  // src/cli/ui/presets.ts
9796
10088
  var PRESETS = {
@@ -9829,7 +10121,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
9829
10121
  if (key.escape && step !== "saved" && onCancel) onCancel();
9830
10122
  });
9831
10123
  if (step === "apiKey") {
9832
- return /* @__PURE__ */ React21.createElement(
10124
+ return /* @__PURE__ */ React22.createElement(
9833
10125
  ApiKeyStep,
9834
10126
  {
9835
10127
  onSubmit: (key) => {
@@ -9843,7 +10135,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
9843
10135
  );
9844
10136
  }
9845
10137
  if (step === "preset") {
9846
- return /* @__PURE__ */ React21.createElement(StepFrame, { title: "Pick a preset", step: 1, total: 3 }, /* @__PURE__ */ React21.createElement(
10138
+ return /* @__PURE__ */ React22.createElement(StepFrame, { title: "Pick a preset", step: 1, total: 3 }, /* @__PURE__ */ React22.createElement(
9847
10139
  SingleSelect,
9848
10140
  {
9849
10141
  items: presetItems(),
@@ -9853,10 +10145,10 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
9853
10145
  setStep("mcp");
9854
10146
  }
9855
10147
  }
9856
- ), /* @__PURE__ */ React21.createElement(Box17, { marginTop: 1 }, /* @__PURE__ */ React21.createElement(Text17, { dimColor: true }, "\u2191/\u2193 move \xB7 enter confirm \xB7 esc cancel")));
10148
+ ), /* @__PURE__ */ React22.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React22.createElement(Text18, { dimColor: true }, "\u2191/\u2193 move \xB7 enter confirm \xB7 esc cancel")));
9857
10149
  }
9858
10150
  if (step === "mcp") {
9859
- return /* @__PURE__ */ React21.createElement(StepFrame, { title: "Which MCP servers should Reasonix wire up for you?", step: 2, total: 3 }, /* @__PURE__ */ React21.createElement(
10151
+ return /* @__PURE__ */ React22.createElement(StepFrame, { title: "Which MCP servers should Reasonix wire up for you?", step: 2, total: 3 }, /* @__PURE__ */ React22.createElement(
9860
10152
  MultiSelect,
9861
10153
  {
9862
10154
  items: mcpItems(),
@@ -9881,7 +10173,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
9881
10173
  }
9882
10174
  const currentName = pending[0];
9883
10175
  const entry = CATALOG_BY_NAME.get(currentName);
9884
- return /* @__PURE__ */ React21.createElement(
10176
+ return /* @__PURE__ */ React22.createElement(
9885
10177
  McpArgsStep,
9886
10178
  {
9887
10179
  entry,
@@ -9899,7 +10191,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
9899
10191
  }
9900
10192
  if (step === "review") {
9901
10193
  const specs = data.selectedCatalog.map((name) => buildSpec(name, data.catalogArgs));
9902
- 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(
10194
+ 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(
9903
10195
  SummaryLine,
9904
10196
  {
9905
10197
  label: "MCP",
@@ -9907,8 +10199,8 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
9907
10199
  }
9908
10200
  ), specs.map((spec, i) => (
9909
10201
  // biome-ignore lint/suspicious/noArrayIndexKey: review-only render, order fixed
9910
- /* @__PURE__ */ React21.createElement(Box17, { key: i, paddingLeft: 14 }, /* @__PURE__ */ React21.createElement(Text17, { dimColor: true }, "\xB7 ", spec))
9911
- )), /* @__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(
10202
+ /* @__PURE__ */ React22.createElement(Box18, { key: i, paddingLeft: 14 }, /* @__PURE__ */ React22.createElement(Text18, { dimColor: true }, "\xB7 ", spec))
10203
+ )), /* @__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(
9912
10204
  ReviewConfirm,
9913
10205
  {
9914
10206
  onConfirm: () => {
@@ -9934,7 +10226,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
9934
10226
  }
9935
10227
  ));
9936
10228
  }
9937
- 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 }));
10229
+ 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 }));
9938
10230
  }
9939
10231
  function ApiKeyStep({
9940
10232
  onSubmit,
@@ -9942,7 +10234,7 @@ function ApiKeyStep({
9942
10234
  onError
9943
10235
  }) {
9944
10236
  const [value, setValue] = useState10("");
9945
- 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(
10237
+ 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(
9946
10238
  TextInput2,
9947
10239
  {
9948
10240
  value,
@@ -9959,7 +10251,7 @@ function ApiKeyStep({
9959
10251
  mask: "\u2022",
9960
10252
  placeholder: "sk-..."
9961
10253
  }
9962
- )), 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);
10254
+ )), 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);
9963
10255
  }
9964
10256
  function McpArgsStep({
9965
10257
  entry,
@@ -9968,7 +10260,7 @@ function McpArgsStep({
9968
10260
  onError
9969
10261
  }) {
9970
10262
  const [value, setValue] = useState10("");
9971
- 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(
10263
+ 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(
9972
10264
  TextInput2,
9973
10265
  {
9974
10266
  value,
@@ -9984,7 +10276,7 @@ function McpArgsStep({
9984
10276
  },
9985
10277
  placeholder: placeholderFor(entry)
9986
10278
  }
9987
- )), error ? /* @__PURE__ */ React21.createElement(Box17, { marginTop: 1 }, /* @__PURE__ */ React21.createElement(Text17, { color: "red" }, error)) : null));
10279
+ )), error ? /* @__PURE__ */ React22.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React22.createElement(Text18, { color: "red" }, error)) : null));
9988
10280
  }
9989
10281
  function ReviewConfirm({ onConfirm }) {
9990
10282
  useInput7((_i, key) => {
@@ -10004,10 +10296,10 @@ function StepFrame({
10004
10296
  total,
10005
10297
  children
10006
10298
  }) {
10007
- 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));
10299
+ 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));
10008
10300
  }
10009
10301
  function SummaryLine({ label, value }) {
10010
- return /* @__PURE__ */ React21.createElement(Box17, null, /* @__PURE__ */ React21.createElement(Text17, null, label.padEnd(12)), /* @__PURE__ */ React21.createElement(Text17, { bold: true }, value));
10302
+ return /* @__PURE__ */ React22.createElement(Box18, null, /* @__PURE__ */ React22.createElement(Text18, null, label.padEnd(12)), /* @__PURE__ */ React22.createElement(Text18, { bold: true }, value));
10011
10303
  }
10012
10304
  function presetItems() {
10013
10305
  return ["fast", "smart", "max"].map((name) => ({
@@ -10063,7 +10355,7 @@ async function setupCommand(_opts = {}) {
10063
10355
  const existingKey = loadApiKey();
10064
10356
  const existing = readConfig();
10065
10357
  const { waitUntilExit, unmount } = render4(
10066
- /* @__PURE__ */ React22.createElement(
10358
+ /* @__PURE__ */ React23.createElement(
10067
10359
  Wizard,
10068
10360
  {
10069
10361
  existingApiKey: existingKey,
@@ -10111,13 +10403,13 @@ function planUpdate(input) {
10111
10403
  };
10112
10404
  }
10113
10405
  function defaultSpawn(argv) {
10114
- return new Promise((resolve6, reject) => {
10406
+ return new Promise((resolve7, reject) => {
10115
10407
  const child = spawn4(argv[0], argv.slice(1), {
10116
10408
  stdio: "inherit",
10117
10409
  shell: process.platform === "win32"
10118
10410
  });
10119
10411
  child.once("error", reject);
10120
- child.once("exit", (code) => resolve6(code ?? 1));
10412
+ child.once("exit", (code) => resolve7(code ?? 1));
10121
10413
  });
10122
10414
  }
10123
10415
  async function updateCommand(opts = {}) {