reasonix 0.7.2 → 0.7.4

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
@@ -715,13 +715,13 @@ async function runHooks(opts) {
715
715
  const matching = opts.hooks.filter((h) => h.event === event && matchesTool(h, toolName));
716
716
  const outcomes = [];
717
717
  let blocked = false;
718
- const stdin2 = `${JSON.stringify(opts.payload)}
718
+ const stdin3 = `${JSON.stringify(opts.payload)}
719
719
  `;
720
720
  for (const hook of matching) {
721
721
  const start = Date.now();
722
722
  const timeoutMs = hook.timeout ?? DEFAULT_TIMEOUTS_MS[event];
723
723
  const cwd = hook.cwd ?? opts.payload.cwd;
724
- const raw = await spawner({ command: hook.command, cwd, stdin: stdin2, timeoutMs });
724
+ const raw = await spawner({ command: hook.command, cwd, stdin: stdin3, timeoutMs });
725
725
  const decision = decideOutcome(event, raw);
726
726
  outcomes.push({
727
727
  hook,
@@ -7113,11 +7113,11 @@ function formatLogSize(path = defaultUsageLogPath()) {
7113
7113
  // src/cli/commands/chat.tsx
7114
7114
  import { existsSync as existsSync12, statSync as statSync7 } from "fs";
7115
7115
  import { render } from "ink";
7116
- import React23, { useState as useState12 } from "react";
7116
+ import React25, { useState as useState12 } from "react";
7117
7117
 
7118
7118
  // src/cli/ui/App.tsx
7119
- import { Box as Box19, Static, useApp, useInput as useInput5, useStdout as useStdout5 } from "ink";
7120
- import React20, { useCallback as useCallback4, useEffect as useEffect5, useMemo as useMemo3, useRef as useRef5, useState as useState10 } from "react";
7119
+ import { Box as Box20, Static, useApp, useStdout as useStdout5 } from "ink";
7120
+ import React22, { useCallback as useCallback4, useEffect as useEffect6, useMemo as useMemo3, useRef as useRef6, useState as useState10 } from "react";
7121
7121
 
7122
7122
  // src/code/pending-edits.ts
7123
7123
  import { existsSync as existsSync9, mkdirSync as mkdirSync6, readFileSync as readFileSync11, unlinkSync as unlinkSync3, writeFileSync as writeFileSync5 } from "fs";
@@ -7442,11 +7442,348 @@ function FileRow({ path, isSelected }) {
7442
7442
 
7443
7443
  // src/cli/ui/ChoiceConfirm.tsx
7444
7444
  import { Box as Box3, Text as Text3 } from "ink";
7445
- import React3 from "react";
7445
+ import React4 from "react";
7446
+
7447
+ // src/cli/ui/Select.tsx
7448
+ import { Box as Box2, Text as Text2 } from "ink";
7449
+ import React3, { useState } from "react";
7450
+
7451
+ // src/cli/ui/keystroke-context.tsx
7452
+ import React2, { createContext, useContext, useEffect, useRef } from "react";
7453
+
7454
+ // src/cli/ui/stdin-reader.ts
7455
+ import { stdin } from "process";
7456
+ var ESC_TIMEOUT_MS = 250;
7457
+ var PASTE_END = "\x1B[201~";
7458
+ var PASTE_START_BARE = "[200~";
7459
+ var PASTE_END_BARE = "[201~";
7460
+ var CSI_TAIL_MAP = [
7461
+ { tail: "A", ev: { input: "", upArrow: true } },
7462
+ { tail: "B", ev: { input: "", downArrow: true } },
7463
+ { tail: "C", ev: { input: "", rightArrow: true } },
7464
+ { tail: "D", ev: { input: "", leftArrow: true } },
7465
+ { tail: "H", ev: { input: "", home: true } },
7466
+ { tail: "F", ev: { input: "", end: true } },
7467
+ { tail: "1~", ev: { input: "", home: true } },
7468
+ { tail: "4~", ev: { input: "", end: true } },
7469
+ { tail: "5~", ev: { input: "", pageUp: true } },
7470
+ { tail: "6~", ev: { input: "", pageDown: true } },
7471
+ { tail: "3~", ev: { input: "", delete: true } },
7472
+ { tail: "Z", ev: { input: "", shift: true, tab: true } },
7473
+ // modifyOtherKeys (xterm CSI > 4 ; 2 m) sequences for Enter with
7474
+ // modifiers. Only fired when App.tsx has enabled the mode at
7475
+ // startup; otherwise Shift+Enter stays indistinguishable from Enter.
7476
+ // Modifier encoding: 2=shift, 3=alt, 4=alt+shift, 5=ctrl,
7477
+ // 6=ctrl+shift, 7=ctrl+alt, 8=ctrl+alt+shift. Keycode 13 = Enter.
7478
+ { tail: "27;2;13~", ev: { input: "", return: true, shift: true } },
7479
+ { tail: "27;5;13~", ev: { input: "", return: true, ctrl: true } },
7480
+ { tail: "27;6;13~", ev: { input: "", return: true, ctrl: true, shift: true } },
7481
+ // Kitty keyboard protocol — same idea, different envelope:
7482
+ // `\x1b[<keycode>;<mod>u`. Some terminals (kitty, recent Windows
7483
+ // Terminal previews) prefer this shape. Harmless to map here too.
7484
+ { tail: "13;2u", ev: { input: "", return: true, shift: true } },
7485
+ { tail: "13;5u", ev: { input: "", return: true, ctrl: true } },
7486
+ { tail: "13;6u", ev: { input: "", return: true, ctrl: true, shift: true } }
7487
+ ];
7488
+ var SS3_MAP = {
7489
+ A: { input: "", upArrow: true },
7490
+ B: { input: "", downArrow: true },
7491
+ C: { input: "", rightArrow: true },
7492
+ D: { input: "", leftArrow: true },
7493
+ H: { input: "", home: true },
7494
+ F: { input: "", end: true }
7495
+ };
7496
+ function tryEscapelessCsi(chunk, i) {
7497
+ if (chunk[i] !== "[") return null;
7498
+ for (const entry of CSI_TAIL_MAP) {
7499
+ const candidate = `[${entry.tail}`;
7500
+ if (chunk.slice(i, i + candidate.length) === candidate) {
7501
+ return { advance: candidate.length, ev: entry.ev };
7502
+ }
7503
+ }
7504
+ return null;
7505
+ }
7506
+ function isCsiFinal(ch) {
7507
+ const code = ch.charCodeAt(0);
7508
+ return code >= 64 && code <= 126;
7509
+ }
7510
+ function lookupCsi(tail) {
7511
+ for (const entry of CSI_TAIL_MAP) {
7512
+ if (entry.tail === tail) return entry.ev;
7513
+ }
7514
+ return null;
7515
+ }
7516
+ var StdinReader = class {
7517
+ subscribers = /* @__PURE__ */ new Set();
7518
+ state = "idle";
7519
+ /** Buffer for partial sequences across chunks. */
7520
+ csiBuf = "";
7521
+ /** Buffer for paste content. */
7522
+ pasteBuf = "";
7523
+ escTimer = null;
7524
+ started = false;
7525
+ /** The actual `data` listener — kept as a field so `stop()` can detach it. */
7526
+ listener = null;
7527
+ start() {
7528
+ if (this.started) return;
7529
+ if (!stdin.isTTY) {
7530
+ return;
7531
+ }
7532
+ stdin.setRawMode(true);
7533
+ stdin.setEncoding("utf8");
7534
+ stdin.resume();
7535
+ this.listener = (chunk) => this.handleChunk(typeof chunk === "string" ? chunk : chunk.toString("utf8"));
7536
+ stdin.on("data", this.listener);
7537
+ this.started = true;
7538
+ }
7539
+ stop() {
7540
+ if (!this.started) return;
7541
+ if (this.listener) {
7542
+ stdin.off("data", this.listener);
7543
+ this.listener = null;
7544
+ }
7545
+ if (stdin.isTTY) {
7546
+ try {
7547
+ stdin.setRawMode(false);
7548
+ } catch {
7549
+ }
7550
+ }
7551
+ stdin.pause();
7552
+ this.cancelEscTimer();
7553
+ this.state = "idle";
7554
+ this.csiBuf = "";
7555
+ this.pasteBuf = "";
7556
+ this.started = false;
7557
+ }
7558
+ /**
7559
+ * Subscribe to parsed key events. Returns an unsubscribe function.
7560
+ * Multiple subscribers are supported — every event fans out to all
7561
+ * of them; the React Context layer above uses one subscriber and
7562
+ * dispatches further to its own consumer list.
7563
+ */
7564
+ subscribe(fn) {
7565
+ this.subscribers.add(fn);
7566
+ return () => {
7567
+ this.subscribers.delete(fn);
7568
+ };
7569
+ }
7570
+ /**
7571
+ * Inject a chunk of bytes as if it came from stdin. Used by tests
7572
+ * to drive the parser without a real TTY.
7573
+ */
7574
+ feed(chunk) {
7575
+ this.handleChunk(chunk);
7576
+ }
7577
+ dispatch(ev) {
7578
+ for (const sub of this.subscribers) sub(ev);
7579
+ }
7580
+ cancelEscTimer() {
7581
+ if (this.escTimer) {
7582
+ clearTimeout(this.escTimer);
7583
+ this.escTimer = null;
7584
+ }
7585
+ }
7586
+ scheduleEscTimer() {
7587
+ this.cancelEscTimer();
7588
+ this.escTimer = setTimeout(() => {
7589
+ if (this.state === "esc") {
7590
+ this.state = "idle";
7591
+ this.dispatch({ input: "", escape: true });
7592
+ }
7593
+ }, ESC_TIMEOUT_MS);
7594
+ }
7595
+ handleChunk(chunk) {
7596
+ this.cancelEscTimer();
7597
+ let i = 0;
7598
+ while (i < chunk.length) {
7599
+ if (this.state === "paste") {
7600
+ const endA = chunk.indexOf(PASTE_END, i);
7601
+ const endB = chunk.indexOf(PASTE_END_BARE, i);
7602
+ let endIdx = -1;
7603
+ let endLen = 0;
7604
+ if (endA !== -1 && (endB === -1 || endA <= endB)) {
7605
+ endIdx = endA;
7606
+ endLen = PASTE_END.length;
7607
+ } else if (endB !== -1) {
7608
+ endIdx = endB;
7609
+ endLen = PASTE_END_BARE.length;
7610
+ }
7611
+ if (endIdx === -1) {
7612
+ this.pasteBuf += chunk.slice(i);
7613
+ i = chunk.length;
7614
+ break;
7615
+ }
7616
+ this.pasteBuf += chunk.slice(i, endIdx);
7617
+ this.dispatch({ input: this.pasteBuf, paste: true });
7618
+ this.pasteBuf = "";
7619
+ this.state = "idle";
7620
+ i = endIdx + endLen;
7621
+ continue;
7622
+ }
7623
+ if (this.state === "csi") {
7624
+ const ch2 = chunk[i];
7625
+ this.csiBuf += ch2;
7626
+ if (isCsiFinal(ch2)) {
7627
+ this.dispatchCsi(this.csiBuf);
7628
+ this.csiBuf = "";
7629
+ if (this.state === "csi") this.state = "idle";
7630
+ }
7631
+ i++;
7632
+ continue;
7633
+ }
7634
+ if (this.state === "ss3") {
7635
+ const ev = SS3_MAP[chunk[i]];
7636
+ if (ev) this.dispatch(ev);
7637
+ this.state = "idle";
7638
+ i++;
7639
+ continue;
7640
+ }
7641
+ if (this.state === "esc") {
7642
+ const ch2 = chunk[i];
7643
+ if (ch2 === "[") {
7644
+ this.state = "csi";
7645
+ this.csiBuf = "";
7646
+ i++;
7647
+ continue;
7648
+ }
7649
+ if (ch2 === "O") {
7650
+ this.state = "ss3";
7651
+ i++;
7652
+ continue;
7653
+ }
7654
+ this.dispatch({ input: ch2, meta: true });
7655
+ this.state = "idle";
7656
+ i++;
7657
+ continue;
7658
+ }
7659
+ const ch = chunk[i];
7660
+ if (ch === "\x1B") {
7661
+ this.state = "esc";
7662
+ i++;
7663
+ continue;
7664
+ }
7665
+ if (chunk.slice(i, i + PASTE_START_BARE.length) === PASTE_START_BARE) {
7666
+ this.state = "paste";
7667
+ this.pasteBuf = "";
7668
+ i += PASTE_START_BARE.length;
7669
+ continue;
7670
+ }
7671
+ const escapeless = tryEscapelessCsi(chunk, i);
7672
+ if (escapeless) {
7673
+ this.dispatch(escapeless.ev);
7674
+ i += escapeless.advance;
7675
+ continue;
7676
+ }
7677
+ if (ch === "\r") {
7678
+ this.dispatch({ input: "", return: true });
7679
+ i++;
7680
+ continue;
7681
+ }
7682
+ if (ch === "\n") {
7683
+ this.dispatch({ input: "j", ctrl: true });
7684
+ i++;
7685
+ continue;
7686
+ }
7687
+ if (ch === " ") {
7688
+ this.dispatch({ input: "", tab: true });
7689
+ i++;
7690
+ continue;
7691
+ }
7692
+ if (ch === "\x7F" || ch === "\b") {
7693
+ this.dispatch({ input: "", backspace: true });
7694
+ i++;
7695
+ continue;
7696
+ }
7697
+ if (ch === "") {
7698
+ this.dispatch({ input: "c", ctrl: true });
7699
+ i++;
7700
+ continue;
7701
+ }
7702
+ const code = ch.charCodeAt(0);
7703
+ if (code >= 1 && code <= 26) {
7704
+ const letter = String.fromCharCode(96 + code);
7705
+ this.dispatch({ input: letter, ctrl: true });
7706
+ i++;
7707
+ continue;
7708
+ }
7709
+ let end = i + 1;
7710
+ while (end < chunk.length) {
7711
+ const c = chunk[end];
7712
+ if (c === "\x1B" || c === "\r" || c === "\n" || c === " ") break;
7713
+ if (c === "\x7F" || c === "\b" || c === "") break;
7714
+ const cc = c.charCodeAt(0);
7715
+ if (cc >= 1 && cc <= 26) break;
7716
+ if (c === "[" && tryEscapelessCsi(chunk, end)) break;
7717
+ if (chunk.slice(end, end + PASTE_START_BARE.length) === PASTE_START_BARE) break;
7718
+ end++;
7719
+ }
7720
+ this.dispatch({ input: chunk.slice(i, end) });
7721
+ i = end;
7722
+ }
7723
+ if (this.state === "esc") {
7724
+ this.scheduleEscTimer();
7725
+ }
7726
+ }
7727
+ dispatchCsi(seq) {
7728
+ if (seq === "200~") {
7729
+ this.state = "paste";
7730
+ this.pasteBuf = "";
7731
+ return;
7732
+ }
7733
+ if (seq === "201~") {
7734
+ return;
7735
+ }
7736
+ const ev = lookupCsi(seq);
7737
+ if (ev) this.dispatch(ev);
7738
+ }
7739
+ };
7740
+ var singleton = null;
7741
+ function getStdinReader() {
7742
+ if (!singleton) singleton = new StdinReader();
7743
+ return singleton;
7744
+ }
7745
+
7746
+ // src/cli/ui/keystroke-context.tsx
7747
+ var KeystrokeContext = createContext(null);
7748
+ function KeystrokeProvider({
7749
+ children,
7750
+ reader: providedReader
7751
+ }) {
7752
+ const handlersRef = useRef(/* @__PURE__ */ new Set());
7753
+ const busRef = useRef(null);
7754
+ if (busRef.current === null) {
7755
+ busRef.current = {
7756
+ subscribe(handler) {
7757
+ handlersRef.current.add(handler);
7758
+ return () => {
7759
+ handlersRef.current.delete(handler);
7760
+ };
7761
+ }
7762
+ };
7763
+ }
7764
+ useEffect(() => {
7765
+ const reader = providedReader ?? getStdinReader();
7766
+ reader.start();
7767
+ const unsubscribe = reader.subscribe((ev) => {
7768
+ for (const fn of [...handlersRef.current]) fn(ev);
7769
+ });
7770
+ return () => {
7771
+ unsubscribe();
7772
+ };
7773
+ }, [providedReader]);
7774
+ return /* @__PURE__ */ React2.createElement(KeystrokeContext.Provider, { value: busRef.current }, children);
7775
+ }
7776
+ function useKeystroke(handler, isActive = true) {
7777
+ const bus = useContext(KeystrokeContext);
7778
+ const handlerRef = useRef(handler);
7779
+ handlerRef.current = handler;
7780
+ useEffect(() => {
7781
+ if (!bus || !isActive) return void 0;
7782
+ return bus.subscribe((ev) => handlerRef.current(ev));
7783
+ }, [bus, isActive]);
7784
+ }
7446
7785
 
7447
7786
  // src/cli/ui/Select.tsx
7448
- import { Box as Box2, Text as Text2, useInput } from "ink";
7449
- import React2, { useState } from "react";
7450
7787
  function SingleSelect({
7451
7788
  items,
7452
7789
  initialValue,
@@ -7459,19 +7796,20 @@ function SingleSelect({
7459
7796
  items.findIndex((i) => i.value === initialValue && !i.disabled)
7460
7797
  );
7461
7798
  const [index, setIndex] = useState(initialIndex === -1 ? 0 : initialIndex);
7462
- useInput((_input, key) => {
7463
- if (key.upArrow) {
7799
+ useKeystroke((ev) => {
7800
+ if (ev.paste) return;
7801
+ if (ev.upArrow) {
7464
7802
  setIndex((i) => findNextEnabled(items, i, -1));
7465
- } else if (key.downArrow) {
7803
+ } else if (ev.downArrow) {
7466
7804
  setIndex((i) => findNextEnabled(items, i, 1));
7467
- } else if (key.return) {
7805
+ } else if (ev.return) {
7468
7806
  const chosen = items[index];
7469
7807
  if (chosen && !chosen.disabled) onSubmit(chosen.value);
7470
- } else if (key.escape && onCancel) {
7808
+ } else if (ev.escape && onCancel) {
7471
7809
  onCancel();
7472
7810
  }
7473
7811
  });
7474
- return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column" }, items.map((item, i) => /* @__PURE__ */ React2.createElement(
7812
+ return /* @__PURE__ */ React3.createElement(Box2, { flexDirection: "column" }, items.map((item, i) => /* @__PURE__ */ React3.createElement(
7475
7813
  SelectRow,
7476
7814
  {
7477
7815
  key: item.value,
@@ -7479,7 +7817,7 @@ function SingleSelect({
7479
7817
  active: i === index,
7480
7818
  marker: i === index ? "\u25B8" : " "
7481
7819
  }
7482
- )), footer ? /* @__PURE__ */ React2.createElement(Box2, { marginTop: 1 }, /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, footer)) : null);
7820
+ )), footer ? /* @__PURE__ */ React3.createElement(Box2, { marginTop: 1 }, /* @__PURE__ */ React3.createElement(Text2, { dimColor: true }, footer)) : null);
7483
7821
  }
7484
7822
  function MultiSelect({
7485
7823
  items,
@@ -7493,12 +7831,13 @@ function MultiSelect({
7493
7831
  return first === -1 ? 0 : first;
7494
7832
  });
7495
7833
  const [selected, setSelected] = useState(new Set(initialSelected));
7496
- useInput((input, key) => {
7497
- if (key.upArrow) {
7834
+ useKeystroke((ev) => {
7835
+ if (ev.paste) return;
7836
+ if (ev.upArrow) {
7498
7837
  setIndex((i) => findNextEnabled(items, i, -1));
7499
- } else if (key.downArrow) {
7838
+ } else if (ev.downArrow) {
7500
7839
  setIndex((i) => findNextEnabled(items, i, 1));
7501
- } else if (input === " ") {
7840
+ } else if (ev.input === " ") {
7502
7841
  const item = items[index];
7503
7842
  if (!item || item.disabled) return;
7504
7843
  setSelected((prev) => {
@@ -7507,17 +7846,17 @@ function MultiSelect({
7507
7846
  else next.add(item.value);
7508
7847
  return next;
7509
7848
  });
7510
- } else if (key.return) {
7849
+ } else if (ev.return) {
7511
7850
  const ordered = items.filter((i) => selected.has(i.value)).map((i) => i.value);
7512
7851
  onSubmit(ordered);
7513
- } else if (key.escape && onCancel) {
7852
+ } else if (ev.escape && onCancel) {
7514
7853
  onCancel();
7515
7854
  }
7516
7855
  });
7517
- return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column" }, items.map((item, i) => {
7856
+ return /* @__PURE__ */ React3.createElement(Box2, { flexDirection: "column" }, items.map((item, i) => {
7518
7857
  const checked = selected.has(item.value);
7519
7858
  const marker = checked ? "[x]" : "[ ]";
7520
- return /* @__PURE__ */ React2.createElement(
7859
+ return /* @__PURE__ */ React3.createElement(
7521
7860
  SelectRow,
7522
7861
  {
7523
7862
  key: item.value,
@@ -7526,7 +7865,7 @@ function MultiSelect({
7526
7865
  marker: `${i === index ? "\u25B8" : " "} ${marker}`
7527
7866
  }
7528
7867
  );
7529
- }), footer ? /* @__PURE__ */ React2.createElement(Box2, { marginTop: 1 }, /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, footer)) : null);
7868
+ }), footer ? /* @__PURE__ */ React3.createElement(Box2, { marginTop: 1 }, /* @__PURE__ */ React3.createElement(Text2, { dimColor: true }, footer)) : null);
7530
7869
  }
7531
7870
  function SelectRow({
7532
7871
  item,
@@ -7534,7 +7873,7 @@ function SelectRow({
7534
7873
  marker
7535
7874
  }) {
7536
7875
  const color = item.disabled ? "gray" : active ? "cyan" : void 0;
7537
- return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column" }, /* @__PURE__ */ React2.createElement(Box2, null, /* @__PURE__ */ React2.createElement(Text2, { color }, marker, " ", item.label)), item.hint ? /* @__PURE__ */ React2.createElement(Box2, { paddingLeft: marker.length + 1 }, /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, item.hint)) : null);
7876
+ return /* @__PURE__ */ React3.createElement(Box2, { flexDirection: "column" }, /* @__PURE__ */ React3.createElement(Box2, null, /* @__PURE__ */ React3.createElement(Text2, { color }, marker, " ", item.label)), item.hint ? /* @__PURE__ */ React3.createElement(Box2, { paddingLeft: marker.length + 1 }, /* @__PURE__ */ React3.createElement(Text2, { dimColor: true }, item.hint)) : null);
7538
7877
  }
7539
7878
  function findNextEnabled(items, from, step) {
7540
7879
  if (items.length === 0) return 0;
@@ -7567,7 +7906,7 @@ function ChoiceConfirmInner({ question, options, allowCustom, onChoose }) {
7567
7906
  label: "Cancel \u2014 drop the question",
7568
7907
  hint: "Model stops and asks what you want instead."
7569
7908
  });
7570
- return /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", borderStyle: "round", borderColor: "magenta", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React3.createElement(Box3, null, /* @__PURE__ */ React3.createElement(Text3, { bold: true, color: "magenta" }, "\u{1F500} the model is asking you to pick")), /* @__PURE__ */ React3.createElement(Box3, { marginTop: 1 }, /* @__PURE__ */ React3.createElement(Text3, null, question)), /* @__PURE__ */ React3.createElement(Box3, { marginTop: 1 }, /* @__PURE__ */ React3.createElement(
7909
+ return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React4.createElement(Box3, null, /* @__PURE__ */ React4.createElement(Text3, { bold: true, color: "magenta" }, "\u{1F500} the model is asking you to pick")), /* @__PURE__ */ React4.createElement(Box3, { marginTop: 1 }, /* @__PURE__ */ React4.createElement(Text3, null, question)), /* @__PURE__ */ React4.createElement(Box3, { marginTop: 1 }, /* @__PURE__ */ React4.createElement(
7571
7910
  SingleSelect,
7572
7911
  {
7573
7912
  initialValue: options[0]?.id,
@@ -7582,11 +7921,11 @@ function ChoiceConfirmInner({ question, options, allowCustom, onChoose }) {
7582
7921
  }
7583
7922
  )));
7584
7923
  }
7585
- var ChoiceConfirm = React3.memo(ChoiceConfirmInner);
7924
+ var ChoiceConfirm = React4.memo(ChoiceConfirmInner);
7586
7925
 
7587
7926
  // src/cli/ui/EditConfirm.tsx
7588
- import { Box as Box4, Text as Text4, useInput as useInput2, useStdout } from "ink";
7589
- import React4, { useMemo, useState as useState2 } from "react";
7927
+ import { Box as Box4, Text as Text4, useStdout } from "ink";
7928
+ import React5, { useMemo, useState as useState2 } from "react";
7590
7929
 
7591
7930
  // src/code/diff-preview.ts
7592
7931
  function formatEditBlockDiff(block, opts = {}) {
@@ -7671,7 +8010,10 @@ function EditConfirm({ block, onChoose }) {
7671
8010
  const [scroll, setScroll] = useState2(0);
7672
8011
  const maxScroll = Math.max(0, allLines.length - budget);
7673
8012
  const effectiveScroll = Math.min(scroll, maxScroll);
7674
- useInput2((input, key) => {
8013
+ useKeystroke((ev) => {
8014
+ if (ev.paste) return;
8015
+ const input = ev.input;
8016
+ const key = ev;
7675
8017
  if (key.return || input === "y") {
7676
8018
  onChoose("apply");
7677
8019
  return;
@@ -7722,17 +8064,17 @@ function EditConfirm({ block, onChoose }) {
7722
8064
  const hiddenBelow = Math.max(0, allLines.length - effectiveScroll - budget);
7723
8065
  const totalLines = allLines.length;
7724
8066
  const showScrollHud = hiddenAbove + hiddenBelow > 0;
7725
- return /* @__PURE__ */ React4.createElement(Box4, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React4.createElement(Box4, null, /* @__PURE__ */ React4.createElement(Text4, { bold: true, color: "yellow" }, "\u25B8 model wants to edit a file")), /* @__PURE__ */ React4.createElement(Box4, null, /* @__PURE__ */ React4.createElement(Text4, { 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__ */ React4.createElement(Box4, { marginTop: 1 }, /* @__PURE__ */ React4.createElement(Text4, null, /* @__PURE__ */ React4.createElement(Text4, { color: isNew ? "green" : "yellow", bold: true }, `[${tag}] `), /* @__PURE__ */ React4.createElement(Text4, { color: "cyan" }, block.path), /* @__PURE__ */ React4.createElement(Text4, { dimColor: true }, ` (-${removed} +${added} lines)`), showScrollHud ? /* @__PURE__ */ React4.createElement(Text4, { dimColor: true }, ` \xB7 viewing ${effectiveScroll + 1}-${effectiveScroll + visibleLines.length}/${totalLines}`) : null)), hiddenAbove > 0 ? /* @__PURE__ */ React4.createElement(
8067
+ return /* @__PURE__ */ React5.createElement(Box4, { flexDirection: "column", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React5.createElement(Box4, null, /* @__PURE__ */ React5.createElement(Text4, { bold: true, color: "yellow" }, "\u25B8 model wants to edit a file")), /* @__PURE__ */ React5.createElement(Box4, null, /* @__PURE__ */ React5.createElement(Text4, { 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__ */ React5.createElement(Box4, { marginTop: 1 }, /* @__PURE__ */ React5.createElement(Text4, null, /* @__PURE__ */ React5.createElement(Text4, { color: isNew ? "green" : "yellow", bold: true }, `[${tag}] `), /* @__PURE__ */ React5.createElement(Text4, { color: "cyan" }, block.path), /* @__PURE__ */ React5.createElement(Text4, { dimColor: true }, ` (-${removed} +${added} lines)`), showScrollHud ? /* @__PURE__ */ React5.createElement(Text4, { dimColor: true }, ` \xB7 viewing ${effectiveScroll + 1}-${effectiveScroll + visibleLines.length}/${totalLines}`) : null)), hiddenAbove > 0 ? /* @__PURE__ */ React5.createElement(
7726
8068
  Text4,
7727
8069
  {
7728
8070
  dimColor: true
7729
8071
  },
7730
8072
  ` \u2191 ${hiddenAbove} line${hiddenAbove === 1 ? "" : "s"} above (\u2191/k or PgUp)`
7731
- ) : null, /* @__PURE__ */ React4.createElement(Box4, { marginTop: hiddenAbove > 0 ? 0 : 1, flexDirection: "column" }, visibleLines.map((line, i) => {
8073
+ ) : null, /* @__PURE__ */ React5.createElement(Box4, { marginTop: hiddenAbove > 0 ? 0 : 1, flexDirection: "column" }, visibleLines.map((line, i) => {
7732
8074
  const trimmed = line.trimStart();
7733
8075
  const color = trimmed.startsWith("+") ? "green" : trimmed.startsWith("-") ? "red" : void 0;
7734
8076
  const dim = !color;
7735
- return /* @__PURE__ */ React4.createElement(
8077
+ return /* @__PURE__ */ React5.createElement(
7736
8078
  Text4,
7737
8079
  {
7738
8080
  key: `diff-${effectiveScroll}-${i}`,
@@ -7741,22 +8083,22 @@ function EditConfirm({ block, onChoose }) {
7741
8083
  },
7742
8084
  line
7743
8085
  );
7744
- })), hiddenBelow > 0 ? /* @__PURE__ */ React4.createElement(
8086
+ })), hiddenBelow > 0 ? /* @__PURE__ */ React5.createElement(
7745
8087
  Text4,
7746
8088
  {
7747
8089
  dimColor: true
7748
8090
  },
7749
8091
  ` \u2193 ${hiddenBelow} line${hiddenBelow === 1 ? "" : "s"} below (\u2193/j or Space/PgDn)`
7750
- ) : null, /* @__PURE__ */ React4.createElement(Box4, { marginTop: 1 }, /* @__PURE__ */ React4.createElement(Text4, { dimColor: true }, "[", /* @__PURE__ */ React4.createElement(Text4, { color: "cyan", bold: true }, "y"), "/Enter] apply \xB7 [", /* @__PURE__ */ React4.createElement(Text4, { color: "cyan", bold: true }, "n"), "] reject \xB7 [", /* @__PURE__ */ React4.createElement(Text4, { color: "cyan", bold: true }, "a"), "] apply rest \xB7 [", /* @__PURE__ */ React4.createElement(Text4, { color: "cyan", bold: true }, "A"), "] flip AUTO \xB7 [", /* @__PURE__ */ React4.createElement(Text4, { color: "cyan", bold: true }, "\u2191\u2193/Space"), "] scroll \xB7 [Esc] abort")));
8092
+ ) : null, /* @__PURE__ */ React5.createElement(Box4, { marginTop: 1 }, /* @__PURE__ */ React5.createElement(Text4, { dimColor: true }, "[", /* @__PURE__ */ React5.createElement(Text4, { color: "cyan", bold: true }, "y"), "/Enter] apply \xB7 [", /* @__PURE__ */ React5.createElement(Text4, { color: "cyan", bold: true }, "n"), "] reject \xB7 [", /* @__PURE__ */ React5.createElement(Text4, { color: "cyan", bold: true }, "a"), "] apply rest \xB7 [", /* @__PURE__ */ React5.createElement(Text4, { color: "cyan", bold: true }, "A"), "] flip AUTO \xB7 [", /* @__PURE__ */ React5.createElement(Text4, { color: "cyan", bold: true }, "\u2191\u2193/Space"), "] scroll \xB7 [Esc] abort")));
7751
8093
  }
7752
8094
 
7753
8095
  // src/cli/ui/EventLog.tsx
7754
8096
  import { Box as Box8, Text as Text8, useStdout as useStdout2 } from "ink";
7755
- import React9 from "react";
8097
+ import React10 from "react";
7756
8098
 
7757
8099
  // src/cli/ui/PlanStateBlock.tsx
7758
8100
  import { Box as Box5, Text as Text5 } from "ink";
7759
- import React5 from "react";
8101
+ import React6 from "react";
7760
8102
  function PlanStateBlock({ planState }) {
7761
8103
  const fields = [];
7762
8104
  if (planState.subgoals.length) fields.push(["subgoals", planState.subgoals, "cyan", false]);
@@ -7767,12 +8109,12 @@ function PlanStateBlock({ planState }) {
7767
8109
  if (planState.rejectedPaths.length)
7768
8110
  fields.push(["rejected", planState.rejectedPaths, "red", true]);
7769
8111
  if (fields.length === 0) return null;
7770
- return /* @__PURE__ */ React5.createElement(Box5, { flexDirection: "column", marginBottom: 1 }, fields.map(([label, items, color, dim]) => /* @__PURE__ */ React5.createElement(Text5, { key: label }, /* @__PURE__ */ React5.createElement(Text5, { color, bold: true, dimColor: dim }, "\u2039 ", label), /* @__PURE__ */ React5.createElement(Text5, { dimColor: true }, ` (${items.length})`), /* @__PURE__ */ React5.createElement(Text5, null, `: ${items.join(" \xB7 ")}`))));
8112
+ return /* @__PURE__ */ React6.createElement(Box5, { flexDirection: "column", marginBottom: 1 }, fields.map(([label, items, color, dim]) => /* @__PURE__ */ React6.createElement(Text5, { key: label }, /* @__PURE__ */ React6.createElement(Text5, { color, bold: true, dimColor: dim }, "\u2039 ", label), /* @__PURE__ */ React6.createElement(Text5, { dimColor: true }, ` (${items.length})`), /* @__PURE__ */ React6.createElement(Text5, null, `: ${items.join(" \xB7 ")}`))));
7771
8113
  }
7772
8114
 
7773
8115
  // src/cli/ui/PlanStepList.tsx
7774
8116
  import { Box as Box6, Text as Text6 } from "ink";
7775
- import React6 from "react";
8117
+ import React7 from "react";
7776
8118
  function riskDots(risk) {
7777
8119
  switch (risk) {
7778
8120
  case "high":
@@ -7811,25 +8153,25 @@ function PlanStepListInner({ steps, statuses, focusStepId }) {
7811
8153
  { length: steps.length },
7812
8154
  (_, i) => getStatus(steps[i].id, statuses)
7813
8155
  ).filter((s) => s === "done").length;
7814
- return /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Box6, null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, `${steps.length} step${steps.length === 1 ? "" : "s"}`, doneCount > 0 ? ` \xB7 ${doneCount} done` : "", hasAnyRisk ? " \xB7 risk: " : ""), hasAnyRisk ? /* @__PURE__ */ React6.createElement(RiskLegend, null) : null), /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column", marginTop: 1 }, steps.map((step) => {
8156
+ return /* @__PURE__ */ React7.createElement(Box6, { flexDirection: "column" }, /* @__PURE__ */ React7.createElement(Box6, null, /* @__PURE__ */ React7.createElement(Text6, { dimColor: true }, `${steps.length} step${steps.length === 1 ? "" : "s"}`, doneCount > 0 ? ` \xB7 ${doneCount} done` : "", hasAnyRisk ? " \xB7 risk: " : ""), hasAnyRisk ? /* @__PURE__ */ React7.createElement(RiskLegend, null) : null), /* @__PURE__ */ React7.createElement(Box6, { flexDirection: "column", marginTop: 1 }, steps.map((step) => {
7815
8157
  const status2 = getStatus(step.id, statuses);
7816
8158
  const focus = focusStepId === step.id;
7817
8159
  const risk = riskDots(step.risk);
7818
8160
  const glyph = statusGlyph(status2);
7819
8161
  const titleDim = status2 === "done" || status2 === "skipped";
7820
- return /* @__PURE__ */ React6.createElement(Box6, { key: step.id }, /* @__PURE__ */ React6.createElement(Text6, { color: focus ? "cyan" : "gray", bold: focus }, focus ? "\u203A " : " "), /* @__PURE__ */ React6.createElement(Text6, { color: risk.color, bold: true }, risk.dots), /* @__PURE__ */ React6.createElement(Text6, { color: glyph.color, bold: true }, ` ${glyph.glyph} `), /* @__PURE__ */ React6.createElement(Text6, { dimColor: titleDim }, `${step.id} \xB7 ${step.title}`));
8162
+ return /* @__PURE__ */ React7.createElement(Box6, { key: step.id }, /* @__PURE__ */ React7.createElement(Text6, { color: focus ? "cyan" : "gray", bold: focus }, focus ? "\u203A " : " "), /* @__PURE__ */ React7.createElement(Text6, { color: risk.color, bold: true }, risk.dots), /* @__PURE__ */ React7.createElement(Text6, { color: glyph.color, bold: true }, ` ${glyph.glyph} `), /* @__PURE__ */ React7.createElement(Text6, { dimColor: titleDim }, `${step.id} \xB7 ${step.title}`));
7821
8163
  })));
7822
8164
  }
7823
8165
  function RiskLegend() {
7824
- return /* @__PURE__ */ React6.createElement(Box6, null, /* @__PURE__ */ React6.createElement(Text6, { color: "green" }, "\u25CF"), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " low "), /* @__PURE__ */ React6.createElement(Text6, { color: "yellow" }, "\u25CF\u25CF"), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " med "), /* @__PURE__ */ React6.createElement(Text6, { color: "red" }, "\u25CF\u25CF\u25CF"), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " high"));
8166
+ return /* @__PURE__ */ React7.createElement(Box6, null, /* @__PURE__ */ React7.createElement(Text6, { color: "green" }, "\u25CF"), /* @__PURE__ */ React7.createElement(Text6, { dimColor: true }, " low "), /* @__PURE__ */ React7.createElement(Text6, { color: "yellow" }, "\u25CF\u25CF"), /* @__PURE__ */ React7.createElement(Text6, { dimColor: true }, " med "), /* @__PURE__ */ React7.createElement(Text6, { color: "red" }, "\u25CF\u25CF\u25CF"), /* @__PURE__ */ React7.createElement(Text6, { dimColor: true }, " high"));
7825
8167
  }
7826
- var PlanStepList = React6.memo(PlanStepListInner);
8168
+ var PlanStepList = React7.memo(PlanStepListInner);
7827
8169
 
7828
8170
  // src/cli/ui/markdown.tsx
7829
8171
  import { readFileSync as readFileSync13, statSync as statSync6 } from "fs";
7830
8172
  import { isAbsolute as isAbsolute4, join as join11 } from "path";
7831
8173
  import { Box as Box7, Text as Text7 } from "ink";
7832
- import React7 from "react";
8174
+ import React8 from "react";
7833
8175
  var SUPERSCRIPT = {
7834
8176
  "0": "\u2070",
7835
8177
  "1": "\xB9",
@@ -8084,67 +8426,67 @@ function InlineMd({
8084
8426
  for (const m of text.matchAll(INLINE_RE)) {
8085
8427
  const start = m.index ?? 0;
8086
8428
  if (start > last) {
8087
- parts.push(/* @__PURE__ */ React7.createElement(Text7, { key: `t${idx++}` }, text.slice(last, start)));
8429
+ parts.push(/* @__PURE__ */ React8.createElement(Text7, { key: `t${idx++}` }, text.slice(last, start)));
8088
8430
  }
8089
8431
  if (m[2] !== void 0 && m[3] !== void 0) {
8090
8432
  const linkText = m[2];
8091
8433
  const url = m[3];
8092
8434
  if (isExternalUrl(url)) {
8093
8435
  parts.push(
8094
- /* @__PURE__ */ React7.createElement(Text7, { key: `l${idx++}`, color: "blue", underline: true }, linkText)
8436
+ /* @__PURE__ */ React8.createElement(Text7, { key: `l${idx++}`, color: "blue", underline: true }, linkText)
8095
8437
  );
8096
8438
  } else {
8097
8439
  const status2 = citations?.get(url);
8098
8440
  if (status2 && !status2.ok) {
8099
8441
  parts.push(
8100
- /* @__PURE__ */ React7.createElement(Text7, { key: `l${idx++}`, color: "red", strikethrough: true }, `${linkText} \u2717`)
8442
+ /* @__PURE__ */ React8.createElement(Text7, { key: `l${idx++}`, color: "red", strikethrough: true }, `${linkText} \u2717`)
8101
8443
  );
8102
8444
  } else {
8103
8445
  parts.push(
8104
- /* @__PURE__ */ React7.createElement(Text7, { key: `l${idx++}`, color: "cyan", underline: true }, linkText)
8446
+ /* @__PURE__ */ React8.createElement(Text7, { key: `l${idx++}`, color: "cyan", underline: true }, linkText)
8105
8447
  );
8106
8448
  }
8107
8449
  }
8108
8450
  } else if (m[4] !== void 0) {
8109
8451
  parts.push(
8110
- /* @__PURE__ */ React7.createElement(Text7, { key: `bi${idx++}`, bold: true, italic: true }, m[4])
8452
+ /* @__PURE__ */ React8.createElement(Text7, { key: `bi${idx++}`, bold: true, italic: true }, m[4])
8111
8453
  );
8112
8454
  } else if (m[5] !== void 0) {
8113
8455
  parts.push(
8114
- /* @__PURE__ */ React7.createElement(Text7, { key: `b${idx++}`, bold: true }, m[5])
8456
+ /* @__PURE__ */ React8.createElement(Text7, { key: `b${idx++}`, bold: true }, m[5])
8115
8457
  );
8116
8458
  } else if (m[6] !== void 0) {
8117
8459
  const stripped = m[6].replace(/^(\w+)\s+/, "");
8118
8460
  parts.push(
8119
- /* @__PURE__ */ React7.createElement(Text7, { key: `c${idx++}`, color: "yellow" }, stripped)
8461
+ /* @__PURE__ */ React8.createElement(Text7, { key: `c${idx++}`, color: "yellow" }, stripped)
8120
8462
  );
8121
8463
  } else if (m[7] !== void 0) {
8122
8464
  parts.push(
8123
- /* @__PURE__ */ React7.createElement(Text7, { key: `c${idx++}`, color: "yellow" }, m[7])
8465
+ /* @__PURE__ */ React8.createElement(Text7, { key: `c${idx++}`, color: "yellow" }, m[7])
8124
8466
  );
8125
8467
  } else if (m[8] !== void 0) {
8126
8468
  parts.push(
8127
- /* @__PURE__ */ React7.createElement(Text7, { key: `s${idx++}`, strikethrough: true, dimColor: true }, m[8])
8469
+ /* @__PURE__ */ React8.createElement(Text7, { key: `s${idx++}`, strikethrough: true, dimColor: true }, m[8])
8128
8470
  );
8129
8471
  } else if (m[9] !== void 0) {
8130
8472
  parts.push(
8131
- /* @__PURE__ */ React7.createElement(Text7, { key: `i${idx++}`, italic: true }, m[9])
8473
+ /* @__PURE__ */ React8.createElement(Text7, { key: `i${idx++}`, italic: true }, m[9])
8132
8474
  );
8133
8475
  } else if (m[10] !== void 0) {
8134
- parts.push(/* @__PURE__ */ React7.createElement(Text7, { key: `esc${idx++}` }, m[10]));
8476
+ parts.push(/* @__PURE__ */ React8.createElement(Text7, { key: `esc${idx++}` }, m[10]));
8135
8477
  }
8136
8478
  last = start + m[0].length;
8137
8479
  }
8138
8480
  if (last < text.length) {
8139
- parts.push(/* @__PURE__ */ React7.createElement(Text7, { key: `t${idx++}` }, text.slice(last)));
8481
+ parts.push(/* @__PURE__ */ React8.createElement(Text7, { key: `t${idx++}` }, text.slice(last)));
8140
8482
  }
8141
8483
  if (padTo !== void 0) {
8142
8484
  const seen = visibleWidth(text);
8143
8485
  if (seen < padTo) {
8144
- parts.push(/* @__PURE__ */ React7.createElement(Text7, { key: `pad${idx++}` }, " ".repeat(padTo - seen)));
8486
+ parts.push(/* @__PURE__ */ React8.createElement(Text7, { key: `pad${idx++}` }, " ".repeat(padTo - seen)));
8145
8487
  }
8146
8488
  }
8147
- return /* @__PURE__ */ React7.createElement(Text7, null, parts);
8489
+ return /* @__PURE__ */ React8.createElement(Text7, null, parts);
8148
8490
  }
8149
8491
  function stripInlineMarkup(s) {
8150
8492
  return s.replace(
@@ -8383,34 +8725,34 @@ function parseBulletItem(raw) {
8383
8725
  function BlockView({ block, citations }) {
8384
8726
  switch (block.kind) {
8385
8727
  case "heading":
8386
- return /* @__PURE__ */ React7.createElement(Text7, { bold: true, color: "cyan" }, /* @__PURE__ */ React7.createElement(InlineMd, { text: block.text, citations }));
8728
+ return /* @__PURE__ */ React8.createElement(Text7, { bold: true, color: "cyan" }, /* @__PURE__ */ React8.createElement(InlineMd, { text: block.text, citations }));
8387
8729
  case "paragraph":
8388
- return /* @__PURE__ */ React7.createElement(ParagraphView, { text: block.text, citations });
8730
+ return /* @__PURE__ */ React8.createElement(ParagraphView, { text: block.text, citations });
8389
8731
  case "bullet":
8390
- return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column" }, block.items.map((item, i) => /* @__PURE__ */ React7.createElement(Box7, { key: `${i}-${item.text.slice(0, 24)}` }, /* @__PURE__ */ React7.createElement(Text7, { color: item.task === "done" ? "green" : "cyan" }, bulletPrefix(block, i, item)), item.task === "done" ? /* @__PURE__ */ React7.createElement(Text7, { strikethrough: true, dimColor: true }, /* @__PURE__ */ React7.createElement(InlineMd, { text: item.text, citations })) : /* @__PURE__ */ React7.createElement(InlineMd, { text: item.text, citations }))));
8732
+ return /* @__PURE__ */ React8.createElement(Box7, { flexDirection: "column" }, block.items.map((item, i) => /* @__PURE__ */ React8.createElement(Box7, { key: `${i}-${item.text.slice(0, 24)}` }, /* @__PURE__ */ React8.createElement(Text7, { color: item.task === "done" ? "green" : "cyan" }, bulletPrefix(block, i, item)), item.task === "done" ? /* @__PURE__ */ React8.createElement(Text7, { strikethrough: true, dimColor: true }, /* @__PURE__ */ React8.createElement(InlineMd, { text: item.text, citations })) : /* @__PURE__ */ React8.createElement(InlineMd, { text: item.text, citations }))));
8391
8733
  case "quote":
8392
- return /* @__PURE__ */ React7.createElement(BlockquoteView, { block, citations });
8734
+ return /* @__PURE__ */ React8.createElement(BlockquoteView, { block, citations });
8393
8735
  case "code":
8394
8736
  if (DIAGRAM_LANGS.has(block.lang.toLowerCase())) {
8395
- return /* @__PURE__ */ React7.createElement(DiagramCodeBlock, { lang: block.lang, text: block.text });
8737
+ return /* @__PURE__ */ React8.createElement(DiagramCodeBlock, { lang: block.lang, text: block.text });
8396
8738
  }
8397
- return /* @__PURE__ */ React7.createElement(Box7, { borderStyle: "single", borderColor: "gray", paddingX: 1 }, /* @__PURE__ */ React7.createElement(Text7, { color: "yellow" }, block.text));
8739
+ return /* @__PURE__ */ React8.createElement(Box7, { borderStyle: "single", borderColor: "gray", paddingX: 1 }, /* @__PURE__ */ React8.createElement(Text7, { color: "yellow" }, block.text));
8398
8740
  case "edit-block":
8399
- return /* @__PURE__ */ React7.createElement(EditBlockRow, { block });
8741
+ return /* @__PURE__ */ React8.createElement(EditBlockRow, { block });
8400
8742
  case "table":
8401
- return /* @__PURE__ */ React7.createElement(TableBlockRow, { block, citations });
8743
+ return /* @__PURE__ */ React8.createElement(TableBlockRow, { block, citations });
8402
8744
  case "hr":
8403
- return /* @__PURE__ */ React7.createElement(Text7, { 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");
8745
+ return /* @__PURE__ */ React8.createElement(Text7, { 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");
8404
8746
  }
8405
8747
  }
8406
8748
  function ParagraphView({ text, citations }) {
8407
8749
  if (!text.includes("\n")) {
8408
- return /* @__PURE__ */ React7.createElement(InlineMd, { text, citations });
8750
+ return /* @__PURE__ */ React8.createElement(InlineMd, { text, citations });
8409
8751
  }
8410
8752
  const rows = text.split("\n");
8411
- return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column" }, rows.map((row2, i) => (
8753
+ return /* @__PURE__ */ React8.createElement(Box7, { flexDirection: "column" }, rows.map((row2, i) => (
8412
8754
  // biome-ignore lint/suspicious/noArrayIndexKey: hard-break rows are source-ordered and never reorder
8413
- /* @__PURE__ */ React7.createElement(InlineMd, { key: `ln-${i}`, text: row2, citations })
8755
+ /* @__PURE__ */ React8.createElement(InlineMd, { key: `ln-${i}`, text: row2, citations })
8414
8756
  )));
8415
8757
  }
8416
8758
  function bulletPrefix(block, i, item) {
@@ -8423,7 +8765,7 @@ function BlockquoteView({
8423
8765
  block,
8424
8766
  citations
8425
8767
  }) {
8426
- return /* @__PURE__ */ React7.createElement(
8768
+ return /* @__PURE__ */ React8.createElement(
8427
8769
  Box7,
8428
8770
  {
8429
8771
  borderStyle: "single",
@@ -8436,7 +8778,7 @@ function BlockquoteView({
8436
8778
  flexDirection: "column",
8437
8779
  gap: 1
8438
8780
  },
8439
- block.children.map((child, i) => /* @__PURE__ */ React7.createElement(BlockView, { key: `q-${i}-${child.kind}`, block: child, citations }))
8781
+ block.children.map((child, i) => /* @__PURE__ */ React8.createElement(BlockView, { key: `q-${i}-${child.kind}`, block: child, citations }))
8440
8782
  );
8441
8783
  }
8442
8784
  function splitTableRow(line) {
@@ -8454,14 +8796,14 @@ function TableBlockRow({ block, citations }) {
8454
8796
  widths.push(Math.min(40, Math.max(3, ...cellLengths)));
8455
8797
  }
8456
8798
  const separator = widths.map((w) => "\u2500".repeat(w)).join("\u2500\u253C\u2500");
8457
- return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column" }, /* @__PURE__ */ React7.createElement(Box7, null, block.header.map((cell, ci) => (
8799
+ return /* @__PURE__ */ React8.createElement(Box7, { flexDirection: "column" }, /* @__PURE__ */ React8.createElement(Box7, null, block.header.map((cell, ci) => (
8458
8800
  // biome-ignore lint/suspicious/noArrayIndexKey: table columns never reorder — derived from a static header array
8459
- /* @__PURE__ */ React7.createElement(Text7, { key: `h-${ci}`, bold: true, color: "cyan" }, /* @__PURE__ */ React7.createElement(InlineMd, { text: cell, padTo: widths[ci] ?? 3, citations }), ci < colCount - 1 ? " \u2502 " : "")
8460
- ))), /* @__PURE__ */ React7.createElement(Text7, { dimColor: true }, separator), block.rows.map((row2, ri) => (
8801
+ /* @__PURE__ */ React8.createElement(Text7, { key: `h-${ci}`, bold: true, color: "cyan" }, /* @__PURE__ */ React8.createElement(InlineMd, { text: cell, padTo: widths[ci] ?? 3, citations }), ci < colCount - 1 ? " \u2502 " : "")
8802
+ ))), /* @__PURE__ */ React8.createElement(Text7, { dimColor: true }, separator), block.rows.map((row2, ri) => (
8461
8803
  // biome-ignore lint/suspicious/noArrayIndexKey: table rows render in source order and don't reorder
8462
- /* @__PURE__ */ React7.createElement(Box7, { key: `r-${ri}` }, Array.from({ length: colCount }).map((_, ci) => (
8804
+ /* @__PURE__ */ React8.createElement(Box7, { key: `r-${ri}` }, Array.from({ length: colCount }).map((_, ci) => (
8463
8805
  // biome-ignore lint/suspicious/noArrayIndexKey: same — column axis is fixed by the table shape
8464
- /* @__PURE__ */ React7.createElement(Text7, { key: `c-${ri}-${ci}` }, /* @__PURE__ */ React7.createElement(InlineMd, { text: row2[ci] ?? "", padTo: widths[ci] ?? 3, citations }), ci < colCount - 1 ? " \u2502 " : "")
8806
+ /* @__PURE__ */ React8.createElement(Text7, { key: `c-${ri}-${ci}` }, /* @__PURE__ */ React8.createElement(InlineMd, { text: row2[ci] ?? "", padTo: widths[ci] ?? 3, citations }), ci < colCount - 1 ? " \u2502 " : "")
8465
8807
  )))
8466
8808
  )));
8467
8809
  }
@@ -8481,7 +8823,7 @@ function EditBlockRow({ block }) {
8481
8823
  const isNewFile = block.search.length === 0;
8482
8824
  const searchLines = block.search.split("\n");
8483
8825
  const replaceLines = block.replace.split("\n");
8484
- return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React7.createElement(Box7, null, /* @__PURE__ */ React7.createElement(Text7, { bold: true, color: "cyan" }, block.filename), isNewFile ? /* @__PURE__ */ React7.createElement(Text7, { color: "green", bold: true }, " (new file)") : null), isNewFile ? null : /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column", marginTop: 1 }, searchLines.map((line, i) => /* @__PURE__ */ React7.createElement(Text7, { key: `s-${i}-${line.length}`, color: "red" }, `- ${line}`))), /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column", marginTop: isNewFile ? 1 : 0 }, replaceLines.map((line, i) => /* @__PURE__ */ React7.createElement(Text7, { key: `r-${i}-${line.length}`, color: "green" }, `+ ${line}`))));
8826
+ return /* @__PURE__ */ React8.createElement(Box7, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React8.createElement(Box7, null, /* @__PURE__ */ React8.createElement(Text7, { bold: true, color: "cyan" }, block.filename), isNewFile ? /* @__PURE__ */ React8.createElement(Text7, { color: "green", bold: true }, " (new file)") : null), isNewFile ? null : /* @__PURE__ */ React8.createElement(Box7, { flexDirection: "column", marginTop: 1 }, searchLines.map((line, i) => /* @__PURE__ */ React8.createElement(Text7, { key: `s-${i}-${line.length}`, color: "red" }, `- ${line}`))), /* @__PURE__ */ React8.createElement(Box7, { flexDirection: "column", marginTop: isNewFile ? 1 : 0 }, replaceLines.map((line, i) => /* @__PURE__ */ React8.createElement(Text7, { key: `r-${i}-${line.length}`, color: "green" }, `+ ${line}`))));
8485
8827
  }
8486
8828
  var DIAGRAM_LANGS = /* @__PURE__ */ new Set([
8487
8829
  "mermaid",
@@ -8503,41 +8845,41 @@ var DIAGRAM_VIEWER_HINT = {
8503
8845
  };
8504
8846
  function DiagramCodeBlock({ lang, text }) {
8505
8847
  const hint = DIAGRAM_VIEWER_HINT[lang.toLowerCase()] ?? "\u2192 render with the matching viewer to view";
8506
- return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column", borderStyle: "double", borderColor: "magenta", paddingX: 1 }, /* @__PURE__ */ React7.createElement(Text7, { bold: true, color: "magenta" }, `\u25C7 ${lang} diagram (source \u2014 terminal can't draw the graph)`), /* @__PURE__ */ React7.createElement(Box7, { marginTop: 1 }, /* @__PURE__ */ React7.createElement(Text7, { color: "yellow" }, text)), /* @__PURE__ */ React7.createElement(Box7, { marginTop: 1 }, /* @__PURE__ */ React7.createElement(Text7, { dimColor: true }, hint)));
8848
+ return /* @__PURE__ */ React8.createElement(Box7, { flexDirection: "column", borderStyle: "double", borderColor: "magenta", paddingX: 1 }, /* @__PURE__ */ React8.createElement(Text7, { bold: true, color: "magenta" }, `\u25C7 ${lang} diagram (source \u2014 terminal can't draw the graph)`), /* @__PURE__ */ React8.createElement(Box7, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(Text7, { color: "yellow" }, text)), /* @__PURE__ */ React8.createElement(Box7, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(Text7, { dimColor: true }, hint)));
8507
8849
  }
8508
8850
  function Markdown({ text, projectRoot }) {
8509
8851
  const cleaned = expandAutolinks(expandEmoji(stripMath(text)));
8510
8852
  const root = projectRoot ?? process.cwd();
8511
- const citations = React7.useMemo(() => collectCitations(cleaned, root), [cleaned, root]);
8512
- const blocks = React7.useMemo(() => parseBlocks(cleaned), [cleaned]);
8853
+ const citations = React8.useMemo(() => collectCitations(cleaned, root), [cleaned, root]);
8854
+ const blocks = React8.useMemo(() => parseBlocks(cleaned), [cleaned]);
8513
8855
  const broken = [];
8514
8856
  for (const [url, status2] of citations) {
8515
8857
  if (!status2.ok) broken.push({ url, reason: status2.reason });
8516
8858
  }
8517
- return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column", gap: 1 }, blocks.map((b, i) => /* @__PURE__ */ React7.createElement(BlockView, { key: `${i}-${b.kind}`, block: b, citations })), broken.length > 0 ? /* @__PURE__ */ React7.createElement(BrokenCitationsBlock, { items: broken }) : null);
8859
+ return /* @__PURE__ */ React8.createElement(Box7, { flexDirection: "column", gap: 1 }, blocks.map((b, i) => /* @__PURE__ */ React8.createElement(BlockView, { key: `${i}-${b.kind}`, block: b, citations })), broken.length > 0 ? /* @__PURE__ */ React8.createElement(BrokenCitationsBlock, { items: broken }) : null);
8518
8860
  }
8519
8861
  function BrokenCitationsBlock({ items }) {
8520
- return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column", borderStyle: "round", borderColor: "red", paddingX: 1 }, /* @__PURE__ */ React7.createElement(Text7, { 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) => (
8862
+ return /* @__PURE__ */ React8.createElement(Box7, { flexDirection: "column", borderStyle: "round", borderColor: "red", paddingX: 1 }, /* @__PURE__ */ React8.createElement(Text7, { 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) => (
8521
8863
  // biome-ignore lint/suspicious/noArrayIndexKey: list is derived from a Map iteration order, stable per render
8522
- /* @__PURE__ */ React7.createElement(Text7, { key: `bc-${i}`, color: "red" }, ` \u2717 ${b.url} \u2192 ${b.reason}`)
8864
+ /* @__PURE__ */ React8.createElement(Text7, { key: `bc-${i}`, color: "red" }, ` \u2717 ${b.url} \u2192 ${b.reason}`)
8523
8865
  )));
8524
8866
  }
8525
8867
 
8526
8868
  // src/cli/ui/ticker.tsx
8527
- import React8, { createContext, useContext, useEffect, useState as useState3 } from "react";
8869
+ import React9, { createContext as createContext2, useContext as useContext2, useEffect as useEffect2, useState as useState3 } from "react";
8528
8870
  var TICK_MS = 120;
8529
- var TickContext = createContext(0);
8871
+ var TickContext = createContext2(0);
8530
8872
  function TickerProvider({ children, disabled }) {
8531
8873
  const [tick, setTick] = useState3(0);
8532
- useEffect(() => {
8874
+ useEffect2(() => {
8533
8875
  if (disabled) return;
8534
8876
  const id = setInterval(() => setTick((t) => t + 1), TICK_MS);
8535
8877
  return () => clearInterval(id);
8536
8878
  }, [disabled]);
8537
- return /* @__PURE__ */ React8.createElement(TickContext.Provider, { value: tick }, children);
8879
+ return /* @__PURE__ */ React9.createElement(TickContext.Provider, { value: tick }, children);
8538
8880
  }
8539
8881
  function useTick() {
8540
- return useContext(TickContext);
8882
+ return useContext2(TickContext);
8541
8883
  }
8542
8884
  function useElapsedSeconds() {
8543
8885
  const [start] = useState3(() => Date.now());
@@ -8687,28 +9029,28 @@ function RoleGlyph({
8687
9029
  glyph,
8688
9030
  color
8689
9031
  }) {
8690
- return /* @__PURE__ */ React9.createElement(Text8, { color, bold: true }, glyph);
9032
+ return /* @__PURE__ */ React10.createElement(Text8, { color, bold: true }, glyph);
8691
9033
  }
8692
9034
  function indentContinuationLines(text) {
8693
9035
  if (!text.includes("\n")) return text;
8694
9036
  return text.split("\n").join("\n ");
8695
9037
  }
8696
- var EventRow = React9.memo(function EventRow2({
9038
+ var EventRow = React10.memo(function EventRow2({
8697
9039
  event,
8698
9040
  projectRoot
8699
9041
  }) {
8700
9042
  if (event.role === "user") {
8701
- return /* @__PURE__ */ React9.createElement(Box8, { marginTop: event.leadSeparator ? 1 : 0 }, /* @__PURE__ */ React9.createElement(RoleGlyph, { glyph: ROLE_GLYPH.user, color: "cyan" }), /* @__PURE__ */ React9.createElement(Text8, null, " ", indentContinuationLines(event.text)));
9043
+ return /* @__PURE__ */ React10.createElement(Box8, { flexDirection: "column" }, event.leadSeparator ? /* @__PURE__ */ React10.createElement(TurnSeparator, null) : null, /* @__PURE__ */ React10.createElement(Box8, null, /* @__PURE__ */ React10.createElement(RoleGlyph, { glyph: ROLE_GLYPH.user, color: "cyan" }), /* @__PURE__ */ React10.createElement(Text8, null, " ", indentContinuationLines(event.text))));
8702
9044
  }
8703
9045
  if (event.role === "assistant") {
8704
- if (event.streaming) return /* @__PURE__ */ React9.createElement(StreamingAssistant, { event });
8705
- return /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React9.createElement(Box8, null, /* @__PURE__ */ React9.createElement(RoleGlyph, { glyph: ROLE_GLYPH.assistant, color: "green" }), event.stats ? /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, ` ${event.stats.model}`) : null), /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column", paddingLeft: 2, marginTop: 1 }, event.branch ? /* @__PURE__ */ React9.createElement(BranchBlock, { branch: event.branch }) : null, event.reasoning ? /* @__PURE__ */ React9.createElement(ReasoningBlock, { reasoning: event.reasoning }) : null, !isPlanStateEmpty(event.planState) ? /* @__PURE__ */ React9.createElement(PlanStateBlock, { planState: event.planState }) : null, event.text ? /* @__PURE__ */ React9.createElement(Markdown, { text: event.text, projectRoot }) : /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, "(no content)"), event.stats ? /* @__PURE__ */ React9.createElement(StatsLine, { stats: event.stats }) : null, event.repair ? /* @__PURE__ */ React9.createElement(Text8, { color: "magenta" }, event.repair) : null));
9046
+ if (event.streaming) return /* @__PURE__ */ React10.createElement(StreamingAssistant, { event });
9047
+ return /* @__PURE__ */ React10.createElement(Box8, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React10.createElement(Box8, null, /* @__PURE__ */ React10.createElement(RoleGlyph, { glyph: ROLE_GLYPH.assistant, color: "green" }), event.stats ? /* @__PURE__ */ React10.createElement(Text8, { dimColor: true }, ` ${event.stats.model}`) : null), /* @__PURE__ */ React10.createElement(Box8, { flexDirection: "column", paddingLeft: 2, marginTop: 1 }, event.branch ? /* @__PURE__ */ React10.createElement(BranchBlock, { branch: event.branch }) : null, event.reasoning ? /* @__PURE__ */ React10.createElement(ReasoningBlock, { reasoning: event.reasoning }) : null, !isPlanStateEmpty(event.planState) ? /* @__PURE__ */ React10.createElement(PlanStateBlock, { planState: event.planState }) : null, event.text ? /* @__PURE__ */ React10.createElement(Markdown, { text: event.text, projectRoot }) : /* @__PURE__ */ React10.createElement(Text8, { dimColor: true }, "(no content)"), event.stats ? /* @__PURE__ */ React10.createElement(StatsLine, { stats: event.stats }) : null, event.repair ? /* @__PURE__ */ React10.createElement(Text8, { color: "magenta" }, event.repair) : null));
8706
9048
  }
8707
9049
  if (event.role === "tool") {
8708
9050
  const isExplicitError = event.text.startsWith("ERROR:");
8709
9051
  const isEditFile = (event.toolName === "edit_file" || event.toolName?.endsWith("_edit_file")) && !isExplicitError;
8710
9052
  if (isEditFile) {
8711
- return /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React9.createElement(Box8, null, /* @__PURE__ */ React9.createElement(RoleGlyph, { glyph: ROLE_GLYPH.toolOk, color: "yellow" }), /* @__PURE__ */ React9.createElement(Text8, { color: "yellow", bold: true }, ` ${event.toolName ?? "?"}`), /* @__PURE__ */ React9.createElement(Text8, { color: "yellow", dimColor: true }, " \u2192")), /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column", paddingLeft: 2, marginTop: 1 }, /* @__PURE__ */ React9.createElement(EditFileDiff, { text: event.text })));
9053
+ return /* @__PURE__ */ React10.createElement(Box8, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React10.createElement(Box8, null, /* @__PURE__ */ React10.createElement(RoleGlyph, { glyph: ROLE_GLYPH.toolOk, color: "yellow" }), /* @__PURE__ */ React10.createElement(Text8, { color: "yellow", bold: true }, ` ${event.toolName ?? "?"}`), /* @__PURE__ */ React10.createElement(Text8, { color: "yellow", dimColor: true }, " \u2192")), /* @__PURE__ */ React10.createElement(Box8, { flexDirection: "column", paddingLeft: 2, marginTop: 1 }, /* @__PURE__ */ React10.createElement(EditFileDiff, { text: event.text })));
8712
9054
  }
8713
9055
  const summary = summarizeToolResult(event.toolName ?? "?", event.text);
8714
9056
  const color = summary.isError ? "red" : "yellow";
@@ -8716,22 +9058,22 @@ var EventRow = React9.memo(function EventRow2({
8716
9058
  const marker = summary.isError ? "\u2717" : "\u2192";
8717
9059
  const durationLabel = event.durationMs !== void 0 && event.durationMs >= 100 ? ` (${formatDuration(event.durationMs)})` : "";
8718
9060
  const indexHint = event.toolIndex !== void 0 ? ` /tool ${event.toolIndex}` : "";
8719
- return /* @__PURE__ */ React9.createElement(Box8, null, /* @__PURE__ */ React9.createElement(RoleGlyph, { glyph, color }), /* @__PURE__ */ React9.createElement(Text8, { color, bold: true }, ` ${event.toolName ?? "?"}`), durationLabel ? /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, durationLabel) : null, /* @__PURE__ */ React9.createElement(Text8, { color, dimColor: true }, ` ${marker} `), /* @__PURE__ */ React9.createElement(Text8, { color: summary.isError ? "red" : void 0, dimColor: !summary.isError }, summary.summary), indexHint ? /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, indexHint) : null);
9061
+ return /* @__PURE__ */ React10.createElement(Box8, null, /* @__PURE__ */ React10.createElement(RoleGlyph, { glyph, color }), /* @__PURE__ */ React10.createElement(Text8, { color, bold: true }, ` ${event.toolName ?? "?"}`), durationLabel ? /* @__PURE__ */ React10.createElement(Text8, { dimColor: true }, durationLabel) : null, /* @__PURE__ */ React10.createElement(Text8, { color, dimColor: true }, ` ${marker} `), /* @__PURE__ */ React10.createElement(Text8, { color: summary.isError ? "red" : void 0, dimColor: !summary.isError }, summary.summary), indexHint ? /* @__PURE__ */ React10.createElement(Text8, { dimColor: true }, indexHint) : null);
8720
9062
  }
8721
9063
  if (event.role === "error") {
8722
- return /* @__PURE__ */ React9.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(RoleGlyph, { glyph: ROLE_GLYPH.error, color: "red" }), /* @__PURE__ */ React9.createElement(Text8, { color: "red" }, " ", indentContinuationLines(event.text)));
9064
+ return /* @__PURE__ */ React10.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(RoleGlyph, { glyph: ROLE_GLYPH.error, color: "red" }), /* @__PURE__ */ React10.createElement(Text8, { color: "red" }, " ", indentContinuationLines(event.text)));
8723
9065
  }
8724
9066
  if (event.role === "info") {
8725
- return /* @__PURE__ */ React9.createElement(Box8, null, /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, event.text));
9067
+ return /* @__PURE__ */ React10.createElement(Box8, null, /* @__PURE__ */ React10.createElement(Text8, { dimColor: true }, event.text));
8726
9068
  }
8727
9069
  if (event.role === "plan") {
8728
- return /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React9.createElement(Box8, null, /* @__PURE__ */ React9.createElement(Text8, { bold: true, color: "cyan" }, "\u{1F4CB} plan proposed \u2014 pick a choice below")), /* @__PURE__ */ React9.createElement(Box8, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React9.createElement(Markdown, { text: event.text, projectRoot })));
9070
+ return /* @__PURE__ */ React10.createElement(Box8, { flexDirection: "column", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React10.createElement(Box8, null, /* @__PURE__ */ React10.createElement(Text8, { bold: true, color: "cyan" }, "\u{1F4CB} plan proposed \u2014 pick a choice below")), /* @__PURE__ */ React10.createElement(Box8, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React10.createElement(Markdown, { text: event.text, projectRoot })));
8729
9071
  }
8730
9072
  if (event.role === "step-progress") {
8731
9073
  const sp = event.stepProgress;
8732
9074
  const counter = sp && sp.total > 0 ? ` (${sp.completed}/${sp.total})` : "";
8733
9075
  const label = sp?.title ? `${sp.stepId} \xB7 ${sp.title}` : sp?.stepId ?? "";
8734
- return /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React9.createElement(Box8, null, /* @__PURE__ */ React9.createElement(Text8, { color: "green", bold: true }, "\u2713"), /* @__PURE__ */ React9.createElement(Text8, { color: "green" }, ` ${label}`), /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, counter)), event.text ? /* @__PURE__ */ React9.createElement(Box8, { paddingLeft: 2 }, /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, event.text)) : null, sp?.notes ? /* @__PURE__ */ React9.createElement(Box8, { paddingLeft: 2 }, /* @__PURE__ */ React9.createElement(Text8, { color: "yellow", dimColor: true }, `note: ${sp.notes}`)) : null);
9076
+ return /* @__PURE__ */ React10.createElement(Box8, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React10.createElement(Box8, null, /* @__PURE__ */ React10.createElement(Text8, { color: "green", bold: true }, "\u2713"), /* @__PURE__ */ React10.createElement(Text8, { color: "green" }, ` ${label}`), /* @__PURE__ */ React10.createElement(Text8, { dimColor: true }, counter)), event.text ? /* @__PURE__ */ React10.createElement(Box8, { paddingLeft: 2 }, /* @__PURE__ */ React10.createElement(Text8, { dimColor: true }, event.text)) : null, sp?.notes ? /* @__PURE__ */ React10.createElement(Box8, { paddingLeft: 2 }, /* @__PURE__ */ React10.createElement(Text8, { color: "yellow", dimColor: true }, `note: ${sp.notes}`)) : null);
8735
9077
  }
8736
9078
  if (event.role === "plan-resumed") {
8737
9079
  const rp = event.resumedPlan;
@@ -8746,7 +9088,7 @@ var EventRow = React9.memo(function EventRow2({
8746
9088
  ])
8747
9089
  );
8748
9090
  const nextStep = rp.steps.find((s) => !completedSet.has(s.id));
8749
- return /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column" }, /* @__PURE__ */ React9.createElement(Box8, null, /* @__PURE__ */ React9.createElement(Text8, { bold: true, color: "cyan" }, "\u25B8 resumed plan"), /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, ` ${done}/${total} done \xB7 last touched ${rp.relativeTime}`)), rp.summary ? /* @__PURE__ */ React9.createElement(Box8, null, /* @__PURE__ */ React9.createElement(Text8, { color: "cyan" }, ` ${rp.summary}`)) : null), /* @__PURE__ */ React9.createElement(Box8, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React9.createElement(PlanStepList, { steps: rp.steps, statuses, focusStepId: nextStep?.id })));
9091
+ return /* @__PURE__ */ React10.createElement(Box8, { flexDirection: "column", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React10.createElement(Box8, { flexDirection: "column" }, /* @__PURE__ */ React10.createElement(Box8, null, /* @__PURE__ */ React10.createElement(Text8, { bold: true, color: "cyan" }, "\u25B8 resumed plan"), /* @__PURE__ */ React10.createElement(Text8, { dimColor: true }, ` ${done}/${total} done \xB7 last touched ${rp.relativeTime}`)), rp.summary ? /* @__PURE__ */ React10.createElement(Box8, null, /* @__PURE__ */ React10.createElement(Text8, { color: "cyan" }, ` ${rp.summary}`)) : null), /* @__PURE__ */ React10.createElement(Box8, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React10.createElement(PlanStepList, { steps: rp.steps, statuses, focusStepId: nextStep?.id })));
8750
9092
  }
8751
9093
  if (event.role === "plan-replay") {
8752
9094
  const r = event.replayPlan;
@@ -8758,31 +9100,40 @@ var EventRow = React9.memo(function EventRow2({
8758
9100
  r.steps.map((s) => [s.id, completedSet.has(s.id) ? "done" : "pending"])
8759
9101
  );
8760
9102
  const navHint = r.total > 1 ? ` \xB7 ${r.index}/${r.total}` : "";
8761
- return /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column", borderStyle: "round", borderColor: "gray", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column" }, /* @__PURE__ */ React9.createElement(Box8, null, /* @__PURE__ */ React9.createElement(Text8, { bold: true, dimColor: true }, "\u23EA replay"), /* @__PURE__ */ React9.createElement(
9103
+ return /* @__PURE__ */ React10.createElement(Box8, { flexDirection: "column", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React10.createElement(Box8, { flexDirection: "column" }, /* @__PURE__ */ React10.createElement(Box8, null, /* @__PURE__ */ React10.createElement(Text8, { bold: true, dimColor: true }, "\u23EA replay"), /* @__PURE__ */ React10.createElement(
8762
9104
  Text8,
8763
9105
  {
8764
9106
  dimColor: true
8765
9107
  },
8766
9108
  ` completed ${r.relativeTime} \xB7 ${done}/${total} done${navHint}`
8767
- )), r.summary ? /* @__PURE__ */ React9.createElement(Box8, null, /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, ` ${r.summary}`)) : null, /* @__PURE__ */ React9.createElement(Box8, null, /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, ` ${r.archiveBasename}`))), r.body ? /* @__PURE__ */ React9.createElement(Box8, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React9.createElement(Markdown, { text: r.body, projectRoot })) : null, /* @__PURE__ */ React9.createElement(Box8, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React9.createElement(PlanStepList, { steps: r.steps, statuses })), /* @__PURE__ */ React9.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, r.total > 1 ? `(read-only \xB7 /replay ${r.index === 1 ? 2 : 1} for the ${r.index === 1 ? "next" : "newest"} archive)` : "(read-only \xB7 this is an archived plan)")));
9109
+ )), r.summary ? /* @__PURE__ */ React10.createElement(Box8, null, /* @__PURE__ */ React10.createElement(Text8, { dimColor: true }, ` ${r.summary}`)) : null, /* @__PURE__ */ React10.createElement(Box8, null, /* @__PURE__ */ React10.createElement(Text8, { dimColor: true }, ` ${r.archiveBasename}`))), r.body ? /* @__PURE__ */ React10.createElement(Box8, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React10.createElement(Markdown, { text: r.body, projectRoot })) : null, /* @__PURE__ */ React10.createElement(Box8, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React10.createElement(PlanStepList, { steps: r.steps, statuses })), /* @__PURE__ */ React10.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text8, { dimColor: true }, r.total > 1 ? `(read-only \xB7 /replay ${r.index === 1 ? 2 : 1} for the ${r.index === 1 ? "next" : "newest"} archive)` : "(read-only \xB7 this is an archived plan)")));
8768
9110
  }
