reasonix 0.7.4 → 0.7.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -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 React25, { useState as useState12 } from "react";
7116
+ import React26, { useState as useState12 } from "react";
7117
7117
 
7118
7118
  // src/cli/ui/App.tsx
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";
7119
+ import { Box as Box21, Static, useApp, useStdout as useStdout8 } from "ink";
7120
+ import React23, { 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";
@@ -7430,26 +7430,42 @@ function AtMentionSuggestions({
7430
7430
  return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", paddingX: 1, marginTop: 1 }, hiddenAbove > 0 ? /* @__PURE__ */ React.createElement(Text, { dimColor: true }, " \u2191 ", hiddenAbove, " more above") : null, shown.map((path, i) => /* @__PURE__ */ React.createElement(FileRow, { key: path, path, isSelected: windowStart + i === selectedIndex })), hiddenBelow > 0 ? /* @__PURE__ */ React.createElement(Text, { dimColor: true }, " \u2193 ", hiddenBelow, " more below") : null, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, " [\u2191\u2193] navigate \xB7 [Tab]/[Enter] pick \xB7 file content inlined on send"));
7431
7431
  }
7432
7432
  function FileRow({ path, isSelected }) {
7433
- const marker = isSelected ? "\u25B8" : " ";
7434
7433
  const slash = path.lastIndexOf("/");
7435
7434
  const dir = slash >= 0 ? `${path.slice(0, slash)}/` : "";
7436
7435
  const base = slash >= 0 ? path.slice(slash + 1) : path;
7437
7436
  if (isSelected) {
7438
- return /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { bold: true, color: "cyan" }, marker, " ", base), /* @__PURE__ */ React.createElement(Text, { color: "cyan" }, dir ? ` ${dir}` : ""));
7437
+ return /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { backgroundColor: "#67e8f9", color: "black", bold: true }, ` \u25B8 ${base}${dir ? ` ${dir}` : ""} `));
7439
7438
  }
7440
- return /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, marker, " ", base, dir ? ` ${dir}` : ""));
7439
+ return /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: "#94a3b8" }, ` ${base}`), dir ? /* @__PURE__ */ React.createElement(Text, { dimColor: true }, ` ${dir}`) : null);
7441
7440
  }
7442
7441
 
7443
7442
  // src/cli/ui/ChoiceConfirm.tsx
7444
- import { Box as Box3, Text as Text3 } from "ink";
7445
- import React4 from "react";
7443
+ import { Box as Box4 } from "ink";
7444
+ import React5 from "react";
7445
+
7446
+ // src/cli/ui/ModalCard.tsx
7447
+ import { Box as Box2, Text as Text2, useStdout } from "ink";
7448
+ import React2 from "react";
7449
+ function ModalCard({
7450
+ accent,
7451
+ title,
7452
+ subtitle,
7453
+ icon,
7454
+ children
7455
+ }) {
7456
+ const { stdout: stdout2 } = useStdout();
7457
+ const cols = stdout2?.columns ?? 80;
7458
+ const ruleWidth = Math.min(80, Math.max(28, cols - 4));
7459
+ const titleText = icon ? ` ${icon} ${title} ` : ` ${title} `;
7460
+ return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React2.createElement(Box2, null, /* @__PURE__ */ React2.createElement(Text2, { color: accent }, "\u2594".repeat(ruleWidth))), /* @__PURE__ */ React2.createElement(Box2, { marginTop: 1 }, /* @__PURE__ */ React2.createElement(Text2, { backgroundColor: accent, color: "black", bold: true }, titleText), subtitle ? /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, ` ${subtitle}`) : null), /* @__PURE__ */ React2.createElement(Box2, { marginTop: 1, flexDirection: "column" }, children), /* @__PURE__ */ React2.createElement(Box2, { marginTop: 1 }, /* @__PURE__ */ React2.createElement(Text2, { color: accent, dimColor: true }, "\u2581".repeat(ruleWidth))));
7461
+ }
7446
7462
 
7447
7463
  // src/cli/ui/Select.tsx
7448
- import { Box as Box2, Text as Text2 } from "ink";
7449
- import React3, { useState } from "react";
7464
+ import { Box as Box3, Text as Text3 } from "ink";
7465
+ import React4, { useState } from "react";
7450
7466
 
7451
7467
  // src/cli/ui/keystroke-context.tsx
7452
- import React2, { createContext, useContext, useEffect, useRef } from "react";
7468
+ import React3, { createContext, useContext, useEffect, useRef } from "react";
7453
7469
 
7454
7470
  // src/cli/ui/stdin-reader.ts
7455
7471
  import { stdin } from "process";
@@ -7771,7 +7787,7 @@ function KeystrokeProvider({
7771
7787
  unsubscribe();
7772
7788
  };
7773
7789
  }, [providedReader]);
7774
- return /* @__PURE__ */ React2.createElement(KeystrokeContext.Provider, { value: busRef.current }, children);
7790
+ return /* @__PURE__ */ React3.createElement(KeystrokeContext.Provider, { value: busRef.current }, children);
7775
7791
  }
7776
7792
  function useKeystroke(handler, isActive = true) {
7777
7793
  const bus = useContext(KeystrokeContext);
@@ -7809,7 +7825,7 @@ function SingleSelect({
7809
7825
  onCancel();
7810
7826
  }
7811
7827
  });
7812
- return /* @__PURE__ */ React3.createElement(Box2, { flexDirection: "column" }, items.map((item, i) => /* @__PURE__ */ React3.createElement(
7828
+ return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column" }, items.map((item, i) => /* @__PURE__ */ React4.createElement(
7813
7829
  SelectRow,
7814
7830
  {
7815
7831
  key: item.value,
@@ -7817,7 +7833,7 @@ function SingleSelect({
7817
7833
  active: i === index,
7818
7834
  marker: i === index ? "\u25B8" : " "
7819
7835
  }
7820
- )), footer ? /* @__PURE__ */ React3.createElement(Box2, { marginTop: 1 }, /* @__PURE__ */ React3.createElement(Text2, { dimColor: true }, footer)) : null);
7836
+ )), footer ? /* @__PURE__ */ React4.createElement(Box3, { marginTop: 1 }, /* @__PURE__ */ React4.createElement(Text3, { dimColor: true }, footer)) : null);
7821
7837
  }
7822
7838
  function MultiSelect({
7823
7839
  items,
@@ -7853,10 +7869,10 @@ function MultiSelect({
7853
7869
  onCancel();
7854
7870
  }
7855
7871
  });
7856
- return /* @__PURE__ */ React3.createElement(Box2, { flexDirection: "column" }, items.map((item, i) => {
7872
+ return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column" }, items.map((item, i) => {
7857
7873
  const checked = selected.has(item.value);
7858
7874
  const marker = checked ? "[x]" : "[ ]";
7859
- return /* @__PURE__ */ React3.createElement(
7875
+ return /* @__PURE__ */ React4.createElement(
7860
7876
  SelectRow,
7861
7877
  {
7862
7878
  key: item.value,
@@ -7865,7 +7881,7 @@ function MultiSelect({
7865
7881
  marker: `${i === index ? "\u25B8" : " "} ${marker}`
7866
7882
  }
7867
7883
  );
7868
- }), footer ? /* @__PURE__ */ React3.createElement(Box2, { marginTop: 1 }, /* @__PURE__ */ React3.createElement(Text2, { dimColor: true }, footer)) : null);
7884
+ }), footer ? /* @__PURE__ */ React4.createElement(Box3, { marginTop: 1 }, /* @__PURE__ */ React4.createElement(Text3, { dimColor: true }, footer)) : null);
7869
7885
  }
