@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/LICENSE +21 -0
- package/README.md +43 -0
- package/dist/index.d.mts +409 -21
- package/dist/index.d.ts +409 -21
- package/dist/index.js +1608 -115
- package/dist/index.mjs +1564 -85
- package/package.json +8 -5
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: !
|
|
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: !
|
|
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
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
1974
|
+
const startRef = useRef3(Date.now());
|
|
1918
1975
|
const allVerbs = verbs ?? (verb ? [verb] : ["Thinking"]);
|
|
1919
|
-
|
|
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
|
-
|
|
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
|
|
1958
|
-
import { Box as
|
|
1959
|
-
import { jsx as
|
|
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] =
|
|
1963
|
-
const focusRef =
|
|
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 =
|
|
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 =
|
|
2768
|
+
const visibleOptions = useMemo4(
|
|
1975
2769
|
() => options.slice(scrollOffset, scrollOffset + max),
|
|
1976
2770
|
[options, scrollOffset, max]
|
|
1977
2771
|
);
|
|
1978
|
-
const moveFocus =
|
|
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__ */
|
|
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 =
|
|
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__ */
|
|
2036
|
-
title && /* @__PURE__ */
|
|
2037
|
-
scrollOffset > 0 && /* @__PURE__ */
|
|
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__ */
|
|
2044
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
2062
|
-
opt.description && /* @__PURE__ */
|
|
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__ */
|
|
2069
|
-
/* @__PURE__ */
|
|
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] =
|
|
2082
|
-
const handleConfirm =
|
|
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 =
|
|
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__ */
|
|
2110
|
-
title && /* @__PURE__ */
|
|
2111
|
-
scrollOffset > 0 && /* @__PURE__ */
|
|
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__ */
|
|
2118
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
2144
|
-
/* @__PURE__ */
|
|
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
|
|
2150
|
-
import { jsx as
|
|
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__ */
|
|
2166
|
-
/* @__PURE__ */
|
|
2167
|
-
/* @__PURE__ */
|
|
2168
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
2182
|
-
messages.map((message, i) => /* @__PURE__ */
|
|
2183
|
-
streamingContent != null && streamingContent.length > 0 && /* @__PURE__ */
|
|
2184
|
-
/* @__PURE__ */
|
|
2185
|
-
/* @__PURE__ */
|
|
2186
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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
|
|
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
|
|
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] =
|
|
2211
|
-
const onCompleteRef =
|
|
3004
|
+
const [revealed, setRevealed] = useState7(0);
|
|
3005
|
+
const onCompleteRef = useRef6(onComplete);
|
|
2212
3006
|
onCompleteRef.current = onComplete;
|
|
2213
|
-
|
|
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__ */
|
|
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
|
|
2231
|
-
import { Box as
|
|
2232
|
-
import { jsx as
|
|
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] =
|
|
2250
|
-
const [internalHistory, setInternalHistory] =
|
|
2251
|
-
const submittingRef =
|
|
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 =
|
|
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__ */
|
|
2306
|
-
/* @__PURE__ */
|
|
2307
|
-
/* @__PURE__ */
|
|
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__ */
|
|
3109
|
+
isLoading && !streamingContent && /* @__PURE__ */ jsx14(Box7, { marginTop: messages.length > 0 ? 1 : 0, children: spinner ?? /* @__PURE__ */ jsx14(Spinner, {}) })
|
|
2316
3110
|
] }),
|
|
2317
|
-
/* @__PURE__ */
|
|
2318
|
-
/* @__PURE__ */
|
|
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__ */
|
|
2332
|
-
resolvedSegments.length > 0 && /* @__PURE__ */
|
|
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
|
-
|
|
3837
|
+
usePreviewTheme,
|
|
3838
|
+
useStatusLine,
|
|
3839
|
+
useTabsWidth,
|
|
3840
|
+
useTerminalSize,
|
|
3841
|
+
useTheme,
|
|
3842
|
+
useThemeSetting
|
|
2364
3843
|
};
|