8769
9111
  if (event.role === "warning") {
8770
- return /* @__PURE__ */ React9.createElement(Box8, null, /* @__PURE__ */ React9.createElement(RoleGlyph, { glyph: ROLE_GLYPH.warning, color: "yellow" }), /* @__PURE__ */ React9.createElement(Text8, { color: "yellow" }, " ", indentContinuationLines(event.text)));
9112
+ return /* @__PURE__ */ React10.createElement(Box8, null, /* @__PURE__ */ React10.createElement(RoleGlyph, { glyph: ROLE_GLYPH.warning, color: "yellow" }), /* @__PURE__ */ React10.createElement(Text8, { color: "yellow" }, " ", indentContinuationLines(event.text)));
8771
9113
  }
8772
- return /* @__PURE__ */ React9.createElement(Box8, null, /* @__PURE__ */ React9.createElement(Text8, null, event.text));
9114
+ return /* @__PURE__ */ React10.createElement(Box8, null, /* @__PURE__ */ React10.createElement(Text8, null, event.text));
8773
9115
  });
9116
+ function TurnSeparator() {
9117
+ const { stdout: stdout2 } = useStdout2();
9118
+ const cols = stdout2?.columns ?? 80;
9119
+ const width = Math.max(16, cols - 2);
9120
+ const half = Math.floor((width - 3) / 2);
9121
+ const left = "\u2500".repeat(half);
9122
+ const right = "\u2500".repeat(width - half - 3);
9123
+ return /* @__PURE__ */ React10.createElement(Box8, { marginTop: 1, marginBottom: 1 }, /* @__PURE__ */ React10.createElement(Text8, { dimColor: true }, left), /* @__PURE__ */ React10.createElement(Text8, { color: "cyan", bold: true }, " \u25C6 "), /* @__PURE__ */ React10.createElement(Text8, { dimColor: true }, right));
9124
+ }
8774
9125
  function EditFileDiff({ text }) {
8775
9126
  const lines = text.split(/\r?\n/);
8776
9127
  const [statusHeader, hunkHeader, ...body] = lines;
8777
- return /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column" }, /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, ` ${statusHeader ?? ""}`), hunkHeader !== void 0 ? /* @__PURE__ */ React9.createElement(Text8, { color: "cyan", bold: true }, hunkHeader) : null, body.map((line, i) => {
9128
+ return /* @__PURE__ */ React10.createElement(Box8, { flexDirection: "column" }, /* @__PURE__ */ React10.createElement(Text8, { dimColor: true }, ` ${statusHeader ?? ""}`), hunkHeader !== void 0 ? /* @__PURE__ */ React10.createElement(Text8, { color: "cyan", bold: true }, hunkHeader) : null, body.map((line, i) => {
8778
9129
  const key = `${i}-${line.slice(0, 32)}`;
8779
9130
  if (line.startsWith("- ")) {
8780
- return /* @__PURE__ */ React9.createElement(Text8, { key, color: "red" }, line);
9131
+ return /* @__PURE__ */ React10.createElement(Text8, { key, color: "red" }, line);
8781
9132
  }
8782
9133
  if (line.startsWith("+ ")) {
8783
- return /* @__PURE__ */ React9.createElement(Text8, { key, color: "green" }, line);
9134
+ return /* @__PURE__ */ React10.createElement(Text8, { key, color: "green" }, line);
8784
9135
  }
8785
- return /* @__PURE__ */ React9.createElement(Text8, { key, dimColor: true }, line);
9136
+ return /* @__PURE__ */ React10.createElement(Text8, { key, dimColor: true }, line);
8786
9137
  }));
8787
9138
  }