7870
7886
  function SelectRow({
7871
7887
  item,
@@ -7873,7 +7889,7 @@ function SelectRow({
7873
7889
  marker
7874
7890
  }) {
7875
7891
  const color = item.disabled ? "gray" : active ? "cyan" : void 0;
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);
7892
+ return /* @__PURE__ */ React4.createElement(Box3, { flexDirection: "column" }, /* @__PURE__ */ React4.createElement(Box3, null, /* @__PURE__ */ React4.createElement(Text3, { color }, marker, " ", item.label)), item.hint ? /* @__PURE__ */ React4.createElement(Box3, { paddingLeft: marker.length + 1 }, /* @__PURE__ */ React4.createElement(Text3, { dimColor: true }, item.hint)) : null);
7877
7893
  }
7878
7894
  function findNextEnabled(items, from, step) {
7879
7895
  if (items.length === 0) return 0;
@@ -7906,7 +7922,7 @@ function ChoiceConfirmInner({ question, options, allowCustom, onChoose }) {
7906
7922
  label: "Cancel \u2014 drop the question",
7907
7923
  hint: "Model stops and asks what you want instead."
7908
7924
  });
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(
7925
+ return /* @__PURE__ */ React5.createElement(ModalCard, { accent: "#f0abfc", icon: "\u{1F500}", title: "model wants you to pick", subtitle: question }, /* @__PURE__ */ React5.createElement(Box4, null, /* @__PURE__ */ React5.createElement(
7910
7926
  SingleSelect,
7911
7927
  {
7912
7928
  initialValue: options[0]?.id,
@@ -7921,11 +7937,11 @@ function ChoiceConfirmInner({ question, options, allowCustom, onChoose }) {
7921
7937
  }
7922
7938
  )));
7923
7939
  }
7924
- var ChoiceConfirm = React4.memo(ChoiceConfirmInner);
7940
+ var ChoiceConfirm = React5.memo(ChoiceConfirmInner);
7925
7941
 
7926
7942
  // src/cli/ui/EditConfirm.tsx
7927
- import { Box as Box4, Text as Text4, useStdout } from "ink";
7928
- import React5, { useMemo, useState as useState2 } from "react";
7943
+ import { Box as Box5, Text as Text4, useStdout as useStdout2 } from "ink";
7944
+ import React6, { useMemo, useState as useState2 } from "react";
7929
7945
 
7930
7946
  // src/code/diff-preview.ts
7931
7947
  function formatEditBlockDiff(block, opts = {}) {
@@ -8000,7 +8016,7 @@ function capLines(lines, maxLines, indent) {
8000
8016
  var MODAL_OVERHEAD_ROWS = 18;
8001
8017
  var MIN_DIFF_ROWS = 8;
8002
8018
  function EditConfirm({ block, onChoose }) {
8003
- const { stdout: stdout2 } = useStdout();
8019
+ const { stdout: stdout2 } = useStdout2();
8004
8020
  const rows = stdout2?.rows ?? 40;
8005
8021
  const budget = Math.max(MIN_DIFF_ROWS, rows - MODAL_OVERHEAD_ROWS);
8006
8022
  const allLines = useMemo(
@@ -8064,57 +8080,75 @@ function EditConfirm({ block, onChoose }) {
8064
8080
  const hiddenBelow = Math.max(0, allLines.length - effectiveScroll - budget);
8065
8081
  const totalLines = allLines.length;
8066
8082
  const showScrollHud = hiddenAbove + hiddenBelow > 0;
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(
8068
- Text4,
8083
+ const subtitleParts = [`-${removed} +${added} lines`];
8084
+ if (showScrollHud) {
8085
+ subtitleParts.push(
8086
+ `viewing ${effectiveScroll + 1}-${effectiveScroll + visibleLines.length}/${totalLines}`
8087
+ );
8088
+ }
8089
+ return /* @__PURE__ */ React6.createElement(
8090
+ ModalCard,
8069
8091
  {
8070
- dimColor: true
8092
+ accent: isNew ? "#86efac" : "#fcd34d",
8093
+ icon: isNew ? "\u271A" : "\u270E",
8094
+ title: `${tag} ${block.path}`,
8095
+ subtitle: subtitleParts.join(" \xB7 ")
8071
8096
  },
8072
- ` \u2191 ${hiddenAbove} line${hiddenAbove === 1 ? "" : "s"} above (\u2191/k or PgUp)`
8073
- ) : null, /* @__PURE__ */ React5.createElement(Box4, { marginTop: hiddenAbove > 0 ? 0 : 1, flexDirection: "column" }, visibleLines.map((line, i) => {
8074
- const trimmed = line.trimStart();
8075
- const color = trimmed.startsWith("+") ? "green" : trimmed.startsWith("-") ? "red" : void 0;
8076
- const dim = !color;
8077
- return /* @__PURE__ */ React5.createElement(
8097
+ hiddenAbove > 0 ? /* @__PURE__ */ React6.createElement(
8078
8098
  Text4,
8079
8099
  {
8080
- key: `diff-${effectiveScroll}-${i}`,
8081
- color,
8082
- dimColor: dim
8100
+ dimColor: true
8083
8101
  },
8084
- line
8085
- );
8086
- })), hiddenBelow > 0 ? /* @__PURE__ */ React5.createElement(
8087
- Text4,
8088
- {
8089
- dimColor: true
8090
- },
8091
- ` \u2193 ${hiddenBelow} line${hiddenBelow === 1 ? "" : "s"} below (\u2193/j or Space/PgDn)`
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")));
8102
+ ` \u2191 ${hiddenAbove} line${hiddenAbove === 1 ? "" : "s"} above (\u2191/k or PgUp)`
8103
+ ) : null,
8104
+ /* @__PURE__ */ React6.createElement(Box5, { flexDirection: "column" }, visibleLines.map((line, i) => {
8105
+ const trimmed = line.trimStart();
8106
+ const color = trimmed.startsWith("+") ? "#4ade80" : trimmed.startsWith("-") ? "#f87171" : void 0;
8107
+ const dim = !color;
8108
+ return /* @__PURE__ */ React6.createElement(
8109
+ Text4,
8110
+ {
8111
+ key: `diff-${effectiveScroll}-${i}`,
8112
+ color,
8113
+ dimColor: dim
8114
+ },
8115
+ line
8116
+ );
8117
+ })),
8118
+ hiddenBelow > 0 ? /* @__PURE__ */ React6.createElement(
8119
+ Text4,
8120
+ {
8121
+ dimColor: true
8122
+ },
8123
+ ` \u2193 ${hiddenBelow} line${hiddenBelow === 1 ? "" : "s"} below (\u2193/j or Space/PgDn)`
8124
+ ) : null,
8125
+ /* @__PURE__ */ React6.createElement(Box5, { marginTop: 1 }, /* @__PURE__ */ React6.createElement(Text4, { dimColor: true }, "[", /* @__PURE__ */ React6.createElement(Text4, { color: "#67e8f9", bold: true }, "y"), "/Enter] apply \xB7 [", /* @__PURE__ */ React6.createElement(Text4, { color: "#67e8f9", bold: true }, "n"), "] reject \xB7 [", /* @__PURE__ */ React6.createElement(Text4, { color: "#67e8f9", bold: true }, "a"), "] apply rest \xB7 [", /* @__PURE__ */ React6.createElement(Text4, { color: "#67e8f9", bold: true }, "A"), "] flip AUTO \xB7 [", /* @__PURE__ */ React6.createElement(Text4, { color: "#67e8f9", bold: true }, "\u2191\u2193/Space"), "] scroll \xB7 [Esc] abort"))
8126
+ );
8093
8127
  }
8094
8128
 
8095
8129
  // src/cli/ui/EventLog.tsx
8096
- import { Box as Box8, Text as Text8, useStdout as useStdout2 } from "ink";
8097
- import React10 from "react";
8130
+ import { Box as Box9, Text as Text8, useStdout as useStdout3 } from "ink";
8131
+ import React11 from "react";
8098
8132
 
8099
8133
  // src/cli/ui/PlanStateBlock.tsx
8100
- import { Box as Box5, Text as Text5 } from "ink";
8101
- import React6 from "react";
8134
+ import { Box as Box6, Text as Text5 } from "ink";
8135
+ import React7 from "react";
8102
8136
  function PlanStateBlock({ planState }) {
8103
8137
  const fields = [];
8104
- if (planState.subgoals.length) fields.push(["subgoals", planState.subgoals, "cyan", false]);
8138
+ if (planState.subgoals.length) fields.push(["subgoals", planState.subgoals, "#67e8f9", false]);
8105
8139
  if (planState.hypotheses.length)
8106
- fields.push(["hypotheses", planState.hypotheses, "green", false]);
8140
+ fields.push(["hypotheses", planState.hypotheses, "#86efac", false]);
8107
8141
  if (planState.uncertainties.length)
8108
- fields.push(["uncertainties", planState.uncertainties, "yellow", false]);
8142
+ fields.push(["uncertainties", planState.uncertainties, "#fcd34d", false]);
8109
8143
  if (planState.rejectedPaths.length)
8110
- fields.push(["rejected", planState.rejectedPaths, "red", true]);
8144
+ fields.push(["rejected", planState.rejectedPaths, "#94a3b8", true]);
8111
8145
  if (fields.length === 0) return null;
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 ")}`))));
8146
+ return /* @__PURE__ */ React7.createElement(Box6, { flexDirection: "column", marginBottom: 1 }, fields.map(([label, items, color, dim]) => /* @__PURE__ */ React7.createElement(Box6, { key: label }, /* @__PURE__ */ React7.createElement(Text5, { backgroundColor: color, color: "black", bold: true, dimColor: dim }, ` ${label} ${items.length} `), /* @__PURE__ */ React7.createElement(Text5, null, " "), /* @__PURE__ */ React7.createElement(Text5, { dimColor: dim }, items.join(" \xB7 ")))));
8113
8147
  }
8114
8148
 
8115
8149
  // src/cli/ui/PlanStepList.tsx
8116
- import { Box as Box6, Text as Text6 } from "ink";
8117
- import React7 from "react";
8150
+ import { Box as Box7, Text as Text6 } from "ink";
8151
+ import React8 from "react";
8118
8152
  function riskDots(risk) {
8119
8153
  switch (risk) {
8120
8154
  case "high":
@@ -8127,18 +8161,6 @@ function riskDots(risk) {
8127
8161
  return { dots: " ", color: "gray" };
8128
8162
  }
8129
8163
  }
8130
- function statusGlyph(status2) {
8131
- switch (status2) {
8132
- case "done":
8133
- return { glyph: "\u2713", color: "green" };
8134
- case "running":
8135
- return { glyph: "\u25B6", color: "cyan" };
8136
- case "skipped":
8137
- return { glyph: "\u2014", color: "gray" };
8138
- default:
8139
- return { glyph: " ", color: "yellow" };
8140
- }
8141
- }
8142
8164
  function getStatus(stepId, statuses) {
8143
8165
  if (!statuses) return "pending";
8144
8166
  if (statuses instanceof Map) {
@@ -8153,25 +8175,37 @@ function PlanStepListInner({ steps, statuses, focusStepId }) {
8153
8175
  { length: steps.length },
8154
8176
  (_, i) => getStatus(steps[i].id, statuses)
8155
8177
  ).filter((s) => s === "done").length;
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) => {
8178
+ const pct2 = Math.round(doneCount / steps.length * 100);
8179
+ return /* @__PURE__ */ React8.createElement(Box7, { flexDirection: "column" }, /* @__PURE__ */ React8.createElement(Box7, null, /* @__PURE__ */ React8.createElement(Text6, { dimColor: true }, `${steps.length} step${steps.length === 1 ? "" : "s"}`, doneCount > 0 ? ` \xB7 ${doneCount}/${steps.length} done (${pct2}%)` : "", hasAnyRisk ? " \xB7 risk: " : ""), hasAnyRisk ? /* @__PURE__ */ React8.createElement(RiskLegend, null) : null), /* @__PURE__ */ React8.createElement(Box7, { flexDirection: "column", marginTop: 1 }, steps.map((step) => {
8157
8180
  const status2 = getStatus(step.id, statuses);
8158
8181
  const focus = focusStepId === step.id;
8159
8182
  const risk = riskDots(step.risk);
8160
- const glyph = statusGlyph(status2);
8161
8183
  const titleDim = status2 === "done" || status2 === "skipped";
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}`));
8184
+ return /* @__PURE__ */ React8.createElement(Box7, { key: step.id }, /* @__PURE__ */ React8.createElement(Text6, { color: focus ? "#67e8f9" : "gray", bold: focus }, focus ? "\u25B8 " : " "), /* @__PURE__ */ React8.createElement(Text6, { color: risk.color, bold: true }, risk.dots), /* @__PURE__ */ React8.createElement(Text6, null, " "), /* @__PURE__ */ React8.createElement(StatusBadge, { status: status2 }), /* @__PURE__ */ React8.createElement(Text6, null, " "), /* @__PURE__ */ React8.createElement(Text6, { dimColor: titleDim, bold: focus }, `${step.id} \xB7 ${step.title}`));
8163
8185
  })));
8164
8186
  }
8187
+ function StatusBadge({ status: status2 }) {
8188
+ switch (status2) {
8189
+ case "done":
8190
+ return /* @__PURE__ */ React8.createElement(Text6, { backgroundColor: "#4ade80", color: "black", bold: true }, " \u2713 DONE ");
8191
+ case "running":
8192
+ return /* @__PURE__ */ React8.createElement(Text6, { backgroundColor: "#67e8f9", color: "black", bold: true }, " \u25B6 RUN ");
8193
+ case "skipped":
8194
+ return /* @__PURE__ */ React8.createElement(Text6, { backgroundColor: "#94a3b8", color: "black", bold: true }, " \u2014 SKIP ");
8195
+ default:
8196
+ return /* @__PURE__ */ React8.createElement(Text6, { color: "#94a3b8", dimColor: true }, " \u2610 PEND ");
8197
+ }
8198
+ }
8165
8199
  function RiskLegend() {
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"));
8200
+ return /* @__PURE__ */ React8.createElement(Box7, null, /* @__PURE__ */ React8.createElement(Text6, { color: "green" }, "\u25CF"), /* @__PURE__ */ React8.createElement(Text6, { dimColor: true }, " low "), /* @__PURE__ */ React8.createElement(Text6, { color: "yellow" }, "\u25CF\u25CF"), /* @__PURE__ */ React8.createElement(Text6, { dimColor: true }, " med "), /* @__PURE__ */ React8.createElement(Text6, { color: "red" }, "\u25CF\u25CF\u25CF"), /* @__PURE__ */ React8.createElement(Text6, { dimColor: true }, " high"));
8167
8201
  }
8168
- var PlanStepList = React7.memo(PlanStepListInner);
8202
+ var PlanStepList = React8.memo(PlanStepListInner);
8169
8203
 
8170
8204
  // src/cli/ui/markdown.tsx
8171
8205
  import { readFileSync as readFileSync13, statSync as statSync6 } from "fs";
8172
8206
  import { isAbsolute as isAbsolute4, join as join11 } from "path";
8173
- import { Box as Box7, Text as Text7 } from "ink";
8174
- import React8 from "react";
8207
+ import { Box as Box8, Text as Text7 } from "ink";
8208
+ import React9 from "react";
8175
8209
  var SUPERSCRIPT = {
8176
8210
  "0": "\u2070",
8177
8211
  "1": "\xB9",
@@ -8426,67 +8460,67 @@ function InlineMd({
8426
8460
  for (const m of text.matchAll(INLINE_RE)) {
8427
8461
  const start = m.index ?? 0;
8428
8462
  if (start > last) {
8429
- parts.push(/* @__PURE__ */ React8.createElement(Text7, { key: `t${idx++}` }, text.slice(last, start)));
8463
+ parts.push(/* @__PURE__ */ React9.createElement(Text7, { key: `t${idx++}` }, text.slice(last, start)));
8430
8464
  }
8431
8465
  if (m[2] !== void 0 && m[3] !== void 0) {
8432
8466
  const linkText = m[2];
8433
8467
  const url = m[3];
8434
8468
  if (isExternalUrl(url)) {
8435
8469
  parts.push(
8436
- /* @__PURE__ */ React8.createElement(Text7, { key: `l${idx++}`, color: "blue", underline: true }, linkText)
8470
+ /* @__PURE__ */ React9.createElement(Text7, { key: `l${idx++}`, color: "blue", underline: true }, linkText)
8437
8471
  );
8438
8472
  } else {
8439
8473
  const status2 = citations?.get(url);
8440
8474
  if (status2 && !status2.ok) {
8441
8475
  parts.push(
8442
- /* @__PURE__ */ React8.createElement(Text7, { key: `l${idx++}`, color: "red", strikethrough: true }, `${linkText} \u2717`)
8476
+ /* @__PURE__ */ React9.createElement(Text7, { key: `l${idx++}`, color: "red", strikethrough: true }, `${linkText} \u2717`)
8443
8477
  );
8444
8478
  } else {
8445
8479
  parts.push(
8446
- /* @__PURE__ */ React8.createElement(Text7, { key: `l${idx++}`, color: "cyan", underline: true }, linkText)
8480
+ /* @__PURE__ */ React9.createElement(Text7, { key: `l${idx++}`, color: "cyan", underline: true }, linkText)
8447
8481
  );
8448
8482
  }
8449
8483
  }
8450
8484
  } else if (m[4] !== void 0) {
8451
8485
  parts.push(
8452
- /* @__PURE__ */ React8.createElement(Text7, { key: `bi${idx++}`, bold: true, italic: true }, m[4])
8486
+ /* @__PURE__ */ React9.createElement(Text7, { key: `bi${idx++}`, bold: true, italic: true }, m[4])
8453
8487
  );
8454
8488
  } else if (m[5] !== void 0) {
8455
8489
  parts.push(
8456
- /* @__PURE__ */ React8.createElement(Text7, { key: `b${idx++}`, bold: true }, m[5])
8490
+ /* @__PURE__ */ React9.createElement(Text7, { key: `b${idx++}`, bold: true }, m[5])
8457
8491
  );
8458
8492
  } else if (m[6] !== void 0) {
8459
8493
  const stripped = m[6].replace(/^(\w+)\s+/, "");
8460
8494
  parts.push(
8461
- /* @__PURE__ */ React8.createElement(Text7, { key: `c${idx++}`, color: "yellow" }, stripped)
8495
+ /* @__PURE__ */ React9.createElement(Text7, { key: `c${idx++}`, color: "yellow" }, stripped)
8462
8496
  );
8463
8497
  } else if (m[7] !== void 0) {
8464
8498
  parts.push(
8465
- /* @__PURE__ */ React8.createElement(Text7, { key: `c${idx++}`, color: "yellow" }, m[7])
8499
+ /* @__PURE__ */ React9.createElement(Text7, { key: `c${idx++}`, color: "yellow" }, m[7])
8466
8500
  );
8467
8501
  } else if (m[8] !== void 0) {
8468
8502
  parts.push(
8469
- /* @__PURE__ */ React8.createElement(Text7, { key: `s${idx++}`, strikethrough: true, dimColor: true }, m[8])
8503
+ /* @__PURE__ */ React9.createElement(Text7, { key: `s${idx++}`, strikethrough: true, dimColor: true }, m[8])
8470
8504
  );
8471
8505
  } else if (m[9] !== void 0) {
8472
8506
  parts.push(
8473
- /* @__PURE__ */ React8.createElement(Text7, { key: `i${idx++}`, italic: true }, m[9])
8507
+ /* @__PURE__ */ React9.createElement(Text7, { key: `i${idx++}`, italic: true }, m[9])
8474
8508
  );
8475
8509
  } else if (m[10] !== void 0) {
8476
- parts.push(/* @__PURE__ */ React8.createElement(Text7, { key: `esc${idx++}` }, m[10]));
8510
+ parts.push(/* @__PURE__ */ React9.createElement(Text7, { key: `esc${idx++}` }, m[10]));
8477
8511
  }
8478
8512
  last = start + m[0].length;
8479
8513
  }
8480
8514
  if (last < text.length) {
8481
- parts.push(/* @__PURE__ */ React8.createElement(Text7, { key: `t${idx++}` }, text.slice(last)));
8515
+ parts.push(/* @__PURE__ */ React9.createElement(Text7, { key: `t${idx++}` }, text.slice(last)));
8482
8516
  }
8483
8517
  if (padTo !== void 0) {
8484
8518
  const seen = visibleWidth(text);
8485
8519
  if (seen < padTo) {
8486
- parts.push(/* @__PURE__ */ React8.createElement(Text7, { key: `pad${idx++}` }, " ".repeat(padTo - seen)));
8520
+ parts.push(/* @__PURE__ */ React9.createElement(Text7, { key: `pad${idx++}` }, " ".repeat(padTo - seen)));
8487
8521
  }
8488
8522
  }
8489
- return /* @__PURE__ */ React8.createElement(Text7, null, parts);
8523
+ return /* @__PURE__ */ React9.createElement(Text7, null, parts);
8490
8524
  }
8491
8525
  function stripInlineMarkup(s) {
8492
8526
  return s.replace(
@@ -8725,34 +8759,34 @@ function parseBulletItem(raw) {
8725
8759
  function BlockView({ block, citations }) {
8726
8760
  switch (block.kind) {
8727
8761
  case "heading":
8728
- return /* @__PURE__ */ React8.createElement(Text7, { bold: true, color: "cyan" }, /* @__PURE__ */ React8.createElement(InlineMd, { text: block.text, citations }));
8762
+ return /* @__PURE__ */ React9.createElement(HeadingView, { level: block.level, text: block.text, citations });
8729
8763
  case "paragraph":
8730
- return /* @__PURE__ */ React8.createElement(ParagraphView, { text: block.text, citations });
8764
+ return /* @__PURE__ */ React9.createElement(ParagraphView, { text: block.text, citations });
8731
8765
  case "bullet":
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 }))));
8766
+ return /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column" }, block.items.map((item, i) => /* @__PURE__ */ React9.createElement(Box8, { key: `${i}-${item.text.slice(0, 24)}` }, /* @__PURE__ */ React9.createElement(Text7, { color: item.task === "done" ? "green" : "cyan" }, bulletPrefix(block, i, item)), item.task === "done" ? /* @__PURE__ */ React9.createElement(Text7, { strikethrough: true, dimColor: true }, /* @__PURE__ */ React9.createElement(InlineMd, { text: item.text, citations })) : /* @__PURE__ */ React9.createElement(InlineMd, { text: item.text, citations }))));
8733
8767
  case "quote":
8734
- return /* @__PURE__ */ React8.createElement(BlockquoteView, { block, citations });
8768
+ return /* @__PURE__ */ React9.createElement(BlockquoteView, { block, citations });
8735
8769
  case "code":
8736
8770
  if (DIAGRAM_LANGS.has(block.lang.toLowerCase())) {
8737
- return /* @__PURE__ */ React8.createElement(DiagramCodeBlock, { lang: block.lang, text: block.text });
8771
+ return /* @__PURE__ */ React9.createElement(DiagramCodeBlock, { lang: block.lang, text: block.text });
8738
8772
  }
8739
- return /* @__PURE__ */ React8.createElement(Box7, { borderStyle: "single", borderColor: "gray", paddingX: 1 }, /* @__PURE__ */ React8.createElement(Text7, { color: "yellow" }, block.text));
8773
+ return /* @__PURE__ */ React9.createElement(CodeBlockView, { lang: block.lang, text: block.text });
8740
8774
  case "edit-block":
8741
- return /* @__PURE__ */ React8.createElement(EditBlockRow, { block });
8775
+ return /* @__PURE__ */ React9.createElement(EditBlockRow, { block });
8742
8776
  case "table":
8743
- return /* @__PURE__ */ React8.createElement(TableBlockRow, { block, citations });
8777
+ return /* @__PURE__ */ React9.createElement(TableBlockRow, { block, citations });
8744
8778
  case "hr":
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");
8779
+ return /* @__PURE__ */ React9.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");
8746
8780
  }
8747
8781
  }
8748
8782
  function ParagraphView({ text, citations }) {
8749
8783
  if (!text.includes("\n")) {
8750
- return /* @__PURE__ */ React8.createElement(InlineMd, { text, citations });
8784
+ return /* @__PURE__ */ React9.createElement(InlineMd, { text, citations });
8751
8785
  }
8752
8786
  const rows = text.split("\n");
8753
- return /* @__PURE__ */ React8.createElement(Box7, { flexDirection: "column" }, rows.map((row2, i) => (
8787
+ return /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column" }, rows.map((row2, i) => (
8754
8788
  // biome-ignore lint/suspicious/noArrayIndexKey: hard-break rows are source-ordered and never reorder
8755
- /* @__PURE__ */ React8.createElement(InlineMd, { key: `ln-${i}`, text: row2, citations })
8789
+ /* @__PURE__ */ React9.createElement(InlineMd, { key: `ln-${i}`, text: row2, citations })
8756
8790
  )));
8757
8791
  }
8758
8792
  function bulletPrefix(block, i, item) {
@@ -8765,12 +8799,11 @@ function BlockquoteView({
8765
8799
  block,
8766
8800
  citations
8767
8801
  }) {
8768
- return /* @__PURE__ */ React8.createElement(
8769
- Box7,
8802
+ return /* @__PURE__ */ React9.createElement(
8803
+ Box8,
8770
8804
  {
8771
8805
  borderStyle: "single",
8772
- borderColor: "gray",
8773
- borderDimColor: true,
8806
+ borderColor: "#c4b5fd",
8774
8807
  borderTop: false,
8775
8808
  borderRight: false,
8776
8809
  borderBottom: false,
@@ -8778,7 +8811,7 @@ function BlockquoteView({
8778
8811
  flexDirection: "column",
8779
8812
  gap: 1
8780
8813
  },
8781
- block.children.map((child, i) => /* @__PURE__ */ React8.createElement(BlockView, { key: `q-${i}-${child.kind}`, block: child, citations }))
8814
+ block.children.map((child, i) => /* @__PURE__ */ React9.createElement(BlockView, { key: `q-${i}-${child.kind}`, block: child, citations }))
8782
8815
  );
8783
8816
  }
8784
8817
  function splitTableRow(line) {
@@ -8796,14 +8829,14 @@ function TableBlockRow({ block, citations }) {
8796
8829
  widths.push(Math.min(40, Math.max(3, ...cellLengths)));
8797
8830
  }
8798
8831
  const separator = widths.map((w) => "\u2500".repeat(w)).join("\u2500\u253C\u2500");
8799
- return /* @__PURE__ */ React8.createElement(Box7, { flexDirection: "column" }, /* @__PURE__ */ React8.createElement(Box7, null, block.header.map((cell, ci) => (
8832
+ return /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column" }, /* @__PURE__ */ React9.createElement(Box8, null, block.header.map((cell, ci) => (
8800
8833
  // biome-ignore lint/suspicious/noArrayIndexKey: table columns never reorder — derived from a static header array
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) => (
8834
+ /* @__PURE__ */ React9.createElement(Text7, { key: `h-${ci}`, bold: true, color: "cyan" }, /* @__PURE__ */ React9.createElement(InlineMd, { text: cell, padTo: widths[ci] ?? 3, citations }), ci < colCount - 1 ? " \u2502 " : "")
8835
+ ))), /* @__PURE__ */ React9.createElement(Text7, { dimColor: true }, separator), block.rows.map((row2, ri) => (
8803
8836
  // biome-ignore lint/suspicious/noArrayIndexKey: table rows render in source order and don't reorder
8804
- /* @__PURE__ */ React8.createElement(Box7, { key: `r-${ri}` }, Array.from({ length: colCount }).map((_, ci) => (
8837
+ /* @__PURE__ */ React9.createElement(Box8, { key: `r-${ri}` }, Array.from({ length: colCount }).map((_, ci) => (
8805
8838
  // biome-ignore lint/suspicious/noArrayIndexKey: same — column axis is fixed by the table shape
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 " : "")
8839
+ /* @__PURE__ */ React9.createElement(Text7, { key: `c-${ri}-${ci}` }, /* @__PURE__ */ React9.createElement(InlineMd, { text: row2[ci] ?? "", padTo: widths[ci] ?? 3, citations }), ci < colCount - 1 ? " \u2502 " : "")
8807
8840
  )))
8808
8841
  )));
8809
8842
  }
@@ -8823,7 +8856,7 @@ function EditBlockRow({ block }) {
8823
8856
  const isNewFile = block.search.length === 0;
8824
8857
  const searchLines = block.search.split("\n");
8825
8858
  const replaceLines = block.replace.split("\n");
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}`))));
8859
+ return /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React9.createElement(Box8, null, /* @__PURE__ */ React9.createElement(Text7, { bold: true, color: "cyan" }, block.filename), isNewFile ? /* @__PURE__ */ React9.createElement(Text7, { color: "green", bold: true }, " (new file)") : null), isNewFile ? null : /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column", marginTop: 1 }, searchLines.map((line, i) => /* @__PURE__ */ React9.createElement(Text7, { key: `s-${i}-${line.length}`, color: "red" }, `- ${line}`))), /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column", marginTop: isNewFile ? 1 : 0 }, replaceLines.map((line, i) => /* @__PURE__ */ React9.createElement(Text7, { key: `r-${i}-${line.length}`, color: "green" }, `+ ${line}`))));
8827
8860
  }
8828
8861
  var DIAGRAM_LANGS = /* @__PURE__ */ new Set([
8829
8862
  "mermaid",
@@ -8843,30 +8876,124 @@ var DIAGRAM_VIEWER_HINT = {
8843
8876
  dot: "\u2192 paste at https://dreampuf.github.io/GraphvizOnline to view",
8844
8877
  graphviz: "\u2192 paste at https://dreampuf.github.io/GraphvizOnline to view"
8845
8878
  };
8879
+ function HeadingView({
8880
+ level,
8881
+ text,
8882
+ citations
8883
+ }) {
8884
+ if (level === 1) {
8885
+ return /* @__PURE__ */ React9.createElement(Box8, { marginY: 1 }, /* @__PURE__ */ React9.createElement(Text7, { backgroundColor: "#67e8f9", color: "black", bold: true }, ` ${text} `));
8886
+ }
8887
+ if (level === 2) {
8888
+ return /* @__PURE__ */ React9.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(Text7, { backgroundColor: "#c4b5fd", color: "black", bold: true }, ` ${text} `));
8889
+ }
8890
+ if (level === 3) {
8891
+ return /* @__PURE__ */ React9.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(Text7, { backgroundColor: "#f0abfc", color: "black", bold: true }, ` ${text} `));
8892
+ }
8893
+ return /* @__PURE__ */ React9.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(Text7, { bold: true, color: "#f0abfc" }, "\u25B8", " "), /* @__PURE__ */ React9.createElement(Text7, { bold: true }, /* @__PURE__ */ React9.createElement(InlineMd, { text, citations })));
8894
+ }
8895
+ function CodeBlockView({ lang, text }) {
8896
+ const langLabel = lang.trim();
8897
+ return /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column", borderStyle: "round", borderColor: "#7dd3fc", paddingX: 1 }, langLabel ? /* @__PURE__ */ React9.createElement(Box8, null, /* @__PURE__ */ React9.createElement(Text7, { backgroundColor: "#7dd3fc", color: "black", bold: true }, ` ${langLabel} `)) : null, /* @__PURE__ */ React9.createElement(Text7, { color: "#fde68a" }, text));
8898
+ }
8846
8899
  function DiagramCodeBlock({ lang, text }) {
8847
8900
  const hint = DIAGRAM_VIEWER_HINT[lang.toLowerCase()] ?? "\u2192 render with the matching viewer to view";
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)));
8901
+ return /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column", borderStyle: "double", borderColor: "magenta", paddingX: 1 }, /* @__PURE__ */ React9.createElement(Text7, { bold: true, color: "magenta" }, `\u25C7 ${lang} diagram (source \u2014 terminal can't draw the graph)`), /* @__PURE__ */ React9.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(Text7, { color: "yellow" }, text)), /* @__PURE__ */ React9.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(Text7, { dimColor: true }, hint)));
8849
8902
  }
8850
8903
  function Markdown({ text, projectRoot }) {
8851
8904
  const cleaned = expandAutolinks(expandEmoji(stripMath(text)));
8852
8905
  const root = projectRoot ?? process.cwd();
8853
- const citations = React8.useMemo(() => collectCitations(cleaned, root), [cleaned, root]);
8854
- const blocks = React8.useMemo(() => parseBlocks(cleaned), [cleaned]);
8906
+ const citations = React9.useMemo(() => collectCitations(cleaned, root), [cleaned, root]);
8907
+ const blocks = React9.useMemo(() => parseBlocks(cleaned), [cleaned]);
8855
8908
  const broken = [];
8856
8909
  for (const [url, status2] of citations) {
8857
8910
  if (!status2.ok) broken.push({ url, reason: status2.reason });
8858
8911
  }
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);
8912
+ return /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column", gap: 1 }, blocks.map((b, i) => /* @__PURE__ */ React9.createElement(BlockView, { key: `${i}-${b.kind}`, block: b, citations })), broken.length > 0 ? /* @__PURE__ */ React9.createElement(BrokenCitationsBlock, { items: broken }) : null);
8860
8913
  }
8861
8914
  function BrokenCitationsBlock({ items }) {
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) => (
8915
+ return /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column", borderStyle: "round", borderColor: "red", paddingX: 1 }, /* @__PURE__ */ React9.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) => (
8863
8916
  // biome-ignore lint/suspicious/noArrayIndexKey: list is derived from a Map iteration order, stable per render
8864
- /* @__PURE__ */ React8.createElement(Text7, { key: `bc-${i}`, color: "red" }, ` \u2717 ${b.url} \u2192 ${b.reason}`)
8917
+ /* @__PURE__ */ React9.createElement(Text7, { key: `bc-${i}`, color: "red" }, ` \u2717 ${b.url} \u2192 ${b.reason}`)
8865
8918
  )));
8866
8919
  }
8867
8920
 
8921
+ // src/cli/ui/theme.ts
8922
+ var GRADIENT = [
8923
+ "#5eead4",
8924
+ // teal
8925
+ "#67e8f9",
8926
+ // cyan
8927
+ "#7dd3fc",
8928
+ // sky
8929
+ "#93c5fd",
8930
+ // blue
8931
+ "#a5b4fc",
8932
+ // indigo
8933
+ "#c4b5fd",
8934
+ // violet
8935
+ "#d8b4fe",
8936
+ // purple
8937
+ "#f0abfc"
8938
+ // fuchsia
8939
+ ];
8940
+ var COLOR = {
8941
+ primary: "#67e8f9",
8942
+ // cyan-300
8943
+ accent: "#c4b5fd",
8944
+ // violet-300
8945
+ brand: "#5eead4",
8946
+ // teal-300
8947
+ user: "#67e8f9",
8948
+ // user message glyph + bar
8949
+ assistant: "#86efac",
8950
+ // green-300, assistant glyph + bar
8951
+ tool: "#fcd34d",
8952
+ // amber-300, tool ok pill bg
8953
+ toolErr: "#fda4af",
8954
+ // rose-300, tool err pill bg
8955
+ info: "#94a3b8",
8956
+ // slate-400, info / dim
8957
+ warn: "#fbbf24",
8958
+ // amber-400
8959
+ err: "#f87171",
8960
+ // red-400
8961
+ ok: "#4ade80"
8962
+ // green-400
8963
+ };
8964
+ var GLYPH = {
8965
+ brand: "\u25C8",
8966
+ user: "\u25C7",
8967
+ assistant: "\u25C6",
8968
+ toolOk: "\u25A3",
8969
+ toolErr: "\u25A5",
8970
+ warn: "\u25B2",
8971
+ err: "\u2726",
8972
+ arrow: "\u203A",
8973
+ bullet: "\xB7",
8974
+ bar: "\u258E",
8975
+ thinBar: "\u258F",
8976
+ block: "\u2588",
8977
+ shade1: "\u2591",
8978
+ shade2: "\u2592",
8979
+ shade3: "\u2593"
8980
+ };
8981
+ function gradientCells(width, glyph = GLYPH.block) {
8982
+ const cells = [];
8983
+ if (width <= 0) return cells;
8984
+ const last = GRADIENT.length - 1;
8985
+ for (let i = 0; i < width; i++) {
8986
+ const t = width === 1 ? 0 : i * last / (width - 1);
8987
+ const lo = Math.floor(t);
8988
+ const hi = Math.min(last, lo + 1);
8989
+ const color = t - lo < 0.5 ? GRADIENT[lo] : GRADIENT[hi];
8990
+ cells.push({ ch: glyph, color });
8991
+ }
8992
+ return cells;
8993
+ }
8994
+
8868
8995
  // src/cli/ui/ticker.tsx
8869
- import React9, { createContext as createContext2, useContext as useContext2, useEffect as useEffect2, useState as useState3 } from "react";
8996
+ import React10, { createContext as createContext2, useContext as useContext2, useEffect as useEffect2, useState as useState3 } from "react";
8870
8997
  var TICK_MS = 120;
8871
8998
  var TickContext = createContext2(0);
8872
8999
  function TickerProvider({ children, disabled }) {
@@ -8876,7 +9003,7 @@ function TickerProvider({ children, disabled }) {
8876
9003
  const id = setInterval(() => setTick((t) => t + 1), TICK_MS);
8877
9004
  return () => clearInterval(id);
8878
9005
  }, [disabled]);
8879
- return /* @__PURE__ */ React9.createElement(TickContext.Provider, { value: tick }, children);
9006
+ return /* @__PURE__ */ React10.createElement(TickContext.Provider, { value: tick }, children);
8880
9007
  }
8881
9008
  function useTick() {
8882
9009
  return useContext2(TickContext);
@@ -9029,51 +9156,105 @@ function RoleGlyph({
9029
9156
  glyph,
9030
9157
  color
9031
9158
  }) {
9032
- return /* @__PURE__ */ React10.createElement(Text8, { color, bold: true }, glyph);
9159
+ return /* @__PURE__ */ React11.createElement(Text8, { color, bold: true }, glyph);
9160
+ }
9161
+ function ToolPill({ label, status: status2 }) {
9162
+ const bg = status2 === "err" ? "red" : "yellow";
9163
+ const symbol = status2 === "err" ? "\u2717" : "\u2713";
9164
+ return /* @__PURE__ */ React11.createElement(Text8, { backgroundColor: bg, color: "black", bold: true }, ` ${symbol} ${label} `);
9033
9165
  }
9034
9166
  function indentContinuationLines(text) {
9035
9167
  if (!text.includes("\n")) return text;
9036
9168
  return text.split("\n").join("\n ");
9037
9169
  }
9038
- var EventRow = React10.memo(function EventRow2({
9170
+ var EventRow = React11.memo(function EventRow2({
9039
9171
  event,
9040
9172
  projectRoot
9041
9173
  }) {
9042
9174
  if (event.role === "user") {
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))));
9175
+ return /* @__PURE__ */ React11.createElement(Box9, { flexDirection: "column" }, event.leadSeparator ? /* @__PURE__ */ React11.createElement(TurnSeparator, null) : null, /* @__PURE__ */ React11.createElement(Box9, null, /* @__PURE__ */ React11.createElement(RoleGlyph, { glyph: ROLE_GLYPH.user, color: "cyan" }), /* @__PURE__ */ React11.createElement(Text8, null, " "), /* @__PURE__ */ React11.createElement(
9176
+ Box9,
9177
+ {
9178
+ flexDirection: "column",
9179
+ borderStyle: "single",
9180
+ borderTop: false,
9181
+ borderRight: false,
9182
+ borderBottom: false,
9183
+ borderColor: COLOR.user,
9184
+ paddingLeft: 1
9185
+ },
9186
+ /* @__PURE__ */ React11.createElement(Text8, null, indentContinuationLines(event.text))
9187
+ )));
9044
9188
  }
9045
9189
  if (event.role === "assistant") {
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));
9190
+ if (event.streaming) return /* @__PURE__ */ React11.createElement(StreamingAssistant, { event });
9191
+ return /* @__PURE__ */ React11.createElement(Box9, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React11.createElement(Box9, null, /* @__PURE__ */ React11.createElement(RoleGlyph, { glyph: ROLE_GLYPH.assistant, color: "green" }), event.stats ? /* @__PURE__ */ React11.createElement(React11.Fragment, null, /* @__PURE__ */ React11.createElement(Text8, null, " "), /* @__PURE__ */ React11.createElement(Text8, { backgroundColor: COLOR.assistant, color: "black", bold: true }, ` ${event.stats.model.replace(/^deepseek-/, "")} `)) : null), /* @__PURE__ */ React11.createElement(
9192
+ Box9,
9193
+ {
9194
+ flexDirection: "column",
9195
+ marginTop: 1,
9196
+ borderStyle: "single",
9197
+ borderTop: false,
9198
+ borderRight: false,
9199
+ borderBottom: false,
9200
+ borderColor: COLOR.assistant,
9201
+ paddingLeft: 1
9202
+ },
9203
+ event.branch ? /* @__PURE__ */ React11.createElement(BranchBlock, { branch: event.branch }) : null,
9204
+ event.reasoning ? /* @__PURE__ */ React11.createElement(ReasoningBlock, { reasoning: event.reasoning }) : null,
9205
+ !isPlanStateEmpty(event.planState) ? /* @__PURE__ */ React11.createElement(PlanStateBlock, { planState: event.planState }) : null,
9206
+ event.text ? /* @__PURE__ */ React11.createElement(Markdown, { text: event.text, projectRoot }) : /* @__PURE__ */ React11.createElement(Text8, { dimColor: true }, "(no content)"),
9207
+ event.stats ? /* @__PURE__ */ React11.createElement(StatsLine, { stats: event.stats }) : null,
9208
+ event.repair ? /* @__PURE__ */ React11.createElement(Text8, { color: COLOR.accent }, event.repair) : null
9209
+ ));
9048
9210
  }
