@claude-code-kit/ui 0.1.0 → 0.1.1

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/index.mjs CHANGED
@@ -5,7 +5,7 @@ export * from "@claude-code-kit/ink-renderer";
5
5
  import { useContext } from "react";
6
6
  import { Text, Ansi, TerminalSizeContext, stringWidth } from "@claude-code-kit/ink-renderer";
7
7
  import { jsx, jsxs } from "react/jsx-runtime";
8
- function Divider({ width, color, char = "\u2500", padding = 0, title }) {
8
+ function Divider({ width, color: color2, char = "\u2500", padding = 0, title }) {
9
9
  const terminalSize = useContext(TerminalSizeContext);
10
10
  const terminalWidth = terminalSize?.columns ?? 80;
11
11
  const effectiveWidth = Math.max(0, (width ?? terminalWidth - 2) - padding);
@@ -14,7 +14,7 @@ function Divider({ width, color, char = "\u2500", padding = 0, title }) {
14
14
  const sideWidth = Math.max(0, effectiveWidth - titleWidth);
15
15
  const leftWidth = Math.floor(sideWidth / 2);
16
16
  const rightWidth = sideWidth - leftWidth;
17
- return /* @__PURE__ */ jsxs(Text, { color, dimColor: !color, children: [
17
+ return /* @__PURE__ */ jsxs(Text, { color: color2, dimColor: !color2, children: [
18
18
  char.repeat(leftWidth),
19
19
  " ",
20
20
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: /* @__PURE__ */ jsx(Ansi, { children: title }) }),
@@ -22,7 +22,7 @@ function Divider({ width, color, char = "\u2500", padding = 0, title }) {
22
22
  char.repeat(rightWidth)
23
23
  ] });
24
24
  }
25
- return /* @__PURE__ */ jsx(Text, { color, dimColor: !color, children: char.repeat(effectiveWidth) });
25
+ return /* @__PURE__ */ jsx(Text, { color: color2, dimColor: !color2, children: char.repeat(effectiveWidth) });
26
26
  }
27
27
 
28
28
  // src/ProgressBar.tsx
@@ -365,10 +365,13 @@ function parseBindings(blocks) {
365
365
 
366
366
  // src/keybindings/resolver.ts
367
367
  function getBindingDisplayText(action, context, bindings) {
368
- const binding = bindings.findLast(
369
- (b) => b.action === action && b.context === context
370
- );
371
- return binding ? chordToString(binding.chord) : void 0;
368
+ for (let i = bindings.length - 1; i >= 0; i--) {
369
+ const binding = bindings[i];
370
+ if (binding && binding.action === action && binding.context === context) {
371
+ return chordToString(binding.chord);
372
+ }
373
+ }
374
+ return void 0;
372
375
  }
373
376
  function buildKeystroke(input, key) {
374
377
  const keyName = getKeyName(input, key);
@@ -1706,8 +1709,62 @@ function ChordInterceptor({
1706
1709
  return null;
1707
1710
  }
1708
1711
 
1712
+ // src/hooks/useDoublePress.ts
1713
+ import { useCallback as useCallback3, useEffect as useEffect4, useRef as useRef2 } from "react";
1714
+ var DOUBLE_PRESS_TIMEOUT_MS = 800;
1715
+ function useDoublePress(setPending, onDoublePress, onFirstPress) {
1716
+ const lastPressRef = useRef2(0);
1717
+ const timeoutRef = useRef2(void 0);
1718
+ const clearTimeoutSafe = useCallback3(() => {
1719
+ if (timeoutRef.current) {
1720
+ clearTimeout(timeoutRef.current);
1721
+ timeoutRef.current = void 0;
1722
+ }
1723
+ }, []);
1724
+ useEffect4(() => {
1725
+ return () => {
1726
+ clearTimeoutSafe();
1727
+ };
1728
+ }, [clearTimeoutSafe]);
1729
+ return useCallback3(() => {
1730
+ const now = Date.now();
1731
+ const timeSinceLastPress = now - lastPressRef.current;
1732
+ const isDoublePress = timeSinceLastPress <= DOUBLE_PRESS_TIMEOUT_MS && timeoutRef.current !== void 0;
1733
+ if (isDoublePress) {
1734
+ clearTimeoutSafe();
1735
+ setPending(false);
1736
+ onDoublePress();
1737
+ } else {
1738
+ onFirstPress?.();
1739
+ setPending(true);
1740
+ clearTimeoutSafe();
1741
+ timeoutRef.current = setTimeout(
1742
+ (setPending2, timeoutRef2) => {
1743
+ setPending2(false);
1744
+ timeoutRef2.current = void 0;
1745
+ },
1746
+ DOUBLE_PRESS_TIMEOUT_MS,
1747
+ setPending,
1748
+ timeoutRef
1749
+ );
1750
+ }
1751
+ lastPressRef.current = now;
1752
+ }, [setPending, onDoublePress, onFirstPress, clearTimeoutSafe]);
1753
+ }
1754
+
1755
+ // src/hooks/useTerminalSize.ts
1756
+ import { useContext as useContext3 } from "react";
1757
+ import { TerminalSizeContext as TerminalSizeContext2 } from "@claude-code-kit/ink-renderer";
1758
+ function useTerminalSize() {
1759
+ const size = useContext3(TerminalSizeContext2);
1760
+ if (!size) {
1761
+ throw new Error("useTerminalSize must be used within an Ink App component");
1762
+ }
1763
+ return size;
1764
+ }
1765
+
1709
1766
  // src/PromptInput.tsx
1710
- import { useState as useState3, useCallback as useCallback3 } from "react";
1767
+ import { useState as useState3, useCallback as useCallback4 } from "react";
1711
1768
  import { Text as Text5, Box as Box2, useInput as useInput3 } from "@claude-code-kit/ink-renderer";
1712
1769
  import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
1713
1770
  function PromptInput({
@@ -1728,7 +1785,7 @@ function PromptInput({
1728
1785
  const [showSuggestions, setShowSuggestions] = useState3(false);
1729
1786
  const suggestions = value.startsWith("/") && commands.length > 0 ? commands.filter((cmd) => `/${cmd.name}`.startsWith(value)) : [];
1730
1787
  const hasSuggestions = showSuggestions && suggestions.length > 0;
1731
- const updateValue = useCallback3(
1788
+ const updateValue = useCallback4(
1732
1789
  (newValue, newCursor) => {
1733
1790
  onChange(newValue);
1734
1791
  setCursor(newCursor ?? newValue.length);
@@ -1896,7 +1953,7 @@ function PromptInput({
1896
1953
  }
1897
1954
 
1898
1955
  // src/Spinner.tsx
1899
- import { useState as useState4, useEffect as useEffect4, useRef as useRef2 } from "react";
1956
+ import { useState as useState4, useEffect as useEffect5, useRef as useRef3 } from "react";
1900
1957
  import { Text as Text6, Box as Box3 } from "@claude-code-kit/ink-renderer";
1901
1958
  import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
1902
1959
  var FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
@@ -1908,22 +1965,22 @@ function Spinner({
1908
1965
  label,
1909
1966
  verb,
1910
1967
  verbs,
1911
- color = DEFAULT_COLOR,
1968
+ color: color2 = DEFAULT_COLOR,
1912
1969
  showElapsed = true
1913
1970
  }) {
1914
1971
  const [frameIndex, setFrameIndex] = useState4(0);
1915
1972
  const [verbIndex, setVerbIndex] = useState4(0);
1916
1973
  const [elapsed, setElapsed] = useState4(0);
1917
- const startRef = useRef2(Date.now());
1974
+ const startRef = useRef3(Date.now());
1918
1975
  const allVerbs = verbs ?? (verb ? [verb] : ["Thinking"]);
1919
- useEffect4(() => {
1976
+ useEffect5(() => {
1920
1977
  const id = setInterval(() => {
1921
1978
  setFrameIndex((i) => (i + 1) % FRAMES.length);
1922
1979
  setElapsed(Date.now() - startRef.current);
1923
1980
  }, SPINNER_INTERVAL);
1924
1981
  return () => clearInterval(id);
1925
1982
  }, []);
1926
- useEffect4(() => {
1983
+ useEffect5(() => {
1927
1984
  if (allVerbs.length <= 1) return;
1928
1985
  const id = setInterval(() => {
1929
1986
  setVerbIndex((i) => (i + 1) % allVerbs.length);
@@ -1935,7 +1992,7 @@ function Spinner({
1935
1992
  const elapsedSec = Math.floor(elapsed / 1e3);
1936
1993
  const showTime = showElapsed && elapsed >= ELAPSED_SHOW_AFTER;
1937
1994
  return /* @__PURE__ */ jsxs5(Box3, { children: [
1938
- /* @__PURE__ */ jsx7(Text6, { color, children: frame }),
1995
+ /* @__PURE__ */ jsx7(Text6, { color: color2, children: frame }),
1939
1996
  /* @__PURE__ */ jsxs5(Text6, { children: [
1940
1997
  " ",
1941
1998
  currentVerb,
@@ -1953,29 +2010,766 @@ function Spinner({
1953
2010
  ] });
1954
2011
  }
1955
2012
 
2013
+ // src/Markdown.tsx
2014
+ import { marked as marked2 } from "marked";
2015
+ import { Suspense, use, useMemo as useMemo3, useRef as useRef4 } from "react";
2016
+ import { Ansi as Ansi4, Box as Box4 } from "@claude-code-kit/ink-renderer";
2017
+
2018
+ // src/design-system/ThemeProvider.tsx
2019
+ import { createContext as createContext2, useContext as useContext4, useMemo as useMemo2, useState as useState5 } from "react";
2020
+ import { jsx as jsx8 } from "react/jsx-runtime";
2021
+ var themes = {
2022
+ dark: {
2023
+ text: "#E0E0E0",
2024
+ dimText: "#666666",
2025
+ border: "#444444",
2026
+ accent: "#5B9BD5",
2027
+ success: "#6BC76B",
2028
+ warning: "#E5C07B",
2029
+ error: "#E06C75",
2030
+ assistant: "#DA7756",
2031
+ inactive: "#666666",
2032
+ inverseText: "#1E1E1E",
2033
+ permission: "#5B9BD5"
2034
+ },
2035
+ light: {
2036
+ text: "#1E1E1E",
2037
+ dimText: "#999999",
2038
+ border: "#CCCCCC",
2039
+ accent: "#0066CC",
2040
+ success: "#2E7D32",
2041
+ warning: "#F57C00",
2042
+ error: "#C62828",
2043
+ assistant: "#DA7756",
2044
+ inactive: "#999999",
2045
+ inverseText: "#FFFFFF",
2046
+ permission: "#0066CC"
2047
+ }
2048
+ };
2049
+ function getTheme(name) {
2050
+ return themes[name] ?? themes.dark;
2051
+ }
2052
+ var DEFAULT_THEME = "dark";
2053
+ var ThemeContext = createContext2({
2054
+ themeSetting: DEFAULT_THEME,
2055
+ setThemeSetting: () => {
2056
+ },
2057
+ setPreviewTheme: () => {
2058
+ },
2059
+ savePreview: () => {
2060
+ },
2061
+ cancelPreview: () => {
2062
+ },
2063
+ currentTheme: DEFAULT_THEME
2064
+ });
2065
+ function ThemeProvider({
2066
+ children,
2067
+ initialState = "dark",
2068
+ onThemeSave
2069
+ }) {
2070
+ const [themeSetting, setThemeSetting] = useState5(initialState);
2071
+ const [previewTheme, setPreviewTheme] = useState5(null);
2072
+ const activeSetting = previewTheme ?? themeSetting;
2073
+ const currentTheme = activeSetting === "auto" ? "dark" : activeSetting;
2074
+ const value = useMemo2(
2075
+ () => ({
2076
+ themeSetting,
2077
+ setThemeSetting: (newSetting) => {
2078
+ setThemeSetting(newSetting);
2079
+ setPreviewTheme(null);
2080
+ onThemeSave?.(newSetting);
2081
+ },
2082
+ setPreviewTheme: (newSetting) => {
2083
+ setPreviewTheme(newSetting);
2084
+ },
2085
+ savePreview: () => {
2086
+ if (previewTheme !== null) {
2087
+ setThemeSetting(previewTheme);
2088
+ setPreviewTheme(null);
2089
+ onThemeSave?.(previewTheme);
2090
+ }
2091
+ },
2092
+ cancelPreview: () => {
2093
+ if (previewTheme !== null) {
2094
+ setPreviewTheme(null);
2095
+ }
2096
+ },
2097
+ currentTheme
2098
+ }),
2099
+ [themeSetting, previewTheme, currentTheme, onThemeSave]
2100
+ );
2101
+ return /* @__PURE__ */ jsx8(ThemeContext.Provider, { value, children });
2102
+ }
2103
+ function useTheme() {
2104
+ const { currentTheme, setThemeSetting } = useContext4(ThemeContext);
2105
+ return [currentTheme, setThemeSetting];
2106
+ }
2107
+ function useThemeSetting() {
2108
+ return useContext4(ThemeContext).themeSetting;
2109
+ }
2110
+ function usePreviewTheme() {
2111
+ const { setPreviewTheme, savePreview, cancelPreview } = useContext4(ThemeContext);
2112
+ return { setPreviewTheme, savePreview, cancelPreview };
2113
+ }
2114
+
2115
+ // src/utils/optional/cliHighlight.ts
2116
+ var cliHighlightPromise;
2117
+ async function loadCliHighlight() {
2118
+ try {
2119
+ const cliHighlight = await import("cli-highlight");
2120
+ return {
2121
+ highlight: cliHighlight.highlight,
2122
+ supportsLanguage: cliHighlight.supportsLanguage
2123
+ };
2124
+ } catch {
2125
+ return null;
2126
+ }
2127
+ }
2128
+ function getCliHighlightPromise() {
2129
+ cliHighlightPromise ?? (cliHighlightPromise = loadCliHighlight());
2130
+ return cliHighlightPromise;
2131
+ }
2132
+
2133
+ // src/utils/hash.ts
2134
+ function hashContent(content) {
2135
+ let h = 2166136261 | 0;
2136
+ for (let i = 0; i < content.length; i++) {
2137
+ h ^= content.charCodeAt(i);
2138
+ h = Math.imul(h, 16777619);
2139
+ }
2140
+ let h2 = 26499749718 | 0;
2141
+ for (let i = 0; i < content.length; i++) {
2142
+ h2 ^= content.charCodeAt(i);
2143
+ h2 = Math.imul(h2, 16777619);
2144
+ }
2145
+ return ((h >>> 0) * 1048576 + (h2 >>> 0)).toString(36) + content.length.toString(36);
2146
+ }
2147
+
2148
+ // src/utils/markdown.ts
2149
+ import chalk from "chalk";
2150
+ import { marked } from "marked";
2151
+ import stripAnsi from "strip-ansi";
2152
+ import { stringWidth as stringWidth2 } from "@claude-code-kit/ink-renderer";
2153
+
2154
+ // src/design-system/color.ts
2155
+ import { colorize } from "@claude-code-kit/ink-renderer";
2156
+ function color(c, theme, type = "foreground") {
2157
+ return (text) => {
2158
+ if (!c) {
2159
+ return text;
2160
+ }
2161
+ if (c.startsWith("rgb(") || c.startsWith("#") || c.startsWith("ansi256(") || c.startsWith("ansi:")) {
2162
+ return colorize(text, c, type);
2163
+ }
2164
+ return colorize(text, getTheme(theme)[c], type);
2165
+ };
2166
+ }
2167
+
2168
+ // src/utils/markdown.ts
2169
+ function logForDebugging3(...args) {
2170
+ if (process.env["DEBUG"]) {
2171
+ console.debug(...args);
2172
+ }
2173
+ }
2174
+ var EOL = "\n";
2175
+ var BLOCKQUOTE_BAR = "\u258E";
2176
+ var OSC8_START = "\x1B]8;;";
2177
+ var OSC8_END = "\x07";
2178
+ function supportsHyperlinks() {
2179
+ const termProgram = process.env["TERM_PROGRAM"];
2180
+ const lcTerminal = process.env["LC_TERMINAL"];
2181
+ const term = process.env["TERM"];
2182
+ const supported = ["ghostty", "Hyper", "kitty", "alacritty", "iTerm.app", "iTerm2"];
2183
+ return !!(termProgram && supported.includes(termProgram)) || !!(lcTerminal && supported.includes(lcTerminal)) || !!term?.includes("kitty");
2184
+ }
2185
+ function createHyperlink(url, content) {
2186
+ if (!supportsHyperlinks()) {
2187
+ return url;
2188
+ }
2189
+ const displayText = content ?? url;
2190
+ const coloredText = chalk.blue(displayText);
2191
+ return `${OSC8_START}${url}${OSC8_END}${coloredText}${OSC8_START}${OSC8_END}`;
2192
+ }
2193
+ var markedConfigured = false;
2194
+ function configureMarked() {
2195
+ if (markedConfigured) return;
2196
+ markedConfigured = true;
2197
+ marked.use({
2198
+ tokenizer: {
2199
+ del() {
2200
+ return void 0;
2201
+ }
2202
+ }
2203
+ });
2204
+ }
2205
+ function formatToken(token, theme, listDepth = 0, orderedListNumber = null, parent = null, highlight = null) {
2206
+ switch (token.type) {
2207
+ case "blockquote": {
2208
+ const inner = (token.tokens ?? []).map((_) => formatToken(_, theme, 0, null, null, highlight)).join("");
2209
+ const bar = chalk.dim(BLOCKQUOTE_BAR);
2210
+ return inner.split(EOL).map(
2211
+ (line) => stripAnsi(line).trim() ? `${bar} ${chalk.italic(line)}` : line
2212
+ ).join(EOL);
2213
+ }
2214
+ case "code": {
2215
+ if (!highlight) {
2216
+ return token.text + EOL;
2217
+ }
2218
+ let language = "plaintext";
2219
+ if (token.lang) {
2220
+ if (highlight.supportsLanguage(token.lang)) {
2221
+ language = token.lang;
2222
+ } else {
2223
+ logForDebugging3(
2224
+ `Language not supported while highlighting code, falling back to plaintext: ${token.lang}`
2225
+ );
2226
+ }
2227
+ }
2228
+ return highlight.highlight(token.text, { language }) + EOL;
2229
+ }
2230
+ case "codespan": {
2231
+ return color("permission", theme)(token.text);
2232
+ }
2233
+ case "em":
2234
+ return chalk.italic(
2235
+ (token.tokens ?? []).map((_) => formatToken(_, theme, 0, null, parent, highlight)).join("")
2236
+ );
2237
+ case "strong":
2238
+ return chalk.bold(
2239
+ (token.tokens ?? []).map((_) => formatToken(_, theme, 0, null, parent, highlight)).join("")
2240
+ );
2241
+ case "heading":
2242
+ switch (token.depth) {
2243
+ case 1:
2244
+ return chalk.bold.italic.underline(
2245
+ (token.tokens ?? []).map((_) => formatToken(_, theme, 0, null, null, highlight)).join("")
2246
+ ) + EOL + EOL;
2247
+ case 2:
2248
+ return chalk.bold(
2249
+ (token.tokens ?? []).map((_) => formatToken(_, theme, 0, null, null, highlight)).join("")
2250
+ ) + EOL + EOL;
2251
+ default:
2252
+ return chalk.bold(
2253
+ (token.tokens ?? []).map((_) => formatToken(_, theme, 0, null, null, highlight)).join("")
2254
+ ) + EOL + EOL;
2255
+ }
2256
+ case "hr":
2257
+ return "---";
2258
+ case "image":
2259
+ return token.href;
2260
+ case "link": {
2261
+ if (token.href.startsWith("mailto:")) {
2262
+ const email = token.href.replace(/^mailto:/, "");
2263
+ return email;
2264
+ }
2265
+ const linkText = (token.tokens ?? []).map((_) => formatToken(_, theme, 0, null, token, highlight)).join("");
2266
+ const plainLinkText = stripAnsi(linkText);
2267
+ if (plainLinkText && plainLinkText !== token.href) {
2268
+ return createHyperlink(token.href, linkText);
2269
+ }
2270
+ return createHyperlink(token.href);
2271
+ }
2272
+ case "list": {
2273
+ return token.items.map(
2274
+ (_, index) => formatToken(
2275
+ _,
2276
+ theme,
2277
+ listDepth,
2278
+ token.ordered ? token.start + index : null,
2279
+ token,
2280
+ highlight
2281
+ )
2282
+ ).join("");
2283
+ }
2284
+ case "list_item":
2285
+ return (token.tokens ?? []).map(
2286
+ (_) => `${" ".repeat(listDepth)}${formatToken(_, theme, listDepth + 1, orderedListNumber, token, highlight)}`
2287
+ ).join("");
2288
+ case "paragraph":
2289
+ return (token.tokens ?? []).map((_) => formatToken(_, theme, 0, null, null, highlight)).join("") + EOL;
2290
+ case "space":
2291
+ return EOL;
2292
+ case "br":
2293
+ return EOL;
2294
+ case "text":
2295
+ if (parent?.type === "link") {
2296
+ return token.text;
2297
+ }
2298
+ if (parent?.type === "list_item") {
2299
+ return `${orderedListNumber === null ? "-" : getListNumber(listDepth, orderedListNumber) + "."} ${token.tokens ? token.tokens.map((_) => formatToken(_, theme, listDepth, orderedListNumber, token, highlight)).join("") : linkifyIssueReferences(token.text)}${EOL}`;
2300
+ }
2301
+ return linkifyIssueReferences(token.text);
2302
+ case "table": {
2303
+ let getDisplayText2 = function(tokens) {
2304
+ return stripAnsi(
2305
+ tokens?.map((_) => formatToken(_, theme, 0, null, null, highlight)).join("") ?? ""
2306
+ );
2307
+ };
2308
+ var getDisplayText = getDisplayText2;
2309
+ const tableToken = token;
2310
+ const columnWidths = tableToken.header.map((header, index) => {
2311
+ let maxWidth = stringWidth2(getDisplayText2(header.tokens));
2312
+ for (const row of tableToken.rows) {
2313
+ const cellLength = stringWidth2(getDisplayText2(row[index]?.tokens));
2314
+ maxWidth = Math.max(maxWidth, cellLength);
2315
+ }
2316
+ return Math.max(maxWidth, 3);
2317
+ });
2318
+ let tableOutput = "| ";
2319
+ tableToken.header.forEach((header, index) => {
2320
+ const content = header.tokens?.map((_) => formatToken(_, theme, 0, null, null, highlight)).join("") ?? "";
2321
+ const displayText = getDisplayText2(header.tokens);
2322
+ const width = columnWidths[index];
2323
+ const align = tableToken.align?.[index];
2324
+ tableOutput += padAligned(content, stringWidth2(displayText), width, align) + " | ";
2325
+ });
2326
+ tableOutput = tableOutput.trimEnd() + EOL;
2327
+ tableOutput += "|";
2328
+ columnWidths.forEach((width) => {
2329
+ const separator = "-".repeat(width + 2);
2330
+ tableOutput += separator + "|";
2331
+ });
2332
+ tableOutput += EOL;
2333
+ tableToken.rows.forEach((row) => {
2334
+ tableOutput += "| ";
2335
+ row.forEach((cell, index) => {
2336
+ const content = cell.tokens?.map((_) => formatToken(_, theme, 0, null, null, highlight)).join("") ?? "";
2337
+ const displayText = getDisplayText2(cell.tokens);
2338
+ const width = columnWidths[index];
2339
+ const align = tableToken.align?.[index];
2340
+ tableOutput += padAligned(content, stringWidth2(displayText), width, align) + " | ";
2341
+ });
2342
+ tableOutput = tableOutput.trimEnd() + EOL;
2343
+ });
2344
+ return tableOutput + EOL;
2345
+ }
2346
+ case "escape":
2347
+ return token.text;
2348
+ case "def":
2349
+ case "del":
2350
+ case "html":
2351
+ return "";
2352
+ }
2353
+ return "";
2354
+ }
2355
+ var ISSUE_REF_PATTERN = /(^|[^\w./-])([A-Za-z0-9][\w-]*\/[A-Za-z0-9][\w.-]*)#(\d+)\b/g;
2356
+ function linkifyIssueReferences(text) {
2357
+ if (!supportsHyperlinks()) {
2358
+ return text;
2359
+ }
2360
+ return text.replace(
2361
+ ISSUE_REF_PATTERN,
2362
+ (_match, prefix, repo, num) => prefix + createHyperlink(
2363
+ `https://github.com/${repo}/issues/${num}`,
2364
+ `${repo}#${num}`
2365
+ )
2366
+ );
2367
+ }
2368
+ function numberToLetter(n) {
2369
+ let result = "";
2370
+ while (n > 0) {
2371
+ n--;
2372
+ result = String.fromCharCode(97 + n % 26) + result;
2373
+ n = Math.floor(n / 26);
2374
+ }
2375
+ return result;
2376
+ }
2377
+ var ROMAN_VALUES = [
2378
+ [1e3, "m"],
2379
+ [900, "cm"],
2380
+ [500, "d"],
2381
+ [400, "cd"],
2382
+ [100, "c"],
2383
+ [90, "xc"],
2384
+ [50, "l"],
2385
+ [40, "xl"],
2386
+ [10, "x"],
2387
+ [9, "ix"],
2388
+ [5, "v"],
2389
+ [4, "iv"],
2390
+ [1, "i"]
2391
+ ];
2392
+ function numberToRoman(n) {
2393
+ let result = "";
2394
+ for (const [value, numeral] of ROMAN_VALUES) {
2395
+ while (n >= value) {
2396
+ result += numeral;
2397
+ n -= value;
2398
+ }
2399
+ }
2400
+ return result;
2401
+ }
2402
+ function getListNumber(listDepth, orderedListNumber) {
2403
+ switch (listDepth) {
2404
+ case 0:
2405
+ case 1:
2406
+ return orderedListNumber.toString();
2407
+ case 2:
2408
+ return numberToLetter(orderedListNumber);
2409
+ case 3:
2410
+ return numberToRoman(orderedListNumber);
2411
+ default:
2412
+ return orderedListNumber.toString();
2413
+ }
2414
+ }
2415
+ function padAligned(content, displayWidth, targetWidth, align) {
2416
+ const padding = Math.max(0, targetWidth - displayWidth);
2417
+ if (align === "center") {
2418
+ const leftPad = Math.floor(padding / 2);
2419
+ return " ".repeat(leftPad) + content + " ".repeat(padding - leftPad);
2420
+ }
2421
+ if (align === "right") {
2422
+ return " ".repeat(padding) + content;
2423
+ }
2424
+ return content + " ".repeat(padding);
2425
+ }
2426
+
2427
+ // src/MarkdownTable.tsx
2428
+ import { useContext as useContext5 } from "react";
2429
+ import stripAnsi2 from "strip-ansi";
2430
+ import { TerminalSizeContext as TerminalSizeContext3 } from "@claude-code-kit/ink-renderer";
2431
+ import { stringWidth as stringWidth3 } from "@claude-code-kit/ink-renderer";
2432
+ import { wrapAnsi } from "@claude-code-kit/ink-renderer";
2433
+ import { Ansi as Ansi3 } from "@claude-code-kit/ink-renderer";
2434
+ import { jsx as jsx9 } from "react/jsx-runtime";
2435
+ var SAFETY_MARGIN = 4;
2436
+ var MIN_COLUMN_WIDTH = 3;
2437
+ var MAX_ROW_LINES = 4;
2438
+ var ANSI_BOLD_START = "\x1B[1m";
2439
+ var ANSI_BOLD_END = "\x1B[22m";
2440
+ function wrapText(text, width, options) {
2441
+ if (width <= 0) return [text];
2442
+ const trimmedText = text.trimEnd();
2443
+ const wrapped = wrapAnsi(trimmedText, width, {
2444
+ hard: options?.hard ?? false,
2445
+ trim: false,
2446
+ wordWrap: true
2447
+ });
2448
+ const lines = wrapped.split("\n").filter((line) => line.length > 0);
2449
+ return lines.length > 0 ? lines : [""];
2450
+ }
2451
+ function MarkdownTable({
2452
+ token,
2453
+ highlight,
2454
+ forceWidth
2455
+ }) {
2456
+ const [theme] = useTheme();
2457
+ const terminalSize = useContext5(TerminalSizeContext3);
2458
+ const actualTerminalWidth = terminalSize?.columns ?? 80;
2459
+ const terminalWidth = forceWidth ?? actualTerminalWidth;
2460
+ function formatCell(tokens) {
2461
+ return tokens?.map((_) => formatToken(_, theme, 0, null, null, highlight)).join("") ?? "";
2462
+ }
2463
+ function getPlainText(tokens_0) {
2464
+ return stripAnsi2(formatCell(tokens_0));
2465
+ }
2466
+ function getMinWidth(tokens_1) {
2467
+ const text = getPlainText(tokens_1);
2468
+ const words = text.split(/\s+/).filter((w) => w.length > 0);
2469
+ if (words.length === 0) return MIN_COLUMN_WIDTH;
2470
+ return Math.max(...words.map((w_0) => stringWidth3(w_0)), MIN_COLUMN_WIDTH);
2471
+ }
2472
+ function getIdealWidth(tokens_2) {
2473
+ return Math.max(stringWidth3(getPlainText(tokens_2)), MIN_COLUMN_WIDTH);
2474
+ }
2475
+ const minWidths = token.header.map((header, colIndex) => {
2476
+ let maxMinWidth = getMinWidth(header.tokens);
2477
+ for (const row of token.rows) {
2478
+ maxMinWidth = Math.max(maxMinWidth, getMinWidth(row[colIndex]?.tokens));
2479
+ }
2480
+ return maxMinWidth;
2481
+ });
2482
+ const idealWidths = token.header.map((header_0, colIndex_0) => {
2483
+ let maxIdeal = getIdealWidth(header_0.tokens);
2484
+ for (const row_0 of token.rows) {
2485
+ maxIdeal = Math.max(maxIdeal, getIdealWidth(row_0[colIndex_0]?.tokens));
2486
+ }
2487
+ return maxIdeal;
2488
+ });
2489
+ const numCols = token.header.length;
2490
+ const borderOverhead = 1 + numCols * 3;
2491
+ const availableWidth = Math.max(terminalWidth - borderOverhead - SAFETY_MARGIN, numCols * MIN_COLUMN_WIDTH);
2492
+ const totalMin = minWidths.reduce((sum, w_1) => sum + w_1, 0);
2493
+ const totalIdeal = idealWidths.reduce((sum_0, w_2) => sum_0 + w_2, 0);
2494
+ let needsHardWrap = false;
2495
+ let columnWidths;
2496
+ if (totalIdeal <= availableWidth) {
2497
+ columnWidths = idealWidths;
2498
+ } else if (totalMin <= availableWidth) {
2499
+ const extraSpace = availableWidth - totalMin;
2500
+ const overflows = idealWidths.map((ideal, i) => ideal - minWidths[i]);
2501
+ const totalOverflow = overflows.reduce((sum_1, o) => sum_1 + o, 0);
2502
+ columnWidths = minWidths.map((min, i_0) => {
2503
+ if (totalOverflow === 0) return min;
2504
+ const extra = Math.floor(overflows[i_0] / totalOverflow * extraSpace);
2505
+ return min + extra;
2506
+ });
2507
+ } else {
2508
+ needsHardWrap = true;
2509
+ const scaleFactor = availableWidth / totalMin;
2510
+ columnWidths = minWidths.map((w_3) => Math.max(Math.floor(w_3 * scaleFactor), MIN_COLUMN_WIDTH));
2511
+ }
2512
+ function calculateMaxRowLines() {
2513
+ let maxLines = 1;
2514
+ for (let i_1 = 0; i_1 < token.header.length; i_1++) {
2515
+ const content = formatCell(token.header[i_1].tokens);
2516
+ const wrapped = wrapText(content, columnWidths[i_1], {
2517
+ hard: needsHardWrap
2518
+ });
2519
+ maxLines = Math.max(maxLines, wrapped.length);
2520
+ }
2521
+ for (const row_1 of token.rows) {
2522
+ for (let i_2 = 0; i_2 < row_1.length; i_2++) {
2523
+ const content_0 = formatCell(row_1[i_2]?.tokens);
2524
+ const wrapped_0 = wrapText(content_0, columnWidths[i_2], {
2525
+ hard: needsHardWrap
2526
+ });
2527
+ maxLines = Math.max(maxLines, wrapped_0.length);
2528
+ }
2529
+ }
2530
+ return maxLines;
2531
+ }
2532
+ const maxRowLines = calculateMaxRowLines();
2533
+ const useVerticalFormat = maxRowLines > MAX_ROW_LINES;
2534
+ function renderRowLines(cells, isHeader) {
2535
+ const cellLines = cells.map((cell, colIndex_1) => {
2536
+ const formattedText = formatCell(cell.tokens);
2537
+ const width = columnWidths[colIndex_1];
2538
+ return wrapText(formattedText, width, {
2539
+ hard: needsHardWrap
2540
+ });
2541
+ });
2542
+ const maxLines_0 = Math.max(...cellLines.map((lines) => lines.length), 1);
2543
+ const verticalOffsets = cellLines.map((lines_0) => Math.floor((maxLines_0 - lines_0.length) / 2));
2544
+ const result = [];
2545
+ for (let lineIdx = 0; lineIdx < maxLines_0; lineIdx++) {
2546
+ let line = "\u2502";
2547
+ for (let colIndex_2 = 0; colIndex_2 < cells.length; colIndex_2++) {
2548
+ const lines_1 = cellLines[colIndex_2];
2549
+ const offset = verticalOffsets[colIndex_2];
2550
+ const contentLineIdx = lineIdx - offset;
2551
+ const lineText = contentLineIdx >= 0 && contentLineIdx < lines_1.length ? lines_1[contentLineIdx] : "";
2552
+ const width_0 = columnWidths[colIndex_2];
2553
+ const align = isHeader ? "center" : token.align?.[colIndex_2] ?? "left";
2554
+ line += " " + padAligned(lineText, stringWidth3(lineText), width_0, align) + " \u2502";
2555
+ }
2556
+ result.push(line);
2557
+ }
2558
+ return result;
2559
+ }
2560
+ function renderBorderLine(type) {
2561
+ const [left, mid, cross, right] = {
2562
+ top: ["\u250C", "\u2500", "\u252C", "\u2510"],
2563
+ middle: ["\u251C", "\u2500", "\u253C", "\u2524"],
2564
+ bottom: ["\u2514", "\u2500", "\u2534", "\u2518"]
2565
+ }[type];
2566
+ let line_0 = left;
2567
+ columnWidths.forEach((width_1, colIndex_3) => {
2568
+ line_0 += mid.repeat(width_1 + 2);
2569
+ line_0 += colIndex_3 < columnWidths.length - 1 ? cross : right;
2570
+ });
2571
+ return line_0;
2572
+ }
2573
+ function renderVerticalFormat() {
2574
+ const lines_2 = [];
2575
+ const headers = token.header.map((h) => getPlainText(h.tokens));
2576
+ const separatorWidth = Math.min(terminalWidth - 1, 40);
2577
+ const separator = "\u2500".repeat(separatorWidth);
2578
+ const wrapIndent = " ";
2579
+ token.rows.forEach((row_2, rowIndex) => {
2580
+ if (rowIndex > 0) {
2581
+ lines_2.push(separator);
2582
+ }
2583
+ row_2.forEach((cell_0, colIndex_4) => {
2584
+ const label = headers[colIndex_4] || `Column ${colIndex_4 + 1}`;
2585
+ const rawValue = formatCell(cell_0.tokens).trimEnd();
2586
+ const value = rawValue.replace(/\n+/g, " ").replace(/\s+/g, " ").trim();
2587
+ const firstLineWidth = terminalWidth - stringWidth3(label) - 3;
2588
+ const subsequentLineWidth = terminalWidth - wrapIndent.length - 1;
2589
+ const firstPassLines = wrapText(value, Math.max(firstLineWidth, 10));
2590
+ const firstLine = firstPassLines[0] || "";
2591
+ let wrappedValue;
2592
+ if (firstPassLines.length <= 1 || subsequentLineWidth <= firstLineWidth) {
2593
+ wrappedValue = firstPassLines;
2594
+ } else {
2595
+ const remainingText = firstPassLines.slice(1).map((l) => l.trim()).join(" ");
2596
+ const rewrapped = wrapText(remainingText, subsequentLineWidth);
2597
+ wrappedValue = [firstLine, ...rewrapped];
2598
+ }
2599
+ lines_2.push(`${ANSI_BOLD_START}${label}:${ANSI_BOLD_END} ${wrappedValue[0] || ""}`);
2600
+ for (let i_3 = 1; i_3 < wrappedValue.length; i_3++) {
2601
+ const line_1 = wrappedValue[i_3];
2602
+ if (!line_1.trim()) continue;
2603
+ lines_2.push(`${wrapIndent}${line_1}`);
2604
+ }
2605
+ });
2606
+ });
2607
+ return lines_2.join("\n");
2608
+ }
2609
+ if (useVerticalFormat) {
2610
+ return /* @__PURE__ */ jsx9(Ansi3, { children: renderVerticalFormat() });
2611
+ }
2612
+ const tableLines = [];
2613
+ tableLines.push(renderBorderLine("top"));
2614
+ tableLines.push(...renderRowLines(token.header, true));
2615
+ tableLines.push(renderBorderLine("middle"));
2616
+ token.rows.forEach((row_3, rowIndex_0) => {
2617
+ tableLines.push(...renderRowLines(row_3, false));
2618
+ if (rowIndex_0 < token.rows.length - 1) {
2619
+ tableLines.push(renderBorderLine("middle"));
2620
+ }
2621
+ });
2622
+ tableLines.push(renderBorderLine("bottom"));
2623
+ const maxLineWidth = Math.max(...tableLines.map((line_2) => stringWidth3(stripAnsi2(line_2))));
2624
+ if (maxLineWidth > terminalWidth - SAFETY_MARGIN) {
2625
+ return /* @__PURE__ */ jsx9(Ansi3, { children: renderVerticalFormat() });
2626
+ }
2627
+ return /* @__PURE__ */ jsx9(Ansi3, { children: tableLines.join("\n") });
2628
+ }
2629
+
2630
+ // src/Markdown.tsx
2631
+ import { jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
2632
+ var TOKEN_CACHE_MAX = 500;
2633
+ var tokenCache = /* @__PURE__ */ new Map();
2634
+ var MD_SYNTAX_RE = /[#*`|[>\-_~]|\n\n|^\d+\. |\n\d+\. /;
2635
+ function hasMarkdownSyntax(s) {
2636
+ return MD_SYNTAX_RE.test(s.length > 500 ? s.slice(0, 500) : s);
2637
+ }
2638
+ function stripPromptXMLTags(content) {
2639
+ return content.replace(/<(commit_analysis|context|function_analysis|pr_analysis)>.*?<\/\1>\n?/gs, "").trim();
2640
+ }
2641
+ function cachedLexer(content) {
2642
+ if (!hasMarkdownSyntax(content)) {
2643
+ return [
2644
+ {
2645
+ type: "paragraph",
2646
+ raw: content,
2647
+ text: content,
2648
+ tokens: [{ type: "text", raw: content, text: content }]
2649
+ }
2650
+ ];
2651
+ }
2652
+ const key = hashContent(content);
2653
+ const hit = tokenCache.get(key);
2654
+ if (hit) {
2655
+ tokenCache.delete(key);
2656
+ tokenCache.set(key, hit);
2657
+ return hit;
2658
+ }
2659
+ const tokens = marked2.lexer(content);
2660
+ if (tokenCache.size >= TOKEN_CACHE_MAX) {
2661
+ const first = tokenCache.keys().next().value;
2662
+ if (first !== void 0) tokenCache.delete(first);
2663
+ }
2664
+ tokenCache.set(key, tokens);
2665
+ return tokens;
2666
+ }
2667
+ function Markdown(props) {
2668
+ const settings = {};
2669
+ if (settings.syntaxHighlightingDisabled) {
2670
+ return /* @__PURE__ */ jsx10(MarkdownBody, { ...props, highlight: null });
2671
+ }
2672
+ return /* @__PURE__ */ jsx10(Suspense, { fallback: /* @__PURE__ */ jsx10(MarkdownBody, { ...props, highlight: null }), children: /* @__PURE__ */ jsx10(MarkdownWithHighlight, { ...props }) });
2673
+ }
2674
+ function MarkdownWithHighlight(props) {
2675
+ const highlight = use(getCliHighlightPromise());
2676
+ return /* @__PURE__ */ jsx10(MarkdownBody, { ...props, highlight });
2677
+ }
2678
+ function MarkdownBody({
2679
+ children,
2680
+ dimColor,
2681
+ highlight
2682
+ }) {
2683
+ const [theme] = useTheme();
2684
+ configureMarked();
2685
+ const elements = useMemo3(() => {
2686
+ const tokens = cachedLexer(stripPromptXMLTags(children));
2687
+ const elements2 = [];
2688
+ let nonTableContent = "";
2689
+ function flushNonTableContent() {
2690
+ if (nonTableContent) {
2691
+ elements2.push(
2692
+ /* @__PURE__ */ jsx10(Ansi4, { dimColor, children: nonTableContent.trim() }, elements2.length)
2693
+ );
2694
+ nonTableContent = "";
2695
+ }
2696
+ }
2697
+ for (const token of tokens) {
2698
+ if (token.type === "table") {
2699
+ flushNonTableContent();
2700
+ elements2.push(
2701
+ /* @__PURE__ */ jsx10(
2702
+ MarkdownTable,
2703
+ {
2704
+ token,
2705
+ highlight
2706
+ },
2707
+ elements2.length
2708
+ )
2709
+ );
2710
+ } else {
2711
+ nonTableContent += formatToken(token, theme, 0, null, null, highlight);
2712
+ }
2713
+ }
2714
+ flushNonTableContent();
2715
+ return elements2;
2716
+ }, [children, dimColor, highlight, theme]);
2717
+ return /* @__PURE__ */ jsx10(Box4, { flexDirection: "column", gap: 1, children: elements });
2718
+ }
2719
+ function StreamingMarkdown({
2720
+ children
2721
+ }) {
2722
+ "use no memo";
2723
+ configureMarked();
2724
+ const stripped = stripPromptXMLTags(children);
2725
+ const stablePrefixRef = useRef4("");
2726
+ if (!stripped.startsWith(stablePrefixRef.current)) {
2727
+ stablePrefixRef.current = "";
2728
+ }
2729
+ const boundary = stablePrefixRef.current.length;
2730
+ const tokens = marked2.lexer(stripped.substring(boundary));
2731
+ let lastContentIdx = tokens.length - 1;
2732
+ while (lastContentIdx >= 0 && tokens[lastContentIdx].type === "space") {
2733
+ lastContentIdx--;
2734
+ }
2735
+ let advance = 0;
2736
+ for (let i = 0; i < lastContentIdx; i++) {
2737
+ advance += tokens[i].raw.length;
2738
+ }
2739
+ if (advance > 0) {
2740
+ stablePrefixRef.current = stripped.substring(0, boundary + advance);
2741
+ }
2742
+ const stablePrefix = stablePrefixRef.current;
2743
+ const unstableSuffix = stripped.substring(stablePrefix.length);
2744
+ return /* @__PURE__ */ jsxs6(Box4, { flexDirection: "column", gap: 1, children: [
2745
+ stablePrefix && /* @__PURE__ */ jsx10(Markdown, { children: stablePrefix }),
2746
+ unstableSuffix && /* @__PURE__ */ jsx10(Markdown, { children: unstableSuffix })
2747
+ ] });
2748
+ }
2749
+
1956
2750
  // src/Select.tsx
1957
- import { useState as useState5, useRef as useRef3, useMemo as useMemo2, useCallback as useCallback4 } from "react";
1958
- import { Box as Box4, Text as Text7, useInput as useInput4 } from "@claude-code-kit/ink-renderer";
1959
- import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
2751
+ import { useState as useState6, useRef as useRef5, useMemo as useMemo4, useCallback as useCallback5 } from "react";
2752
+ import { Box as Box5, Text as Text7, useInput as useInput4 } from "@claude-code-kit/ink-renderer";
2753
+ import { jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
1960
2754
  function useListNavigation(opts) {
1961
2755
  const { options, maxVisible, onCancel, onSelect, extraHandler } = opts;
1962
- const [focusIndex, setFocusIndex] = useState5(0);
1963
- const focusRef = useRef3(focusIndex);
2756
+ const [focusIndex, setFocusIndex] = useState6(0);
2757
+ const focusRef = useRef5(focusIndex);
1964
2758
  focusRef.current = focusIndex;
1965
2759
  const total = options.length;
1966
2760
  const max = maxVisible ?? total;
1967
- const scrollOffset = useMemo2(() => {
2761
+ const scrollOffset = useMemo4(() => {
1968
2762
  if (total <= max) return 0;
1969
2763
  const half = Math.floor(max / 2);
1970
2764
  if (focusIndex <= half) return 0;
1971
2765
  if (focusIndex >= total - max + half) return total - max;
1972
2766
  return focusIndex - half;
1973
2767
  }, [focusIndex, total, max]);
1974
- const visibleOptions = useMemo2(
2768
+ const visibleOptions = useMemo4(
1975
2769
  () => options.slice(scrollOffset, scrollOffset + max),
1976
2770
  [options, scrollOffset, max]
1977
2771
  );
1978
- const moveFocus = useCallback4(
2772
+ const moveFocus = useCallback5(
1979
2773
  (dir) => {
1980
2774
  setFocusIndex((prev) => {
1981
2775
  let next = prev;
@@ -2011,7 +2805,7 @@ function useListNavigation(opts) {
2011
2805
  return { focusIndex, scrollOffset, visibleOptions, max, total };
2012
2806
  }
2013
2807
  function ScrollHint({ count, direction }) {
2014
- return /* @__PURE__ */ jsxs6(Text7, { dimColor: true, children: [
2808
+ return /* @__PURE__ */ jsxs7(Text7, { dimColor: true, children: [
2015
2809
  " ",
2016
2810
  direction === "up" ? "\u2191" : "\u2193",
2017
2811
  " ",
@@ -2027,25 +2821,25 @@ function Select({
2027
2821
  title,
2028
2822
  maxVisible
2029
2823
  }) {
2030
- const handleSelect = useCallback4(
2824
+ const handleSelect = useCallback5(
2031
2825
  (index) => onChange(options[index].value),
2032
2826
  [onChange, options]
2033
2827
  );
2034
2828
  const { focusIndex, scrollOffset, visibleOptions, max, total } = useListNavigation({ options, maxVisible, onCancel, onSelect: handleSelect });
2035
- return /* @__PURE__ */ jsxs6(Box4, { flexDirection: "column", children: [
2036
- title && /* @__PURE__ */ jsx8(Box4, { marginBottom: 1, children: /* @__PURE__ */ jsx8(Text7, { bold: true, children: title }) }),
2037
- scrollOffset > 0 && /* @__PURE__ */ jsx8(ScrollHint, { count: scrollOffset, direction: "up" }),
2829
+ return /* @__PURE__ */ jsxs7(Box5, { flexDirection: "column", children: [
2830
+ title && /* @__PURE__ */ jsx11(Box5, { marginBottom: 1, children: /* @__PURE__ */ jsx11(Text7, { bold: true, children: title }) }),
2831
+ scrollOffset > 0 && /* @__PURE__ */ jsx11(ScrollHint, { count: scrollOffset, direction: "up" }),
2038
2832
  visibleOptions.map((opt, i) => {
2039
2833
  const realIndex = scrollOffset + i;
2040
2834
  const isFocused = realIndex === focusIndex;
2041
2835
  const isSelected = opt.value === defaultValue;
2042
2836
  const isDisabled = opt.disabled === true;
2043
- return /* @__PURE__ */ jsxs6(Box4, { children: [
2044
- /* @__PURE__ */ jsxs6(Text7, { color: isFocused ? "cyan" : void 0, children: [
2837
+ return /* @__PURE__ */ jsxs7(Box5, { children: [
2838
+ /* @__PURE__ */ jsxs7(Text7, { color: isFocused ? "cyan" : void 0, children: [
2045
2839
  isFocused ? "\u276F" : " ",
2046
2840
  " "
2047
2841
  ] }),
2048
- /* @__PURE__ */ jsxs6(
2842
+ /* @__PURE__ */ jsxs7(
2049
2843
  Text7,
2050
2844
  {
2051
2845
  color: isDisabled ? "gray" : isFocused ? "cyan" : void 0,
@@ -2058,15 +2852,15 @@ function Select({
2058
2852
  ]
2059
2853
  }
2060
2854
  ),
2061
- isSelected && /* @__PURE__ */ jsx8(Text7, { color: "green", children: " \u2713" }),
2062
- opt.description && /* @__PURE__ */ jsxs6(Text7, { dimColor: true, children: [
2855
+ isSelected && /* @__PURE__ */ jsx11(Text7, { color: "green", children: " \u2713" }),
2856
+ opt.description && /* @__PURE__ */ jsxs7(Text7, { dimColor: true, children: [
2063
2857
  " ",
2064
2858
  opt.description
2065
2859
  ] })
2066
2860
  ] }, realIndex);
2067
2861
  }),
2068
- scrollOffset + max < total && /* @__PURE__ */ jsx8(ScrollHint, { count: total - scrollOffset - max, direction: "down" }),
2069
- /* @__PURE__ */ jsx8(Box4, { marginTop: 1, children: /* @__PURE__ */ jsx8(Text7, { dimColor: true, children: "Enter to confirm \xB7 Esc to exit" }) })
2862
+ scrollOffset + max < total && /* @__PURE__ */ jsx11(ScrollHint, { count: total - scrollOffset - max, direction: "down" }),
2863
+ /* @__PURE__ */ jsx11(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx11(Text7, { dimColor: true, children: "Enter to confirm \xB7 Esc to exit" }) })
2070
2864
  ] });
2071
2865
  }
2072
2866
  function MultiSelect({
@@ -2078,12 +2872,12 @@ function MultiSelect({
2078
2872
  title,
2079
2873
  maxVisible
2080
2874
  }) {
2081
- const [selected, setSelected] = useState5(() => new Set(selectedValues));
2082
- const handleConfirm = useCallback4(
2875
+ const [selected, setSelected] = useState6(() => new Set(selectedValues));
2876
+ const handleConfirm = useCallback5(
2083
2877
  () => onConfirm(Array.from(selected)),
2084
2878
  [onConfirm, selected]
2085
2879
  );
2086
- const handleSpace = useCallback4(
2880
+ const handleSpace = useCallback5(
2087
2881
  (input, _key, focusIndex2) => {
2088
2882
  if (input !== " ") return false;
2089
2883
  const opt = options[focusIndex2];
@@ -2106,20 +2900,20 @@ function MultiSelect({
2106
2900
  onSelect: handleConfirm,
2107
2901
  extraHandler: handleSpace
2108
2902
  });
2109
- return /* @__PURE__ */ jsxs6(Box4, { flexDirection: "column", children: [
2110
- title && /* @__PURE__ */ jsx8(Box4, { marginBottom: 1, children: /* @__PURE__ */ jsx8(Text7, { bold: true, children: title }) }),
2111
- scrollOffset > 0 && /* @__PURE__ */ jsx8(ScrollHint, { count: scrollOffset, direction: "up" }),
2903
+ return /* @__PURE__ */ jsxs7(Box5, { flexDirection: "column", children: [
2904
+ title && /* @__PURE__ */ jsx11(Box5, { marginBottom: 1, children: /* @__PURE__ */ jsx11(Text7, { bold: true, children: title }) }),
2905
+ scrollOffset > 0 && /* @__PURE__ */ jsx11(ScrollHint, { count: scrollOffset, direction: "up" }),
2112
2906
  visibleOptions.map((opt, i) => {
2113
2907
  const realIndex = scrollOffset + i;
2114
2908
  const isFocused = realIndex === focusIndex;
2115
2909
  const isChecked = selected.has(opt.value);
2116
2910
  const isDisabled = opt.disabled === true;
2117
- return /* @__PURE__ */ jsxs6(Box4, { children: [
2118
- /* @__PURE__ */ jsxs6(Text7, { color: isFocused ? "cyan" : void 0, children: [
2911
+ return /* @__PURE__ */ jsxs7(Box5, { children: [
2912
+ /* @__PURE__ */ jsxs7(Text7, { color: isFocused ? "cyan" : void 0, children: [
2119
2913
  isFocused ? "\u276F" : " ",
2120
2914
  " "
2121
2915
  ] }),
2122
- /* @__PURE__ */ jsxs6(
2916
+ /* @__PURE__ */ jsxs7(
2123
2917
  Text7,
2124
2918
  {
2125
2919
  color: isDisabled ? "gray" : isFocused ? "cyan" : void 0,
@@ -2134,20 +2928,20 @@ function MultiSelect({
2134
2928
  ]
2135
2929
  }
2136
2930
  ),
2137
- opt.description && /* @__PURE__ */ jsxs6(Text7, { dimColor: true, children: [
2931
+ opt.description && /* @__PURE__ */ jsxs7(Text7, { dimColor: true, children: [
2138
2932
  " ",
2139
2933
  opt.description
2140
2934
  ] })
2141
2935
  ] }, realIndex);
2142
2936
  }),
2143
- scrollOffset + max < total && /* @__PURE__ */ jsx8(ScrollHint, { count: total - scrollOffset - max, direction: "down" }),
2144
- /* @__PURE__ */ jsx8(Box4, { marginTop: 1, children: /* @__PURE__ */ jsx8(Text7, { dimColor: true, children: "Space to toggle \xB7 Enter to confirm \xB7 Esc to exit" }) })
2937
+ scrollOffset + max < total && /* @__PURE__ */ jsx11(ScrollHint, { count: total - scrollOffset - max, direction: "down" }),
2938
+ /* @__PURE__ */ jsx11(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx11(Text7, { dimColor: true, children: "Space to toggle \xB7 Enter to confirm \xB7 Esc to exit" }) })
2145
2939
  ] });
2146
2940
  }
2147
2941
 
2148
2942
  // src/MessageList.tsx
2149
- import { Box as Box5, Text as Text8 } from "@claude-code-kit/ink-renderer";
2150
- import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
2943
+ import { Box as Box6, Text as Text8 } from "@claude-code-kit/ink-renderer";
2944
+ import { jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
2151
2945
  var ROLE_CONFIG = {
2152
2946
  user: { icon: "\u276F", label: "You", color: "cyan" },
2153
2947
  assistant: { icon: "\u25CF", label: "Claude", color: "#DA7756" },
@@ -2162,15 +2956,15 @@ function MessageItem({
2162
2956
  }
2163
2957
  const config = ROLE_CONFIG[message.role];
2164
2958
  const isSystem = message.role === "system";
2165
- return /* @__PURE__ */ jsxs7(Box5, { flexDirection: "column", children: [
2166
- /* @__PURE__ */ jsxs7(Box5, { children: [
2167
- /* @__PURE__ */ jsx9(Text8, { color: config.color, dimColor: isSystem, children: config.icon }),
2168
- /* @__PURE__ */ jsxs7(Text8, { color: config.color, dimColor: isSystem, bold: !isSystem, children: [
2959
+ return /* @__PURE__ */ jsxs8(Box6, { flexDirection: "column", children: [
2960
+ /* @__PURE__ */ jsxs8(Box6, { children: [
2961
+ /* @__PURE__ */ jsx12(Text8, { color: config.color, dimColor: isSystem, children: config.icon }),
2962
+ /* @__PURE__ */ jsxs8(Text8, { color: config.color, dimColor: isSystem, bold: !isSystem, children: [
2169
2963
  " ",
2170
2964
  config.label
2171
2965
  ] })
2172
2966
  ] }),
2173
- message.content.split("\n").map((line, i) => /* @__PURE__ */ jsx9(Box5, { marginLeft: 2, children: /* @__PURE__ */ jsx9(Text8, { dimColor: isSystem, children: line }) }, i))
2967
+ message.content.split("\n").map((line, i) => /* @__PURE__ */ jsx12(Box6, { marginLeft: 2, children: /* @__PURE__ */ jsx12(Text8, { dimColor: isSystem, children: line }) }, i))
2174
2968
  ] });
2175
2969
  }
2176
2970
  function MessageList({
@@ -2178,39 +2972,39 @@ function MessageList({
2178
2972
  streamingContent,
2179
2973
  renderMessage
2180
2974
  }) {
2181
- return /* @__PURE__ */ jsxs7(Box5, { flexDirection: "column", children: [
2182
- messages.map((message, i) => /* @__PURE__ */ jsx9(Box5, { flexDirection: "column", marginTop: i > 0 ? 1 : 0, children: /* @__PURE__ */ jsx9(MessageItem, { message, renderMessage }) }, message.id)),
2183
- streamingContent != null && streamingContent.length > 0 && /* @__PURE__ */ jsxs7(Box5, { flexDirection: "column", marginTop: messages.length > 0 ? 1 : 0, children: [
2184
- /* @__PURE__ */ jsxs7(Box5, { children: [
2185
- /* @__PURE__ */ jsx9(Text8, { color: "#DA7756", children: "\u25CF" }),
2186
- /* @__PURE__ */ jsxs7(Text8, { color: "#DA7756", bold: true, children: [
2975
+ return /* @__PURE__ */ jsxs8(Box6, { flexDirection: "column", children: [
2976
+ messages.map((message, i) => /* @__PURE__ */ jsx12(Box6, { flexDirection: "column", marginTop: i > 0 ? 1 : 0, children: /* @__PURE__ */ jsx12(MessageItem, { message, renderMessage }) }, message.id)),
2977
+ streamingContent != null && streamingContent.length > 0 && /* @__PURE__ */ jsxs8(Box6, { flexDirection: "column", marginTop: messages.length > 0 ? 1 : 0, children: [
2978
+ /* @__PURE__ */ jsxs8(Box6, { children: [
2979
+ /* @__PURE__ */ jsx12(Text8, { color: "#DA7756", children: "\u25CF" }),
2980
+ /* @__PURE__ */ jsxs8(Text8, { color: "#DA7756", bold: true, children: [
2187
2981
  " ",
2188
2982
  "Claude"
2189
2983
  ] })
2190
2984
  ] }),
2191
- streamingContent.split("\n").map((line, i) => /* @__PURE__ */ jsx9(Box5, { marginLeft: 2, children: /* @__PURE__ */ jsxs7(Text8, { children: [
2985
+ streamingContent.split("\n").map((line, i) => /* @__PURE__ */ jsx12(Box6, { marginLeft: 2, children: /* @__PURE__ */ jsxs8(Text8, { children: [
2192
2986
  line,
2193
- i === streamingContent.split("\n").length - 1 && /* @__PURE__ */ jsx9(Text8, { color: "#DA7756", children: "\u2588" })
2987
+ i === streamingContent.split("\n").length - 1 && /* @__PURE__ */ jsx12(Text8, { color: "#DA7756", children: "\u2588" })
2194
2988
  ] }) }, i))
2195
2989
  ] })
2196
2990
  ] });
2197
2991
  }
2198
2992
 
2199
2993
  // src/StreamingText.tsx
2200
- import { useState as useState6, useEffect as useEffect5, useRef as useRef4 } from "react";
2994
+ import { useState as useState7, useEffect as useEffect6, useRef as useRef6 } from "react";
2201
2995
  import { Text as Text9 } from "@claude-code-kit/ink-renderer";
2202
- import { jsx as jsx10 } from "react/jsx-runtime";
2996
+ import { jsx as jsx13 } from "react/jsx-runtime";
2203
2997
  function StreamingText({
2204
2998
  text,
2205
2999
  speed = 3,
2206
3000
  interval = 20,
2207
3001
  onComplete,
2208
- color
3002
+ color: color2
2209
3003
  }) {
2210
- const [revealed, setRevealed] = useState6(0);
2211
- const onCompleteRef = useRef4(onComplete);
3004
+ const [revealed, setRevealed] = useState7(0);
3005
+ const onCompleteRef = useRef6(onComplete);
2212
3006
  onCompleteRef.current = onComplete;
2213
- useEffect5(() => {
3007
+ useEffect6(() => {
2214
3008
  if (revealed >= text.length) return;
2215
3009
  const id = setInterval(() => {
2216
3010
  setRevealed((prev) => {
@@ -2223,13 +3017,13 @@ function StreamingText({
2223
3017
  }, interval);
2224
3018
  return () => clearInterval(id);
2225
3019
  }, [text.length, speed, interval, revealed >= text.length]);
2226
- return /* @__PURE__ */ jsx10(Text9, { color, children: text.slice(0, revealed) });
3020
+ return /* @__PURE__ */ jsx13(Text9, { color: color2, children: text.slice(0, revealed) });
2227
3021
  }
2228
3022
 
2229
3023
  // src/REPL.tsx
2230
- import { useState as useState7, useCallback as useCallback5, useRef as useRef5 } from "react";
2231
- import { Box as Box6, useInput as useInput5, useApp } from "@claude-code-kit/ink-renderer";
2232
- import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
3024
+ import { useState as useState8, useCallback as useCallback6, useRef as useRef7 } from "react";
3025
+ import { Box as Box7, useInput as useInput5, useApp } from "@claude-code-kit/ink-renderer";
3026
+ import { jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
2233
3027
  function REPL({
2234
3028
  onSubmit,
2235
3029
  onExit,
@@ -2246,15 +3040,15 @@ function REPL({
2246
3040
  spinner
2247
3041
  }) {
2248
3042
  const { exit } = useApp();
2249
- const [inputValue, setInputValue] = useState7("");
2250
- const [internalHistory, setInternalHistory] = useState7([]);
2251
- const submittingRef = useRef5(false);
3043
+ const [inputValue, setInputValue] = useState8("");
3044
+ const [internalHistory, setInternalHistory] = useState8([]);
3045
+ const submittingRef = useRef7(false);
2252
3046
  const history = externalHistory ?? internalHistory;
2253
3047
  const promptCommands = commands.map((c) => ({
2254
3048
  name: c.name,
2255
3049
  description: c.description
2256
3050
  }));
2257
- const handleSubmit = useCallback5(
3051
+ const handleSubmit = useCallback6(
2258
3052
  (value) => {
2259
3053
  if (submittingRef.current) return;
2260
3054
  const trimmed = value.trim();
@@ -2302,9 +3096,9 @@ function REPL({
2302
3096
  { isActive: true }
2303
3097
  );
2304
3098
  const resolvedSegments = statusSegments ?? buildDefaultSegments(model);
2305
- return /* @__PURE__ */ jsxs8(Box6, { flexDirection: "column", flexGrow: 1, children: [
2306
- /* @__PURE__ */ jsxs8(Box6, { flexDirection: "column", flexGrow: 1, children: [
2307
- /* @__PURE__ */ jsx11(
3099
+ return /* @__PURE__ */ jsxs9(Box7, { flexDirection: "column", flexGrow: 1, children: [
3100
+ /* @__PURE__ */ jsxs9(Box7, { flexDirection: "column", flexGrow: 1, children: [
3101
+ /* @__PURE__ */ jsx14(
2308
3102
  MessageList,
2309
3103
  {
2310
3104
  messages,
@@ -2312,10 +3106,10 @@ function REPL({
2312
3106
  renderMessage
2313
3107
  }
2314
3108
  ),
2315
- isLoading && !streamingContent && /* @__PURE__ */ jsx11(Box6, { marginTop: messages.length > 0 ? 1 : 0, children: spinner ?? /* @__PURE__ */ jsx11(Spinner, {}) })
3109
+ isLoading && !streamingContent && /* @__PURE__ */ jsx14(Box7, { marginTop: messages.length > 0 ? 1 : 0, children: spinner ?? /* @__PURE__ */ jsx14(Spinner, {}) })
2316
3110
  ] }),
2317
- /* @__PURE__ */ jsx11(Divider, {}),
2318
- /* @__PURE__ */ jsx11(
3111
+ /* @__PURE__ */ jsx14(Divider, {}),
3112
+ /* @__PURE__ */ jsx14(
2319
3113
  PromptInput,
2320
3114
  {
2321
3115
  value: inputValue,
@@ -2328,37 +3122,722 @@ function REPL({
2328
3122
  history
2329
3123
  }
2330
3124
  ),
2331
- /* @__PURE__ */ jsx11(Divider, {}),
2332
- resolvedSegments.length > 0 && /* @__PURE__ */ jsx11(StatusLine, { segments: resolvedSegments })
3125
+ /* @__PURE__ */ jsx14(Divider, {}),
3126
+ resolvedSegments.length > 0 && /* @__PURE__ */ jsx14(StatusLine, { segments: resolvedSegments })
2333
3127
  ] });
2334
3128
  }
2335
3129
  function buildDefaultSegments(model) {
2336
3130
  if (!model) return [];
2337
3131
  return [{ content: model, color: "green" }];
2338
3132
  }
3133
+
3134
+ // src/design-system/ThemedBox.tsx
3135
+ import { Box as Box8 } from "@claude-code-kit/ink-renderer";
3136
+ import { jsx as jsx15 } from "react/jsx-runtime";
3137
+ function resolveColor(color2, theme) {
3138
+ if (!color2) return void 0;
3139
+ if (color2.startsWith("rgb(") || color2.startsWith("#") || color2.startsWith("ansi256(") || color2.startsWith("ansi:")) {
3140
+ return color2;
3141
+ }
3142
+ return theme[color2];
3143
+ }
3144
+ function ThemedBox({
3145
+ borderColor,
3146
+ borderTopColor,
3147
+ borderBottomColor,
3148
+ borderLeftColor,
3149
+ borderRightColor,
3150
+ backgroundColor,
3151
+ children,
3152
+ ref,
3153
+ ...rest
3154
+ }) {
3155
+ const [themeName] = useTheme();
3156
+ const theme = getTheme(themeName);
3157
+ const resolvedBorderColor = resolveColor(borderColor, theme);
3158
+ const resolvedBorderTopColor = resolveColor(borderTopColor, theme);
3159
+ const resolvedBorderBottomColor = resolveColor(borderBottomColor, theme);
3160
+ const resolvedBorderLeftColor = resolveColor(borderLeftColor, theme);
3161
+ const resolvedBorderRightColor = resolveColor(borderRightColor, theme);
3162
+ const resolvedBackgroundColor = resolveColor(backgroundColor, theme);
3163
+ return /* @__PURE__ */ jsx15(
3164
+ Box8,
3165
+ {
3166
+ ref,
3167
+ borderColor: resolvedBorderColor,
3168
+ borderTopColor: resolvedBorderTopColor,
3169
+ borderBottomColor: resolvedBorderBottomColor,
3170
+ borderLeftColor: resolvedBorderLeftColor,
3171
+ borderRightColor: resolvedBorderRightColor,
3172
+ backgroundColor: resolvedBackgroundColor,
3173
+ ...rest,
3174
+ children
3175
+ }
3176
+ );
3177
+ }
3178
+ var ThemedBox_default = ThemedBox;
3179
+
3180
+ // src/design-system/ThemedText.tsx
3181
+ import React13, { useContext as useContext6 } from "react";
3182
+ import { Text as Text11 } from "@claude-code-kit/ink-renderer";
3183
+ import { jsx as jsx16 } from "react/jsx-runtime";
3184
+ var TextHoverColorContext = React13.createContext(void 0);
3185
+ function resolveColor2(color2, theme) {
3186
+ if (!color2) return void 0;
3187
+ if (color2.startsWith("rgb(") || color2.startsWith("#") || color2.startsWith("ansi256(") || color2.startsWith("ansi:")) {
3188
+ return color2;
3189
+ }
3190
+ return theme[color2];
3191
+ }
3192
+ function ThemedText({
3193
+ color: color2,
3194
+ backgroundColor,
3195
+ dimColor = false,
3196
+ bold = false,
3197
+ italic = false,
3198
+ underline = false,
3199
+ strikethrough = false,
3200
+ inverse = false,
3201
+ wrap = "wrap",
3202
+ children
3203
+ }) {
3204
+ const [themeName] = useTheme();
3205
+ const theme = getTheme(themeName);
3206
+ const hoverColor = useContext6(TextHoverColorContext);
3207
+ const resolvedColor = !color2 && hoverColor ? resolveColor2(hoverColor, theme) : dimColor ? theme.inactive : resolveColor2(color2, theme);
3208
+ const resolvedBackgroundColor = backgroundColor ? theme[backgroundColor] : void 0;
3209
+ return /* @__PURE__ */ jsx16(
3210
+ Text11,
3211
+ {
3212
+ color: resolvedColor,
3213
+ backgroundColor: resolvedBackgroundColor,
3214
+ bold,
3215
+ italic,
3216
+ underline,
3217
+ strikethrough,
3218
+ inverse,
3219
+ wrap,
3220
+ children
3221
+ }
3222
+ );
3223
+ }
3224
+
3225
+ // src/design-system/Dialog.tsx
3226
+ import { useCallback as useCallback7 } from "react";
3227
+ import { Box as Box10, Text as Text14, useInput as useInput6 } from "@claude-code-kit/ink-renderer";
3228
+
3229
+ // src/design-system/Byline.tsx
3230
+ import React14, { Children, isValidElement } from "react";
3231
+ import { Text as Text12 } from "@claude-code-kit/ink-renderer";
3232
+ import { Fragment, jsx as jsx17, jsxs as jsxs10 } from "react/jsx-runtime";
3233
+ function Byline({ children }) {
3234
+ const validChildren = Children.toArray(children);
3235
+ if (validChildren.length === 0) {
3236
+ return null;
3237
+ }
3238
+ return /* @__PURE__ */ jsx17(Fragment, { children: validChildren.map((child, index) => /* @__PURE__ */ jsxs10(
3239
+ React14.Fragment,
3240
+ {
3241
+ children: [
3242
+ index > 0 && /* @__PURE__ */ jsx17(Text12, { dimColor: true, children: " \xB7 " }),
3243
+ child
3244
+ ]
3245
+ },
3246
+ isValidElement(child) ? child.key ?? index : index
3247
+ )) });
3248
+ }
3249
+
3250
+ // src/design-system/KeyboardShortcutHint.tsx
3251
+ import { Text as Text13 } from "@claude-code-kit/ink-renderer";
3252
+ import { jsx as jsx18, jsxs as jsxs11 } from "react/jsx-runtime";
3253
+ function KeyboardShortcutHint({
3254
+ shortcut,
3255
+ action,
3256
+ parens = false,
3257
+ bold = false
3258
+ }) {
3259
+ const shortcutText = bold ? /* @__PURE__ */ jsx18(Text13, { bold: true, children: shortcut }) : shortcut;
3260
+ if (parens) {
3261
+ return /* @__PURE__ */ jsxs11(Text13, { children: [
3262
+ "(",
3263
+ shortcutText,
3264
+ " to ",
3265
+ action,
3266
+ ")"
3267
+ ] });
3268
+ }
3269
+ return /* @__PURE__ */ jsxs11(Text13, { children: [
3270
+ shortcutText,
3271
+ " to ",
3272
+ action
3273
+ ] });
3274
+ }
3275
+
3276
+ // src/design-system/Pane.tsx
3277
+ import { Box as Box9 } from "@claude-code-kit/ink-renderer";
3278
+ import { jsx as jsx19, jsxs as jsxs12 } from "react/jsx-runtime";
3279
+ function Pane({ children, color: color2 }) {
3280
+ return /* @__PURE__ */ jsxs12(Box9, { flexDirection: "column", paddingTop: 1, children: [
3281
+ /* @__PURE__ */ jsx19(Divider, { color: color2 }),
3282
+ /* @__PURE__ */ jsx19(Box9, { flexDirection: "column", paddingX: 2, children })
3283
+ ] });
3284
+ }
3285
+
3286
+ // src/design-system/Dialog.tsx
3287
+ import { Fragment as Fragment2, jsx as jsx20, jsxs as jsxs13 } from "react/jsx-runtime";
3288
+ function Dialog({
3289
+ title,
3290
+ subtitle,
3291
+ children,
3292
+ onCancel,
3293
+ color: color2 = "permission",
3294
+ hideInputGuide,
3295
+ hideBorder
3296
+ }) {
3297
+ useInput6(
3298
+ useCallback7(
3299
+ (_input, key) => {
3300
+ if (key.escape) {
3301
+ onCancel();
3302
+ }
3303
+ },
3304
+ [onCancel]
3305
+ )
3306
+ );
3307
+ const defaultInputGuide = /* @__PURE__ */ jsxs13(Byline, { children: [
3308
+ /* @__PURE__ */ jsx20(KeyboardShortcutHint, { shortcut: "Enter", action: "confirm" }),
3309
+ /* @__PURE__ */ jsx20(KeyboardShortcutHint, { shortcut: "Esc", action: "cancel" })
3310
+ ] });
3311
+ const content = /* @__PURE__ */ jsxs13(Fragment2, { children: [
3312
+ /* @__PURE__ */ jsxs13(Box10, { flexDirection: "column", gap: 1, children: [
3313
+ /* @__PURE__ */ jsxs13(Box10, { flexDirection: "column", children: [
3314
+ /* @__PURE__ */ jsx20(Text14, { bold: true, color: color2, children: title }),
3315
+ subtitle && /* @__PURE__ */ jsx20(Text14, { dimColor: true, children: subtitle })
3316
+ ] }),
3317
+ children
3318
+ ] }),
3319
+ !hideInputGuide && /* @__PURE__ */ jsx20(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx20(Text14, { dimColor: true, italic: true, children: defaultInputGuide }) })
3320
+ ] });
3321
+ if (hideBorder) {
3322
+ return content;
3323
+ }
3324
+ return /* @__PURE__ */ jsx20(Pane, { color: color2, children: content });
3325
+ }
3326
+
3327
+ // src/design-system/FuzzyPicker.tsx
3328
+ import { useCallback as useCallback8, useContext as useContext7, useEffect as useEffect7, useState as useState9 } from "react";
3329
+ import {
3330
+ clamp,
3331
+ Box as Box12,
3332
+ Text as Text16,
3333
+ useInput as useInput7,
3334
+ TerminalSizeContext as TerminalSizeContext4
3335
+ } from "@claude-code-kit/ink-renderer";
3336
+
3337
+ // src/design-system/ListItem.tsx
3338
+ import figures2 from "figures";
3339
+ import { useDeclaredCursor } from "@claude-code-kit/ink-renderer";
3340
+ import { Box as Box11, Text as Text15 } from "@claude-code-kit/ink-renderer";
3341
+ import { jsx as jsx21, jsxs as jsxs14 } from "react/jsx-runtime";
3342
+ function ListItem({
3343
+ isFocused,
3344
+ isSelected = false,
3345
+ children,
3346
+ description,
3347
+ showScrollDown,
3348
+ showScrollUp,
3349
+ styled = true,
3350
+ disabled = false,
3351
+ declareCursor
3352
+ }) {
3353
+ function renderIndicator() {
3354
+ if (disabled) {
3355
+ return /* @__PURE__ */ jsx21(Text15, { children: " " });
3356
+ }
3357
+ if (isFocused) {
3358
+ return /* @__PURE__ */ jsx21(Text15, { color: "suggestion", children: figures2.pointer });
3359
+ }
3360
+ if (showScrollDown) {
3361
+ return /* @__PURE__ */ jsx21(Text15, { dimColor: true, children: figures2.arrowDown });
3362
+ }
3363
+ if (showScrollUp) {
3364
+ return /* @__PURE__ */ jsx21(Text15, { dimColor: true, children: figures2.arrowUp });
3365
+ }
3366
+ return /* @__PURE__ */ jsx21(Text15, { children: " " });
3367
+ }
3368
+ function getTextColor() {
3369
+ if (disabled) {
3370
+ return "inactive";
3371
+ }
3372
+ if (!styled) {
3373
+ return void 0;
3374
+ }
3375
+ if (isSelected) {
3376
+ return "success";
3377
+ }
3378
+ if (isFocused) {
3379
+ return "suggestion";
3380
+ }
3381
+ return void 0;
3382
+ }
3383
+ const textColor = getTextColor();
3384
+ const cursorRef = useDeclaredCursor({
3385
+ line: 0,
3386
+ column: 0,
3387
+ active: isFocused && !disabled && declareCursor !== false
3388
+ });
3389
+ return /* @__PURE__ */ jsxs14(Box11, { ref: cursorRef, flexDirection: "column", children: [
3390
+ /* @__PURE__ */ jsxs14(Box11, { flexDirection: "row", gap: 1, children: [
3391
+ renderIndicator(),
3392
+ styled ? /* @__PURE__ */ jsx21(Text15, { color: textColor, dimColor: disabled, children }) : children,
3393
+ isSelected && !disabled && /* @__PURE__ */ jsx21(Text15, { color: "success", children: figures2.tick })
3394
+ ] }),
3395
+ description && /* @__PURE__ */ jsx21(Box11, { paddingLeft: 2, children: /* @__PURE__ */ jsx21(Text15, { color: "inactive", children: description }) })
3396
+ ] });
3397
+ }
3398
+
3399
+ // src/design-system/FuzzyPicker.tsx
3400
+ import { jsx as jsx22, jsxs as jsxs15 } from "react/jsx-runtime";
3401
+ var DEFAULT_VISIBLE = 8;
3402
+ var CHROME_ROWS = 10;
3403
+ var MIN_VISIBLE = 2;
3404
+ function FuzzyPicker({
3405
+ title,
3406
+ placeholder = "Type to search...",
3407
+ initialQuery,
3408
+ items,
3409
+ getKey,
3410
+ renderItem,
3411
+ renderPreview,
3412
+ previewPosition = "bottom",
3413
+ visibleCount: requestedVisible = DEFAULT_VISIBLE,
3414
+ direction = "down",
3415
+ onQueryChange,
3416
+ onSelect,
3417
+ onTab,
3418
+ onShiftTab,
3419
+ onFocus,
3420
+ onCancel,
3421
+ emptyMessage = "No results",
3422
+ matchLabel,
3423
+ selectAction = "select",
3424
+ extraHints
3425
+ }) {
3426
+ const terminalSize = useContext7(TerminalSizeContext4);
3427
+ const rows = terminalSize?.rows ?? 24;
3428
+ const columns = terminalSize?.columns ?? 80;
3429
+ const [focusedIndex, setFocusedIndex] = useState9(0);
3430
+ const [query, setQuery] = useState9(initialQuery ?? "");
3431
+ const visibleCount = Math.max(
3432
+ MIN_VISIBLE,
3433
+ Math.min(requestedVisible, rows - CHROME_ROWS - (matchLabel ? 1 : 0))
3434
+ );
3435
+ const compact = columns < 120;
3436
+ const step = useCallback8(
3437
+ (delta) => {
3438
+ setFocusedIndex((i) => clamp(i + delta, 0, items.length - 1));
3439
+ },
3440
+ [items.length]
3441
+ );
3442
+ useInput7(
3443
+ useCallback8(
3444
+ (input, key) => {
3445
+ if (key.escape) {
3446
+ onCancel();
3447
+ return;
3448
+ }
3449
+ if (key.upArrow || key.ctrl && input === "p") {
3450
+ step(direction === "up" ? 1 : -1);
3451
+ return;
3452
+ }
3453
+ if (key.downArrow || key.ctrl && input === "n") {
3454
+ step(direction === "up" ? -1 : 1);
3455
+ return;
3456
+ }
3457
+ if (key.return) {
3458
+ const selected = items[focusedIndex];
3459
+ if (selected) onSelect(selected);
3460
+ return;
3461
+ }
3462
+ if (key.tab) {
3463
+ const selected = items[focusedIndex];
3464
+ if (!selected) return;
3465
+ const tabAction = key.shift ? onShiftTab ?? onTab : onTab;
3466
+ if (tabAction) {
3467
+ tabAction.handler(selected);
3468
+ } else {
3469
+ onSelect(selected);
3470
+ }
3471
+ return;
3472
+ }
3473
+ if (key.backspace) {
3474
+ setQuery((q) => q.slice(0, -1));
3475
+ return;
3476
+ }
3477
+ if (input && !key.ctrl) {
3478
+ setQuery((q) => q + input);
3479
+ }
3480
+ },
3481
+ [onCancel, step, direction, items, focusedIndex, onSelect, onShiftTab, onTab]
3482
+ )
3483
+ );
3484
+ useEffect7(() => {
3485
+ onQueryChange(query);
3486
+ setFocusedIndex(0);
3487
+ }, [query]);
3488
+ useEffect7(() => {
3489
+ setFocusedIndex((i) => clamp(i, 0, items.length - 1));
3490
+ }, [items.length]);
3491
+ const focused = items[focusedIndex];
3492
+ useEffect7(() => {
3493
+ onFocus?.(focused);
3494
+ }, [focused]);
3495
+ const windowStart = clamp(
3496
+ focusedIndex - visibleCount + 1,
3497
+ 0,
3498
+ items.length - visibleCount
3499
+ );
3500
+ const visible = items.slice(windowStart, windowStart + visibleCount);
3501
+ const emptyText = typeof emptyMessage === "function" ? emptyMessage(query) : emptyMessage;
3502
+ const searchInput = /* @__PURE__ */ jsx22(Box12, { borderStyle: "round", paddingX: 1, children: /* @__PURE__ */ jsx22(Text16, { dimColor: !query, children: query || placeholder }) });
3503
+ const listBlock = /* @__PURE__ */ jsx22(
3504
+ List,
3505
+ {
3506
+ visible,
3507
+ windowStart,
3508
+ visibleCount,
3509
+ total: items.length,
3510
+ focusedIndex,
3511
+ direction,
3512
+ getKey,
3513
+ renderItem,
3514
+ emptyText
3515
+ }
3516
+ );
3517
+ const preview = renderPreview && focused ? /* @__PURE__ */ jsx22(Box12, { flexDirection: "column", flexGrow: 1, children: renderPreview(focused) }) : null;
3518
+ const listGroup = renderPreview && previewPosition === "right" ? /* @__PURE__ */ jsxs15(
3519
+ Box12,
3520
+ {
3521
+ flexDirection: "row",
3522
+ gap: 2,
3523
+ height: visibleCount + (matchLabel ? 1 : 0),
3524
+ children: [
3525
+ /* @__PURE__ */ jsxs15(Box12, { flexDirection: "column", flexShrink: 0, children: [
3526
+ listBlock,
3527
+ matchLabel && /* @__PURE__ */ jsx22(Text16, { dimColor: true, children: matchLabel })
3528
+ ] }),
3529
+ preview ?? /* @__PURE__ */ jsx22(Box12, { flexGrow: 1 })
3530
+ ]
3531
+ }
3532
+ ) : /* @__PURE__ */ jsxs15(Box12, { flexDirection: "column", children: [
3533
+ listBlock,
3534
+ matchLabel && /* @__PURE__ */ jsx22(Text16, { dimColor: true, children: matchLabel }),
3535
+ preview
3536
+ ] });
3537
+ const inputAbove = direction !== "up";
3538
+ return /* @__PURE__ */ jsx22(Pane, { color: "permission", children: /* @__PURE__ */ jsxs15(Box12, { flexDirection: "column", gap: 1, children: [
3539
+ /* @__PURE__ */ jsx22(Text16, { bold: true, color: "permission", children: title }),
3540
+ inputAbove && searchInput,
3541
+ listGroup,
3542
+ !inputAbove && searchInput,
3543
+ /* @__PURE__ */ jsx22(Text16, { dimColor: true, children: /* @__PURE__ */ jsxs15(Byline, { children: [
3544
+ /* @__PURE__ */ jsx22(
3545
+ KeyboardShortcutHint,
3546
+ {
3547
+ shortcut: "up/dn",
3548
+ action: compact ? "nav" : "navigate"
3549
+ }
3550
+ ),
3551
+ /* @__PURE__ */ jsx22(KeyboardShortcutHint, { shortcut: "Enter", action: selectAction }),
3552
+ onTab && /* @__PURE__ */ jsx22(KeyboardShortcutHint, { shortcut: "Tab", action: onTab.action }),
3553
+ onShiftTab && !compact && /* @__PURE__ */ jsx22(
3554
+ KeyboardShortcutHint,
3555
+ {
3556
+ shortcut: "shift+tab",
3557
+ action: onShiftTab.action
3558
+ }
3559
+ ),
3560
+ /* @__PURE__ */ jsx22(KeyboardShortcutHint, { shortcut: "Esc", action: "cancel" }),
3561
+ extraHints
3562
+ ] }) })
3563
+ ] }) });
3564
+ }
3565
+ function List({
3566
+ visible,
3567
+ windowStart,
3568
+ visibleCount,
3569
+ total,
3570
+ focusedIndex,
3571
+ direction,
3572
+ getKey,
3573
+ renderItem,
3574
+ emptyText
3575
+ }) {
3576
+ if (visible.length === 0) {
3577
+ return /* @__PURE__ */ jsx22(Box12, { height: visibleCount, flexShrink: 0, children: /* @__PURE__ */ jsx22(Text16, { dimColor: true, children: emptyText }) });
3578
+ }
3579
+ const rows = visible.map((item, i) => {
3580
+ const actualIndex = windowStart + i;
3581
+ const isFocused = actualIndex === focusedIndex;
3582
+ const atLowEdge = i === 0 && windowStart > 0;
3583
+ const atHighEdge = i === visible.length - 1 && windowStart + visibleCount < total;
3584
+ return /* @__PURE__ */ jsx22(
3585
+ ListItem,
3586
+ {
3587
+ isFocused,
3588
+ showScrollUp: direction === "up" ? atHighEdge : atLowEdge,
3589
+ showScrollDown: direction === "up" ? atLowEdge : atHighEdge,
3590
+ styled: false,
3591
+ children: renderItem(item, isFocused)
3592
+ },
3593
+ getKey(item)
3594
+ );
3595
+ });
3596
+ return /* @__PURE__ */ jsx22(
3597
+ Box12,
3598
+ {
3599
+ height: visibleCount,
3600
+ flexShrink: 0,
3601
+ flexDirection: direction === "up" ? "column-reverse" : "column",
3602
+ children: rows
3603
+ }
3604
+ );
3605
+ }
3606
+
3607
+ // src/design-system/LoadingState.tsx
3608
+ import { Box as Box13, Text as Text17 } from "@claude-code-kit/ink-renderer";
3609
+ import { jsx as jsx23, jsxs as jsxs16 } from "react/jsx-runtime";
3610
+ function LoadingState({
3611
+ message,
3612
+ bold = false,
3613
+ dimColor = false,
3614
+ subtitle
3615
+ }) {
3616
+ return /* @__PURE__ */ jsxs16(Box13, { flexDirection: "column", children: [
3617
+ /* @__PURE__ */ jsxs16(Box13, { flexDirection: "row", children: [
3618
+ /* @__PURE__ */ jsx23(Spinner, {}),
3619
+ /* @__PURE__ */ jsxs16(Text17, { bold, dimColor, children: [
3620
+ " ",
3621
+ message
3622
+ ] })
3623
+ ] }),
3624
+ subtitle && /* @__PURE__ */ jsx23(Text17, { dimColor: true, children: subtitle })
3625
+ ] });
3626
+ }
3627
+
3628
+ // src/design-system/Ratchet.tsx
3629
+ import { useCallback as useCallback9, useContext as useContext8, useLayoutEffect as useLayoutEffect2, useRef as useRef8, useState as useState10 } from "react";
3630
+ import { TerminalSizeContext as TerminalSizeContext5 } from "@claude-code-kit/ink-renderer";
3631
+ import { useTerminalViewport } from "@claude-code-kit/ink-renderer";
3632
+ import { Box as Box14, measureElement } from "@claude-code-kit/ink-renderer";
3633
+ import { jsx as jsx24 } from "react/jsx-runtime";
3634
+ function Ratchet({
3635
+ children,
3636
+ lock = "always"
3637
+ }) {
3638
+ const [viewportRef, { isVisible }] = useTerminalViewport();
3639
+ const terminalSize = useContext8(TerminalSizeContext5);
3640
+ const rows = terminalSize?.rows ?? 24;
3641
+ const innerRef = useRef8(null);
3642
+ const maxHeight = useRef8(0);
3643
+ const [minHeight, setMinHeight] = useState10(0);
3644
+ const outerRef = useCallback9(
3645
+ (el) => {
3646
+ viewportRef(el);
3647
+ },
3648
+ [viewportRef]
3649
+ );
3650
+ const engaged = lock === "always" || !isVisible;
3651
+ useLayoutEffect2(() => {
3652
+ if (!innerRef.current) {
3653
+ return;
3654
+ }
3655
+ const { height } = measureElement(innerRef.current);
3656
+ if (height > maxHeight.current) {
3657
+ maxHeight.current = Math.min(height, rows);
3658
+ setMinHeight(maxHeight.current);
3659
+ }
3660
+ });
3661
+ return /* @__PURE__ */ jsx24(Box14, { minHeight: engaged ? minHeight : void 0, ref: outerRef, children: /* @__PURE__ */ jsx24(Box14, { ref: innerRef, flexDirection: "column", children }) });
3662
+ }
3663
+
3664
+ // src/design-system/Tabs.tsx
3665
+ import {
3666
+ createContext as createContext3,
3667
+ useCallback as useCallback10,
3668
+ useContext as useContext9,
3669
+ useState as useState11
3670
+ } from "react";
3671
+ import { TerminalSizeContext as TerminalSizeContext6 } from "@claude-code-kit/ink-renderer";
3672
+ import { stringWidth as stringWidth4 } from "@claude-code-kit/ink-renderer";
3673
+ import { Box as Box15, Text as Text18, useInput as useInput8 } from "@claude-code-kit/ink-renderer";
3674
+ import { jsx as jsx25, jsxs as jsxs17 } from "react/jsx-runtime";
3675
+ var TabsContext = createContext3({
3676
+ selectedTab: void 0,
3677
+ width: void 0
3678
+ });
3679
+ function Tabs({
3680
+ title,
3681
+ color: color2,
3682
+ defaultTab,
3683
+ children,
3684
+ hidden,
3685
+ useFullWidth,
3686
+ selectedTab: controlledSelectedTab,
3687
+ onTabChange,
3688
+ banner,
3689
+ disableNavigation
3690
+ }) {
3691
+ const terminalSize = useContext9(TerminalSizeContext6);
3692
+ const terminalWidth = terminalSize?.columns ?? 80;
3693
+ const tabs = children.map((child) => [
3694
+ child.props.id ?? child.props.title,
3695
+ child.props.title
3696
+ ]);
3697
+ const defaultTabIndex = defaultTab ? tabs.findIndex((tab) => defaultTab === tab[0]) : 0;
3698
+ const isControlled = controlledSelectedTab !== void 0;
3699
+ const [internalSelectedTab, setInternalSelectedTab] = useState11(
3700
+ defaultTabIndex !== -1 ? defaultTabIndex : 0
3701
+ );
3702
+ const controlledTabIndex = isControlled ? tabs.findIndex((tab) => tab[0] === controlledSelectedTab) : -1;
3703
+ const selectedTabIndex = isControlled ? controlledTabIndex !== -1 ? controlledTabIndex : 0 : internalSelectedTab;
3704
+ const handleTabChange = useCallback10(
3705
+ (offset) => {
3706
+ const newIndex = (selectedTabIndex + tabs.length + offset) % tabs.length;
3707
+ const newTabId = tabs[newIndex]?.[0];
3708
+ if (isControlled && onTabChange && newTabId) {
3709
+ onTabChange(newTabId);
3710
+ } else {
3711
+ setInternalSelectedTab(newIndex);
3712
+ }
3713
+ },
3714
+ [selectedTabIndex, tabs, isControlled, onTabChange]
3715
+ );
3716
+ useInput8(
3717
+ useCallback10(
3718
+ (_input, key) => {
3719
+ if (hidden || disableNavigation) return;
3720
+ if (key.tab && !key.shift) {
3721
+ handleTabChange(1);
3722
+ } else if (key.tab && key.shift) {
3723
+ handleTabChange(-1);
3724
+ } else if (key.leftArrow) {
3725
+ handleTabChange(-1);
3726
+ } else if (key.rightArrow) {
3727
+ handleTabChange(1);
3728
+ }
3729
+ },
3730
+ [hidden, disableNavigation, handleTabChange]
3731
+ )
3732
+ );
3733
+ const titleWidth = title ? stringWidth4(title) + 1 : 0;
3734
+ const tabsWidth = tabs.reduce(
3735
+ (sum, [, tabTitle]) => sum + (tabTitle ? stringWidth4(tabTitle) : 0) + 3,
3736
+ 0
3737
+ );
3738
+ const usedWidth = titleWidth + tabsWidth;
3739
+ const spacerWidth = useFullWidth ? Math.max(0, terminalWidth - usedWidth) : 0;
3740
+ const contentWidth = useFullWidth ? terminalWidth : void 0;
3741
+ return /* @__PURE__ */ jsx25(
3742
+ TabsContext.Provider,
3743
+ {
3744
+ value: {
3745
+ selectedTab: tabs[selectedTabIndex]?.[0],
3746
+ width: contentWidth
3747
+ },
3748
+ children: /* @__PURE__ */ jsxs17(Box15, { flexDirection: "column", children: [
3749
+ !hidden && /* @__PURE__ */ jsxs17(Box15, { flexDirection: "row", gap: 1, children: [
3750
+ title !== void 0 && /* @__PURE__ */ jsx25(Text18, { bold: true, color: color2, children: title }),
3751
+ tabs.map(([id, tabTitle], i) => {
3752
+ const isCurrent = selectedTabIndex === i;
3753
+ return /* @__PURE__ */ jsxs17(
3754
+ Text18,
3755
+ {
3756
+ inverse: isCurrent,
3757
+ bold: isCurrent,
3758
+ children: [
3759
+ " ",
3760
+ tabTitle,
3761
+ " "
3762
+ ]
3763
+ },
3764
+ id
3765
+ );
3766
+ }),
3767
+ spacerWidth > 0 && /* @__PURE__ */ jsx25(Text18, { children: " ".repeat(spacerWidth) })
3768
+ ] }),
3769
+ banner,
3770
+ /* @__PURE__ */ jsx25(
3771
+ Box15,
3772
+ {
3773
+ width: contentWidth,
3774
+ marginTop: hidden ? 0 : 1,
3775
+ children
3776
+ }
3777
+ )
3778
+ ] })
3779
+ }
3780
+ );
3781
+ }
3782
+ function Tab({ title, id, children }) {
3783
+ const { selectedTab, width } = useContext9(TabsContext);
3784
+ if (selectedTab !== (id ?? title)) {
3785
+ return null;
3786
+ }
3787
+ return /* @__PURE__ */ jsx25(Box15, { width, children });
3788
+ }
3789
+ function useTabsWidth() {
3790
+ const { width } = useContext9(TabsContext);
3791
+ return width;
3792
+ }
2339
3793
  export {
3794
+ Byline,
2340
3795
  CommandRegistry,
2341
3796
  DEFAULT_BINDINGS,
3797
+ Dialog,
2342
3798
  Divider,
3799
+ FuzzyPicker,
2343
3800
  KeybindingSetup,
3801
+ KeyboardShortcutHint,
3802
+ ListItem,
3803
+ LoadingState,
3804
+ Markdown,
3805
+ MarkdownTable,
2344
3806
  MessageList,
2345
3807
  MultiSelect,
3808
+ Pane,
2346
3809
  ProgressBar,
2347
3810
  PromptInput,
2348
3811
  REPL,
3812
+ Ratchet,
2349
3813
  Select,
2350
3814
  Spinner,
2351
3815
  StatusIcon,
2352
3816
  StatusLine,
3817
+ StreamingMarkdown,
2353
3818
  StreamingText,
3819
+ Tab,
3820
+ Tabs,
3821
+ TextHoverColorContext,
3822
+ ThemeProvider,
3823
+ ThemedBox_default as ThemedBox,
3824
+ ThemedText,
2354
3825
  clearCommand,
3826
+ color,
2355
3827
  createCommandRegistry,
2356
3828
  defineCommand,
2357
3829
  defineJSXCommand,
2358
3830
  defineLocalCommand,
2359
3831
  exitCommand,
3832
+ getTheme,
2360
3833
  helpCommand,
3834
+ useDoublePress,
2361
3835
  useKeybinding,
2362
3836
  useKeybindings,
2363
- useStatusLine
3837
+ usePreviewTheme,
3838
+ useStatusLine,
3839
+ useTabsWidth,
3840
+ useTerminalSize,
3841
+ useTheme,
3842
+ useThemeSetting
2364
3843
  };