8788
9139
  function BranchBlock({ branch: branch2 }) {
@@ -8791,33 +9142,33 @@ function BranchBlock({ branch: branch2 }) {
8791
9142
  const t = (branch2.temperatures[i] ?? 0).toFixed(1);
8792
9143
  return `${marker} #${i} T=${t} u=${u}`;
8793
9144
  }).join(" ");
8794
- return /* @__PURE__ */ React9.createElement(Box8, null, /* @__PURE__ */ React9.createElement(Text8, { color: "blue" }, "\u2387 branched ", /* @__PURE__ */ React9.createElement(Text8, { bold: true }, branch2.budget), ` samples \u2192 picked #${branch2.chosenIndex} `, /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, per)));
9145
+ return /* @__PURE__ */ React10.createElement(Box8, null, /* @__PURE__ */ React10.createElement(Text8, { color: "blue" }, "\u2387 branched ", /* @__PURE__ */ React10.createElement(Text8, { bold: true }, branch2.budget), ` samples \u2192 picked #${branch2.chosenIndex} `, /* @__PURE__ */ React10.createElement(Text8, { dimColor: true }, per)));
8795
9146
  }
8796
9147
  function ReasoningBlock({ reasoning }) {
8797
9148
  const max = 260;
8798
9149
  const flat = reasoning.replace(/\s+/g, " ").trim();
8799
9150
  const preview = flat.length <= max ? flat : `\u2026 (+${flat.length - max} earlier chars) ${flat.slice(-max)}`;
8800
- return /* @__PURE__ */ React9.createElement(Box8, { marginBottom: 1 }, /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, "\u258F "), /* @__PURE__ */ React9.createElement(Text8, { dimColor: true, italic: true }, "thinking ", preview));
9151
+ return /* @__PURE__ */ React10.createElement(Box8, { marginBottom: 1 }, /* @__PURE__ */ React10.createElement(Text8, { dimColor: true }, "\u258F "), /* @__PURE__ */ React10.createElement(Text8, { dimColor: true, italic: true }, "thinking ", preview));
8801
9152
  }
8802
9153
  function Elapsed() {
8803
9154
  const s = useElapsedSeconds();
8804
9155
  const mm = String(Math.floor(s / 60)).padStart(2, "0");
8805
9156
  const ss = String(s % 60).padStart(2, "0");
8806
- return /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, `${mm}:${ss}`);
9157
+ return /* @__PURE__ */ React10.createElement(Text8, { dimColor: true }, `${mm}:${ss}`);
8807
9158
  }
8808
9159
  function PulsingAssistantGlyph() {
8809
9160
  const tick = useTick();
8810
9161
  const on = Math.floor(tick / 4) % 2 === 0;
8811
- return /* @__PURE__ */ React9.createElement(Text8, { color: "green", bold: true }, on ? ROLE_GLYPH.assistant : ROLE_GLYPH.assistantPulse);
9162
+ return /* @__PURE__ */ React10.createElement(Text8, { color: "green", bold: true }, on ? ROLE_GLYPH.assistant : ROLE_GLYPH.assistantPulse);
8812
9163
  }