9049
9211
  if (event.role === "tool") {
9050
9212
  const isExplicitError = event.text.startsWith("ERROR:");
9051
9213
  const isEditFile = (event.toolName === "edit_file" || event.toolName?.endsWith("_edit_file")) && !isExplicitError;
9052
9214
  if (isEditFile) {
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 })));
9215
+ return /* @__PURE__ */ React11.createElement(Box9, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React11.createElement(Box9, null, /* @__PURE__ */ React11.createElement(ToolPill, { label: event.toolName ?? "?", status: "ok" }), /* @__PURE__ */ React11.createElement(Text8, { dimColor: true }, " diff:")), /* @__PURE__ */ React11.createElement(
9216
+ Box9,
9217
+ {
9218
+ flexDirection: "column",
9219
+ marginTop: 1,
9220
+ borderStyle: "single",
9221
+ borderTop: false,
9222
+ borderRight: false,
9223
+ borderBottom: false,
9224
+ borderColor: COLOR.tool,
9225
+ paddingLeft: 1
9226
+ },
9227
+ /* @__PURE__ */ React11.createElement(EditFileDiff, { text: event.text })
9228
+ ));
9054
9229
  }
9055
9230
  const summary = summarizeToolResult(event.toolName ?? "?", event.text);
9056
- const color = summary.isError ? "red" : "yellow";
9057
- const glyph = summary.isError ? ROLE_GLYPH.toolErr : ROLE_GLYPH.toolOk;
9058
- const marker = summary.isError ? "\u2717" : "\u2192";
9059
- const durationLabel = event.durationMs !== void 0 && event.durationMs >= 100 ? ` (${formatDuration(event.durationMs)})` : "";
9231
+ const status2 = summary.isError ? "err" : "ok";
9232
+ const durationLabel = event.durationMs !== void 0 && event.durationMs >= 100 ? formatDuration(event.durationMs) : "";
9060
9233
  const indexHint = event.toolIndex !== void 0 ? ` /tool ${event.toolIndex}` : "";
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);
9234
+ return /* @__PURE__ */ React11.createElement(Box9, null, /* @__PURE__ */ React11.createElement(ToolPill, { label: event.toolName ?? "?", status: status2 }), durationLabel ? /* @__PURE__ */ React11.createElement(Text8, { dimColor: true }, ` ${durationLabel}`) : null, /* @__PURE__ */ React11.createElement(Text8, { dimColor: true }, " "), /* @__PURE__ */ React11.createElement(Text8, { color: status2 === "err" ? "red" : void 0, dimColor: status2 === "ok" }, summary.summary), indexHint ? /* @__PURE__ */ React11.createElement(Text8, { dimColor: true }, indexHint) : null);
9062
9235
  }
9063
9236
  if (event.role === "error") {
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)));
9237
+ return /* @__PURE__ */ React11.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React11.createElement(Text8, { backgroundColor: "#f87171", color: "black", bold: true }, " \u2726 ERROR "), /* @__PURE__ */ React11.createElement(Text8, null, " "), /* @__PURE__ */ React11.createElement(Text8, { color: "#f87171" }, indentContinuationLines(event.text)));
9065
9238
  }
9066
9239
  if (event.role === "info") {
9067
- return /* @__PURE__ */ React10.createElement(Box8, null, /* @__PURE__ */ React10.createElement(Text8, { dimColor: true }, event.text));
9240
+ const m = event.text.match(/^([▸▶▲⚠✓✗✖↻ⓘ])\s*(.*)$/s);
9241
+ const lead = m?.[1] ?? "\u25B8";
9242
+ const body = m?.[2] ?? event.text;
9243
+ let leadColor = COLOR.info;
9244
+ if (lead === "\u25B2" || lead === "\u26A0") leadColor = COLOR.warn;
9245
+ else if (lead === "\u2713") leadColor = COLOR.ok;
9246
+ else if (lead === "\u2717" || lead === "\u2716") leadColor = COLOR.err;
9247
+ else if (lead === "\u21BB") leadColor = COLOR.primary;
9248
+ return /* @__PURE__ */ React11.createElement(Box9, null, /* @__PURE__ */ React11.createElement(Text8, { color: leadColor, bold: true }, lead), /* @__PURE__ */ React11.createElement(Text8, null, " "), /* @__PURE__ */ React11.createElement(Text8, { dimColor: true }, body));
9068
9249
  }
9069
9250
  if (event.role === "plan") {
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 })));
9251
+ return /* @__PURE__ */ React11.createElement(Box9, { flexDirection: "column", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React11.createElement(Box9, null, /* @__PURE__ */ React11.createElement(Text8, { bold: true, color: "cyan" }, "\u{1F4CB} plan proposed \u2014 pick a choice below")), /* @__PURE__ */ React11.createElement(Box9, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React11.createElement(Markdown, { text: event.text, projectRoot })));
9071
9252
  }
9072
9253
  if (event.role === "step-progress") {
9073
9254
  const sp = event.stepProgress;
9074
- const counter = sp && sp.total > 0 ? ` (${sp.completed}/${sp.total})` : "";
9255
+ const counter = sp && sp.total > 0 ? `${sp.completed}/${sp.total}` : "";
9075
9256
  const label = sp?.title ? `${sp.stepId} \xB7 ${sp.title}` : sp?.stepId ?? "";
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);
9257
+ return /* @__PURE__ */ React11.createElement(Box9, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React11.createElement(Box9, null, /* @__PURE__ */ React11.createElement(Text8, { backgroundColor: "#4ade80", color: "black", bold: true }, " \u2713 STEP "), counter ? /* @__PURE__ */ React11.createElement(React11.Fragment, null, /* @__PURE__ */ React11.createElement(Text8, null, " "), /* @__PURE__ */ React11.createElement(Text8, { color: "#4ade80", bold: true }, counter)) : null, /* @__PURE__ */ React11.createElement(Text8, null, " "), /* @__PURE__ */ React11.createElement(Text8, { color: "#86efac" }, label)), event.text ? /* @__PURE__ */ React11.createElement(Box9, { paddingLeft: 2 }, /* @__PURE__ */ React11.createElement(Text8, { dimColor: true }, event.text)) : null, sp?.notes ? /* @__PURE__ */ React11.createElement(Box9, { paddingLeft: 2 }, /* @__PURE__ */ React11.createElement(Text8, { color: "#fbbf24", dimColor: true }, `note: ${sp.notes}`)) : null);
9077
9258
  }
9078
9259
  if (event.role === "plan-resumed") {
9079
9260
  const rp = event.resumedPlan;
@@ -9088,7 +9269,7 @@ var EventRow = React10.memo(function EventRow2({
9088
9269
  ])
9089
9270
  );
9090
9271
  const nextStep = rp.steps.find((s) => !completedSet.has(s.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 })));
9272
+ return /* @__PURE__ */ React11.createElement(Box9, { flexDirection: "column", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React11.createElement(Box9, null, /* @__PURE__ */ React11.createElement(Text8, { backgroundColor: "#67e8f9", color: "black", bold: true }, " \u21BB RESUMED PLAN "), /* @__PURE__ */ React11.createElement(Text8, null, " "), /* @__PURE__ */ React11.createElement(Text8, { color: "#67e8f9", bold: true }, `${done}/${total}`), /* @__PURE__ */ React11.createElement(Text8, { dimColor: true }, ` done \xB7 last touched ${rp.relativeTime}`)), rp.summary ? /* @__PURE__ */ React11.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React11.createElement(Text8, { color: "#67e8f9" }, rp.summary)) : null, /* @__PURE__ */ React11.createElement(Box9, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React11.createElement(PlanStepList, { steps: rp.steps, statuses, focusStepId: nextStep?.id })));
9092
9273
  }
9093
9274
  if (event.role === "plan-replay") {
9094
9275
  const r = event.replayPlan;
@@ -9099,76 +9280,79 @@ var EventRow = React10.memo(function EventRow2({
9099
9280
  const statuses = new Map(
9100
9281
  r.steps.map((s) => [s.id, completedSet.has(s.id) ? "done" : "pending"])
9101
9282
  );
9102
- const navHint = r.total > 1 ? ` \xB7 ${r.index}/${r.total}` : "";
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(
9104
- Text8,
9105
- {
9106
- dimColor: true
9107
- },
9108
- ` completed ${r.relativeTime} \xB7 ${done}/${total} done${navHint}`
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)")));
9283
+ const navHint = r.total > 1 ? ` \xB7 ${r.index}/${r.total}` : "";
9284
+ return /* @__PURE__ */ React11.createElement(Box9, { flexDirection: "column", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React11.createElement(Box9, null, /* @__PURE__ */ React11.createElement(Text8, { backgroundColor: "#94a3b8", color: "black", bold: true }, " \u23EA REPLAY "), /* @__PURE__ */ React11.createElement(Text8, null, " "), /* @__PURE__ */ React11.createElement(Text8, { color: "#94a3b8", bold: true }, `${done}/${total}`), /* @__PURE__ */ React11.createElement(Text8, { dimColor: true }, ` done \xB7 ${r.relativeTime}${navHint}`)), r.summary ? /* @__PURE__ */ React11.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React11.createElement(Text8, { color: "#94a3b8" }, r.summary)) : null, /* @__PURE__ */ React11.createElement(Box9, null, /* @__PURE__ */ React11.createElement(Text8, { dimColor: true }, r.archiveBasename)), r.body ? /* @__PURE__ */ React11.createElement(Box9, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React11.createElement(Markdown, { text: r.body, projectRoot })) : null, /* @__PURE__ */ React11.createElement(Box9, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React11.createElement(PlanStepList, { steps: r.steps, statuses })), /* @__PURE__ */ React11.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React11.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)")));
9110
9285
  }
9111
9286
  if (event.role === "warning") {
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)));
9287
+ return /* @__PURE__ */ React11.createElement(Box9, null, /* @__PURE__ */ React11.createElement(Text8, { backgroundColor: "#fbbf24", color: "black", bold: true }, " \u25B2 WARN "), /* @__PURE__ */ React11.createElement(Text8, null, " "), /* @__PURE__ */ React11.createElement(Text8, { color: "#fbbf24" }, indentContinuationLines(event.text)));
9113
9288
  }
9114
- return /* @__PURE__ */ React10.createElement(Box8, null, /* @__PURE__ */ React10.createElement(Text8, null, event.text));
9289
+ return /* @__PURE__ */ React11.createElement(Box9, null, /* @__PURE__ */ React11.createElement(Text8, null, event.text));
9115
9290
  });
9116
9291
  function TurnSeparator() {
9117
- const { stdout: stdout2 } = useStdout2();
9292
+ const { stdout: stdout2 } = useStdout3();
9118
9293
  const cols = stdout2?.columns ?? 80;
9119
9294
  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));
9295
+ const sideWidth = Math.max(2, Math.floor((width - 5) / 2));
9296
+ const leftCells = gradientCells(sideWidth, "\u2500");
9297
+ const rightCells = gradientCells(sideWidth, "\u2500");
9298
+ return /* @__PURE__ */ React11.createElement(Box9, { marginTop: 1, marginBottom: 1 }, leftCells.map((c, i) => (
9299
+ // biome-ignore lint/suspicious/noArrayIndexKey: fixed-width gradient row
9300
+ /* @__PURE__ */ React11.createElement(Text8, { key: `tsep-l-${i}`, color: c.color }, c.ch)
9301
+ )), /* @__PURE__ */ React11.createElement(Text8, { color: COLOR.brand, bold: true }, " \u25C6 "), rightCells.map((c, i) => (
9302
+ // biome-ignore lint/suspicious/noArrayIndexKey: fixed-width gradient row
9303
+ /* @__PURE__ */ React11.createElement(Text8, { key: `tsep-r-${i}`, color: c.color }, c.ch)
9304
+ )));
9124
9305
  }
9125
9306
  function EditFileDiff({ text }) {
9126
9307
  const lines = text.split(/\r?\n/);
9127
9308
  const [statusHeader, hunkHeader, ...body] = lines;
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) => {
9309
+ return /* @__PURE__ */ React11.createElement(Box9, { flexDirection: "column" }, /* @__PURE__ */ React11.createElement(Text8, { dimColor: true }, ` ${statusHeader ?? ""}`), hunkHeader !== void 0 ? /* @__PURE__ */ React11.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React11.createElement(Text8, { backgroundColor: "#c4b5fd", color: "black", bold: true }, ` ${hunkHeader.trim()} `)) : null, body.map((line, i) => {
9129
9310
  const key = `${i}-${line.slice(0, 32)}`;
9130
- if (line.startsWith("- ")) {
9131
- return /* @__PURE__ */ React10.createElement(Text8, { key, color: "red" }, line);
9311
+ const stripped = line.replace(/^ {2}/, "");
9312
+ if (stripped.startsWith("- ")) {
9313
+ return /* @__PURE__ */ React11.createElement(Box9, { key }, /* @__PURE__ */ React11.createElement(Text8, { color: "#f87171", bold: true }, "\u2212 "), /* @__PURE__ */ React11.createElement(Text8, { color: "#fca5a5" }, stripped.slice(2)));
9132
9314
  }
9133
- if (line.startsWith("+ ")) {
9134
- return /* @__PURE__ */ React10.createElement(Text8, { key, color: "green" }, line);
9315
+ if (stripped.startsWith("+ ")) {
9316
+ return /* @__PURE__ */ React11.createElement(Box9, { key }, /* @__PURE__ */ React11.createElement(Text8, { color: "#4ade80", bold: true }, "+ "), /* @__PURE__ */ React11.createElement(Text8, { color: "#86efac" }, stripped.slice(2)));
9135
9317
  }
9136
- return /* @__PURE__ */ React10.createElement(Text8, { key, dimColor: true }, line);
9318
+ return /* @__PURE__ */ React11.createElement(Box9, { key }, /* @__PURE__ */ React11.createElement(Text8, { dimColor: true }, " "), /* @__PURE__ */ React11.createElement(Text8, { dimColor: true }, stripped));
9137
9319
  }));
9138
9320
  }
9139
9321
  function BranchBlock({ branch: branch2 }) {
9140
- const per = branch2.uncertainties.map((u, i) => {
9141
- const marker = i === branch2.chosenIndex ? "\u25B8" : " ";
9322
+ return /* @__PURE__ */ React11.createElement(Box9, { flexDirection: "column", marginBottom: 1 }, /* @__PURE__ */ React11.createElement(Box9, null, /* @__PURE__ */ React11.createElement(Text8, { backgroundColor: "#93c5fd", color: "black", bold: true }, ` \u2387 BRANCH \xD7${branch2.budget} `), /* @__PURE__ */ React11.createElement(Text8, null, " "), /* @__PURE__ */ React11.createElement(Text8, { color: "#93c5fd" }, "picked "), /* @__PURE__ */ React11.createElement(Text8, { color: "#93c5fd", bold: true }, "#", branch2.chosenIndex)), /* @__PURE__ */ React11.createElement(Box9, { paddingLeft: 2, marginTop: 1 }, branch2.uncertainties.map((u, i) => {
9323
+ const chosen = i === branch2.chosenIndex;
9142
9324
  const t = (branch2.temperatures[i] ?? 0).toFixed(1);
9143
- return `${marker} #${i} T=${t} u=${u}`;
9144
- }).join(" ");
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)));
9325
+ return (
9326
+ // biome-ignore lint/suspicious/noArrayIndexKey: branch index is positional and stable
9327
+ /* @__PURE__ */ React11.createElement(Text8, { key: `b-${i}` }, /* @__PURE__ */ React11.createElement(Text8, { color: chosen ? "#93c5fd" : "#475569", bold: chosen }, chosen ? "\u25B8 " : " "), /* @__PURE__ */ React11.createElement(Text8, { color: chosen ? "#93c5fd" : "#94a3b8", bold: chosen }, `#${i}`), /* @__PURE__ */ React11.createElement(Text8, { dimColor: true }, ` T=${t} u=${u} `))
9328
+ );
9329
+ })));
9146
9330
  }
9147
9331
  function ReasoningBlock({ reasoning }) {
9148
9332
  const max = 260;
9149
9333
  const flat = reasoning.replace(/\s+/g, " ").trim();
9150
9334
  const preview = flat.length <= max ? flat : `\u2026 (+${flat.length - max} earlier chars) ${flat.slice(-max)}`;
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));
9335
+ return /* @__PURE__ */ React11.createElement(Box9, { marginBottom: 1 }, /* @__PURE__ */ React11.createElement(Text8, { backgroundColor: COLOR.accent, color: "black", bold: true }, " \u22EF thinking "), /* @__PURE__ */ React11.createElement(Text8, null, " "), /* @__PURE__ */ React11.createElement(Text8, { color: COLOR.accent, italic: true, dimColor: true }, preview));
9152
9336
  }
9153
9337
  function Elapsed() {
9154
9338
  const s = useElapsedSeconds();
9155
9339
  const mm = String(Math.floor(s / 60)).padStart(2, "0");
9156
9340
  const ss = String(s % 60).padStart(2, "0");
9157
- return /* @__PURE__ */ React10.createElement(Text8, { dimColor: true }, `${mm}:${ss}`);
9341
+ return /* @__PURE__ */ React11.createElement(Text8, { dimColor: true }, `${mm}:${ss}`);
9158
9342
  }
9159
9343
  function PulsingAssistantGlyph() {
9160
9344
  const tick = useTick();
9161
9345
  const on = Math.floor(tick / 4) % 2 === 0;
9162
- return /* @__PURE__ */ React10.createElement(Text8, { color: "green", bold: true }, on ? ROLE_GLYPH.assistant : ROLE_GLYPH.assistantPulse);
9346
+ return /* @__PURE__ */ React11.createElement(Text8, { color: "green", bold: true }, on ? ROLE_GLYPH.assistant : ROLE_GLYPH.assistantPulse);
9163
9347
  }
9164
9348
  function StreamingAssistant({ event }) {
9165
9349
  if (event.branchProgress) {
9166
9350
  const p = event.branchProgress;
9167
9351
  if (p.completed === 0) {
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"));
9352
+ return /* @__PURE__ */ React11.createElement(Box9, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React11.createElement(Box9, null, /* @__PURE__ */ React11.createElement(PulsingAssistantGlyph, null), /* @__PURE__ */ React11.createElement(Text8, { color: "blue" }, " \u2387 launching ", p.total, " parallel samples (R1 thinking in parallel)\u2026 "), /* @__PURE__ */ React11.createElement(Elapsed, null)), /* @__PURE__ */ React11.createElement(Text8, { color: "yellow" }, " ", "spread across T=0.0/0.5/1.0 \xB7 reasoner typically takes 30-90s \u2014 this is normal"));
9169
9353
  }
9170
9354
  const pct2 = Math.round(p.completed / p.total * 100);
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"));
9355
+ return /* @__PURE__ */ React11.createElement(Box9, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React11.createElement(Box9, null, /* @__PURE__ */ React11.createElement(PulsingAssistantGlyph, null), /* @__PURE__ */ React11.createElement(Text8, { color: "blue" }, " \u2387 branching ", p.completed, "/", p.total, " (", pct2, "%) "), /* @__PURE__ */ React11.createElement(Elapsed, null)), /* @__PURE__ */ React11.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"));
9172
9356
  }
9173
9357
  const tail = lastLine(event.text, 140);
9174
9358
  const reasoningTail = event.reasoning ? lastLine(event.reasoning, 120) : "";
@@ -9176,38 +9360,43 @@ function StreamingAssistant({ event }) {
9176
9360
  const preFirstByte = !event.text && !event.reasoning && !toolCallBuild;
9177
9361
  const reasoningOnly = !event.text && !!event.reasoning && !toolCallBuild;
9178
9362
  const toolCallOnly = !event.text && !event.reasoning && !!toolCallBuild;
9363
+ let pillBg;
9364
+ let pillText;
9179
9365
  let label;
9180
- let labelColor;
9181
9366
  if (preFirstByte) {
9367
+ pillBg = "#fbbf24";
9368
+ pillText = "WAITING";
9182
9369
  label = "request sent \xB7 waiting for server";
9183
- labelColor = "yellow";
9184
9370
  } else if (reasoningOnly) {
9185
- label = `R1 reasoning \xB7 ${event.reasoning?.length ?? 0} chars of thought`;
9186
- labelColor = "cyan";
9371
+ pillBg = "#c4b5fd";
9372
+ pillText = "THINKING";
9373
+ label = `${event.reasoning?.length ?? 0} chars of thought`;
9187
9374
  } else if (toolCallOnly) {
9188
- label = `assembling tool call${formatToolCallIndex(toolCallBuild)} <${toolCallBuild.name}> \xB7 ${toolCallBuild.chars} chars of arguments${formatReadyTail(toolCallBuild)}`;
9189
- labelColor = "magenta";
9375
+ pillBg = "#f0abfc";
9376
+ pillText = "DISPATCH";
9377
+ label = `assembling${formatToolCallIndex(toolCallBuild)} <${toolCallBuild.name}> \xB7 ${toolCallBuild.chars} chars${formatReadyTail(toolCallBuild)}`;
9190
9378
  } else {
9191
- const parts = [`writing response \xB7 ${event.text.length} chars`];
9192
- if (event.reasoning) parts.push(`after ${event.reasoning.length} chars of reasoning`);
9379
+ pillBg = "#86efac";
9380
+ pillText = "WRITING";
9381
+ const parts = [`${event.text.length} chars`];
9382
+ if (event.reasoning) parts.push(`after ${event.reasoning.length} reasoning`);
9193
9383
  if (toolCallBuild) {
9194
9384
  parts.push(
9195
- `building tool call${formatToolCallIndex(toolCallBuild)} <${toolCallBuild.name}> \xB7 ${toolCallBuild.chars} chars${formatReadyTail(toolCallBuild)}`
9385
+ `tool${formatToolCallIndex(toolCallBuild)} <${toolCallBuild.name}> ${toolCallBuild.chars}c${formatReadyTail(toolCallBuild)}`
9196
9386
  );
9197
9387
  }
9198
9388
  label = parts.join(" \xB7 ");
9199
- labelColor = "green";
9200
9389
  }
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 ? (
9202
- // Non-dim yellow: first-time users misread the dim version as
9390
+ return /* @__PURE__ */ React11.createElement(Box9, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React11.createElement(Box9, null, /* @__PURE__ */ React11.createElement(PulsingAssistantGlyph, null), /* @__PURE__ */ React11.createElement(Text8, null, " "), /* @__PURE__ */ React11.createElement(Pulse, null), /* @__PURE__ */ React11.createElement(Text8, null, " "), /* @__PURE__ */ React11.createElement(Text8, { backgroundColor: pillBg, color: "black", bold: true }, ` ${pillText} `), /* @__PURE__ */ React11.createElement(Text8, { dimColor: true }, ` ${label} `), /* @__PURE__ */ React11.createElement(Elapsed, null)), reasoningTail ? /* @__PURE__ */ React11.createElement(Box9, { paddingLeft: 3 }, /* @__PURE__ */ React11.createElement(Text8, { color: "#c4b5fd", italic: true, dimColor: true }, "\u21B3 ", reasoningTail)) : null, tail ? /* @__PURE__ */ React11.createElement(Box9, { paddingLeft: 3 }, /* @__PURE__ */ React11.createElement(Text8, { dimColor: true }, "\u25B8 ", tail)) : preFirstByte ? (
9391
+ // Non-dim amber: first-time users misread the dim version as
9203
9392
  // "app frozen". The reassurance has to be VISIBLE to do its job.
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);
9393
+ /* @__PURE__ */ React11.createElement(Box9, { paddingLeft: 3 }, /* @__PURE__ */ React11.createElement(Text8, { color: "#fbbf24", italic: true }, "waiting for first byte \u2014 typical 5\u201360s depending on model + load"))
9394
+ ) : reasoningOnly ? /* @__PURE__ */ React11.createElement(Box9, { paddingLeft: 3 }, /* @__PURE__ */ React11.createElement(Text8, { color: "#c4b5fd", italic: true }, "R1 thinks before it speaks \u2014 body text arrives when reasoning finishes (20\u201390s)")) : toolCallOnly ? /* @__PURE__ */ React11.createElement(Box9, { paddingLeft: 3 }, /* @__PURE__ */ React11.createElement(Text8, { color: "#f0abfc", italic: true }, "tool-call arguments streaming \u2014 about to dispatch")) : event.reasoning ? /* @__PURE__ */ React11.createElement(Box9, { paddingLeft: 3 }, /* @__PURE__ */ React11.createElement(Text8, { color: "#fbbf24", italic: true }, "R1 still reasoning \u2014 body text or tool call arrives when thinking finishes")) : null);
9206
9395
  }
9207
9396
  function Pulse() {
9208
9397
  const tick = useTick();
9209
9398
  const frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
9210
- return /* @__PURE__ */ React10.createElement(Text8, { color: "cyan" }, frames[Math.floor(tick / 4) % frames.length]);
9399
+ return /* @__PURE__ */ React11.createElement(Text8, { color: "cyan" }, frames[Math.floor(tick / 4) % frames.length]);
9211
9400
  }
9212
9401
  function formatToolCallIndex(tb) {
9213
9402
  if (!tb || tb.index === void 0) return "";
@@ -9226,17 +9415,18 @@ function lastLine(s, maxChars) {
9226
9415
  }
9227
9416
  function StatsLine({ stats: stats2 }) {
9228
9417
  const hit = (stats2.cacheHitRatio * 100).toFixed(1);
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)));
9418
+ const hitColor = stats2.cacheHitRatio >= 0.7 ? "#4ade80" : stats2.cacheHitRatio >= 0.4 ? "#fcd34d" : "#f87171";
9419
+ return /* @__PURE__ */ React11.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React11.createElement(Text8, { color: hitColor, bold: true }, `\u232C ${hit}%`), /* @__PURE__ */ React11.createElement(Text8, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React11.createElement(Text8, { color: "#94a3b8" }, "in ", /* @__PURE__ */ React11.createElement(Text8, { color: "#67e8f9", bold: true }, stats2.usage.promptTokens), " \u2192 out ", /* @__PURE__ */ React11.createElement(Text8, { color: "#c4b5fd", bold: true }, stats2.usage.completionTokens)), /* @__PURE__ */ React11.createElement(Text8, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React11.createElement(Text8, { color: "#86efac", bold: true }, `$${stats2.cost.toFixed(6)}`));
9230
9420
  }
9231
9421
 
9232
9422
  // src/cli/ui/LiveRows.tsx
9233
- import { Box as Box9, Text as Text9 } from "ink";
9234
- import React11 from "react";
9423
+ import { Box as Box10, Text as Text9, useStdout as useStdout4 } from "ink";
9424
+ import React12 from "react";
9235
9425
  var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
9236
9426
  function StatusRow({ text }) {
9237
9427
  const tick = useTick();
9238
9428
  const elapsed = useElapsedSeconds();
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`));
9429
+ return /* @__PURE__ */ React12.createElement(Box10, { marginY: 1, paddingX: 1 }, /* @__PURE__ */ React12.createElement(Text9, { color: "#c4b5fd", bold: true }, SPINNER_FRAMES[tick % SPINNER_FRAMES.length]), /* @__PURE__ */ React12.createElement(Text9, null, " "), /* @__PURE__ */ React12.createElement(Text9, { color: "#c4b5fd" }, text), /* @__PURE__ */ React12.createElement(Text9, { dimColor: true }, ` \xB7 ${elapsed}s`));
9240
9430
  }
9241
9431
  function ModeStatusBar({
9242
9432
  editMode,
@@ -9248,14 +9438,28 @@ function ModeStatusBar({
9248
9438
  }) {
9249
9439
  useTick();
9250
9440
  const running = jobs2?.runningCount() ?? 0;
9251
- const jobsTag = running > 0 ? /* @__PURE__ */ React11.createElement(Text9, { color: "yellow", bold: true }, ` \xB7 \u23F5 ${running} job${running === 1 ? "" : "s"}`) : null;
9441
+ const jobsTag = running > 0 ? /* @__PURE__ */ React12.createElement(Text9, { color: "yellow", bold: true }, ` \xB7 \u23F5 ${running} job${running === 1 ? "" : "s"}`) : null;
9252
9442
  if (planMode) {
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);
9443
+ return /* @__PURE__ */ React12.createElement(ModeBarFrame, null, /* @__PURE__ */ React12.createElement(ModePill, { label: "PLAN MODE", bg: "red", flash }), /* @__PURE__ */ React12.createElement(Text9, { dimColor: true }, " writes gated \xB7 /plan off to leave"), jobsTag);
9254
9444
  }
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);
9445
+ const isAuto = editMode === "auto";
9446
+ const label = isAuto ? "AUTO" : "REVIEW";
9447
+ const bg = isAuto ? "magenta" : "cyan";
9448
+ const mid = isAuto ? "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";
9449
+ return /* @__PURE__ */ React12.createElement(ModeBarFrame, null, /* @__PURE__ */ React12.createElement(ModePill, { label, bg, flash }), /* @__PURE__ */ React12.createElement(Text9, { dimColor: true }, ` ${mid} \xB7 Shift+Tab to flip`), jobsTag);
9450
+ }
9451
+ function ModeBarFrame({ children }) {
9452
+ const { stdout: stdout2 } = useStdout4();
9453
+ const cols = stdout2?.columns ?? 80;
9454
+ const ruleWidth = Math.max(20, cols - 2);
9455
+ return /* @__PURE__ */ React12.createElement(Box10, { flexDirection: "column" }, /* @__PURE__ */ React12.createElement(Box10, { paddingX: 1 }, /* @__PURE__ */ React12.createElement(Text9, { color: "#475569", dimColor: true }, "\u254C".repeat(ruleWidth))), /* @__PURE__ */ React12.createElement(Box10, { paddingX: 1 }, children));
9456
+ }
9457
+ function ModePill({
9458
+ label,
9459
+ bg,
9460
+ flash
9461
+ }) {
9462
+ return /* @__PURE__ */ React12.createElement(Text9, { backgroundColor: bg, color: "white", bold: true, inverse: flash }, ` ${label} `);
9259
9463
  }
9260
9464
  function UndoBanner({
9261
9465
  banner
@@ -9265,14 +9469,15 @@ function UndoBanner({
9265
9469
  const remainingSec = Math.ceil(remainingMs / 1e3);
9266
9470
  const ok = banner.results.filter((r) => r.status === "applied" || r.status === "created").length;
9267
9471
  const total = banner.results.length;
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 }, ")"));
9472
+ const urgent = remainingSec <= 1;
9473
+ return /* @__PURE__ */ React12.createElement(Box10, { marginY: 1, paddingX: 1 }, /* @__PURE__ */ React12.createElement(Text9, { backgroundColor: "#c4b5fd", color: "black", bold: true }, ` \u2713 AUTO-APPLIED ${ok}/${total} `), /* @__PURE__ */ React12.createElement(Text9, { dimColor: true }, " press "), /* @__PURE__ */ React12.createElement(Text9, { backgroundColor: "#67e8f9", color: "black", bold: true }, " u "), /* @__PURE__ */ React12.createElement(Text9, { dimColor: true }, " to undo "), /* @__PURE__ */ React12.createElement(Text9, { color: urgent ? "#f87171" : "#c4b5fd", bold: urgent }, `${remainingSec}s`));
9269
9474
  }
9270
9475
  function SubagentRow({
9271
9476
  activity
9272
9477
  }) {
9273
9478
  const tick = useTick();
9274
9479
  const seconds = (activity.elapsedMs / 1e3).toFixed(1);
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`));
9480
+ return /* @__PURE__ */ React12.createElement(Box10, { paddingLeft: 3 }, /* @__PURE__ */ React12.createElement(Text9, { color: "#c4b5fd", bold: true }, SPINNER_FRAMES[tick % SPINNER_FRAMES.length]), /* @__PURE__ */ React12.createElement(Text9, null, " "), /* @__PURE__ */ React12.createElement(Text9, { backgroundColor: "#c4b5fd", color: "black", bold: true }, " \u232C subagent "), /* @__PURE__ */ React12.createElement(Text9, { color: "#c4b5fd" }, ` ${activity.task}`), /* @__PURE__ */ React12.createElement(Text9, { dimColor: true }, ` iter ${activity.iter} \xB7 ${seconds}s`));
9276
9481
  }