8813
9164
  function StreamingAssistant({ event }) {
8814
9165
  if (event.branchProgress) {
8815
9166
  const p = event.branchProgress;
8816
9167
  if (p.completed === 0) {
8817
- return /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React9.createElement(Box8, null, /* @__PURE__ */ React9.createElement(PulsingAssistantGlyph, null), /* @__PURE__ */ React9.createElement(Text8, { color: "blue" }, " \u2387 launching ", p.total, " parallel samples (R1 thinking in parallel)\u2026 "), /* @__PURE__ */ React9.createElement(Elapsed, null)), /* @__PURE__ */ React9.createElement(Text8, { color: "yellow" }, " ", "spread across T=0.0/0.5/1.0 \xB7 reasoner typically takes 30-90s \u2014 this is normal"));
9168
+ return /* @__PURE__ */ React10.createElement(Box8, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React10.createElement(Box8, null, /* @__PURE__ */ React10.createElement(PulsingAssistantGlyph, null), /* @__PURE__ */ React10.createElement(Text8, { color: "blue" }, " \u2387 launching ", p.total, " parallel samples (R1 thinking in parallel)\u2026 "), /* @__PURE__ */ React10.createElement(Elapsed, null)), /* @__PURE__ */ React10.createElement(Text8, { color: "yellow" }, " ", "spread across T=0.0/0.5/1.0 \xB7 reasoner typically takes 30-90s \u2014 this is normal"));
8818
9169
  }
8819
9170
  const pct2 = Math.round(p.completed / p.total * 100);
8820
- return /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React9.createElement(Box8, null, /* @__PURE__ */ React9.createElement(PulsingAssistantGlyph, null), /* @__PURE__ */ React9.createElement(Text8, { color: "blue" }, " \u2387 branching ", p.completed, "/", p.total, " (", pct2, "%) "), /* @__PURE__ */ React9.createElement(Elapsed, null)), /* @__PURE__ */ React9.createElement(Text8, { 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"));
9171
+ return /* @__PURE__ */ React10.createElement(Box8, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React10.createElement(Box8, null, /* @__PURE__ */ React10.createElement(PulsingAssistantGlyph, null), /* @__PURE__ */ React10.createElement(Text8, { color: "blue" }, " \u2387 branching ", p.completed, "/", p.total, " (", pct2, "%) "), /* @__PURE__ */ React10.createElement(Elapsed, null)), /* @__PURE__ */ React10.createElement(Text8, { 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"));
8821
9172
  }
8822
9173
  const tail = lastLine(event.text, 140);
8823
9174
  const reasoningTail = event.reasoning ? lastLine(event.reasoning, 120) : "";
@@ -8847,16 +9198,16 @@ function StreamingAssistant({ event }) {
8847
9198
  label = parts.join(" \xB7 ");
8848
9199
  labelColor = "green";
8849
9200
  }
8850
- return /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React9.createElement(Box8, null, /* @__PURE__ */ React9.createElement(PulsingAssistantGlyph, null), /* @__PURE__ */ React9.createElement(Text8, null, " "), /* @__PURE__ */ React9.createElement(Pulse, null), /* @__PURE__ */ React9.createElement(Text8, { color: labelColor }, ` ${label} `), /* @__PURE__ */ React9.createElement(Elapsed, null)), reasoningTail ? /* @__PURE__ */ React9.createElement(Text8, { dimColor: true, italic: true }, "\u21B3 thinking: ", reasoningTail) : null, tail ? /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, "\u25B8 ", tail) : preFirstByte ? (
9201
+ return /* @__PURE__ */ React10.createElement(Box8, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React10.createElement(Box8, null, /* @__PURE__ */ React10.createElement(PulsingAssistantGlyph, null), /* @__PURE__ */ React10.createElement(Text8, null, " "), /* @__PURE__ */ React10.createElement(Pulse, null), /* @__PURE__ */ React10.createElement(Text8, { color: labelColor }, ` ${label} `), /* @__PURE__ */ React10.createElement(Elapsed, null)), reasoningTail ? /* @__PURE__ */ React10.createElement(Text8, { dimColor: true, italic: true }, "\u21B3 thinking: ", reasoningTail) : null, tail ? /* @__PURE__ */ React10.createElement(Text8, { dimColor: true }, "\u25B8 ", tail) : preFirstByte ? (
8851
9202
  // Non-dim yellow: first-time users misread the dim version as
8852
9203
  // "app frozen". The reassurance has to be VISIBLE to do its job.
8853
- /* @__PURE__ */ React9.createElement(Text8, { color: "yellow", italic: true }, " waiting for first byte \u2014 this is normal, typically 5-60s depending on model + load")
8854
- ) : reasoningOnly ? /* @__PURE__ */ React9.createElement(Text8, { 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__ */ React9.createElement(Text8, { color: "magenta", italic: true }, " tool-call arguments streaming \u2014 the model is about to dispatch a tool") : event.reasoning ? /* @__PURE__ */ React9.createElement(Text8, { color: "yellow", italic: true }, " R1 still reasoning \u2014 body text or tool call arrives when thinking finishes") : null);
9204
+ /* @__PURE__ */ React10.createElement(Text8, { color: "yellow", italic: true }, " waiting for first byte \u2014 this is normal, typically 5-60s depending on model + load")
9205
+ ) : reasoningOnly ? /* @__PURE__ */ React10.createElement(Text8, { 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__ */ React10.createElement(Text8, { color: "magenta", italic: true }, " tool-call arguments streaming \u2014 the model is about to dispatch a tool") : event.reasoning ? /* @__PURE__ */ React10.createElement(Text8, { color: "yellow", italic: true }, " R1 still reasoning \u2014 body text or tool call arrives when thinking finishes") : null);
8855
9206
  }
8856
9207
  function Pulse() {
8857
9208
  const tick = useTick();
8858
9209
  const frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
8859
- return /* @__PURE__ */ React9.createElement(Text8, { color: "cyan" }, frames[Math.floor(tick / 4) % frames.length]);
9210
+ return /* @__PURE__ */ React10.createElement(Text8, { color: "cyan" }, frames[Math.floor(tick / 4) % frames.length]);
8860
9211
  }
8861
9212
  function formatToolCallIndex(tb) {
8862
9213
  if (!tb || tb.index === void 0) return "";
@@ -8875,17 +9226,17 @@ function lastLine(s, maxChars) {
8875
9226
  }
8876
9227
  function StatsLine({ stats: stats2 }) {
8877
9228
  const hit = (stats2.cacheHitRatio * 100).toFixed(1);
8878
- return /* @__PURE__ */ React9.createElement(Box8, null, /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, "\u258F "), /* @__PURE__ */ React9.createElement(Text8, { dimColor: true }, "cache ", hit, "% \xB7 tokens ", stats2.usage.promptTokens, " \u2192 ", stats2.usage.completionTokens, " \xB7 $", stats2.cost.toFixed(6)));
9229
+ return /* @__PURE__ */ React10.createElement(Box8, null, /* @__PURE__ */ React10.createElement(Text8, { dimColor: true }, "\u258F "), /* @__PURE__ */ React10.createElement(Text8, { dimColor: true }, "cache ", hit, "% \xB7 tokens ", stats2.usage.promptTokens, " \u2192 ", stats2.usage.completionTokens, " \xB7 $", stats2.cost.toFixed(6)));
8879
9230
  }
8880
9231
 
8881
9232
  // src/cli/ui/LiveRows.tsx
8882
9233
  import { Box as Box9, Text as Text9 } from "ink";
8883
- import React10 from "react";
9234
+ import React11 from "react";
8884
9235
  var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
8885
9236
  function StatusRow({ text }) {
8886
9237
  const tick = useTick();
8887
9238
  const elapsed = useElapsedSeconds();
8888
- return /* @__PURE__ */ React10.createElement(Box9, { marginY: 1 }, /* @__PURE__ */ React10.createElement(Text9, { color: "magenta" }, SPINNER_FRAMES[tick % SPINNER_FRAMES.length]), /* @__PURE__ */ React10.createElement(Text9, { color: "magenta" }, ` ${text}`), /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, ` ${elapsed}s`));
9239
+ return /* @__PURE__ */ React11.createElement(Box9, { marginY: 1 }, /* @__PURE__ */ React11.createElement(Text9, { color: "magenta" }, SPINNER_FRAMES[tick % SPINNER_FRAMES.length]), /* @__PURE__ */ React11.createElement(Text9, { color: "magenta" }, ` ${text}`), /* @__PURE__ */ React11.createElement(Text9, { dimColor: true }, ` ${elapsed}s`));
8889
9240
  }
8890
9241
  function ModeStatusBar({
8891
9242
  editMode,
@@ -8897,15 +9248,14 @@ function ModeStatusBar({
8897
9248
  }) {
8898
9249
  useTick();
8899
9250
  const running = jobs2?.runningCount() ?? 0;
8900
- const jobsTag = running > 0 ? /* @__PURE__ */ React10.createElement(Text9, { color: "yellow", bold: true }, ` \xB7 \u23F5 ${running} job${running === 1 ? "" : "s"}`) : null;
9251
+ const jobsTag = running > 0 ? /* @__PURE__ */ React11.createElement(Text9, { color: "yellow", bold: true }, ` \xB7 \u23F5 ${running} job${running === 1 ? "" : "s"}`) : null;
8901
9252
  if (planMode) {
8902
- return /* @__PURE__ */ React10.createElement(Box9, { paddingX: 1 }, /* @__PURE__ */ React10.createElement(Text9, { color: "red", bold: true, inverse: flash }, "\u25B8 PLAN"), /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, " writes gated \u2014 submit_plan + approval required \xB7 /plan off to leave"), jobsTag);
9253
+ return /* @__PURE__ */ React11.createElement(Box9, { paddingX: 1 }, /* @__PURE__ */ React11.createElement(Text9, { color: "red", bold: true, inverse: flash }, "plan mode"), /* @__PURE__ */ React11.createElement(Text9, { dimColor: true }, " writes gated \xB7 /plan off to leave"), jobsTag);
8903
9254
  }
8904
- const label = editMode === "auto" ? "AUTO" : "review";
8905
- const color = editMode === "auto" ? "magenta" : "cyan";
8906
- const mid = editMode === "auto" ? undoArmed ? "edits apply immediately \xB7 u = undo last batch" : "edits apply immediately \xB7 5s undo window after each batch" : pendingCount > 0 ? `${pendingCount} queued \xB7 y = /apply \xB7 n = /discard` : "edits queue for review \xB7 y = /apply \xB7 n = /discard";
8907
- const flip = editMode === "auto" ? "Shift+Tab \u2192 review" : "Shift+Tab \u2192 AUTO";
8908
- return /* @__PURE__ */ React10.createElement(Box9, { paddingX: 1 }, /* @__PURE__ */ React10.createElement(Text9, { color, bold: true, inverse: flash }, `\u25B8 ${label}`), /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, ` ${mid} \xB7 ${flip}`), jobsTag);
9255
+ const label = editMode === "auto" ? "auto" : "review";
9256
+ const labelColor = editMode === "auto" ? "magenta" : "cyan";
9257
+ const mid = editMode === "auto" ? "edits land now \xB7 u to undo" : pendingCount > 0 ? `${pendingCount} queued \xB7 y apply \xB7 n discard` : "edits queued \xB7 y apply \xB7 n discard";
9258
+ return /* @__PURE__ */ React11.createElement(Box9, { paddingX: 1 }, /* @__PURE__ */ React11.createElement(Text9, { color: labelColor, bold: true, inverse: flash }, label), /* @__PURE__ */ React11.createElement(Text9, { dimColor: true }, ` ${mid} \xB7 Shift+Tab to flip`), jobsTag);
8909
9259
  }
8910
9260
  function UndoBanner({
8911
9261
  banner
@@ -8915,14 +9265,14 @@ function UndoBanner({
8915
9265
  const remainingSec = Math.ceil(remainingMs / 1e3);
8916
9266
  const ok = banner.results.filter((r) => r.status === "applied" || r.status === "created").length;
8917
9267
  const total = banner.results.length;
8918
- return /* @__PURE__ */ React10.createElement(Box9, { marginY: 1, borderStyle: "round", borderColor: "magenta", paddingX: 1 }, /* @__PURE__ */ React10.createElement(Text9, { color: "magenta", bold: true }, "\u2713 auto-applied "), /* @__PURE__ */ React10.createElement(Text9, { color: "magenta" }, `${ok}/${total} edit${total === 1 ? "" : "s"}`), /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, " \xB7 press "), /* @__PURE__ */ React10.createElement(Text9, { color: "magenta", bold: true }, "u"), /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, " to undo ("), /* @__PURE__ */ React10.createElement(Text9, { color: remainingSec <= 1 ? "red" : "magenta" }, `${remainingSec}s`), /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, ")"));
9268
+ return /* @__PURE__ */ React11.createElement(Box9, { marginY: 1, paddingX: 1 }, /* @__PURE__ */ React11.createElement(Text9, { color: "magenta", bold: true }, "\u2713 auto-applied "), /* @__PURE__ */ React11.createElement(Text9, { color: "magenta" }, `${ok}/${total} edit${total === 1 ? "" : "s"}`), /* @__PURE__ */ React11.createElement(Text9, { dimColor: true }, " \xB7 press "), /* @__PURE__ */ React11.createElement(Text9, { color: "magenta", bold: true }, "u"), /* @__PURE__ */ React11.createElement(Text9, { dimColor: true }, " to undo ("), /* @__PURE__ */ React11.createElement(Text9, { color: remainingSec <= 1 ? "red" : "magenta" }, `${remainingSec}s`), /* @__PURE__ */ React11.createElement(Text9, { dimColor: true }, ")"));
8919
9269
  }
8920
9270
  function SubagentRow({
8921
9271
  activity
8922
9272
  }) {
8923
9273
  const tick = useTick();
8924
9274
  const seconds = (activity.elapsedMs / 1e3).toFixed(1);
8925
- return /* @__PURE__ */ React10.createElement(Box9, { paddingLeft: 2 }, /* @__PURE__ */ React10.createElement(Text9, { color: "magenta" }, SPINNER_FRAMES[tick % SPINNER_FRAMES.length]), /* @__PURE__ */ React10.createElement(Text9, { color: "magenta" }, ` \u232C subagent: ${activity.task}`), /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, ` \xB7 iter ${activity.iter} \xB7 ${seconds}s`));
9275
+ return /* @__PURE__ */ React11.createElement(Box9, { paddingLeft: 2 }, /* @__PURE__ */ React11.createElement(Text9, { color: "magenta" }, SPINNER_FRAMES[tick % SPINNER_FRAMES.length]), /* @__PURE__ */ React11.createElement(Text9, { color: "magenta" }, ` \u232C subagent: ${activity.task}`), /* @__PURE__ */ React11.createElement(Text9, { dimColor: true }, ` \xB7 iter ${activity.iter} \xB7 ${seconds}s`));
8926
9276
  }
8927
9277
  function OngoingToolRow({
8928
9278
  tool: tool2,
@@ -8931,7 +9281,7 @@ function OngoingToolRow({
8931
9281
  const tick = useTick();
8932
9282
  const elapsed = useElapsedSeconds();
8933
9283
  const summary = summarizeToolArgs(tool2.name, tool2.args);
8934
- return /* @__PURE__ */ React10.createElement(Box9, { marginY: 1, flexDirection: "column" }, /* @__PURE__ */ React10.createElement(Box9, null, /* @__PURE__ */ React10.createElement(Text9, { color: "cyan" }, SPINNER_FRAMES[tick % SPINNER_FRAMES.length]), /* @__PURE__ */ React10.createElement(Text9, { color: "yellow" }, ` tool<${tool2.name}> running\u2026`), /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, ` ${elapsed}s`)), progress ? /* @__PURE__ */ React10.createElement(Box9, { paddingLeft: 2 }, /* @__PURE__ */ React10.createElement(Text9, { color: "cyan" }, renderProgressLine(progress))) : null, summary ? /* @__PURE__ */ React10.createElement(Box9, { paddingLeft: 2 }, /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, summary)) : null);
9284
+ return /* @__PURE__ */ React11.createElement(Box9, { marginY: 1, flexDirection: "column" }, /* @__PURE__ */ React11.createElement(Box9, null, /* @__PURE__ */ React11.createElement(Text9, { color: "cyan" }, SPINNER_FRAMES[tick % SPINNER_FRAMES.length]), /* @__PURE__ */ React11.createElement(Text9, { color: "yellow" }, ` tool<${tool2.name}> running\u2026`), /* @__PURE__ */ React11.createElement(Text9, { dimColor: true }, ` ${elapsed}s`)), progress ? /* @__PURE__ */ React11.createElement(Box9, { paddingLeft: 2 }, /* @__PURE__ */ React11.createElement(Text9, { color: "cyan" }, renderProgressLine(progress))) : null, summary ? /* @__PURE__ */ React11.createElement(Box9, { paddingLeft: 2 }, /* @__PURE__ */ React11.createElement(Text9, { dimColor: true }, summary)) : null);
8935
9285
  }
8936
9286
  function renderProgressLine(p) {
8937
9287
  const msg = p.message ? ` ${p.message}` : "";
@@ -8988,7 +9338,7 @@ function summarizeToolArgs(name, args) {
8988
9338
 
8989
9339
  // src/cli/ui/PlanCheckpointConfirm.tsx
8990
9340
  import { Box as Box10, Text as Text10 } from "ink";
8991
- import React11 from "react";
9341
+ import React12 from "react";
8992
9342
  function PlanCheckpointConfirmInner({
8993
9343
  stepId,
8994
9344
  title,
@@ -9002,7 +9352,7 @@ function PlanCheckpointConfirmInner({
9002
9352
  const counter = total > 0 ? ` (${completed}/${total})` : "";
9003
9353
  const isLast = total > 0 && completed >= total;
9004
9354
  const statuses = buildStatusMap(steps, completedStepIds, stepId, isLast);
9005
- return /* @__PURE__ */ React11.createElement(Box10, { flexDirection: "column", borderStyle: "round", borderColor: "green", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React11.createElement(Box10, null, /* @__PURE__ */ React11.createElement(Text10, { bold: true, color: "green" }, "\u25B8 checkpoint \u2014 step done"), /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, ` ${label}${counter}`)), steps && steps.length > 0 ? /* @__PURE__ */ React11.createElement(Box10, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React11.createElement(PlanStepList, { steps, statuses, focusStepId: stepId })) : null, /* @__PURE__ */ React11.createElement(Box10, { marginTop: 1 }, /* @__PURE__ */ React11.createElement(
9355
+ return /* @__PURE__ */ React12.createElement(Box10, { flexDirection: "column", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React12.createElement(Box10, null, /* @__PURE__ */ React12.createElement(Text10, { bold: true, color: "green" }, "\u25B8 checkpoint \u2014 step done"), /* @__PURE__ */ React12.createElement(Text10, { dimColor: true }, ` ${label}${counter}`)), steps && steps.length > 0 ? /* @__PURE__ */ React12.createElement(Box10, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React12.createElement(PlanStepList, { steps, statuses, focusStepId: stepId })) : null, /* @__PURE__ */ React12.createElement(Box10, { marginTop: 1 }, /* @__PURE__ */ React12.createElement(
9006
9356
  SingleSelect,
9007
9357
  {
9008
9358
  initialValue: isLast ? "stop" : "continue",
@@ -9029,7 +9379,7 @@ function PlanCheckpointConfirmInner({
9029
9379
  }
9030
9380
  )));
9031
9381
  }
9032
- var PlanCheckpointConfirm = React11.memo(PlanCheckpointConfirmInner);
9382
+ var PlanCheckpointConfirm = React12.memo(PlanCheckpointConfirmInner);
9033
9383
  function buildStatusMap(steps, completedStepIds, currentStepId, isLast) {
9034
9384
  const map = /* @__PURE__ */ new Map();
9035
9385
  if (!steps) return map;
@@ -9047,10 +9397,10 @@ function buildStatusMap(steps, completedStepIds, currentStepId, isLast) {
9047
9397
 
9048
9398
  // src/cli/ui/PlanConfirm.tsx
9049
9399
  import { Box as Box11, Text as Text11 } from "ink";
9050
- import React12 from "react";
9400
+ import React13 from "react";
9051
9401
  function PlanConfirmInner({ plan: plan2, steps, summary, onChoose }) {
9052
9402
  const hasOpenQuestions = /^#{1,6}\s*(open[-\s]?questions?|risks?|unknowns?|assumptions?|unclear)/im.test(plan2) || /^#{1,6}\s*(待确认|开放问题|风险|未知|假设|不确定)/im.test(plan2);
9053
- return /* @__PURE__ */ React12.createElement(Box11, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React12.createElement(Box11, { flexDirection: "column" }, /* @__PURE__ */ React12.createElement(Box11, null, /* @__PURE__ */ React12.createElement(Text11, { bold: true, color: "cyan" }, "\u25B8 plan proposed (full text above) \u2014 approve / refine / cancel")), summary ? /* @__PURE__ */ React12.createElement(Box11, null, /* @__PURE__ */ React12.createElement(Text11, { color: "cyan" }, ` ${summary}`)) : null), hasOpenQuestions ? /* @__PURE__ */ React12.createElement(Box11, { marginTop: 1 }, /* @__PURE__ */ React12.createElement(Text11, { color: "yellow" }, "\u25B2 the plan flags open questions or risks \u2014 pick", " ", /* @__PURE__ */ React12.createElement(Text11, { bold: true }, "Refine / answer questions"), " to write concrete answers before the model moves on.")) : null, steps && steps.length > 0 ? /* @__PURE__ */ React12.createElement(Box11, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React12.createElement(PlanStepList, { steps })) : null, /* @__PURE__ */ React12.createElement(Box11, { marginTop: 1 }, /* @__PURE__ */ React12.createElement(
9403
+ return /* @__PURE__ */ React13.createElement(Box11, { flexDirection: "column", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React13.createElement(Box11, { flexDirection: "column" }, /* @__PURE__ */ React13.createElement(Box11, null, /* @__PURE__ */ React13.createElement(Text11, { bold: true, color: "cyan" }, "\u25B8 plan proposed (full text above) \u2014 approve / refine / cancel")), summary ? /* @__PURE__ */ React13.createElement(Box11, null, /* @__PURE__ */ React13.createElement(Text11, { color: "cyan" }, ` ${summary}`)) : null), hasOpenQuestions ? /* @__PURE__ */ React13.createElement(Box11, { marginTop: 1 }, /* @__PURE__ */ React13.createElement(Text11, { color: "yellow" }, "\u25B2 the plan flags open questions or risks \u2014 pick", " ", /* @__PURE__ */ React13.createElement(Text11, { bold: true }, "Refine / answer questions"), " to write concrete answers before the model moves on.")) : null, steps && steps.length > 0 ? /* @__PURE__ */ React13.createElement(Box11, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React13.createElement(PlanStepList, { steps })) : null, /* @__PURE__ */ React13.createElement(Box11, { marginTop: 1 }, /* @__PURE__ */ React13.createElement(
9054
9404
  SingleSelect,
9055
9405
  {
9056
9406
  initialValue: hasOpenQuestions ? "refine" : "approve",
@@ -9077,39 +9427,43 @@ function PlanConfirmInner({ plan: plan2, steps, summary, onChoose }) {
9077
9427
  }
9078
9428
  )));
9079
9429
  }
9080
- var PlanConfirm = React12.memo(PlanConfirmInner);
9430
+ var PlanConfirm = React13.memo(PlanConfirmInner);
9081
9431
 
9082
9432
  // src/cli/ui/PlanRefineInput.tsx
9083
- import { Box as Box12, Text as Text12, useInput as useInput3 } from "ink";
9084
- import React13, { useState as useState4 } from "react";
9433
+ import { Box as Box12, Text as Text12 } from "ink";
9434
+ import React14, { useState as useState4 } from "react";
9085
9435
  function PlanRefineInput({ mode: mode2, onSubmit, onCancel }) {
9086
9436
  const [value, setValue] = useState4("");
9087
- useInput3((input, key) => {
9088
- if (key.escape) {
9437
+ useKeystroke((ev) => {
9438
+ if (ev.paste) {
9439
+ setValue((v) => v + ev.input.replace(/\r?\n/g, " "));
9440
+ return;
9441
+ }
9442
+ if (ev.escape) {
9089
9443
  onCancel();
9090
9444
  return;
9091
9445
  }
9092
- if (key.return) {
9446
+ if (ev.return) {
9093
9447
  onSubmit(value.trim());
9094
9448
  return;
9095
9449
  }
9096
- if (key.backspace || key.delete) {
9450
+ if (ev.backspace || ev.delete) {
9097
9451
  setValue((v) => v.slice(0, -1));
9098
9452
  return;
9099
9453
  }
9100
- if (input && !key.ctrl && !key.meta) {
9101
- setValue((v) => v + input);
9454
+ if (ev.input && !ev.ctrl && !ev.meta) {
9455
+ setValue((v) => v + ev.input);
9102
9456
  }
9103
9457
  });
9104
9458
  const title = mode2 === "approve" ? "\u25B8 approving \u2014 any last instructions or answers to open questions?" : mode2 === "checkpoint-revise" ? "\u25B8 revising \u2014 what should change before the next step?" : mode2 === "choice-custom" ? "\u25B8 custom answer \u2014 type whatever fits" : "\u25B8 refining \u2014 what should the model change?";
9105
9459
  const hint = mode2 === "approve" ? "Answer questions the plan raised, add constraints, or just press Enter to approve as-is." : mode2 === "checkpoint-revise" ? "Scope change, skip steps, alternative approach \u2014 the model will adjust the remaining plan based on this." : mode2 === "choice-custom" ? "Free-form reply. The model reads it verbatim and proceeds \u2014 no need to match the listed options." : "Describe what's wrong or missing, or answer questions the plan raised.";
9106
9460
  const blankHint = mode2 === "approve" ? " (Enter with blank = approve without extra instructions.)" : mode2 === "checkpoint-revise" ? " (Enter with blank = continue with the current plan.)" : mode2 === "choice-custom" ? " (Enter with blank = ask the model what you actually want.)" : " (Enter with blank = ask the model to list concrete questions.)";
9107
- return /* @__PURE__ */ React13.createElement(Box12, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React13.createElement(Box12, null, /* @__PURE__ */ React13.createElement(Text12, { bold: true, color: "yellow" }, title)), /* @__PURE__ */ React13.createElement(Box12, { marginTop: 1 }, /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, hint, " Enter to send \xB7 Esc to return to the picker.", value === "" ? blankHint : "")), /* @__PURE__ */ React13.createElement(Box12, { marginTop: 1 }, /* @__PURE__ */ React13.createElement(Text12, null, /* @__PURE__ */ React13.createElement(Text12, { color: "yellow" }, "\u203A "), /* @__PURE__ */ React13.createElement(Text12, null, value || " "), /* @__PURE__ */ React13.createElement(Text12, { color: "yellow" }, "\u258D"))));
9461
+ return /* @__PURE__ */ React14.createElement(Box12, { flexDirection: "column", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React14.createElement(Box12, null, /* @__PURE__ */ React14.createElement(Text12, { bold: true, color: "yellow" }, title)), /* @__PURE__ */ React14.createElement(Box12, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text12, { dimColor: true }, hint, " Enter to send \xB7 Esc to return to the picker.", value === "" ? blankHint : "")), /* @__PURE__ */ React14.createElement(Box12, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text12, null, /* @__PURE__ */ React14.createElement(Text12, { color: "yellow" }, "\u203A "), /* @__PURE__ */ React14.createElement(Text12, null, value || " "), /* @__PURE__ */ React14.createElement(Text12, { color: "yellow" }, "\u258D"))));
9108
9462
  }
9109
9463
 
9110
9464
  // src/cli/ui/PlanReviseConfirm.tsx
9111
9465
  import { Box as Box13, Text as Text13 } from "ink";
9112
- import React14 from "react";
9466
+ import React15 from "react";
9113
9467
  function computeDiff(oldSteps, newSteps) {
9114
9468
  const oldIds = new Set(oldSteps.map((s) => s.id));
9115
9469
  const newIds = new Set(newSteps.map((s) => s.id));
@@ -9145,14 +9499,14 @@ function PlanReviseConfirmInner({
9145
9499
  const removedCount = rows.filter((r) => r.kind === "removed").length;
9146
9500
  const addedCount = rows.filter((r) => r.kind === "added").length;
9147
9501
  const keptCount = rows.filter((r) => r.kind === "kept").length;
9148
- return /* @__PURE__ */ React14.createElement(Box13, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React14.createElement(Box13, null, /* @__PURE__ */ React14.createElement(Text13, { bold: true, color: "yellow" }, "\u270F plan revision proposed"), /* @__PURE__ */ React14.createElement(Text13, { dimColor: true }, ` \u2212${removedCount} +${addedCount} (${keptCount} kept)`)), /* @__PURE__ */ React14.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text13, null, reason)), summary ? /* @__PURE__ */ React14.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(Text13, { dimColor: true }, `updated summary: ${summary}`)) : null, /* @__PURE__ */ React14.createElement(Box13, { marginTop: 1, flexDirection: "column" }, rows.map((row2) => {
9502
+ return /* @__PURE__ */ React15.createElement(Box13, { flexDirection: "column", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React15.createElement(Box13, null, /* @__PURE__ */ React15.createElement(Text13, { bold: true, color: "yellow" }, "\u270F plan revision proposed"), /* @__PURE__ */ React15.createElement(Text13, { dimColor: true }, ` \u2212${removedCount} +${addedCount} (${keptCount} kept)`)), /* @__PURE__ */ React15.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React15.createElement(Text13, null, reason)), summary ? /* @__PURE__ */ React15.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React15.createElement(Text13, { dimColor: true }, `updated summary: ${summary}`)) : null, /* @__PURE__ */ React15.createElement(Box13, { marginTop: 1, flexDirection: "column" }, rows.map((row2) => {
9149
9503
  const risk = riskDots2(row2.step.risk);
9150
9504
  const prefix = row2.kind === "removed" ? "\u2212" : row2.kind === "added" ? "+" : " ";
9151
9505
  const prefixColor = row2.kind === "removed" ? "red" : row2.kind === "added" ? "green" : "gray";
9152
9506
  const dim = row2.kind === "kept";
9153
9507
  const strike = row2.kind === "removed";
9154
- return /* @__PURE__ */ React14.createElement(Box13, { key: `${row2.kind}-${row2.step.id}` }, /* @__PURE__ */ React14.createElement(Text13, { color: prefixColor, bold: true }, `${prefix} `), /* @__PURE__ */ React14.createElement(Text13, { color: risk.color, bold: true, dimColor: dim }, risk.dots), /* @__PURE__ */ React14.createElement(Text13, { dimColor: dim, strikethrough: strike }, ` ${row2.step.id} \xB7 ${row2.step.title}`));
9155
- })), /* @__PURE__ */ React14.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React14.createElement(
9508
+ return /* @__PURE__ */ React15.createElement(Box13, { key: `${row2.kind}-${row2.step.id}` }, /* @__PURE__ */ React15.createElement(Text13, { color: prefixColor, bold: true }, `${prefix} `), /* @__PURE__ */ React15.createElement(Text13, { color: risk.color, bold: true, dimColor: dim }, risk.dots), /* @__PURE__ */ React15.createElement(Text13, { dimColor: dim, strikethrough: strike }, ` ${row2.step.id} \xB7 ${row2.step.title}`));
9509
+ })), /* @__PURE__ */ React15.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React15.createElement(
9156
9510
  SingleSelect,
9157
9511
  {
9158
9512
  initialValue: "accept",
@@ -9174,25 +9528,62 @@ function PlanReviseConfirmInner({
9174
9528
  }
9175
9529
  )));
9176
9530
  }
9177
- var PlanReviseConfirm = React14.memo(PlanReviseConfirmInner);
9531
+ var PlanReviseConfirm = React15.memo(PlanReviseConfirmInner);
9178
9532
 
9179
9533
  // src/cli/ui/PromptInput.tsx
9180
- import { Box as Box14, Text as Text14, useInput as useInput4, useStdout as useStdout3 } from "ink";
9181
- import React15, { useRef, useState as useState5 } from "react";
9534
+ import { Box as Box14, Text as Text14, useStdout as useStdout3 } from "ink";
9535
+ import React16, { useRef as useRef2, useState as useState5 } from "react";
9536
+
9537
+ // src/cli/ui/key-normalize.ts
9538
+ var CSI_TAIL_TO_FLAGS = [
9539
+ // Arrow keys — the most common ConPTY victim.
9540
+ { tail: "[A", flags: { upArrow: true } },
9541
+ { tail: "[B", flags: { downArrow: true } },
9542
+ { tail: "[C", flags: { rightArrow: true } },
9543
+ { tail: "[D", flags: { leftArrow: true } },
9544
+ // Page navigation.
9545
+ { tail: "[5~", flags: { pageUp: true } },
9546
+ { tail: "[6~", flags: { pageDown: true } },
9547
+ // Forward-delete (the key labelled Delete on most keyboards).
9548
+ { tail: "[3~", flags: { delete: true } },
9549
+ // Shift+Tab — terminal sends `\x1b[Z` rather than tab-with-shift.
9550
+ { tail: "[Z", flags: { shift: true, tab: true } }
9551
+ ];
9552
+ function alreadyStructured(flags) {
9553
+ return Boolean(
9554
+ flags.upArrow || flags.downArrow || flags.leftArrow || flags.rightArrow || flags.pageUp || flags.pageDown || flags.delete || flags.tab && flags.shift
9555
+ );
9556
+ }
9557
+ function recoverCsiTail(input, existing = {}) {
9558
+ if (alreadyStructured(existing)) return null;
9559
+ for (const entry of CSI_TAIL_TO_FLAGS) {
9560
+ if (input === entry.tail || input === `\x1B${entry.tail}`) {
9561
+ return entry.flags;
9562
+ }
9563
+ }
9564
+ return null;
9565
+ }
9566
+ var STRIPPABLE_CSI_FRAGMENTS = [
9567
+ "\x1B[200~",
9568
+ "\x1B[201~",
9569
+ "[200~",
9570
+ "[201~",
9571
+ ...CSI_TAIL_TO_FLAGS.flatMap((e) => [`\x1B${e.tail}`, e.tail])
9572
+ ];
9573
+ function stripCsiFragments(input) {
9574
+ let out = input;
9575
+ for (const frag of STRIPPABLE_CSI_FRAGMENTS) {
9576
+ if (out.includes(frag)) out = out.replaceAll(frag, "");
9577
+ }
9578
+ return out;
9579
+ }
9182
9580
 
9183
9581
  // src/cli/ui/multiline-keys.ts
9184
9582
  var BACKSLASH_SUFFIX = /\\$/;
9185
9583
  var NOOP = { next: null, cursor: null, submit: false };
9186
- function rewriteRawArrowEscape(key) {
9187
- if (key.upArrow || key.downArrow || key.leftArrow || key.rightArrow) return key;
9188
- if (key.input === "\x1B[A") return { ...key, upArrow: true, input: "" };
9189
- if (key.input === "\x1B[B") return { ...key, downArrow: true, input: "" };
9190
- if (key.input === "\x1B[C") return { ...key, rightArrow: true, input: "" };
9191
- if (key.input === "\x1B[D") return { ...key, leftArrow: true, input: "" };
9192
- return key;
9193
- }
9194
9584
  function processMultilineKey(value, cursor, keyIn) {
9195
- const key = rewriteRawArrowEscape(keyIn);
9585
+ const recovered = recoverCsiTail(keyIn.input, keyIn);
9586
+ const key = recovered ? { ...keyIn, ...recovered, input: "" } : keyIn;
9196
9587
  if (key.tab || key.escape) {
9197
9588
  return NOOP;
9198
9589
  }
@@ -9239,7 +9630,7 @@ function processMultilineKey(value, cursor, keyIn) {
9239
9630
  submit: false
9240
9631
  };
9241
9632
  }
9242
- const stripped = key.input.replaceAll("\x1B[200~", "").replaceAll("\x1B[201~", "");
9633
+ const stripped = stripCsiFragments(key.input);
9243
9634
  const looksLikePaste = stripped.length > 1 && (stripped.includes("\n") || stripped.includes("\r"));
9244
9635
  if (looksLikePaste) {
9245
9636
  const normalized = stripped.replace(/\r\n?/g, "\n");
@@ -9383,10 +9774,159 @@ function formatBytesShort(n) {
9383
9774
  return `${(n / (1024 * 1024)).toFixed(1)}MB`;
9384
9775
  }
9385
9776
 
9777
+ // src/cli/ui/prompt-viewport.ts
9778
+ function charCells(ch) {
9779
+ if (ch.length === 0) return 0;
9780
+ const code = ch.charCodeAt(0);
9781
+ if (code < 32 || code === 127) return 0;
9782
+ if (code < 4352) return 1;
9783
+ if (code >= 4352 && code <= 4447) return 2;
9784
+ if (code >= 11904 && code <= 12350) return 2;
9785
+ if (code >= 12353 && code <= 13311) return 2;
9786
+ if (code >= 13312 && code <= 19903) return 2;
9787
+ if (code >= 19968 && code <= 40959) return 2;
9788
+ if (code >= 40960 && code <= 42191) return 2;
9789
+ if (code >= 44032 && code <= 55203) return 2;
9790
+ if (code >= 63744 && code <= 64255) return 2;
9791
+ if (code >= 65072 && code <= 65103) return 2;
9792
+ if (code >= 65280 && code <= 65376) return 2;
9793
+ if (code >= 65504 && code <= 65510) return 2;
9794
+ return 1;
9795
+ }
9796
+ function stringCells(s, pastes) {
9797
+ let n = 0;
9798
+ for (let i = 0; i < s.length; i++) {
9799
+ const ch = s[i];
9800
+ const id = decodePasteSentinel(ch);
9801
+ if (id !== null) {
9802
+ n += pasteSentinelCells(id, pastes);
9803
+ } else {
9804
+ n += charCells(ch);
9805
+ }
9806
+ }
9807
+ return n;
9808
+ }
9809
+ function pasteSentinelLabel(id, entry) {
9810
+ if (!entry) return `[paste #${id + 1} \xB7 (missing)]`;
9811
+ return `[paste #${id + 1} \xB7 ${entry.lineCount}l \xB7 ${formatBytesShort(entry.charCount)}]`;
9812
+ }
9813
+ function pasteSentinelCells(id, pastes) {
9814
+ const entry = pastes?.get(id);
9815
+ return pasteSentinelLabel(id, entry).length;
9816
+ }
9817
+ function buildViewport(line, cursorCol, visibleCells, pastes) {
9818
+ if (visibleCells <= 0) {
9819
+ return {
9820
+ segments: [],
9821
+ cursorCell: cursorCol === null ? null : 0,
9822
+ hiddenLeft: false,
9823
+ hiddenRight: line.length > 0
9824
+ };
9825
+ }
9826
+ const totalCells = stringCells(line, pastes);
9827
+ if (totalCells <= visibleCells) {
9828
+ const segments = textToSegments(line, pastes);
9829
+ let cursorCell = null;
9830
+ if (cursorCol !== null) {
9831
+ cursorCell = stringCells(line.slice(0, cursorCol), pastes);
9832
+ }
9833
+ return { segments, cursorCell, hiddenLeft: false, hiddenRight: false };
9834
+ }
9835
+ if (cursorCol === null) {
9836
+ return clipFromLeft(line, visibleCells, pastes);
9837
+ }
9838
+ return clipAroundCursor(line, cursorCol, visibleCells, pastes);
9839
+ }
9840
+ function clipFromLeft(line, visibleCells, pastes) {
9841
+ const budget = Math.max(1, visibleCells - 1);
9842
+ let used = 0;
9843
+ let end = 0;
9844
+ while (end < line.length) {
9845
+ const ch = line[end];
9846
+ const cw = charCellsAt(line, end, pastes);
9847
+ if (used + cw > budget) break;
9848
+ used += cw;
9849
+ end++;
9850
+ }
9851
+ const segments = textToSegments(line.slice(0, end), pastes);
9852
+ return { segments, cursorCell: null, hiddenLeft: false, hiddenRight: end < line.length };
9853
+ }
9854
+ function clipAroundCursor(line, cursorCol, visibleCells, pastes) {
9855
+ let budget = visibleCells;
9856
+ const reservedForMarkers = 2;
9857
+ budget = Math.max(1, budget - reservedForMarkers);
9858
+ const halfBudget = Math.floor(budget / 2);
9859
+ let start = cursorCol;
9860
+ let leftCells = 0;
9861
+ while (start > 0 && leftCells < halfBudget) {
9862
+ const cw = charCellsAt(line, start - 1, pastes);
9863
+ if (leftCells + cw > halfBudget) break;
9864
+ start--;
9865
+ leftCells += cw;
9866
+ }
9867
+ const rightBudget = budget - leftCells;
9868
+ let end = cursorCol;
9869
+ let rightCells = 0;
9870
+ const cursorChar = cursorCol < line.length ? charCellsAt(line, cursorCol, pastes) : 1;
9871
+ if (rightBudget >= cursorChar) {
9872
+ if (cursorCol < line.length) end = cursorCol + 1;
9873
+ rightCells = cursorChar;
9874
+ while (end < line.length && rightCells < rightBudget) {
9875
+ const cw = charCellsAt(line, end, pastes);
9876
+ if (rightCells + cw > rightBudget) break;
9877
+ rightCells += cw;
9878
+ end++;
9879
+ }
9880
+ }
9881
+ let extraLeftBudget = rightBudget - rightCells;
9882
+ while (start > 0 && extraLeftBudget > 0) {
9883
+ const cw = charCellsAt(line, start - 1, pastes);
9884
+ if (cw > extraLeftBudget) break;
9885
+ start--;
9886
+ leftCells += cw;
9887
+ extraLeftBudget -= cw;
9888
+ }
9889
+ const hiddenLeft = start > 0;
9890
+ const hiddenRight = end < line.length;
9891
+ const segments = textToSegments(line.slice(start, end), pastes);
9892
+ const cursorCell = stringCells(line.slice(start, cursorCol), pastes);
9893
+ return { segments, cursorCell, hiddenLeft, hiddenRight };
9894
+ }
9895
+ function charCellsAt(line, idx, pastes) {
9896
+ const ch = line[idx];
9897
+ const id = decodePasteSentinel(ch);
9898
+ if (id !== null) {
9899
+ const entry = pastes?.get(id);
9900
+ return pasteSentinelLabel(id, entry).length;
9901
+ }
9902
+ return charCells(ch);
9903
+ }
9904
+ function textToSegments(line, pastes) {
9905
+ const out = [];
9906
+ let buf = "";
9907
+ const flushBuf = () => {
9908
+ if (buf.length > 0) {
9909
+ out.push({ kind: "text", text: buf });
9910
+ buf = "";
9911
+ }
9912
+ };
9913
+ for (let i = 0; i < line.length; i++) {
9914
+ const ch = line[i];
9915
+ const id = decodePasteSentinel(ch);
9916
+ if (id !== null) {
9917
+ flushBuf();
9918
+ const label = pasteSentinelLabel(id, pastes?.get(id));
9919
+ out.push({ kind: "paste", id, label });
9920
+ } else {
9921
+ buf += ch;
9922
+ }
9923
+ }
9924
+ flushBuf();
9925
+ return out;
9926
+ }
9927
+
9386
9928
  // src/cli/ui/PromptInput.tsx
9387
- var PASTE_START_MARKER = "\x1B[200~";
9388
- var PASTE_END_MARKER = "\x1B[201~";
9389
- var PASTE_MERGE_WINDOW_MS = 30;
9929
+ var BAR = "\u258E ";
9390
9930
  function PromptInput({
9391
9931
  value,
9392
9932
  onChange,
@@ -9397,157 +9937,248 @@ function PromptInput({
9397
9937
  onHistoryNext
9398
9938
  }) {
9399
9939
  const [cursor, setCursor] = useState5(value.length);
9400
- const pastesRef = useRef(/* @__PURE__ */ new Map());
9401
- const nextPasteIdRef = useRef(0);
9402
- const pasteAccumRef = useRef(null);
9403
- const lastPasteRef = useRef(null);
9404
- const lastLocalValueRef = useRef(value);
9940
+ const pastesRef = useRef2(/* @__PURE__ */ new Map());
9941
+ const nextPasteIdRef = useRef2(0);
9942
+ const lastLocalValueRef = useRef2(value);
9405
9943
  if (value !== lastLocalValueRef.current) {
9406
9944
  lastLocalValueRef.current = value;
9407
- if (cursor !== value.length) {
9408
- setCursor(value.length);
9409
- }
9945
+ if (cursor !== value.length) setCursor(value.length);
9410
9946
  }
9411
- const cursorRef = useRef(cursor);
9412
- cursorRef.current = cursor;
9413
- const tick = useTick();
9414
- const showCursor = disabled ? false : Math.floor(tick / 4) % 2 === 0;
9415
9947
  const registerPaste = (content) => {
9416
9948
  const v = lastLocalValueRef.current;
9417
- const c = cursorRef.current;
9418
- const now = Date.now();
9419
- const last = lastPasteRef.current;
9420
- const prevChar = c > 0 ? v[c - 1] : null;
9421
- const prevId = prevChar ? decodePasteSentinel(prevChar) : null;
9422
- const canMerge = last !== null && prevId === last.id && now - last.at < PASTE_MERGE_WINDOW_MS && pastesRef.current.has(last.id);
9423
- if (canMerge && last) {
9424
- const existing = pastesRef.current.get(last.id);
9425
- if (existing) {
9426
- const merged = existing.content + content;
9427
- pastesRef.current.set(last.id, makePasteEntry(last.id, merged));
9428
- lastPasteRef.current = { id: last.id, at: now };
9429
- return;
9430
- }
9431
- }
9949
+ const c = cursor;
9432
9950
  const id = nextPasteIdRef.current % PASTE_SENTINEL_RANGE;
9433
9951
  nextPasteIdRef.current = id + 1;
9434
9952
  pastesRef.current.set(id, makePasteEntry(id, content));
9435
9953
  const sentinel = encodePasteSentinel(id);
9436
9954
  const next = v.slice(0, c) + sentinel + v.slice(c);
9437
9955
  lastLocalValueRef.current = next;
9438
- cursorRef.current = c + 1;
9439
9956
  onChange(next);
9440
9957
  setCursor(c + 1);
9441
- lastPasteRef.current = { id, at: now };
9442
9958
  };
9443
- useInput4(
9444
- (input, key) => {
9445
- if (pasteAccumRef.current !== null) {
9446
- const endIdx = input.indexOf(PASTE_END_MARKER);
9447
- if (endIdx === -1) {
9448
- pasteAccumRef.current += input;
9449
- return;
9450
- }
9451
- const content = pasteAccumRef.current + input.slice(0, endIdx);
9452
- pasteAccumRef.current = null;
9453
- registerPaste(content);
9454
- return;
9455
- }
9456
- const startIdx = input.indexOf(PASTE_START_MARKER);
9457
- if (startIdx !== -1) {
9458
- const afterStart = input.slice(startIdx + PASTE_START_MARKER.length);
9459
- const endIdx = afterStart.indexOf(PASTE_END_MARKER);
9460
- if (endIdx !== -1) {
9461
- registerPaste(afterStart.slice(0, endIdx));
9462
- } else {
9463
- pasteAccumRef.current = afterStart;
9464
- }
9465
- return;
9466
- }
9467
- const ke = {
9468
- input,
9469
- return: key.return,
9470
- shift: key.shift,
9471
- ctrl: key.ctrl,
9472
- meta: key.meta,
9473
- backspace: key.backspace,
9474
- delete: key.delete,
9475
- tab: key.tab,
9476
- upArrow: key.upArrow,
9477
- downArrow: key.downArrow,
9478
- leftArrow: key.leftArrow,
9479
- rightArrow: key.rightArrow,
9480
- escape: key.escape,
9481
- pageUp: key.pageUp,
9482
- pageDown: key.pageDown
9483
- };
9484
- const action = processMultilineKey(value, cursor, ke);
9485
- if (action.pasteRequest) {
9486
- registerPaste(action.pasteRequest.content);
9487
- return;
9488
- }
9489
- if (action.next !== null) {
9490
- lastLocalValueRef.current = action.next;
9491
- onChange(action.next);
9492
- }
9493
- if (action.cursor !== null) {
9494
- setCursor(action.cursor);
9495
- }
9496
- if (action.submit) {
9497
- const raw = action.submitValue ?? value;
9498
- const expanded = expandPasteSentinels(raw, pastesRef.current);
9499
- const reachable = new Set(listPasteIdsInBuffer(raw));
9500
- for (const id of pastesRef.current.keys()) {
9501
- if (!reachable.has(id)) pastesRef.current.delete(id);
9502
- }
9503
- onSubmit(expanded);
9959
+ useKeystroke((ev) => {
9960
+ if (disabled) return;
9961
+ if (ev.paste) {
9962
+ if (ev.input.length > 0) registerPaste(ev.input);
9963
+ return;
9964
+ }
9965
+ const key = {
9966
+ input: ev.input,
9967
+ return: ev.return,
9968
+ shift: ev.shift,
9969
+ ctrl: ev.ctrl,
9970
+ meta: ev.meta,
9971
+ backspace: ev.backspace,
9972
+ delete: ev.delete,
9973
+ tab: ev.tab,
9974
+ upArrow: ev.upArrow,
9975
+ downArrow: ev.downArrow,
9976
+ leftArrow: ev.leftArrow,
9977
+ rightArrow: ev.rightArrow,
9978
+ escape: ev.escape,
9979
+ pageUp: ev.pageUp,
9980
+ pageDown: ev.pageDown
9981
+ };
9982
+ const action = processMultilineKey(value, cursor, key);
9983
+ if (action.pasteRequest) {
9984
+ registerPaste(action.pasteRequest.content);
9985
+ return;
9986
+ }
9987
+ if (action.next !== null) {
9988
+ lastLocalValueRef.current = action.next;
9989
+ onChange(action.next);
9990
+ }
9991
+ if (action.cursor !== null) {
9992
+ setCursor(action.cursor);
9993
+ }
9994
+ if (action.submit) {
9995
+ const raw = action.submitValue ?? value;
9996
+ const expanded = expandPasteSentinels(raw, pastesRef.current);
9997
+ const reachable = new Set(listPasteIdsInBuffer(raw));
9998
+ for (const id of pastesRef.current.keys()) {
9999
+ if (!reachable.has(id)) pastesRef.current.delete(id);
9504
10000
  }
9505
- if (action.historyHandoff === "prev") onHistoryPrev?.();
9506
- if (action.historyHandoff === "next") onHistoryNext?.();
9507
- },
9508
- { isActive: !disabled }
9509
- );
10001
+ onSubmit(expanded);
10002
+ }
10003
+ if (action.historyHandoff === "prev") onHistoryPrev?.();
10004
+ if (action.historyHandoff === "next") onHistoryNext?.();
10005
+ }, !disabled);
9510
10006
  const { stdout: stdout2 } = useStdout3();
9511
10007
  const cols = stdout2?.columns ?? 80;
9512
10008
  const narrow = cols <= 90;
9513
- const promptPrefix = narrow ? "\u203A " : "you \u203A ";
9514
- const continuationIndent = narrow ? " " : " ";
9515
- const placeholderActive = narrow ? "type a message, or /command" : "type a message, or /command \xB7 [Shift+Enter] / [Ctrl+J] newline";
10009
+ const promptBody = narrow ? "\u203A " : "you \u203A ";
10010
+ const promptPrefix = BAR + promptBody;
10011
+ const continuationIndent = BAR + " ".repeat(promptBody.length);
10012
+ const prefixCells = promptPrefix.length;
10013
+ const visibleCells = Math.max(8, cols - prefixCells - 3);
10014
+ const placeholderActive = narrow ? "type a message, or /command" : "type a message, or /command \xB7 [Ctrl+J] newline (Shift+Enter where supported)";
9516
10015
  const effectivePlaceholder = disabled ? placeholder ?? "\u2026waiting for response\u2026" : placeholder ?? placeholderActive;
9517
10016
  const lines = value.length > 0 ? value.split("\n") : [""];
9518
- const borderColor = disabled ? "gray" : "cyan";
10017
+ const accentColor = disabled ? "gray" : "cyan";
9519
10018
  const { line: cursorLine, col: cursorCol } = lineAndColumn(value, cursor);
9520
10019
  const renderItems = collapseLinesForDisplay(lines, cursorLine);
9521
10020
  const showHugeBufferHints = lines.length > 20;
9522
- return /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement(Box14, { borderStyle: "round", borderColor, paddingX: 1, flexDirection: "column" }, renderItems.map((item, renderIdx) => {
10021
+ return /* @__PURE__ */ React16.createElement(Box14, { flexDirection: "column", paddingX: 1 }, renderItems.map((item, renderIdx) => {
9523
10022
  if (item.kind === "skip") {
9524
10023
  return (
9525
- // biome-ignore lint/suspicious/noArrayIndexKey: stable — skip markers are derived from a fixed-size window over `lines`
9526
- /* @__PURE__ */ React15.createElement(Box14, { key: `skip-${renderIdx}` }, /* @__PURE__ */ React15.createElement(Text14, { dimColor: true }, continuationIndent), /* @__PURE__ */ React15.createElement(
9527
- Text14,
9528
- {
9529
- dimColor: true
9530
- },
9531
- `[\u2026 ${item.linesHidden} line${item.linesHidden === 1 ? "" : "s"} hidden \u2014 full content kept, submitted on Enter \u2026]`
9532
- ))
10024
+ // biome-ignore lint/suspicious/noArrayIndexKey: stable — collapse markers derive from a fixed sliding window
10025
+ /* @__PURE__ */ React16.createElement(Box14, { key: `skip-${renderIdx}` }, /* @__PURE__ */ React16.createElement(Text14, { color: accentColor }, BAR), /* @__PURE__ */ React16.createElement(Text14, { dimColor: true }, continuationIndent.slice(BAR.length)), /* @__PURE__ */ React16.createElement(Text14, { dimColor: true }, `[\u2026 ${item.linesHidden} line${item.linesHidden === 1 ? "" : "s"} hidden \u2014 full content kept, submitted on Enter \u2026]`))
9533
10026
  );
9534
10027
  }
9535
- const line = item.line;
9536
10028
  const i = item.originalIndex;
10029
+ const line = item.line;
9537
10030
  const isFirst = i === 0;
9538
- const showPlaceholder = isFirst && value.length === 0;
9539
10031
  const isCursorLine = i === cursorLine;
9540
- return /* @__PURE__ */ React15.createElement(Box14, { key: `ln-${i}` }, isFirst ? /* @__PURE__ */ React15.createElement(Text14, { bold: true, color: borderColor }, promptPrefix) : /* @__PURE__ */ React15.createElement(Text14, { dimColor: true }, continuationIndent), showPlaceholder ? /* @__PURE__ */ React15.createElement(React15.Fragment, null, isCursorLine && !disabled ? /* @__PURE__ */ React15.createElement(Text14, { color: borderColor }, showCursor ? "\u258C" : " ") : null, /* @__PURE__ */ React15.createElement(Text14, { dimColor: true }, effectivePlaceholder)) : isCursorLine && !disabled ? /* @__PURE__ */ React15.createElement(
9541
- LineWithCursor,
10032
+ const showPlaceholder = isFirst && value.length === 0;
10033
+ return /* @__PURE__ */ React16.createElement(
10034
+ PromptLine,
9542
10035
  {
10036
+ key: `ln-${i}`,
9543
10037
  line,
9544
- col: cursorCol,
9545
- showCursor,
9546
- borderColor,
9547
- pastes: pastesRef.current
10038
+ isFirst,
10039
+ isCursorLine: isCursorLine && !disabled,
10040
+ cursorCol: isCursorLine ? cursorCol : null,
10041
+ showPlaceholder,
10042
+ placeholderText: effectivePlaceholder,
10043
+ promptPrefix,
10044
+ continuationIndent,
10045
+ visibleCells,
10046
+ accentColor,
10047
+ pastes: pastesRef.current,
10048
+ disabled: disabled === true
9548
10049
  }
9549
- ) : /* @__PURE__ */ React15.createElement(RenderLine, { line, pastes: pastesRef.current }));
9550
- }), showHugeBufferHints && !disabled ? /* @__PURE__ */ React15.createElement(Box14, null, /* @__PURE__ */ React15.createElement(Text14, { dimColor: true }, continuationIndent), /* @__PURE__ */ React15.createElement(Text14, { dimColor: true }, `[${lines.length} lines \xB7 PageUp/PageDown jump to top/bottom \xB7 Ctrl+U clear \xB7 Ctrl+W del word]`)) : null), disabled ? /* @__PURE__ */ React15.createElement(Box14, { paddingX: 1 }, /* @__PURE__ */ React15.createElement(Text14, { dimColor: true }, "[Esc] to stop")) : null);
10050
+ );
10051
+ }), showHugeBufferHints && !disabled ? /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Text14, { color: accentColor }, BAR), /* @__PURE__ */ React16.createElement(Text14, { dimColor: true }, continuationIndent.slice(BAR.length)), /* @__PURE__ */ React16.createElement(Text14, { dimColor: true }, `[${lines.length} lines \xB7 PageUp/PageDown jump to top/bottom \xB7 Ctrl+U clear \xB7 Ctrl+W del word]`)) : null, !disabled && !narrow && value.length > 0 && !value.includes("\n") ? /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Text14, { color: accentColor }, BAR), /* @__PURE__ */ React16.createElement(Text14, { dimColor: true }, continuationIndent.slice(BAR.length)), /* @__PURE__ */ React16.createElement(Text14, { dimColor: true }, "[Ctrl+J] newline \xB7 [Enter] submit \xB7 ends with \\ for line continuation")) : null, disabled ? /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Text14, { color: accentColor }, BAR), /* @__PURE__ */ React16.createElement(Text14, { dimColor: true }, continuationIndent.slice(BAR.length)), /* @__PURE__ */ React16.createElement(Text14, { dimColor: true }, "[Esc] to stop")) : null);
10052
+ }
10053
+ function PromptLine({
10054
+ line,
10055
+ isFirst,
10056
+ isCursorLine,
10057
+ cursorCol,
10058
+ showPlaceholder,
10059
+ placeholderText,
10060
+ promptPrefix,
10061
+ continuationIndent,
10062
+ visibleCells,
10063
+ accentColor,
10064
+ pastes,
10065
+ disabled
10066
+ }) {
10067
+ const barText = promptPrefix.slice(0, BAR.length);
10068
+ const bodyPrefix = promptPrefix.slice(BAR.length);
10069
+ const bodyContinuation = continuationIndent.slice(BAR.length);
10070
+ if (showPlaceholder) {
10071
+ return /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Text14, { color: accentColor }, barText), /* @__PURE__ */ React16.createElement(Text14, { bold: true, color: accentColor }, bodyPrefix), !disabled ? /* @__PURE__ */ React16.createElement(Text14, { color: accentColor }, "\u258C") : null, /* @__PURE__ */ React16.createElement(Text14, { dimColor: true }, placeholderText));
10072
+ }
10073
+ const viewport = buildViewport(line, isCursorLine ? cursorCol : null, visibleCells, pastes);
10074
+ return /* @__PURE__ */ React16.createElement(Box14, null, /* @__PURE__ */ React16.createElement(Text14, { color: accentColor }, barText), isFirst ? /* @__PURE__ */ React16.createElement(Text14, { bold: true, color: accentColor }, bodyPrefix) : /* @__PURE__ */ React16.createElement(Text14, { dimColor: true }, bodyContinuation), viewport.hiddenLeft ? /* @__PURE__ */ React16.createElement(Text14, { color: "gray", dimColor: true }, "\u2039") : null, /* @__PURE__ */ React16.createElement(
10075
+ ViewportContent,
10076
+ {
10077
+ segments: viewport.segments,
10078
+ cursorCell: isCursorLine ? viewport.cursorCell : null,
10079
+ accentColor
10080
+ }
10081
+ ), viewport.hiddenRight ? /* @__PURE__ */ React16.createElement(Text14, { color: "gray", dimColor: true }, "\u203A") : null);
10082
+ }
10083
+ function ViewportContent({
10084
+ segments,
10085
+ cursorCell,
10086
+ accentColor
10087
+ }) {
10088
+ if (cursorCell === null) {
10089
+ return /* @__PURE__ */ React16.createElement(React16.Fragment, null, segments.map((seg, i) => renderSegment(seg, i, false)));
10090
+ }
10091
+ const out = [];
10092
+ let cells = 0;
10093
+ let placed = false;
10094
+ for (let i = 0; i < segments.length; i++) {
10095
+ const seg = segments[i];
10096
+ const segCells = segmentCells(seg);
10097
+ if (placed) {
10098
+ out.push(renderSegment(seg, i, false));
10099
+ continue;
10100
+ }
10101
+ if (cursorCell >= cells + segCells) {
10102
+ out.push(renderSegment(seg, i, false));
10103
+ cells += segCells;
10104
+ continue;
10105
+ }
10106
+ if (seg.kind === "paste") {
10107
+ out.push(
10108
+ /* @__PURE__ */ React16.createElement(Text14, { key: `p-${i}-cursor`, color: "magenta", bold: true, inverse: true }, seg.label)
10109
+ );
10110
+ placed = true;
10111
+ cells += segCells;
10112
+ continue;
10113
+ }
10114
+ const offsetIntoSeg = cursorCell - cells;
10115
+ const split = splitTextByCells(seg.text, offsetIntoSeg);
10116
+ if (split.before.length > 0) {
10117
+ out.push(/* @__PURE__ */ React16.createElement(Text14, { key: `t-${i}-b` }, split.before));
10118
+ }
10119
+ if (split.atCursor.length > 0) {
10120
+ out.push(
10121
+ /* @__PURE__ */ React16.createElement(Text14, { key: `t-${i}-c`, inverse: true, color: accentColor }, split.atCursor)
10122
+ );
10123
+ } else {
10124
+ out.push(
10125
+ /* @__PURE__ */ React16.createElement(Text14, { key: `t-${i}-c-eol`, color: accentColor }, "\u258C")
10126
+ );
10127
+ }
10128
+ if (split.after.length > 0) {
10129
+ out.push(/* @__PURE__ */ React16.createElement(Text14, { key: `t-${i}-a` }, split.after));
10130
+ }
10131
+ placed = true;
10132
+ cells += segCells;
10133
+ }
10134
+ if (!placed) {
10135
+ out.push(
10136
+ /* @__PURE__ */ React16.createElement(Text14, { key: "cursor-eol", color: accentColor }, "\u258C")
10137
+ );
10138
+ }
10139
+ return /* @__PURE__ */ React16.createElement(React16.Fragment, null, out);
10140
+ }
10141
+ function segmentCells(seg) {
10142
+ if (seg.kind === "paste") return seg.label.length;
10143
+ return stringCells(seg.text);
10144
+ }
10145
+ function splitTextByCells(text, cellOffset) {
10146
+ let cells = 0;
10147
+ for (let i = 0; i < text.length; i++) {
10148
+ const ch = text[i];
10149
+ const cw = charCellsForText(ch);
10150
+ if (cells === cellOffset) {
10151
+ return { before: text.slice(0, i), atCursor: ch, after: text.slice(i + 1) };
10152
+ }
10153
+ if (cells + cw > cellOffset) {
10154
+ return { before: text.slice(0, i), atCursor: ch, after: text.slice(i + 1) };
10155
+ }
10156
+ cells += cw;
10157
+ }
10158
+ return { before: text, atCursor: "", after: "" };
10159
+ }
10160
+ function charCellsForText(ch) {
10161
+ const code = ch.charCodeAt(0);
10162
+ if (code < 32 || code === 127) return 0;
10163
+ if (code < 4352) return 1;
10164
+ if (code >= 4352 && code <= 4447) return 2;
10165
+ if (code >= 11904 && code <= 12350) return 2;
10166
+ if (code >= 12353 && code <= 13311) return 2;
10167
+ if (code >= 13312 && code <= 19903) return 2;
10168
+ if (code >= 19968 && code <= 40959) return 2;
10169
+ if (code >= 40960 && code <= 42191) return 2;
10170
+ if (code >= 44032 && code <= 55203) return 2;
10171
+ if (code >= 63744 && code <= 64255) return 2;
10172
+ if (code >= 65072 && code <= 65103) return 2;
10173
+ if (code >= 65280 && code <= 65376) return 2;
10174
+ if (code >= 65504 && code <= 65510) return 2;
10175
+ return 1;
10176
+ }
10177
+ function renderSegment(seg, key, _inverse) {
10178
+ if (seg.kind === "text") {
10179
+ return /* @__PURE__ */ React16.createElement(Text14, { key: `s-${key}` }, seg.text);
10180
+ }
10181
+ return /* @__PURE__ */ React16.createElement(Text14, { key: `s-${key}`, color: "magenta", bold: true }, seg.label);
9551
10182
  }
9552
10183
  var COLLAPSE_THRESHOLD = 20;
9553
10184
  var COLLAPSE_HEAD_LINES = 3;
@@ -9572,63 +10203,13 @@ function collapseLinesForDisplay(lines, cursorLine) {
9572
10203
  }
9573
10204
  return out;
9574
10205
  }
9575
- function RenderLine({
9576
- line,
9577
- pastes,
9578
- inverse
9579
- }) {
9580
- const segments = [];
9581
- let buf = "";
9582
- let segIdx = 0;
9583
- const flushBuf = () => {
9584
- if (buf.length === 0) return;
9585
- segments.push(
9586
- /* @__PURE__ */ React15.createElement(Text14, { key: `t-${segIdx++}`, inverse }, buf)
9587
- );
9588
- buf = "";
9589
- };
9590
- for (let i = 0; i < line.length; i++) {
9591
- const ch = line[i];
9592
- const id = decodePasteSentinel(ch);
9593
- if (id === null) {
9594
- buf += ch;
9595
- continue;
9596
- }
9597
- flushBuf();
9598
- const entry = pastes.get(id);
9599
- const label = entry ? `[paste #${id + 1} \xB7 ${entry.lineCount}l \xB7 ${formatBytesShort(entry.charCount)}]` : `[paste #${id + 1} \xB7 (missing)]`;
9600
- segments.push(
9601
- /* @__PURE__ */ React15.createElement(Text14, { key: `p-${segIdx++}`, color: "magenta", bold: true, inverse }, label)
9602
- );
9603
- }
9604
- flushBuf();
9605
- if (segments.length === 0) {
9606
- return /* @__PURE__ */ React15.createElement(Text14, null, " ");
9607
- }
9608
- return /* @__PURE__ */ React15.createElement(React15.Fragment, null, segments);
9609
- }
9610
- function LineWithCursor({
9611
- line,
9612
- col,
9613
- showCursor,
9614
- borderColor,
9615
- pastes
9616
- }) {
9617
- const before = line.slice(0, col);
9618
- const atCursor = line.slice(col, col + 1);
9619
- const after = line.slice(col + 1);
9620
- if (atCursor.length === 0) {
9621
- return /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement(RenderLine, { line: before, pastes }), /* @__PURE__ */ React15.createElement(Text14, { color: borderColor }, showCursor ? "\u258C" : " "));
9622
- }
9623
- return /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement(RenderLine, { line: before, pastes }), /* @__PURE__ */ React15.createElement(RenderLine, { line: atCursor, pastes, inverse: showCursor }), /* @__PURE__ */ React15.createElement(RenderLine, { line: after, pastes }));
9624
- }
9625
10206
 
9626
10207
  // src/cli/ui/ShellConfirm.tsx
9627
10208
  import { Box as Box15, Text as Text15 } from "ink";
9628
- import React16 from "react";
10209
+ import React17 from "react";
9629
10210
  function ShellConfirm({ command, allowPrefix, kind, onChoose }) {
9630
10211
  const isBackground = kind === "run_background";
9631
- return /* @__PURE__ */ React16.createElement(Box15, { flexDirection: "column", borderStyle: "round", borderColor: "red", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React16.createElement(Box15, null, /* @__PURE__ */ React16.createElement(Text15, { bold: true, color: "red" }, isBackground ? "\u25B8 model wants to start a BACKGROUND process" : "\u25B8 model wants to run a shell command")), isBackground ? /* @__PURE__ */ React16.createElement(Box15, null, /* @__PURE__ */ React16.createElement(Text15, { dimColor: true }, " (long-running: dev server / watcher; keeps running after approval, /kill to stop)")) : null, /* @__PURE__ */ React16.createElement(Box15, null, /* @__PURE__ */ React16.createElement(Text15, { color: "red", 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__ */ React16.createElement(Box15, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text15, null, /* @__PURE__ */ React16.createElement(Text15, { dimColor: true }, "$ "), /* @__PURE__ */ React16.createElement(Text15, { color: "cyan" }, command))), /* @__PURE__ */ React16.createElement(Box15, { marginTop: 1 }, /* @__PURE__ */ React16.createElement(
10212
+ return /* @__PURE__ */ React17.createElement(Box15, { flexDirection: "column", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React17.createElement(Box15, null, /* @__PURE__ */ React17.createElement(Text15, { bold: true, color: "red" }, isBackground ? "\u25B8 model wants to start a BACKGROUND process" : "\u25B8 model wants to run a shell command")), isBackground ? /* @__PURE__ */ React17.createElement(Box15, null, /* @__PURE__ */ React17.createElement(Text15, { dimColor: true }, " (long-running: dev server / watcher; keeps running after approval, /kill to stop)")) : null, /* @__PURE__ */ React17.createElement(Box15, null, /* @__PURE__ */ React17.createElement(Text15, { color: "red", 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__ */ React17.createElement(Box15, { marginTop: 1 }, /* @__PURE__ */ React17.createElement(Text15, null, /* @__PURE__ */ React17.createElement(Text15, { dimColor: true }, "$ "), /* @__PURE__ */ React17.createElement(Text15, { color: "cyan" }, command))), /* @__PURE__ */ React17.createElement(Box15, { marginTop: 1 }, /* @__PURE__ */ React17.createElement(
9632
10213
  SingleSelect,
9633
10214
  {
9634
10215
  initialValue: "run_once",
@@ -9686,7 +10267,7 @@ function derivePrefix(command) {
9686
10267
 
9687
10268
  // src/cli/ui/SlashArgPicker.tsx
9688
10269
  import { Box as Box16, Text as Text16 } from "ink";
9689
- import React17 from "react";
10270
+ import React18 from "react";
9690
10271
  function SlashArgPicker({
9691
10272
  matches,
9692
10273
  selectedIndex,
@@ -9695,11 +10276,11 @@ function SlashArgPicker({
9695
10276
  partial
9696
10277
  }) {
9697
10278
  if (kind === "hint") {
9698
- return /* @__PURE__ */ React17.createElement(Box16, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React17.createElement(Text16, { dimColor: true }, " ", /* @__PURE__ */ React17.createElement(Text16, { bold: true }, "/", spec.cmd), spec.argsHint ? ` ${spec.argsHint}` : "", " \u2014 ", spec.summary));
10279
+ return /* @__PURE__ */ React18.createElement(Box16, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React18.createElement(Text16, { dimColor: true }, " ", /* @__PURE__ */ React18.createElement(Text16, { bold: true }, "/", spec.cmd), spec.argsHint ? ` ${spec.argsHint}` : "", " \u2014 ", spec.summary));
9699
10280
  }
9700
10281
  if (matches === null) return null;
9701
10282
  if (matches.length === 0) {
9702
- return /* @__PURE__ */ React17.createElement(Box16, { flexDirection: "column", paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React17.createElement(Text16, { dimColor: true }, " ", /* @__PURE__ */ React17.createElement(Text16, { bold: true }, "/", spec.cmd), spec.argsHint ? ` ${spec.argsHint}` : "", " \u2014 ", spec.summary), /* @__PURE__ */ React17.createElement(Text16, { color: "yellow" }, ' no match for "', partial, '" \u2014 keep typing, or Backspace to edit'));
10283
+ return /* @__PURE__ */ React18.createElement(Box16, { flexDirection: "column", paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React18.createElement(Text16, { dimColor: true }, " ", /* @__PURE__ */ React18.createElement(Text16, { bold: true }, "/", spec.cmd), spec.argsHint ? ` ${spec.argsHint}` : "", " \u2014 ", spec.summary), /* @__PURE__ */ React18.createElement(Text16, { color: "yellow" }, ' no match for "', partial, '" \u2014 keep typing, or Backspace to edit'));
9703
10284
  }
9704
10285
  const MAX = 8;
9705
10286
  const total = matches.length;
@@ -9707,26 +10288,26 @@ function SlashArgPicker({
9707
10288
  const shown = matches.slice(windowStart, windowStart + MAX);
9708
10289
  const hiddenAbove = windowStart;
9709
10290
  const hiddenBelow = total - windowStart - shown.length;
9710
- return /* @__PURE__ */ React17.createElement(Box16, { flexDirection: "column", paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React17.createElement(Text16, { dimColor: true }, " ", /* @__PURE__ */ React17.createElement(Text16, { bold: true }, "/", spec.cmd), spec.argsHint ? ` ${spec.argsHint}` : "", " \u2014 ", spec.summary), hiddenAbove > 0 ? /* @__PURE__ */ React17.createElement(Text16, { dimColor: true }, " \u2191 ", hiddenAbove, " more above") : null, shown.map((value, i) => /* @__PURE__ */ React17.createElement(ArgRow, { key: value, value, isSelected: windowStart + i === selectedIndex })), hiddenBelow > 0 ? /* @__PURE__ */ React17.createElement(Text16, { dimColor: true }, " \u2193 ", hiddenBelow, " more below") : null, /* @__PURE__ */ React17.createElement(Text16, { dimColor: true }, " [\u2191\u2193] navigate \xB7 [Tab]/[Enter] pick"));
10291
+ return /* @__PURE__ */ React18.createElement(Box16, { flexDirection: "column", paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React18.createElement(Text16, { dimColor: true }, " ", /* @__PURE__ */ React18.createElement(Text16, { bold: true }, "/", spec.cmd), spec.argsHint ? ` ${spec.argsHint}` : "", " \u2014 ", spec.summary), hiddenAbove > 0 ? /* @__PURE__ */ React18.createElement(Text16, { dimColor: true }, " \u2191 ", hiddenAbove, " more above") : null, shown.map((value, i) => /* @__PURE__ */ React18.createElement(ArgRow, { key: value, value, isSelected: windowStart + i === selectedIndex })), hiddenBelow > 0 ? /* @__PURE__ */ React18.createElement(Text16, { dimColor: true }, " \u2193 ", hiddenBelow, " more below") : null, /* @__PURE__ */ React18.createElement(Text16, { dimColor: true }, " [\u2191\u2193] navigate \xB7 [Tab]/[Enter] pick"));
9711
10292
  }
9712
10293
  function ArgRow({ value, isSelected }) {
9713
10294
  const marker = isSelected ? "\u25B8" : " ";
9714
10295
  if (isSelected) {
9715
- return /* @__PURE__ */ React17.createElement(Box16, null, /* @__PURE__ */ React17.createElement(Text16, { bold: true, color: "cyan" }, marker, " ", value));
10296
+ return /* @__PURE__ */ React18.createElement(Box16, null, /* @__PURE__ */ React18.createElement(Text16, { bold: true, color: "cyan" }, marker, " ", value));
9716
10297
  }
9717
- return /* @__PURE__ */ React17.createElement(Box16, null, /* @__PURE__ */ React17.createElement(Text16, { dimColor: true }, marker, " ", value));
10298
+ return /* @__PURE__ */ React18.createElement(Box16, null, /* @__PURE__ */ React18.createElement(Text16, { dimColor: true }, marker, " ", value));
9718
10299
  }
9719
10300
 
9720
10301
  // src/cli/ui/SlashSuggestions.tsx
9721
10302
  import { Box as Box17, Text as Text17 } from "ink";
9722
- import React18 from "react";
10303
+ import React19 from "react";
9723
10304
  function SlashSuggestions({
9724
10305
  matches,
9725
10306
  selectedIndex
9726
10307
  }) {
9727
10308
  if (matches === null) return null;
9728
10309
  if (matches.length === 0) {
9729
- return /* @__PURE__ */ React18.createElement(Box17, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React18.createElement(Text17, { color: "yellow" }, "no slash command matches that prefix"), /* @__PURE__ */ React18.createElement(Text17, { dimColor: true }, " \u2014 Backspace to edit, or /help for the full list"));
10310
+ return /* @__PURE__ */ React19.createElement(Box17, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React19.createElement(Text17, { color: "yellow" }, "no slash command matches that prefix"), /* @__PURE__ */ React19.createElement(Text17, { dimColor: true }, " \u2014 Backspace to edit, or /help for the full list"));
9730
10311
  }
9731
10312
  const MAX = 8;
9732
10313
  const total = matches.length;
@@ -9734,21 +10315,21 @@ function SlashSuggestions({
9734
10315
  const shown = matches.slice(windowStart, windowStart + MAX);
9735
10316
  const hiddenAbove = windowStart;
9736
10317
  const hiddenBelow = total - windowStart - shown.length;
9737
- return /* @__PURE__ */ React18.createElement(Box17, { flexDirection: "column", paddingX: 1, marginTop: 1 }, hiddenAbove > 0 ? /* @__PURE__ */ React18.createElement(Text17, { dimColor: true }, " \u2191 ", hiddenAbove, " more above") : null, shown.map((spec, i) => /* @__PURE__ */ React18.createElement(SuggestionRow, { key: spec.cmd, spec, isSelected: windowStart + i === selectedIndex })), hiddenBelow > 0 ? /* @__PURE__ */ React18.createElement(Text17, { dimColor: true }, " \u2193 ", hiddenBelow, " more below") : null, /* @__PURE__ */ React18.createElement(Text17, { dimColor: true }, " [\u2191\u2193] navigate \xB7 [Tab]/[Enter] pick"));
10318
+ return /* @__PURE__ */ React19.createElement(Box17, { flexDirection: "column", paddingX: 1, marginTop: 1 }, hiddenAbove > 0 ? /* @__PURE__ */ React19.createElement(Text17, { dimColor: true }, " \u2191 ", hiddenAbove, " more above") : null, shown.map((spec, i) => /* @__PURE__ */ React19.createElement(SuggestionRow, { key: spec.cmd, spec, isSelected: windowStart + i === selectedIndex })), hiddenBelow > 0 ? /* @__PURE__ */ React19.createElement(Text17, { dimColor: true }, " \u2193 ", hiddenBelow, " more below") : null, /* @__PURE__ */ React19.createElement(Text17, { dimColor: true }, " [\u2191\u2193] navigate \xB7 [Tab]/[Enter] pick"));
9738
10319
  }
9739
10320
  function SuggestionRow({ spec, isSelected }) {
9740
10321
  const marker = isSelected ? "\u25B8" : " ";
9741
10322
  const name = `/${spec.cmd}`;
9742
10323
  const argsSuffix = spec.argsHint ? ` ${spec.argsHint}` : "";
9743
10324
  if (isSelected) {
9744
- return /* @__PURE__ */ React18.createElement(Box17, null, /* @__PURE__ */ React18.createElement(Text17, { bold: true, color: "cyan" }, marker, " ", name.padEnd(12), argsSuffix.padEnd(16)), /* @__PURE__ */ React18.createElement(Text17, { color: "cyan" }, " ", spec.summary));
10325
+ return /* @__PURE__ */ React19.createElement(Box17, null, /* @__PURE__ */ React19.createElement(Text17, { bold: true, color: "cyan" }, marker, " ", name.padEnd(12), argsSuffix.padEnd(16)), /* @__PURE__ */ React19.createElement(Text17, { color: "cyan" }, " ", spec.summary));
9745
10326
  }
9746
- return /* @__PURE__ */ React18.createElement(Box17, null, /* @__PURE__ */ React18.createElement(Text17, { dimColor: true }, marker, " ", name.padEnd(12), argsSuffix.padEnd(16), " ", spec.summary));
10327
+ return /* @__PURE__ */ React19.createElement(Box17, null, /* @__PURE__ */ React19.createElement(Text17, { dimColor: true }, marker, " ", name.padEnd(12), argsSuffix.padEnd(16), " ", spec.summary));
9747
10328
  }
9748
10329
 
9749
10330
  // src/cli/ui/StatsPanel.tsx
9750
10331
  import { Box as Box18, Text as Text18, useStdout as useStdout4 } from "ink";
9751
- import React19 from "react";
10332
+ import React20 from "react";
9752
10333
  var WORDMARK_STYLES = [
9753
10334
  { ch: "\u25C8", color: "#5eead4", isLogo: true },
9754
10335
  // teal — brand mark
@@ -9774,7 +10355,7 @@ function Wordmark({ busy }) {
9774
10355
  const tick = useTick();
9775
10356
  const period = busy ? 5 : 12;
9776
10357
  const bright = Math.floor(tick / period) % 2 === 0;
9777
- return /* @__PURE__ */ React19.createElement(Text18, null, WORDMARK_STYLES.map((c) => /* @__PURE__ */ React19.createElement(Text18, { key: `${c.ch}-${c.color}`, color: c.color, bold: c.isLogo ? bright : true }, c.ch)));
10358
+ return /* @__PURE__ */ React20.createElement(Text18, null, WORDMARK_STYLES.map((c) => /* @__PURE__ */ React20.createElement(Text18, { key: `${c.ch}-${c.color}`, color: c.color, bold: c.isLogo ? bright : true }, c.ch)));
9778
10359
  }
9779
10360
  var NARROW_BREAKPOINT = 120;
9780
10361
  var COLD_START_TURNS = 3;
@@ -9800,17 +10381,16 @@ function StatsPanel({
9800
10381
  const columns = stdout2?.columns ?? 80;
9801
10382
  const narrow = columns < NARROW_BREAKPOINT;
9802
10383
  const coldStart = summary.turns <= COLD_START_TURNS;
10384
+ const ruleWidth = Math.max(20, columns - 2);
9803
10385
  return (
9804
- // Explicit `width={columns}` pins the border frame to the exact
9805
- // terminal width. Without this, Ink auto-flexes the Box to
9806
- // container width, and on terminal resize the prior frame's
9807
- // wrapped-overflow can leave tails in the scrollback (each
9808
- // redraw stacks a slightly-wider-or-narrower frame). Fixing
9809
- // width per-render doesn't eliminate the underlying Ink
9810
- // limitation (eraseLines counts logical rows, not post-wrap
9811
- // display rows) but makes each frame's dimensions exact so
9812
- // there's no residual uncertainty in the erase.
9813
- /* @__PURE__ */ React19.createElement(Box18, { borderStyle: "round", borderColor: "cyan", flexDirection: "column", paddingX: 1, width: columns }, /* @__PURE__ */ React19.createElement(
10386
+ // Borderless layout: no `borderStyle`, no rounded box, no `width={cols}`
10387
+ // pinning. Bordered Boxes were the most visible amplifier of Ink's
10388
+ // eraseLines miscount on Windows terminals every miscounted render
10389
+ // pushed a top-border frame into scrollback. Without a border there
10390
+ // is nothing visually obvious to duplicate; visual structure comes
10391
+ // from the gradient wordmark + colored pills + a top/bottom margin
10392
+ // + a thin dim rule that closes the panel cleanly under the metrics.
10393
+ /* @__PURE__ */ React20.createElement(Box18, { flexDirection: "column", paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React20.createElement(
9814
10394
  Header,
9815
10395
  {
9816
10396
  model: model2,
@@ -9828,7 +10408,7 @@ function StatsPanel({
9828
10408
  proArmed: proArmed ?? false,
9829
10409
  escalated: escalated ?? false
9830
10410
  }
9831
- ), narrow ? /* @__PURE__ */ React19.createElement(
10411
+ ), narrow ? /* @__PURE__ */ React20.createElement(
9832
10412
  StackedMetrics,
9833
10413
  {
9834
10414
  summary,
@@ -9837,7 +10417,7 @@ function StatsPanel({
9837
10417
  balance,
9838
10418
  coldStart
9839
10419
  }
9840
- ) : /* @__PURE__ */ React19.createElement(
10420
+ ) : /* @__PURE__ */ React20.createElement(
9841
10421
  InlineMetrics,
9842
10422
  {
9843
10423
  summary,
@@ -9846,7 +10426,7 @@ function StatsPanel({
9846
10426
  balance,
9847
10427
  coldStart
9848
10428
  }
9849
- ))
10429
+ ), /* @__PURE__ */ React20.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, "\u2500".repeat(ruleWidth))))
9850
10430
  );
9851
10431
  }
9852
10432
  function Header({
@@ -9865,7 +10445,12 @@ function Header({
9865
10445
  proArmed,
9866
10446
  escalated
9867
10447
  }) {
9868
- return /* @__PURE__ */ React19.createElement(Box18, { justifyContent: "space-between" }, /* @__PURE__ */ React19.createElement(Box18, null, /* @__PURE__ */ React19.createElement(Wordmark, { busy }), /* @__PURE__ */ React19.createElement(Text18, { dimColor: true }, ` v${VERSION}`), /* @__PURE__ */ React19.createElement(Text18, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React19.createElement(Text18, { color: "yellow" }, model2), narrow ? null : /* @__PURE__ */ React19.createElement(React19.Fragment, null, /* @__PURE__ */ React19.createElement(Text18, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React19.createElement(Text18, { dimColor: true }, prefixHash)), harvestOn ? /* @__PURE__ */ React19.createElement(Text18, { color: "magenta" }, " \xB7 harvest") : null, branchOn ? /* @__PURE__ */ React19.createElement(Text18, { color: "blue" }, " \xB7 branch", branchBudget) : null, reasoningEffort === "max" ? /* @__PURE__ */ React19.createElement(Text18, { color: "green" }, " \xB7 max") : null, reasoningEffort === "high" ? /* @__PURE__ */ React19.createElement(Text18, { color: "yellow" }, " \xB7 high") : null, planMode ? /* @__PURE__ */ React19.createElement(Text18, { color: "red", bold: true }, " \xB7 PLAN") : null, editMode ? /* @__PURE__ */ React19.createElement(Text18, { color: editMode === "auto" ? "magenta" : "cyan", bold: true }, editMode === "auto" ? " \xB7 AUTO" : " \xB7 review") : null, escalated ? /* @__PURE__ */ React19.createElement(Text18, { color: "red", bold: true }, " \xB7 \u21E7 pro escalated") : proArmed ? /* @__PURE__ */ React19.createElement(Text18, { color: "yellow", bold: true }, " \xB7 \u21E7 pro armed") : null), /* @__PURE__ */ React19.createElement(Text18, null, updateAvailable ? /* @__PURE__ */ React19.createElement(Text18, { color: "yellow", bold: true }, `update: ${updateAvailable} \xB7 `) : null, /* @__PURE__ */ React19.createElement(Text18, { dimColor: true }, narrow ? `turn ${turns}` : `turn ${turns} \xB7 /help`)));
10448
+ const modePill = planMode ? { label: "PLAN", bg: "red" } : editMode === "auto" ? { label: "AUTO", bg: "magenta" } : editMode === "review" ? { label: "REVIEW", bg: "cyan" } : null;
10449
+ const proPill = escalated ? { label: "\u21E7 PRO", bg: "red" } : proArmed ? { label: "\u21E7 PRO", bg: "yellow" } : null;
10450
+ return /* @__PURE__ */ React20.createElement(Box18, { justifyContent: "space-between" }, /* @__PURE__ */ React20.createElement(Box18, null, /* @__PURE__ */ React20.createElement(Wordmark, { busy }), /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, ` ${VERSION}`), /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, " "), /* @__PURE__ */ React20.createElement(Text18, { color: "yellow", bold: true }, model2.replace(/^deepseek-/, "")), modePill ? /* @__PURE__ */ React20.createElement(React20.Fragment, null, /* @__PURE__ */ React20.createElement(Text18, null, " "), /* @__PURE__ */ React20.createElement(Pill, { label: modePill.label, bg: modePill.bg })) : null, proPill ? /* @__PURE__ */ React20.createElement(React20.Fragment, null, /* @__PURE__ */ React20.createElement(Text18, null, " "), /* @__PURE__ */ React20.createElement(Pill, { label: proPill.label, bg: proPill.bg })) : null, harvestOn ? /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, /* @__PURE__ */ React20.createElement(Text18, null, " "), /* @__PURE__ */ React20.createElement(Text18, { color: "magenta" }, "harvest")) : null, branchOn ? /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, /* @__PURE__ */ React20.createElement(Text18, null, " "), /* @__PURE__ */ React20.createElement(Text18, { color: "blue" }, `branch\xD7${branchBudget}`)) : null, reasoningEffort === "max" ? /* @__PURE__ */ React20.createElement(React20.Fragment, null, /* @__PURE__ */ React20.createElement(Text18, null, " "), /* @__PURE__ */ React20.createElement(Text18, { color: "green", dimColor: true }, "max")) : null, reasoningEffort === "high" ? /* @__PURE__ */ React20.createElement(React20.Fragment, null, /* @__PURE__ */ React20.createElement(Text18, null, " "), /* @__PURE__ */ React20.createElement(Text18, { color: "yellow", dimColor: true }, "high")) : null), /* @__PURE__ */ React20.createElement(Text18, null, updateAvailable ? /* @__PURE__ */ React20.createElement(Text18, { color: "yellow", bold: true }, `\u2191 ${updateAvailable} `) : null, /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, narrow ? `t${turns}` : `turn ${turns} \xB7 /help`)));
10451
+ }
10452
+ function Pill({ label, bg }) {
10453
+ return /* @__PURE__ */ React20.createElement(Text18, { backgroundColor: bg, color: "white", bold: true }, ` ${label} `);
9869
10454
  }
9870
10455
  function InlineMetrics({
9871
10456
  summary,
@@ -9874,7 +10459,7 @@ function InlineMetrics({
9874
10459
  balance,
9875
10460
  coldStart
9876
10461
  }) {
9877
- return /* @__PURE__ */ React19.createElement(Box18, { marginTop: 1, gap: 3 }, /* @__PURE__ */ React19.createElement(ContextCell, { ratio: ctxRatio, promptTokens: summary.lastPromptTokens, ctxMax }), /* @__PURE__ */ React19.createElement(CacheCell, { hitRatio: summary.cacheHitRatio, coldStart, turns: summary.turns }), /* @__PURE__ */ React19.createElement(CostCell, { summary, coldStart }), balance ? /* @__PURE__ */ React19.createElement(BalanceCell, { balance }) : null);
10462
+ return /* @__PURE__ */ React20.createElement(Box18, { marginTop: 1, gap: 3 }, /* @__PURE__ */ React20.createElement(ContextCell, { ratio: ctxRatio, promptTokens: summary.lastPromptTokens, ctxMax }), /* @__PURE__ */ React20.createElement(CacheCell, { hitRatio: summary.cacheHitRatio, coldStart, turns: summary.turns }), /* @__PURE__ */ React20.createElement(CostCell, { summary, coldStart }), balance ? /* @__PURE__ */ React20.createElement(BalanceCell, { balance }) : null);
9878
10463
  }
9879
10464
  function StackedMetrics({
9880
10465
  summary,
@@ -9883,7 +10468,7 @@ function StackedMetrics({
9883
10468
  balance,
9884
10469
  coldStart
9885
10470
  }) {
9886
- return /* @__PURE__ */ React19.createElement(Box18, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React19.createElement(
10471
+ return /* @__PURE__ */ React20.createElement(Box18, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React20.createElement(
9887
10472
  ContextCell,
9888
10473
  {
9889
10474
  ratio: ctxRatio,
@@ -9891,7 +10476,7 @@ function StackedMetrics({
9891
10476
  ctxMax,
9892
10477
  showBar: true
9893
10478
  }
9894
- ), balance ? /* @__PURE__ */ React19.createElement(BalanceCell, { balance }) : null, /* @__PURE__ */ React19.createElement(CacheCell, { hitRatio: summary.cacheHitRatio, coldStart, turns: summary.turns }), /* @__PURE__ */ React19.createElement(CostCell, { summary, coldStart }));
10479
+ ), balance ? /* @__PURE__ */ React20.createElement(BalanceCell, { balance }) : null, /* @__PURE__ */ React20.createElement(CacheCell, { hitRatio: summary.cacheHitRatio, coldStart, turns: summary.turns }), /* @__PURE__ */ React20.createElement(CostCell, { summary, coldStart }));
9895
10480
  }
9896
10481
  function ContextCell({
9897
10482
  ratio,
@@ -9900,11 +10485,11 @@ function ContextCell({
9900
10485
  showBar
9901
10486
  }) {
9902
10487
  if (promptTokens === 0) {
9903
- return /* @__PURE__ */ React19.createElement(Text18, null, /* @__PURE__ */ React19.createElement(Text18, { dimColor: true }, "ctx "), /* @__PURE__ */ React19.createElement(Text18, { dimColor: true }, "\u2014 (no turns yet)"));
10488
+ return /* @__PURE__ */ React20.createElement(Text18, null, /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, "ctx "), /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, "\u2014 (no turns yet)"));
9904
10489
  }
9905
10490
  const color = ratio >= 0.8 ? "red" : ratio >= 0.6 ? "yellow" : "green";
9906
10491
  const pct2 = Math.round(ratio * 100);
9907
- return /* @__PURE__ */ React19.createElement(Text18, null, /* @__PURE__ */ React19.createElement(Text18, { dimColor: true }, "ctx "), showBar ? /* @__PURE__ */ React19.createElement(Bar, { ratio, color }) : null, showBar ? /* @__PURE__ */ React19.createElement(Text18, null, " ") : null, /* @__PURE__ */ React19.createElement(Text18, { color, bold: true }, formatTokens(promptTokens), "/", formatTokens(ctxMax)), /* @__PURE__ */ React19.createElement(Text18, { dimColor: true }, " (", pct2, "%)"), ratio >= 0.8 ? /* @__PURE__ */ React19.createElement(Text18, { color: "red", bold: true }, " \xB7 /compact") : null);
10492
+ return /* @__PURE__ */ React20.createElement(Text18, null, /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, "ctx "), showBar ? /* @__PURE__ */ React20.createElement(Bar, { ratio, color }) : null, showBar ? /* @__PURE__ */ React20.createElement(Text18, null, " ") : null, /* @__PURE__ */ React20.createElement(Text18, { color, bold: true }, formatTokens(promptTokens), "/", formatTokens(ctxMax)), /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, " (", pct2, "%)"), ratio >= 0.8 ? /* @__PURE__ */ React20.createElement(Text18, { color: "red", bold: true }, " \xB7 /compact") : null);
9908
10493
  }
9909
10494
  function CacheCell({
9910
10495
  hitRatio,
@@ -9913,13 +10498,13 @@ function CacheCell({
9913
10498
  }) {
9914
10499
  const pct2 = (hitRatio * 100).toFixed(1);
9915
10500
  if (turns === 0) {
9916
- return /* @__PURE__ */ React19.createElement(Text18, null, /* @__PURE__ */ React19.createElement(Text18, { dimColor: true }, "cache "), /* @__PURE__ */ React19.createElement(Text18, { dimColor: true }, "\u2014"));
10501
+ return /* @__PURE__ */ React20.createElement(Text18, null, /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, "cache "), /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, "\u2014"));
9917
10502
  }
9918
10503
  if (coldStart) {
9919
- return /* @__PURE__ */ React19.createElement(Text18, null, /* @__PURE__ */ React19.createElement(Text18, { dimColor: true }, "cache "), /* @__PURE__ */ React19.createElement(Text18, { dimColor: true }, pct2, "% "), /* @__PURE__ */ React19.createElement(Text18, { dimColor: true, italic: true }, "(cold start)"));
10504
+ return /* @__PURE__ */ React20.createElement(Text18, null, /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, "cache "), /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, pct2, "% "), /* @__PURE__ */ React20.createElement(Text18, { dimColor: true, italic: true }, "(cold start)"));
9920
10505
  }
9921
10506
  const color = hitRatio >= 0.7 ? "green" : hitRatio >= 0.4 ? "yellow" : "red";
9922
- return /* @__PURE__ */ React19.createElement(Text18, null, /* @__PURE__ */ React19.createElement(Text18, { dimColor: true }, "cache "), /* @__PURE__ */ React19.createElement(Text18, { color, bold: true }, pct2, "%"));
10507
+ return /* @__PURE__ */ React20.createElement(Text18, null, /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, "cache "), /* @__PURE__ */ React20.createElement(Text18, { color, bold: true }, pct2, "%"));
9923
10508
  }
9924
10509
  function turnCostColor(cost) {
9925
10510
  if (cost <= 0) return void 0;
@@ -9938,21 +10523,21 @@ function CostCell({
9938
10523
  coldStart
9939
10524
  }) {
9940
10525
  if (summary.turns === 0) {
9941
- return /* @__PURE__ */ React19.createElement(Text18, null, /* @__PURE__ */ React19.createElement(Text18, { dimColor: true }, "cost "), /* @__PURE__ */ React19.createElement(Text18, { dimColor: true }, "\u2014"));
10526
+ return /* @__PURE__ */ React20.createElement(Text18, null, /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, "cost "), /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, "\u2014"));
9942
10527
  }
9943
10528
  const turnColor = coldStart ? void 0 : turnCostColor(summary.lastTurnCostUsd);
9944
10529
  const sessionColor = coldStart ? void 0 : sessionCostColor(summary.totalCostUsd);
9945
- return /* @__PURE__ */ React19.createElement(Text18, null, /* @__PURE__ */ React19.createElement(Text18, { dimColor: true }, "turn "), /* @__PURE__ */ React19.createElement(Text18, { color: turnColor, bold: !coldStart, dimColor: coldStart }, "$", summary.lastTurnCostUsd.toFixed(4)), /* @__PURE__ */ React19.createElement(Text18, { dimColor: true }, " \xB7 session "), /* @__PURE__ */ React19.createElement(Text18, { color: sessionColor, bold: !coldStart, dimColor: coldStart }, "$", summary.totalCostUsd.toFixed(4)));
10530
+ return /* @__PURE__ */ React20.createElement(Text18, null, /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, "turn "), /* @__PURE__ */ React20.createElement(Text18, { color: turnColor, bold: !coldStart, dimColor: coldStart }, "$", summary.lastTurnCostUsd.toFixed(4)), /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, " \xB7 session "), /* @__PURE__ */ React20.createElement(Text18, { color: sessionColor, bold: !coldStart, dimColor: coldStart }, "$", summary.totalCostUsd.toFixed(4)));
9946
10531
  }
9947
10532
  function BalanceCell({ balance }) {
9948
10533
  const color = balance.total < 1 ? "red" : balance.total < 5 ? "yellow" : "green";
9949
- return /* @__PURE__ */ React19.createElement(Text18, null, /* @__PURE__ */ React19.createElement(Text18, { dimColor: true }, "balance "), /* @__PURE__ */ React19.createElement(Text18, { color, bold: true }, balance.currency === "USD" ? "$" : "", balance.total.toFixed(2), balance.currency !== "USD" ? ` ${balance.currency}` : ""));
10534
+ return /* @__PURE__ */ React20.createElement(Text18, null, /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, "balance "), /* @__PURE__ */ React20.createElement(Text18, { color, bold: true }, balance.currency === "USD" ? "$" : "", balance.total.toFixed(2), balance.currency !== "USD" ? ` ${balance.currency}` : ""));
9950
10535
  }
9951
10536
  function Bar({ ratio, color }) {
9952
10537
  const cells = 10;
9953
10538
  const filled = Math.max(0, Math.min(cells, Math.round(ratio * cells)));
9954
10539
  const bar = "\u2588".repeat(filled) + "\u2591".repeat(cells - filled);
9955
- return /* @__PURE__ */ React19.createElement(Text18, { color }, bar);
10540
+ return /* @__PURE__ */ React20.createElement(Text18, { color }, bar);
9956
10541
  }
9957
10542
  function formatTokens(n) {
9958
10543
  if (n < 1024) return String(n);
@@ -9960,6 +10545,16 @@ function formatTokens(n) {
9960
10545
  return k >= 100 ? `${k.toFixed(0)}K` : `${k.toFixed(1)}K`;
9961
10546
  }
9962
10547
 
10548
+ // src/cli/ui/WelcomeBanner.tsx
10549
+ import { Box as Box19, Text as Text19 } from "ink";
10550
+ import React21 from "react";
10551
+ function WelcomeBanner({ inCodeMode }) {
10552
+ return /* @__PURE__ */ React21.createElement(Box19, { flexDirection: "column", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React21.createElement(Box19, null, /* @__PURE__ */ React21.createElement(Text19, { bold: true, color: "cyan" }, "Hi"), /* @__PURE__ */ React21.createElement(Text19, null, " \u2014 type a message to start, or try:")), /* @__PURE__ */ React21.createElement(Box19, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React21.createElement(Hint, { cmd: "/help", desc: "every command + keyboard shortcut" }), /* @__PURE__ */ React21.createElement(Hint, { cmd: "/skill", desc: "invoke a stored playbook" }), inCodeMode ? /* @__PURE__ */ React21.createElement(React21.Fragment, null, /* @__PURE__ */ React21.createElement(Hint, { cmd: "@path", desc: "inline a file in your message" }), /* @__PURE__ */ React21.createElement(Hint, { cmd: "!cmd", desc: "run a shell command, output goes to context" })) : null, /* @__PURE__ */ React21.createElement(Hint, { cmd: "/exit", desc: "quit" })));
10553
+ }
10554
+ function Hint({ cmd, desc }) {
10555
+ return /* @__PURE__ */ React21.createElement(Box19, null, /* @__PURE__ */ React21.createElement(Text19, { dimColor: true }, " "), /* @__PURE__ */ React21.createElement(Text19, { bold: true, color: "magenta" }, cmd.padEnd(8)), /* @__PURE__ */ React21.createElement(Text19, { dimColor: true }, ` ${desc}`));
10556
+ }
10557
+
9963
10558
  // src/cli/ui/bang.ts
9964
10559
  function detectBangCommand(text) {
9965
10560
  if (!text.startsWith("!")) return null;
@@ -11800,7 +12395,7 @@ function handleSlash(cmd, args, loop, ctx = {}) {
11800
12395
  }
11801
12396
 
11802
12397
  // src/cli/ui/useCompletionPickers.ts
11803
- import { useCallback, useEffect as useEffect2, useMemo as useMemo2, useRef as useRef2, useState as useState6 } from "react";
12398
+ import { useCallback, useEffect as useEffect3, useMemo as useMemo2, useRef as useRef3, useState as useState6 } from "react";
11804
12399
  function useCompletionPickers({
11805
12400
  input,
11806
12401
  setInput,
@@ -11813,7 +12408,7 @@ function useCompletionPickers({
11813
12408
  if (!input.startsWith("/") || input.includes(" ")) return null;
11814
12409
  return suggestSlashCommands(input.slice(1), !!codeMode);
11815
12410
  }, [input, codeMode]);
11816
- useEffect2(() => {
12411
+ useEffect3(() => {
11817
12412
  setSlashSelected((prev) => {
11818
12413
  if (!slashMatches || slashMatches.length === 0) return 0;
11819
12414
  if (prev >= slashMatches.length) return slashMatches.length - 1;
@@ -11829,7 +12424,7 @@ function useCompletionPickers({
11829
12424
  return [];
11830
12425
  }
11831
12426
  }, [codeMode?.rootDir]);
11832
- const recentFilesRef = useRef2([]);
12427
+ const recentFilesRef = useRef3([]);
11833
12428
  const recordRecentFile = useCallback((p) => {
11834
12429
  const list = recentFilesRef.current;
11835
12430
  const i = list.indexOf(p);
@@ -11849,7 +12444,7 @@ function useCompletionPickers({
11849
12444
  recentlyUsed: recentFilesRef.current
11850
12445
  });
11851
12446
  }, [atPicker, atFiles]);
11852
- useEffect2(() => {
12447
+ useEffect3(() => {
11853
12448
  setAtSelected((prev) => {
11854
12449
  if (!atMatches || atMatches.length === 0) return 0;
11855
12450
  if (prev >= atMatches.length) return atMatches.length - 1;
@@ -11910,7 +12505,7 @@ function useCompletionPickers({
11910
12505
  }
11911
12506
  return null;
11912
12507
  }, [slashArgContext, models2, mcpServers]);
11913
- useEffect2(() => {
12508
+ useEffect3(() => {
11914
12509
  setSlashArgSelected((prev) => {
11915
12510
  if (!slashArgMatches || slashArgMatches.length === 0) return 0;
11916
12511
  if (prev >= slashArgMatches.length) return slashArgMatches.length - 1;
@@ -11944,13 +12539,13 @@ function useCompletionPickers({
11944
12539
  }
11945
12540
 
11946
12541
  // src/cli/ui/useEditHistory.ts
11947
- import { useCallback as useCallback2, useRef as useRef3, useState as useState7 } from "react";
12542
+ import { useCallback as useCallback2, useRef as useRef4, useState as useState7 } from "react";
11948
12543
  function useEditHistory(codeMode) {
11949
- const editHistory = useRef3([]);
11950
- const nextHistoryId = useRef3(1);
11951
- const currentTurnEntry = useRef3(null);
12544
+ const editHistory = useRef4([]);
12545
+ const nextHistoryId = useRef4(1);
12546
+ const currentTurnEntry = useRef4(null);
11952
12547
  const [undoBanner, setUndoBanner] = useState7(null);
11953
- const undoTimeoutRef = useRef3(null);
12548
+ const undoTimeoutRef = useRef4(null);
11954
12549
  const recordEdit = useCallback2(
11955
12550
  (source, blocks, results, snaps) => {
11956
12551
  if (snaps.length === 0) return;
@@ -12146,12 +12741,12 @@ function useEditHistory(codeMode) {
12146
12741
  }
12147
12742
 
12148
12743
  // src/cli/ui/useSessionInfo.ts
12149
- import { useCallback as useCallback3, useEffect as useEffect3, useState as useState8 } from "react";
12744
+ import { useCallback as useCallback3, useEffect as useEffect4, useState as useState8 } from "react";
12150
12745
  function useSessionInfo(loop) {
12151
12746
  const [balance, setBalance] = useState8(null);
12152
12747
  const [models2, setModels] = useState8(null);
12153
12748
  const [latestVersion, setLatestVersion] = useState8(null);
12154
- useEffect3(() => {
12749
+ useEffect4(() => {
12155
12750
  let cancelled = false;
12156
12751
  void (async () => {
12157
12752
  const bal = await loop.client.getBalance().catch(() => null);
@@ -12163,7 +12758,7 @@ function useSessionInfo(loop) {
12163
12758
  cancelled = true;
12164
12759
  };
12165
12760
  }, [loop]);
12166
- useEffect3(() => {
12761
+ useEffect4(() => {
12167
12762
  let cancelled = false;
12168
12763
  void (async () => {
12169
12764
  const list = await loop.client.listModels().catch(() => null);
@@ -12174,7 +12769,7 @@ function useSessionInfo(loop) {
12174
12769
  cancelled = true;
12175
12770
  };
12176
12771
  }, [loop]);
12177
- useEffect3(() => {
12772
+ useEffect4(() => {
12178
12773
  let cancelled = false;
12179
12774
  void (async () => {
12180
12775
  const latest = await getLatestVersion();
@@ -12219,11 +12814,11 @@ function useSessionInfo(loop) {
12219
12814
  }
12220
12815
 
12221
12816
  // src/cli/ui/useSubagent.ts
12222
- import { useEffect as useEffect4, useRef as useRef4, useState as useState9 } from "react";
12817
+ import { useEffect as useEffect5, useRef as useRef5, useState as useState9 } from "react";
12223
12818
  function useSubagent({ session, setHistorical }) {
12224
12819
  const [activity, setActivity] = useState9(null);
12225
- const sinkRef = useRef4({ current: null });
12226
- useEffect4(() => {
12820
+ const sinkRef = useRef5({ current: null });
12821
+ useEffect5(() => {
12227
12822
  sinkRef.current.current = (ev) => {
12228
12823
  if (ev.kind === "start") {
12229
12824
  setActivity({
@@ -12296,15 +12891,17 @@ function App({
12296
12891
  const [streaming, setStreaming] = useState10(null);
12297
12892
  const [input, setInput] = useState10("");
12298
12893
  const [busy, setBusy] = useState10(false);
12299
- const abortedThisTurn = useRef5(false);
12894
+ const abortedThisTurn = useRef6(false);
12300
12895
  const [ongoingTool, setOngoingTool] = useState10(null);
12301
12896
  const [toolProgress, setToolProgress] = useState10(null);
12302
12897
  const { stdout: stdout2 } = useStdout5();
12303
- useEffect5(() => {
12898
+ useEffect6(() => {
12304
12899
  if (!stdout2 || !stdout2.isTTY) return;
12305
12900
  stdout2.write("\x1B[?2004h");
12901
+ stdout2.write("\x1B[>4;2m");
12306
12902
  return () => {
12307
12903
  stdout2.write("\x1B[?2004l");
12904
+ stdout2.write("\x1B[>4m");
12308
12905
  };
12309
12906
  }, [stdout2]);
12310
12907
  const { activity: subagentActivity, sinkRef: subagentSinkRef } = useSubagent({
@@ -12326,24 +12923,24 @@ function App({
12326
12923
  sealCurrentEntry,
12327
12924
  hasUndoable
12328
12925
  } = useEditHistory(codeMode);
12329
- const pendingEdits = useRef5([]);
12926
+ const pendingEdits = useRef6([]);
12330
12927
  const [pendingCount, setPendingCount] = useState10(0);
12331
12928
  const syncPendingCount = useCallback4(() => {
12332
12929
  setPendingCount(pendingEdits.current.length);
12333
12930
  }, []);
12334
12931
  const [editMode, setEditMode] = useState10(() => codeMode ? loadEditMode() : "review");
12335
- const editModeRef = useRef5(editMode);
12336
- useEffect5(() => {
12932
+ const editModeRef = useRef6(editMode);
12933
+ useEffect6(() => {
12337
12934
  editModeRef.current = editMode;
12338
12935
  if (codeMode) saveEditMode(editMode);
12339
12936
  }, [editMode, codeMode]);
12340
12937
  const [pendingEditReview, setPendingEditReview] = useState10(null);
12341
- const editReviewResolveRef = useRef5(null);
12342
- const turnEditPolicyRef = useRef5("ask");
12938
+ const editReviewResolveRef = useRef6(null);
12939
+ const turnEditPolicyRef = useRef6("ask");
12343
12940
  const [modeFlash, setModeFlash] = useState10(false);
12344
- const modeFlashTimeoutRef = useRef5(null);
12345
- const prevEditModeRef = useRef5(editMode);
12346
- useEffect5(() => {
12941
+ const modeFlashTimeoutRef = useRef6(null);
12942
+ const prevEditModeRef = useRef6(editMode);
12943
+ useEffect6(() => {
12347
12944
  if (prevEditModeRef.current === editMode) return;
12348
12945
  prevEditModeRef.current = editMode;
12349
12946
  setModeFlash(true);
@@ -12365,15 +12962,15 @@ function App({
12365
12962
  const [proArmed, setProArmed] = useState10(false);
12366
12963
  const [turnOnPro, setTurnOnPro] = useState10(false);
12367
12964
  const [queuedSubmit, setQueuedSubmit] = useState10(null);
12368
- const promptHistory = useRef5([]);
12369
- const historyCursor = useRef5(-1);
12370
- const assistantIterCounter = useRef5(0);
12371
- const toolHistoryRef = useRef5([]);
12372
- const planStepsRef = useRef5(null);
12373
- const completedStepIdsRef = useRef5(/* @__PURE__ */ new Set());
12374
- const planBodyRef = useRef5(null);
12375
- const planSummaryRef = useRef5(null);
12376
- const toolStartedAtRef = useRef5(null);
12965
+ const promptHistory = useRef6([]);
12966
+ const historyCursor = useRef6(-1);
12967
+ const assistantIterCounter = useRef6(0);
12968
+ const toolHistoryRef = useRef6([]);
12969
+ const planStepsRef = useRef6(null);
12970
+ const completedStepIdsRef = useRef6(/* @__PURE__ */ new Set());
12971
+ const planBodyRef = useRef6(null);
12972
+ const planSummaryRef = useRef6(null);
12973
+ const toolStartedAtRef = useRef6(null);
12377
12974
  const persistPlanState = useCallback4(() => {
12378
12975
  if (!session) return;
12379
12976
  const steps = planStepsRef.current;
@@ -12397,7 +12994,7 @@ function App({
12397
12994
  lastPromptTokens: 0,
12398
12995
  lastTurnCostUsd: 0
12399
12996
  });
12400
- const transcriptRef = useRef5(null);
12997
+ const transcriptRef = useRef6(null);
12401
12998
  if (transcript && !transcriptRef.current) {
12402
12999
  transcriptRef.current = openTranscriptFile(transcript, {
12403
13000
  version: 1,
@@ -12406,12 +13003,12 @@ function App({
12406
13003
  startedAt: (/* @__PURE__ */ new Date()).toISOString()
12407
13004
  });
12408
13005
  }
12409
- useEffect5(() => {
13006
+ useEffect6(() => {
12410
13007
  return () => {
12411
13008
  transcriptRef.current?.end();
12412
13009
  };
12413
13010
  }, []);
12414
- const loopRef = useRef5(null);
13011
+ const loopRef = useRef6(null);
12415
13012
  const loop = useMemo3(() => {
12416
13013
  if (loopRef.current) return loopRef.current;
12417
13014
  const client = new DeepSeekClient();
@@ -12460,7 +13057,7 @@ function App({
12460
13057
  loopRef.current = l;
12461
13058
  return l;
12462
13059
  }, [model2, system, harvest3, branch2, session, tools, codeMode]);
12463
- useEffect5(() => {
13060
+ useEffect6(() => {
12464
13061
  loop.hooks = hookList;
12465
13062
  }, [loop, hookList]);
12466
13063
  const {
@@ -12488,7 +13085,7 @@ function App({
12488
13085
  setSlashArgSelected,
12489
13086
  pickSlashArg
12490
13087
  } = useCompletionPickers({ input, setInput, codeMode, models: models2, mcpServers });
12491
- useEffect5(() => {
13088
+ useEffect6(() => {
12492
13089
  if (!progressSink) return;
12493
13090
  progressSink.current = (info) => {
12494
13091
  setToolProgress({
@@ -12501,8 +13098,8 @@ function App({
12501
13098
  if (progressSink.current) progressSink.current = null;
12502
13099
  };
12503
13100
  }, [progressSink]);
12504
- const sessionBannerShown = useRef5(false);
12505
- useEffect5(() => {
13101
+ const sessionBannerShown = useRef6(false);
13102
+ useEffect6(() => {
12506
13103
  if (sessionBannerShown.current) return;
12507
13104
  sessionBannerShown.current = true;
12508
13105
  if (!session) {
@@ -12584,7 +13181,26 @@ function App({
12584
13181
  markEditModeHintShown();
12585
13182
  }
12586
13183
  }, [session, loop, codeMode, syncPendingCount]);
12587
- useInput5((chKey, key) => {
13184
+ const quitProcess = useCallback4(() => {
13185
+ transcriptRef.current?.end();
13186
+ process.exit(0);
13187
+ }, []);
13188
+ useEffect6(() => {
13189
+ process.on("SIGINT", quitProcess);
13190
+ return () => {
13191
+ process.off("SIGINT", quitProcess);
13192
+ };
13193
+ }, [quitProcess]);
13194
+ useKeystroke((ev) => {
13195
+ const chKey = ev.input;
13196
+ const key = ev;
13197
+ if (ev.paste) {
13198
+ return;
13199
+ }
13200
+ if (key.ctrl && key.input === "c") {
13201
+ quitProcess();
13202
+ return;
13203
+ }
12588
13204
  if (key.escape && busy) {
12589
13205
  if (abortedThisTurn.current) return;
12590
13206
  abortedThisTurn.current = true;
@@ -12682,7 +13298,7 @@ function App({
12682
13298
  historyCursor.current = nextCursor;
12683
13299
  setInput(nextCursor < 0 ? "" : hist[hist.length - 1 - nextCursor] ?? "");
12684
13300
  }, []);
12685
- useEffect5(() => {
13301
+ useEffect6(() => {
12686
13302
  if (!tools || !codeMode) return;
12687
13303
  tools.setToolInterceptor(async (name, args) => {
12688
13304
  if (name !== "edit_file" && name !== "write_file") return null;
@@ -13548,7 +14164,7 @@ ${body}`;
13548
14164
  },
13549
14165
  [pendingShell, codeMode, handleSubmit, busy, loop]
13550
14166
  );
13551
- useEffect5(() => {
14167
+ useEffect6(() => {
13552
14168
  if (!busy && queuedSubmit !== null) {
13553
14169
  const text = queuedSubmit;
13554
14170
  setQueuedSubmit(null);
@@ -13592,8 +14208,8 @@ ${body}`;
13592
14208
  },
13593
14209
  [pendingPlan, togglePlanMode, busy, loop, handleSubmit, persistPlanState]
13594
14210
  );
13595
- const handlePlanConfirmRef = useRef5(handlePlanConfirm);
13596
- useEffect5(() => {
14211
+ const handlePlanConfirmRef = useRef6(handlePlanConfirm);
14212
+ useEffect6(() => {
13597
14213
  handlePlanConfirmRef.current = handlePlanConfirm;
13598
14214
  }, [handlePlanConfirm]);
13599
14215
  const stableHandlePlanConfirm = useCallback4(
@@ -13684,8 +14300,8 @@ Stay in plan mode \u2014 address the feedback (explore more if needed), then sub
13684
14300
  },
13685
14301
  [pendingCheckpoint, busy, loop, handleSubmit]
13686
14302
  );
13687
- const handleCheckpointConfirmRef = useRef5(handleCheckpointConfirm);
13688
- useEffect5(() => {
14303
+ const handleCheckpointConfirmRef = useRef6(handleCheckpointConfirm);
14304
+ useEffect6(() => {
13689
14305
  handleCheckpointConfirmRef.current = handleCheckpointConfirm;
13690
14306
  }, [handleCheckpointConfirm]);
13691
14307
  const stableHandleCheckpointConfirm = useCallback4(
@@ -13762,8 +14378,8 @@ If the feedback only tweaks how you execute (extra constraints, style preference
13762
14378
  },
13763
14379
  [pendingChoice, busy, loop, handleSubmit]
13764
14380
  );
13765
- const handleChoiceConfirmRef = useRef5(handleChoiceConfirm);
13766
- useEffect5(() => {
14381
+ const handleChoiceConfirmRef = useRef6(handleChoiceConfirm);
14382
+ useEffect6(() => {
13767
14383
  handleChoiceConfirmRef.current = handleChoiceConfirm;
13768
14384
  }, [handleChoiceConfirm]);
13769
14385
  const stableHandleChoiceConfirm = useCallback4(
@@ -13853,20 +14469,20 @@ Continue executing from the next pending step. Call mark_step_complete after eac
13853
14469
  },
13854
14470
  [pendingRevision, busy, loop, handleSubmit, persistPlanState]
13855
14471
  );
13856
- const handleReviseConfirmRef = useRef5(handleReviseConfirm);
13857
- useEffect5(() => {
14472
+ const handleReviseConfirmRef = useRef6(handleReviseConfirm);
14473
+ useEffect6(() => {
13858
14474
  handleReviseConfirmRef.current = handleReviseConfirm;
13859
14475
  }, [handleReviseConfirm]);
13860
14476
  const stableHandleReviseConfirm = useCallback4(
13861
14477
  async (choice) => handleReviseConfirmRef.current(choice),
13862
14478
  []
13863
14479
  );
13864
- return /* @__PURE__ */ React20.createElement(
14480
+ return /* @__PURE__ */ React22.createElement(React22.Fragment, null, /* @__PURE__ */ React22.createElement(
13865
14481
  TickerProvider,
13866
14482
  {
13867
14483
  disabled: PLAIN_UI || !!pendingPlan || !!pendingShell || !!pendingEditReview || !!pendingCheckpoint || !!stagedCheckpointRevise || !!pendingChoice || !!stagedChoiceCustom || !!pendingRevision
13868
14484
  },
13869
- /* @__PURE__ */ React20.createElement(Box19, { flexDirection: "column" }, /* @__PURE__ */ React20.createElement(
14485
+ /* @__PURE__ */ React22.createElement(Box20, { flexDirection: "column" }, /* @__PURE__ */ React22.createElement(
13870
14486
  StatsPanel,
13871
14487
  {
13872
14488
  summary,
@@ -13883,28 +14499,28 @@ Continue executing from the next pending step. Call mark_step_complete after eac
13883
14499
  proArmed,
13884
14500
  escalated: turnOnPro
13885
14501
  }
13886
- ), /* @__PURE__ */ React20.createElement(Static, { items: historical }, (item) => /* @__PURE__ */ React20.createElement(EventRow, { key: item.id, event: item, projectRoot: hookCwd })), !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && streaming ? /* @__PURE__ */ React20.createElement(Box19, { marginY: 1 }, /* @__PURE__ */ React20.createElement(EventRow, { event: streaming, projectRoot: hookCwd })) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && ongoingTool ? /* @__PURE__ */ React20.createElement(OngoingToolRow, { tool: ongoingTool, progress: toolProgress }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && subagentActivity ? /* @__PURE__ */ React20.createElement(SubagentRow, { activity: subagentActivity }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && !ongoingTool && statusLine ? /* @__PURE__ */ React20.createElement(StatusRow, { text: statusLine }) : null, !PLAIN_UI && undoBanner && !pendingShell && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && !pendingChoice && !stagedChoiceCustom && !pendingRevision ? /* @__PURE__ */ React20.createElement(UndoBanner, { banner: undoBanner }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && busy && !streaming && !ongoingTool && !statusLine ? /* @__PURE__ */ React20.createElement(StatusRow, { text: "processing\u2026" }) : null, stagedInput ? /* @__PURE__ */ React20.createElement(
14502
+ ), /* @__PURE__ */ React22.createElement(Static, { items: historical }, (item) => /* @__PURE__ */ React22.createElement(EventRow, { key: item.id, event: item, projectRoot: hookCwd })), !historical.some((e) => e.role === "user" || e.role === "assistant") && !busy && !streaming ? /* @__PURE__ */ React22.createElement(WelcomeBanner, { inCodeMode: !!codeMode }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && streaming ? /* @__PURE__ */ React22.createElement(Box20, { marginY: 1 }, /* @__PURE__ */ React22.createElement(EventRow, { event: streaming, projectRoot: hookCwd })) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && ongoingTool ? /* @__PURE__ */ React22.createElement(OngoingToolRow, { tool: ongoingTool, progress: toolProgress }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && subagentActivity ? /* @__PURE__ */ React22.createElement(SubagentRow, { activity: subagentActivity }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && !ongoingTool && statusLine ? /* @__PURE__ */ React22.createElement(StatusRow, { text: statusLine }) : null, !PLAIN_UI && undoBanner && !pendingShell && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && !pendingChoice && !stagedChoiceCustom && !pendingRevision ? /* @__PURE__ */ React22.createElement(UndoBanner, { banner: undoBanner }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && busy && !streaming && !ongoingTool && !statusLine ? /* @__PURE__ */ React22.createElement(StatusRow, { text: "processing\u2026" }) : null, stagedInput ? /* @__PURE__ */ React22.createElement(
13887
14503
  PlanRefineInput,
13888
14504
  {
13889
14505
  mode: stagedInput.mode,
13890
14506
  onSubmit: handleStagedInputSubmit,
13891
14507
  onCancel: handleStagedInputCancel
13892
14508
  }
13893
- ) : stagedCheckpointRevise ? /* @__PURE__ */ React20.createElement(
14509
+ ) : stagedCheckpointRevise ? /* @__PURE__ */ React22.createElement(
13894
14510
  PlanRefineInput,
13895
14511
  {
13896
14512
  mode: "checkpoint-revise",
13897
14513
  onSubmit: handleCheckpointReviseSubmit,
13898
14514
  onCancel: handleCheckpointReviseCancel
13899
14515
  }
13900
- ) : stagedChoiceCustom ? /* @__PURE__ */ React20.createElement(
14516
+ ) : stagedChoiceCustom ? /* @__PURE__ */ React22.createElement(
13901
14517
  PlanRefineInput,
13902
14518
  {
13903
14519
  mode: "choice-custom",
13904
14520
  onSubmit: handleChoiceCustomSubmit,
13905
14521
  onCancel: handleChoiceCustomCancel
13906
14522
  }
13907
- ) : pendingChoice ? /* @__PURE__ */ React20.createElement(
14523
+ ) : pendingChoice ? /* @__PURE__ */ React22.createElement(
13908
14524
  ChoiceConfirm,
13909
14525
  {
13910
14526
  question: pendingChoice.question,
@@ -13912,7 +14528,7 @@ Continue executing from the next pending step. Call mark_step_complete after eac
13912
14528
  allowCustom: pendingChoice.allowCustom,
13913
14529
  onChoose: stableHandleChoiceConfirm
13914
14530
  }
13915
- ) : pendingRevision ? /* @__PURE__ */ React20.createElement(
14531
+ ) : pendingRevision ? /* @__PURE__ */ React22.createElement(
13916
14532
  PlanReviseConfirm,
13917
14533
  {
13918
14534
  reason: pendingRevision.reason,
@@ -13923,7 +14539,7 @@ Continue executing from the next pending step. Call mark_step_complete after eac
13923
14539
  summary: pendingRevision.summary,
13924
14540
  onChoose: stableHandleReviseConfirm
13925
14541
  }
13926
- ) : pendingCheckpoint ? /* @__PURE__ */ React20.createElement(
14542
+ ) : pendingCheckpoint ? /* @__PURE__ */ React22.createElement(
13927
14543
  PlanCheckpointConfirm,
13928
14544
  {
13929
14545
  stepId: pendingCheckpoint.stepId,
@@ -13934,7 +14550,7 @@ Continue executing from the next pending step. Call mark_step_complete after eac
13934
14550
  completedStepIds: completedStepIdsRef.current,
13935
14551
  onChoose: stableHandleCheckpointConfirm
13936
14552
  }
13937
- ) : pendingPlan ? /* @__PURE__ */ React20.createElement(
14553
+ ) : pendingPlan ? /* @__PURE__ */ React22.createElement(
13938
14554
  PlanConfirm,
13939
14555
  {
13940
14556
  plan: pendingPlan,
@@ -13943,7 +14559,7 @@ Continue executing from the next pending step. Call mark_step_complete after eac
13943
14559
  onChoose: stableHandlePlanConfirm,
13944
14560
  projectRoot: hookCwd
13945
14561
  }
13946
- ) : pendingShell ? /* @__PURE__ */ React20.createElement(
14562
+ ) : pendingShell ? /* @__PURE__ */ React22.createElement(
13947
14563
  ShellConfirm,
13948
14564
  {
13949
14565
  command: pendingShell.command,
@@ -13951,7 +14567,7 @@ Continue executing from the next pending step. Call mark_step_complete after eac
13951
14567
  kind: pendingShell.kind,
13952
14568
  onChoose: handleShellConfirm
13953
14569
  }
13954
- ) : pendingEditReview ? /* @__PURE__ */ React20.createElement(
14570
+ ) : pendingEditReview ? /* @__PURE__ */ React22.createElement(
13955
14571
  EditConfirm,
13956
14572
  {
13957
14573
  block: pendingEditReview,
@@ -13963,7 +14579,7 @@ Continue executing from the next pending step. Call mark_step_complete after eac
13963
14579
  }
13964
14580
  }
13965
14581
  }
13966
- ) : /* @__PURE__ */ React20.createElement(React20.Fragment, null, codeMode ? /* @__PURE__ */ React20.createElement(
14582
+ ) : /* @__PURE__ */ React22.createElement(React22.Fragment, null, codeMode ? /* @__PURE__ */ React22.createElement(
13967
14583
  ModeStatusBar,
13968
14584
  {
13969
14585
  editMode,
@@ -13973,7 +14589,7 @@ Continue executing from the next pending step. Call mark_step_complete after eac
13973
14589
  undoArmed: !!undoBanner || hasUndoable(),
13974
14590
  jobs: codeMode.jobs
13975
14591
  }
13976
- ) : null, /* @__PURE__ */ React20.createElement(
14592
+ ) : null, /* @__PURE__ */ React22.createElement(
13977
14593
  PromptInput,
13978
14594
  {
13979
14595
  value: input,
@@ -13983,14 +14599,14 @@ Continue executing from the next pending step. Call mark_step_complete after eac
13983
14599
  onHistoryPrev: recallPrev,
13984
14600
  onHistoryNext: recallNext
13985
14601
  }
13986
- ), /* @__PURE__ */ React20.createElement(SlashSuggestions, { matches: slashMatches, selectedIndex: slashSelected }), /* @__PURE__ */ React20.createElement(
14602
+ ), /* @__PURE__ */ React22.createElement(SlashSuggestions, { matches: slashMatches, selectedIndex: slashSelected }), /* @__PURE__ */ React22.createElement(
13987
14603
  AtMentionSuggestions,
13988
14604
  {
13989
14605
  matches: atMatches,
13990
14606
  selectedIndex: atSelected,
13991
14607
  query: atPicker?.query ?? ""
13992
14608
  }
13993
- ), slashArgContext ? /* @__PURE__ */ React20.createElement(
14609
+ ), slashArgContext ? /* @__PURE__ */ React22.createElement(
13994
14610
  SlashArgPicker,
13995
14611
  {
13996
14612
  matches: slashArgMatches,
@@ -14000,19 +14616,19 @@ Continue executing from the next pending step. Call mark_step_complete after eac
14000
14616
  partial: slashArgContext.partial
14001
14617
  }
14002
14618
  ) : null))
14003
- );
14619
+ ));
14004
14620
  }
14005
14621
 
14006
14622
  // src/cli/ui/SessionPicker.tsx
14007
- import { Box as Box20, Text as Text19 } from "ink";
14008
- import React21 from "react";
14623
+ import { Box as Box21, Text as Text20 } from "ink";
14624
+ import React23 from "react";
14009
14625
  function SessionPicker({
14010
14626
  sessionName,
14011
14627
  messageCount,
14012
14628
  lastActive,
14013
14629
  onChoose
14014
14630
  }) {
14015
- return /* @__PURE__ */ React21.createElement(Box20, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React21.createElement(Box20, { marginBottom: 1 }, /* @__PURE__ */ React21.createElement(Text19, { bold: true, color: "cyan" }, `Session "${sessionName}" has ${messageCount} prior message${messageCount === 1 ? "" : "s"}`), /* @__PURE__ */ React21.createElement(Text19, { dimColor: true }, ` \xB7 last active ${relativeTime2(lastActive)}`)), /* @__PURE__ */ React21.createElement(
14631
+ return /* @__PURE__ */ React23.createElement(Box21, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React23.createElement(Box21, { marginBottom: 1 }, /* @__PURE__ */ React23.createElement(Text20, { bold: true, color: "cyan" }, `Session "${sessionName}" has ${messageCount} prior message${messageCount === 1 ? "" : "s"}`), /* @__PURE__ */ React23.createElement(Text20, { dimColor: true }, ` \xB7 last active ${relativeTime2(lastActive)}`)), /* @__PURE__ */ React23.createElement(
14016
14632
  SingleSelect,
14017
14633
  {
14018
14634
  initialValue: "new",
@@ -14035,7 +14651,7 @@ function SessionPicker({
14035
14651
  ],
14036
14652
  onSubmit: (v) => onChoose(v)
14037
14653
  }
14038
- ), /* @__PURE__ */ React21.createElement(Box20, { marginTop: 1 }, /* @__PURE__ */ React21.createElement(Text19, { dimColor: true }, "[\u2191\u2193] navigate \xB7 [Enter] select")));
14654
+ ), /* @__PURE__ */ React23.createElement(Box21, { marginTop: 1 }, /* @__PURE__ */ React23.createElement(Text20, { dimColor: true }, "[\u2191\u2193] navigate \xB7 [Enter] select")));
14039
14655
  }
14040
14656
  function relativeTime2(date) {
14041
14657
  const ms = Date.now() - date.getTime();
@@ -14051,9 +14667,9 @@ function relativeTime2(date) {
14051
14667
  }
14052
14668
 
14053
14669
  // src/cli/ui/Setup.tsx
14054
- import { Box as Box21, Text as Text20, useApp as useApp2 } from "ink";
14670
+ import { Box as Box22, Text as Text21, useApp as useApp2 } from "ink";
14055
14671
  import TextInput from "ink-text-input";
14056
- import React22, { useState as useState11 } from "react";
14672
+ import React24, { useState as useState11 } from "react";
14057
14673
  function Setup({ onReady }) {
14058
14674
  const [value, setValue] = useState11("");
14059
14675
  const [error, setError] = useState11(null);
@@ -14077,7 +14693,7 @@ function Setup({ onReady }) {
14077
14693
  }
14078
14694
  onReady(trimmed);
14079
14695
  };
14080
- return /* @__PURE__ */ React22.createElement(Box21, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React22.createElement(Text20, { bold: true, color: "cyan" }, "Welcome to Reasonix."), /* @__PURE__ */ React22.createElement(Box21, { marginTop: 1 }, /* @__PURE__ */ React22.createElement(Text20, null, "Paste your DeepSeek API key to get started.")), /* @__PURE__ */ React22.createElement(Text20, { dimColor: true }, "Get one (free credit on signup): https://platform.deepseek.com/api_keys"), /* @__PURE__ */ React22.createElement(Text20, { dimColor: true }, "Saved locally to ", defaultConfigPath()), /* @__PURE__ */ React22.createElement(Box21, { marginTop: 1 }, /* @__PURE__ */ React22.createElement(Text20, { bold: true, color: "cyan" }, "key \u203A "), /* @__PURE__ */ React22.createElement(
14696
+ return /* @__PURE__ */ React24.createElement(Box22, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React24.createElement(Text21, { bold: true, color: "cyan" }, "Welcome to Reasonix."), /* @__PURE__ */ React24.createElement(Box22, { marginTop: 1 }, /* @__PURE__ */ React24.createElement(Text21, null, "Paste your DeepSeek API key to get started.")), /* @__PURE__ */ React24.createElement(Text21, { dimColor: true }, "Get one (free credit on signup): https://platform.deepseek.com/api_keys"), /* @__PURE__ */ React24.createElement(Text21, { dimColor: true }, "Saved locally to ", defaultConfigPath()), /* @__PURE__ */ React24.createElement(Box22, { marginTop: 1 }, /* @__PURE__ */ React24.createElement(Text21, { bold: true, color: "cyan" }, "key \u203A "), /* @__PURE__ */ React24.createElement(
14081
14697
  TextInput,
14082
14698
  {
14083
14699
  value,
@@ -14086,7 +14702,7 @@ function Setup({ onReady }) {
14086
14702
  mask: "\u2022",
14087
14703
  placeholder: "sk-..."
14088
14704
  }
14089
- )), error ? /* @__PURE__ */ React22.createElement(Box21, { marginTop: 1 }, /* @__PURE__ */ React22.createElement(Text20, { color: "red" }, error)) : value ? /* @__PURE__ */ React22.createElement(Box21, { marginTop: 1 }, /* @__PURE__ */ React22.createElement(Text20, { dimColor: true }, "preview: ", redactKey(value))) : null, /* @__PURE__ */ React22.createElement(Box21, { marginTop: 1 }, /* @__PURE__ */ React22.createElement(Text20, { dimColor: true }, "(Type /exit to abort.)")));
14705
+ )), error ? /* @__PURE__ */ React24.createElement(Box22, { marginTop: 1 }, /* @__PURE__ */ React24.createElement(Text21, { color: "red" }, error)) : value ? /* @__PURE__ */ React24.createElement(Box22, { marginTop: 1 }, /* @__PURE__ */ React24.createElement(Text21, { dimColor: true }, "preview: ", redactKey(value))) : null, /* @__PURE__ */ React24.createElement(Box22, { marginTop: 1 }, /* @__PURE__ */ React24.createElement(Text21, { dimColor: true }, "(Type /exit to abort.)")));
14090
14706
  }
14091
14707
 
14092
14708
  // src/cli/commands/chat.tsx
@@ -14102,7 +14718,7 @@ function Root({
14102
14718
  const [key, setKey] = useState12(initialKey);
14103
14719
  const [pending, setPending] = useState12(sessionPreview);
14104
14720
  if (!key) {
14105
- return /* @__PURE__ */ React23.createElement(
14721
+ return /* @__PURE__ */ React25.createElement(
14106
14722
  Setup,
14107
14723
  {
14108
14724
  onReady: (k) => {
@@ -14114,7 +14730,7 @@ function Root({
14114
14730
  }
14115
14731
  process.env.DEEPSEEK_API_KEY = key;
14116
14732
  if (pending && appProps.session) {
14117
- return /* @__PURE__ */ React23.createElement(
14733
+ return /* @__PURE__ */ React25.createElement(KeystrokeProvider, null, /* @__PURE__ */ React25.createElement(
14118
14734
  SessionPicker,
14119
14735
  {
14120
14736
  sessionName: appProps.session,
@@ -14127,9 +14743,9 @@ function Root({
14127
14743
  setPending(void 0);
14128
14744
  }
14129
14745
  }
14130
- );
14746
+ ));
14131
14747
  }
14132
- return /* @__PURE__ */ React23.createElement(
14748
+ return /* @__PURE__ */ React25.createElement(KeystrokeProvider, null, /* @__PURE__ */ React25.createElement(
14133
14749
  App,
14134
14750
  {
14135
14751
  model: appProps.model,
@@ -14144,7 +14760,7 @@ function Root({
14144
14760
  progressSink,
14145
14761
  codeMode: appProps.codeMode
14146
14762
  }
14147
- );
14763
+ ));
14148
14764
  }
14149
14765
  async function chatCommand(opts) {
14150
14766
  loadDotenv();
@@ -14234,7 +14850,7 @@ async function chatCommand(opts) {
14234
14850
  rewriteSession(opts.session, []);
14235
14851
  }
14236
14852
  const { waitUntilExit } = render(
14237
- /* @__PURE__ */ React23.createElement(
14853
+ /* @__PURE__ */ React25.createElement(
14238
14854
  Root,
14239
14855
  {
14240
14856
  initialKey,
@@ -14283,12 +14899,9 @@ async function codeCommand(opts = {}) {
14283
14899
  `\u25B8 reasonix code: rooted at ${rootDir}, session "${session ?? "(ephemeral)"}" \xB7 ${tools.size} native tool(s)
14284
14900
  `
14285
14901
  );
14286
- const sigShutdown = () => {
14902
+ process.once("exit", () => {
14287
14903
  void jobs2.shutdown();
14288
- };
14289
- process.once("SIGINT", sigShutdown);
14290
- process.once("SIGTERM", sigShutdown);
14291
- process.once("exit", sigShutdown);
14904
+ });
14292
14905
  await chatCommand({
14293
14906
  model: opts.model ?? "deepseek-v4-flash",
14294
14907
  harvest: opts.harvest ?? false,
@@ -14306,35 +14919,35 @@ async function codeCommand(opts = {}) {
14306
14919
  import { writeFileSync as writeFileSync7 } from "fs";
14307
14920
  import { basename as basename3 } from "path";
14308
14921
  import { render as render2 } from "ink";
14309
- import React26 from "react";
14922
+ import React28 from "react";
14310
14923
 
14311
14924
  // src/cli/ui/DiffApp.tsx
14312
- import { Box as Box23, Static as Static2, Text as Text22, useApp as useApp3, useInput as useInput6 } from "ink";
14313
- import React25, { useState as useState13 } from "react";
14925
+ import { Box as Box24, Static as Static2, Text as Text23, useApp as useApp3, useInput } from "ink";
14926
+ import React27, { useState as useState13 } from "react";
14314
14927
 
14315
14928
  // src/cli/ui/RecordView.tsx
14316
- import { Box as Box22, Text as Text21 } from "ink";
14317
- import React24 from "react";
14929
+ import { Box as Box23, Text as Text22 } from "ink";
14930
+ import React26 from "react";
14318
14931
  function RecordView({ rec, compact: compact2 = false }) {
14319
14932
  const toolArgsMax = compact2 ? 120 : 200;
14320
14933
  const toolContentMax = compact2 ? 200 : 400;
14321
14934
  if (rec.role === "user") {
14322
14935
  const content = rec.content.includes("\n") ? rec.content.split("\n").join("\n ") : rec.content;
14323
- return /* @__PURE__ */ React24.createElement(Box22, { marginTop: 1 }, /* @__PURE__ */ React24.createElement(Text21, { bold: true, color: "cyan" }, "you \u203A", " "), /* @__PURE__ */ React24.createElement(Text21, null, content));
14936
+ return /* @__PURE__ */ React26.createElement(Box23, { marginTop: 1 }, /* @__PURE__ */ React26.createElement(Text22, { bold: true, color: "cyan" }, "you \u203A", " "), /* @__PURE__ */ React26.createElement(Text22, null, content));
14324
14937
  }
14325
14938
  if (rec.role === "assistant_final") {
14326
- return /* @__PURE__ */ React24.createElement(Box22, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React24.createElement(Box22, null, /* @__PURE__ */ React24.createElement(Text21, { bold: true, color: "green" }, "assistant"), rec.cost !== void 0 ? /* @__PURE__ */ React24.createElement(Text21, { dimColor: true }, " $", rec.cost.toFixed(6)) : null, rec.usage ? /* @__PURE__ */ React24.createElement(CacheBadge, { usage: rec.usage }) : null), rec.planState ? /* @__PURE__ */ React24.createElement(PlanStateBlock, { planState: rec.planState }) : null, rec.content ? /* @__PURE__ */ React24.createElement(Text21, null, rec.content) : /* @__PURE__ */ React24.createElement(Text21, { dimColor: true, italic: true }, "(tool-call response only)"));
14939
+ return /* @__PURE__ */ React26.createElement(Box23, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React26.createElement(Box23, null, /* @__PURE__ */ React26.createElement(Text22, { bold: true, color: "green" }, "assistant"), rec.cost !== void 0 ? /* @__PURE__ */ React26.createElement(Text22, { dimColor: true }, " $", rec.cost.toFixed(6)) : null, rec.usage ? /* @__PURE__ */ React26.createElement(CacheBadge, { usage: rec.usage }) : null), rec.planState ? /* @__PURE__ */ React26.createElement(PlanStateBlock, { planState: rec.planState }) : null, rec.content ? /* @__PURE__ */ React26.createElement(Text22, null, rec.content) : /* @__PURE__ */ React26.createElement(Text22, { dimColor: true, italic: true }, "(tool-call response only)"));
14327
14940
  }
14328
14941
  if (rec.role === "tool") {
14329
- return /* @__PURE__ */ React24.createElement(Box22, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React24.createElement(Text21, { color: "yellow" }, "tool<", rec.tool ?? "?", ">"), rec.args ? /* @__PURE__ */ React24.createElement(Text21, { dimColor: true }, " args: ", truncate2(rec.args, toolArgsMax)) : null, /* @__PURE__ */ React24.createElement(Text21, { dimColor: true }, " \u2192 ", truncate2(rec.content, toolContentMax)));
14942
+ return /* @__PURE__ */ React26.createElement(Box23, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React26.createElement(Text22, { color: "yellow" }, "tool<", rec.tool ?? "?", ">"), rec.args ? /* @__PURE__ */ React26.createElement(Text22, { dimColor: true }, " args: ", truncate2(rec.args, toolArgsMax)) : null, /* @__PURE__ */ React26.createElement(Text22, { dimColor: true }, " \u2192 ", truncate2(rec.content, toolContentMax)));
14330
14943
  }
14331
14944
  if (rec.role === "error") {
14332
- return /* @__PURE__ */ React24.createElement(Box22, { marginTop: 1 }, /* @__PURE__ */ React24.createElement(Text21, { color: "red", bold: true }, "error", " "), /* @__PURE__ */ React24.createElement(Text21, { color: "red" }, rec.error ?? rec.content));
14945
+ return /* @__PURE__ */ React26.createElement(Box23, { marginTop: 1 }, /* @__PURE__ */ React26.createElement(Text22, { color: "red", bold: true }, "error", " "), /* @__PURE__ */ React26.createElement(Text22, { color: "red" }, rec.error ?? rec.content));
14333
14946
  }
14334
14947
  if (rec.role === "done" || rec.role === "assistant_delta") {
14335
14948
  return null;
14336
14949
  }
14337
- return /* @__PURE__ */ React24.createElement(Box22, null, /* @__PURE__ */ React24.createElement(Text21, { dimColor: true }, "[", rec.role, "] ", rec.content));
14950
+ return /* @__PURE__ */ React26.createElement(Box23, null, /* @__PURE__ */ React26.createElement(Text22, { dimColor: true }, "[", rec.role, "] ", rec.content));
14338
14951
  }
14339
14952
  function CacheBadge({ usage }) {
14340
14953
  const hit = usage.prompt_cache_hit_tokens ?? 0;
@@ -14343,7 +14956,7 @@ function CacheBadge({ usage }) {
14343
14956
  if (total === 0) return null;
14344
14957
  const pct2 = hit / total * 100;
14345
14958
  const color = pct2 >= 70 ? "green" : pct2 >= 40 ? "yellow" : "red";
14346
- return /* @__PURE__ */ React24.createElement(Text21, null, /* @__PURE__ */ React24.createElement(Text21, { dimColor: true }, " \xB7 cache "), /* @__PURE__ */ React24.createElement(Text21, { color }, pct2.toFixed(1), "%"));
14959
+ return /* @__PURE__ */ React26.createElement(Text22, null, /* @__PURE__ */ React26.createElement(Text22, { dimColor: true }, " \xB7 cache "), /* @__PURE__ */ React26.createElement(Text22, { color }, pct2.toFixed(1), "%"));
14347
14960
  }
14348
14961
  function truncate2(s, max) {
14349
14962
  return s.length <= max ? s : `${s.slice(0, max)}\u2026 (+${s.length - max} chars)`;
@@ -14355,7 +14968,7 @@ function DiffApp({ report }) {
14355
14968
  const maxIdx = Math.max(0, report.pairs.length - 1);
14356
14969
  const initialIdx = report.firstDivergenceTurn ? report.pairs.findIndex((p) => p.turn === report.firstDivergenceTurn) : 0;
14357
14970
  const [idx, setIdx] = useState13(Math.max(0, initialIdx));
14358
- useInput6((input, key) => {
14971
+ useInput((input, key) => {
14359
14972
  if (input === "q" || key.ctrl && input === "c") {
14360
14973
  exit2();
14361
14974
  return;
@@ -14377,7 +14990,7 @@ function DiffApp({ report }) {
14377
14990
  }
14378
14991
  });
14379
14992
  const pair = report.pairs[idx];
14380
- return /* @__PURE__ */ React25.createElement(Box23, { flexDirection: "column" }, /* @__PURE__ */ React25.createElement(DiffHeader, { report }), /* @__PURE__ */ React25.createElement(Box23, { marginTop: 1, paddingX: 1, justifyContent: "space-between" }, /* @__PURE__ */ React25.createElement(Text22, { color: "cyan", bold: true }, "turn ", pair?.turn ?? "?", " (", idx + 1, " / ", report.pairs.length, ")"), /* @__PURE__ */ React25.createElement(Text22, null, pair ? /* @__PURE__ */ React25.createElement(KindBadge, { kind: pair.kind }) : null)), /* @__PURE__ */ React25.createElement(Box23, { flexDirection: "row", marginTop: 1 }, /* @__PURE__ */ React25.createElement(Pane, { label: report.a.label, headerColor: "blue", records: paneRecords(pair, "a") }), /* @__PURE__ */ React25.createElement(Pane, { label: report.b.label, headerColor: "magenta", records: paneRecords(pair, "b") })), pair?.divergenceNote ? /* @__PURE__ */ React25.createElement(Box23, { marginTop: 1, paddingX: 1 }, /* @__PURE__ */ React25.createElement(Text22, { color: "yellow" }, "\u2605 "), /* @__PURE__ */ React25.createElement(Text22, null, pair.divergenceNote)) : null, /* @__PURE__ */ React25.createElement(Box23, { marginTop: 1, paddingX: 1, borderStyle: "single", borderColor: "gray" }, /* @__PURE__ */ React25.createElement(Text22, { dimColor: true }, /* @__PURE__ */ React25.createElement(Text22, { bold: true }, "j"), "/", /* @__PURE__ */ React25.createElement(Text22, { bold: true }, "\u2193"), " next \xB7 ", /* @__PURE__ */ React25.createElement(Text22, { bold: true }, "k"), "/", /* @__PURE__ */ React25.createElement(Text22, { bold: true }, "\u2191"), " ", "prev \xB7 ", /* @__PURE__ */ React25.createElement(Text22, { bold: true }, "n"), " next-diverge \xB7 ", /* @__PURE__ */ React25.createElement(Text22, { bold: true }, "N"), "/", /* @__PURE__ */ React25.createElement(Text22, { bold: true }, "p"), " ", "prev-diverge \xB7 ", /* @__PURE__ */ React25.createElement(Text22, { bold: true }, "g"), "/", /* @__PURE__ */ React25.createElement(Text22, { bold: true }, "G"), " first/last \xB7 ", /* @__PURE__ */ React25.createElement(Text22, { bold: true }, "q"), " ", "quit")));
14993
+ return /* @__PURE__ */ React27.createElement(Box24, { flexDirection: "column" }, /* @__PURE__ */ React27.createElement(DiffHeader, { report }), /* @__PURE__ */ React27.createElement(Box24, { marginTop: 1, paddingX: 1, justifyContent: "space-between" }, /* @__PURE__ */ React27.createElement(Text23, { color: "cyan", bold: true }, "turn ", pair?.turn ?? "?", " (", idx + 1, " / ", report.pairs.length, ")"), /* @__PURE__ */ React27.createElement(Text23, null, pair ? /* @__PURE__ */ React27.createElement(KindBadge, { kind: pair.kind }) : null)), /* @__PURE__ */ React27.createElement(Box24, { flexDirection: "row", marginTop: 1 }, /* @__PURE__ */ React27.createElement(Pane, { label: report.a.label, headerColor: "blue", records: paneRecords(pair, "a") }), /* @__PURE__ */ React27.createElement(Pane, { label: report.b.label, headerColor: "magenta", records: paneRecords(pair, "b") })), pair?.divergenceNote ? /* @__PURE__ */ React27.createElement(Box24, { marginTop: 1, paddingX: 1 }, /* @__PURE__ */ React27.createElement(Text23, { color: "yellow" }, "\u2605 "), /* @__PURE__ */ React27.createElement(Text23, null, pair.divergenceNote)) : null, /* @__PURE__ */ React27.createElement(Box24, { marginTop: 1, paddingX: 1, borderStyle: "single", borderColor: "gray" }, /* @__PURE__ */ React27.createElement(Text23, { dimColor: true }, /* @__PURE__ */ React27.createElement(Text23, { bold: true }, "j"), "/", /* @__PURE__ */ React27.createElement(Text23, { bold: true }, "\u2193"), " next \xB7 ", /* @__PURE__ */ React27.createElement(Text23, { bold: true }, "k"), "/", /* @__PURE__ */ React27.createElement(Text23, { bold: true }, "\u2191"), " ", "prev \xB7 ", /* @__PURE__ */ React27.createElement(Text23, { bold: true }, "n"), " next-diverge \xB7 ", /* @__PURE__ */ React27.createElement(Text23, { bold: true }, "N"), "/", /* @__PURE__ */ React27.createElement(Text23, { bold: true }, "p"), " ", "prev-diverge \xB7 ", /* @__PURE__ */ React27.createElement(Text23, { bold: true }, "g"), "/", /* @__PURE__ */ React27.createElement(Text23, { bold: true }, "G"), " first/last \xB7 ", /* @__PURE__ */ React27.createElement(Text23, { bold: true }, "q"), " ", "quit")));
14381
14994
  }
14382
14995
  function DiffHeader({ report }) {
14383
14996
  const a = report.a;
@@ -14395,15 +15008,15 @@ function DiffHeader({ report }) {
14395
15008
  } else if (a.stats.prefixHashes[0] && a.stats.prefixHashes[0] === b.stats.prefixHashes[0]) {
14396
15009
  prefixLine = `shared prefix hash ${a.stats.prefixHashes[0].slice(0, 12)}\u2026 \u2014 cache delta attributable to log stability, not prompt change.`;
14397
15010
  }
14398
- return /* @__PURE__ */ React25.createElement(Box23, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React25.createElement(Box23, { justifyContent: "space-between" }, /* @__PURE__ */ React25.createElement(Text22, null, /* @__PURE__ */ React25.createElement(Text22, { color: "cyan", bold: true }, "reasonix diff"), /* @__PURE__ */ React25.createElement(Text22, { dimColor: true }, " \xB7 A="), /* @__PURE__ */ React25.createElement(Text22, { color: "blue" }, a.label), /* @__PURE__ */ React25.createElement(Text22, { dimColor: true }, " vs B="), /* @__PURE__ */ React25.createElement(Text22, { color: "magenta" }, b.label)), /* @__PURE__ */ React25.createElement(Text22, { dimColor: true }, report.pairs.length, " turns aligned")), /* @__PURE__ */ React25.createElement(Box23, { marginTop: 1, gap: 3 }, /* @__PURE__ */ React25.createElement(Text22, null, /* @__PURE__ */ React25.createElement(Text22, { dimColor: true }, "cache "), /* @__PURE__ */ React25.createElement(Text22, null, (a.stats.cacheHitRatio * 100).toFixed(1), "%"), /* @__PURE__ */ React25.createElement(Text22, { dimColor: true }, " \u2192 "), /* @__PURE__ */ React25.createElement(Text22, null, (b.stats.cacheHitRatio * 100).toFixed(1), "%"), /* @__PURE__ */ React25.createElement(Text22, { color: cacheDelta >= 0 ? "green" : "red", bold: true }, " ", cacheDelta >= 0 ? "+" : "", (cacheDelta * 100).toFixed(1), "pp")), /* @__PURE__ */ React25.createElement(Text22, null, /* @__PURE__ */ React25.createElement(Text22, { dimColor: true }, "cost "), /* @__PURE__ */ React25.createElement(Text22, null, "$", a.stats.totalCostUsd.toFixed(6)), /* @__PURE__ */ React25.createElement(Text22, { dimColor: true }, " \u2192 "), /* @__PURE__ */ React25.createElement(Text22, null, "$", b.stats.totalCostUsd.toFixed(6)), /* @__PURE__ */ React25.createElement(Text22, { color: costDelta2 <= 0 ? "green" : "red", bold: true }, " ", costDelta2 >= 0 ? "+" : "", costDelta2.toFixed(1), "%")), /* @__PURE__ */ React25.createElement(Text22, null, /* @__PURE__ */ React25.createElement(Text22, { dimColor: true }, "model calls "), /* @__PURE__ */ React25.createElement(Text22, null, a.stats.turns, " \u2192 ", b.stats.turns))), prefixLine ? /* @__PURE__ */ React25.createElement(Box23, { marginTop: 1 }, /* @__PURE__ */ React25.createElement(Text22, { dimColor: true, italic: true }, prefixLine)) : null);
15011
+ return /* @__PURE__ */ React27.createElement(Box24, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React27.createElement(Box24, { justifyContent: "space-between" }, /* @__PURE__ */ React27.createElement(Text23, null, /* @__PURE__ */ React27.createElement(Text23, { color: "cyan", bold: true }, "reasonix diff"), /* @__PURE__ */ React27.createElement(Text23, { dimColor: true }, " \xB7 A="), /* @__PURE__ */ React27.createElement(Text23, { color: "blue" }, a.label), /* @__PURE__ */ React27.createElement(Text23, { dimColor: true }, " vs B="), /* @__PURE__ */ React27.createElement(Text23, { color: "magenta" }, b.label)), /* @__PURE__ */ React27.createElement(Text23, { dimColor: true }, report.pairs.length, " turns aligned")), /* @__PURE__ */ React27.createElement(Box24, { marginTop: 1, gap: 3 }, /* @__PURE__ */ React27.createElement(Text23, null, /* @__PURE__ */ React27.createElement(Text23, { dimColor: true }, "cache "), /* @__PURE__ */ React27.createElement(Text23, null, (a.stats.cacheHitRatio * 100).toFixed(1), "%"), /* @__PURE__ */ React27.createElement(Text23, { dimColor: true }, " \u2192 "), /* @__PURE__ */ React27.createElement(Text23, null, (b.stats.cacheHitRatio * 100).toFixed(1), "%"), /* @__PURE__ */ React27.createElement(Text23, { color: cacheDelta >= 0 ? "green" : "red", bold: true }, " ", cacheDelta >= 0 ? "+" : "", (cacheDelta * 100).toFixed(1), "pp")), /* @__PURE__ */ React27.createElement(Text23, null, /* @__PURE__ */ React27.createElement(Text23, { dimColor: true }, "cost "), /* @__PURE__ */ React27.createElement(Text23, null, "$", a.stats.totalCostUsd.toFixed(6)), /* @__PURE__ */ React27.createElement(Text23, { dimColor: true }, " \u2192 "), /* @__PURE__ */ React27.createElement(Text23, null, "$", b.stats.totalCostUsd.toFixed(6)), /* @__PURE__ */ React27.createElement(Text23, { color: costDelta2 <= 0 ? "green" : "red", bold: true }, " ", costDelta2 >= 0 ? "+" : "", costDelta2.toFixed(1), "%")), /* @__PURE__ */ React27.createElement(Text23, null, /* @__PURE__ */ React27.createElement(Text23, { dimColor: true }, "model calls "), /* @__PURE__ */ React27.createElement(Text23, null, a.stats.turns, " \u2192 ", b.stats.turns))), prefixLine ? /* @__PURE__ */ React27.createElement(Box24, { marginTop: 1 }, /* @__PURE__ */ React27.createElement(Text23, { dimColor: true, italic: true }, prefixLine)) : null);
14399
15012
  }
14400
15013
  function Pane({
14401
15014
  label,
14402
15015
  headerColor,
14403
15016
  records
14404
15017
  }) {
14405
- return /* @__PURE__ */ React25.createElement(
14406
- Box23,
15018
+ return /* @__PURE__ */ React27.createElement(
15019
+ Box24,
14407
15020
  {
14408
15021
  flexDirection: "column",
14409
15022
  flexGrow: 1,
@@ -14411,21 +15024,21 @@ function Pane({
14411
15024
  borderStyle: "single",
14412
15025
  borderColor: headerColor
14413
15026
  },
14414
- /* @__PURE__ */ React25.createElement(Text22, { color: headerColor, bold: true }, label),
14415
- records.length === 0 ? /* @__PURE__ */ React25.createElement(Box23, { marginTop: 1 }, /* @__PURE__ */ React25.createElement(Text22, { dimColor: true, italic: true }, "(no records on this side for this turn)")) : /* @__PURE__ */ React25.createElement(Static2, { items: records.map((rec, i) => ({ key: `${label}-${i}`, rec })) }, ({ key, rec }) => /* @__PURE__ */ React25.createElement(RecordView, { key, rec, compact: true }))
15027
+ /* @__PURE__ */ React27.createElement(Text23, { color: headerColor, bold: true }, label),
15028
+ records.length === 0 ? /* @__PURE__ */ React27.createElement(Box24, { marginTop: 1 }, /* @__PURE__ */ React27.createElement(Text23, { dimColor: true, italic: true }, "(no records on this side for this turn)")) : /* @__PURE__ */ React27.createElement(Static2, { items: records.map((rec, i) => ({ key: `${label}-${i}`, rec })) }, ({ key, rec }) => /* @__PURE__ */ React27.createElement(RecordView, { key, rec, compact: true }))
14416
15029
  );
14417
15030
  }
14418
15031
  function KindBadge({ kind }) {
14419
15032
  if (kind === "match") {
14420
- return /* @__PURE__ */ React25.createElement(Text22, { color: "green" }, "\u2713 match");
15033
+ return /* @__PURE__ */ React27.createElement(Text23, { color: "green" }, "\u2713 match");
14421
15034
  }
14422
15035
  if (kind === "diverge") {
14423
- return /* @__PURE__ */ React25.createElement(Text22, { color: "yellow" }, "\u2605 diverge");
15036
+ return /* @__PURE__ */ React27.createElement(Text23, { color: "yellow" }, "\u2605 diverge");
14424
15037
  }
14425
15038
  if (kind === "only_in_a") {
14426
- return /* @__PURE__ */ React25.createElement(Text22, { color: "blue" }, "\u2190 only in A");
15039
+ return /* @__PURE__ */ React27.createElement(Text23, { color: "blue" }, "\u2190 only in A");
14427
15040
  }
14428
- return /* @__PURE__ */ React25.createElement(Text22, { color: "magenta" }, "\u2192 only in B");
15041
+ return /* @__PURE__ */ React27.createElement(Text23, { color: "magenta" }, "\u2192 only in B");
14429
15042
  }
14430
15043
  function paneRecords(pair, side) {
14431
15044
  if (!pair) return [];
@@ -14456,7 +15069,7 @@ markdown report written to ${opts.mdPath}`);
14456
15069
  return;
14457
15070
  }
14458
15071
  if (wantTui) {
14459
- const { waitUntilExit } = render2(React26.createElement(DiffApp, { report }), {
15072
+ const { waitUntilExit } = render2(React28.createElement(DiffApp, { report }), {
14460
15073
  exitOnCtrlC: true,
14461
15074
  patchConsole: false
14462
15075
  });
@@ -14597,16 +15210,16 @@ function pad2(s, width) {
14597
15210
 
14598
15211
  // src/cli/commands/replay.ts
14599
15212
  import { render as render3 } from "ink";
14600
- import React28 from "react";
15213
+ import React30 from "react";
14601
15214
 
14602
15215
  // src/cli/ui/ReplayApp.tsx
14603
- import { Box as Box24, Static as Static3, Text as Text23, useApp as useApp4, useInput as useInput7 } from "ink";
14604
- import React27, { useMemo as useMemo4, useState as useState14 } from "react";
15216
+ import { Box as Box25, Static as Static3, Text as Text24, useApp as useApp4, useInput as useInput2 } from "ink";
15217
+ import React29, { useMemo as useMemo4, useState as useState14 } from "react";
14605
15218
  function ReplayApp({ meta, pages }) {
14606
15219
  const { exit: exit2 } = useApp4();
14607
15220
  const maxIdx = Math.max(0, pages.length - 1);
14608
15221
  const [idx, setIdx] = useState14(maxIdx);
14609
- useInput7((input, key) => {
15222
+ useInput2((input, key) => {
14610
15223
  if (input === "q" || key.ctrl && input === "c") {
14611
15224
  exit2();
14612
15225
  return;
@@ -14641,14 +15254,14 @@ function ReplayApp({ meta, pages }) {
14641
15254
  const prefixHash = cumStats.prefixHashes.length === 1 ? cumStats.prefixHashes[0].slice(0, 16) : cumStats.prefixHashes.length === 0 ? "(untracked)" : `(churned \xD7${cumStats.prefixHashes.length})`;
14642
15255
  const currentPage = pages[idx];
14643
15256
  const progressLabel = pages.length === 0 ? "empty transcript" : `turn ${idx + 1} / ${pages.length}`;
14644
- return /* @__PURE__ */ React27.createElement(Box24, { flexDirection: "column" }, /* @__PURE__ */ React27.createElement(
15257
+ return /* @__PURE__ */ React29.createElement(Box25, { flexDirection: "column" }, /* @__PURE__ */ React29.createElement(
14645
15258
  StatsPanel,
14646
15259
  {
14647
15260
  summary,
14648
15261
  model: cumStats.models[0] ?? meta?.model ?? "?",
14649
15262
  prefixHash
14650
15263
  }
14651
- ), /* @__PURE__ */ React27.createElement(Box24, { flexDirection: "column", marginTop: 1, paddingX: 1 }, /* @__PURE__ */ React27.createElement(Box24, { justifyContent: "space-between" }, /* @__PURE__ */ React27.createElement(Text23, { color: "cyan", bold: true }, progressLabel), meta ? /* @__PURE__ */ React27.createElement(Text23, { dimColor: true }, meta.source, meta.task ? ` \xB7 ${meta.task}` : "", meta.mode ? ` \xB7 ${meta.mode}` : "") : null), currentPage ? /* @__PURE__ */ React27.createElement(Static3, { items: currentPage.records.map((rec, i) => ({ key: `${idx}-${i}`, rec })) }, ({ key, rec }) => /* @__PURE__ */ React27.createElement(RecordView, { key, rec })) : /* @__PURE__ */ React27.createElement(Text23, { dimColor: true, italic: true }, "no records")), /* @__PURE__ */ React27.createElement(Box24, { marginTop: 1, paddingX: 1, borderStyle: "single", borderColor: "gray" }, /* @__PURE__ */ React27.createElement(Text23, { dimColor: true }, /* @__PURE__ */ React27.createElement(Text23, { bold: true }, "j"), "/", /* @__PURE__ */ React27.createElement(Text23, { bold: true }, "\u2193"), "/", /* @__PURE__ */ React27.createElement(Text23, { bold: true }, "space"), " next \xB7 ", /* @__PURE__ */ React27.createElement(Text23, { bold: true }, "k"), "/", /* @__PURE__ */ React27.createElement(Text23, { bold: true }, "\u2191"), " prev \xB7 ", /* @__PURE__ */ React27.createElement(Text23, { bold: true }, "g"), " first \xB7 ", /* @__PURE__ */ React27.createElement(Text23, { bold: true }, "G"), " last \xB7", " ", /* @__PURE__ */ React27.createElement(Text23, { bold: true }, "q"), " quit")));
15264
+ ), /* @__PURE__ */ React29.createElement(Box25, { flexDirection: "column", marginTop: 1, paddingX: 1 }, /* @__PURE__ */ React29.createElement(Box25, { justifyContent: "space-between" }, /* @__PURE__ */ React29.createElement(Text24, { color: "cyan", bold: true }, progressLabel), meta ? /* @__PURE__ */ React29.createElement(Text24, { dimColor: true }, meta.source, meta.task ? ` \xB7 ${meta.task}` : "", meta.mode ? ` \xB7 ${meta.mode}` : "") : null), currentPage ? /* @__PURE__ */ React29.createElement(Static3, { items: currentPage.records.map((rec, i) => ({ key: `${idx}-${i}`, rec })) }, ({ key, rec }) => /* @__PURE__ */ React29.createElement(RecordView, { key, rec })) : /* @__PURE__ */ React29.createElement(Text24, { dimColor: true, italic: true }, "no records")), /* @__PURE__ */ React29.createElement(Box25, { marginTop: 1, paddingX: 1, borderStyle: "single", borderColor: "gray" }, /* @__PURE__ */ React29.createElement(Text24, { dimColor: true }, /* @__PURE__ */ React29.createElement(Text24, { bold: true }, "j"), "/", /* @__PURE__ */ React29.createElement(Text24, { bold: true }, "\u2193"), "/", /* @__PURE__ */ React29.createElement(Text24, { bold: true }, "space"), " next \xB7 ", /* @__PURE__ */ React29.createElement(Text24, { bold: true }, "k"), "/", /* @__PURE__ */ React29.createElement(Text24, { bold: true }, "\u2191"), " prev \xB7 ", /* @__PURE__ */ React29.createElement(Text24, { bold: true }, "g"), " first \xB7 ", /* @__PURE__ */ React29.createElement(Text24, { bold: true }, "G"), " last \xB7", " ", /* @__PURE__ */ React29.createElement(Text24, { bold: true }, "q"), " quit")));
14652
15265
  }
14653
15266
 
14654
15267
  // src/cli/commands/replay.ts
@@ -14660,7 +15273,7 @@ async function replayCommand(opts) {
14660
15273
  }
14661
15274
  const { parsed } = replayFromFile(opts.path);
14662
15275
  const pages = groupRecordsByTurn(parsed.records);
14663
- const { waitUntilExit } = render3(React28.createElement(ReplayApp, { meta: parsed.meta, pages }), {
15276
+ const { waitUntilExit } = render3(React30.createElement(ReplayApp, { meta: parsed.meta, pages }), {
14664
15277
  exitOnCtrlC: true,
14665
15278
  patchConsole: false
14666
15279
  });
@@ -14754,12 +15367,12 @@ function oneLine2(s, max = 200) {
14754
15367
  }
14755
15368
 
14756
15369
  // src/cli/commands/run.ts
14757
- import { stdin, stdout } from "process";
15370
+ import { stdin as stdin2, stdout } from "process";
14758
15371
  import { createInterface } from "readline/promises";
14759
15372
  async function ensureApiKey() {
14760
15373
  const existing = loadApiKey();
14761
15374
  if (existing) return existing;
14762
- if (!stdin.isTTY) {
15375
+ if (!stdin2.isTTY) {
14763
15376
  process.stderr.write(
14764
15377
  "DEEPSEEK_API_KEY is not set and stdin is not a TTY (cannot prompt).\nSet the env var, or run `reasonix chat` once interactively to save a key.\n"
14765
15378
  );
@@ -14768,7 +15381,7 @@ async function ensureApiKey() {
14768
15381
  process.stdout.write(
14769
15382
  "DeepSeek API key not configured.\nGet one at https://platform.deepseek.com/api_keys\n"
14770
15383
  );
14771
- const rl = createInterface({ input: stdin, output: stdout });
15384
+ const rl = createInterface({ input: stdin2, output: stdout });
14772
15385
  try {
14773
15386
  while (true) {
14774
15387
  const answer = (await rl.question("API key \u203A ")).trim();
@@ -14965,12 +15578,12 @@ function truncate3(s, max) {
14965
15578
 
14966
15579
  // src/cli/commands/setup.tsx
14967
15580
  import { render as render4 } from "ink";
14968
- import React30 from "react";
15581
+ import React32 from "react";
14969
15582
 
14970
15583
  // src/cli/ui/Wizard.tsx
14971
- import { Box as Box25, Text as Text24, useApp as useApp5, useInput as useInput8 } from "ink";
15584
+ import { Box as Box26, Text as Text25, useApp as useApp5, useInput as useInput3 } from "ink";
14972
15585
  import TextInput2 from "ink-text-input";
14973
- import React29, { useState as useState15 } from "react";
15586
+ import React31, { useState as useState15 } from "react";
14974
15587
 
14975
15588
  // src/cli/ui/presets.ts
14976
15589
  var PRESETS = {
@@ -15014,11 +15627,11 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
15014
15627
  catalogArgs: {}
15015
15628
  });
15016
15629
  const [error, setError] = useState15(null);
15017
- useInput8((_input, key) => {
15630
+ useInput3((_input, key) => {
15018
15631
  if (key.escape && step !== "saved" && onCancel) onCancel();
15019
15632
  });
15020
15633
  if (step === "apiKey") {
15021
- return /* @__PURE__ */ React29.createElement(
15634
+ return /* @__PURE__ */ React31.createElement(
15022
15635
  ApiKeyStep,
15023
15636
  {
15024
15637
  onSubmit: (key) => {
@@ -15032,7 +15645,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
15032
15645
  );
15033
15646
  }
15034
15647
  if (step === "preset") {
15035
- return /* @__PURE__ */ React29.createElement(StepFrame, { title: "Pick a preset", step: 1, total: 3 }, /* @__PURE__ */ React29.createElement(
15648
+ return /* @__PURE__ */ React31.createElement(StepFrame, { title: "Pick a preset", step: 1, total: 3 }, /* @__PURE__ */ React31.createElement(
15036
15649
  SingleSelect,
15037
15650
  {
15038
15651
  items: presetItems(),
@@ -15042,10 +15655,10 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
15042
15655
  setStep("mcp");
15043
15656
  }
15044
15657
  }
15045
- ), /* @__PURE__ */ React29.createElement(Box25, { marginTop: 1 }, /* @__PURE__ */ React29.createElement(Text24, { dimColor: true }, "[\u2191\u2193] navigate \xB7 [Enter] confirm \xB7 [Esc] cancel")));
15658
+ ), /* @__PURE__ */ React31.createElement(Box26, { marginTop: 1 }, /* @__PURE__ */ React31.createElement(Text25, { dimColor: true }, "[\u2191\u2193] navigate \xB7 [Enter] confirm \xB7 [Esc] cancel")));
15046
15659
  }
15047
15660
  if (step === "mcp") {
15048
- return /* @__PURE__ */ React29.createElement(StepFrame, { title: "Which MCP servers should Reasonix wire up for you?", step: 2, total: 3 }, /* @__PURE__ */ React29.createElement(
15661
+ return /* @__PURE__ */ React31.createElement(StepFrame, { title: "Which MCP servers should Reasonix wire up for you?", step: 2, total: 3 }, /* @__PURE__ */ React31.createElement(
15049
15662
  MultiSelect,
15050
15663
  {
15051
15664
  items: mcpItems(),
@@ -15070,7 +15683,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
15070
15683
  }
15071
15684
  const currentName = pending[0];
15072
15685
  const entry = CATALOG_BY_NAME.get(currentName);
15073
- return /* @__PURE__ */ React29.createElement(
15686
+ return /* @__PURE__ */ React31.createElement(
15074
15687
  McpArgsStep,
15075
15688
  {
15076
15689
  entry,
@@ -15088,7 +15701,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
15088
15701
  }
15089
15702
  if (step === "review") {
15090
15703
  const specs = data.selectedCatalog.map((name) => buildSpec(name, data.catalogArgs));
15091
- return /* @__PURE__ */ React29.createElement(StepFrame, { title: "Ready to save", step: 3, total: 3 }, /* @__PURE__ */ React29.createElement(Box25, { flexDirection: "column" }, /* @__PURE__ */ React29.createElement(SummaryLine, { label: "API key", value: redactKey(data.apiKey) }), /* @__PURE__ */ React29.createElement(SummaryLine, { label: "Preset", value: data.preset }), /* @__PURE__ */ React29.createElement(
15704
+ return /* @__PURE__ */ React31.createElement(StepFrame, { title: "Ready to save", step: 3, total: 3 }, /* @__PURE__ */ React31.createElement(Box26, { flexDirection: "column" }, /* @__PURE__ */ React31.createElement(SummaryLine, { label: "API key", value: redactKey(data.apiKey) }), /* @__PURE__ */ React31.createElement(SummaryLine, { label: "Preset", value: data.preset }), /* @__PURE__ */ React31.createElement(
15092
15705
  SummaryLine,
15093
15706
  {
15094
15707
  label: "MCP",
@@ -15096,8 +15709,8 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
15096
15709
  }
15097
15710
  ), specs.map((spec, i) => (
15098
15711
  // biome-ignore lint/suspicious/noArrayIndexKey: review-only render, order fixed
15099
- /* @__PURE__ */ React29.createElement(Box25, { key: i, paddingLeft: 14 }, /* @__PURE__ */ React29.createElement(Text24, { dimColor: true }, "\xB7 ", spec))
15100
- )), /* @__PURE__ */ React29.createElement(Box25, { marginTop: 1 }, /* @__PURE__ */ React29.createElement(Text24, null, "Saves to ", defaultConfigPath())), error ? /* @__PURE__ */ React29.createElement(Box25, { marginTop: 1 }, /* @__PURE__ */ React29.createElement(Text24, { color: "red" }, error)) : null, /* @__PURE__ */ React29.createElement(Box25, { marginTop: 1 }, /* @__PURE__ */ React29.createElement(Text24, { dimColor: true }, "[Enter] save \xB7 [Esc] cancel"))), /* @__PURE__ */ React29.createElement(
15712
+ /* @__PURE__ */ React31.createElement(Box26, { key: i, paddingLeft: 14 }, /* @__PURE__ */ React31.createElement(Text25, { dimColor: true }, "\xB7 ", spec))
15713
+ )), /* @__PURE__ */ React31.createElement(Box26, { marginTop: 1 }, /* @__PURE__ */ React31.createElement(Text25, null, "Saves to ", defaultConfigPath())), error ? /* @__PURE__ */ React31.createElement(Box26, { marginTop: 1 }, /* @__PURE__ */ React31.createElement(Text25, { color: "red" }, error)) : null, /* @__PURE__ */ React31.createElement(Box26, { marginTop: 1 }, /* @__PURE__ */ React31.createElement(Text25, { dimColor: true }, "[Enter] save \xB7 [Esc] cancel"))), /* @__PURE__ */ React31.createElement(
15101
15714
  ReviewConfirm,
15102
15715
  {
15103
15716
  onConfirm: () => {
@@ -15123,7 +15736,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
15123
15736
  }
15124
15737
  ));
15125
15738
  }
15126
- return /* @__PURE__ */ React29.createElement(Box25, { flexDirection: "column", borderStyle: "round", borderColor: "green", paddingX: 1 }, /* @__PURE__ */ React29.createElement(Text24, { bold: true, color: "green" }, "\u25B8 Saved."), /* @__PURE__ */ React29.createElement(Box25, { marginTop: 1 }, /* @__PURE__ */ React29.createElement(Text24, null, "Run `reasonix` any time to start chatting \u2014 your settings are remembered.")), /* @__PURE__ */ React29.createElement(Box25, { marginTop: 1 }, /* @__PURE__ */ React29.createElement(Text24, { dimColor: true }, "[Enter] to exit")), /* @__PURE__ */ React29.createElement(ExitOnEnter, { onExit: exit2 }));
15739
+ return /* @__PURE__ */ React31.createElement(Box26, { flexDirection: "column", borderStyle: "round", borderColor: "green", paddingX: 1 }, /* @__PURE__ */ React31.createElement(Text25, { bold: true, color: "green" }, "\u25B8 Saved."), /* @__PURE__ */ React31.createElement(Box26, { marginTop: 1 }, /* @__PURE__ */ React31.createElement(Text25, null, "Run `reasonix` any time to start chatting \u2014 your settings are remembered.")), /* @__PURE__ */ React31.createElement(Box26, { marginTop: 1 }, /* @__PURE__ */ React31.createElement(Text25, { dimColor: true }, "[Enter] to exit")), /* @__PURE__ */ React31.createElement(ExitOnEnter, { onExit: exit2 }));
15127
15740
  }
15128
15741
  function ApiKeyStep({
15129
15742
  onSubmit,
@@ -15131,7 +15744,7 @@ function ApiKeyStep({
15131
15744
  onError
15132
15745
  }) {
15133
15746
  const [value, setValue] = useState15("");
15134
- return /* @__PURE__ */ React29.createElement(Box25, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React29.createElement(Text24, { bold: true, color: "cyan" }, "Welcome to Reasonix."), /* @__PURE__ */ React29.createElement(Box25, { marginTop: 1 }, /* @__PURE__ */ React29.createElement(Text24, null, "Paste your DeepSeek API key to get started.")), /* @__PURE__ */ React29.createElement(Text24, { dimColor: true }, "Get one (free credit on signup): https://platform.deepseek.com/api_keys"), /* @__PURE__ */ React29.createElement(Text24, { dimColor: true }, "Saved locally to ", defaultConfigPath()), /* @__PURE__ */ React29.createElement(Box25, { marginTop: 1 }, /* @__PURE__ */ React29.createElement(Text24, { bold: true, color: "cyan" }, "key \u203A "), /* @__PURE__ */ React29.createElement(
15747
+ return /* @__PURE__ */ React31.createElement(Box26, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React31.createElement(Text25, { bold: true, color: "cyan" }, "Welcome to Reasonix."), /* @__PURE__ */ React31.createElement(Box26, { marginTop: 1 }, /* @__PURE__ */ React31.createElement(Text25, null, "Paste your DeepSeek API key to get started.")), /* @__PURE__ */ React31.createElement(Text25, { dimColor: true }, "Get one (free credit on signup): https://platform.deepseek.com/api_keys"), /* @__PURE__ */ React31.createElement(Text25, { dimColor: true }, "Saved locally to ", defaultConfigPath()), /* @__PURE__ */ React31.createElement(Box26, { marginTop: 1 }, /* @__PURE__ */ React31.createElement(Text25, { bold: true, color: "cyan" }, "key \u203A "), /* @__PURE__ */ React31.createElement(
15135
15748
  TextInput2,
15136
15749
  {
15137
15750
  value,
@@ -15148,7 +15761,7 @@ function ApiKeyStep({
15148
15761
  mask: "\u2022",
15149
15762
  placeholder: "sk-..."
15150
15763
  }
15151
- )), error ? /* @__PURE__ */ React29.createElement(Box25, { marginTop: 1 }, /* @__PURE__ */ React29.createElement(Text24, { color: "red" }, error)) : value ? /* @__PURE__ */ React29.createElement(Box25, { marginTop: 1 }, /* @__PURE__ */ React29.createElement(Text24, { dimColor: true }, "preview: ", redactKey(value))) : null);
15764
+ )), error ? /* @__PURE__ */ React31.createElement(Box26, { marginTop: 1 }, /* @__PURE__ */ React31.createElement(Text25, { color: "red" }, error)) : value ? /* @__PURE__ */ React31.createElement(Box26, { marginTop: 1 }, /* @__PURE__ */ React31.createElement(Text25, { dimColor: true }, "preview: ", redactKey(value))) : null);
15152
15765
  }
15153
15766
  function McpArgsStep({
15154
15767
  entry,
@@ -15157,7 +15770,7 @@ function McpArgsStep({
15157
15770
  onError
15158
15771
  }) {
15159
15772
  const [value, setValue] = useState15("");
15160
- return /* @__PURE__ */ React29.createElement(StepFrame, { title: `Configure ${entry.name}`, step: 2, total: 3 }, /* @__PURE__ */ React29.createElement(Box25, { flexDirection: "column" }, /* @__PURE__ */ React29.createElement(Text24, null, entry.summary), entry.note ? /* @__PURE__ */ React29.createElement(Box25, { marginTop: 1 }, /* @__PURE__ */ React29.createElement(Text24, { dimColor: true }, entry.note)) : null, /* @__PURE__ */ React29.createElement(Box25, { marginTop: 1 }, /* @__PURE__ */ React29.createElement(Text24, null, "Required parameter: "), /* @__PURE__ */ React29.createElement(Text24, { bold: true }, entry.userArgs)), /* @__PURE__ */ React29.createElement(Box25, { marginTop: 1 }, /* @__PURE__ */ React29.createElement(Text24, { bold: true, color: "cyan" }, entry.userArgs, " \u203A "), /* @__PURE__ */ React29.createElement(
15773
+ return /* @__PURE__ */ React31.createElement(StepFrame, { title: `Configure ${entry.name}`, step: 2, total: 3 }, /* @__PURE__ */ React31.createElement(Box26, { flexDirection: "column" }, /* @__PURE__ */ React31.createElement(Text25, null, entry.summary), entry.note ? /* @__PURE__ */ React31.createElement(Box26, { marginTop: 1 }, /* @__PURE__ */ React31.createElement(Text25, { dimColor: true }, entry.note)) : null, /* @__PURE__ */ React31.createElement(Box26, { marginTop: 1 }, /* @__PURE__ */ React31.createElement(Text25, null, "Required parameter: "), /* @__PURE__ */ React31.createElement(Text25, { bold: true }, entry.userArgs)), /* @__PURE__ */ React31.createElement(Box26, { marginTop: 1 }, /* @__PURE__ */ React31.createElement(Text25, { bold: true, color: "cyan" }, entry.userArgs, " \u203A "), /* @__PURE__ */ React31.createElement(
15161
15774
  TextInput2,
15162
15775
  {
15163
15776
  value,
@@ -15173,16 +15786,16 @@ function McpArgsStep({
15173
15786
  },
15174
15787
  placeholder: placeholderFor(entry)
15175
15788
  }
15176
- )), error ? /* @__PURE__ */ React29.createElement(Box25, { marginTop: 1 }, /* @__PURE__ */ React29.createElement(Text24, { color: "red" }, error)) : null));
15789
+ )), error ? /* @__PURE__ */ React31.createElement(Box26, { marginTop: 1 }, /* @__PURE__ */ React31.createElement(Text25, { color: "red" }, error)) : null));
15177
15790
  }
15178
15791
  function ReviewConfirm({ onConfirm }) {
15179
- useInput8((_i, key) => {
15792
+ useInput3((_i, key) => {
15180
15793
  if (key.return) onConfirm();
15181
15794
  });
15182
15795
  return null;
15183
15796
  }
15184
15797
  function ExitOnEnter({ onExit }) {
15185
- useInput8((_i, key) => {
15798
+ useInput3((_i, key) => {
15186
15799
  if (key.return) onExit();
15187
15800
  });
15188
15801
  return null;
@@ -15193,10 +15806,10 @@ function StepFrame({
15193
15806
  total,
15194
15807
  children
15195
15808
  }) {
15196
- return /* @__PURE__ */ React29.createElement(Box25, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React29.createElement(Box25, null, /* @__PURE__ */ React29.createElement(Text24, { dimColor: true }, "Step ", step, "/", total, " \xB7", " "), /* @__PURE__ */ React29.createElement(Text24, { bold: true, color: "cyan" }, title)), /* @__PURE__ */ React29.createElement(Box25, { marginTop: 1, flexDirection: "column" }, children));
15809
+ return /* @__PURE__ */ React31.createElement(Box26, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React31.createElement(Box26, null, /* @__PURE__ */ React31.createElement(Text25, { dimColor: true }, "Step ", step, "/", total, " \xB7", " "), /* @__PURE__ */ React31.createElement(Text25, { bold: true, color: "cyan" }, title)), /* @__PURE__ */ React31.createElement(Box26, { marginTop: 1, flexDirection: "column" }, children));
15197
15810
  }
15198
15811
  function SummaryLine({ label, value }) {
15199
- return /* @__PURE__ */ React29.createElement(Box25, null, /* @__PURE__ */ React29.createElement(Text24, null, label.padEnd(12)), /* @__PURE__ */ React29.createElement(Text24, { bold: true }, value));
15812
+ return /* @__PURE__ */ React31.createElement(Box26, null, /* @__PURE__ */ React31.createElement(Text25, null, label.padEnd(12)), /* @__PURE__ */ React31.createElement(Text25, { bold: true }, value));
15200
15813
  }
15201
15814
  function presetItems() {
15202
15815
  return ["fast", "smart", "max"].map((name) => ({
@@ -15252,7 +15865,7 @@ async function setupCommand(_opts = {}) {
15252
15865
  const existingKey = loadApiKey();
15253
15866
  const existing = readConfig();
15254
15867
  const { waitUntilExit, unmount } = render4(
15255
- /* @__PURE__ */ React30.createElement(
15868
+ /* @__PURE__ */ React32.createElement(
15256
15869
  Wizard,
15257
15870
  {
15258
15871
  existingApiKey: existingKey,