9277
9482
  function OngoingToolRow({
9278
9483
  tool: tool2,
@@ -9281,7 +9486,7 @@ function OngoingToolRow({
9281
9486
  const tick = useTick();
9282
9487
  const elapsed = useElapsedSeconds();
9283
9488
  const summary = summarizeToolArgs(tool2.name, tool2.args);
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);
9489
+ return /* @__PURE__ */ React12.createElement(Box10, { marginY: 1, flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React12.createElement(Box10, null, /* @__PURE__ */ React12.createElement(Text9, { color: "#fcd34d", bold: true }, SPINNER_FRAMES[tick % SPINNER_FRAMES.length]), /* @__PURE__ */ React12.createElement(Text9, null, " "), /* @__PURE__ */ React12.createElement(Text9, { backgroundColor: "#fcd34d", color: "black", bold: true }, ` \u23F5 ${tool2.name} `), /* @__PURE__ */ React12.createElement(Text9, { color: "#fcd34d" }, " running"), /* @__PURE__ */ React12.createElement(Text9, { dimColor: true }, ` \xB7 ${elapsed}s`)), progress ? /* @__PURE__ */ React12.createElement(Box10, { paddingLeft: 3 }, /* @__PURE__ */ React12.createElement(Text9, { color: "#67e8f9" }, renderProgressLine(progress))) : null, summary ? /* @__PURE__ */ React12.createElement(Box10, { paddingLeft: 3 }, /* @__PURE__ */ React12.createElement(Text9, { dimColor: true }, summary)) : null);
9285
9490
  }
9286
9491
  function renderProgressLine(p) {
9287
9492
  const msg = p.message ? ` ${p.message}` : "";
@@ -9337,8 +9542,8 @@ function summarizeToolArgs(name, args) {
9337
9542
  }
9338
9543
 
9339
9544
  // src/cli/ui/PlanCheckpointConfirm.tsx
9340
- import { Box as Box10, Text as Text10 } from "ink";
9341
- import React12 from "react";
9545
+ import { Box as Box11 } from "ink";
9546
+ import React13 from "react";
9342
9547
  function PlanCheckpointConfirmInner({
9343
9548
  stepId,
9344
9549
  title,
@@ -9349,10 +9554,11 @@ function PlanCheckpointConfirmInner({
9349
9554
  onChoose
9350
9555
  }) {
9351
9556
  const label = title ? `${stepId} \xB7 ${title}` : stepId;
9352
- const counter = total > 0 ? ` (${completed}/${total})` : "";
9557
+ const counter = total > 0 ? `${completed}/${total}` : "";
9353
9558
  const isLast = total > 0 && completed >= total;
9354
9559
  const statuses = buildStatusMap(steps, completedStepIds, stepId, isLast);
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(
9560
+ const subtitle = counter ? `${counter} \xB7 ${label}` : label;
9561
+ return /* @__PURE__ */ React13.createElement(ModalCard, { accent: "#86efac", icon: "\u2713", title: "checkpoint \u2014 step done", subtitle }, steps && steps.length > 0 ? /* @__PURE__ */ React13.createElement(Box11, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React13.createElement(PlanStepList, { steps, statuses, focusStepId: stepId })) : null, /* @__PURE__ */ React13.createElement(
9356
9562
  SingleSelect,
9357
9563
  {
9358
9564
  initialValue: isLast ? "stop" : "continue",
@@ -9377,9 +9583,9 @@ function PlanCheckpointConfirmInner({
9377
9583
  onCancel: () => onChoose("stop"),
9378
9584
  footer: "[\u2191\u2193] navigate \xB7 [Enter] select \xB7 [Esc] stop"
9379
9585
  }
9380
- )));
9586
+ ));
9381
9587
  }
9382
- var PlanCheckpointConfirm = React12.memo(PlanCheckpointConfirmInner);
9588
+ var PlanCheckpointConfirm = React13.memo(PlanCheckpointConfirmInner);
9383
9589
  function buildStatusMap(steps, completedStepIds, currentStepId, isLast) {
9384
9590
  const map = /* @__PURE__ */ new Map();
9385
9591
  if (!steps) return map;
@@ -9396,42 +9602,53 @@ function buildStatusMap(steps, completedStepIds, currentStepId, isLast) {
9396
9602
  }
9397
9603
 
9398
9604
  // src/cli/ui/PlanConfirm.tsx
9399
- import { Box as Box11, Text as Text11 } from "ink";
9400
- import React13 from "react";
9605
+ import { Box as Box12, Text as Text10 } from "ink";
9606
+ import React14 from "react";
9401
9607
  function PlanConfirmInner({ plan: plan2, steps, summary, onChoose }) {
9402
9608
  const hasOpenQuestions = /^#{1,6}\s*(open[-\s]?questions?|risks?|unknowns?|assumptions?|unclear)/im.test(plan2) || /^#{1,6}\s*(待确认|开放问题|风险|未知|假设|不确定)/im.test(plan2);
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(
9404
- SingleSelect,
9609
+ return /* @__PURE__ */ React14.createElement(
9610
+ ModalCard,
9405
9611
  {
9406
- initialValue: hasOpenQuestions ? "refine" : "approve",
9407
- items: [
9408
- {
9409
- value: "approve",
9410
- label: "Approve and implement",
9411
- hint: "Exit plan mode. The model starts executing. You'll get a text input to add any last instructions (or just press Enter to skip)."
9412
- },
9413
- {
9414
- value: "refine",
9415
- label: "Refine / answer questions",
9416
- hint: "Stay in plan mode. Write answers, modifications, or critiques; the model revises and re-submits."
9417
- },
9418
- {
9419
- value: "cancel",
9420
- label: "Cancel",
9421
- hint: "Exit plan mode. Drop the plan; the model won't implement it."
9422
- }
9423
- ],
9424
- onSubmit: (v) => onChoose(v),
9425
- onCancel: () => onChoose("cancel"),
9426
- footer: "[\u2191\u2193] navigate \xB7 [Enter] select \xB7 [Esc] cancel"
9427
- }
9428
- )));
9612
+ accent: "#67e8f9",
9613
+ icon: "\u{1F4CB}",
9614
+ title: "plan proposed",
9615
+ subtitle: summary ?? "approve / refine / cancel"
9616
+ },
9617
+ hasOpenQuestions ? /* @__PURE__ */ React14.createElement(Box12, { marginBottom: 1 }, /* @__PURE__ */ React14.createElement(Text10, { color: "#fbbf24" }, "\u25B2 the plan flags open questions or risks \u2014 pick", " ", /* @__PURE__ */ React14.createElement(Text10, { bold: true }, "Refine / answer questions"), " to write concrete answers before the model moves on.")) : null,
9618
+ steps && steps.length > 0 ? /* @__PURE__ */ React14.createElement(Box12, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React14.createElement(PlanStepList, { steps })) : null,
9619
+ /* @__PURE__ */ React14.createElement(
9620
+ SingleSelect,
9621
+ {
9622
+ initialValue: hasOpenQuestions ? "refine" : "approve",
9623
+ items: [
9624
+ {
9625
+ value: "approve",
9626
+ label: "Approve and implement",
9627
+ hint: "Exit plan mode. The model starts executing. You'll get a text input to add any last instructions (or just press Enter to skip)."
9628
+ },
9629
+ {
9630
+ value: "refine",
9631
+ label: "Refine / answer questions",
9632
+ hint: "Stay in plan mode. Write answers, modifications, or critiques; the model revises and re-submits."
9633
+ },
9634
+ {
9635
+ value: "cancel",
9636
+ label: "Cancel",
9637
+ hint: "Exit plan mode. Drop the plan; the model won't implement it."
9638
+ }
9639
+ ],
9640
+ onSubmit: (v) => onChoose(v),
9641
+ onCancel: () => onChoose("cancel"),
9642
+ footer: "[\u2191\u2193] navigate \xB7 [Enter] select \xB7 [Esc] cancel"
9643
+ }
9644
+ )
9645
+ );
9429
9646
  }
9430
- var PlanConfirm = React13.memo(PlanConfirmInner);
9647
+ var PlanConfirm = React14.memo(PlanConfirmInner);
9431
9648
 
9432
9649
  // src/cli/ui/PlanRefineInput.tsx
9433
- import { Box as Box12, Text as Text12 } from "ink";
9434
- import React14, { useState as useState4 } from "react";
9650
+ import { Box as Box13, Text as Text11 } from "ink";
9651
+ import React15, { useState as useState4 } from "react";
9435
9652
  function PlanRefineInput({ mode: mode2, onSubmit, onCancel }) {
9436
9653
  const [value, setValue] = useState4("");
9437
9654
  useKeystroke((ev) => {
@@ -9455,15 +9672,33 @@ function PlanRefineInput({ mode: mode2, onSubmit, onCancel }) {
9455
9672
  setValue((v) => v + ev.input);
9456
9673
  }
9457
9674
  });
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?";
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.";
9675
+ const tick = useTick();
9676
+ const cursorOn = Math.floor(tick / 4) % 2 === 0;
9677
+ const meta = mode2 === "approve" ? {
9678
+ title: "approving \u2014 any last instructions?",
9679
+ icon: "\u{1F4CB}",
9680
+ accent: "#67e8f9"
9681
+ } : mode2 === "checkpoint-revise" ? {
9682
+ title: "revising \u2014 what should change before the next step?",
9683
+ icon: "\u270F",
9684
+ accent: "#fbbf24"
9685
+ } : mode2 === "choice-custom" ? {
9686
+ title: "custom answer \u2014 type whatever fits",
9687
+ icon: "\u{1F500}",
9688
+ accent: "#f0abfc"
9689
+ } : {
9690
+ title: "refining \u2014 what should the model change?",
9691
+ icon: "\u270F",
9692
+ accent: "#fbbf24"
9693
+ };
9694
+ 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 adjusts the remaining plan." : 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.";
9460
9695
  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.)";
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"))));
9696
+ return /* @__PURE__ */ React15.createElement(ModalCard, { accent: meta.accent, icon: meta.icon, title: meta.title }, /* @__PURE__ */ React15.createElement(Box13, { marginBottom: 1 }, /* @__PURE__ */ React15.createElement(Text11, { dimColor: true }, hint, " Enter to send \xB7 Esc to return to the picker.", value === "" ? blankHint : "")), /* @__PURE__ */ React15.createElement(Box13, null, /* @__PURE__ */ React15.createElement(Text11, { color: meta.accent, bold: true }, "\u203A "), /* @__PURE__ */ React15.createElement(Text11, null, value), /* @__PURE__ */ React15.createElement(Text11, { color: meta.accent, bold: true }, cursorOn ? "\u258D" : " ")));
9462
9697
  }
9463
9698
 
9464
9699
  // src/cli/ui/PlanReviseConfirm.tsx
9465
- import { Box as Box13, Text as Text13 } from "ink";
9466
- import React15 from "react";
9700
+ import { Box as Box14, Text as Text12 } from "ink";
9701
+ import React16 from "react";
9467
9702
  function computeDiff(oldSteps, newSteps) {
9468
9703
  const oldIds = new Set(oldSteps.map((s) => s.id));
9469
9704
  const newIds = new Set(newSteps.map((s) => s.id));
@@ -9479,13 +9714,13 @@ function computeDiff(oldSteps, newSteps) {
9479
9714
  function riskDots2(risk) {
9480
9715
  switch (risk) {
9481
9716
  case "high":
9482
- return { dots: "\u25CF\u25CF\u25CF", color: "red" };
9717
+ return { dots: "\u25CF\u25CF\u25CF", color: "#f87171" };
9483
9718
  case "med":
9484
- return { dots: "\u25CF\u25CF ", color: "yellow" };
9719
+ return { dots: "\u25CF\u25CF ", color: "#fbbf24" };
9485
9720
  case "low":
9486
- return { dots: "\u25CF ", color: "green" };
9721
+ return { dots: "\u25CF ", color: "#4ade80" };
9487
9722
  default:
9488
- return { dots: " ", color: "gray" };
9723
+ return { dots: " ", color: "#94a3b8" };
9489
9724
  }
9490
9725
  }
9491
9726
  function PlanReviseConfirmInner({
@@ -9499,40 +9734,52 @@ function PlanReviseConfirmInner({
9499
9734
  const removedCount = rows.filter((r) => r.kind === "removed").length;
9500
9735
  const addedCount = rows.filter((r) => r.kind === "added").length;
9501
9736
  const keptCount = rows.filter((r) => r.kind === "kept").length;
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) => {
9503
- const risk = riskDots2(row2.step.risk);
9504
- const prefix = row2.kind === "removed" ? "\u2212" : row2.kind === "added" ? "+" : " ";
9505
- const prefixColor = row2.kind === "removed" ? "red" : row2.kind === "added" ? "green" : "gray";
9506
- const dim = row2.kind === "kept";
9507
- const strike = row2.kind === "removed";
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(
9510
- SingleSelect,
9737
+ return /* @__PURE__ */ React16.createElement(
9738
+ ModalCard,
9511
9739
  {
9512
- initialValue: "accept",
9513
- items: [
9514
- {
9515
- value: "accept",
9516
- label: "Accept revision \u2014 apply the new step list",
9517
- hint: "Replaces the remaining plan with the proposed steps. Done steps are untouched."
9518
- },
9519
- {
9520
- value: "reject",
9521
- label: "Reject \u2014 keep the original plan",
9522
- hint: "Drops the proposal. Model continues with the original remaining steps."
9523
- }
9524
- ],
9525
- onSubmit: (v) => onChoose(v),
9526
- onCancel: () => onChoose("reject"),
9527
- footer: "[\u2191\u2193] navigate \xB7 [Enter] select \xB7 [Esc] reject"
9528
- }
9529
- )));
9740
+ accent: "#fbbf24",
9741
+ icon: "\u270F",
9742
+ title: "plan revision proposed",
9743
+ subtitle: `\u2212${removedCount} +${addedCount} \xB7 ${keptCount} kept`
9744
+ },
9745
+ /* @__PURE__ */ React16.createElement(Box14, { marginBottom: 1 }, /* @__PURE__ */ React16.createElement(Text12, null, reason)),
9746
+ summary ? /* @__PURE__ */ React16.createElement(Box14, { marginBottom: 1 }, /* @__PURE__ */ React16.createElement(Text12, { dimColor: true }, `updated summary: ${summary}`)) : null,
9747
+ /* @__PURE__ */ React16.createElement(Box14, { marginBottom: 1, flexDirection: "column" }, rows.map((row2) => {
9748
+ const risk = riskDots2(row2.step.risk);
9749
+ const prefix = row2.kind === "removed" ? "\u2212" : row2.kind === "added" ? "+" : " ";
9750
+ const prefixColor = row2.kind === "removed" ? "#f87171" : row2.kind === "added" ? "#4ade80" : "#94a3b8";
9751
+ const dim = row2.kind === "kept";
9752
+ const strike = row2.kind === "removed";
9753
+ return /* @__PURE__ */ React16.createElement(Box14, { key: `${row2.kind}-${row2.step.id}` }, /* @__PURE__ */ React16.createElement(Text12, { color: prefixColor, bold: true }, `${prefix} `), /* @__PURE__ */ React16.createElement(Text12, { color: risk.color, bold: true, dimColor: dim }, risk.dots), /* @__PURE__ */ React16.createElement(Text12, { dimColor: dim, strikethrough: strike }, ` ${row2.step.id} \xB7 ${row2.step.title}`));
9754
+ })),
9755
+ /* @__PURE__ */ React16.createElement(
9756
+ SingleSelect,
9757
+ {
9758
+ initialValue: "accept",
9759
+ items: [
9760
+ {
9761
+ value: "accept",
9762
+ label: "Accept revision \u2014 apply the new step list",
9763
+ hint: "Replaces the remaining plan with the proposed steps. Done steps are untouched."
9764
+ },
9765
+ {
9766
+ value: "reject",
9767
+ label: "Reject \u2014 keep the original plan",
9768
+ hint: "Drops the proposal. Model continues with the original remaining steps."
9769
+ }
9770
+ ],
9771
+ onSubmit: (v) => onChoose(v),
9772
+ onCancel: () => onChoose("reject"),
9773
+ footer: "[\u2191\u2193] navigate \xB7 [Enter] select \xB7 [Esc] reject"
9774
+ }
9775
+ )
9776
+ );
9530
9777
  }
9531
- var PlanReviseConfirm = React15.memo(PlanReviseConfirmInner);
9778
+ var PlanReviseConfirm = React16.memo(PlanReviseConfirmInner);
9532
9779
 
9533
9780
  // src/cli/ui/PromptInput.tsx
9534
- import { Box as Box14, Text as Text14, useStdout as useStdout3 } from "ink";
9535
- import React16, { useRef as useRef2, useState as useState5 } from "react";
9781
+ import { Box as Box15, Text as Text13, useStdout as useStdout5 } from "ink";
9782
+ import React17, { useRef as useRef2, useState as useState5 } from "react";
9536
9783
 
9537
9784
  // src/cli/ui/key-normalize.ts
9538
9785
  var CSI_TAIL_TO_FLAGS = [
@@ -10003,7 +10250,7 @@ function PromptInput({
10003
10250
  if (action.historyHandoff === "prev") onHistoryPrev?.();
10004
10251
  if (action.historyHandoff === "next") onHistoryNext?.();
10005
10252
  }, !disabled);
10006
- const { stdout: stdout2 } = useStdout3();
10253
+ const { stdout: stdout2 } = useStdout5();
10007
10254
  const cols = stdout2?.columns ?? 80;
10008
10255
  const narrow = cols <= 90;
10009
10256
  const promptBody = narrow ? "\u203A " : "you \u203A ";
@@ -10015,14 +10262,19 @@ function PromptInput({
10015
10262
  const effectivePlaceholder = disabled ? placeholder ?? "\u2026waiting for response\u2026" : placeholder ?? placeholderActive;
10016
10263
  const lines = value.length > 0 ? value.split("\n") : [""];
10017
10264
  const accentColor = disabled ? "gray" : "cyan";
10265
+ const animate = !disabled && cols >= 100;
10266
+ const tick = useTick();
10267
+ const barOffset = animate ? Math.floor(tick / 6) : 0;
10268
+ const barColorAt = (rowIdx) => disabled ? "gray" : GRADIENT[((rowIdx + barOffset) % GRADIENT.length + GRADIENT.length) % GRADIENT.length];
10269
+ const cursorVisible = animate ? Math.floor(tick / 4) % 2 === 0 : true;
10018
10270
  const { line: cursorLine, col: cursorCol } = lineAndColumn(value, cursor);
10019
10271
  const renderItems = collapseLinesForDisplay(lines, cursorLine);
10020
10272
  const showHugeBufferHints = lines.length > 20;
10021
- return /* @__PURE__ */ React16.createElement(Box14, { flexDirection: "column", paddingX: 1 }, renderItems.map((item, renderIdx) => {
10273
+ return /* @__PURE__ */ React17.createElement(Box15, { flexDirection: "column", paddingX: 1 }, renderItems.map((item, renderIdx) => {
10022
10274
  if (item.kind === "skip") {
10023
10275
  return (
10024
10276
  // 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]`))
10277
+ /* @__PURE__ */ React17.createElement(Box15, { key: `skip-${renderIdx}` }, /* @__PURE__ */ React17.createElement(Text13, { color: barColorAt(renderIdx) }, BAR), /* @__PURE__ */ React17.createElement(Text13, { dimColor: true }, continuationIndent.slice(BAR.length)), /* @__PURE__ */ React17.createElement(Text13, { dimColor: true }, `[\u2026 ${item.linesHidden} line${item.linesHidden === 1 ? "" : "s"} hidden \u2014 full content kept, submitted on Enter \u2026]`))
10026
10278
  );
10027
10279
  }
10028
10280
  const i = item.originalIndex;
@@ -10030,7 +10282,7 @@ function PromptInput({
10030
10282
  const isFirst = i === 0;
10031
10283
  const isCursorLine = i === cursorLine;
10032
10284
  const showPlaceholder = isFirst && value.length === 0;
10033
- return /* @__PURE__ */ React16.createElement(
10285
+ return /* @__PURE__ */ React17.createElement(
10034
10286
  PromptLine,
10035
10287
  {
10036
10288
  key: `ln-${i}`,
@@ -10038,29 +10290,33 @@ function PromptInput({
10038
10290
  isFirst,
10039
10291
  isCursorLine: isCursorLine && !disabled,
10040
10292
  cursorCol: isCursorLine ? cursorCol : null,
10293
+ cursorVisible,
10041
10294
  showPlaceholder,
10042
10295
  placeholderText: effectivePlaceholder,
10043
10296
  promptPrefix,
10044
10297
  continuationIndent,
10045
10298
  visibleCells,
10046
10299
  accentColor,
10300
+ barColor: barColorAt(i),
10047
10301
  pastes: pastesRef.current,
10048
10302
  disabled: disabled === true
10049
10303
  }
10050
10304
  );
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);
10305
+ }), showHugeBufferHints && !disabled ? /* @__PURE__ */ React17.createElement(Box15, null, /* @__PURE__ */ React17.createElement(Text13, { color: barColorAt(0) }, BAR), /* @__PURE__ */ React17.createElement(Text13, { dimColor: true }, continuationIndent.slice(BAR.length)), /* @__PURE__ */ React17.createElement(Text13, { 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__ */ React17.createElement(Box15, null, /* @__PURE__ */ React17.createElement(Text13, { color: barColorAt(0) }, BAR), /* @__PURE__ */ React17.createElement(Text13, { dimColor: true }, continuationIndent.slice(BAR.length)), /* @__PURE__ */ React17.createElement(Text13, { dimColor: true }, "[Ctrl+J] newline \xB7 [Enter] submit \xB7 ends with \\ for line continuation")) : null, disabled ? /* @__PURE__ */ React17.createElement(Box15, null, /* @__PURE__ */ React17.createElement(Text13, { color: barColorAt(0) }, BAR), /* @__PURE__ */ React17.createElement(Text13, { dimColor: true }, continuationIndent.slice(BAR.length)), /* @__PURE__ */ React17.createElement(Text13, { dimColor: true }, "[Esc] to stop")) : null);
10052
10306
  }
10053
10307
  function PromptLine({
10054
10308
  line,
10055
10309
  isFirst,
10056
10310
  isCursorLine,
10057
10311
  cursorCol,
10312
+ cursorVisible,
10058
10313
  showPlaceholder,
10059
10314
  placeholderText,
10060
10315
  promptPrefix,
10061
10316
  continuationIndent,
10062
10317
  visibleCells,
10063
10318
  accentColor,
10319
+ barColor,
10064
10320
  pastes,
10065
10321
  disabled
10066
10322
  }) {
@@ -10068,25 +10324,27 @@ function PromptLine({
10068
10324
  const bodyPrefix = promptPrefix.slice(BAR.length);
10069
10325
  const bodyContinuation = continuationIndent.slice(BAR.length);
10070
10326
  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));
10327
+ return /* @__PURE__ */ React17.createElement(Box15, null, /* @__PURE__ */ React17.createElement(Text13, { color: barColor }, barText), /* @__PURE__ */ React17.createElement(Text13, { bold: true, color: accentColor }, bodyPrefix), !disabled ? /* @__PURE__ */ React17.createElement(Text13, { color: accentColor }, cursorVisible ? "\u258C" : " ") : null, /* @__PURE__ */ React17.createElement(Text13, { dimColor: true }, placeholderText));
10072
10328
  }
10073
10329
  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(
10330
+ return /* @__PURE__ */ React17.createElement(Box15, null, /* @__PURE__ */ React17.createElement(Text13, { color: barColor }, barText), isFirst ? /* @__PURE__ */ React17.createElement(Text13, { bold: true, color: accentColor }, bodyPrefix) : /* @__PURE__ */ React17.createElement(Text13, { dimColor: true }, bodyContinuation), viewport.hiddenLeft ? /* @__PURE__ */ React17.createElement(Text13, { color: "gray", dimColor: true }, "\u2039") : null, /* @__PURE__ */ React17.createElement(
10075
10331
  ViewportContent,
10076
10332
  {
10077
10333
  segments: viewport.segments,
10078
10334
  cursorCell: isCursorLine ? viewport.cursorCell : null,
10079
- accentColor
10335
+ accentColor,
10336
+ cursorVisible
10080
10337
  }
10081
- ), viewport.hiddenRight ? /* @__PURE__ */ React16.createElement(Text14, { color: "gray", dimColor: true }, "\u203A") : null);
10338
+ ), viewport.hiddenRight ? /* @__PURE__ */ React17.createElement(Text13, { color: "gray", dimColor: true }, "\u203A") : null);
10082
10339
  }
10083
10340
  function ViewportContent({
10084
10341
  segments,
10085
10342
  cursorCell,
10086
- accentColor
10343
+ accentColor,
10344
+ cursorVisible
10087
10345
  }) {
10088
10346
  if (cursorCell === null) {
10089
- return /* @__PURE__ */ React16.createElement(React16.Fragment, null, segments.map((seg, i) => renderSegment(seg, i, false)));
10347
+ return /* @__PURE__ */ React17.createElement(React17.Fragment, null, segments.map((seg, i) => renderSegment(seg, i, false)));
10090
10348
  }
10091
10349
  const out = [];
10092
10350
  let cells = 0;
@@ -10105,7 +10363,7 @@ function ViewportContent({
10105
10363
  }
10106
10364
  if (seg.kind === "paste") {
10107
10365
  out.push(
10108
- /* @__PURE__ */ React16.createElement(Text14, { key: `p-${i}-cursor`, color: "magenta", bold: true, inverse: true }, seg.label)
10366
+ /* @__PURE__ */ React17.createElement(Text13, { key: `p-${i}-cursor`, color: "magenta", bold: true, inverse: cursorVisible }, seg.label)
10109
10367
  );
10110
10368
  placed = true;
10111
10369
  cells += segCells;
@@ -10114,29 +10372,29 @@ function ViewportContent({
10114
10372
  const offsetIntoSeg = cursorCell - cells;
10115
10373
  const split = splitTextByCells(seg.text, offsetIntoSeg);
10116
10374
  if (split.before.length > 0) {
10117
- out.push(/* @__PURE__ */ React16.createElement(Text14, { key: `t-${i}-b` }, split.before));
10375
+ out.push(/* @__PURE__ */ React17.createElement(Text13, { key: `t-${i}-b` }, split.before));
10118
10376
  }
10119
10377
  if (split.atCursor.length > 0) {
10120
10378
  out.push(
10121
- /* @__PURE__ */ React16.createElement(Text14, { key: `t-${i}-c`, inverse: true, color: accentColor }, split.atCursor)
10379
+ /* @__PURE__ */ React17.createElement(Text13, { key: `t-${i}-c`, inverse: cursorVisible, color: accentColor }, split.atCursor)
10122
10380
  );
10123
10381
  } else {
10124
10382
  out.push(
10125
- /* @__PURE__ */ React16.createElement(Text14, { key: `t-${i}-c-eol`, color: accentColor }, "\u258C")
10383
+ /* @__PURE__ */ React17.createElement(Text13, { key: `t-${i}-c-eol`, color: accentColor }, cursorVisible ? "\u258C" : " ")
10126
10384
  );
10127
10385
  }
10128
10386
  if (split.after.length > 0) {
10129
- out.push(/* @__PURE__ */ React16.createElement(Text14, { key: `t-${i}-a` }, split.after));
10387
+ out.push(/* @__PURE__ */ React17.createElement(Text13, { key: `t-${i}-a` }, split.after));
10130
10388
  }
10131
10389
  placed = true;
10132
10390
  cells += segCells;
10133
10391
  }
10134
10392
  if (!placed) {
10135
10393
  out.push(
10136
- /* @__PURE__ */ React16.createElement(Text14, { key: "cursor-eol", color: accentColor }, "\u258C")
10394
+ /* @__PURE__ */ React17.createElement(Text13, { key: "cursor-eol", color: accentColor }, cursorVisible ? "\u258C" : " ")
10137
10395
  );
10138
10396
  }
10139
- return /* @__PURE__ */ React16.createElement(React16.Fragment, null, out);
10397
+ return /* @__PURE__ */ React17.createElement(React17.Fragment, null, out);
10140
10398
  }
10141
10399
  function segmentCells(seg) {
10142
10400
  if (seg.kind === "paste") return seg.label.length;
@@ -10176,9 +10434,9 @@ function charCellsForText(ch) {
10176
10434
  }
10177
10435
  function renderSegment(seg, key, _inverse) {
10178
10436
  if (seg.kind === "text") {
10179
- return /* @__PURE__ */ React16.createElement(Text14, { key: `s-${key}` }, seg.text);
10437
+ return /* @__PURE__ */ React17.createElement(Text13, { key: `s-${key}` }, seg.text);
10180
10438
  }
10181
- return /* @__PURE__ */ React16.createElement(Text14, { key: `s-${key}`, color: "magenta", bold: true }, seg.label);
10439
+ return /* @__PURE__ */ React17.createElement(Text13, { key: `s-${key}`, backgroundColor: "#f0abfc", color: "black", bold: true }, seg.label);
10182
10440
  }
10183
10441
  var COLLAPSE_THRESHOLD = 20;
10184
10442
  var COLLAPSE_HEAD_LINES = 3;
@@ -10205,36 +10463,47 @@ function collapseLinesForDisplay(lines, cursorLine) {
10205
10463
  }
10206
10464
 
10207
10465
  // src/cli/ui/ShellConfirm.tsx
10208
- import { Box as Box15, Text as Text15 } from "ink";
10209
- import React17 from "react";
10466
+ import { Box as Box16, Text as Text14 } from "ink";
10467
+ import React18 from "react";
10210
10468
  function ShellConfirm({ command, allowPrefix, kind, onChoose }) {
10211
10469
  const isBackground = kind === "run_background";
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(
10213
- SingleSelect,
10470
+ const subtitle = isBackground ? "long-running process \u2014 keeps running after approval, /kill to stop" : "model wants to run a shell command";
10471
+ return /* @__PURE__ */ React18.createElement(
10472
+ ModalCard,
10214
10473
  {
10215
- initialValue: "run_once",
10216
- items: [
10217
- {
10218
- value: "run_once",
10219
- label: "Run once",
10220
- hint: "Execute this command, don't remember it."
10221
- },
10222
- {
10223
- value: "always_allow",
10224
- label: `Always allow "${allowPrefix}" in this project`,
10225
- hint: "Save the prefix to ~/.reasonix/config.json; future matches auto-run."
10226
- },
10227
- {
10228
- value: "deny",
10229
- label: "Deny",
10230
- hint: "Tell the model the user refused; it will continue without this command."
10231
- }
10232
- ],
10233
- onSubmit: (v) => onChoose(v),
10234
- onCancel: () => onChoose("deny"),
10235
- footer: "[\u2191\u2193] navigate \xB7 [Enter] select \xB7 [Esc] deny"
10236
- }
10237
- )));
10474
+ accent: "#f87171",
10475
+ icon: isBackground ? "\u23F1" : "\u26A1",
10476
+ title: isBackground ? "background process" : "shell command",
10477
+ subtitle
10478
+ },
10479
+ /* @__PURE__ */ React18.createElement(Box16, { marginBottom: 1 }, /* @__PURE__ */ React18.createElement(Text14, { dimColor: true }, "$ "), /* @__PURE__ */ React18.createElement(Text14, { color: "#67e8f9", bold: true }, command)),
10480
+ /* @__PURE__ */ React18.createElement(
10481
+ SingleSelect,
10482
+ {
10483
+ initialValue: "run_once",
10484
+ items: [
10485
+ {
10486
+ value: "run_once",
10487
+ label: "Run once",
10488
+ hint: "Execute this command, don't remember it."
10489
+ },
10490
+ {
10491
+ value: "always_allow",
10492
+ label: `Always allow "${allowPrefix}" in this project`,
10493
+ hint: "Save the prefix to ~/.reasonix/config.json; future matches auto-run."
10494
+ },
10495
+ {
10496
+ value: "deny",
10497
+ label: "Deny",
10498
+ hint: "Tell the model the user refused; it will continue without this command."
10499
+ }
10500
+ ],
10501
+ onSubmit: (v) => onChoose(v),
10502
+ onCancel: () => onChoose("deny"),
10503
+ footer: "[\u2191\u2193] navigate \xB7 [Enter] select \xB7 [Esc] deny"
10504
+ }
10505
+ )
10506
+ );
10238
10507
  }
10239
10508
  function derivePrefix(command) {
10240
10509
  const tokens = command.trim().split(/\s+/).filter(Boolean);
@@ -10266,8 +10535,8 @@ function derivePrefix(command) {
10266
10535
  }
10267
10536
 
10268
10537
  // src/cli/ui/SlashArgPicker.tsx
10269
- import { Box as Box16, Text as Text16 } from "ink";
10270
- import React18 from "react";
10538
+ import { Box as Box17, Text as Text15 } from "ink";
10539
+ import React19 from "react";
10271
10540
  function SlashArgPicker({
10272
10541
  matches,
10273
10542
  selectedIndex,
@@ -10276,11 +10545,11 @@ function SlashArgPicker({
10276
10545
  partial
10277
10546
  }) {
10278
10547
  if (kind === "hint") {
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));
10548
+ return /* @__PURE__ */ React19.createElement(Box17, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React19.createElement(Text15, { dimColor: true }, " ", /* @__PURE__ */ React19.createElement(Text15, { bold: true }, "/", spec.cmd), spec.argsHint ? ` ${spec.argsHint}` : "", " \u2014 ", spec.summary));
10280
10549
  }
10281
10550
  if (matches === null) return null;
10282
10551
  if (matches.length === 0) {
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'));
10552
+ return /* @__PURE__ */ React19.createElement(Box17, { flexDirection: "column", paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React19.createElement(Text15, { dimColor: true }, " ", /* @__PURE__ */ React19.createElement(Text15, { bold: true }, "/", spec.cmd), spec.argsHint ? ` ${spec.argsHint}` : "", " \u2014 ", spec.summary), /* @__PURE__ */ React19.createElement(Text15, { color: "yellow" }, ' no match for "', partial, '" \u2014 keep typing, or Backspace to edit'));
10284
10553
  }
10285
10554
  const MAX = 8;
10286
10555
  const total = matches.length;
@@ -10288,26 +10557,26 @@ function SlashArgPicker({
10288
10557
  const shown = matches.slice(windowStart, windowStart + MAX);
10289
10558
  const hiddenAbove = windowStart;
10290
10559
  const hiddenBelow = total - windowStart - shown.length;
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"));
10560
+ return /* @__PURE__ */ React19.createElement(Box17, { flexDirection: "column", paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React19.createElement(Text15, { dimColor: true }, " ", /* @__PURE__ */ React19.createElement(Text15, { bold: true }, "/", spec.cmd), spec.argsHint ? ` ${spec.argsHint}` : "", " \u2014 ", spec.summary), hiddenAbove > 0 ? /* @__PURE__ */ React19.createElement(Text15, { dimColor: true }, " \u2191 ", hiddenAbove, " more above") : null, shown.map((value, i) => /* @__PURE__ */ React19.createElement(ArgRow, { key: value, value, isSelected: windowStart + i === selectedIndex })), hiddenBelow > 0 ? /* @__PURE__ */ React19.createElement(Text15, { dimColor: true }, " \u2193 ", hiddenBelow, " more below") : null, /* @__PURE__ */ React19.createElement(Text15, { dimColor: true }, " [\u2191\u2193] navigate \xB7 [Tab]/[Enter] pick"));
10292
10561
  }
10293
10562
  function ArgRow({ value, isSelected }) {
10294
10563
  const marker = isSelected ? "\u25B8" : " ";
10295
10564
  if (isSelected) {
10296
- return /* @__PURE__ */ React18.createElement(Box16, null, /* @__PURE__ */ React18.createElement(Text16, { bold: true, color: "cyan" }, marker, " ", value));
10565
+ return /* @__PURE__ */ React19.createElement(Box17, null, /* @__PURE__ */ React19.createElement(Text15, { bold: true, color: "cyan" }, marker, " ", value));
10297
10566
  }
10298
- return /* @__PURE__ */ React18.createElement(Box16, null, /* @__PURE__ */ React18.createElement(Text16, { dimColor: true }, marker, " ", value));
10567
+ return /* @__PURE__ */ React19.createElement(Box17, null, /* @__PURE__ */ React19.createElement(Text15, { dimColor: true }, marker, " ", value));
10299
10568
  }
10300
10569
 
10301
10570
  // src/cli/ui/SlashSuggestions.tsx
10302
- import { Box as Box17, Text as Text17 } from "ink";
10303
- import React19 from "react";
10571
+ import { Box as Box18, Text as Text16 } from "ink";
10572
+ import React20 from "react";
10304
10573
  function SlashSuggestions({
10305
10574
  matches,
10306
10575
  selectedIndex
10307
10576
  }) {
10308
10577
  if (matches === null) return null;
10309
10578
  if (matches.length === 0) {
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"));
10579
+ return /* @__PURE__ */ React20.createElement(Box18, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React20.createElement(Text16, { color: "yellow" }, "no slash command matches that prefix"), /* @__PURE__ */ React20.createElement(Text16, { dimColor: true }, " \u2014 Backspace to edit, or /help for the full list"));
10311
10580
  }
10312
10581
  const MAX = 8;
10313
10582
  const total = matches.length;
@@ -10315,47 +10584,29 @@ function SlashSuggestions({
10315
10584
  const shown = matches.slice(windowStart, windowStart + MAX);
10316
10585
  const hiddenAbove = windowStart;
10317
10586
  const hiddenBelow = total - windowStart - shown.length;
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"));
10587
+ return /* @__PURE__ */ React20.createElement(Box18, { flexDirection: "column", paddingX: 1, marginTop: 1 }, hiddenAbove > 0 ? /* @__PURE__ */ React20.createElement(Text16, { dimColor: true }, " \u2191 ", hiddenAbove, " more above") : null, shown.map((spec, i) => /* @__PURE__ */ React20.createElement(SuggestionRow, { key: spec.cmd, spec, isSelected: windowStart + i === selectedIndex })), hiddenBelow > 0 ? /* @__PURE__ */ React20.createElement(Text16, { dimColor: true }, " \u2193 ", hiddenBelow, " more below") : null, /* @__PURE__ */ React20.createElement(Text16, { dimColor: true }, " [\u2191\u2193] navigate \xB7 [Tab]/[Enter] pick"));
10319
10588
  }
10320
10589
  function SuggestionRow({ spec, isSelected }) {
10321
- const marker = isSelected ? "\u25B8" : " ";
10322
10590
  const name = `/${spec.cmd}`;
10323
10591
  const argsSuffix = spec.argsHint ? ` ${spec.argsHint}` : "";
10324
10592
  if (isSelected) {
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));
10593
+ return /* @__PURE__ */ React20.createElement(Box18, null, /* @__PURE__ */ React20.createElement(Text16, { backgroundColor: "#67e8f9", color: "black", bold: true }, ` \u25B8 ${name.padEnd(12)}${argsSuffix.padEnd(16)} ${spec.summary} `));
10326
10594
  }
10327
- return /* @__PURE__ */ React19.createElement(Box17, null, /* @__PURE__ */ React19.createElement(Text17, { dimColor: true }, marker, " ", name.padEnd(12), argsSuffix.padEnd(16), " ", spec.summary));
10595
+ return /* @__PURE__ */ React20.createElement(Box18, null, /* @__PURE__ */ React20.createElement(Text16, { color: "#94a3b8" }, ` ${name.padEnd(12)}${argsSuffix.padEnd(16)} ${spec.summary}`));
10328
10596
  }
10329
10597
 
10330
10598
  // src/cli/ui/StatsPanel.tsx
10331
- import { Box as Box18, Text as Text18, useStdout as useStdout4 } from "ink";
10332
- import React20 from "react";
10333
- var WORDMARK_STYLES = [
10334
- { ch: "\u25C8", color: "#5eead4", isLogo: true },
10335
- // teal — brand mark
10336
- { ch: " ", color: "#5eead4", isLogo: false },
10337
- { ch: "R", color: "#67e8f9", isLogo: false },
10338
- // cyan
10339
- { ch: "E", color: "#7dd3fc", isLogo: false },
10340
- // sky
10341
- { ch: "A", color: "#93c5fd", isLogo: false },
10342
- // blue
10343
- { ch: "S", color: "#a5b4fc", isLogo: false },
10344
- // indigo
10345
- { ch: "O", color: "#c4b5fd", isLogo: false },
10346
- // violet
10347
- { ch: "N", color: "#d8b4fe", isLogo: false },
10348
- // purple
10349
- { ch: "I", color: "#f0abfc", isLogo: false },
10350
- // fuchsia
10351
- { ch: "X", color: "#f0abfc", isLogo: false }
10352
- // fuchsia
10353
- ];
10354
- function Wordmark({ busy }) {
10599
+ import { Box as Box19, Text as Text17, useStdout as useStdout6 } from "ink";
10600
+ import React21 from "react";
10601
+ var WORDMARK_LETTERS = ["R", "E", "A", "S", "O", "N", "I", "X"];
10602
+ function Wordmark({ busy, animate }) {
10355
10603
  const tick = useTick();
10356
- const period = busy ? 5 : 12;
10357
- const bright = Math.floor(tick / period) % 2 === 0;
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)));
10604
+ const pulsePeriod = busy ? 5 : 12;
10605
+ const bright = animate ? Math.floor(tick / pulsePeriod) % 2 === 0 : true;
10606
+ const rotateEvery = busy ? 2 : 4;
10607
+ const offset = animate ? Math.floor(tick / rotateEvery) : 0;
10608
+ const colorAt = (i) => GRADIENT[((i + offset) % GRADIENT.length + GRADIENT.length) % GRADIENT.length];
10609
+ return /* @__PURE__ */ React21.createElement(Text17, null, /* @__PURE__ */ React21.createElement(Text17, { color: colorAt(0), bold: bright }, "\u25C8"), /* @__PURE__ */ React21.createElement(Text17, null, " "), WORDMARK_LETTERS.map((letter, i) => /* @__PURE__ */ React21.createElement(Text17, { key: letter, color: colorAt(i + 1), bold: true }, letter)));
10359
10610
  }
10360
10611
  var NARROW_BREAKPOINT = 120;
10361
10612
  var COLD_START_TURNS = 3;
@@ -10377,20 +10628,20 @@ function StatsPanel({
10377
10628
  const branchOn = (branchBudget ?? 1) > 1;
10378
10629
  const ctxMax = DEEPSEEK_CONTEXT_TOKENS[model2] ?? DEFAULT_CONTEXT_TOKENS;
10379
10630
  const ctxRatio = summary.lastPromptTokens / ctxMax;
10380
- const { stdout: stdout2 } = useStdout4();
10631
+ const { stdout: stdout2 } = useStdout6();
10381
10632
  const columns = stdout2?.columns ?? 80;
10382
10633
  const narrow = columns < NARROW_BREAKPOINT;
10383
10634
  const coldStart = summary.turns <= COLD_START_TURNS;
10384
10635
  const ruleWidth = Math.max(20, columns - 2);
10636
+ const animate = columns >= 100;
10385
10637
  return (
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(
10638
+ // Borderless layout: no `borderStyle`, no rounded box. Bordered
10639
+ // Boxes were the most visible amplifier of Ink's eraseLines
10640
+ // miscount on Windows terminals. Visual weight here comes from
10641
+ // truecolor gradient rules at the top and bottom (rendered as
10642
+ // pure Text so they never trigger the eraseLines bug), the
10643
+ // animated wordmark + pill row, and a soft inner padding.
10644
+ /* @__PURE__ */ React21.createElement(Box19, { flexDirection: "column", paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React21.createElement(GradientRule, { width: ruleWidth, animate }), /* @__PURE__ */ React21.createElement(Box19, { marginTop: 1 }, /* @__PURE__ */ React21.createElement(
10394
10645
  Header,
10395
10646
  {
10396
10647
  model: model2,
@@ -10406,9 +10657,10 @@ function StatsPanel({
10406
10657
  narrow,
10407
10658
  busy: busy ?? false,
10408
10659
  proArmed: proArmed ?? false,
10409
- escalated: escalated ?? false
10660
+ escalated: escalated ?? false,
10661
+ animate
10410
10662
  }
10411
- ), narrow ? /* @__PURE__ */ React20.createElement(
10663
+ )), narrow ? /* @__PURE__ */ React21.createElement(
10412
10664
  StackedMetrics,
10413
10665
  {
10414
10666
  summary,
@@ -10417,7 +10669,7 @@ function StatsPanel({
10417
10669
  balance,
10418
10670
  coldStart
10419
10671
  }
10420
- ) : /* @__PURE__ */ React20.createElement(
10672
+ ) : /* @__PURE__ */ React21.createElement(
10421
10673
  InlineMetrics,
10422
10674
  {
10423
10675
  summary,
@@ -10426,9 +10678,28 @@ function StatsPanel({
10426
10678
  balance,
10427
10679
  coldStart
10428
10680
  }
10429
- ), /* @__PURE__ */ React20.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, "\u2500".repeat(ruleWidth))))
10681
+ ), /* @__PURE__ */ React21.createElement(Box19, { marginTop: 1 }, /* @__PURE__ */ React21.createElement(GradientRule, { width: ruleWidth, thin: true, animate })))
10430
10682
  );
10431
10683
  }
10684
+ function GradientRule({
10685
+ width,
10686
+ thin,
10687
+ animate
10688
+ }) {
10689
+ const tick = useTick();
10690
+ const offset = animate ? Math.floor(tick / 6) : 0;
10691
+ const ch = thin ? "\u2581" : "\u2584";
10692
+ const len = GRADIENT.length;
10693
+ return /* @__PURE__ */ React21.createElement(Box19, null, Array.from({ length: width }, (_, i) => {
10694
+ const t = width === 1 ? 0 : i * (len - 1) / (width - 1);
10695
+ const idx = (Math.round(t) + offset) % len;
10696
+ const color = GRADIENT[(idx % len + len) % len];
10697
+ return (
10698
+ // biome-ignore lint/suspicious/noArrayIndexKey: fixed-width gradient cells never reorder
10699
+ /* @__PURE__ */ React21.createElement(Text17, { key: `grule-${i}`, color }, ch)
10700
+ );
10701
+ }));
10702
+ }
10432
10703
  function Header({
10433
10704
  model: model2,
10434
10705
  prefixHash,
@@ -10443,14 +10714,16 @@ function Header({
10443
10714
  narrow,
10444
10715
  busy,
10445
10716
  proArmed,
10446
- escalated
10717
+ escalated,
10718
+ animate
10447
10719
  }) {
10448
10720
  const modePill = planMode ? { label: "PLAN", bg: "red" } : editMode === "auto" ? { label: "AUTO", bg: "magenta" } : editMode === "review" ? { label: "REVIEW", bg: "cyan" } : null;
10449
10721
  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`)));
10722
+ const showSecondary = animate && !narrow;
10723
+ return /* @__PURE__ */ React21.createElement(Box19, { justifyContent: "space-between" }, /* @__PURE__ */ React21.createElement(Box19, null, /* @__PURE__ */ React21.createElement(Wordmark, { busy, animate }), /* @__PURE__ */ React21.createElement(Text17, { dimColor: true }, ` ${VERSION}`), /* @__PURE__ */ React21.createElement(Text17, { dimColor: true }, " "), /* @__PURE__ */ React21.createElement(Text17, { color: "yellow", bold: true }, model2.replace(/^deepseek-/, "")), modePill ? /* @__PURE__ */ React21.createElement(React21.Fragment, null, /* @__PURE__ */ React21.createElement(Text17, null, " "), /* @__PURE__ */ React21.createElement(Pill, { label: modePill.label, bg: modePill.bg })) : null, proPill ? /* @__PURE__ */ React21.createElement(React21.Fragment, null, /* @__PURE__ */ React21.createElement(Text17, null, " "), /* @__PURE__ */ React21.createElement(Pill, { label: proPill.label, bg: proPill.bg })) : null, showSecondary && harvestOn ? /* @__PURE__ */ React21.createElement(Text17, { dimColor: true }, /* @__PURE__ */ React21.createElement(Text17, null, " "), /* @__PURE__ */ React21.createElement(Text17, { color: "magenta" }, "harvest")) : null, showSecondary && branchOn ? /* @__PURE__ */ React21.createElement(Text17, { dimColor: true }, /* @__PURE__ */ React21.createElement(Text17, null, " "), /* @__PURE__ */ React21.createElement(Text17, { color: "blue" }, `branch\xD7${branchBudget}`)) : null, showSecondary && reasoningEffort === "max" ? /* @__PURE__ */ React21.createElement(React21.Fragment, null, /* @__PURE__ */ React21.createElement(Text17, null, " "), /* @__PURE__ */ React21.createElement(Text17, { color: "green", dimColor: true }, "max")) : null, showSecondary && reasoningEffort === "high" ? /* @__PURE__ */ React21.createElement(React21.Fragment, null, /* @__PURE__ */ React21.createElement(Text17, null, " "), /* @__PURE__ */ React21.createElement(Text17, { color: "yellow", dimColor: true }, "high")) : null), /* @__PURE__ */ React21.createElement(Text17, null, updateAvailable ? /* @__PURE__ */ React21.createElement(Text17, { color: "yellow", bold: true }, `\u2191 ${updateAvailable} `) : null, /* @__PURE__ */ React21.createElement(Text17, { dimColor: true }, narrow ? `t${turns}` : `turn ${turns} \xB7 /help`)));
10451
10724
  }
10452
10725
  function Pill({ label, bg }) {
10453
- return /* @__PURE__ */ React20.createElement(Text18, { backgroundColor: bg, color: "white", bold: true }, ` ${label} `);
10726
+ return /* @__PURE__ */ React21.createElement(Text17, { backgroundColor: bg, color: "white", bold: true }, ` ${label} `);
10454
10727
  }
10455
10728
  function InlineMetrics({
10456
10729
  summary,
@@ -10459,7 +10732,7 @@ function InlineMetrics({
10459
10732
  balance,
10460
10733
  coldStart
10461
10734
  }) {
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);
10735
+ return /* @__PURE__ */ React21.createElement(Box19, { marginTop: 1, gap: 3 }, /* @__PURE__ */ React21.createElement(ContextCell, { ratio: ctxRatio, promptTokens: summary.lastPromptTokens, ctxMax }), /* @__PURE__ */ React21.createElement(CacheCell, { hitRatio: summary.cacheHitRatio, coldStart, turns: summary.turns }), /* @__PURE__ */ React21.createElement(CostCell, { summary, coldStart }), balance ? /* @__PURE__ */ React21.createElement(BalanceCell, { balance }) : null);
10463
10736
  }
10464
10737
  function StackedMetrics({
10465
10738
  summary,
@@ -10468,7 +10741,7 @@ function StackedMetrics({
10468
10741
  balance,
10469
10742
  coldStart
10470
10743
  }) {
10471
- return /* @__PURE__ */ React20.createElement(Box18, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React20.createElement(
10744
+ return /* @__PURE__ */ React21.createElement(Box19, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React21.createElement(
10472
10745
  ContextCell,
10473
10746
  {
10474
10747
  ratio: ctxRatio,
@@ -10476,7 +10749,7 @@ function StackedMetrics({
10476
10749
  ctxMax,
10477
10750
  showBar: true
10478
10751
  }
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 }));
10752
+ ), balance ? /* @__PURE__ */ React21.createElement(BalanceCell, { balance }) : null, /* @__PURE__ */ React21.createElement(CacheCell, { hitRatio: summary.cacheHitRatio, coldStart, turns: summary.turns }), /* @__PURE__ */ React21.createElement(CostCell, { summary, coldStart }));
10480
10753
  }
10481
10754
  function ContextCell({
10482
10755
  ratio,
@@ -10485,11 +10758,11 @@ function ContextCell({
10485
10758
  showBar
10486
10759
  }) {
10487
10760
  if (promptTokens === 0) {
10488
- return /* @__PURE__ */ React20.createElement(Text18, null, /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, "ctx "), /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, "\u2014 (no turns yet)"));
10761
+ return /* @__PURE__ */ React21.createElement(Text17, null, /* @__PURE__ */ React21.createElement(Text17, { color: COLOR.info, dimColor: true }, "\u25A3 ctx "), /* @__PURE__ */ React21.createElement(Text17, { dimColor: true }, "\u2014 (no turns yet)"));
10489
10762
  }
10490
- const color = ratio >= 0.8 ? "red" : ratio >= 0.6 ? "yellow" : "green";
10763
+ const color = ratio >= 0.8 ? COLOR.err : ratio >= 0.6 ? COLOR.warn : COLOR.ok;
10491
10764
  const pct2 = Math.round(ratio * 100);
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);
10765
+ return /* @__PURE__ */ React21.createElement(Text17, null, /* @__PURE__ */ React21.createElement(Text17, { color: COLOR.info }, "\u25A3 ctx "), /* @__PURE__ */ React21.createElement(Bar, { ratio, color, cells: showBar ? 14 : 10 }), /* @__PURE__ */ React21.createElement(Text17, null, " "), /* @__PURE__ */ React21.createElement(Text17, { color, bold: true }, formatTokens(promptTokens), "/", formatTokens(ctxMax)), /* @__PURE__ */ React21.createElement(Text17, { dimColor: true }, " (", pct2, "%)"), ratio >= 0.8 ? /* @__PURE__ */ React21.createElement(Text17, { color: COLOR.err, bold: true }, " \xB7 /compact") : null);
10493
10766
  }
10494
10767
  function CacheCell({
10495
10768
  hitRatio,
@@ -10498,46 +10771,48 @@ function CacheCell({
10498
10771
  }) {
10499
10772
  const pct2 = (hitRatio * 100).toFixed(1);
10500
10773
  if (turns === 0) {
10501
- return /* @__PURE__ */ React20.createElement(Text18, null, /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, "cache "), /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, "\u2014"));
10774
+ return /* @__PURE__ */ React21.createElement(Text17, null, /* @__PURE__ */ React21.createElement(Text17, { color: COLOR.info, dimColor: true }, "\u232C cache "), /* @__PURE__ */ React21.createElement(Text17, { dimColor: true }, "\u2014"));
10502
10775
  }
10503
10776
  if (coldStart) {
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)"));
10777
+ return /* @__PURE__ */ React21.createElement(Text17, null, /* @__PURE__ */ React21.createElement(Text17, { color: COLOR.info, dimColor: true }, "\u232C cache "), /* @__PURE__ */ React21.createElement(Text17, { dimColor: true }, pct2, "% "), /* @__PURE__ */ React21.createElement(Text17, { dimColor: true, italic: true }, "(cold start)"));
10505
10778
  }
10506
- const color = hitRatio >= 0.7 ? "green" : hitRatio >= 0.4 ? "yellow" : "red";
10507
- return /* @__PURE__ */ React20.createElement(Text18, null, /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, "cache "), /* @__PURE__ */ React20.createElement(Text18, { color, bold: true }, pct2, "%"));
10779
+ const color = hitRatio >= 0.7 ? COLOR.ok : hitRatio >= 0.4 ? COLOR.warn : COLOR.err;
10780
+ return /* @__PURE__ */ React21.createElement(Text17, null, /* @__PURE__ */ React21.createElement(Text17, { color: COLOR.info }, "\u232C cache "), /* @__PURE__ */ React21.createElement(Text17, { color, bold: true }, pct2, "%"));
10508
10781
  }
10509
10782
  function turnCostColor(cost) {
10510
10783
  if (cost <= 0) return void 0;
10511
- if (cost >= 0.2) return "red";
10512
- if (cost >= 0.05) return "yellow";
10513
- return "green";
10784
+ if (cost >= 0.2) return COLOR.err;
10785
+ if (cost >= 0.05) return COLOR.warn;
10786
+ return COLOR.ok;
10514
10787
  }
10515
10788
  function sessionCostColor(cost) {
10516
10789
  if (cost <= 0) return void 0;
10517
- if (cost >= 5) return "red";
10518
- if (cost >= 0.5) return "yellow";
10519
- return "green";
10790
+ if (cost >= 5) return COLOR.err;
10791
+ if (cost >= 0.5) return COLOR.warn;
10792
+ return COLOR.ok;
10520
10793
  }
10521
10794
  function CostCell({
10522
10795
  summary,
10523
10796
  coldStart
10524
10797
  }) {
10525
10798
  if (summary.turns === 0) {
10526
- return /* @__PURE__ */ React20.createElement(Text18, null, /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, "cost "), /* @__PURE__ */ React20.createElement(Text18, { dimColor: true }, "\u2014"));
10799
+ return /* @__PURE__ */ React21.createElement(Text17, null, /* @__PURE__ */ React21.createElement(Text17, { color: COLOR.info, dimColor: true }, "\u25F4 cost "), /* @__PURE__ */ React21.createElement(Text17, { dimColor: true }, "\u2014"));
10527
10800
  }
10528
10801
  const turnColor = coldStart ? void 0 : turnCostColor(summary.lastTurnCostUsd);
10529
10802
  const sessionColor = coldStart ? void 0 : sessionCostColor(summary.totalCostUsd);
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)));
10803
+ return /* @__PURE__ */ React21.createElement(Text17, null, /* @__PURE__ */ React21.createElement(Text17, { color: COLOR.info }, "\u25F4 turn "), /* @__PURE__ */ React21.createElement(Text17, { color: turnColor, bold: !coldStart, dimColor: coldStart }, "$", summary.lastTurnCostUsd.toFixed(4)), /* @__PURE__ */ React21.createElement(Text17, { dimColor: true }, " \xB7 session "), /* @__PURE__ */ React21.createElement(Text17, { color: sessionColor, bold: !coldStart, dimColor: coldStart }, "$", summary.totalCostUsd.toFixed(4)));
10531
10804
  }
10532
10805
  function BalanceCell({ balance }) {
10533
- const color = balance.total < 1 ? "red" : balance.total < 5 ? "yellow" : "green";
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}` : ""));
10806
+ const color = balance.total < 1 ? COLOR.err : balance.total < 5 ? COLOR.warn : COLOR.ok;
10807
+ return /* @__PURE__ */ React21.createElement(Text17, null, /* @__PURE__ */ React21.createElement(Text17, { color: COLOR.info }, "\u25D0 balance "), /* @__PURE__ */ React21.createElement(Text17, { color, bold: true }, balance.currency === "USD" ? "$" : "", balance.total.toFixed(2), balance.currency !== "USD" ? ` ${balance.currency}` : ""));
10535
10808
  }
10536
- function Bar({ ratio, color }) {
10537
- const cells = 10;
10809
+ function Bar({
10810
+ ratio,
10811
+ color,
10812
+ cells = 14
10813
+ }) {
10538
10814
  const filled = Math.max(0, Math.min(cells, Math.round(ratio * cells)));
10539
- const bar = "\u2588".repeat(filled) + "\u2591".repeat(cells - filled);
10540
- return /* @__PURE__ */ React20.createElement(Text18, { color }, bar);
10815
+ return /* @__PURE__ */ React21.createElement(Text17, null, /* @__PURE__ */ React21.createElement(Text17, { color }, "\u25B0".repeat(filled)), /* @__PURE__ */ React21.createElement(Text17, { dimColor: true }, "\u25B1".repeat(cells - filled)));
10541
10816
  }
10542
10817
  function formatTokens(n) {
10543
10818
  if (n < 1024) return String(n);
@@ -10546,13 +10821,26 @@ function formatTokens(n) {
10546
10821
  }
10547
10822
 
10548
10823
  // src/cli/ui/WelcomeBanner.tsx
10549
- import { Box as Box19, Text as Text19 } from "ink";
10550
- import React21 from "react";
10824
+ import { Box as Box20, Text as Text18, useStdout as useStdout7 } from "ink";
10825
+ import React22 from "react";
10551
10826
  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" })));
10827
+ const { stdout: stdout2 } = useStdout7();
10828
+ const cols = stdout2?.columns ?? 80;
10829
+ const ruleWidth = Math.min(60, Math.max(28, cols - 4));
10830
+ return /* @__PURE__ */ React22.createElement(Box20, { flexDirection: "column", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React22.createElement(GradientRule2, { width: ruleWidth }), /* @__PURE__ */ React22.createElement(BarRow, null, /* @__PURE__ */ React22.createElement(Text18, { bold: true, color: COLOR.brand }, "\u25C8 welcome"), /* @__PURE__ */ React22.createElement(Text18, { dimColor: true }, " \xB7 type a message to start")), /* @__PURE__ */ React22.createElement(BarRow, null), /* @__PURE__ */ React22.createElement(BarRow, null, /* @__PURE__ */ React22.createElement(Text18, { bold: true, color: COLOR.primary }, "quick start")), /* @__PURE__ */ React22.createElement(Hint, { cmd: "/help", desc: "every command + keyboard shortcut" }), /* @__PURE__ */ React22.createElement(Hint, { cmd: "/skill", desc: "invoke a stored playbook" }), inCodeMode ? /* @__PURE__ */ React22.createElement(React22.Fragment, null, /* @__PURE__ */ React22.createElement(Hint, { cmd: "@path", desc: "inline a file in your message" }), /* @__PURE__ */ React22.createElement(Hint, { cmd: "!cmd", desc: "run a shell command, output goes to context" })) : null, /* @__PURE__ */ React22.createElement(Hint, { cmd: "/exit", desc: "quit (Ctrl+C also works)" }), /* @__PURE__ */ React22.createElement(BarRow, null), /* @__PURE__ */ React22.createElement(BarRow, null, /* @__PURE__ */ React22.createElement(Text18, { dimColor: true, italic: true }, "tip:"), /* @__PURE__ */ React22.createElement(Text18, { dimColor: true }, " Ctrl+J inserts a newline \xB7 trailing \\ also continues")), /* @__PURE__ */ React22.createElement(Box20, { marginTop: 1 }, /* @__PURE__ */ React22.createElement(GradientRule2, { width: ruleWidth, thin: true })));
10831
+ }
10832
+ function GradientRule2({ width, thin }) {
10833
+ const cells = gradientCells(width, thin ? "\u2581" : "\u2584");
10834
+ return /* @__PURE__ */ React22.createElement(Box20, null, cells.map((c, i) => (
10835
+ // biome-ignore lint/suspicious/noArrayIndexKey: fixed-width gradient row, never reordered
10836
+ /* @__PURE__ */ React22.createElement(Text18, { key: `wrule-${i}`, color: c.color }, c.ch)
10837
+ )));
10838
+ }
10839
+ function BarRow({ children }) {
10840
+ return /* @__PURE__ */ React22.createElement(Box20, null, /* @__PURE__ */ React22.createElement(Text18, { color: COLOR.brand, bold: true }, "\u258E"), /* @__PURE__ */ React22.createElement(Text18, null, " "), children);
10553
10841
  }
10554
10842
  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}`));
10843
+ return /* @__PURE__ */ React22.createElement(BarRow, null, /* @__PURE__ */ React22.createElement(Text18, { bold: true, color: COLOR.accent }, cmd.padEnd(8)), /* @__PURE__ */ React22.createElement(Text18, { dimColor: true }, ` ${desc}`));
10556
10844
  }
10557
10845
 
10558
10846
  // src/cli/ui/bang.ts
@@ -12894,7 +13182,7 @@ function App({
12894
13182
  const abortedThisTurn = useRef6(false);
12895
13183
  const [ongoingTool, setOngoingTool] = useState10(null);
12896
13184
  const [toolProgress, setToolProgress] = useState10(null);
12897
- const { stdout: stdout2 } = useStdout5();
13185
+ const { stdout: stdout2 } = useStdout8();
12898
13186
  useEffect6(() => {
12899
13187
  if (!stdout2 || !stdout2.isTTY) return;
12900
13188
  stdout2.write("\x1B[?2004h");
@@ -14477,12 +14765,12 @@ Continue executing from the next pending step. Call mark_step_complete after eac
14477
14765
  async (choice) => handleReviseConfirmRef.current(choice),
14478
14766
  []
14479
14767
  );
14480
- return /* @__PURE__ */ React22.createElement(React22.Fragment, null, /* @__PURE__ */ React22.createElement(
14768
+ return /* @__PURE__ */ React23.createElement(React23.Fragment, null, /* @__PURE__ */ React23.createElement(
14481
14769
  TickerProvider,
14482
14770
  {
14483
14771
  disabled: PLAIN_UI || !!pendingPlan || !!pendingShell || !!pendingEditReview || !!pendingCheckpoint || !!stagedCheckpointRevise || !!pendingChoice || !!stagedChoiceCustom || !!pendingRevision
14484
14772
  },
14485
- /* @__PURE__ */ React22.createElement(Box20, { flexDirection: "column" }, /* @__PURE__ */ React22.createElement(
14773
+ /* @__PURE__ */ React23.createElement(Box21, { flexDirection: "column" }, /* @__PURE__ */ React23.createElement(
14486
14774
  StatsPanel,
14487
14775
  {
14488
14776
  summary,
@@ -14499,28 +14787,28 @@ Continue executing from the next pending step. Call mark_step_complete after eac
14499
14787
  proArmed,
14500
14788
  escalated: turnOnPro
14501
14789
  }
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(
14790
+ ), /* @__PURE__ */ React23.createElement(Static, { items: historical }, (item) => /* @__PURE__ */ React23.createElement(EventRow, { key: item.id, event: item, projectRoot: hookCwd })), !historical.some((e) => e.role === "user" || e.role === "assistant") && !busy && !streaming ? /* @__PURE__ */ React23.createElement(WelcomeBanner, { inCodeMode: !!codeMode }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && streaming ? /* @__PURE__ */ React23.createElement(Box21, { marginY: 1 }, /* @__PURE__ */ React23.createElement(EventRow, { event: streaming, projectRoot: hookCwd })) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && ongoingTool ? /* @__PURE__ */ React23.createElement(OngoingToolRow, { tool: ongoingTool, progress: toolProgress }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && subagentActivity ? /* @__PURE__ */ React23.createElement(SubagentRow, { activity: subagentActivity }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && !ongoingTool && statusLine ? /* @__PURE__ */ React23.createElement(StatusRow, { text: statusLine }) : null, !PLAIN_UI && undoBanner && !pendingShell && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && !pendingChoice && !stagedChoiceCustom && !pendingRevision ? /* @__PURE__ */ React23.createElement(UndoBanner, { banner: undoBanner }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !stagedInput && !pendingEditReview && !pendingCheckpoint && !stagedCheckpointRevise && busy && !streaming && !ongoingTool && !statusLine ? /* @__PURE__ */ React23.createElement(StatusRow, { text: "processing\u2026" }) : null, stagedInput ? /* @__PURE__ */ React23.createElement(
14503
14791
  PlanRefineInput,
14504
14792
  {
14505
14793
  mode: stagedInput.mode,
14506
14794
  onSubmit: handleStagedInputSubmit,
14507
14795
  onCancel: handleStagedInputCancel
14508
14796
  }
14509
- ) : stagedCheckpointRevise ? /* @__PURE__ */ React22.createElement(
14797
+ ) : stagedCheckpointRevise ? /* @__PURE__ */ React23.createElement(
14510
14798
  PlanRefineInput,
14511
14799
  {
14512
14800
  mode: "checkpoint-revise",
14513
14801
  onSubmit: handleCheckpointReviseSubmit,
14514
14802
  onCancel: handleCheckpointReviseCancel
14515
14803
  }
14516
- ) : stagedChoiceCustom ? /* @__PURE__ */ React22.createElement(
14804
+ ) : stagedChoiceCustom ? /* @__PURE__ */ React23.createElement(
14517
14805
  PlanRefineInput,
14518
14806
  {
14519
14807
  mode: "choice-custom",
14520
14808
  onSubmit: handleChoiceCustomSubmit,
14521
14809
  onCancel: handleChoiceCustomCancel
14522
14810
  }
14523
- ) : pendingChoice ? /* @__PURE__ */ React22.createElement(
14811
+ ) : pendingChoice ? /* @__PURE__ */ React23.createElement(
14524
14812
  ChoiceConfirm,
14525
14813
  {
14526
14814
  question: pendingChoice.question,
@@ -14528,7 +14816,7 @@ Continue executing from the next pending step. Call mark_step_complete after eac
14528
14816
  allowCustom: pendingChoice.allowCustom,
14529
14817
  onChoose: stableHandleChoiceConfirm
14530
14818
  }
14531
- ) : pendingRevision ? /* @__PURE__ */ React22.createElement(
14819
+ ) : pendingRevision ? /* @__PURE__ */ React23.createElement(
14532
14820
  PlanReviseConfirm,
14533
14821
  {
14534
14822
  reason: pendingRevision.reason,
@@ -14539,7 +14827,7 @@ Continue executing from the next pending step. Call mark_step_complete after eac
14539
14827
  summary: pendingRevision.summary,
14540
14828
  onChoose: stableHandleReviseConfirm
14541
14829
  }
14542
- ) : pendingCheckpoint ? /* @__PURE__ */ React22.createElement(
14830
+ ) : pendingCheckpoint ? /* @__PURE__ */ React23.createElement(
14543
14831
  PlanCheckpointConfirm,
14544
14832
  {
14545
14833
  stepId: pendingCheckpoint.stepId,
@@ -14550,7 +14838,7 @@ Continue executing from the next pending step. Call mark_step_complete after eac
14550
14838
  completedStepIds: completedStepIdsRef.current,
14551
14839
  onChoose: stableHandleCheckpointConfirm
14552
14840
  }
14553
- ) : pendingPlan ? /* @__PURE__ */ React22.createElement(
14841
+ ) : pendingPlan ? /* @__PURE__ */ React23.createElement(
14554
14842
  PlanConfirm,
14555
14843
  {
14556
14844
  plan: pendingPlan,
@@ -14559,7 +14847,7 @@ Continue executing from the next pending step. Call mark_step_complete after eac
14559
14847
  onChoose: stableHandlePlanConfirm,
14560
14848
  projectRoot: hookCwd
14561
14849
  }
14562
- ) : pendingShell ? /* @__PURE__ */ React22.createElement(
14850
+ ) : pendingShell ? /* @__PURE__ */ React23.createElement(
14563
14851
  ShellConfirm,
14564
14852
  {
14565
14853
  command: pendingShell.command,
@@ -14567,7 +14855,7 @@ Continue executing from the next pending step. Call mark_step_complete after eac
14567
14855
  kind: pendingShell.kind,
14568
14856
  onChoose: handleShellConfirm
14569
14857
  }
14570
- ) : pendingEditReview ? /* @__PURE__ */ React22.createElement(
14858
+ ) : pendingEditReview ? /* @__PURE__ */ React23.createElement(
14571
14859
  EditConfirm,
14572
14860
  {
14573
14861
  block: pendingEditReview,
@@ -14579,7 +14867,7 @@ Continue executing from the next pending step. Call mark_step_complete after eac
14579
14867
  }
14580
14868
  }
14581
14869
  }
14582
- ) : /* @__PURE__ */ React22.createElement(React22.Fragment, null, codeMode ? /* @__PURE__ */ React22.createElement(
14870
+ ) : /* @__PURE__ */ React23.createElement(React23.Fragment, null, codeMode ? /* @__PURE__ */ React23.createElement(
14583
14871
  ModeStatusBar,
14584
14872
  {
14585
14873
  editMode,
@@ -14589,7 +14877,7 @@ Continue executing from the next pending step. Call mark_step_complete after eac
14589
14877
  undoArmed: !!undoBanner || hasUndoable(),
14590
14878
  jobs: codeMode.jobs
14591
14879
  }
14592
- ) : null, /* @__PURE__ */ React22.createElement(
14880
+ ) : null, /* @__PURE__ */ React23.createElement(
14593
14881
  PromptInput,
14594
14882
  {
14595
14883
  value: input,
@@ -14599,14 +14887,14 @@ Continue executing from the next pending step. Call mark_step_complete after eac
14599
14887
  onHistoryPrev: recallPrev,
14600
14888
  onHistoryNext: recallNext
14601
14889
  }
14602
- ), /* @__PURE__ */ React22.createElement(SlashSuggestions, { matches: slashMatches, selectedIndex: slashSelected }), /* @__PURE__ */ React22.createElement(
14890
+ ), /* @__PURE__ */ React23.createElement(SlashSuggestions, { matches: slashMatches, selectedIndex: slashSelected }), /* @__PURE__ */ React23.createElement(
14603
14891
  AtMentionSuggestions,
14604
14892
  {
14605
14893
  matches: atMatches,
14606
14894
  selectedIndex: atSelected,
14607
14895
  query: atPicker?.query ?? ""
14608
14896
  }
14609
- ), slashArgContext ? /* @__PURE__ */ React22.createElement(
14897
+ ), slashArgContext ? /* @__PURE__ */ React23.createElement(
14610
14898
  SlashArgPicker,
14611
14899
  {
14612
14900
  matches: slashArgMatches,
@@ -14620,15 +14908,15 @@ Continue executing from the next pending step. Call mark_step_complete after eac
14620
14908
  }
14621
14909
 
14622
14910
  // src/cli/ui/SessionPicker.tsx
14623
- import { Box as Box21, Text as Text20 } from "ink";
14624
- import React23 from "react";
14911
+ import { Box as Box22, Text as Text19 } from "ink";
14912
+ import React24 from "react";
14625
14913
  function SessionPicker({
14626
14914
  sessionName,
14627
14915
  messageCount,
14628
14916
  lastActive,
14629
14917
  onChoose
14630
14918
  }) {
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(
14919
+ return /* @__PURE__ */ React24.createElement(Box22, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React24.createElement(Box22, { marginBottom: 1 }, /* @__PURE__ */ React24.createElement(Text19, { bold: true, color: "cyan" }, `Session "${sessionName}" has ${messageCount} prior message${messageCount === 1 ? "" : "s"}`), /* @__PURE__ */ React24.createElement(Text19, { dimColor: true }, ` \xB7 last active ${relativeTime2(lastActive)}`)), /* @__PURE__ */ React24.createElement(
14632
14920
  SingleSelect,
14633
14921
  {
14634
14922
  initialValue: "new",
@@ -14651,7 +14939,7 @@ function SessionPicker({
14651
14939
  ],
14652
14940
  onSubmit: (v) => onChoose(v)
14653
14941
  }
14654
- ), /* @__PURE__ */ React23.createElement(Box21, { marginTop: 1 }, /* @__PURE__ */ React23.createElement(Text20, { dimColor: true }, "[\u2191\u2193] navigate \xB7 [Enter] select")));
14942
+ ), /* @__PURE__ */ React24.createElement(Box22, { marginTop: 1 }, /* @__PURE__ */ React24.createElement(Text19, { dimColor: true }, "[\u2191\u2193] navigate \xB7 [Enter] select")));
14655
14943
  }
14656
14944
  function relativeTime2(date) {
14657
14945
  const ms = Date.now() - date.getTime();
@@ -14667,9 +14955,9 @@ function relativeTime2(date) {
14667
14955
  }
14668
14956
 
14669
14957
  // src/cli/ui/Setup.tsx
14670
- import { Box as Box22, Text as Text21, useApp as useApp2 } from "ink";
14958
+ import { Box as Box23, Text as Text20, useApp as useApp2 } from "ink";
14671
14959
  import TextInput from "ink-text-input";
14672
- import React24, { useState as useState11 } from "react";
14960
+ import React25, { useState as useState11 } from "react";
14673
14961
  function Setup({ onReady }) {
14674
14962
  const [value, setValue] = useState11("");
14675
14963
  const [error, setError] = useState11(null);
@@ -14693,7 +14981,7 @@ function Setup({ onReady }) {
14693
14981
  }
14694
14982
  onReady(trimmed);
14695
14983
  };
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(
14984
+ return /* @__PURE__ */ React25.createElement(Box23, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React25.createElement(Text20, { bold: true, color: "cyan" }, "Welcome to Reasonix."), /* @__PURE__ */ React25.createElement(Box23, { marginTop: 1 }, /* @__PURE__ */ React25.createElement(Text20, null, "Paste your DeepSeek API key to get started.")), /* @__PURE__ */ React25.createElement(Text20, { dimColor: true }, "Get one (free credit on signup): https://platform.deepseek.com/api_keys"), /* @__PURE__ */ React25.createElement(Text20, { dimColor: true }, "Saved locally to ", defaultConfigPath()), /* @__PURE__ */ React25.createElement(Box23, { marginTop: 1 }, /* @__PURE__ */ React25.createElement(Text20, { bold: true, color: "cyan" }, "key \u203A "), /* @__PURE__ */ React25.createElement(
14697
14985
  TextInput,
14698
14986
  {
14699
14987
  value,
@@ -14702,7 +14990,7 @@ function Setup({ onReady }) {
14702
14990
  mask: "\u2022",
14703
14991
  placeholder: "sk-..."
14704
14992
  }
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.)")));
14993
+ )), error ? /* @__PURE__ */ React25.createElement(Box23, { marginTop: 1 }, /* @__PURE__ */ React25.createElement(Text20, { color: "red" }, error)) : value ? /* @__PURE__ */ React25.createElement(Box23, { marginTop: 1 }, /* @__PURE__ */ React25.createElement(Text20, { dimColor: true }, "preview: ", redactKey(value))) : null, /* @__PURE__ */ React25.createElement(Box23, { marginTop: 1 }, /* @__PURE__ */ React25.createElement(Text20, { dimColor: true }, "(Type /exit to abort.)")));
14706
14994
  }
14707
14995
 
14708
14996
  // src/cli/commands/chat.tsx
@@ -14718,7 +15006,7 @@ function Root({
14718
15006
  const [key, setKey] = useState12(initialKey);
14719
15007
  const [pending, setPending] = useState12(sessionPreview);
14720
15008
  if (!key) {
14721
- return /* @__PURE__ */ React25.createElement(
15009
+ return /* @__PURE__ */ React26.createElement(
14722
15010
  Setup,
14723
15011
  {
14724
15012
  onReady: (k) => {
@@ -14730,7 +15018,7 @@ function Root({
14730
15018
  }
14731
15019
  process.env.DEEPSEEK_API_KEY = key;
14732
15020
  if (pending && appProps.session) {
14733
- return /* @__PURE__ */ React25.createElement(KeystrokeProvider, null, /* @__PURE__ */ React25.createElement(
15021
+ return /* @__PURE__ */ React26.createElement(KeystrokeProvider, null, /* @__PURE__ */ React26.createElement(
14734
15022
  SessionPicker,
14735
15023
  {
14736
15024
  sessionName: appProps.session,
@@ -14745,7 +15033,7 @@ function Root({
14745
15033
  }
14746
15034
  ));
14747
15035
  }
14748
- return /* @__PURE__ */ React25.createElement(KeystrokeProvider, null, /* @__PURE__ */ React25.createElement(
15036
+ return /* @__PURE__ */ React26.createElement(KeystrokeProvider, null, /* @__PURE__ */ React26.createElement(
14749
15037
  App,
14750
15038
  {
14751
15039
  model: appProps.model,
@@ -14849,8 +15137,11 @@ async function chatCommand(opts) {
14849
15137
  } else if (opts.session && opts.forceNew) {
14850
15138
  rewriteSession(opts.session, []);
14851
15139
  }
15140
+ if (process.stdout.isTTY) {
15141
+ process.stdout.write("\x1B[2J\x1B[3J\x1B[H");
15142
+ }
14852
15143
  const { waitUntilExit } = render(
14853
- /* @__PURE__ */ React25.createElement(
15144
+ /* @__PURE__ */ React26.createElement(
14854
15145
  Root,
14855
15146
  {
14856
15147
  initialKey,
@@ -14919,35 +15210,35 @@ async function codeCommand(opts = {}) {
14919
15210
  import { writeFileSync as writeFileSync7 } from "fs";
14920
15211
  import { basename as basename3 } from "path";
14921
15212
  import { render as render2 } from "ink";
14922
- import React28 from "react";
15213
+ import React29 from "react";
14923
15214
 
14924
15215
  // src/cli/ui/DiffApp.tsx
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";
15216
+ import { Box as Box25, Static as Static2, Text as Text22, useApp as useApp3, useInput } from "ink";
15217
+ import React28, { useState as useState13 } from "react";
14927
15218
 
14928
15219
  // src/cli/ui/RecordView.tsx
14929
- import { Box as Box23, Text as Text22 } from "ink";
14930
- import React26 from "react";
15220
+ import { Box as Box24, Text as Text21 } from "ink";
15221
+ import React27 from "react";
14931
15222
  function RecordView({ rec, compact: compact2 = false }) {
14932
15223
  const toolArgsMax = compact2 ? 120 : 200;
14933
15224
  const toolContentMax = compact2 ? 200 : 400;
14934
15225
  if (rec.role === "user") {
14935
15226
  const content = rec.content.includes("\n") ? rec.content.split("\n").join("\n ") : rec.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));
15227
+ return /* @__PURE__ */ React27.createElement(Box24, { marginTop: 1 }, /* @__PURE__ */ React27.createElement(Text21, { bold: true, color: "cyan" }, "you \u203A", " "), /* @__PURE__ */ React27.createElement(Text21, null, content));
14937
15228
  }
14938
15229
  if (rec.role === "assistant_final") {
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)"));
15230
+ return /* @__PURE__ */ React27.createElement(Box24, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React27.createElement(Box24, null, /* @__PURE__ */ React27.createElement(Text21, { bold: true, color: "green" }, "assistant"), rec.cost !== void 0 ? /* @__PURE__ */ React27.createElement(Text21, { dimColor: true }, " $", rec.cost.toFixed(6)) : null, rec.usage ? /* @__PURE__ */ React27.createElement(CacheBadge, { usage: rec.usage }) : null), rec.planState ? /* @__PURE__ */ React27.createElement(PlanStateBlock, { planState: rec.planState }) : null, rec.content ? /* @__PURE__ */ React27.createElement(Text21, null, rec.content) : /* @__PURE__ */ React27.createElement(Text21, { dimColor: true, italic: true }, "(tool-call response only)"));
14940
15231
  }
14941
15232
  if (rec.role === "tool") {
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)));
15233
+ return /* @__PURE__ */ React27.createElement(Box24, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React27.createElement(Text21, { color: "yellow" }, "tool<", rec.tool ?? "?", ">"), rec.args ? /* @__PURE__ */ React27.createElement(Text21, { dimColor: true }, " args: ", truncate2(rec.args, toolArgsMax)) : null, /* @__PURE__ */ React27.createElement(Text21, { dimColor: true }, " \u2192 ", truncate2(rec.content, toolContentMax)));
14943
15234
  }
14944
15235
  if (rec.role === "error") {
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));
15236
+ return /* @__PURE__ */ React27.createElement(Box24, { marginTop: 1 }, /* @__PURE__ */ React27.createElement(Text21, { color: "red", bold: true }, "error", " "), /* @__PURE__ */ React27.createElement(Text21, { color: "red" }, rec.error ?? rec.content));
14946
15237
  }
14947
15238
  if (rec.role === "done" || rec.role === "assistant_delta") {
14948
15239
  return null;
14949
15240
  }
14950
- return /* @__PURE__ */ React26.createElement(Box23, null, /* @__PURE__ */ React26.createElement(Text22, { dimColor: true }, "[", rec.role, "] ", rec.content));
15241
+ return /* @__PURE__ */ React27.createElement(Box24, null, /* @__PURE__ */ React27.createElement(Text21, { dimColor: true }, "[", rec.role, "] ", rec.content));
14951
15242
  }
14952
15243
  function CacheBadge({ usage }) {
14953
15244
  const hit = usage.prompt_cache_hit_tokens ?? 0;
@@ -14956,7 +15247,7 @@ function CacheBadge({ usage }) {
14956
15247
  if (total === 0) return null;
14957
15248
  const pct2 = hit / total * 100;
14958
15249
  const color = pct2 >= 70 ? "green" : pct2 >= 40 ? "yellow" : "red";
14959
- return /* @__PURE__ */ React26.createElement(Text22, null, /* @__PURE__ */ React26.createElement(Text22, { dimColor: true }, " \xB7 cache "), /* @__PURE__ */ React26.createElement(Text22, { color }, pct2.toFixed(1), "%"));
15250
+ return /* @__PURE__ */ React27.createElement(Text21, null, /* @__PURE__ */ React27.createElement(Text21, { dimColor: true }, " \xB7 cache "), /* @__PURE__ */ React27.createElement(Text21, { color }, pct2.toFixed(1), "%"));
14960
15251
  }
14961
15252
  function truncate2(s, max) {
14962
15253
  return s.length <= max ? s : `${s.slice(0, max)}\u2026 (+${s.length - max} chars)`;
@@ -14990,7 +15281,7 @@ function DiffApp({ report }) {
14990
15281
  }
14991
15282
  });
14992
15283
  const pair = report.pairs[idx];
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")));
15284
+ return /* @__PURE__ */ React28.createElement(Box25, { flexDirection: "column" }, /* @__PURE__ */ React28.createElement(DiffHeader, { report }), /* @__PURE__ */ React28.createElement(Box25, { marginTop: 1, paddingX: 1, justifyContent: "space-between" }, /* @__PURE__ */ React28.createElement(Text22, { color: "cyan", bold: true }, "turn ", pair?.turn ?? "?", " (", idx + 1, " / ", report.pairs.length, ")"), /* @__PURE__ */ React28.createElement(Text22, null, pair ? /* @__PURE__ */ React28.createElement(KindBadge, { kind: pair.kind }) : null)), /* @__PURE__ */ React28.createElement(Box25, { flexDirection: "row", marginTop: 1 }, /* @__PURE__ */ React28.createElement(Pane, { label: report.a.label, headerColor: "blue", records: paneRecords(pair, "a") }), /* @__PURE__ */ React28.createElement(Pane, { label: report.b.label, headerColor: "magenta", records: paneRecords(pair, "b") })), pair?.divergenceNote ? /* @__PURE__ */ React28.createElement(Box25, { marginTop: 1, paddingX: 1 }, /* @__PURE__ */ React28.createElement(Text22, { color: "yellow" }, "\u2605 "), /* @__PURE__ */ React28.createElement(Text22, null, pair.divergenceNote)) : null, /* @__PURE__ */ React28.createElement(Box25, { marginTop: 1, paddingX: 1, borderStyle: "single", borderColor: "gray" }, /* @__PURE__ */ React28.createElement(Text22, { dimColor: true }, /* @__PURE__ */ React28.createElement(Text22, { bold: true }, "j"), "/", /* @__PURE__ */ React28.createElement(Text22, { bold: true }, "\u2193"), " next \xB7 ", /* @__PURE__ */ React28.createElement(Text22, { bold: true }, "k"), "/", /* @__PURE__ */ React28.createElement(Text22, { bold: true }, "\u2191"), " ", "prev \xB7 ", /* @__PURE__ */ React28.createElement(Text22, { bold: true }, "n"), " next-diverge \xB7 ", /* @__PURE__ */ React28.createElement(Text22, { bold: true }, "N"), "/", /* @__PURE__ */ React28.createElement(Text22, { bold: true }, "p"), " ", "prev-diverge \xB7 ", /* @__PURE__ */ React28.createElement(Text22, { bold: true }, "g"), "/", /* @__PURE__ */ React28.createElement(Text22, { bold: true }, "G"), " first/last \xB7 ", /* @__PURE__ */ React28.createElement(Text22, { bold: true }, "q"), " ", "quit")));
14994
15285
  }
14995
15286
  function DiffHeader({ report }) {
14996
15287
  const a = report.a;
@@ -15008,15 +15299,15 @@ function DiffHeader({ report }) {
15008
15299
  } else if (a.stats.prefixHashes[0] && a.stats.prefixHashes[0] === b.stats.prefixHashes[0]) {
15009
15300
  prefixLine = `shared prefix hash ${a.stats.prefixHashes[0].slice(0, 12)}\u2026 \u2014 cache delta attributable to log stability, not prompt change.`;
15010
15301
  }
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);
15302
+ return /* @__PURE__ */ React28.createElement(Box25, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React28.createElement(Box25, { justifyContent: "space-between" }, /* @__PURE__ */ React28.createElement(Text22, null, /* @__PURE__ */ React28.createElement(Text22, { color: "cyan", bold: true }, "reasonix diff"), /* @__PURE__ */ React28.createElement(Text22, { dimColor: true }, " \xB7 A="), /* @__PURE__ */ React28.createElement(Text22, { color: "blue" }, a.label), /* @__PURE__ */ React28.createElement(Text22, { dimColor: true }, " vs B="), /* @__PURE__ */ React28.createElement(Text22, { color: "magenta" }, b.label)), /* @__PURE__ */ React28.createElement(Text22, { dimColor: true }, report.pairs.length, " turns aligned")), /* @__PURE__ */ React28.createElement(Box25, { marginTop: 1, gap: 3 }, /* @__PURE__ */ React28.createElement(Text22, null, /* @__PURE__ */ React28.createElement(Text22, { dimColor: true }, "cache "), /* @__PURE__ */ React28.createElement(Text22, null, (a.stats.cacheHitRatio * 100).toFixed(1), "%"), /* @__PURE__ */ React28.createElement(Text22, { dimColor: true }, " \u2192 "), /* @__PURE__ */ React28.createElement(Text22, null, (b.stats.cacheHitRatio * 100).toFixed(1), "%"), /* @__PURE__ */ React28.createElement(Text22, { color: cacheDelta >= 0 ? "green" : "red", bold: true }, " ", cacheDelta >= 0 ? "+" : "", (cacheDelta * 100).toFixed(1), "pp")), /* @__PURE__ */ React28.createElement(Text22, null, /* @__PURE__ */ React28.createElement(Text22, { dimColor: true }, "cost "), /* @__PURE__ */ React28.createElement(Text22, null, "$", a.stats.totalCostUsd.toFixed(6)), /* @__PURE__ */ React28.createElement(Text22, { dimColor: true }, " \u2192 "), /* @__PURE__ */ React28.createElement(Text22, null, "$", b.stats.totalCostUsd.toFixed(6)), /* @__PURE__ */ React28.createElement(Text22, { color: costDelta2 <= 0 ? "green" : "red", bold: true }, " ", costDelta2 >= 0 ? "+" : "", costDelta2.toFixed(1), "%")), /* @__PURE__ */ React28.createElement(Text22, null, /* @__PURE__ */ React28.createElement(Text22, { dimColor: true }, "model calls "), /* @__PURE__ */ React28.createElement(Text22, null, a.stats.turns, " \u2192 ", b.stats.turns))), prefixLine ? /* @__PURE__ */ React28.createElement(Box25, { marginTop: 1 }, /* @__PURE__ */ React28.createElement(Text22, { dimColor: true, italic: true }, prefixLine)) : null);
15012
15303
  }
15013
15304
  function Pane({
15014
15305
  label,
15015
15306
  headerColor,
15016
15307
  records
15017
15308
  }) {
15018
- return /* @__PURE__ */ React27.createElement(
15019
- Box24,
15309
+ return /* @__PURE__ */ React28.createElement(
15310
+ Box25,
15020
15311
  {
15021
15312
  flexDirection: "column",
15022
15313
  flexGrow: 1,
@@ -15024,21 +15315,21 @@ function Pane({
15024
15315
  borderStyle: "single",
15025
15316
  borderColor: headerColor
15026
15317
  },
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 }))
15318
+ /* @__PURE__ */ React28.createElement(Text22, { color: headerColor, bold: true }, label),
15319
+ records.length === 0 ? /* @__PURE__ */ React28.createElement(Box25, { marginTop: 1 }, /* @__PURE__ */ React28.createElement(Text22, { dimColor: true, italic: true }, "(no records on this side for this turn)")) : /* @__PURE__ */ React28.createElement(Static2, { items: records.map((rec, i) => ({ key: `${label}-${i}`, rec })) }, ({ key, rec }) => /* @__PURE__ */ React28.createElement(RecordView, { key, rec, compact: true }))
15029
15320
  );
15030
15321
  }
15031
15322
  function KindBadge({ kind }) {
15032
15323
  if (kind === "match") {
15033
- return /* @__PURE__ */ React27.createElement(Text23, { color: "green" }, "\u2713 match");
15324
+ return /* @__PURE__ */ React28.createElement(Text22, { color: "green" }, "\u2713 match");
15034
15325
  }
15035
15326
  if (kind === "diverge") {
15036
- return /* @__PURE__ */ React27.createElement(Text23, { color: "yellow" }, "\u2605 diverge");
15327
+ return /* @__PURE__ */ React28.createElement(Text22, { color: "yellow" }, "\u2605 diverge");
15037
15328
  }
15038
15329
  if (kind === "only_in_a") {
15039
- return /* @__PURE__ */ React27.createElement(Text23, { color: "blue" }, "\u2190 only in A");
15330
+ return /* @__PURE__ */ React28.createElement(Text22, { color: "blue" }, "\u2190 only in A");
15040
15331
  }
15041
- return /* @__PURE__ */ React27.createElement(Text23, { color: "magenta" }, "\u2192 only in B");
15332
+ return /* @__PURE__ */ React28.createElement(Text22, { color: "magenta" }, "\u2192 only in B");
15042
15333
  }
15043
15334
  function paneRecords(pair, side) {
15044
15335
  if (!pair) return [];
@@ -15069,7 +15360,7 @@ markdown report written to ${opts.mdPath}`);
15069
15360
  return;
15070
15361
  }
15071
15362
  if (wantTui) {
15072
- const { waitUntilExit } = render2(React28.createElement(DiffApp, { report }), {
15363
+ const { waitUntilExit } = render2(React29.createElement(DiffApp, { report }), {
15073
15364
  exitOnCtrlC: true,
15074
15365
  patchConsole: false
15075
15366
  });
@@ -15210,11 +15501,11 @@ function pad2(s, width) {
15210
15501
 
15211
15502
  // src/cli/commands/replay.ts
15212
15503
  import { render as render3 } from "ink";
15213
- import React30 from "react";
15504
+ import React31 from "react";
15214
15505
 
15215
15506
  // src/cli/ui/ReplayApp.tsx
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";
15507
+ import { Box as Box26, Static as Static3, Text as Text23, useApp as useApp4, useInput as useInput2 } from "ink";
15508
+ import React30, { useMemo as useMemo4, useState as useState14 } from "react";
15218
15509
  function ReplayApp({ meta, pages }) {
15219
15510
  const { exit: exit2 } = useApp4();
15220
15511
  const maxIdx = Math.max(0, pages.length - 1);
@@ -15254,14 +15545,14 @@ function ReplayApp({ meta, pages }) {
15254
15545
  const prefixHash = cumStats.prefixHashes.length === 1 ? cumStats.prefixHashes[0].slice(0, 16) : cumStats.prefixHashes.length === 0 ? "(untracked)" : `(churned \xD7${cumStats.prefixHashes.length})`;
15255
15546
  const currentPage = pages[idx];
15256
15547
  const progressLabel = pages.length === 0 ? "empty transcript" : `turn ${idx + 1} / ${pages.length}`;
15257
- return /* @__PURE__ */ React29.createElement(Box25, { flexDirection: "column" }, /* @__PURE__ */ React29.createElement(
15548
+ return /* @__PURE__ */ React30.createElement(Box26, { flexDirection: "column" }, /* @__PURE__ */ React30.createElement(
15258
15549
  StatsPanel,
15259
15550
  {
15260
15551
  summary,
15261
15552
  model: cumStats.models[0] ?? meta?.model ?? "?",
15262
15553
  prefixHash
15263
15554
  }
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")));
15555
+ ), /* @__PURE__ */ React30.createElement(Box26, { flexDirection: "column", marginTop: 1, paddingX: 1 }, /* @__PURE__ */ React30.createElement(Box26, { justifyContent: "space-between" }, /* @__PURE__ */ React30.createElement(Text23, { color: "cyan", bold: true }, progressLabel), meta ? /* @__PURE__ */ React30.createElement(Text23, { dimColor: true }, meta.source, meta.task ? ` \xB7 ${meta.task}` : "", meta.mode ? ` \xB7 ${meta.mode}` : "") : null), currentPage ? /* @__PURE__ */ React30.createElement(Static3, { items: currentPage.records.map((rec, i) => ({ key: `${idx}-${i}`, rec })) }, ({ key, rec }) => /* @__PURE__ */ React30.createElement(RecordView, { key, rec })) : /* @__PURE__ */ React30.createElement(Text23, { dimColor: true, italic: true }, "no records")), /* @__PURE__ */ React30.createElement(Box26, { marginTop: 1, paddingX: 1, borderStyle: "single", borderColor: "gray" }, /* @__PURE__ */ React30.createElement(Text23, { dimColor: true }, /* @__PURE__ */ React30.createElement(Text23, { bold: true }, "j"), "/", /* @__PURE__ */ React30.createElement(Text23, { bold: true }, "\u2193"), "/", /* @__PURE__ */ React30.createElement(Text23, { bold: true }, "space"), " next \xB7 ", /* @__PURE__ */ React30.createElement(Text23, { bold: true }, "k"), "/", /* @__PURE__ */ React30.createElement(Text23, { bold: true }, "\u2191"), " prev \xB7 ", /* @__PURE__ */ React30.createElement(Text23, { bold: true }, "g"), " first \xB7 ", /* @__PURE__ */ React30.createElement(Text23, { bold: true }, "G"), " last \xB7", " ", /* @__PURE__ */ React30.createElement(Text23, { bold: true }, "q"), " quit")));
15265
15556
  }
15266
15557
 
15267
15558
  // src/cli/commands/replay.ts
@@ -15273,7 +15564,7 @@ async function replayCommand(opts) {
15273
15564
  }
15274
15565
  const { parsed } = replayFromFile(opts.path);
15275
15566
  const pages = groupRecordsByTurn(parsed.records);
15276
- const { waitUntilExit } = render3(React30.createElement(ReplayApp, { meta: parsed.meta, pages }), {
15567
+ const { waitUntilExit } = render3(React31.createElement(ReplayApp, { meta: parsed.meta, pages }), {
15277
15568
  exitOnCtrlC: true,
15278
15569
  patchConsole: false
15279
15570
  });
@@ -15578,12 +15869,12 @@ function truncate3(s, max) {
15578
15869
 
15579
15870
  // src/cli/commands/setup.tsx
15580
15871
  import { render as render4 } from "ink";
15581
- import React32 from "react";
15872
+ import React33 from "react";
15582
15873
 
15583
15874
  // src/cli/ui/Wizard.tsx
15584
- import { Box as Box26, Text as Text25, useApp as useApp5, useInput as useInput3 } from "ink";
15875
+ import { Box as Box27, Text as Text24, useApp as useApp5, useInput as useInput3 } from "ink";
15585
15876
  import TextInput2 from "ink-text-input";
15586
- import React31, { useState as useState15 } from "react";
15877
+ import React32, { useState as useState15 } from "react";
15587
15878
 
15588
15879
  // src/cli/ui/presets.ts
15589
15880
  var PRESETS = {
@@ -15631,7 +15922,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
15631
15922
  if (key.escape && step !== "saved" && onCancel) onCancel();
15632
15923
  });
15633
15924
  if (step === "apiKey") {
15634
- return /* @__PURE__ */ React31.createElement(
15925
+ return /* @__PURE__ */ React32.createElement(
15635
15926
  ApiKeyStep,
15636
15927
  {
15637
15928
  onSubmit: (key) => {
@@ -15645,7 +15936,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
15645
15936
  );
15646
15937
  }
15647
15938
  if (step === "preset") {
15648
- return /* @__PURE__ */ React31.createElement(StepFrame, { title: "Pick a preset", step: 1, total: 3 }, /* @__PURE__ */ React31.createElement(
15939
+ return /* @__PURE__ */ React32.createElement(StepFrame, { title: "Pick a preset", step: 1, total: 3 }, /* @__PURE__ */ React32.createElement(
15649
15940
  SingleSelect,
15650
15941
  {
15651
15942
  items: presetItems(),
@@ -15655,10 +15946,10 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
15655
15946
  setStep("mcp");
15656
15947
  }
15657
15948
  }
15658
- ), /* @__PURE__ */ React31.createElement(Box26, { marginTop: 1 }, /* @__PURE__ */ React31.createElement(Text25, { dimColor: true }, "[\u2191\u2193] navigate \xB7 [Enter] confirm \xB7 [Esc] cancel")));
15949
+ ), /* @__PURE__ */ React32.createElement(Box27, { marginTop: 1 }, /* @__PURE__ */ React32.createElement(Text24, { dimColor: true }, "[\u2191\u2193] navigate \xB7 [Enter] confirm \xB7 [Esc] cancel")));
15659
15950
  }
15660
15951
  if (step === "mcp") {
15661
- return /* @__PURE__ */ React31.createElement(StepFrame, { title: "Which MCP servers should Reasonix wire up for you?", step: 2, total: 3 }, /* @__PURE__ */ React31.createElement(
15952
+ return /* @__PURE__ */ React32.createElement(StepFrame, { title: "Which MCP servers should Reasonix wire up for you?", step: 2, total: 3 }, /* @__PURE__ */ React32.createElement(
15662
15953
  MultiSelect,
15663
15954
  {
15664
15955
  items: mcpItems(),
@@ -15683,7 +15974,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
15683
15974
  }
15684
15975
  const currentName = pending[0];
15685
15976
  const entry = CATALOG_BY_NAME.get(currentName);
15686
- return /* @__PURE__ */ React31.createElement(
15977
+ return /* @__PURE__ */ React32.createElement(
15687
15978
  McpArgsStep,
15688
15979
  {
15689
15980
  entry,
@@ -15701,7 +15992,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
15701
15992
  }
15702
15993
  if (step === "review") {
15703
15994
  const specs = data.selectedCatalog.map((name) => buildSpec(name, data.catalogArgs));
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(
15995
+ return /* @__PURE__ */ React32.createElement(StepFrame, { title: "Ready to save", step: 3, total: 3 }, /* @__PURE__ */ React32.createElement(Box27, { flexDirection: "column" }, /* @__PURE__ */ React32.createElement(SummaryLine, { label: "API key", value: redactKey(data.apiKey) }), /* @__PURE__ */ React32.createElement(SummaryLine, { label: "Preset", value: data.preset }), /* @__PURE__ */ React32.createElement(
15705
15996
  SummaryLine,
15706
15997
  {
15707
15998
  label: "MCP",
@@ -15709,8 +16000,8 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
15709
16000
  }
15710
16001
  ), specs.map((spec, i) => (
15711
16002
  // biome-ignore lint/suspicious/noArrayIndexKey: review-only render, order fixed
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(
16003
+ /* @__PURE__ */ React32.createElement(Box27, { key: i, paddingLeft: 14 }, /* @__PURE__ */ React32.createElement(Text24, { dimColor: true }, "\xB7 ", spec))
16004
+ )), /* @__PURE__ */ React32.createElement(Box27, { marginTop: 1 }, /* @__PURE__ */ React32.createElement(Text24, null, "Saves to ", defaultConfigPath())), error ? /* @__PURE__ */ React32.createElement(Box27, { marginTop: 1 }, /* @__PURE__ */ React32.createElement(Text24, { color: "red" }, error)) : null, /* @__PURE__ */ React32.createElement(Box27, { marginTop: 1 }, /* @__PURE__ */ React32.createElement(Text24, { dimColor: true }, "[Enter] save \xB7 [Esc] cancel"))), /* @__PURE__ */ React32.createElement(
15714
16005
  ReviewConfirm,
15715
16006
  {
15716
16007
  onConfirm: () => {
@@ -15736,7 +16027,7 @@ function Wizard({ onComplete, onCancel, existingApiKey, initial }) {
15736
16027
  }
15737
16028
  ));
15738
16029
  }
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 }));
16030
+ return /* @__PURE__ */ React32.createElement(Box27, { flexDirection: "column", borderStyle: "round", borderColor: "green", paddingX: 1 }, /* @__PURE__ */ React32.createElement(Text24, { bold: true, color: "green" }, "\u25B8 Saved."), /* @__PURE__ */ React32.createElement(Box27, { marginTop: 1 }, /* @__PURE__ */ React32.createElement(Text24, null, "Run `reasonix` any time to start chatting \u2014 your settings are remembered.")), /* @__PURE__ */ React32.createElement(Box27, { marginTop: 1 }, /* @__PURE__ */ React32.createElement(Text24, { dimColor: true }, "[Enter] to exit")), /* @__PURE__ */ React32.createElement(ExitOnEnter, { onExit: exit2 }));
15740
16031
  }
15741
16032
  function ApiKeyStep({
15742
16033
  onSubmit,
@@ -15744,7 +16035,7 @@ function ApiKeyStep({
15744
16035
  onError
15745
16036
  }) {
15746
16037
  const [value, setValue] = useState15("");
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(
16038
+ return /* @__PURE__ */ React32.createElement(Box27, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React32.createElement(Text24, { bold: true, color: "cyan" }, "Welcome to Reasonix."), /* @__PURE__ */ React32.createElement(Box27, { marginTop: 1 }, /* @__PURE__ */ React32.createElement(Text24, null, "Paste your DeepSeek API key to get started.")), /* @__PURE__ */ React32.createElement(Text24, { dimColor: true }, "Get one (free credit on signup): https://platform.deepseek.com/api_keys"), /* @__PURE__ */ React32.createElement(Text24, { dimColor: true }, "Saved locally to ", defaultConfigPath()), /* @__PURE__ */ React32.createElement(Box27, { marginTop: 1 }, /* @__PURE__ */ React32.createElement(Text24, { bold: true, color: "cyan" }, "key \u203A "), /* @__PURE__ */ React32.createElement(
15748
16039
  TextInput2,
15749
16040
  {
15750
16041
  value,
@@ -15761,7 +16052,7 @@ function ApiKeyStep({
15761
16052
  mask: "\u2022",
15762
16053
  placeholder: "sk-..."
15763
16054
  }
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);
16055
+ )), error ? /* @__PURE__ */ React32.createElement(Box27, { marginTop: 1 }, /* @__PURE__ */ React32.createElement(Text24, { color: "red" }, error)) : value ? /* @__PURE__ */ React32.createElement(Box27, { marginTop: 1 }, /* @__PURE__ */ React32.createElement(Text24, { dimColor: true }, "preview: ", redactKey(value))) : null);
15765
16056
  }
15766
16057
  function McpArgsStep({
15767
16058
  entry,
@@ -15770,7 +16061,7 @@ function McpArgsStep({
15770
16061
  onError
15771
16062
  }) {
15772
16063
  const [value, setValue] = useState15("");
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(
16064
+ return /* @__PURE__ */ React32.createElement(StepFrame, { title: `Configure ${entry.name}`, step: 2, total: 3 }, /* @__PURE__ */ React32.createElement(Box27, { flexDirection: "column" }, /* @__PURE__ */ React32.createElement(Text24, null, entry.summary), entry.note ? /* @__PURE__ */ React32.createElement(Box27, { marginTop: 1 }, /* @__PURE__ */ React32.createElement(Text24, { dimColor: true }, entry.note)) : null, /* @__PURE__ */ React32.createElement(Box27, { marginTop: 1 }, /* @__PURE__ */ React32.createElement(Text24, null, "Required parameter: "), /* @__PURE__ */ React32.createElement(Text24, { bold: true }, entry.userArgs)), /* @__PURE__ */ React32.createElement(Box27, { marginTop: 1 }, /* @__PURE__ */ React32.createElement(Text24, { bold: true, color: "cyan" }, entry.userArgs, " \u203A "), /* @__PURE__ */ React32.createElement(
15774
16065
  TextInput2,
15775
16066
  {
15776
16067
  value,
@@ -15786,7 +16077,7 @@ function McpArgsStep({
15786
16077
  },
15787
16078
  placeholder: placeholderFor(entry)
15788
16079
  }
15789
- )), error ? /* @__PURE__ */ React31.createElement(Box26, { marginTop: 1 }, /* @__PURE__ */ React31.createElement(Text25, { color: "red" }, error)) : null));
16080
+ )), error ? /* @__PURE__ */ React32.createElement(Box27, { marginTop: 1 }, /* @__PURE__ */ React32.createElement(Text24, { color: "red" }, error)) : null));
15790
16081
  }
15791
16082
  function ReviewConfirm({ onConfirm }) {
15792
16083
  useInput3((_i, key) => {
@@ -15806,10 +16097,10 @@ function StepFrame({
15806
16097
  total,
15807
16098
  children
15808
16099
  }) {
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));
16100
+ return /* @__PURE__ */ React32.createElement(Box27, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React32.createElement(Box27, null, /* @__PURE__ */ React32.createElement(Text24, { dimColor: true }, "Step ", step, "/", total, " \xB7", " "), /* @__PURE__ */ React32.createElement(Text24, { bold: true, color: "cyan" }, title)), /* @__PURE__ */ React32.createElement(Box27, { marginTop: 1, flexDirection: "column" }, children));
15810
16101
  }
15811
16102
  function SummaryLine({ label, value }) {
15812
- return /* @__PURE__ */ React31.createElement(Box26, null, /* @__PURE__ */ React31.createElement(Text25, null, label.padEnd(12)), /* @__PURE__ */ React31.createElement(Text25, { bold: true }, value));
16103
+ return /* @__PURE__ */ React32.createElement(Box27, null, /* @__PURE__ */ React32.createElement(Text24, null, label.padEnd(12)), /* @__PURE__ */ React32.createElement(Text24, { bold: true }, value));
15813
16104
  }
15814
16105
  function presetItems() {
15815
16106
  return ["fast", "smart", "max"].map((name) => ({
@@ -15865,7 +16156,7 @@ async function setupCommand(_opts = {}) {
15865
16156
  const existingKey = loadApiKey();
15866
16157
  const existing = readConfig();
15867
16158
  const { waitUntilExit, unmount } = render4(
15868
- /* @__PURE__ */ React32.createElement(
16159
+ /* @__PURE__ */ React33.createElement(
15869
16160
  Wizard,
15870
16161
  {
15871
16162
  existingApiKey: existingKey,