@claude-code-kit/ui 0.1.0 → 0.2.0
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 +669 -24
- package/dist/index.d.ts +669 -24
- package/dist/index.js +3333 -350
- package/dist/index.mjs +3264 -312
- package/package.json +18 -9
package/dist/index.js
CHANGED
|
@@ -31,61 +31,230 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
// src/index.ts
|
|
32
32
|
var index_exports = {};
|
|
33
33
|
__export(index_exports, {
|
|
34
|
+
AgentContext: () => AgentContext,
|
|
35
|
+
AgentProvider: () => AgentProvider,
|
|
36
|
+
AgentREPL: () => AgentREPL,
|
|
37
|
+
AuthFlowUI: () => AuthFlowUI,
|
|
38
|
+
BashPermissionContent: () => BashPermissionContent,
|
|
39
|
+
Byline: () => Byline,
|
|
40
|
+
ClawdLogo: () => ClawdLogo,
|
|
34
41
|
CommandRegistry: () => CommandRegistry,
|
|
35
42
|
DEFAULT_BINDINGS: () => DEFAULT_BINDINGS,
|
|
43
|
+
Dialog: () => Dialog,
|
|
44
|
+
DiffView: () => DiffView,
|
|
36
45
|
Divider: () => Divider,
|
|
46
|
+
FileEditPermissionContent: () => FileEditPermissionContent,
|
|
47
|
+
FuzzyPicker: () => FuzzyPicker,
|
|
37
48
|
KeybindingSetup: () => KeybindingSetup,
|
|
49
|
+
KeyboardShortcutHint: () => KeyboardShortcutHint,
|
|
50
|
+
ListItem: () => ListItem,
|
|
51
|
+
LoadingState: () => LoadingState,
|
|
52
|
+
Markdown: () => Markdown,
|
|
53
|
+
MarkdownTable: () => MarkdownTable,
|
|
38
54
|
MessageList: () => MessageList,
|
|
39
55
|
MultiSelect: () => MultiSelect,
|
|
56
|
+
Pane: () => Pane,
|
|
57
|
+
PermissionRequest: () => PermissionRequest,
|
|
40
58
|
ProgressBar: () => ProgressBar,
|
|
41
59
|
PromptInput: () => PromptInput,
|
|
42
60
|
REPL: () => REPL,
|
|
61
|
+
Ratchet: () => Ratchet,
|
|
62
|
+
SearchOverlay: () => SearchOverlay,
|
|
43
63
|
Select: () => Select,
|
|
44
64
|
Spinner: () => Spinner,
|
|
45
65
|
StatusIcon: () => StatusIcon,
|
|
46
66
|
StatusLine: () => StatusLine,
|
|
67
|
+
StreamingMarkdown: () => StreamingMarkdown,
|
|
47
68
|
StreamingText: () => StreamingText,
|
|
69
|
+
Tab: () => Tab,
|
|
70
|
+
Tabs: () => Tabs,
|
|
71
|
+
TextHoverColorContext: () => TextHoverColorContext,
|
|
72
|
+
ThemeProvider: () => ThemeProvider,
|
|
73
|
+
ThemedBox: () => ThemedBox_default,
|
|
74
|
+
ThemedText: () => ThemedText,
|
|
75
|
+
VirtualList: () => VirtualList,
|
|
76
|
+
WelcomeScreen: () => WelcomeScreen,
|
|
48
77
|
clearCommand: () => clearCommand,
|
|
78
|
+
color: () => color,
|
|
49
79
|
createCommandRegistry: () => createCommandRegistry,
|
|
50
80
|
defineCommand: () => defineCommand,
|
|
51
81
|
defineJSXCommand: () => defineJSXCommand,
|
|
52
82
|
defineLocalCommand: () => defineLocalCommand,
|
|
53
83
|
exitCommand: () => exitCommand,
|
|
84
|
+
getTheme: () => getTheme,
|
|
54
85
|
helpCommand: () => helpCommand,
|
|
86
|
+
parseUnifiedDiff: () => parseUnifiedDiff,
|
|
87
|
+
useAgent: () => useAgent,
|
|
88
|
+
useAgentContext: () => useAgentContext,
|
|
89
|
+
useDoublePress: () => useDoublePress,
|
|
55
90
|
useKeybinding: () => useKeybinding,
|
|
56
91
|
useKeybindings: () => useKeybindings,
|
|
57
|
-
|
|
92
|
+
usePreviewTheme: () => usePreviewTheme,
|
|
93
|
+
useSearch: () => useSearch,
|
|
94
|
+
useStatusLine: () => useStatusLine,
|
|
95
|
+
useTabsWidth: () => useTabsWidth,
|
|
96
|
+
useTerminalSize: () => useTerminalSize,
|
|
97
|
+
useTheme: () => useTheme,
|
|
98
|
+
useThemeSetting: () => useThemeSetting,
|
|
99
|
+
useVirtualScroll: () => useVirtualScroll
|
|
58
100
|
});
|
|
59
101
|
module.exports = __toCommonJS(index_exports);
|
|
60
102
|
__reExport(index_exports, require("@claude-code-kit/ink-renderer"), module.exports);
|
|
61
103
|
|
|
62
|
-
// src/
|
|
104
|
+
// src/DiffView.tsx
|
|
63
105
|
var import_react = require("react");
|
|
64
106
|
var import_ink_renderer = require("@claude-code-kit/ink-renderer");
|
|
65
107
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
66
|
-
function
|
|
67
|
-
const
|
|
108
|
+
function parseUnifiedDiff(diff) {
|
|
109
|
+
const rawLines = diff.split("\n");
|
|
110
|
+
let filename = "";
|
|
111
|
+
const lines = [];
|
|
112
|
+
let oldLine = 0;
|
|
113
|
+
let newLine = 0;
|
|
114
|
+
for (const line of rawLines) {
|
|
115
|
+
if (line.startsWith("+++ ")) {
|
|
116
|
+
const path = line.slice(4).trim();
|
|
117
|
+
filename = path.startsWith("b/") ? path.slice(2) : path;
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
if (line.startsWith("--- ")) continue;
|
|
121
|
+
const hunkMatch = line.match(/^@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@/);
|
|
122
|
+
if (hunkMatch) {
|
|
123
|
+
oldLine = parseInt(hunkMatch[1], 10);
|
|
124
|
+
newLine = parseInt(hunkMatch[2], 10);
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
if (line.startsWith("diff ") || line.startsWith("index ") || line.startsWith("\\")) {
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
if (oldLine === 0 && newLine === 0) continue;
|
|
131
|
+
if (line.startsWith("+")) {
|
|
132
|
+
lines.push({
|
|
133
|
+
type: "added",
|
|
134
|
+
content: line.slice(1),
|
|
135
|
+
newLineNumber: newLine
|
|
136
|
+
});
|
|
137
|
+
newLine++;
|
|
138
|
+
} else if (line.startsWith("-")) {
|
|
139
|
+
lines.push({
|
|
140
|
+
type: "removed",
|
|
141
|
+
content: line.slice(1),
|
|
142
|
+
oldLineNumber: oldLine
|
|
143
|
+
});
|
|
144
|
+
oldLine++;
|
|
145
|
+
} else {
|
|
146
|
+
lines.push({
|
|
147
|
+
type: "context",
|
|
148
|
+
content: line.startsWith(" ") ? line.slice(1) : line,
|
|
149
|
+
oldLineNumber: oldLine,
|
|
150
|
+
newLineNumber: newLine
|
|
151
|
+
});
|
|
152
|
+
oldLine++;
|
|
153
|
+
newLine++;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return { filename: filename || "unknown", lines };
|
|
157
|
+
}
|
|
158
|
+
function DiffView({
|
|
159
|
+
filename,
|
|
160
|
+
lines: propLines,
|
|
161
|
+
diff,
|
|
162
|
+
showLineNumbers = true,
|
|
163
|
+
maxHeight,
|
|
164
|
+
color: colorOverrides
|
|
165
|
+
}) {
|
|
166
|
+
const parsed = (0, import_react.useMemo)(() => {
|
|
167
|
+
if (diff) return parseUnifiedDiff(diff);
|
|
168
|
+
return null;
|
|
169
|
+
}, [diff]);
|
|
170
|
+
const resolvedFilename = parsed?.filename ?? filename;
|
|
171
|
+
const resolvedLines = parsed?.lines ?? propLines;
|
|
172
|
+
const addedColor = colorOverrides?.added ?? "green";
|
|
173
|
+
const removedColor = colorOverrides?.removed ?? "red";
|
|
174
|
+
const headerColor = colorOverrides?.header ?? "cyan";
|
|
175
|
+
const contextColor = colorOverrides?.context;
|
|
176
|
+
const maxLineNum = (0, import_react.useMemo)(() => {
|
|
177
|
+
let max = 0;
|
|
178
|
+
for (const line of resolvedLines) {
|
|
179
|
+
if (line.oldLineNumber !== void 0 && line.oldLineNumber > max) max = line.oldLineNumber;
|
|
180
|
+
if (line.newLineNumber !== void 0 && line.newLineNumber > max) max = line.newLineNumber;
|
|
181
|
+
}
|
|
182
|
+
return max;
|
|
183
|
+
}, [resolvedLines]);
|
|
184
|
+
const gutterWidth = Math.max(2, String(maxLineNum).length);
|
|
185
|
+
const visibleLines = maxHeight && resolvedLines.length > maxHeight ? resolvedLines.slice(0, maxHeight) : resolvedLines;
|
|
186
|
+
const truncated = maxHeight && resolvedLines.length > maxHeight ? resolvedLines.length - maxHeight : 0;
|
|
187
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink_renderer.Box, { flexDirection: "column", children: [
|
|
188
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink_renderer.Text, { bold: true, color: headerColor, children: [
|
|
189
|
+
" ",
|
|
190
|
+
resolvedFilename
|
|
191
|
+
] }),
|
|
192
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink_renderer.Text, { dimColor: true, children: [
|
|
193
|
+
" ",
|
|
194
|
+
"\u2500".repeat(30)
|
|
195
|
+
] }),
|
|
196
|
+
visibleLines.map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
197
|
+
DiffLineRow,
|
|
198
|
+
{
|
|
199
|
+
line,
|
|
200
|
+
gutterWidth,
|
|
201
|
+
showLineNumbers,
|
|
202
|
+
addedColor,
|
|
203
|
+
removedColor,
|
|
204
|
+
contextColor
|
|
205
|
+
},
|
|
206
|
+
i
|
|
207
|
+
)),
|
|
208
|
+
truncated > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink_renderer.Text, { dimColor: true, children: [
|
|
209
|
+
" ... ",
|
|
210
|
+
truncated,
|
|
211
|
+
" more lines"
|
|
212
|
+
] })
|
|
213
|
+
] });
|
|
214
|
+
}
|
|
215
|
+
function DiffLineRow({ line, gutterWidth, showLineNumbers, addedColor, removedColor, contextColor }) {
|
|
216
|
+
const lineNum = line.type === "removed" ? line.oldLineNumber : line.newLineNumber ?? line.oldLineNumber;
|
|
217
|
+
const prefix = line.type === "added" ? "+ " : line.type === "removed" ? "- " : " ";
|
|
218
|
+
const gutterStr = showLineNumbers && lineNum !== void 0 ? String(lineNum).padStart(gutterWidth) : " ".repeat(gutterWidth);
|
|
219
|
+
const contentColor = line.type === "added" ? addedColor : line.type === "removed" ? removedColor : contextColor;
|
|
220
|
+
const dim = line.type === "context" && !contextColor;
|
|
221
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink_renderer.Text, { children: [
|
|
222
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink_renderer.Text, { dimColor: true, children: gutterStr }),
|
|
223
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink_renderer.Text, { dimColor: true, children: " \u2502 " }),
|
|
224
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink_renderer.Text, { dimColor: dim, color: contentColor, children: [
|
|
225
|
+
prefix,
|
|
226
|
+
line.content
|
|
227
|
+
] })
|
|
228
|
+
] });
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// src/Divider.tsx
|
|
232
|
+
var import_react2 = require("react");
|
|
233
|
+
var import_ink_renderer2 = require("@claude-code-kit/ink-renderer");
|
|
234
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
235
|
+
function Divider({ width, color: color2, char = "\u2500", padding = 0, title }) {
|
|
236
|
+
const terminalSize = (0, import_react2.useContext)(import_ink_renderer2.TerminalSizeContext);
|
|
68
237
|
const terminalWidth = terminalSize?.columns ?? 80;
|
|
69
238
|
const effectiveWidth = Math.max(0, (width ?? terminalWidth - 2) - padding);
|
|
70
239
|
if (title) {
|
|
71
|
-
const titleWidth = (0,
|
|
240
|
+
const titleWidth = (0, import_ink_renderer2.stringWidth)(title) + 2;
|
|
72
241
|
const sideWidth = Math.max(0, effectiveWidth - titleWidth);
|
|
73
242
|
const leftWidth = Math.floor(sideWidth / 2);
|
|
74
243
|
const rightWidth = sideWidth - leftWidth;
|
|
75
|
-
return /* @__PURE__ */ (0,
|
|
244
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink_renderer2.Text, { color: color2, dimColor: !color2, children: [
|
|
76
245
|
char.repeat(leftWidth),
|
|
77
246
|
" ",
|
|
78
|
-
/* @__PURE__ */ (0,
|
|
247
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink_renderer2.Text, { dimColor: true, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink_renderer2.Ansi, { children: title }) }),
|
|
79
248
|
" ",
|
|
80
249
|
char.repeat(rightWidth)
|
|
81
250
|
] });
|
|
82
251
|
}
|
|
83
|
-
return /* @__PURE__ */ (0,
|
|
252
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink_renderer2.Text, { color: color2, dimColor: !color2, children: char.repeat(effectiveWidth) });
|
|
84
253
|
}
|
|
85
254
|
|
|
86
255
|
// src/ProgressBar.tsx
|
|
87
|
-
var
|
|
88
|
-
var
|
|
256
|
+
var import_ink_renderer3 = require("@claude-code-kit/ink-renderer");
|
|
257
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
89
258
|
var BLOCKS = [" ", "\u258F", "\u258E", "\u258D", "\u258C", "\u258B", "\u258A", "\u2589", "\u2588"];
|
|
90
259
|
function ProgressBar({ ratio: inputRatio, width, fillColor, emptyColor }) {
|
|
91
260
|
const ratio = Math.min(1, Math.max(0, inputRatio));
|
|
@@ -100,13 +269,13 @@ function ProgressBar({ ratio: inputRatio, width, fillColor, emptyColor }) {
|
|
|
100
269
|
segments.push(BLOCKS[0].repeat(empty));
|
|
101
270
|
}
|
|
102
271
|
}
|
|
103
|
-
return /* @__PURE__ */ (0,
|
|
272
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ink_renderer3.Text, { color: fillColor, backgroundColor: emptyColor, children: segments.join("") });
|
|
104
273
|
}
|
|
105
274
|
|
|
106
275
|
// src/StatusIcon.tsx
|
|
107
276
|
var import_figures = __toESM(require("figures"));
|
|
108
|
-
var
|
|
109
|
-
var
|
|
277
|
+
var import_ink_renderer4 = require("@claude-code-kit/ink-renderer");
|
|
278
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
110
279
|
var STATUS_CONFIG = {
|
|
111
280
|
success: { icon: import_figures.default.tick, color: "green" },
|
|
112
281
|
error: { icon: import_figures.default.cross, color: "red" },
|
|
@@ -117,16 +286,16 @@ var STATUS_CONFIG = {
|
|
|
117
286
|
};
|
|
118
287
|
function StatusIcon({ status, withSpace = false }) {
|
|
119
288
|
const config = STATUS_CONFIG[status];
|
|
120
|
-
return /* @__PURE__ */ (0,
|
|
289
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ink_renderer4.Text, { color: config.color, dimColor: !config.color, children: [
|
|
121
290
|
config.icon,
|
|
122
291
|
withSpace && " "
|
|
123
292
|
] });
|
|
124
293
|
}
|
|
125
294
|
|
|
126
295
|
// src/StatusLine.tsx
|
|
127
|
-
var
|
|
128
|
-
var
|
|
129
|
-
var
|
|
296
|
+
var import_react3 = __toESM(require("react"));
|
|
297
|
+
var import_ink_renderer5 = require("@claude-code-kit/ink-renderer");
|
|
298
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
130
299
|
function hasAnsi(s) {
|
|
131
300
|
return /\x1b\[/.test(s);
|
|
132
301
|
}
|
|
@@ -134,28 +303,31 @@ function StatusLine({
|
|
|
134
303
|
segments,
|
|
135
304
|
text,
|
|
136
305
|
paddingX = 1,
|
|
137
|
-
|
|
306
|
+
separator = " \xB7 ",
|
|
138
307
|
borderStyle = "none",
|
|
139
308
|
borderColor
|
|
140
309
|
}) {
|
|
141
310
|
const border = borderStyle === "none" ? void 0 : borderStyle;
|
|
142
|
-
return /* @__PURE__ */ (0,
|
|
143
|
-
|
|
311
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
312
|
+
import_ink_renderer5.Box,
|
|
144
313
|
{
|
|
145
314
|
flexDirection: "row",
|
|
146
315
|
paddingX,
|
|
147
316
|
borderStyle: border,
|
|
148
317
|
borderColor,
|
|
149
|
-
children: text !== void 0 ? hasAnsi(text) ? /* @__PURE__ */ (0,
|
|
318
|
+
children: text !== void 0 ? hasAnsi(text) ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_ink_renderer5.Ansi, { children: text }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_ink_renderer5.Text, { dimColor: true, children: text }) : segments?.map((seg, i) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react3.default.Fragment, { children: [
|
|
319
|
+
i > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_ink_renderer5.Text, { dimColor: true, children: separator }),
|
|
320
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_ink_renderer5.Box, { flexGrow: seg.flex ? 1 : 0, children: hasAnsi(seg.content) ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_ink_renderer5.Ansi, { children: seg.content }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_ink_renderer5.Text, { dimColor: true, color: seg.color, children: seg.content }) })
|
|
321
|
+
] }, i))
|
|
150
322
|
}
|
|
151
323
|
);
|
|
152
324
|
}
|
|
153
325
|
function useStatusLine(updater, deps, intervalMs) {
|
|
154
|
-
const [value, setValue] = (0,
|
|
155
|
-
(0,
|
|
326
|
+
const [value, setValue] = (0, import_react3.useState)(() => updater());
|
|
327
|
+
(0, import_react3.useEffect)(() => {
|
|
156
328
|
setValue(updater());
|
|
157
329
|
}, deps);
|
|
158
|
-
(0,
|
|
330
|
+
(0, import_react3.useEffect)(() => {
|
|
159
331
|
if (!intervalMs) return;
|
|
160
332
|
const id = setInterval(() => setValue(updater()), intervalMs);
|
|
161
333
|
return () => clearInterval(id);
|
|
@@ -260,11 +432,11 @@ var clearCommand = {
|
|
|
260
432
|
};
|
|
261
433
|
|
|
262
434
|
// src/keybindings/useKeybinding.ts
|
|
263
|
-
var
|
|
264
|
-
var
|
|
435
|
+
var import_react5 = require("react");
|
|
436
|
+
var import_ink_renderer6 = require("@claude-code-kit/ink-renderer");
|
|
265
437
|
|
|
266
438
|
// src/keybindings/KeybindingContext.tsx
|
|
267
|
-
var
|
|
439
|
+
var import_react4 = require("react");
|
|
268
440
|
|
|
269
441
|
// src/keybindings/match.ts
|
|
270
442
|
function getKeyName(input, key) {
|
|
@@ -418,10 +590,13 @@ function parseBindings(blocks) {
|
|
|
418
590
|
|
|
419
591
|
// src/keybindings/resolver.ts
|
|
420
592
|
function getBindingDisplayText(action, context, bindings) {
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
593
|
+
for (let i = bindings.length - 1; i >= 0; i--) {
|
|
594
|
+
const binding = bindings[i];
|
|
595
|
+
if (binding && binding.action === action && binding.context === context) {
|
|
596
|
+
return chordToString(binding.chord);
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
return void 0;
|
|
425
600
|
}
|
|
426
601
|
function buildKeystroke(input, key) {
|
|
427
602
|
const keyName = getKeyName(input, key);
|
|
@@ -508,8 +683,8 @@ function resolveKeyWithChordState(input, key, activeContexts, bindings, pending)
|
|
|
508
683
|
}
|
|
509
684
|
|
|
510
685
|
// src/keybindings/KeybindingContext.tsx
|
|
511
|
-
var
|
|
512
|
-
var KeybindingContext = (0,
|
|
686
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
687
|
+
var KeybindingContext = (0, import_react4.createContext)(null);
|
|
513
688
|
function KeybindingProvider({
|
|
514
689
|
bindings,
|
|
515
690
|
pendingChordRef,
|
|
@@ -521,11 +696,11 @@ function KeybindingProvider({
|
|
|
521
696
|
handlerRegistryRef,
|
|
522
697
|
children
|
|
523
698
|
}) {
|
|
524
|
-
const getDisplayText = (0,
|
|
699
|
+
const getDisplayText = (0, import_react4.useMemo)(
|
|
525
700
|
() => (action, context) => getBindingDisplayText(action, context, bindings),
|
|
526
701
|
[bindings]
|
|
527
702
|
);
|
|
528
|
-
const registerHandler = (0,
|
|
703
|
+
const registerHandler = (0, import_react4.useMemo)(
|
|
529
704
|
() => (registration) => {
|
|
530
705
|
const registry = handlerRegistryRef.current;
|
|
531
706
|
if (!registry) return () => {
|
|
@@ -546,7 +721,7 @@ function KeybindingProvider({
|
|
|
546
721
|
},
|
|
547
722
|
[handlerRegistryRef]
|
|
548
723
|
);
|
|
549
|
-
const invokeAction = (0,
|
|
724
|
+
const invokeAction = (0, import_react4.useMemo)(
|
|
550
725
|
() => (action) => {
|
|
551
726
|
const registry = handlerRegistryRef.current;
|
|
552
727
|
if (!registry) return false;
|
|
@@ -562,7 +737,7 @@ function KeybindingProvider({
|
|
|
562
737
|
},
|
|
563
738
|
[activeContexts, handlerRegistryRef]
|
|
564
739
|
);
|
|
565
|
-
const resolve = (0,
|
|
740
|
+
const resolve = (0, import_react4.useMemo)(
|
|
566
741
|
() => (input, key, contexts) => resolveKeyWithChordState(
|
|
567
742
|
input,
|
|
568
743
|
key,
|
|
@@ -572,7 +747,7 @@ function KeybindingProvider({
|
|
|
572
747
|
),
|
|
573
748
|
[bindings, pendingChordRef]
|
|
574
749
|
);
|
|
575
|
-
const value = (0,
|
|
750
|
+
const value = (0, import_react4.useMemo)(
|
|
576
751
|
() => ({
|
|
577
752
|
resolve,
|
|
578
753
|
setPendingChord,
|
|
@@ -598,21 +773,21 @@ function KeybindingProvider({
|
|
|
598
773
|
invokeAction
|
|
599
774
|
]
|
|
600
775
|
);
|
|
601
|
-
return /* @__PURE__ */ (0,
|
|
776
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(KeybindingContext.Provider, { value, children });
|
|
602
777
|
}
|
|
603
778
|
function useOptionalKeybindingContext() {
|
|
604
|
-
return (0,
|
|
779
|
+
return (0, import_react4.useContext)(KeybindingContext);
|
|
605
780
|
}
|
|
606
781
|
|
|
607
782
|
// src/keybindings/useKeybinding.ts
|
|
608
783
|
function useKeybinding(action, handler, options = {}) {
|
|
609
784
|
const { context = "Global", isActive = true } = options;
|
|
610
785
|
const keybindingContext = useOptionalKeybindingContext();
|
|
611
|
-
(0,
|
|
786
|
+
(0, import_react5.useEffect)(() => {
|
|
612
787
|
if (!keybindingContext || !isActive) return;
|
|
613
788
|
return keybindingContext.registerHandler({ action, context, handler });
|
|
614
789
|
}, [action, context, handler, keybindingContext, isActive]);
|
|
615
|
-
const handleInput = (0,
|
|
790
|
+
const handleInput = (0, import_react5.useCallback)(
|
|
616
791
|
(input, key, event) => {
|
|
617
792
|
if (!keybindingContext) return;
|
|
618
793
|
const contextsToCheck = [
|
|
@@ -648,12 +823,12 @@ function useKeybinding(action, handler, options = {}) {
|
|
|
648
823
|
},
|
|
649
824
|
[action, context, handler, keybindingContext]
|
|
650
825
|
);
|
|
651
|
-
(0,
|
|
826
|
+
(0, import_ink_renderer6.useInput)(handleInput, { isActive });
|
|
652
827
|
}
|
|
653
828
|
function useKeybindings(handlers, options = {}) {
|
|
654
829
|
const { context = "Global", isActive = true } = options;
|
|
655
830
|
const keybindingContext = useOptionalKeybindingContext();
|
|
656
|
-
(0,
|
|
831
|
+
(0, import_react5.useEffect)(() => {
|
|
657
832
|
if (!keybindingContext || !isActive) return;
|
|
658
833
|
const unregisterFns = [];
|
|
659
834
|
for (const [action, handler] of Object.entries(handlers)) {
|
|
@@ -667,7 +842,7 @@ function useKeybindings(handlers, options = {}) {
|
|
|
667
842
|
}
|
|
668
843
|
};
|
|
669
844
|
}, [context, handlers, keybindingContext, isActive]);
|
|
670
|
-
const handleInput = (0,
|
|
845
|
+
const handleInput = (0, import_react5.useCallback)(
|
|
671
846
|
(input, key, event) => {
|
|
672
847
|
if (!keybindingContext) return;
|
|
673
848
|
const contextsToCheck = [
|
|
@@ -704,12 +879,12 @@ function useKeybindings(handlers, options = {}) {
|
|
|
704
879
|
},
|
|
705
880
|
[context, handlers, keybindingContext]
|
|
706
881
|
);
|
|
707
|
-
(0,
|
|
882
|
+
(0, import_ink_renderer6.useInput)(handleInput, { isActive });
|
|
708
883
|
}
|
|
709
884
|
|
|
710
885
|
// src/keybindings/KeybindingProviderSetup.tsx
|
|
711
|
-
var
|
|
712
|
-
var
|
|
886
|
+
var import_react6 = require("react");
|
|
887
|
+
var import_ink_renderer7 = require("@claude-code-kit/ink-renderer");
|
|
713
888
|
|
|
714
889
|
// src/keybindings/loadUserBindings.ts
|
|
715
890
|
var import_chokidar = __toESM(require("chokidar"));
|
|
@@ -1577,22 +1752,22 @@ function handleDelete(path) {
|
|
|
1577
1752
|
}
|
|
1578
1753
|
|
|
1579
1754
|
// src/keybindings/KeybindingProviderSetup.tsx
|
|
1580
|
-
var
|
|
1755
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
1581
1756
|
var plural = (n, s) => n === 1 ? s : s + "s";
|
|
1582
1757
|
function logForDebugging2(msg) {
|
|
1583
1758
|
if (process.env.DEBUG_KEYBINDINGS) console.error(msg);
|
|
1584
1759
|
}
|
|
1585
1760
|
var CHORD_TIMEOUT_MS = 1e3;
|
|
1586
1761
|
function KeybindingSetup({ children, onWarnings }) {
|
|
1587
|
-
const [{ bindings, warnings }, setLoadResult] = (0,
|
|
1762
|
+
const [{ bindings, warnings }, setLoadResult] = (0, import_react6.useState)(() => {
|
|
1588
1763
|
const result = loadKeybindingsSyncWithWarnings();
|
|
1589
1764
|
logForDebugging2(
|
|
1590
1765
|
`[keybindings] KeybindingSetup initialized with ${result.bindings.length} bindings, ${result.warnings.length} warnings`
|
|
1591
1766
|
);
|
|
1592
1767
|
return result;
|
|
1593
1768
|
});
|
|
1594
|
-
const [isReload, setIsReload] = (0,
|
|
1595
|
-
(0,
|
|
1769
|
+
const [isReload, setIsReload] = (0, import_react6.useState)(false);
|
|
1770
|
+
(0, import_react6.useEffect)(() => {
|
|
1596
1771
|
if (!onWarnings || warnings.length === 0) return;
|
|
1597
1772
|
const errorCount = warnings.filter((w) => w.severity === "error").length;
|
|
1598
1773
|
const warnCount = warnings.filter((w) => w.severity === "warning").length;
|
|
@@ -1606,29 +1781,29 @@ function KeybindingSetup({ children, onWarnings }) {
|
|
|
1606
1781
|
}
|
|
1607
1782
|
onWarnings(message + " \xB7 /doctor for details", errorCount > 0);
|
|
1608
1783
|
}, [warnings, isReload, onWarnings]);
|
|
1609
|
-
const pendingChordRef = (0,
|
|
1610
|
-
const [pendingChord, setPendingChordState] = (0,
|
|
1611
|
-
const chordTimeoutRef = (0,
|
|
1612
|
-
const handlerRegistryRef = (0,
|
|
1784
|
+
const pendingChordRef = (0, import_react6.useRef)(null);
|
|
1785
|
+
const [pendingChord, setPendingChordState] = (0, import_react6.useState)(null);
|
|
1786
|
+
const chordTimeoutRef = (0, import_react6.useRef)(null);
|
|
1787
|
+
const handlerRegistryRef = (0, import_react6.useRef)(
|
|
1613
1788
|
/* @__PURE__ */ new Map()
|
|
1614
1789
|
);
|
|
1615
|
-
const activeContextsRef = (0,
|
|
1616
|
-
const registerActiveContext = (0,
|
|
1790
|
+
const activeContextsRef = (0, import_react6.useRef)(/* @__PURE__ */ new Set());
|
|
1791
|
+
const registerActiveContext = (0, import_react6.useCallback)((context) => {
|
|
1617
1792
|
activeContextsRef.current.add(context);
|
|
1618
1793
|
}, []);
|
|
1619
|
-
const unregisterActiveContext = (0,
|
|
1794
|
+
const unregisterActiveContext = (0, import_react6.useCallback)(
|
|
1620
1795
|
(context) => {
|
|
1621
1796
|
activeContextsRef.current.delete(context);
|
|
1622
1797
|
},
|
|
1623
1798
|
[]
|
|
1624
1799
|
);
|
|
1625
|
-
const clearChordTimeout = (0,
|
|
1800
|
+
const clearChordTimeout = (0, import_react6.useCallback)(() => {
|
|
1626
1801
|
if (chordTimeoutRef.current) {
|
|
1627
1802
|
clearTimeout(chordTimeoutRef.current);
|
|
1628
1803
|
chordTimeoutRef.current = null;
|
|
1629
1804
|
}
|
|
1630
1805
|
}, []);
|
|
1631
|
-
const setPendingChord = (0,
|
|
1806
|
+
const setPendingChord = (0, import_react6.useCallback)(
|
|
1632
1807
|
(pending) => {
|
|
1633
1808
|
clearChordTimeout();
|
|
1634
1809
|
if (pending !== null) {
|
|
@@ -1643,7 +1818,7 @@ function KeybindingSetup({ children, onWarnings }) {
|
|
|
1643
1818
|
},
|
|
1644
1819
|
[clearChordTimeout]
|
|
1645
1820
|
);
|
|
1646
|
-
(0,
|
|
1821
|
+
(0, import_react6.useEffect)(() => {
|
|
1647
1822
|
void initializeKeybindingWatcher();
|
|
1648
1823
|
const unsubscribe = subscribeToKeybindingChanges((result) => {
|
|
1649
1824
|
setIsReload(true);
|
|
@@ -1657,7 +1832,7 @@ function KeybindingSetup({ children, onWarnings }) {
|
|
|
1657
1832
|
clearChordTimeout();
|
|
1658
1833
|
};
|
|
1659
1834
|
}, [clearChordTimeout]);
|
|
1660
|
-
return /* @__PURE__ */ (0,
|
|
1835
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
1661
1836
|
KeybindingProvider,
|
|
1662
1837
|
{
|
|
1663
1838
|
bindings,
|
|
@@ -1669,7 +1844,7 @@ function KeybindingSetup({ children, onWarnings }) {
|
|
|
1669
1844
|
unregisterActiveContext,
|
|
1670
1845
|
handlerRegistryRef,
|
|
1671
1846
|
children: [
|
|
1672
|
-
/* @__PURE__ */ (0,
|
|
1847
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1673
1848
|
ChordInterceptor,
|
|
1674
1849
|
{
|
|
1675
1850
|
bindings,
|
|
@@ -1691,7 +1866,7 @@ function ChordInterceptor({
|
|
|
1691
1866
|
activeContexts,
|
|
1692
1867
|
handlerRegistryRef
|
|
1693
1868
|
}) {
|
|
1694
|
-
const handleInput = (0,
|
|
1869
|
+
const handleInput = (0, import_react6.useCallback)(
|
|
1695
1870
|
(input, key, event) => {
|
|
1696
1871
|
if ((key.wheelUp || key.wheelDown) && pendingChordRef.current === null) {
|
|
1697
1872
|
return;
|
|
@@ -1755,14 +1930,102 @@ function ChordInterceptor({
|
|
|
1755
1930
|
},
|
|
1756
1931
|
[bindings, pendingChordRef, setPendingChord, activeContexts, handlerRegistryRef]
|
|
1757
1932
|
);
|
|
1758
|
-
(0,
|
|
1933
|
+
(0, import_ink_renderer7.useInput)(handleInput);
|
|
1759
1934
|
return null;
|
|
1760
1935
|
}
|
|
1761
1936
|
|
|
1937
|
+
// src/hooks/useDoublePress.ts
|
|
1938
|
+
var import_react7 = require("react");
|
|
1939
|
+
var DOUBLE_PRESS_TIMEOUT_MS = 800;
|
|
1940
|
+
function useDoublePress(setPending, onDoublePress, onFirstPress) {
|
|
1941
|
+
const lastPressRef = (0, import_react7.useRef)(0);
|
|
1942
|
+
const timeoutRef = (0, import_react7.useRef)(void 0);
|
|
1943
|
+
const clearTimeoutSafe = (0, import_react7.useCallback)(() => {
|
|
1944
|
+
if (timeoutRef.current) {
|
|
1945
|
+
clearTimeout(timeoutRef.current);
|
|
1946
|
+
timeoutRef.current = void 0;
|
|
1947
|
+
}
|
|
1948
|
+
}, []);
|
|
1949
|
+
(0, import_react7.useEffect)(() => {
|
|
1950
|
+
return () => {
|
|
1951
|
+
clearTimeoutSafe();
|
|
1952
|
+
};
|
|
1953
|
+
}, [clearTimeoutSafe]);
|
|
1954
|
+
return (0, import_react7.useCallback)(() => {
|
|
1955
|
+
const now = Date.now();
|
|
1956
|
+
const timeSinceLastPress = now - lastPressRef.current;
|
|
1957
|
+
const isDoublePress = timeSinceLastPress <= DOUBLE_PRESS_TIMEOUT_MS && timeoutRef.current !== void 0;
|
|
1958
|
+
if (isDoublePress) {
|
|
1959
|
+
clearTimeoutSafe();
|
|
1960
|
+
setPending(false);
|
|
1961
|
+
onDoublePress();
|
|
1962
|
+
} else {
|
|
1963
|
+
onFirstPress?.();
|
|
1964
|
+
setPending(true);
|
|
1965
|
+
clearTimeoutSafe();
|
|
1966
|
+
timeoutRef.current = setTimeout(
|
|
1967
|
+
(setPending2, timeoutRef2) => {
|
|
1968
|
+
setPending2(false);
|
|
1969
|
+
timeoutRef2.current = void 0;
|
|
1970
|
+
},
|
|
1971
|
+
DOUBLE_PRESS_TIMEOUT_MS,
|
|
1972
|
+
setPending,
|
|
1973
|
+
timeoutRef
|
|
1974
|
+
);
|
|
1975
|
+
}
|
|
1976
|
+
lastPressRef.current = now;
|
|
1977
|
+
}, [setPending, onDoublePress, onFirstPress, clearTimeoutSafe]);
|
|
1978
|
+
}
|
|
1979
|
+
|
|
1980
|
+
// src/hooks/useTerminalSize.ts
|
|
1981
|
+
var import_react8 = require("react");
|
|
1982
|
+
var import_ink_renderer8 = require("@claude-code-kit/ink-renderer");
|
|
1983
|
+
function useTerminalSize() {
|
|
1984
|
+
const size = (0, import_react8.useContext)(import_ink_renderer8.TerminalSizeContext);
|
|
1985
|
+
if (!size) {
|
|
1986
|
+
throw new Error("useTerminalSize must be used within an Ink App component");
|
|
1987
|
+
}
|
|
1988
|
+
return size;
|
|
1989
|
+
}
|
|
1990
|
+
|
|
1762
1991
|
// src/PromptInput.tsx
|
|
1763
|
-
var
|
|
1764
|
-
var
|
|
1765
|
-
|
|
1992
|
+
var import_react9 = require("react");
|
|
1993
|
+
var import_ink_renderer9 = require("@claude-code-kit/ink-renderer");
|
|
1994
|
+
|
|
1995
|
+
// src/utils/promptInputLogic.ts
|
|
1996
|
+
function wordFwd(s, p) {
|
|
1997
|
+
let i = p;
|
|
1998
|
+
while (i < s.length && s[i] !== " ") i++;
|
|
1999
|
+
while (i < s.length && s[i] === " ") i++;
|
|
2000
|
+
return i;
|
|
2001
|
+
}
|
|
2002
|
+
function wordBwd(s, p) {
|
|
2003
|
+
let i = p;
|
|
2004
|
+
if (i > 0) i--;
|
|
2005
|
+
while (i > 0 && s[i] === " ") i--;
|
|
2006
|
+
while (i > 0 && s[i - 1] !== " ") i--;
|
|
2007
|
+
return i;
|
|
2008
|
+
}
|
|
2009
|
+
function lineOffset(lines, line) {
|
|
2010
|
+
let pos = 0;
|
|
2011
|
+
for (let i = 0; i < line; i++) pos += lines[i].length + 1;
|
|
2012
|
+
return pos;
|
|
2013
|
+
}
|
|
2014
|
+
function cursorLineIndex(lines, cursor) {
|
|
2015
|
+
let pos = 0;
|
|
2016
|
+
for (let i = 0; i < lines.length; i++) {
|
|
2017
|
+
if (cursor <= pos + lines[i].length) return i;
|
|
2018
|
+
pos += lines[i].length + 1;
|
|
2019
|
+
}
|
|
2020
|
+
return lines.length - 1;
|
|
2021
|
+
}
|
|
2022
|
+
function filterCommands(commands, value) {
|
|
2023
|
+
if (!value.startsWith("/")) return [];
|
|
2024
|
+
return commands.filter((cmd) => `/${cmd.name}`.startsWith(value));
|
|
2025
|
+
}
|
|
2026
|
+
|
|
2027
|
+
// src/PromptInput.tsx
|
|
2028
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
1766
2029
|
function PromptInput({
|
|
1767
2030
|
value,
|
|
1768
2031
|
onChange,
|
|
@@ -1773,186 +2036,302 @@ function PromptInput({
|
|
|
1773
2036
|
disabled = false,
|
|
1774
2037
|
commands = [],
|
|
1775
2038
|
onCommandSelect,
|
|
1776
|
-
history = []
|
|
2039
|
+
history = [],
|
|
2040
|
+
vimMode = false,
|
|
2041
|
+
multiline = false
|
|
1777
2042
|
}) {
|
|
1778
|
-
const [cursor, setCursor] = (0,
|
|
1779
|
-
const [historyIndex, setHistoryIndex] = (0,
|
|
1780
|
-
const [suggestionIndex, setSuggestionIndex] = (0,
|
|
1781
|
-
const [showSuggestions, setShowSuggestions] = (0,
|
|
1782
|
-
const
|
|
2043
|
+
const [cursor, setCursor] = (0, import_react9.useState)(0);
|
|
2044
|
+
const [historyIndex, setHistoryIndex] = (0, import_react9.useState)(-1);
|
|
2045
|
+
const [suggestionIndex, setSuggestionIndex] = (0, import_react9.useState)(0);
|
|
2046
|
+
const [showSuggestions, setShowSuggestions] = (0, import_react9.useState)(false);
|
|
2047
|
+
const [vim, setVim] = (0, import_react9.useState)("INSERT");
|
|
2048
|
+
const [pendingD, setPendingD] = (0, import_react9.useState)(false);
|
|
2049
|
+
const isVimNormal = vimMode && vim === "NORMAL";
|
|
2050
|
+
const suggestions = commands.length > 0 ? filterCommands(commands, value) : [];
|
|
1783
2051
|
const hasSuggestions = showSuggestions && suggestions.length > 0;
|
|
1784
|
-
const
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
2052
|
+
const lines = multiline ? value.split("\n") : [value];
|
|
2053
|
+
const cursorLine = multiline ? cursorLineIndex(lines, cursor) : 0;
|
|
2054
|
+
const lineOffset2 = (line) => lineOffset(lines, line);
|
|
2055
|
+
const updateValue = (0, import_react9.useCallback)((nv, nc) => {
|
|
2056
|
+
onChange(nv);
|
|
2057
|
+
setCursor(nc ?? nv.length);
|
|
2058
|
+
setHistoryIndex(-1);
|
|
2059
|
+
setShowSuggestions(nv.startsWith("/"));
|
|
2060
|
+
setSuggestionIndex(0);
|
|
2061
|
+
}, [onChange]);
|
|
2062
|
+
const insertNewline = () => {
|
|
2063
|
+
updateValue(value.slice(0, cursor) + "\n" + value.slice(cursor), cursor + 1);
|
|
2064
|
+
};
|
|
2065
|
+
const moveLine = (dir) => {
|
|
2066
|
+
const target = cursorLine + dir;
|
|
2067
|
+
if (multiline && target >= 0 && target < lines.length) {
|
|
2068
|
+
const col = cursor - lineOffset2(cursorLine);
|
|
2069
|
+
setCursor(lineOffset2(target) + Math.min(col, lines[target].length));
|
|
2070
|
+
return true;
|
|
2071
|
+
}
|
|
2072
|
+
return false;
|
|
2073
|
+
};
|
|
2074
|
+
const historyUp = () => {
|
|
2075
|
+
if (history.length > 0 && historyIndex + 1 < history.length) {
|
|
2076
|
+
const ni = historyIndex + 1;
|
|
2077
|
+
setHistoryIndex(ni);
|
|
2078
|
+
const hv = history[ni];
|
|
2079
|
+
onChange(hv);
|
|
2080
|
+
setCursor(hv.length);
|
|
2081
|
+
}
|
|
2082
|
+
};
|
|
2083
|
+
const historyDown = () => {
|
|
2084
|
+
if (historyIndex > 0) {
|
|
2085
|
+
const ni = historyIndex - 1;
|
|
2086
|
+
setHistoryIndex(ni);
|
|
2087
|
+
const hv = history[ni];
|
|
2088
|
+
onChange(hv);
|
|
2089
|
+
setCursor(hv.length);
|
|
2090
|
+
} else if (historyIndex === 0) {
|
|
1788
2091
|
setHistoryIndex(-1);
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
}
|
|
1792
|
-
|
|
1793
|
-
)
|
|
1794
|
-
|
|
1795
|
-
(
|
|
1796
|
-
if (
|
|
1797
|
-
if (
|
|
1798
|
-
|
|
1799
|
-
const cmd = suggestions[suggestionIndex];
|
|
1800
|
-
const cmdValue = `/${cmd.name}`;
|
|
1801
|
-
onCommandSelect?.(cmd.name);
|
|
1802
|
-
onChange(cmdValue);
|
|
1803
|
-
setCursor(cmdValue.length);
|
|
1804
|
-
setShowSuggestions(false);
|
|
1805
|
-
return;
|
|
1806
|
-
}
|
|
1807
|
-
if (value.length > 0) {
|
|
1808
|
-
onSubmit(value);
|
|
1809
|
-
}
|
|
2092
|
+
onChange("");
|
|
2093
|
+
setCursor(0);
|
|
2094
|
+
}
|
|
2095
|
+
};
|
|
2096
|
+
(0, import_ink_renderer9.useInput)((input, key) => {
|
|
2097
|
+
if (disabled) return;
|
|
2098
|
+
if (isVimNormal) {
|
|
2099
|
+
if (input !== "d") setPendingD(false);
|
|
2100
|
+
if (input === "i") {
|
|
2101
|
+
setVim("INSERT");
|
|
1810
2102
|
return;
|
|
1811
2103
|
}
|
|
1812
|
-
if (
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
}
|
|
2104
|
+
if (input === "a") {
|
|
2105
|
+
setVim("INSERT");
|
|
2106
|
+
setCursor((c) => Math.min(value.length, c + 1));
|
|
1816
2107
|
return;
|
|
1817
2108
|
}
|
|
1818
|
-
if (key.
|
|
1819
|
-
|
|
1820
|
-
const cmd = suggestions[suggestionIndex];
|
|
1821
|
-
const cmdValue = `/${cmd.name} `;
|
|
1822
|
-
updateValue(cmdValue);
|
|
1823
|
-
}
|
|
2109
|
+
if (input === "h" || key.leftArrow) {
|
|
2110
|
+
setCursor((c) => Math.max(0, c - 1));
|
|
1824
2111
|
return;
|
|
1825
2112
|
}
|
|
1826
|
-
if (key.
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
2113
|
+
if (input === "l" || key.rightArrow) {
|
|
2114
|
+
setCursor((c) => Math.min(Math.max(0, value.length - 1), c + 1));
|
|
2115
|
+
return;
|
|
2116
|
+
}
|
|
2117
|
+
if (input === "0" || key.home) {
|
|
2118
|
+
setCursor(multiline ? lineOffset2(cursorLine) : 0);
|
|
2119
|
+
return;
|
|
2120
|
+
}
|
|
2121
|
+
if (input === "$" || key.end) {
|
|
2122
|
+
if (multiline) {
|
|
2123
|
+
const endOfLine = lineOffset2(cursorLine) + lines[cursorLine].length;
|
|
2124
|
+
setCursor(Math.max(lineOffset2(cursorLine), endOfLine - 1));
|
|
2125
|
+
} else {
|
|
2126
|
+
setCursor(Math.max(0, value.length - 1));
|
|
1830
2127
|
}
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
2128
|
+
return;
|
|
2129
|
+
}
|
|
2130
|
+
if (input === "w") {
|
|
2131
|
+
setCursor(wordFwd(value, cursor));
|
|
2132
|
+
return;
|
|
2133
|
+
}
|
|
2134
|
+
if (input === "b") {
|
|
2135
|
+
setCursor(wordBwd(value, cursor));
|
|
2136
|
+
return;
|
|
2137
|
+
}
|
|
2138
|
+
if (input === "x") {
|
|
2139
|
+
if (cursor < value.length) {
|
|
2140
|
+
const nv = value.slice(0, cursor) + value.slice(cursor + 1);
|
|
2141
|
+
updateValue(nv, Math.min(cursor, Math.max(0, nv.length - 1)));
|
|
1839
2142
|
}
|
|
1840
2143
|
return;
|
|
1841
2144
|
}
|
|
1842
|
-
if (
|
|
1843
|
-
if (
|
|
1844
|
-
|
|
2145
|
+
if (input === "d") {
|
|
2146
|
+
if (!pendingD) {
|
|
2147
|
+
setPendingD(true);
|
|
1845
2148
|
return;
|
|
1846
2149
|
}
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
const
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
2150
|
+
setPendingD(false);
|
|
2151
|
+
if (multiline && lines.length > 1) {
|
|
2152
|
+
const pos = lineOffset2(cursorLine);
|
|
2153
|
+
const end = pos + lines[cursorLine].length;
|
|
2154
|
+
const from = cursorLine === 0 ? pos : pos - 1;
|
|
2155
|
+
const to = cursorLine === 0 ? Math.min(end + 1, value.length) : end;
|
|
2156
|
+
const nv = value.slice(0, from) + value.slice(to);
|
|
2157
|
+
updateValue(nv, Math.min(from, Math.max(0, nv.length - 1)));
|
|
2158
|
+
} else {
|
|
2159
|
+
updateValue("", 0);
|
|
1857
2160
|
}
|
|
1858
2161
|
return;
|
|
1859
2162
|
}
|
|
1860
|
-
if (key.
|
|
1861
|
-
|
|
2163
|
+
if (key.upArrow || input === "k" && !key.ctrl) {
|
|
2164
|
+
if (!moveLine(-1)) historyUp();
|
|
1862
2165
|
return;
|
|
1863
2166
|
}
|
|
1864
|
-
if (key.
|
|
1865
|
-
|
|
2167
|
+
if (key.downArrow || input === "j" && !key.ctrl) {
|
|
2168
|
+
if (!moveLine(1)) historyDown();
|
|
1866
2169
|
return;
|
|
1867
2170
|
}
|
|
1868
|
-
if (key.
|
|
1869
|
-
|
|
2171
|
+
if (key.return && value.length > 0) {
|
|
2172
|
+
onSubmit(value);
|
|
1870
2173
|
return;
|
|
1871
2174
|
}
|
|
1872
|
-
|
|
1873
|
-
|
|
2175
|
+
return;
|
|
2176
|
+
}
|
|
2177
|
+
if (key.return) {
|
|
2178
|
+
if (hasSuggestions) {
|
|
2179
|
+
const cmd = suggestions[suggestionIndex];
|
|
2180
|
+
const cv = `/${cmd.name}`;
|
|
2181
|
+
onCommandSelect?.(cmd.name);
|
|
2182
|
+
onChange(cv);
|
|
2183
|
+
setCursor(cv.length);
|
|
2184
|
+
setShowSuggestions(false);
|
|
1874
2185
|
return;
|
|
1875
2186
|
}
|
|
1876
|
-
if (
|
|
1877
|
-
|
|
1878
|
-
let i = cursor - 1;
|
|
1879
|
-
while (i > 0 && value[i - 1] === " ") i--;
|
|
1880
|
-
while (i > 0 && value[i - 1] !== " ") i--;
|
|
1881
|
-
const newValue = value.slice(0, i) + value.slice(cursor);
|
|
1882
|
-
updateValue(newValue, i);
|
|
1883
|
-
}
|
|
2187
|
+
if (multiline && key.shift) {
|
|
2188
|
+
insertNewline();
|
|
1884
2189
|
return;
|
|
1885
2190
|
}
|
|
1886
|
-
if (
|
|
1887
|
-
|
|
1888
|
-
|
|
2191
|
+
if (value.length > 0) onSubmit(value);
|
|
2192
|
+
return;
|
|
2193
|
+
}
|
|
2194
|
+
if (key.escape) {
|
|
2195
|
+
if (hasSuggestions) {
|
|
2196
|
+
setShowSuggestions(false);
|
|
1889
2197
|
return;
|
|
1890
2198
|
}
|
|
1891
|
-
if (
|
|
1892
|
-
|
|
1893
|
-
const newValue = value.slice(0, cursor - 1) + value.slice(cursor);
|
|
1894
|
-
updateValue(newValue, cursor - 1);
|
|
1895
|
-
}
|
|
2199
|
+
if (vimMode) {
|
|
2200
|
+
setVim("NORMAL");
|
|
1896
2201
|
return;
|
|
1897
2202
|
}
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
2203
|
+
return;
|
|
2204
|
+
}
|
|
2205
|
+
if (multiline && key.ctrl && input === "j") {
|
|
2206
|
+
insertNewline();
|
|
2207
|
+
return;
|
|
2208
|
+
}
|
|
2209
|
+
if (key.tab) {
|
|
2210
|
+
if (hasSuggestions) {
|
|
2211
|
+
updateValue(`/${suggestions[suggestionIndex].name} `);
|
|
2212
|
+
}
|
|
2213
|
+
;
|
|
2214
|
+
return;
|
|
2215
|
+
}
|
|
2216
|
+
if (key.upArrow) {
|
|
2217
|
+
if (hasSuggestions) {
|
|
2218
|
+
setSuggestionIndex((i) => i > 0 ? i - 1 : suggestions.length - 1);
|
|
1903
2219
|
return;
|
|
1904
2220
|
}
|
|
1905
|
-
if (
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
2221
|
+
if (!moveLine(-1)) historyUp();
|
|
2222
|
+
return;
|
|
2223
|
+
}
|
|
2224
|
+
if (key.downArrow) {
|
|
2225
|
+
if (hasSuggestions) {
|
|
2226
|
+
setSuggestionIndex((i) => i < suggestions.length - 1 ? i + 1 : 0);
|
|
2227
|
+
return;
|
|
1909
2228
|
}
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
return
|
|
1916
|
-
|
|
1917
|
-
|
|
2229
|
+
if (!moveLine(1)) historyDown();
|
|
2230
|
+
return;
|
|
2231
|
+
}
|
|
2232
|
+
if (key.leftArrow) {
|
|
2233
|
+
setCursor((c) => Math.max(0, c - 1));
|
|
2234
|
+
return;
|
|
2235
|
+
}
|
|
2236
|
+
if (key.rightArrow) {
|
|
2237
|
+
setCursor((c) => Math.min(value.length, c + 1));
|
|
2238
|
+
return;
|
|
2239
|
+
}
|
|
2240
|
+
if (key.home || key.ctrl && input === "a") {
|
|
2241
|
+
setCursor(0);
|
|
2242
|
+
return;
|
|
2243
|
+
}
|
|
2244
|
+
if (key.end || key.ctrl && input === "e") {
|
|
2245
|
+
setCursor(value.length);
|
|
2246
|
+
return;
|
|
2247
|
+
}
|
|
2248
|
+
if (key.ctrl && input === "w") {
|
|
2249
|
+
if (cursor > 0) {
|
|
2250
|
+
let i = cursor - 1;
|
|
2251
|
+
while (i > 0 && value[i - 1] === " ") i--;
|
|
2252
|
+
while (i > 0 && value[i - 1] !== " ") i--;
|
|
2253
|
+
updateValue(value.slice(0, i) + value.slice(cursor), i);
|
|
2254
|
+
}
|
|
2255
|
+
;
|
|
2256
|
+
return;
|
|
2257
|
+
}
|
|
2258
|
+
if (key.ctrl && input === "u") {
|
|
2259
|
+
updateValue(value.slice(cursor), 0);
|
|
2260
|
+
return;
|
|
2261
|
+
}
|
|
2262
|
+
if (key.backspace) {
|
|
2263
|
+
if (cursor > 0) updateValue(value.slice(0, cursor - 1) + value.slice(cursor), cursor - 1);
|
|
2264
|
+
return;
|
|
2265
|
+
}
|
|
2266
|
+
if (key.delete) {
|
|
2267
|
+
if (cursor < value.length) updateValue(value.slice(0, cursor) + value.slice(cursor + 1), cursor);
|
|
2268
|
+
return;
|
|
2269
|
+
}
|
|
2270
|
+
if (key.ctrl || key.meta) return;
|
|
2271
|
+
if (input.length > 0) updateValue(value.slice(0, cursor) + input + value.slice(cursor), cursor + input.length);
|
|
2272
|
+
}, { isActive: !disabled });
|
|
2273
|
+
const renderCursor = (text, cur) => {
|
|
2274
|
+
if (text.length === 0 && placeholder && cursor === 0) {
|
|
2275
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink_renderer9.Text, { children: [
|
|
2276
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink_renderer9.Text, { inverse: true, children: " " }),
|
|
2277
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink_renderer9.Text, { dimColor: true, children: placeholder })
|
|
1918
2278
|
] });
|
|
1919
2279
|
}
|
|
1920
|
-
const before =
|
|
1921
|
-
const
|
|
1922
|
-
const after =
|
|
1923
|
-
return /* @__PURE__ */ (0,
|
|
2280
|
+
const before = text.slice(0, cur);
|
|
2281
|
+
const at = cur < text.length ? text[cur] : " ";
|
|
2282
|
+
const after = cur < text.length ? text.slice(cur + 1) : "";
|
|
2283
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink_renderer9.Text, { children: [
|
|
1924
2284
|
before,
|
|
1925
|
-
/* @__PURE__ */ (0,
|
|
2285
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink_renderer9.Text, { inverse: true, children: at }),
|
|
1926
2286
|
after
|
|
1927
2287
|
] });
|
|
1928
2288
|
};
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
/* @__PURE__ */ (0,
|
|
1947
|
-
|
|
2289
|
+
const vimTag = vimMode ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink_renderer9.Text, { dimColor: true, children: ` -- ${vim} --` }) : null;
|
|
2290
|
+
const renderContent = () => {
|
|
2291
|
+
if (!multiline || lines.length <= 1) {
|
|
2292
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink_renderer9.Box, { children: [
|
|
2293
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink_renderer9.Text, { color: prefixColor, children: [
|
|
2294
|
+
prefix,
|
|
2295
|
+
" "
|
|
2296
|
+
] }),
|
|
2297
|
+
renderCursor(value, cursor),
|
|
2298
|
+
vimTag
|
|
2299
|
+
] });
|
|
2300
|
+
}
|
|
2301
|
+
let off = 0;
|
|
2302
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink_renderer9.Box, { flexDirection: "column", children: lines.map((line, i) => {
|
|
2303
|
+
const ls = off;
|
|
2304
|
+
off += line.length + 1;
|
|
2305
|
+
const active = i === cursorLine;
|
|
2306
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink_renderer9.Box, { children: [
|
|
2307
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink_renderer9.Text, { color: prefixColor, children: i === 0 ? `${prefix} ` : "\u2219 " }),
|
|
2308
|
+
active ? renderCursor(line, cursor - ls) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink_renderer9.Text, { children: line }),
|
|
2309
|
+
i === lines.length - 1 && vimTag
|
|
2310
|
+
] }, i);
|
|
2311
|
+
}) });
|
|
2312
|
+
};
|
|
2313
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink_renderer9.Box, { flexDirection: "column", children: [
|
|
2314
|
+
renderContent(),
|
|
2315
|
+
hasSuggestions && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink_renderer9.Box, { flexDirection: "column", marginLeft: 2, children: suggestions.map((cmd, i) => {
|
|
2316
|
+
const isFocused = i === suggestionIndex;
|
|
2317
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink_renderer9.Box, { children: [
|
|
2318
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink_renderer9.Text, { color: isFocused ? "cyan" : void 0, children: [
|
|
2319
|
+
isFocused ? "\u276F" : " ",
|
|
2320
|
+
" "
|
|
2321
|
+
] }),
|
|
2322
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink_renderer9.Text, { color: isFocused ? "cyan" : void 0, bold: isFocused, children: `/${cmd.name}` }),
|
|
2323
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink_renderer9.Text, { dimColor: true, children: ` ${cmd.description}` })
|
|
2324
|
+
] }, cmd.name);
|
|
2325
|
+
}) })
|
|
1948
2326
|
] });
|
|
1949
2327
|
}
|
|
1950
2328
|
|
|
1951
2329
|
// src/Spinner.tsx
|
|
1952
|
-
var
|
|
1953
|
-
var
|
|
1954
|
-
var
|
|
1955
|
-
var
|
|
2330
|
+
var import_react10 = require("react");
|
|
2331
|
+
var import_ink_renderer10 = require("@claude-code-kit/ink-renderer");
|
|
2332
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
2333
|
+
var DEFAULT_CHARACTERS = process.platform === "darwin" ? ["\xB7", "\u2722", "\u2733", "\u2736", "\u273B", "\u273D"] : ["\xB7", "\u2722", "*", "\u2736", "\u273B", "\u273D"];
|
|
2334
|
+
var FRAMES = [...DEFAULT_CHARACTERS, ...[...DEFAULT_CHARACTERS].reverse()];
|
|
1956
2335
|
var SPINNER_INTERVAL = 80;
|
|
1957
2336
|
var VERB_ROTATE_INTERVAL = 4e3;
|
|
1958
2337
|
var ELAPSED_SHOW_AFTER = 1e3;
|
|
@@ -1961,22 +2340,22 @@ function Spinner({
|
|
|
1961
2340
|
label,
|
|
1962
2341
|
verb,
|
|
1963
2342
|
verbs,
|
|
1964
|
-
color = DEFAULT_COLOR,
|
|
2343
|
+
color: color2 = DEFAULT_COLOR,
|
|
1965
2344
|
showElapsed = true
|
|
1966
2345
|
}) {
|
|
1967
|
-
const [frameIndex, setFrameIndex] = (0,
|
|
1968
|
-
const [verbIndex, setVerbIndex] = (0,
|
|
1969
|
-
const [elapsed, setElapsed] = (0,
|
|
1970
|
-
const startRef = (0,
|
|
2346
|
+
const [frameIndex, setFrameIndex] = (0, import_react10.useState)(0);
|
|
2347
|
+
const [verbIndex, setVerbIndex] = (0, import_react10.useState)(0);
|
|
2348
|
+
const [elapsed, setElapsed] = (0, import_react10.useState)(0);
|
|
2349
|
+
const startRef = (0, import_react10.useRef)(Date.now());
|
|
1971
2350
|
const allVerbs = verbs ?? (verb ? [verb] : ["Thinking"]);
|
|
1972
|
-
(0,
|
|
2351
|
+
(0, import_react10.useEffect)(() => {
|
|
1973
2352
|
const id = setInterval(() => {
|
|
1974
2353
|
setFrameIndex((i) => (i + 1) % FRAMES.length);
|
|
1975
2354
|
setElapsed(Date.now() - startRef.current);
|
|
1976
2355
|
}, SPINNER_INTERVAL);
|
|
1977
2356
|
return () => clearInterval(id);
|
|
1978
2357
|
}, []);
|
|
1979
|
-
(0,
|
|
2358
|
+
(0, import_react10.useEffect)(() => {
|
|
1980
2359
|
if (allVerbs.length <= 1) return;
|
|
1981
2360
|
const id = setInterval(() => {
|
|
1982
2361
|
setVerbIndex((i) => (i + 1) % allVerbs.length);
|
|
@@ -1987,18 +2366,18 @@ function Spinner({
|
|
|
1987
2366
|
const currentVerb = allVerbs[verbIndex % allVerbs.length];
|
|
1988
2367
|
const elapsedSec = Math.floor(elapsed / 1e3);
|
|
1989
2368
|
const showTime = showElapsed && elapsed >= ELAPSED_SHOW_AFTER;
|
|
1990
|
-
return /* @__PURE__ */ (0,
|
|
1991
|
-
/* @__PURE__ */ (0,
|
|
1992
|
-
/* @__PURE__ */ (0,
|
|
2369
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink_renderer10.Box, { children: [
|
|
2370
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink_renderer10.Text, { color: color2, children: frame }),
|
|
2371
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink_renderer10.Text, { children: [
|
|
1993
2372
|
" ",
|
|
1994
2373
|
currentVerb,
|
|
1995
2374
|
"..."
|
|
1996
2375
|
] }),
|
|
1997
|
-
label && /* @__PURE__ */ (0,
|
|
2376
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink_renderer10.Text, { children: [
|
|
1998
2377
|
" ",
|
|
1999
2378
|
label
|
|
2000
2379
|
] }),
|
|
2001
|
-
showTime && /* @__PURE__ */ (0,
|
|
2380
|
+
showTime && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink_renderer10.Text, { dimColor: true, children: [
|
|
2002
2381
|
" (",
|
|
2003
2382
|
elapsedSec,
|
|
2004
2383
|
"s)"
|
|
@@ -2006,50 +2385,902 @@ function Spinner({
|
|
|
2006
2385
|
] });
|
|
2007
2386
|
}
|
|
2008
2387
|
|
|
2009
|
-
// src/
|
|
2010
|
-
var
|
|
2011
|
-
var
|
|
2012
|
-
var
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2388
|
+
// src/Markdown.tsx
|
|
2389
|
+
var import_marked2 = require("marked");
|
|
2390
|
+
var import_react13 = require("react");
|
|
2391
|
+
var import_ink_renderer17 = require("@claude-code-kit/ink-renderer");
|
|
2392
|
+
|
|
2393
|
+
// src/design-system/ThemeProvider.tsx
|
|
2394
|
+
var import_react11 = require("react");
|
|
2395
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
2396
|
+
var themes = {
|
|
2397
|
+
dark: {
|
|
2398
|
+
text: "#E0E0E0",
|
|
2399
|
+
dimText: "#666666",
|
|
2400
|
+
border: "#444444",
|
|
2401
|
+
accent: "#5B9BD5",
|
|
2402
|
+
success: "#6BC76B",
|
|
2403
|
+
warning: "#E5C07B",
|
|
2404
|
+
error: "#E06C75",
|
|
2405
|
+
assistant: "#DA7756",
|
|
2406
|
+
inactive: "#666666",
|
|
2407
|
+
inverseText: "#1E1E1E",
|
|
2408
|
+
permission: "#5B9BD5",
|
|
2409
|
+
diffAdded: "#1a3a1a",
|
|
2410
|
+
diffRemoved: "#3a1a1a",
|
|
2411
|
+
diffAddedWord: "#2d5a2d",
|
|
2412
|
+
diffRemovedWord: "#5a2d2d",
|
|
2413
|
+
diffHeader: "#1e2d3d",
|
|
2414
|
+
userMessage: "#2B4A6F",
|
|
2415
|
+
assistantMessage: "#3D2614",
|
|
2416
|
+
systemMessage: "#2D2D2D",
|
|
2417
|
+
toolUseMessage: "#1E3A2D",
|
|
2418
|
+
permissionAllow: "#1B4332",
|
|
2419
|
+
permissionDeny: "#3B1014",
|
|
2420
|
+
permissionAlways: "#1B2F4D",
|
|
2421
|
+
focus: "#5B9BD5",
|
|
2422
|
+
selection: "#264F78",
|
|
2423
|
+
placeholder: "#555555",
|
|
2424
|
+
link: "#79B8FF",
|
|
2425
|
+
code: "#F8BFB0",
|
|
2426
|
+
codeBackground: "#2D2D2D",
|
|
2427
|
+
blockquote: "#444444",
|
|
2428
|
+
info: "#5B9BD5",
|
|
2429
|
+
spinnerColor: "#DA7756",
|
|
2430
|
+
shimmer: "#3A3A3A"
|
|
2431
|
+
},
|
|
2432
|
+
light: {
|
|
2433
|
+
text: "#1E1E1E",
|
|
2434
|
+
dimText: "#999999",
|
|
2435
|
+
border: "#CCCCCC",
|
|
2436
|
+
accent: "#0066CC",
|
|
2437
|
+
success: "#2E7D32",
|
|
2438
|
+
warning: "#F57C00",
|
|
2439
|
+
error: "#C62828",
|
|
2440
|
+
assistant: "#DA7756",
|
|
2441
|
+
inactive: "#999999",
|
|
2442
|
+
inverseText: "#FFFFFF",
|
|
2443
|
+
permission: "#0066CC",
|
|
2444
|
+
diffAdded: "#E6FFEC",
|
|
2445
|
+
diffRemoved: "#FFEBE9",
|
|
2446
|
+
diffAddedWord: "#CCFFD8",
|
|
2447
|
+
diffRemovedWord: "#FFD7D5",
|
|
2448
|
+
diffHeader: "#DDF4FF",
|
|
2449
|
+
userMessage: "#E8F0FE",
|
|
2450
|
+
assistantMessage: "#FDF2EE",
|
|
2451
|
+
systemMessage: "#F5F5F5",
|
|
2452
|
+
toolUseMessage: "#EAF5EE",
|
|
2453
|
+
permissionAllow: "#E6F4EA",
|
|
2454
|
+
permissionDeny: "#FCE8E6",
|
|
2455
|
+
permissionAlways: "#E8F0FE",
|
|
2456
|
+
focus: "#0066CC",
|
|
2457
|
+
selection: "#B3D4FF",
|
|
2458
|
+
placeholder: "#AAAAAA",
|
|
2459
|
+
link: "#0066CC",
|
|
2460
|
+
code: "#C7522A",
|
|
2461
|
+
codeBackground: "#F5F5F5",
|
|
2462
|
+
blockquote: "#EEEEEE",
|
|
2463
|
+
info: "#0066CC",
|
|
2464
|
+
spinnerColor: "#DA7756",
|
|
2465
|
+
shimmer: "#E8E8E8"
|
|
2466
|
+
},
|
|
2467
|
+
"light-high-contrast": {
|
|
2468
|
+
text: "#000000",
|
|
2469
|
+
dimText: "#595959",
|
|
2470
|
+
border: "#767676",
|
|
2471
|
+
accent: "#0000EE",
|
|
2472
|
+
success: "#006400",
|
|
2473
|
+
warning: "#7A4000",
|
|
2474
|
+
error: "#AE1818",
|
|
2475
|
+
assistant: "#B55530",
|
|
2476
|
+
inactive: "#767676",
|
|
2477
|
+
inverseText: "#FFFFFF",
|
|
2478
|
+
permission: "#0000EE",
|
|
2479
|
+
diffAdded: "#CCF0D0",
|
|
2480
|
+
diffRemoved: "#F5C6C6",
|
|
2481
|
+
diffAddedWord: "#99E0A0",
|
|
2482
|
+
diffRemovedWord: "#EBA0A0",
|
|
2483
|
+
diffHeader: "#B8DEFF",
|
|
2484
|
+
userMessage: "#C8DCFF",
|
|
2485
|
+
assistantMessage: "#FCDAC8",
|
|
2486
|
+
systemMessage: "#E0E0E0",
|
|
2487
|
+
toolUseMessage: "#C4EED0",
|
|
2488
|
+
permissionAllow: "#C4EED0",
|
|
2489
|
+
permissionDeny: "#F5C6C6",
|
|
2490
|
+
permissionAlways: "#C8DCFF",
|
|
2491
|
+
focus: "#0000EE",
|
|
2492
|
+
selection: "#80BFFF",
|
|
2493
|
+
placeholder: "#767676",
|
|
2494
|
+
link: "#0000EE",
|
|
2495
|
+
code: "#8B0000",
|
|
2496
|
+
codeBackground: "#E8E8E8",
|
|
2497
|
+
blockquote: "#D0D0D0",
|
|
2498
|
+
info: "#0000EE",
|
|
2499
|
+
spinnerColor: "#B55530",
|
|
2500
|
+
shimmer: "#D0D0D0"
|
|
2501
|
+
},
|
|
2502
|
+
"dark-dimmed": {
|
|
2503
|
+
text: "#ADBAC7",
|
|
2504
|
+
dimText: "#545D68",
|
|
2505
|
+
border: "#373E47",
|
|
2506
|
+
accent: "#539BF5",
|
|
2507
|
+
success: "#57AB5A",
|
|
2508
|
+
warning: "#C69026",
|
|
2509
|
+
error: "#E5534B",
|
|
2510
|
+
assistant: "#DA7756",
|
|
2511
|
+
inactive: "#545D68",
|
|
2512
|
+
inverseText: "#22272E",
|
|
2513
|
+
permission: "#539BF5",
|
|
2514
|
+
diffAdded: "#1B2F23",
|
|
2515
|
+
diffRemoved: "#2F1B1E",
|
|
2516
|
+
diffAddedWord: "#264D30",
|
|
2517
|
+
diffRemovedWord: "#4D2628",
|
|
2518
|
+
diffHeader: "#1C2B3A",
|
|
2519
|
+
userMessage: "#1C2B3A",
|
|
2520
|
+
assistantMessage: "#2F211A",
|
|
2521
|
+
systemMessage: "#2D333B",
|
|
2522
|
+
toolUseMessage: "#1B2B23",
|
|
2523
|
+
permissionAllow: "#1B2B23",
|
|
2524
|
+
permissionDeny: "#2F1B1E",
|
|
2525
|
+
permissionAlways: "#1C2B3A",
|
|
2526
|
+
focus: "#539BF5",
|
|
2527
|
+
selection: "#1C4066",
|
|
2528
|
+
placeholder: "#545D68",
|
|
2529
|
+
link: "#6CB6FF",
|
|
2530
|
+
code: "#F0A070",
|
|
2531
|
+
codeBackground: "#2D333B",
|
|
2532
|
+
blockquote: "#373E47",
|
|
2533
|
+
info: "#539BF5",
|
|
2534
|
+
spinnerColor: "#DA7756",
|
|
2535
|
+
shimmer: "#373E47"
|
|
2536
|
+
}
|
|
2537
|
+
};
|
|
2538
|
+
function getTheme(name) {
|
|
2539
|
+
return themes[name] ?? themes.dark;
|
|
2540
|
+
}
|
|
2541
|
+
var DEFAULT_THEME = "dark";
|
|
2542
|
+
var ThemeContext = (0, import_react11.createContext)({
|
|
2543
|
+
themeSetting: DEFAULT_THEME,
|
|
2544
|
+
setThemeSetting: () => {
|
|
2545
|
+
},
|
|
2546
|
+
setPreviewTheme: () => {
|
|
2547
|
+
},
|
|
2548
|
+
savePreview: () => {
|
|
2549
|
+
},
|
|
2550
|
+
cancelPreview: () => {
|
|
2551
|
+
},
|
|
2552
|
+
currentTheme: DEFAULT_THEME
|
|
2553
|
+
});
|
|
2554
|
+
function ThemeProvider({
|
|
2555
|
+
children,
|
|
2556
|
+
initialState = "dark",
|
|
2557
|
+
onThemeSave
|
|
2558
|
+
}) {
|
|
2559
|
+
const [themeSetting, setThemeSetting] = (0, import_react11.useState)(initialState);
|
|
2560
|
+
const [previewTheme, setPreviewTheme] = (0, import_react11.useState)(null);
|
|
2561
|
+
const activeSetting = previewTheme ?? themeSetting;
|
|
2562
|
+
const currentTheme = activeSetting === "auto" ? "dark" : activeSetting;
|
|
2563
|
+
const value = (0, import_react11.useMemo)(
|
|
2564
|
+
() => ({
|
|
2565
|
+
themeSetting,
|
|
2566
|
+
setThemeSetting: (newSetting) => {
|
|
2567
|
+
setThemeSetting(newSetting);
|
|
2568
|
+
setPreviewTheme(null);
|
|
2569
|
+
onThemeSave?.(newSetting);
|
|
2570
|
+
},
|
|
2571
|
+
setPreviewTheme: (newSetting) => {
|
|
2572
|
+
setPreviewTheme(newSetting);
|
|
2573
|
+
},
|
|
2574
|
+
savePreview: () => {
|
|
2575
|
+
if (previewTheme !== null) {
|
|
2576
|
+
setThemeSetting(previewTheme);
|
|
2577
|
+
setPreviewTheme(null);
|
|
2578
|
+
onThemeSave?.(previewTheme);
|
|
2038
2579
|
}
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2580
|
+
},
|
|
2581
|
+
cancelPreview: () => {
|
|
2582
|
+
if (previewTheme !== null) {
|
|
2583
|
+
setPreviewTheme(null);
|
|
2584
|
+
}
|
|
2585
|
+
},
|
|
2586
|
+
currentTheme
|
|
2587
|
+
}),
|
|
2588
|
+
[themeSetting, previewTheme, currentTheme, onThemeSave]
|
|
2043
2589
|
);
|
|
2044
|
-
(0,
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2590
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ThemeContext.Provider, { value, children });
|
|
2591
|
+
}
|
|
2592
|
+
function useTheme() {
|
|
2593
|
+
const { currentTheme, setThemeSetting } = (0, import_react11.useContext)(ThemeContext);
|
|
2594
|
+
return [currentTheme, setThemeSetting];
|
|
2595
|
+
}
|
|
2596
|
+
function useThemeSetting() {
|
|
2597
|
+
return (0, import_react11.useContext)(ThemeContext).themeSetting;
|
|
2598
|
+
}
|
|
2599
|
+
function usePreviewTheme() {
|
|
2600
|
+
const { setPreviewTheme, savePreview, cancelPreview } = (0, import_react11.useContext)(ThemeContext);
|
|
2601
|
+
return { setPreviewTheme, savePreview, cancelPreview };
|
|
2602
|
+
}
|
|
2603
|
+
|
|
2604
|
+
// src/utils/optional/cliHighlight.ts
|
|
2605
|
+
var cliHighlightPromise;
|
|
2606
|
+
async function loadCliHighlight() {
|
|
2607
|
+
try {
|
|
2608
|
+
const mod = await import("cli-highlight");
|
|
2609
|
+
const cliHighlight = mod;
|
|
2610
|
+
return {
|
|
2611
|
+
highlight: cliHighlight.highlight,
|
|
2612
|
+
supportsLanguage: cliHighlight.supportsLanguage
|
|
2613
|
+
};
|
|
2614
|
+
} catch {
|
|
2615
|
+
return null;
|
|
2616
|
+
}
|
|
2617
|
+
}
|
|
2618
|
+
function getCliHighlightPromise() {
|
|
2619
|
+
cliHighlightPromise ?? (cliHighlightPromise = loadCliHighlight());
|
|
2620
|
+
return cliHighlightPromise;
|
|
2621
|
+
}
|
|
2622
|
+
|
|
2623
|
+
// src/utils/hash.ts
|
|
2624
|
+
function hashContent(content) {
|
|
2625
|
+
let h = 2166136261 | 0;
|
|
2626
|
+
for (let i = 0; i < content.length; i++) {
|
|
2627
|
+
h ^= content.charCodeAt(i);
|
|
2628
|
+
h = Math.imul(h, 16777619);
|
|
2629
|
+
}
|
|
2630
|
+
let h2 = 26499749718 | 0;
|
|
2631
|
+
for (let i = 0; i < content.length; i++) {
|
|
2632
|
+
h2 ^= content.charCodeAt(i);
|
|
2633
|
+
h2 = Math.imul(h2, 16777619);
|
|
2634
|
+
}
|
|
2635
|
+
return ((h >>> 0) * 1048576 + (h2 >>> 0)).toString(36) + content.length.toString(36);
|
|
2636
|
+
}
|
|
2637
|
+
|
|
2638
|
+
// src/utils/markdown.ts
|
|
2639
|
+
var import_chalk = __toESM(require("chalk"));
|
|
2640
|
+
var import_marked = require("marked");
|
|
2641
|
+
var import_strip_ansi = __toESM(require("strip-ansi"));
|
|
2642
|
+
var import_ink_renderer12 = require("@claude-code-kit/ink-renderer");
|
|
2643
|
+
|
|
2644
|
+
// src/design-system/color.ts
|
|
2645
|
+
var import_ink_renderer11 = require("@claude-code-kit/ink-renderer");
|
|
2646
|
+
function color(c, theme, type = "foreground") {
|
|
2647
|
+
return (text) => {
|
|
2648
|
+
if (!c) {
|
|
2649
|
+
return text;
|
|
2650
|
+
}
|
|
2651
|
+
if (c.startsWith("rgb(") || c.startsWith("#") || c.startsWith("ansi256(") || c.startsWith("ansi:")) {
|
|
2652
|
+
return (0, import_ink_renderer11.colorize)(text, c, type);
|
|
2653
|
+
}
|
|
2654
|
+
return (0, import_ink_renderer11.colorize)(text, getTheme(theme)[c], type);
|
|
2655
|
+
};
|
|
2656
|
+
}
|
|
2657
|
+
|
|
2658
|
+
// src/utils/markdown.ts
|
|
2659
|
+
function logForDebugging3(...args) {
|
|
2660
|
+
if (process.env["DEBUG"]) {
|
|
2661
|
+
console.debug(...args);
|
|
2662
|
+
}
|
|
2663
|
+
}
|
|
2664
|
+
var EOL = "\n";
|
|
2665
|
+
var BLOCKQUOTE_BAR = "\u258E";
|
|
2666
|
+
var OSC8_START = "\x1B]8;;";
|
|
2667
|
+
var OSC8_END = "\x07";
|
|
2668
|
+
function supportsHyperlinks() {
|
|
2669
|
+
const termProgram = process.env["TERM_PROGRAM"];
|
|
2670
|
+
const lcTerminal = process.env["LC_TERMINAL"];
|
|
2671
|
+
const term = process.env["TERM"];
|
|
2672
|
+
const supported = ["ghostty", "Hyper", "kitty", "alacritty", "iTerm.app", "iTerm2"];
|
|
2673
|
+
return !!(termProgram && supported.includes(termProgram)) || !!(lcTerminal && supported.includes(lcTerminal)) || !!term?.includes("kitty");
|
|
2674
|
+
}
|
|
2675
|
+
function createHyperlink(url, content) {
|
|
2676
|
+
if (!supportsHyperlinks()) {
|
|
2677
|
+
return url;
|
|
2678
|
+
}
|
|
2679
|
+
const displayText = content ?? url;
|
|
2680
|
+
const coloredText = import_chalk.default.blue(displayText);
|
|
2681
|
+
return `${OSC8_START}${url}${OSC8_END}${coloredText}${OSC8_START}${OSC8_END}`;
|
|
2682
|
+
}
|
|
2683
|
+
var markedConfigured = false;
|
|
2684
|
+
function configureMarked() {
|
|
2685
|
+
if (markedConfigured) return;
|
|
2686
|
+
markedConfigured = true;
|
|
2687
|
+
import_marked.marked.use({
|
|
2688
|
+
tokenizer: {
|
|
2689
|
+
del() {
|
|
2690
|
+
return void 0;
|
|
2691
|
+
}
|
|
2692
|
+
}
|
|
2693
|
+
});
|
|
2694
|
+
}
|
|
2695
|
+
function formatToken(token, theme, listDepth = 0, orderedListNumber = null, parent = null, highlight = null) {
|
|
2696
|
+
switch (token.type) {
|
|
2697
|
+
case "blockquote": {
|
|
2698
|
+
const inner = (token.tokens ?? []).map((_) => formatToken(_, theme, 0, null, null, highlight)).join("");
|
|
2699
|
+
const bar = import_chalk.default.dim(BLOCKQUOTE_BAR);
|
|
2700
|
+
return inner.split(EOL).map(
|
|
2701
|
+
(line) => (0, import_strip_ansi.default)(line).trim() ? `${bar} ${import_chalk.default.italic(line)}` : line
|
|
2702
|
+
).join(EOL);
|
|
2703
|
+
}
|
|
2704
|
+
case "code": {
|
|
2705
|
+
if (!highlight) {
|
|
2706
|
+
return token.text + EOL;
|
|
2707
|
+
}
|
|
2708
|
+
let language = "plaintext";
|
|
2709
|
+
if (token.lang) {
|
|
2710
|
+
if (highlight.supportsLanguage(token.lang)) {
|
|
2711
|
+
language = token.lang;
|
|
2712
|
+
} else {
|
|
2713
|
+
logForDebugging3(
|
|
2714
|
+
`Language not supported while highlighting code, falling back to plaintext: ${token.lang}`
|
|
2715
|
+
);
|
|
2716
|
+
}
|
|
2717
|
+
}
|
|
2718
|
+
return highlight.highlight(token.text, { language }) + EOL;
|
|
2719
|
+
}
|
|
2720
|
+
case "codespan": {
|
|
2721
|
+
return color("permission", theme)(token.text);
|
|
2722
|
+
}
|
|
2723
|
+
case "em":
|
|
2724
|
+
return import_chalk.default.italic(
|
|
2725
|
+
(token.tokens ?? []).map((_) => formatToken(_, theme, 0, null, parent, highlight)).join("")
|
|
2726
|
+
);
|
|
2727
|
+
case "strong":
|
|
2728
|
+
return import_chalk.default.bold(
|
|
2729
|
+
(token.tokens ?? []).map((_) => formatToken(_, theme, 0, null, parent, highlight)).join("")
|
|
2730
|
+
);
|
|
2731
|
+
case "heading":
|
|
2732
|
+
switch (token.depth) {
|
|
2733
|
+
case 1:
|
|
2734
|
+
return import_chalk.default.bold.italic.underline(
|
|
2735
|
+
(token.tokens ?? []).map((_) => formatToken(_, theme, 0, null, null, highlight)).join("")
|
|
2736
|
+
) + EOL + EOL;
|
|
2737
|
+
case 2:
|
|
2738
|
+
return import_chalk.default.bold(
|
|
2739
|
+
(token.tokens ?? []).map((_) => formatToken(_, theme, 0, null, null, highlight)).join("")
|
|
2740
|
+
) + EOL + EOL;
|
|
2741
|
+
default:
|
|
2742
|
+
return import_chalk.default.bold(
|
|
2743
|
+
(token.tokens ?? []).map((_) => formatToken(_, theme, 0, null, null, highlight)).join("")
|
|
2744
|
+
) + EOL + EOL;
|
|
2745
|
+
}
|
|
2746
|
+
case "hr":
|
|
2747
|
+
return "---";
|
|
2748
|
+
case "image":
|
|
2749
|
+
return token.href;
|
|
2750
|
+
case "link": {
|
|
2751
|
+
if (token.href.startsWith("mailto:")) {
|
|
2752
|
+
const email = token.href.replace(/^mailto:/, "");
|
|
2753
|
+
return email;
|
|
2754
|
+
}
|
|
2755
|
+
const linkText = (token.tokens ?? []).map((_) => formatToken(_, theme, 0, null, token, highlight)).join("");
|
|
2756
|
+
const plainLinkText = (0, import_strip_ansi.default)(linkText);
|
|
2757
|
+
if (plainLinkText && plainLinkText !== token.href) {
|
|
2758
|
+
return createHyperlink(token.href, linkText);
|
|
2759
|
+
}
|
|
2760
|
+
return createHyperlink(token.href);
|
|
2761
|
+
}
|
|
2762
|
+
case "list": {
|
|
2763
|
+
return token.items.map(
|
|
2764
|
+
(_, index) => formatToken(
|
|
2765
|
+
_,
|
|
2766
|
+
theme,
|
|
2767
|
+
listDepth,
|
|
2768
|
+
token.ordered ? token.start + index : null,
|
|
2769
|
+
token,
|
|
2770
|
+
highlight
|
|
2771
|
+
)
|
|
2772
|
+
).join("");
|
|
2773
|
+
}
|
|
2774
|
+
case "list_item":
|
|
2775
|
+
return (token.tokens ?? []).map(
|
|
2776
|
+
(_) => `${" ".repeat(listDepth)}${formatToken(_, theme, listDepth + 1, orderedListNumber, token, highlight)}`
|
|
2777
|
+
).join("");
|
|
2778
|
+
case "paragraph":
|
|
2779
|
+
return (token.tokens ?? []).map((_) => formatToken(_, theme, 0, null, null, highlight)).join("") + EOL;
|
|
2780
|
+
case "space":
|
|
2781
|
+
return EOL;
|
|
2782
|
+
case "br":
|
|
2783
|
+
return EOL;
|
|
2784
|
+
case "text":
|
|
2785
|
+
if (parent?.type === "link") {
|
|
2786
|
+
return token.text;
|
|
2787
|
+
}
|
|
2788
|
+
if (parent?.type === "list_item") {
|
|
2789
|
+
return `${orderedListNumber === null ? "-" : getListNumber(listDepth, orderedListNumber) + "."} ${token.tokens ? token.tokens.map((_) => formatToken(_, theme, listDepth, orderedListNumber, token, highlight)).join("") : linkifyIssueReferences(token.text)}${EOL}`;
|
|
2790
|
+
}
|
|
2791
|
+
return linkifyIssueReferences(token.text);
|
|
2792
|
+
case "table": {
|
|
2793
|
+
let getDisplayText2 = function(tokens) {
|
|
2794
|
+
return (0, import_strip_ansi.default)(
|
|
2795
|
+
tokens?.map((_) => formatToken(_, theme, 0, null, null, highlight)).join("") ?? ""
|
|
2796
|
+
);
|
|
2797
|
+
};
|
|
2798
|
+
var getDisplayText = getDisplayText2;
|
|
2799
|
+
const tableToken = token;
|
|
2800
|
+
const columnWidths = tableToken.header.map((header, index) => {
|
|
2801
|
+
let maxWidth = (0, import_ink_renderer12.stringWidth)(getDisplayText2(header.tokens));
|
|
2802
|
+
for (const row of tableToken.rows) {
|
|
2803
|
+
const cellLength = (0, import_ink_renderer12.stringWidth)(getDisplayText2(row[index]?.tokens));
|
|
2804
|
+
maxWidth = Math.max(maxWidth, cellLength);
|
|
2805
|
+
}
|
|
2806
|
+
return Math.max(maxWidth, 3);
|
|
2807
|
+
});
|
|
2808
|
+
let tableOutput = "| ";
|
|
2809
|
+
tableToken.header.forEach((header, index) => {
|
|
2810
|
+
const content = header.tokens?.map((_) => formatToken(_, theme, 0, null, null, highlight)).join("") ?? "";
|
|
2811
|
+
const displayText = getDisplayText2(header.tokens);
|
|
2812
|
+
const width = columnWidths[index];
|
|
2813
|
+
const align = tableToken.align?.[index];
|
|
2814
|
+
tableOutput += padAligned(content, (0, import_ink_renderer12.stringWidth)(displayText), width, align) + " | ";
|
|
2815
|
+
});
|
|
2816
|
+
tableOutput = tableOutput.trimEnd() + EOL;
|
|
2817
|
+
tableOutput += "|";
|
|
2818
|
+
columnWidths.forEach((width) => {
|
|
2819
|
+
const separator = "-".repeat(width + 2);
|
|
2820
|
+
tableOutput += separator + "|";
|
|
2821
|
+
});
|
|
2822
|
+
tableOutput += EOL;
|
|
2823
|
+
tableToken.rows.forEach((row) => {
|
|
2824
|
+
tableOutput += "| ";
|
|
2825
|
+
row.forEach((cell, index) => {
|
|
2826
|
+
const content = cell.tokens?.map((_) => formatToken(_, theme, 0, null, null, highlight)).join("") ?? "";
|
|
2827
|
+
const displayText = getDisplayText2(cell.tokens);
|
|
2828
|
+
const width = columnWidths[index];
|
|
2829
|
+
const align = tableToken.align?.[index];
|
|
2830
|
+
tableOutput += padAligned(content, (0, import_ink_renderer12.stringWidth)(displayText), width, align) + " | ";
|
|
2831
|
+
});
|
|
2832
|
+
tableOutput = tableOutput.trimEnd() + EOL;
|
|
2833
|
+
});
|
|
2834
|
+
return tableOutput + EOL;
|
|
2835
|
+
}
|
|
2836
|
+
case "escape":
|
|
2837
|
+
return token.text;
|
|
2838
|
+
case "def":
|
|
2839
|
+
case "del":
|
|
2840
|
+
case "html":
|
|
2841
|
+
return "";
|
|
2842
|
+
}
|
|
2843
|
+
return "";
|
|
2844
|
+
}
|
|
2845
|
+
var ISSUE_REF_PATTERN = /(^|[^\w./-])([A-Za-z0-9][\w-]*\/[A-Za-z0-9][\w.-]*)#(\d+)\b/g;
|
|
2846
|
+
function linkifyIssueReferences(text) {
|
|
2847
|
+
if (!supportsHyperlinks()) {
|
|
2848
|
+
return text;
|
|
2849
|
+
}
|
|
2850
|
+
return text.replace(
|
|
2851
|
+
ISSUE_REF_PATTERN,
|
|
2852
|
+
(_match, prefix, repo, num) => prefix + createHyperlink(
|
|
2853
|
+
`https://github.com/${repo}/issues/${num}`,
|
|
2854
|
+
`${repo}#${num}`
|
|
2855
|
+
)
|
|
2856
|
+
);
|
|
2857
|
+
}
|
|
2858
|
+
function numberToLetter(n) {
|
|
2859
|
+
let result = "";
|
|
2860
|
+
while (n > 0) {
|
|
2861
|
+
n--;
|
|
2862
|
+
result = String.fromCharCode(97 + n % 26) + result;
|
|
2863
|
+
n = Math.floor(n / 26);
|
|
2864
|
+
}
|
|
2865
|
+
return result;
|
|
2866
|
+
}
|
|
2867
|
+
var ROMAN_VALUES = [
|
|
2868
|
+
[1e3, "m"],
|
|
2869
|
+
[900, "cm"],
|
|
2870
|
+
[500, "d"],
|
|
2871
|
+
[400, "cd"],
|
|
2872
|
+
[100, "c"],
|
|
2873
|
+
[90, "xc"],
|
|
2874
|
+
[50, "l"],
|
|
2875
|
+
[40, "xl"],
|
|
2876
|
+
[10, "x"],
|
|
2877
|
+
[9, "ix"],
|
|
2878
|
+
[5, "v"],
|
|
2879
|
+
[4, "iv"],
|
|
2880
|
+
[1, "i"]
|
|
2881
|
+
];
|
|
2882
|
+
function numberToRoman(n) {
|
|
2883
|
+
let result = "";
|
|
2884
|
+
for (const [value, numeral] of ROMAN_VALUES) {
|
|
2885
|
+
while (n >= value) {
|
|
2886
|
+
result += numeral;
|
|
2887
|
+
n -= value;
|
|
2888
|
+
}
|
|
2889
|
+
}
|
|
2890
|
+
return result;
|
|
2891
|
+
}
|
|
2892
|
+
function getListNumber(listDepth, orderedListNumber) {
|
|
2893
|
+
switch (listDepth) {
|
|
2894
|
+
case 0:
|
|
2895
|
+
case 1:
|
|
2896
|
+
return orderedListNumber.toString();
|
|
2897
|
+
case 2:
|
|
2898
|
+
return numberToLetter(orderedListNumber);
|
|
2899
|
+
case 3:
|
|
2900
|
+
return numberToRoman(orderedListNumber);
|
|
2901
|
+
default:
|
|
2902
|
+
return orderedListNumber.toString();
|
|
2903
|
+
}
|
|
2904
|
+
}
|
|
2905
|
+
function padAligned(content, displayWidth, targetWidth, align) {
|
|
2906
|
+
const padding = Math.max(0, targetWidth - displayWidth);
|
|
2907
|
+
if (align === "center") {
|
|
2908
|
+
const leftPad = Math.floor(padding / 2);
|
|
2909
|
+
return " ".repeat(leftPad) + content + " ".repeat(padding - leftPad);
|
|
2910
|
+
}
|
|
2911
|
+
if (align === "right") {
|
|
2912
|
+
return " ".repeat(padding) + content;
|
|
2913
|
+
}
|
|
2914
|
+
return content + " ".repeat(padding);
|
|
2915
|
+
}
|
|
2916
|
+
|
|
2917
|
+
// src/MarkdownTable.tsx
|
|
2918
|
+
var import_react12 = require("react");
|
|
2919
|
+
var import_strip_ansi2 = __toESM(require("strip-ansi"));
|
|
2920
|
+
var import_ink_renderer13 = require("@claude-code-kit/ink-renderer");
|
|
2921
|
+
var import_ink_renderer14 = require("@claude-code-kit/ink-renderer");
|
|
2922
|
+
var import_ink_renderer15 = require("@claude-code-kit/ink-renderer");
|
|
2923
|
+
var import_ink_renderer16 = require("@claude-code-kit/ink-renderer");
|
|
2924
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
2925
|
+
var SAFETY_MARGIN = 4;
|
|
2926
|
+
var MIN_COLUMN_WIDTH = 3;
|
|
2927
|
+
var MAX_ROW_LINES = 4;
|
|
2928
|
+
var ANSI_BOLD_START = "\x1B[1m";
|
|
2929
|
+
var ANSI_BOLD_END = "\x1B[22m";
|
|
2930
|
+
function wrapText(text, width, options) {
|
|
2931
|
+
if (width <= 0) return [text];
|
|
2932
|
+
const trimmedText = text.trimEnd();
|
|
2933
|
+
const wrapped = (0, import_ink_renderer15.wrapAnsi)(trimmedText, width, {
|
|
2934
|
+
hard: options?.hard ?? false,
|
|
2935
|
+
trim: false,
|
|
2936
|
+
wordWrap: true
|
|
2937
|
+
});
|
|
2938
|
+
const lines = wrapped.split("\n").filter((line) => line.length > 0);
|
|
2939
|
+
return lines.length > 0 ? lines : [""];
|
|
2940
|
+
}
|
|
2941
|
+
function MarkdownTable({
|
|
2942
|
+
token,
|
|
2943
|
+
highlight,
|
|
2944
|
+
forceWidth
|
|
2945
|
+
}) {
|
|
2946
|
+
const [theme] = useTheme();
|
|
2947
|
+
const terminalSize = (0, import_react12.useContext)(import_ink_renderer13.TerminalSizeContext);
|
|
2948
|
+
const actualTerminalWidth = terminalSize?.columns ?? 80;
|
|
2949
|
+
const terminalWidth = forceWidth ?? actualTerminalWidth;
|
|
2950
|
+
function formatCell(tokens) {
|
|
2951
|
+
return tokens?.map((_) => formatToken(_, theme, 0, null, null, highlight)).join("") ?? "";
|
|
2952
|
+
}
|
|
2953
|
+
function getPlainText(tokens_0) {
|
|
2954
|
+
return (0, import_strip_ansi2.default)(formatCell(tokens_0));
|
|
2955
|
+
}
|
|
2956
|
+
function getMinWidth(tokens_1) {
|
|
2957
|
+
const text = getPlainText(tokens_1);
|
|
2958
|
+
const words = text.split(/\s+/).filter((w) => w.length > 0);
|
|
2959
|
+
if (words.length === 0) return MIN_COLUMN_WIDTH;
|
|
2960
|
+
return Math.max(...words.map((w_0) => (0, import_ink_renderer14.stringWidth)(w_0)), MIN_COLUMN_WIDTH);
|
|
2961
|
+
}
|
|
2962
|
+
function getIdealWidth(tokens_2) {
|
|
2963
|
+
return Math.max((0, import_ink_renderer14.stringWidth)(getPlainText(tokens_2)), MIN_COLUMN_WIDTH);
|
|
2964
|
+
}
|
|
2965
|
+
const minWidths = token.header.map((header, colIndex) => {
|
|
2966
|
+
let maxMinWidth = getMinWidth(header.tokens);
|
|
2967
|
+
for (const row of token.rows) {
|
|
2968
|
+
maxMinWidth = Math.max(maxMinWidth, getMinWidth(row[colIndex]?.tokens));
|
|
2969
|
+
}
|
|
2970
|
+
return maxMinWidth;
|
|
2971
|
+
});
|
|
2972
|
+
const idealWidths = token.header.map((header_0, colIndex_0) => {
|
|
2973
|
+
let maxIdeal = getIdealWidth(header_0.tokens);
|
|
2974
|
+
for (const row_0 of token.rows) {
|
|
2975
|
+
maxIdeal = Math.max(maxIdeal, getIdealWidth(row_0[colIndex_0]?.tokens));
|
|
2976
|
+
}
|
|
2977
|
+
return maxIdeal;
|
|
2978
|
+
});
|
|
2979
|
+
const numCols = token.header.length;
|
|
2980
|
+
const borderOverhead = 1 + numCols * 3;
|
|
2981
|
+
const availableWidth = Math.max(terminalWidth - borderOverhead - SAFETY_MARGIN, numCols * MIN_COLUMN_WIDTH);
|
|
2982
|
+
const totalMin = minWidths.reduce((sum, w_1) => sum + w_1, 0);
|
|
2983
|
+
const totalIdeal = idealWidths.reduce((sum_0, w_2) => sum_0 + w_2, 0);
|
|
2984
|
+
let needsHardWrap = false;
|
|
2985
|
+
let columnWidths;
|
|
2986
|
+
if (totalIdeal <= availableWidth) {
|
|
2987
|
+
columnWidths = idealWidths;
|
|
2988
|
+
} else if (totalMin <= availableWidth) {
|
|
2989
|
+
const extraSpace = availableWidth - totalMin;
|
|
2990
|
+
const overflows = idealWidths.map((ideal, i) => ideal - minWidths[i]);
|
|
2991
|
+
const totalOverflow = overflows.reduce((sum_1, o) => sum_1 + o, 0);
|
|
2992
|
+
columnWidths = minWidths.map((min, i_0) => {
|
|
2993
|
+
if (totalOverflow === 0) return min;
|
|
2994
|
+
const extra = Math.floor(overflows[i_0] / totalOverflow * extraSpace);
|
|
2995
|
+
return min + extra;
|
|
2996
|
+
});
|
|
2997
|
+
} else {
|
|
2998
|
+
needsHardWrap = true;
|
|
2999
|
+
const scaleFactor = availableWidth / totalMin;
|
|
3000
|
+
columnWidths = minWidths.map((w_3) => Math.max(Math.floor(w_3 * scaleFactor), MIN_COLUMN_WIDTH));
|
|
3001
|
+
}
|
|
3002
|
+
function calculateMaxRowLines() {
|
|
3003
|
+
let maxLines = 1;
|
|
3004
|
+
for (let i_1 = 0; i_1 < token.header.length; i_1++) {
|
|
3005
|
+
const content = formatCell(token.header[i_1].tokens);
|
|
3006
|
+
const wrapped = wrapText(content, columnWidths[i_1], {
|
|
3007
|
+
hard: needsHardWrap
|
|
3008
|
+
});
|
|
3009
|
+
maxLines = Math.max(maxLines, wrapped.length);
|
|
3010
|
+
}
|
|
3011
|
+
for (const row_1 of token.rows) {
|
|
3012
|
+
for (let i_2 = 0; i_2 < row_1.length; i_2++) {
|
|
3013
|
+
const content_0 = formatCell(row_1[i_2]?.tokens);
|
|
3014
|
+
const wrapped_0 = wrapText(content_0, columnWidths[i_2], {
|
|
3015
|
+
hard: needsHardWrap
|
|
3016
|
+
});
|
|
3017
|
+
maxLines = Math.max(maxLines, wrapped_0.length);
|
|
3018
|
+
}
|
|
3019
|
+
}
|
|
3020
|
+
return maxLines;
|
|
3021
|
+
}
|
|
3022
|
+
const maxRowLines = calculateMaxRowLines();
|
|
3023
|
+
const useVerticalFormat = maxRowLines > MAX_ROW_LINES;
|
|
3024
|
+
function renderRowLines(cells, isHeader) {
|
|
3025
|
+
const cellLines = cells.map((cell, colIndex_1) => {
|
|
3026
|
+
const formattedText = formatCell(cell.tokens);
|
|
3027
|
+
const width = columnWidths[colIndex_1];
|
|
3028
|
+
return wrapText(formattedText, width, {
|
|
3029
|
+
hard: needsHardWrap
|
|
3030
|
+
});
|
|
3031
|
+
});
|
|
3032
|
+
const maxLines_0 = Math.max(...cellLines.map((lines) => lines.length), 1);
|
|
3033
|
+
const verticalOffsets = cellLines.map((lines_0) => Math.floor((maxLines_0 - lines_0.length) / 2));
|
|
3034
|
+
const result = [];
|
|
3035
|
+
for (let lineIdx = 0; lineIdx < maxLines_0; lineIdx++) {
|
|
3036
|
+
let line = "\u2502";
|
|
3037
|
+
for (let colIndex_2 = 0; colIndex_2 < cells.length; colIndex_2++) {
|
|
3038
|
+
const lines_1 = cellLines[colIndex_2];
|
|
3039
|
+
const offset = verticalOffsets[colIndex_2];
|
|
3040
|
+
const contentLineIdx = lineIdx - offset;
|
|
3041
|
+
const lineText = contentLineIdx >= 0 && contentLineIdx < lines_1.length ? lines_1[contentLineIdx] : "";
|
|
3042
|
+
const width_0 = columnWidths[colIndex_2];
|
|
3043
|
+
const align = isHeader ? "center" : token.align?.[colIndex_2] ?? "left";
|
|
3044
|
+
line += " " + padAligned(lineText, (0, import_ink_renderer14.stringWidth)(lineText), width_0, align) + " \u2502";
|
|
3045
|
+
}
|
|
3046
|
+
result.push(line);
|
|
3047
|
+
}
|
|
3048
|
+
return result;
|
|
3049
|
+
}
|
|
3050
|
+
function renderBorderLine(type) {
|
|
3051
|
+
const [left, mid, cross, right] = {
|
|
3052
|
+
top: ["\u250C", "\u2500", "\u252C", "\u2510"],
|
|
3053
|
+
middle: ["\u251C", "\u2500", "\u253C", "\u2524"],
|
|
3054
|
+
bottom: ["\u2514", "\u2500", "\u2534", "\u2518"]
|
|
3055
|
+
}[type];
|
|
3056
|
+
let line_0 = left;
|
|
3057
|
+
columnWidths.forEach((width_1, colIndex_3) => {
|
|
3058
|
+
line_0 += mid.repeat(width_1 + 2);
|
|
3059
|
+
line_0 += colIndex_3 < columnWidths.length - 1 ? cross : right;
|
|
3060
|
+
});
|
|
3061
|
+
return line_0;
|
|
3062
|
+
}
|
|
3063
|
+
function renderVerticalFormat() {
|
|
3064
|
+
const lines_2 = [];
|
|
3065
|
+
const headers = token.header.map((h) => getPlainText(h.tokens));
|
|
3066
|
+
const separatorWidth = Math.min(terminalWidth - 1, 40);
|
|
3067
|
+
const separator = "\u2500".repeat(separatorWidth);
|
|
3068
|
+
const wrapIndent = " ";
|
|
3069
|
+
token.rows.forEach((row_2, rowIndex) => {
|
|
3070
|
+
if (rowIndex > 0) {
|
|
3071
|
+
lines_2.push(separator);
|
|
3072
|
+
}
|
|
3073
|
+
row_2.forEach((cell_0, colIndex_4) => {
|
|
3074
|
+
const label = headers[colIndex_4] || `Column ${colIndex_4 + 1}`;
|
|
3075
|
+
const rawValue = formatCell(cell_0.tokens).trimEnd();
|
|
3076
|
+
const value = rawValue.replace(/\n+/g, " ").replace(/\s+/g, " ").trim();
|
|
3077
|
+
const firstLineWidth = terminalWidth - (0, import_ink_renderer14.stringWidth)(label) - 3;
|
|
3078
|
+
const subsequentLineWidth = terminalWidth - wrapIndent.length - 1;
|
|
3079
|
+
const firstPassLines = wrapText(value, Math.max(firstLineWidth, 10));
|
|
3080
|
+
const firstLine = firstPassLines[0] || "";
|
|
3081
|
+
let wrappedValue;
|
|
3082
|
+
if (firstPassLines.length <= 1 || subsequentLineWidth <= firstLineWidth) {
|
|
3083
|
+
wrappedValue = firstPassLines;
|
|
3084
|
+
} else {
|
|
3085
|
+
const remainingText = firstPassLines.slice(1).map((l) => l.trim()).join(" ");
|
|
3086
|
+
const rewrapped = wrapText(remainingText, subsequentLineWidth);
|
|
3087
|
+
wrappedValue = [firstLine, ...rewrapped];
|
|
3088
|
+
}
|
|
3089
|
+
lines_2.push(`${ANSI_BOLD_START}${label}:${ANSI_BOLD_END} ${wrappedValue[0] || ""}`);
|
|
3090
|
+
for (let i_3 = 1; i_3 < wrappedValue.length; i_3++) {
|
|
3091
|
+
const line_1 = wrappedValue[i_3];
|
|
3092
|
+
if (!line_1.trim()) continue;
|
|
3093
|
+
lines_2.push(`${wrapIndent}${line_1}`);
|
|
3094
|
+
}
|
|
3095
|
+
});
|
|
3096
|
+
});
|
|
3097
|
+
return lines_2.join("\n");
|
|
3098
|
+
}
|
|
3099
|
+
if (useVerticalFormat) {
|
|
3100
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ink_renderer16.Ansi, { children: renderVerticalFormat() });
|
|
3101
|
+
}
|
|
3102
|
+
const tableLines = [];
|
|
3103
|
+
tableLines.push(renderBorderLine("top"));
|
|
3104
|
+
tableLines.push(...renderRowLines(token.header, true));
|
|
3105
|
+
tableLines.push(renderBorderLine("middle"));
|
|
3106
|
+
token.rows.forEach((row_3, rowIndex_0) => {
|
|
3107
|
+
tableLines.push(...renderRowLines(row_3, false));
|
|
3108
|
+
if (rowIndex_0 < token.rows.length - 1) {
|
|
3109
|
+
tableLines.push(renderBorderLine("middle"));
|
|
3110
|
+
}
|
|
3111
|
+
});
|
|
3112
|
+
tableLines.push(renderBorderLine("bottom"));
|
|
3113
|
+
const maxLineWidth = Math.max(...tableLines.map((line_2) => (0, import_ink_renderer14.stringWidth)((0, import_strip_ansi2.default)(line_2))));
|
|
3114
|
+
if (maxLineWidth > terminalWidth - SAFETY_MARGIN) {
|
|
3115
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ink_renderer16.Ansi, { children: renderVerticalFormat() });
|
|
3116
|
+
}
|
|
3117
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ink_renderer16.Ansi, { children: tableLines.join("\n") });
|
|
3118
|
+
}
|
|
3119
|
+
|
|
3120
|
+
// src/Markdown.tsx
|
|
3121
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
3122
|
+
var TOKEN_CACHE_MAX = 500;
|
|
3123
|
+
var tokenCache = /* @__PURE__ */ new Map();
|
|
3124
|
+
var MD_SYNTAX_RE = /[#*`|[>\-_~]|\n\n|^\d+\. |\n\d+\. /;
|
|
3125
|
+
function hasMarkdownSyntax(s) {
|
|
3126
|
+
return MD_SYNTAX_RE.test(s.length > 500 ? s.slice(0, 500) : s);
|
|
3127
|
+
}
|
|
3128
|
+
function stripPromptXMLTags(content) {
|
|
3129
|
+
return content.replace(/<(commit_analysis|context|function_analysis|pr_analysis)>.*?<\/\1>\n?/gs, "").trim();
|
|
3130
|
+
}
|
|
3131
|
+
function cachedLexer(content) {
|
|
3132
|
+
if (!hasMarkdownSyntax(content)) {
|
|
3133
|
+
return [
|
|
3134
|
+
{
|
|
3135
|
+
type: "paragraph",
|
|
3136
|
+
raw: content,
|
|
3137
|
+
text: content,
|
|
3138
|
+
tokens: [{ type: "text", raw: content, text: content }]
|
|
3139
|
+
}
|
|
3140
|
+
];
|
|
3141
|
+
}
|
|
3142
|
+
const key = hashContent(content);
|
|
3143
|
+
const hit = tokenCache.get(key);
|
|
3144
|
+
if (hit) {
|
|
3145
|
+
tokenCache.delete(key);
|
|
3146
|
+
tokenCache.set(key, hit);
|
|
3147
|
+
return hit;
|
|
3148
|
+
}
|
|
3149
|
+
const tokens = import_marked2.marked.lexer(content);
|
|
3150
|
+
if (tokenCache.size >= TOKEN_CACHE_MAX) {
|
|
3151
|
+
const first = tokenCache.keys().next().value;
|
|
3152
|
+
if (first !== void 0) tokenCache.delete(first);
|
|
3153
|
+
}
|
|
3154
|
+
tokenCache.set(key, tokens);
|
|
3155
|
+
return tokens;
|
|
3156
|
+
}
|
|
3157
|
+
function Markdown(props) {
|
|
3158
|
+
const settings = {};
|
|
3159
|
+
if (settings.syntaxHighlightingDisabled) {
|
|
3160
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(MarkdownBody, { ...props, highlight: null });
|
|
3161
|
+
}
|
|
3162
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react13.Suspense, { fallback: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(MarkdownBody, { ...props, highlight: null }), children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(MarkdownWithHighlight, { ...props }) });
|
|
3163
|
+
}
|
|
3164
|
+
function MarkdownWithHighlight(props) {
|
|
3165
|
+
const highlight = (0, import_react13.use)(getCliHighlightPromise());
|
|
3166
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(MarkdownBody, { ...props, highlight });
|
|
3167
|
+
}
|
|
3168
|
+
function MarkdownBody({
|
|
3169
|
+
children,
|
|
3170
|
+
dimColor,
|
|
3171
|
+
highlight
|
|
3172
|
+
}) {
|
|
3173
|
+
const [theme] = useTheme();
|
|
3174
|
+
configureMarked();
|
|
3175
|
+
const elements = (0, import_react13.useMemo)(() => {
|
|
3176
|
+
const tokens = cachedLexer(stripPromptXMLTags(children));
|
|
3177
|
+
const elements2 = [];
|
|
3178
|
+
let nonTableContent = "";
|
|
3179
|
+
function flushNonTableContent() {
|
|
3180
|
+
if (nonTableContent) {
|
|
3181
|
+
elements2.push(
|
|
3182
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_ink_renderer17.Ansi, { dimColor, children: nonTableContent.trim() }, elements2.length)
|
|
3183
|
+
);
|
|
3184
|
+
nonTableContent = "";
|
|
3185
|
+
}
|
|
3186
|
+
}
|
|
3187
|
+
for (const token of tokens) {
|
|
3188
|
+
if (token.type === "table") {
|
|
3189
|
+
flushNonTableContent();
|
|
3190
|
+
elements2.push(
|
|
3191
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
3192
|
+
MarkdownTable,
|
|
3193
|
+
{
|
|
3194
|
+
token,
|
|
3195
|
+
highlight
|
|
3196
|
+
},
|
|
3197
|
+
elements2.length
|
|
3198
|
+
)
|
|
3199
|
+
);
|
|
3200
|
+
} else {
|
|
3201
|
+
nonTableContent += formatToken(token, theme, 0, null, null, highlight);
|
|
3202
|
+
}
|
|
3203
|
+
}
|
|
3204
|
+
flushNonTableContent();
|
|
3205
|
+
return elements2;
|
|
3206
|
+
}, [children, dimColor, highlight, theme]);
|
|
3207
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_ink_renderer17.Box, { flexDirection: "column", gap: 1, children: elements });
|
|
3208
|
+
}
|
|
3209
|
+
function StreamingMarkdown({
|
|
3210
|
+
children
|
|
3211
|
+
}) {
|
|
3212
|
+
"use no memo";
|
|
3213
|
+
configureMarked();
|
|
3214
|
+
const stripped = stripPromptXMLTags(children);
|
|
3215
|
+
const stablePrefixRef = (0, import_react13.useRef)("");
|
|
3216
|
+
if (!stripped.startsWith(stablePrefixRef.current)) {
|
|
3217
|
+
stablePrefixRef.current = "";
|
|
3218
|
+
}
|
|
3219
|
+
const boundary = stablePrefixRef.current.length;
|
|
3220
|
+
const tokens = import_marked2.marked.lexer(stripped.substring(boundary));
|
|
3221
|
+
let lastContentIdx = tokens.length - 1;
|
|
3222
|
+
while (lastContentIdx >= 0 && tokens[lastContentIdx].type === "space") {
|
|
3223
|
+
lastContentIdx--;
|
|
3224
|
+
}
|
|
3225
|
+
let advance = 0;
|
|
3226
|
+
for (let i = 0; i < lastContentIdx; i++) {
|
|
3227
|
+
advance += tokens[i].raw.length;
|
|
3228
|
+
}
|
|
3229
|
+
if (advance > 0) {
|
|
3230
|
+
stablePrefixRef.current = stripped.substring(0, boundary + advance);
|
|
3231
|
+
}
|
|
3232
|
+
const stablePrefix = stablePrefixRef.current;
|
|
3233
|
+
const unstableSuffix = stripped.substring(stablePrefix.length);
|
|
3234
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_ink_renderer17.Box, { flexDirection: "column", gap: 1, children: [
|
|
3235
|
+
stablePrefix && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Markdown, { children: stablePrefix }),
|
|
3236
|
+
unstableSuffix && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Markdown, { children: unstableSuffix })
|
|
3237
|
+
] });
|
|
3238
|
+
}
|
|
3239
|
+
|
|
3240
|
+
// src/Select.tsx
|
|
3241
|
+
var import_react14 = require("react");
|
|
3242
|
+
var import_ink_renderer18 = require("@claude-code-kit/ink-renderer");
|
|
3243
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
3244
|
+
function useListNavigation(opts) {
|
|
3245
|
+
const { options, maxVisible, onCancel, onSelect, extraHandler } = opts;
|
|
3246
|
+
const [focusIndex, setFocusIndex] = (0, import_react14.useState)(0);
|
|
3247
|
+
const focusRef = (0, import_react14.useRef)(focusIndex);
|
|
3248
|
+
focusRef.current = focusIndex;
|
|
3249
|
+
const total = options.length;
|
|
3250
|
+
const max = maxVisible ?? total;
|
|
3251
|
+
const scrollOffset = (0, import_react14.useMemo)(() => {
|
|
3252
|
+
if (total <= max) return 0;
|
|
3253
|
+
const half = Math.floor(max / 2);
|
|
3254
|
+
if (focusIndex <= half) return 0;
|
|
3255
|
+
if (focusIndex >= total - max + half) return total - max;
|
|
3256
|
+
return focusIndex - half;
|
|
3257
|
+
}, [focusIndex, total, max]);
|
|
3258
|
+
const visibleOptions = (0, import_react14.useMemo)(
|
|
3259
|
+
() => options.slice(scrollOffset, scrollOffset + max),
|
|
3260
|
+
[options, scrollOffset, max]
|
|
3261
|
+
);
|
|
3262
|
+
const moveFocus = (0, import_react14.useCallback)(
|
|
3263
|
+
(dir) => {
|
|
3264
|
+
setFocusIndex((prev) => {
|
|
3265
|
+
let next = prev;
|
|
3266
|
+
for (let i = 0; i < total; i++) {
|
|
3267
|
+
next = (next + dir + total) % total;
|
|
3268
|
+
if (!options[next].disabled) return next;
|
|
3269
|
+
}
|
|
3270
|
+
return prev;
|
|
3271
|
+
});
|
|
3272
|
+
},
|
|
3273
|
+
[options, total]
|
|
3274
|
+
);
|
|
3275
|
+
(0, import_ink_renderer18.useInput)((input, key) => {
|
|
3276
|
+
if (extraHandler?.(input, key, focusRef.current)) return;
|
|
3277
|
+
if (key.upArrow || input === "k") {
|
|
3278
|
+
moveFocus(-1);
|
|
3279
|
+
} else if (key.downArrow || input === "j") {
|
|
3280
|
+
moveFocus(1);
|
|
3281
|
+
} else if (key.return) {
|
|
3282
|
+
if (!options[focusRef.current]?.disabled) {
|
|
3283
|
+
onSelect(focusRef.current);
|
|
2053
3284
|
}
|
|
2054
3285
|
} else if (key.escape) {
|
|
2055
3286
|
onCancel?.();
|
|
@@ -2064,7 +3295,7 @@ function useListNavigation(opts) {
|
|
|
2064
3295
|
return { focusIndex, scrollOffset, visibleOptions, max, total };
|
|
2065
3296
|
}
|
|
2066
3297
|
function ScrollHint({ count, direction }) {
|
|
2067
|
-
return /* @__PURE__ */ (0,
|
|
3298
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_ink_renderer18.Text, { dimColor: true, children: [
|
|
2068
3299
|
" ",
|
|
2069
3300
|
direction === "up" ? "\u2191" : "\u2193",
|
|
2070
3301
|
" ",
|
|
@@ -2080,26 +3311,26 @@ function Select({
|
|
|
2080
3311
|
title,
|
|
2081
3312
|
maxVisible
|
|
2082
3313
|
}) {
|
|
2083
|
-
const handleSelect = (0,
|
|
3314
|
+
const handleSelect = (0, import_react14.useCallback)(
|
|
2084
3315
|
(index) => onChange(options[index].value),
|
|
2085
3316
|
[onChange, options]
|
|
2086
3317
|
);
|
|
2087
3318
|
const { focusIndex, scrollOffset, visibleOptions, max, total } = useListNavigation({ options, maxVisible, onCancel, onSelect: handleSelect });
|
|
2088
|
-
return /* @__PURE__ */ (0,
|
|
2089
|
-
title && /* @__PURE__ */ (0,
|
|
2090
|
-
scrollOffset > 0 && /* @__PURE__ */ (0,
|
|
3319
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_ink_renderer18.Box, { flexDirection: "column", children: [
|
|
3320
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_ink_renderer18.Box, { marginBottom: 1, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_ink_renderer18.Text, { bold: true, children: title }) }),
|
|
3321
|
+
scrollOffset > 0 && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ScrollHint, { count: scrollOffset, direction: "up" }),
|
|
2091
3322
|
visibleOptions.map((opt, i) => {
|
|
2092
3323
|
const realIndex = scrollOffset + i;
|
|
2093
3324
|
const isFocused = realIndex === focusIndex;
|
|
2094
3325
|
const isSelected = opt.value === defaultValue;
|
|
2095
3326
|
const isDisabled = opt.disabled === true;
|
|
2096
|
-
return /* @__PURE__ */ (0,
|
|
2097
|
-
/* @__PURE__ */ (0,
|
|
3327
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_ink_renderer18.Box, { children: [
|
|
3328
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_ink_renderer18.Text, { color: isFocused ? "cyan" : void 0, children: [
|
|
2098
3329
|
isFocused ? "\u276F" : " ",
|
|
2099
3330
|
" "
|
|
2100
3331
|
] }),
|
|
2101
|
-
/* @__PURE__ */ (0,
|
|
2102
|
-
|
|
3332
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
3333
|
+
import_ink_renderer18.Text,
|
|
2103
3334
|
{
|
|
2104
3335
|
color: isDisabled ? "gray" : isFocused ? "cyan" : void 0,
|
|
2105
3336
|
bold: isFocused,
|
|
@@ -2111,15 +3342,15 @@ function Select({
|
|
|
2111
3342
|
]
|
|
2112
3343
|
}
|
|
2113
3344
|
),
|
|
2114
|
-
isSelected && /* @__PURE__ */ (0,
|
|
2115
|
-
opt.description && /* @__PURE__ */ (0,
|
|
3345
|
+
isSelected && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_ink_renderer18.Text, { color: "green", children: " \u2713" }),
|
|
3346
|
+
opt.description && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_ink_renderer18.Text, { dimColor: true, children: [
|
|
2116
3347
|
" ",
|
|
2117
3348
|
opt.description
|
|
2118
3349
|
] })
|
|
2119
3350
|
] }, realIndex);
|
|
2120
3351
|
}),
|
|
2121
|
-
scrollOffset + max < total && /* @__PURE__ */ (0,
|
|
2122
|
-
/* @__PURE__ */ (0,
|
|
3352
|
+
scrollOffset + max < total && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ScrollHint, { count: total - scrollOffset - max, direction: "down" }),
|
|
3353
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_ink_renderer18.Box, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_ink_renderer18.Text, { dimColor: true, children: "Enter to confirm \xB7 Esc to exit" }) })
|
|
2123
3354
|
] });
|
|
2124
3355
|
}
|
|
2125
3356
|
function MultiSelect({
|
|
@@ -2131,12 +3362,12 @@ function MultiSelect({
|
|
|
2131
3362
|
title,
|
|
2132
3363
|
maxVisible
|
|
2133
3364
|
}) {
|
|
2134
|
-
const [selected, setSelected] = (0,
|
|
2135
|
-
const handleConfirm = (0,
|
|
3365
|
+
const [selected, setSelected] = (0, import_react14.useState)(() => new Set(selectedValues));
|
|
3366
|
+
const handleConfirm = (0, import_react14.useCallback)(
|
|
2136
3367
|
() => onConfirm(Array.from(selected)),
|
|
2137
3368
|
[onConfirm, selected]
|
|
2138
3369
|
);
|
|
2139
|
-
const handleSpace = (0,
|
|
3370
|
+
const handleSpace = (0, import_react14.useCallback)(
|
|
2140
3371
|
(input, _key, focusIndex2) => {
|
|
2141
3372
|
if (input !== " ") return false;
|
|
2142
3373
|
const opt = options[focusIndex2];
|
|
@@ -2159,21 +3390,21 @@ function MultiSelect({
|
|
|
2159
3390
|
onSelect: handleConfirm,
|
|
2160
3391
|
extraHandler: handleSpace
|
|
2161
3392
|
});
|
|
2162
|
-
return /* @__PURE__ */ (0,
|
|
2163
|
-
title && /* @__PURE__ */ (0,
|
|
2164
|
-
scrollOffset > 0 && /* @__PURE__ */ (0,
|
|
3393
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_ink_renderer18.Box, { flexDirection: "column", children: [
|
|
3394
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_ink_renderer18.Box, { marginBottom: 1, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_ink_renderer18.Text, { bold: true, children: title }) }),
|
|
3395
|
+
scrollOffset > 0 && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ScrollHint, { count: scrollOffset, direction: "up" }),
|
|
2165
3396
|
visibleOptions.map((opt, i) => {
|
|
2166
3397
|
const realIndex = scrollOffset + i;
|
|
2167
3398
|
const isFocused = realIndex === focusIndex;
|
|
2168
3399
|
const isChecked = selected.has(opt.value);
|
|
2169
3400
|
const isDisabled = opt.disabled === true;
|
|
2170
|
-
return /* @__PURE__ */ (0,
|
|
2171
|
-
/* @__PURE__ */ (0,
|
|
3401
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_ink_renderer18.Box, { children: [
|
|
3402
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_ink_renderer18.Text, { color: isFocused ? "cyan" : void 0, children: [
|
|
2172
3403
|
isFocused ? "\u276F" : " ",
|
|
2173
3404
|
" "
|
|
2174
3405
|
] }),
|
|
2175
|
-
/* @__PURE__ */ (0,
|
|
2176
|
-
|
|
3406
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
3407
|
+
import_ink_renderer18.Text,
|
|
2177
3408
|
{
|
|
2178
3409
|
color: isDisabled ? "gray" : isFocused ? "cyan" : void 0,
|
|
2179
3410
|
bold: isFocused,
|
|
@@ -2187,83 +3418,330 @@ function MultiSelect({
|
|
|
2187
3418
|
]
|
|
2188
3419
|
}
|
|
2189
3420
|
),
|
|
2190
|
-
opt.description && /* @__PURE__ */ (0,
|
|
3421
|
+
opt.description && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_ink_renderer18.Text, { dimColor: true, children: [
|
|
2191
3422
|
" ",
|
|
2192
3423
|
opt.description
|
|
2193
3424
|
] })
|
|
2194
3425
|
] }, realIndex);
|
|
2195
3426
|
}),
|
|
2196
|
-
scrollOffset + max < total && /* @__PURE__ */ (0,
|
|
2197
|
-
/* @__PURE__ */ (0,
|
|
3427
|
+
scrollOffset + max < total && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ScrollHint, { count: total - scrollOffset - max, direction: "down" }),
|
|
3428
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_ink_renderer18.Box, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_ink_renderer18.Text, { dimColor: true, children: "Space to toggle \xB7 Enter to confirm \xB7 Esc to exit" }) })
|
|
3429
|
+
] });
|
|
3430
|
+
}
|
|
3431
|
+
|
|
3432
|
+
// src/PermissionRequest.tsx
|
|
3433
|
+
var import_react15 = __toESM(require("react"));
|
|
3434
|
+
var import_ink_renderer19 = require("@claude-code-kit/ink-renderer");
|
|
3435
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
3436
|
+
function PermissionHeader({ toolName, width }) {
|
|
3437
|
+
const label = ` ${toolName} `;
|
|
3438
|
+
const labelLen = toolName.length + 2;
|
|
3439
|
+
const leftLen = 3;
|
|
3440
|
+
const rightLen = Math.max(0, width - leftLen - labelLen);
|
|
3441
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_ink_renderer19.Text, { children: [
|
|
3442
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ink_renderer19.Text, { dimColor: true, children: "\u2500".repeat(leftLen) }),
|
|
3443
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ink_renderer19.Text, { bold: true, color: "cyan", children: label }),
|
|
3444
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ink_renderer19.Text, { dimColor: true, children: "\u2500".repeat(rightLen) })
|
|
3445
|
+
] });
|
|
3446
|
+
}
|
|
3447
|
+
function HorizontalRule({ width }) {
|
|
3448
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ink_renderer19.Text, { dimColor: true, children: "\u2500".repeat(width) });
|
|
3449
|
+
}
|
|
3450
|
+
function BashPermissionContent({ command }) {
|
|
3451
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_ink_renderer19.Box, { flexDirection: "column", children: [
|
|
3452
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ink_renderer19.Text, { children: "Run command:" }),
|
|
3453
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ink_renderer19.Box, { marginLeft: 2, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ink_renderer19.Text, { color: "yellow", children: command }) })
|
|
3454
|
+
] });
|
|
3455
|
+
}
|
|
3456
|
+
function FileEditPermissionContent({
|
|
3457
|
+
filename,
|
|
3458
|
+
diff
|
|
3459
|
+
}) {
|
|
3460
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_ink_renderer19.Box, { flexDirection: "column", children: [
|
|
3461
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_ink_renderer19.Text, { children: [
|
|
3462
|
+
"Edit file: ",
|
|
3463
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ink_renderer19.Text, { color: "cyan", bold: true, children: filename })
|
|
3464
|
+
] }),
|
|
3465
|
+
diff && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ink_renderer19.Box, { marginTop: 1, flexDirection: "column", children: diff.split("\n").map((line, i) => {
|
|
3466
|
+
let color2;
|
|
3467
|
+
if (line.startsWith("+")) color2 = "green";
|
|
3468
|
+
else if (line.startsWith("-")) color2 = "red";
|
|
3469
|
+
else if (line.startsWith("@")) color2 = "cyan";
|
|
3470
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ink_renderer19.Text, { color: color2, dimColor: !color2 && !line.startsWith("+"), children: line }, i);
|
|
3471
|
+
}) })
|
|
3472
|
+
] });
|
|
3473
|
+
}
|
|
3474
|
+
function PermissionRequest({
|
|
3475
|
+
toolName,
|
|
3476
|
+
description,
|
|
3477
|
+
details,
|
|
3478
|
+
showAlwaysAllow = true,
|
|
3479
|
+
onDecision,
|
|
3480
|
+
children,
|
|
3481
|
+
preview
|
|
3482
|
+
}) {
|
|
3483
|
+
const terminalSize = (0, import_react15.useContext)(import_ink_renderer19.TerminalSizeContext);
|
|
3484
|
+
const terminalWidth = Math.min((terminalSize?.columns ?? 80) - 2, 80);
|
|
3485
|
+
const options = (0, import_react15.useMemo)(() => {
|
|
3486
|
+
const opts = [
|
|
3487
|
+
{ value: "allow", label: "Yes, allow this action" }
|
|
3488
|
+
];
|
|
3489
|
+
if (showAlwaysAllow) {
|
|
3490
|
+
opts.push({ value: "always_allow", label: `Yes, and always allow ${toolName}` });
|
|
3491
|
+
}
|
|
3492
|
+
opts.push({ value: "deny", label: "No, deny" });
|
|
3493
|
+
return opts;
|
|
3494
|
+
}, [showAlwaysAllow, toolName]);
|
|
3495
|
+
const [focusIndex, setFocusIndex] = import_react15.default.useState(0);
|
|
3496
|
+
const focusRef = import_react15.default.useRef(focusIndex);
|
|
3497
|
+
focusRef.current = focusIndex;
|
|
3498
|
+
const decide = (0, import_react15.useCallback)(
|
|
3499
|
+
(action) => {
|
|
3500
|
+
onDecision(action);
|
|
3501
|
+
},
|
|
3502
|
+
[onDecision]
|
|
3503
|
+
);
|
|
3504
|
+
(0, import_ink_renderer19.useInput)((input, key) => {
|
|
3505
|
+
if (input === "y") {
|
|
3506
|
+
decide("allow");
|
|
3507
|
+
return;
|
|
3508
|
+
}
|
|
3509
|
+
if (input === "a" && showAlwaysAllow) {
|
|
3510
|
+
decide("always_allow");
|
|
3511
|
+
return;
|
|
3512
|
+
}
|
|
3513
|
+
if (input === "n" || key.escape) {
|
|
3514
|
+
decide("deny");
|
|
3515
|
+
return;
|
|
3516
|
+
}
|
|
3517
|
+
if (key.upArrow || input === "k") {
|
|
3518
|
+
setFocusIndex((prev) => (prev - 1 + options.length) % options.length);
|
|
3519
|
+
} else if (key.downArrow || input === "j") {
|
|
3520
|
+
setFocusIndex((prev) => (prev + 1) % options.length);
|
|
3521
|
+
} else if (key.return) {
|
|
3522
|
+
decide(options[focusRef.current].value);
|
|
3523
|
+
} else if (input >= "1" && input <= "9") {
|
|
3524
|
+
const idx = parseInt(input, 10) - 1;
|
|
3525
|
+
if (idx < options.length) {
|
|
3526
|
+
setFocusIndex(idx);
|
|
3527
|
+
decide(options[idx].value);
|
|
3528
|
+
}
|
|
3529
|
+
}
|
|
3530
|
+
});
|
|
3531
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_ink_renderer19.Box, { flexDirection: "column", children: [
|
|
3532
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(PermissionHeader, { toolName, width: terminalWidth }),
|
|
3533
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ink_renderer19.Box, { marginTop: 1, marginLeft: 2, flexDirection: "column", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ink_renderer19.Text, { children: description }) }),
|
|
3534
|
+
details && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ink_renderer19.Box, { marginTop: 1, marginLeft: 4, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ink_renderer19.Text, { color: "yellow", children: details }) }),
|
|
3535
|
+
children && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ink_renderer19.Box, { marginTop: 1, marginLeft: 2, flexDirection: "column", children }),
|
|
3536
|
+
preview && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ink_renderer19.Box, { marginTop: 1, marginLeft: 2, flexDirection: "column", children: preview }),
|
|
3537
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ink_renderer19.Box, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(HorizontalRule, { width: terminalWidth }) }),
|
|
3538
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ink_renderer19.Box, { marginTop: 1, flexDirection: "column", children: options.map((opt, i) => {
|
|
3539
|
+
const isFocused = i === focusIndex;
|
|
3540
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_ink_renderer19.Box, { children: [
|
|
3541
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_ink_renderer19.Text, { color: isFocused ? "cyan" : void 0, children: [
|
|
3542
|
+
isFocused ? "\u276F" : " ",
|
|
3543
|
+
" "
|
|
3544
|
+
] }),
|
|
3545
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
3546
|
+
import_ink_renderer19.Text,
|
|
3547
|
+
{
|
|
3548
|
+
color: isFocused ? "cyan" : void 0,
|
|
3549
|
+
bold: isFocused,
|
|
3550
|
+
children: [
|
|
3551
|
+
i + 1,
|
|
3552
|
+
". ",
|
|
3553
|
+
opt.label
|
|
3554
|
+
]
|
|
3555
|
+
}
|
|
3556
|
+
)
|
|
3557
|
+
] }, opt.value);
|
|
3558
|
+
}) }),
|
|
3559
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ink_renderer19.Box, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ink_renderer19.Text, { dimColor: true, children: "Enter to confirm \xB7 Esc to deny" }) })
|
|
2198
3560
|
] });
|
|
2199
3561
|
}
|
|
2200
3562
|
|
|
2201
3563
|
// src/MessageList.tsx
|
|
2202
|
-
var
|
|
2203
|
-
var
|
|
3564
|
+
var import_react16 = require("react");
|
|
3565
|
+
var import_ink_renderer20 = require("@claude-code-kit/ink-renderer");
|
|
3566
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
2204
3567
|
var ROLE_CONFIG = {
|
|
2205
3568
|
user: { icon: "\u276F", label: "You", color: "cyan" },
|
|
2206
3569
|
assistant: { icon: "\u25CF", label: "Claude", color: "#DA7756" },
|
|
2207
3570
|
system: { icon: "\u273B", label: "System", color: void 0 }
|
|
2208
3571
|
};
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
}) {
|
|
2213
|
-
if (renderMessage) {
|
|
2214
|
-
return renderMessage(message);
|
|
2215
|
-
}
|
|
2216
|
-
const config = ROLE_CONFIG[message.role];
|
|
2217
|
-
const isSystem = message.role === "system";
|
|
2218
|
-
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_ink_renderer10.Box, { flexDirection: "column", children: [
|
|
2219
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_ink_renderer10.Box, { children: [
|
|
2220
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_ink_renderer10.Text, { color: config.color, dimColor: isSystem, children: config.icon }),
|
|
2221
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_ink_renderer10.Text, { color: config.color, dimColor: isSystem, bold: !isSystem, children: [
|
|
2222
|
-
" ",
|
|
2223
|
-
config.label
|
|
2224
|
-
] })
|
|
2225
|
-
] }),
|
|
2226
|
-
message.content.split("\n").map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_ink_renderer10.Box, { marginLeft: 2, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_ink_renderer10.Text, { dimColor: isSystem, children: line }) }, i))
|
|
2227
|
-
] });
|
|
3572
|
+
var GUTTER = "\u23BF";
|
|
3573
|
+
function TextBlock({ text, dim }) {
|
|
3574
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_jsx_runtime15.Fragment, { children: text.split("\n").map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink_renderer20.Box, { marginLeft: 2, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink_renderer20.Text, { dimColor: dim, children: line }) }, i)) });
|
|
2228
3575
|
}
|
|
2229
|
-
function
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
/* @__PURE__ */ (0,
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
3576
|
+
function ToolUseBlock({ content }) {
|
|
3577
|
+
const statusColor = content.status === "error" ? "red" : content.status === "success" ? "green" : void 0;
|
|
3578
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink_renderer20.Box, { flexDirection: "column", marginLeft: 2, children: [
|
|
3579
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink_renderer20.Box, { children: [
|
|
3580
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink_renderer20.Text, { dimColor: true, children: [
|
|
3581
|
+
GUTTER,
|
|
3582
|
+
" "
|
|
3583
|
+
] }),
|
|
3584
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink_renderer20.Text, { bold: true, children: content.toolName })
|
|
3585
|
+
] }),
|
|
3586
|
+
content.input.split("\n").map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink_renderer20.Box, { marginLeft: 4, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink_renderer20.Text, { dimColor: true, children: line }) }, i)),
|
|
3587
|
+
content.status === "running" && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink_renderer20.Box, { marginLeft: 4, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Spinner, { label: content.toolName, showElapsed: true }) }),
|
|
3588
|
+
content.result != null && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink_renderer20.Box, { flexDirection: "column", marginLeft: 4, children: [
|
|
3589
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink_renderer20.Box, { children: [
|
|
3590
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink_renderer20.Text, { dimColor: true, children: [
|
|
3591
|
+
GUTTER,
|
|
3592
|
+
" "
|
|
3593
|
+
] }),
|
|
3594
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink_renderer20.Text, { color: statusColor, children: [
|
|
3595
|
+
"result (",
|
|
3596
|
+
content.status ?? "done",
|
|
3597
|
+
")"
|
|
2242
3598
|
] })
|
|
2243
3599
|
] }),
|
|
2244
|
-
|
|
2245
|
-
line,
|
|
2246
|
-
i === streamingContent.split("\n").length - 1 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_ink_renderer10.Text, { color: "#DA7756", children: "\u2588" })
|
|
2247
|
-
] }) }, i))
|
|
3600
|
+
content.result.split("\n").map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink_renderer20.Box, { marginLeft: 6, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink_renderer20.Text, { color: statusColor, dimColor: !statusColor, children: line }) }, i))
|
|
2248
3601
|
] })
|
|
2249
3602
|
] });
|
|
2250
3603
|
}
|
|
2251
|
-
|
|
3604
|
+
function ThinkingBlock({ content }) {
|
|
3605
|
+
const [collapsed, setCollapsed] = (0, import_react16.useState)(content.collapsed ?? true);
|
|
3606
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink_renderer20.Box, { flexDirection: "column", marginLeft: 2, children: [
|
|
3607
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink_renderer20.Box, { onClick: () => setCollapsed((c) => !c), children: [
|
|
3608
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink_renderer20.Text, { color: "#DA7756", children: [
|
|
3609
|
+
"\u273B",
|
|
3610
|
+
" "
|
|
3611
|
+
] }),
|
|
3612
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink_renderer20.Text, { dimColor: true, children: [
|
|
3613
|
+
"Thinking...",
|
|
3614
|
+
collapsed ? " (click to expand)" : ""
|
|
3615
|
+
] })
|
|
3616
|
+
] }),
|
|
3617
|
+
!collapsed && content.text.split("\n").map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink_renderer20.Box, { marginLeft: 4, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink_renderer20.Text, { dimColor: true, children: line }) }, i))
|
|
3618
|
+
] });
|
|
3619
|
+
}
|
|
3620
|
+
function DiffBlock({ content }) {
|
|
3621
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink_renderer20.Box, { flexDirection: "column", marginLeft: 2, children: [
|
|
3622
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink_renderer20.Box, { children: [
|
|
3623
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink_renderer20.Text, { dimColor: true, children: [
|
|
3624
|
+
GUTTER,
|
|
3625
|
+
" "
|
|
3626
|
+
] }),
|
|
3627
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink_renderer20.Text, { bold: true, children: content.filename })
|
|
3628
|
+
] }),
|
|
3629
|
+
content.diff.split("\n").map((line, i) => {
|
|
3630
|
+
let color2;
|
|
3631
|
+
if (line.startsWith("+")) color2 = "green";
|
|
3632
|
+
else if (line.startsWith("-")) color2 = "red";
|
|
3633
|
+
else if (line.startsWith("@")) color2 = "cyan";
|
|
3634
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink_renderer20.Box, { marginLeft: 4, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink_renderer20.Text, { color: color2, dimColor: !color2, children: line }) }, i);
|
|
3635
|
+
})
|
|
3636
|
+
] });
|
|
3637
|
+
}
|
|
3638
|
+
function CodeBlock({ content }) {
|
|
3639
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink_renderer20.Box, { flexDirection: "column", marginLeft: 2, children: [
|
|
3640
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink_renderer20.Text, { dimColor: true, children: [
|
|
3641
|
+
"```",
|
|
3642
|
+
content.language ?? ""
|
|
3643
|
+
] }),
|
|
3644
|
+
content.code.split("\n").map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink_renderer20.Box, { marginLeft: 2, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink_renderer20.Text, { children: line }) }, i)),
|
|
3645
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink_renderer20.Text, { dimColor: true, children: "```" })
|
|
3646
|
+
] });
|
|
3647
|
+
}
|
|
3648
|
+
function ErrorBlock({ content }) {
|
|
3649
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink_renderer20.Box, { flexDirection: "column", marginLeft: 2, children: [
|
|
3650
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink_renderer20.Box, { children: [
|
|
3651
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink_renderer20.Text, { color: "red", children: [
|
|
3652
|
+
"\u2716",
|
|
3653
|
+
" Error: "
|
|
3654
|
+
] }),
|
|
3655
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink_renderer20.Text, { color: "red", children: content.message })
|
|
3656
|
+
] }),
|
|
3657
|
+
content.details?.split("\n").map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink_renderer20.Box, { marginLeft: 4, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink_renderer20.Text, { color: "red", dimColor: true, children: line }) }, i))
|
|
3658
|
+
] });
|
|
3659
|
+
}
|
|
3660
|
+
function ContentBlock({ block }) {
|
|
3661
|
+
switch (block.type) {
|
|
3662
|
+
case "text":
|
|
3663
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(TextBlock, { text: block.text });
|
|
3664
|
+
case "tool_use":
|
|
3665
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ToolUseBlock, { content: block });
|
|
3666
|
+
case "thinking":
|
|
3667
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ThinkingBlock, { content: block });
|
|
3668
|
+
case "diff":
|
|
3669
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DiffBlock, { content: block });
|
|
3670
|
+
case "code":
|
|
3671
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(CodeBlock, { content: block });
|
|
3672
|
+
case "error":
|
|
3673
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ErrorBlock, { content: block });
|
|
3674
|
+
default:
|
|
3675
|
+
return null;
|
|
3676
|
+
}
|
|
3677
|
+
}
|
|
3678
|
+
function MessageItem({
|
|
3679
|
+
message,
|
|
3680
|
+
renderMessage
|
|
3681
|
+
}) {
|
|
3682
|
+
if (renderMessage) {
|
|
3683
|
+
return renderMessage(message);
|
|
3684
|
+
}
|
|
3685
|
+
const config = ROLE_CONFIG[message.role];
|
|
3686
|
+
const isSystem = message.role === "system";
|
|
3687
|
+
if (typeof message.content === "string") {
|
|
3688
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink_renderer20.Box, { flexDirection: "column", children: [
|
|
3689
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink_renderer20.Box, { children: [
|
|
3690
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink_renderer20.Text, { color: config.color, dimColor: isSystem, children: config.icon }),
|
|
3691
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink_renderer20.Text, { color: config.color, dimColor: isSystem, bold: !isSystem, children: [
|
|
3692
|
+
" ",
|
|
3693
|
+
config.label
|
|
3694
|
+
] })
|
|
3695
|
+
] }),
|
|
3696
|
+
message.content.split("\n").map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink_renderer20.Box, { marginLeft: 2, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink_renderer20.Text, { dimColor: isSystem, children: line }) }, i))
|
|
3697
|
+
] });
|
|
3698
|
+
}
|
|
3699
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink_renderer20.Box, { flexDirection: "column", children: [
|
|
3700
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink_renderer20.Box, { children: [
|
|
3701
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink_renderer20.Text, { color: config.color, dimColor: isSystem, children: config.icon }),
|
|
3702
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink_renderer20.Text, { color: config.color, dimColor: isSystem, bold: !isSystem, children: [
|
|
3703
|
+
" ",
|
|
3704
|
+
config.label
|
|
3705
|
+
] })
|
|
3706
|
+
] }),
|
|
3707
|
+
message.content.map((block, i) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ContentBlock, { block }, i))
|
|
3708
|
+
] });
|
|
3709
|
+
}
|
|
3710
|
+
function MessageList({
|
|
3711
|
+
messages,
|
|
3712
|
+
streamingContent,
|
|
3713
|
+
renderMessage
|
|
3714
|
+
}) {
|
|
3715
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink_renderer20.Box, { flexDirection: "column", children: [
|
|
3716
|
+
messages.map((message, i) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink_renderer20.Box, { flexDirection: "column", marginTop: i > 0 ? 1 : 0, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(MessageItem, { message, renderMessage }) }, message.id)),
|
|
3717
|
+
streamingContent != null && streamingContent.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink_renderer20.Box, { flexDirection: "column", marginTop: messages.length > 0 ? 1 : 0, children: [
|
|
3718
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink_renderer20.Box, { children: [
|
|
3719
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink_renderer20.Text, { color: "#DA7756", children: "\u25CF" }),
|
|
3720
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink_renderer20.Text, { color: "#DA7756", bold: true, children: " Claude" })
|
|
3721
|
+
] }),
|
|
3722
|
+
streamingContent.split("\n").map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink_renderer20.Box, { marginLeft: 2, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink_renderer20.Text, { children: [
|
|
3723
|
+
line,
|
|
3724
|
+
i === streamingContent.split("\n").length - 1 && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink_renderer20.Text, { color: "#DA7756", children: "\u2588" })
|
|
3725
|
+
] }) }, i))
|
|
3726
|
+
] })
|
|
3727
|
+
] });
|
|
3728
|
+
}
|
|
3729
|
+
|
|
2252
3730
|
// src/StreamingText.tsx
|
|
2253
|
-
var
|
|
2254
|
-
var
|
|
2255
|
-
var
|
|
3731
|
+
var import_react17 = require("react");
|
|
3732
|
+
var import_ink_renderer21 = require("@claude-code-kit/ink-renderer");
|
|
3733
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
2256
3734
|
function StreamingText({
|
|
2257
3735
|
text,
|
|
2258
3736
|
speed = 3,
|
|
2259
3737
|
interval = 20,
|
|
2260
3738
|
onComplete,
|
|
2261
|
-
color
|
|
3739
|
+
color: color2
|
|
2262
3740
|
}) {
|
|
2263
|
-
const [revealed, setRevealed] = (0,
|
|
2264
|
-
const onCompleteRef = (0,
|
|
3741
|
+
const [revealed, setRevealed] = (0, import_react17.useState)(0);
|
|
3742
|
+
const onCompleteRef = (0, import_react17.useRef)(onComplete);
|
|
2265
3743
|
onCompleteRef.current = onComplete;
|
|
2266
|
-
(0,
|
|
3744
|
+
(0, import_react17.useEffect)(() => {
|
|
2267
3745
|
if (revealed >= text.length) return;
|
|
2268
3746
|
const id = setInterval(() => {
|
|
2269
3747
|
setRevealed((prev) => {
|
|
@@ -2276,19 +3754,171 @@ function StreamingText({
|
|
|
2276
3754
|
}, interval);
|
|
2277
3755
|
return () => clearInterval(id);
|
|
2278
3756
|
}, [text.length, speed, interval, revealed >= text.length]);
|
|
2279
|
-
return /* @__PURE__ */ (0,
|
|
3757
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_ink_renderer21.Text, { color: color2, children: text.slice(0, revealed) });
|
|
2280
3758
|
}
|
|
2281
3759
|
|
|
2282
3760
|
// src/REPL.tsx
|
|
2283
|
-
var
|
|
2284
|
-
var
|
|
2285
|
-
|
|
3761
|
+
var import_react19 = require("react");
|
|
3762
|
+
var import_ink_renderer23 = require("@claude-code-kit/ink-renderer");
|
|
3763
|
+
|
|
3764
|
+
// src/SearchOverlay.tsx
|
|
3765
|
+
var import_react18 = require("react");
|
|
3766
|
+
var import_ink_renderer22 = require("@claude-code-kit/ink-renderer");
|
|
3767
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
3768
|
+
function computeMatches(content, query) {
|
|
3769
|
+
if (!query) return [];
|
|
3770
|
+
const lower = query.toLowerCase();
|
|
3771
|
+
const found = [];
|
|
3772
|
+
for (let i = 0; i < content.length; i++) {
|
|
3773
|
+
const text = content[i] ?? "";
|
|
3774
|
+
let offset = 0;
|
|
3775
|
+
let pos = text.toLowerCase().indexOf(lower, offset);
|
|
3776
|
+
while (pos !== -1) {
|
|
3777
|
+
found.push({ index: i, offset: pos, length: query.length });
|
|
3778
|
+
offset = pos + 1;
|
|
3779
|
+
pos = text.toLowerCase().indexOf(lower, offset);
|
|
3780
|
+
}
|
|
3781
|
+
}
|
|
3782
|
+
return found;
|
|
3783
|
+
}
|
|
3784
|
+
function useSearch({ content, isActive }) {
|
|
3785
|
+
const [query, setQueryState] = (0, import_react18.useState)("");
|
|
3786
|
+
const [matches, setMatches] = (0, import_react18.useState)([]);
|
|
3787
|
+
const [currentIndex, setCurrentIndex] = (0, import_react18.useState)(0);
|
|
3788
|
+
const setQuery = (0, import_react18.useCallback)((q) => {
|
|
3789
|
+
setQueryState(q);
|
|
3790
|
+
const found = computeMatches(content, q);
|
|
3791
|
+
setMatches(found);
|
|
3792
|
+
setCurrentIndex(found.length > 0 ? 0 : -1);
|
|
3793
|
+
}, [content]);
|
|
3794
|
+
const next = (0, import_react18.useCallback)(() => {
|
|
3795
|
+
if (matches.length === 0) return;
|
|
3796
|
+
setCurrentIndex((i) => (i + 1) % matches.length);
|
|
3797
|
+
}, [matches.length]);
|
|
3798
|
+
const previous = (0, import_react18.useCallback)(() => {
|
|
3799
|
+
if (matches.length === 0) return;
|
|
3800
|
+
setCurrentIndex((i) => (i - 1 + matches.length) % matches.length);
|
|
3801
|
+
}, [matches.length]);
|
|
3802
|
+
(0, import_react18.useEffect)(() => {
|
|
3803
|
+
if (!isActive) {
|
|
3804
|
+
setQueryState("");
|
|
3805
|
+
setMatches([]);
|
|
3806
|
+
setCurrentIndex(0);
|
|
3807
|
+
}
|
|
3808
|
+
}, [isActive]);
|
|
3809
|
+
return { query, matches, currentIndex, next, previous, setQuery };
|
|
3810
|
+
}
|
|
3811
|
+
function SearchOverlay({
|
|
3812
|
+
isOpen,
|
|
3813
|
+
onClose,
|
|
3814
|
+
onSearch,
|
|
3815
|
+
onNavigate
|
|
3816
|
+
}) {
|
|
3817
|
+
const [query, setQueryState] = (0, import_react18.useState)("");
|
|
3818
|
+
const [cursor, setCursor] = (0, import_react18.useState)(0);
|
|
3819
|
+
const [matches, setMatches] = (0, import_react18.useState)([]);
|
|
3820
|
+
const matchIndexRef = (0, import_react18.useRef)(0);
|
|
3821
|
+
const [matchIndex, setMatchIndexState] = (0, import_react18.useState)(0);
|
|
3822
|
+
const setMatchIndex = (0, import_react18.useCallback)((next) => {
|
|
3823
|
+
matchIndexRef.current = next;
|
|
3824
|
+
setMatchIndexState(next);
|
|
3825
|
+
}, []);
|
|
3826
|
+
(0, import_react18.useEffect)(() => {
|
|
3827
|
+
if (!isOpen) {
|
|
3828
|
+
setQueryState("");
|
|
3829
|
+
setCursor(0);
|
|
3830
|
+
setMatches([]);
|
|
3831
|
+
setMatchIndex(0);
|
|
3832
|
+
}
|
|
3833
|
+
}, [isOpen, setMatchIndex]);
|
|
3834
|
+
const runSearch = (0, import_react18.useCallback)((q) => {
|
|
3835
|
+
const found = onSearch(q);
|
|
3836
|
+
setMatches(found);
|
|
3837
|
+
setMatchIndex(0);
|
|
3838
|
+
if (found.length > 0) onNavigate(found[0]);
|
|
3839
|
+
}, [onSearch, onNavigate, setMatchIndex]);
|
|
3840
|
+
const navigate = (0, import_react18.useCallback)((delta) => {
|
|
3841
|
+
setMatches((currentMatches) => {
|
|
3842
|
+
if (currentMatches.length === 0) return currentMatches;
|
|
3843
|
+
const next = (matchIndexRef.current + delta + currentMatches.length) % currentMatches.length;
|
|
3844
|
+
setMatchIndex(next);
|
|
3845
|
+
onNavigate(currentMatches[next]);
|
|
3846
|
+
return currentMatches;
|
|
3847
|
+
});
|
|
3848
|
+
}, [onNavigate, setMatchIndex]);
|
|
3849
|
+
(0, import_ink_renderer22.useInput)(
|
|
3850
|
+
(input, key) => {
|
|
3851
|
+
if (key.escape) {
|
|
3852
|
+
onClose();
|
|
3853
|
+
return;
|
|
3854
|
+
}
|
|
3855
|
+
if (key.return) {
|
|
3856
|
+
navigate(1);
|
|
3857
|
+
return;
|
|
3858
|
+
}
|
|
3859
|
+
if (input === "n" && key.ctrl) {
|
|
3860
|
+
navigate(1);
|
|
3861
|
+
return;
|
|
3862
|
+
}
|
|
3863
|
+
if (input === "p" && key.ctrl) {
|
|
3864
|
+
navigate(-1);
|
|
3865
|
+
return;
|
|
3866
|
+
}
|
|
3867
|
+
if (key.backspace) {
|
|
3868
|
+
if (cursor > 0) {
|
|
3869
|
+
const next = query.slice(0, cursor - 1) + query.slice(cursor);
|
|
3870
|
+
setQueryState(next);
|
|
3871
|
+
setCursor(cursor - 1);
|
|
3872
|
+
runSearch(next);
|
|
3873
|
+
}
|
|
3874
|
+
return;
|
|
3875
|
+
}
|
|
3876
|
+
if (key.leftArrow) {
|
|
3877
|
+
setCursor((c) => Math.max(0, c - 1));
|
|
3878
|
+
return;
|
|
3879
|
+
}
|
|
3880
|
+
if (key.rightArrow) {
|
|
3881
|
+
setCursor((c) => Math.min(query.length, c + 1));
|
|
3882
|
+
return;
|
|
3883
|
+
}
|
|
3884
|
+
if (key.ctrl || key.meta) return;
|
|
3885
|
+
if (input.length > 0) {
|
|
3886
|
+
const next = query.slice(0, cursor) + input + query.slice(cursor);
|
|
3887
|
+
setQueryState(next);
|
|
3888
|
+
setCursor(cursor + input.length);
|
|
3889
|
+
runSearch(next);
|
|
3890
|
+
}
|
|
3891
|
+
},
|
|
3892
|
+
{ isActive: isOpen }
|
|
3893
|
+
);
|
|
3894
|
+
if (!isOpen) return null;
|
|
3895
|
+
const total = matches.length;
|
|
3896
|
+
const current = total > 0 ? matchIndex + 1 : 0;
|
|
3897
|
+
const countLabel = total > 0 ? `${current}/${total} matches` : "no matches";
|
|
3898
|
+
const before = query.slice(0, cursor);
|
|
3899
|
+
const atCursor = cursor < query.length ? query[cursor] : " ";
|
|
3900
|
+
const after = cursor < query.length ? query.slice(cursor + 1) : "";
|
|
3901
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_ink_renderer22.Box, { flexDirection: "row", paddingX: 1, children: [
|
|
3902
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_ink_renderer22.Text, { color: "cyan", children: "Search: " }),
|
|
3903
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_ink_renderer22.Box, { flexGrow: 1, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_ink_renderer22.Text, { children: [
|
|
3904
|
+
before,
|
|
3905
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_ink_renderer22.Text, { inverse: true, children: atCursor }),
|
|
3906
|
+
after
|
|
3907
|
+
] }) }),
|
|
3908
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_ink_renderer22.Text, { dimColor: true, children: countLabel })
|
|
3909
|
+
] });
|
|
3910
|
+
}
|
|
3911
|
+
|
|
3912
|
+
// src/REPL.tsx
|
|
3913
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
2286
3914
|
function REPL({
|
|
2287
3915
|
onSubmit,
|
|
2288
3916
|
onExit,
|
|
2289
3917
|
messages,
|
|
2290
3918
|
isLoading = false,
|
|
2291
3919
|
streamingContent,
|
|
3920
|
+
welcome,
|
|
3921
|
+
permissionRequest,
|
|
2292
3922
|
commands = [],
|
|
2293
3923
|
model,
|
|
2294
3924
|
statusSegments,
|
|
@@ -2298,16 +3928,20 @@ function REPL({
|
|
|
2298
3928
|
renderMessage,
|
|
2299
3929
|
spinner
|
|
2300
3930
|
}) {
|
|
2301
|
-
const { exit } = (0,
|
|
2302
|
-
const [inputValue, setInputValue] = (0,
|
|
2303
|
-
const [internalHistory, setInternalHistory] = (0,
|
|
2304
|
-
const
|
|
3931
|
+
const { exit } = (0, import_ink_renderer23.useApp)();
|
|
3932
|
+
const [inputValue, setInputValue] = (0, import_react19.useState)("");
|
|
3933
|
+
const [internalHistory, setInternalHistory] = (0, import_react19.useState)([]);
|
|
3934
|
+
const [searchOpen, setSearchOpen] = (0, import_react19.useState)(false);
|
|
3935
|
+
const submittingRef = (0, import_react19.useRef)(false);
|
|
2305
3936
|
const history = externalHistory ?? internalHistory;
|
|
3937
|
+
const messageContents = messages.map(
|
|
3938
|
+
(m) => typeof m.content === "string" ? m.content : m.content.map((b) => "text" in b ? b.text : "").join(" ")
|
|
3939
|
+
);
|
|
2306
3940
|
const promptCommands = commands.map((c) => ({
|
|
2307
3941
|
name: c.name,
|
|
2308
3942
|
description: c.description
|
|
2309
3943
|
}));
|
|
2310
|
-
const handleSubmit = (0,
|
|
3944
|
+
const handleSubmit = (0, import_react19.useCallback)(
|
|
2311
3945
|
(value) => {
|
|
2312
3946
|
if (submittingRef.current) return;
|
|
2313
3947
|
const trimmed = value.trim();
|
|
@@ -2339,7 +3973,7 @@ function REPL({
|
|
|
2339
3973
|
},
|
|
2340
3974
|
[commands, onSubmit, externalHistory]
|
|
2341
3975
|
);
|
|
2342
|
-
(0,
|
|
3976
|
+
(0, import_ink_renderer23.useInput)(
|
|
2343
3977
|
(_input, key) => {
|
|
2344
3978
|
if (key.ctrl && _input === "c" && isLoading) {
|
|
2345
3979
|
return;
|
|
@@ -2351,13 +3985,20 @@ function REPL({
|
|
|
2351
3985
|
exit();
|
|
2352
3986
|
}
|
|
2353
3987
|
}
|
|
3988
|
+
if (key.ctrl && _input === "f") {
|
|
3989
|
+
setSearchOpen(true);
|
|
3990
|
+
}
|
|
2354
3991
|
},
|
|
2355
|
-
|
|
3992
|
+
// Deactivate when search overlay is open so only SearchOverlay handles input.
|
|
3993
|
+
{ isActive: !searchOpen }
|
|
2356
3994
|
);
|
|
2357
3995
|
const resolvedSegments = statusSegments ?? buildDefaultSegments(model);
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
3996
|
+
const showWelcome = welcome && messages.length === 0 && !isLoading;
|
|
3997
|
+
const showPermission = !!permissionRequest;
|
|
3998
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_ink_renderer23.Box, { flexDirection: "column", flexGrow: 1, children: [
|
|
3999
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_ink_renderer23.Box, { flexDirection: "column", flexGrow: 1, children: [
|
|
4000
|
+
showWelcome && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_ink_renderer23.Box, { marginBottom: 1, children: welcome }),
|
|
4001
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
2361
4002
|
MessageList,
|
|
2362
4003
|
{
|
|
2363
4004
|
messages,
|
|
@@ -2365,10 +4006,29 @@ function REPL({
|
|
|
2365
4006
|
renderMessage
|
|
2366
4007
|
}
|
|
2367
4008
|
),
|
|
2368
|
-
isLoading && !streamingContent && /* @__PURE__ */ (0,
|
|
4009
|
+
isLoading && !streamingContent && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_ink_renderer23.Box, { marginTop: messages.length > 0 ? 1 : 0, children: spinner ?? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Spinner, {}) })
|
|
2369
4010
|
] }),
|
|
2370
|
-
/* @__PURE__ */ (0,
|
|
2371
|
-
|
|
4011
|
+
searchOpen && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
4012
|
+
SearchOverlay,
|
|
4013
|
+
{
|
|
4014
|
+
isOpen: searchOpen,
|
|
4015
|
+
onClose: () => setSearchOpen(false),
|
|
4016
|
+
onSearch: (q) => computeMatches(messageContents, q),
|
|
4017
|
+
onNavigate: () => {
|
|
4018
|
+
}
|
|
4019
|
+
}
|
|
4020
|
+
),
|
|
4021
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Divider, {}),
|
|
4022
|
+
showPermission ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
4023
|
+
PermissionRequest,
|
|
4024
|
+
{
|
|
4025
|
+
toolName: permissionRequest.toolName,
|
|
4026
|
+
description: permissionRequest.description,
|
|
4027
|
+
details: permissionRequest.details,
|
|
4028
|
+
preview: permissionRequest.preview,
|
|
4029
|
+
onDecision: permissionRequest.onDecision
|
|
4030
|
+
}
|
|
4031
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
2372
4032
|
PromptInput,
|
|
2373
4033
|
{
|
|
2374
4034
|
value: inputValue,
|
|
@@ -2376,44 +4036,1367 @@ function REPL({
|
|
|
2376
4036
|
onSubmit: handleSubmit,
|
|
2377
4037
|
prefix,
|
|
2378
4038
|
placeholder,
|
|
2379
|
-
disabled: isLoading,
|
|
4039
|
+
disabled: isLoading || searchOpen,
|
|
2380
4040
|
commands: promptCommands,
|
|
2381
4041
|
history
|
|
2382
4042
|
}
|
|
2383
4043
|
),
|
|
2384
|
-
/* @__PURE__ */ (0,
|
|
2385
|
-
resolvedSegments.length > 0 && /* @__PURE__ */ (0,
|
|
4044
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Divider, {}),
|
|
4045
|
+
resolvedSegments.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(StatusLine, { segments: resolvedSegments })
|
|
2386
4046
|
] });
|
|
2387
4047
|
}
|
|
2388
4048
|
function buildDefaultSegments(model) {
|
|
2389
4049
|
if (!model) return [];
|
|
2390
4050
|
return [{ content: model, color: "green" }];
|
|
2391
4051
|
}
|
|
4052
|
+
|
|
4053
|
+
// src/design-system/ThemedBox.tsx
|
|
4054
|
+
var import_ink_renderer24 = require("@claude-code-kit/ink-renderer");
|
|
4055
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
4056
|
+
function resolveColor(color2, theme) {
|
|
4057
|
+
if (!color2) return void 0;
|
|
4058
|
+
if (color2.startsWith("rgb(") || color2.startsWith("#") || color2.startsWith("ansi256(") || color2.startsWith("ansi:")) {
|
|
4059
|
+
return color2;
|
|
4060
|
+
}
|
|
4061
|
+
return theme[color2];
|
|
4062
|
+
}
|
|
4063
|
+
function ThemedBox({
|
|
4064
|
+
borderColor,
|
|
4065
|
+
borderTopColor,
|
|
4066
|
+
borderBottomColor,
|
|
4067
|
+
borderLeftColor,
|
|
4068
|
+
borderRightColor,
|
|
4069
|
+
backgroundColor,
|
|
4070
|
+
children,
|
|
4071
|
+
ref,
|
|
4072
|
+
...rest
|
|
4073
|
+
}) {
|
|
4074
|
+
const [themeName] = useTheme();
|
|
4075
|
+
const theme = getTheme(themeName);
|
|
4076
|
+
const resolvedBorderColor = resolveColor(borderColor, theme);
|
|
4077
|
+
const resolvedBorderTopColor = resolveColor(borderTopColor, theme);
|
|
4078
|
+
const resolvedBorderBottomColor = resolveColor(borderBottomColor, theme);
|
|
4079
|
+
const resolvedBorderLeftColor = resolveColor(borderLeftColor, theme);
|
|
4080
|
+
const resolvedBorderRightColor = resolveColor(borderRightColor, theme);
|
|
4081
|
+
const resolvedBackgroundColor = resolveColor(backgroundColor, theme);
|
|
4082
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4083
|
+
import_ink_renderer24.Box,
|
|
4084
|
+
{
|
|
4085
|
+
ref,
|
|
4086
|
+
borderColor: resolvedBorderColor,
|
|
4087
|
+
borderTopColor: resolvedBorderTopColor,
|
|
4088
|
+
borderBottomColor: resolvedBorderBottomColor,
|
|
4089
|
+
borderLeftColor: resolvedBorderLeftColor,
|
|
4090
|
+
borderRightColor: resolvedBorderRightColor,
|
|
4091
|
+
backgroundColor: resolvedBackgroundColor,
|
|
4092
|
+
...rest,
|
|
4093
|
+
children
|
|
4094
|
+
}
|
|
4095
|
+
);
|
|
4096
|
+
}
|
|
4097
|
+
var ThemedBox_default = ThemedBox;
|
|
4098
|
+
|
|
4099
|
+
// src/design-system/ThemedText.tsx
|
|
4100
|
+
var import_react20 = __toESM(require("react"));
|
|
4101
|
+
var import_ink_renderer25 = require("@claude-code-kit/ink-renderer");
|
|
4102
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
4103
|
+
var TextHoverColorContext = import_react20.default.createContext(void 0);
|
|
4104
|
+
function resolveColor2(color2, theme) {
|
|
4105
|
+
if (!color2) return void 0;
|
|
4106
|
+
if (color2.startsWith("rgb(") || color2.startsWith("#") || color2.startsWith("ansi256(") || color2.startsWith("ansi:")) {
|
|
4107
|
+
return color2;
|
|
4108
|
+
}
|
|
4109
|
+
return theme[color2];
|
|
4110
|
+
}
|
|
4111
|
+
function ThemedText({
|
|
4112
|
+
color: color2,
|
|
4113
|
+
backgroundColor,
|
|
4114
|
+
dimColor = false,
|
|
4115
|
+
bold = false,
|
|
4116
|
+
italic = false,
|
|
4117
|
+
underline = false,
|
|
4118
|
+
strikethrough = false,
|
|
4119
|
+
inverse = false,
|
|
4120
|
+
wrap = "wrap",
|
|
4121
|
+
children
|
|
4122
|
+
}) {
|
|
4123
|
+
const [themeName] = useTheme();
|
|
4124
|
+
const theme = getTheme(themeName);
|
|
4125
|
+
const hoverColor = (0, import_react20.useContext)(TextHoverColorContext);
|
|
4126
|
+
const resolvedColor = !color2 && hoverColor ? resolveColor2(hoverColor, theme) : dimColor ? theme.inactive : resolveColor2(color2, theme);
|
|
4127
|
+
const resolvedBackgroundColor = backgroundColor ? theme[backgroundColor] : void 0;
|
|
4128
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
4129
|
+
import_ink_renderer25.Text,
|
|
4130
|
+
{
|
|
4131
|
+
color: resolvedColor,
|
|
4132
|
+
backgroundColor: resolvedBackgroundColor,
|
|
4133
|
+
bold,
|
|
4134
|
+
italic,
|
|
4135
|
+
underline,
|
|
4136
|
+
strikethrough,
|
|
4137
|
+
inverse,
|
|
4138
|
+
wrap,
|
|
4139
|
+
children
|
|
4140
|
+
}
|
|
4141
|
+
);
|
|
4142
|
+
}
|
|
4143
|
+
|
|
4144
|
+
// src/design-system/Dialog.tsx
|
|
4145
|
+
var import_react22 = require("react");
|
|
4146
|
+
var import_ink_renderer29 = require("@claude-code-kit/ink-renderer");
|
|
4147
|
+
|
|
4148
|
+
// src/design-system/Byline.tsx
|
|
4149
|
+
var import_react21 = __toESM(require("react"));
|
|
4150
|
+
var import_ink_renderer26 = require("@claude-code-kit/ink-renderer");
|
|
4151
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
4152
|
+
function Byline({ children }) {
|
|
4153
|
+
const validChildren = import_react21.Children.toArray(children);
|
|
4154
|
+
if (validChildren.length === 0) {
|
|
4155
|
+
return null;
|
|
4156
|
+
}
|
|
4157
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_jsx_runtime21.Fragment, { children: validChildren.map((child, index) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
4158
|
+
import_react21.default.Fragment,
|
|
4159
|
+
{
|
|
4160
|
+
children: [
|
|
4161
|
+
index > 0 && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_ink_renderer26.Text, { dimColor: true, children: " \xB7 " }),
|
|
4162
|
+
child
|
|
4163
|
+
]
|
|
4164
|
+
},
|
|
4165
|
+
(0, import_react21.isValidElement)(child) ? child.key ?? index : index
|
|
4166
|
+
)) });
|
|
4167
|
+
}
|
|
4168
|
+
|
|
4169
|
+
// src/design-system/KeyboardShortcutHint.tsx
|
|
4170
|
+
var import_ink_renderer27 = require("@claude-code-kit/ink-renderer");
|
|
4171
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
4172
|
+
function KeyboardShortcutHint({
|
|
4173
|
+
shortcut,
|
|
4174
|
+
action,
|
|
4175
|
+
parens = false,
|
|
4176
|
+
bold = false
|
|
4177
|
+
}) {
|
|
4178
|
+
const shortcutText = bold ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_ink_renderer27.Text, { bold: true, children: shortcut }) : shortcut;
|
|
4179
|
+
if (parens) {
|
|
4180
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_ink_renderer27.Text, { children: [
|
|
4181
|
+
"(",
|
|
4182
|
+
shortcutText,
|
|
4183
|
+
" to ",
|
|
4184
|
+
action,
|
|
4185
|
+
")"
|
|
4186
|
+
] });
|
|
4187
|
+
}
|
|
4188
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_ink_renderer27.Text, { children: [
|
|
4189
|
+
shortcutText,
|
|
4190
|
+
" to ",
|
|
4191
|
+
action
|
|
4192
|
+
] });
|
|
4193
|
+
}
|
|
4194
|
+
|
|
4195
|
+
// src/design-system/Pane.tsx
|
|
4196
|
+
var import_ink_renderer28 = require("@claude-code-kit/ink-renderer");
|
|
4197
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
4198
|
+
function Pane({ children, color: color2 }) {
|
|
4199
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_ink_renderer28.Box, { flexDirection: "column", paddingTop: 1, children: [
|
|
4200
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Divider, { color: color2 }),
|
|
4201
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_ink_renderer28.Box, { flexDirection: "column", paddingX: 2, children })
|
|
4202
|
+
] });
|
|
4203
|
+
}
|
|
4204
|
+
|
|
4205
|
+
// src/design-system/Dialog.tsx
|
|
4206
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
4207
|
+
function Dialog({
|
|
4208
|
+
title,
|
|
4209
|
+
subtitle,
|
|
4210
|
+
children,
|
|
4211
|
+
onCancel,
|
|
4212
|
+
color: color2 = "permission",
|
|
4213
|
+
hideInputGuide,
|
|
4214
|
+
hideBorder
|
|
4215
|
+
}) {
|
|
4216
|
+
(0, import_ink_renderer29.useInput)(
|
|
4217
|
+
(0, import_react22.useCallback)(
|
|
4218
|
+
(_input, key) => {
|
|
4219
|
+
if (key.escape) {
|
|
4220
|
+
onCancel();
|
|
4221
|
+
}
|
|
4222
|
+
},
|
|
4223
|
+
[onCancel]
|
|
4224
|
+
)
|
|
4225
|
+
);
|
|
4226
|
+
const defaultInputGuide = /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(Byline, { children: [
|
|
4227
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(KeyboardShortcutHint, { shortcut: "Enter", action: "confirm" }),
|
|
4228
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(KeyboardShortcutHint, { shortcut: "Esc", action: "cancel" })
|
|
4229
|
+
] });
|
|
4230
|
+
const content = /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
|
|
4231
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_ink_renderer29.Box, { flexDirection: "column", gap: 1, children: [
|
|
4232
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_ink_renderer29.Box, { flexDirection: "column", children: [
|
|
4233
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_ink_renderer29.Text, { bold: true, color: color2, children: title }),
|
|
4234
|
+
subtitle && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_ink_renderer29.Text, { dimColor: true, children: subtitle })
|
|
4235
|
+
] }),
|
|
4236
|
+
children
|
|
4237
|
+
] }),
|
|
4238
|
+
!hideInputGuide && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_ink_renderer29.Box, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_ink_renderer29.Text, { dimColor: true, italic: true, children: defaultInputGuide }) })
|
|
4239
|
+
] });
|
|
4240
|
+
if (hideBorder) {
|
|
4241
|
+
return content;
|
|
4242
|
+
}
|
|
4243
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Pane, { color: color2, children: content });
|
|
4244
|
+
}
|
|
4245
|
+
|
|
4246
|
+
// src/design-system/FuzzyPicker.tsx
|
|
4247
|
+
var import_react23 = require("react");
|
|
4248
|
+
var import_ink_renderer32 = require("@claude-code-kit/ink-renderer");
|
|
4249
|
+
|
|
4250
|
+
// src/design-system/ListItem.tsx
|
|
4251
|
+
var import_figures2 = __toESM(require("figures"));
|
|
4252
|
+
var import_ink_renderer30 = require("@claude-code-kit/ink-renderer");
|
|
4253
|
+
var import_ink_renderer31 = require("@claude-code-kit/ink-renderer");
|
|
4254
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
4255
|
+
function ListItem({
|
|
4256
|
+
isFocused,
|
|
4257
|
+
isSelected = false,
|
|
4258
|
+
children,
|
|
4259
|
+
description,
|
|
4260
|
+
showScrollDown,
|
|
4261
|
+
showScrollUp,
|
|
4262
|
+
styled = true,
|
|
4263
|
+
disabled = false,
|
|
4264
|
+
declareCursor
|
|
4265
|
+
}) {
|
|
4266
|
+
function renderIndicator() {
|
|
4267
|
+
if (disabled) {
|
|
4268
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_ink_renderer31.Text, { children: " " });
|
|
4269
|
+
}
|
|
4270
|
+
if (isFocused) {
|
|
4271
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_ink_renderer31.Text, { color: "cyan", children: import_figures2.default.pointer });
|
|
4272
|
+
}
|
|
4273
|
+
if (showScrollDown) {
|
|
4274
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_ink_renderer31.Text, { dimColor: true, children: import_figures2.default.arrowDown });
|
|
4275
|
+
}
|
|
4276
|
+
if (showScrollUp) {
|
|
4277
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_ink_renderer31.Text, { dimColor: true, children: import_figures2.default.arrowUp });
|
|
4278
|
+
}
|
|
4279
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_ink_renderer31.Text, { children: " " });
|
|
4280
|
+
}
|
|
4281
|
+
function getTextColor() {
|
|
4282
|
+
if (disabled) {
|
|
4283
|
+
return void 0;
|
|
4284
|
+
}
|
|
4285
|
+
if (!styled) {
|
|
4286
|
+
return void 0;
|
|
4287
|
+
}
|
|
4288
|
+
if (isSelected) {
|
|
4289
|
+
return "green";
|
|
4290
|
+
}
|
|
4291
|
+
if (isFocused) {
|
|
4292
|
+
return "cyan";
|
|
4293
|
+
}
|
|
4294
|
+
return void 0;
|
|
4295
|
+
}
|
|
4296
|
+
const textColor = getTextColor();
|
|
4297
|
+
const cursorRef = (0, import_ink_renderer30.useDeclaredCursor)({
|
|
4298
|
+
line: 0,
|
|
4299
|
+
column: 0,
|
|
4300
|
+
active: isFocused && !disabled && declareCursor !== false
|
|
4301
|
+
});
|
|
4302
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_ink_renderer31.Box, { ref: cursorRef, flexDirection: "column", children: [
|
|
4303
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_ink_renderer31.Box, { flexDirection: "row", gap: 1, children: [
|
|
4304
|
+
renderIndicator(),
|
|
4305
|
+
styled ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_ink_renderer31.Text, { color: textColor, dimColor: disabled, children }) : children,
|
|
4306
|
+
isSelected && !disabled && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_ink_renderer31.Text, { color: "green", children: import_figures2.default.tick })
|
|
4307
|
+
] }),
|
|
4308
|
+
description && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_ink_renderer31.Box, { paddingLeft: 2, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_ink_renderer31.Text, { dimColor: true, children: description }) })
|
|
4309
|
+
] });
|
|
4310
|
+
}
|
|
4311
|
+
|
|
4312
|
+
// src/design-system/FuzzyPicker.tsx
|
|
4313
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
4314
|
+
var DEFAULT_VISIBLE = 8;
|
|
4315
|
+
var CHROME_ROWS = 10;
|
|
4316
|
+
var MIN_VISIBLE = 2;
|
|
4317
|
+
function FuzzyPicker({
|
|
4318
|
+
title,
|
|
4319
|
+
placeholder = "Type to search...",
|
|
4320
|
+
initialQuery,
|
|
4321
|
+
items,
|
|
4322
|
+
getKey,
|
|
4323
|
+
renderItem,
|
|
4324
|
+
renderPreview,
|
|
4325
|
+
previewPosition = "bottom",
|
|
4326
|
+
visibleCount: requestedVisible = DEFAULT_VISIBLE,
|
|
4327
|
+
direction = "down",
|
|
4328
|
+
onQueryChange,
|
|
4329
|
+
onSelect,
|
|
4330
|
+
onTab,
|
|
4331
|
+
onShiftTab,
|
|
4332
|
+
onFocus,
|
|
4333
|
+
onCancel,
|
|
4334
|
+
emptyMessage = "No results",
|
|
4335
|
+
matchLabel,
|
|
4336
|
+
selectAction = "select",
|
|
4337
|
+
extraHints
|
|
4338
|
+
}) {
|
|
4339
|
+
const terminalSize = (0, import_react23.useContext)(import_ink_renderer32.TerminalSizeContext);
|
|
4340
|
+
const rows = terminalSize?.rows ?? 24;
|
|
4341
|
+
const columns = terminalSize?.columns ?? 80;
|
|
4342
|
+
const [focusedIndex, setFocusedIndex] = (0, import_react23.useState)(0);
|
|
4343
|
+
const [query, setQuery] = (0, import_react23.useState)(initialQuery ?? "");
|
|
4344
|
+
const visibleCount = Math.max(
|
|
4345
|
+
MIN_VISIBLE,
|
|
4346
|
+
Math.min(requestedVisible, rows - CHROME_ROWS - (matchLabel ? 1 : 0))
|
|
4347
|
+
);
|
|
4348
|
+
const compact = columns < 120;
|
|
4349
|
+
const step = (0, import_react23.useCallback)(
|
|
4350
|
+
(delta) => {
|
|
4351
|
+
setFocusedIndex((i) => (0, import_ink_renderer32.clamp)(i + delta, 0, items.length - 1));
|
|
4352
|
+
},
|
|
4353
|
+
[items.length]
|
|
4354
|
+
);
|
|
4355
|
+
(0, import_ink_renderer32.useInput)(
|
|
4356
|
+
(0, import_react23.useCallback)(
|
|
4357
|
+
(input, key) => {
|
|
4358
|
+
if (key.escape) {
|
|
4359
|
+
onCancel();
|
|
4360
|
+
return;
|
|
4361
|
+
}
|
|
4362
|
+
if (key.upArrow || key.ctrl && input === "p") {
|
|
4363
|
+
step(direction === "up" ? 1 : -1);
|
|
4364
|
+
return;
|
|
4365
|
+
}
|
|
4366
|
+
if (key.downArrow || key.ctrl && input === "n") {
|
|
4367
|
+
step(direction === "up" ? -1 : 1);
|
|
4368
|
+
return;
|
|
4369
|
+
}
|
|
4370
|
+
if (key.return) {
|
|
4371
|
+
const selected = items[focusedIndex];
|
|
4372
|
+
if (selected) onSelect(selected);
|
|
4373
|
+
return;
|
|
4374
|
+
}
|
|
4375
|
+
if (key.tab) {
|
|
4376
|
+
const selected = items[focusedIndex];
|
|
4377
|
+
if (!selected) return;
|
|
4378
|
+
const tabAction = key.shift ? onShiftTab ?? onTab : onTab;
|
|
4379
|
+
if (tabAction) {
|
|
4380
|
+
tabAction.handler(selected);
|
|
4381
|
+
} else {
|
|
4382
|
+
onSelect(selected);
|
|
4383
|
+
}
|
|
4384
|
+
return;
|
|
4385
|
+
}
|
|
4386
|
+
if (key.backspace) {
|
|
4387
|
+
setQuery((q) => q.slice(0, -1));
|
|
4388
|
+
return;
|
|
4389
|
+
}
|
|
4390
|
+
if (input && !key.ctrl) {
|
|
4391
|
+
setQuery((q) => q + input);
|
|
4392
|
+
}
|
|
4393
|
+
},
|
|
4394
|
+
[onCancel, step, direction, items, focusedIndex, onSelect, onShiftTab, onTab]
|
|
4395
|
+
)
|
|
4396
|
+
);
|
|
4397
|
+
(0, import_react23.useEffect)(() => {
|
|
4398
|
+
onQueryChange(query);
|
|
4399
|
+
setFocusedIndex(0);
|
|
4400
|
+
}, [query]);
|
|
4401
|
+
(0, import_react23.useEffect)(() => {
|
|
4402
|
+
setFocusedIndex((i) => (0, import_ink_renderer32.clamp)(i, 0, items.length - 1));
|
|
4403
|
+
}, [items.length]);
|
|
4404
|
+
const focused = items[focusedIndex];
|
|
4405
|
+
(0, import_react23.useEffect)(() => {
|
|
4406
|
+
onFocus?.(focused);
|
|
4407
|
+
}, [focused]);
|
|
4408
|
+
const windowStart = (0, import_ink_renderer32.clamp)(
|
|
4409
|
+
focusedIndex - visibleCount + 1,
|
|
4410
|
+
0,
|
|
4411
|
+
items.length - visibleCount
|
|
4412
|
+
);
|
|
4413
|
+
const visible = items.slice(windowStart, windowStart + visibleCount);
|
|
4414
|
+
const emptyText = typeof emptyMessage === "function" ? emptyMessage(query) : emptyMessage;
|
|
4415
|
+
const searchInput = /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_ink_renderer32.Box, { borderStyle: "round", paddingX: 1, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_ink_renderer32.Text, { dimColor: !query, children: query || placeholder }) });
|
|
4416
|
+
const listBlock = /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
4417
|
+
List,
|
|
4418
|
+
{
|
|
4419
|
+
visible,
|
|
4420
|
+
windowStart,
|
|
4421
|
+
visibleCount,
|
|
4422
|
+
total: items.length,
|
|
4423
|
+
focusedIndex,
|
|
4424
|
+
direction,
|
|
4425
|
+
getKey,
|
|
4426
|
+
renderItem,
|
|
4427
|
+
emptyText
|
|
4428
|
+
}
|
|
4429
|
+
);
|
|
4430
|
+
const preview = renderPreview && focused ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_ink_renderer32.Box, { flexDirection: "column", flexGrow: 1, children: renderPreview(focused) }) : null;
|
|
4431
|
+
const listGroup = renderPreview && previewPosition === "right" ? /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
|
|
4432
|
+
import_ink_renderer32.Box,
|
|
4433
|
+
{
|
|
4434
|
+
flexDirection: "row",
|
|
4435
|
+
gap: 2,
|
|
4436
|
+
height: visibleCount + (matchLabel ? 1 : 0),
|
|
4437
|
+
children: [
|
|
4438
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_ink_renderer32.Box, { flexDirection: "column", flexShrink: 0, children: [
|
|
4439
|
+
listBlock,
|
|
4440
|
+
matchLabel && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_ink_renderer32.Text, { dimColor: true, children: matchLabel })
|
|
4441
|
+
] }),
|
|
4442
|
+
preview ?? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_ink_renderer32.Box, { flexGrow: 1 })
|
|
4443
|
+
]
|
|
4444
|
+
}
|
|
4445
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_ink_renderer32.Box, { flexDirection: "column", children: [
|
|
4446
|
+
listBlock,
|
|
4447
|
+
matchLabel && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_ink_renderer32.Text, { dimColor: true, children: matchLabel }),
|
|
4448
|
+
preview
|
|
4449
|
+
] });
|
|
4450
|
+
const inputAbove = direction !== "up";
|
|
4451
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Pane, { color: "permission", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_ink_renderer32.Box, { flexDirection: "column", gap: 1, children: [
|
|
4452
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_ink_renderer32.Text, { bold: true, color: "permission", children: title }),
|
|
4453
|
+
inputAbove && searchInput,
|
|
4454
|
+
listGroup,
|
|
4455
|
+
!inputAbove && searchInput,
|
|
4456
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_ink_renderer32.Text, { dimColor: true, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(Byline, { children: [
|
|
4457
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
4458
|
+
KeyboardShortcutHint,
|
|
4459
|
+
{
|
|
4460
|
+
shortcut: "up/dn",
|
|
4461
|
+
action: compact ? "nav" : "navigate"
|
|
4462
|
+
}
|
|
4463
|
+
),
|
|
4464
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(KeyboardShortcutHint, { shortcut: "Enter", action: selectAction }),
|
|
4465
|
+
onTab && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(KeyboardShortcutHint, { shortcut: "Tab", action: onTab.action }),
|
|
4466
|
+
onShiftTab && !compact && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
4467
|
+
KeyboardShortcutHint,
|
|
4468
|
+
{
|
|
4469
|
+
shortcut: "shift+tab",
|
|
4470
|
+
action: onShiftTab.action
|
|
4471
|
+
}
|
|
4472
|
+
),
|
|
4473
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(KeyboardShortcutHint, { shortcut: "Esc", action: "cancel" }),
|
|
4474
|
+
extraHints
|
|
4475
|
+
] }) })
|
|
4476
|
+
] }) });
|
|
4477
|
+
}
|
|
4478
|
+
function List({
|
|
4479
|
+
visible,
|
|
4480
|
+
windowStart,
|
|
4481
|
+
visibleCount,
|
|
4482
|
+
total,
|
|
4483
|
+
focusedIndex,
|
|
4484
|
+
direction,
|
|
4485
|
+
getKey,
|
|
4486
|
+
renderItem,
|
|
4487
|
+
emptyText
|
|
4488
|
+
}) {
|
|
4489
|
+
if (visible.length === 0) {
|
|
4490
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_ink_renderer32.Box, { height: visibleCount, flexShrink: 0, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_ink_renderer32.Text, { dimColor: true, children: emptyText }) });
|
|
4491
|
+
}
|
|
4492
|
+
const rows = visible.map((item, i) => {
|
|
4493
|
+
const actualIndex = windowStart + i;
|
|
4494
|
+
const isFocused = actualIndex === focusedIndex;
|
|
4495
|
+
const atLowEdge = i === 0 && windowStart > 0;
|
|
4496
|
+
const atHighEdge = i === visible.length - 1 && windowStart + visibleCount < total;
|
|
4497
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
4498
|
+
ListItem,
|
|
4499
|
+
{
|
|
4500
|
+
isFocused,
|
|
4501
|
+
showScrollUp: direction === "up" ? atHighEdge : atLowEdge,
|
|
4502
|
+
showScrollDown: direction === "up" ? atLowEdge : atHighEdge,
|
|
4503
|
+
styled: false,
|
|
4504
|
+
children: renderItem(item, isFocused)
|
|
4505
|
+
},
|
|
4506
|
+
getKey(item)
|
|
4507
|
+
);
|
|
4508
|
+
});
|
|
4509
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
4510
|
+
import_ink_renderer32.Box,
|
|
4511
|
+
{
|
|
4512
|
+
height: visibleCount,
|
|
4513
|
+
flexShrink: 0,
|
|
4514
|
+
flexDirection: direction === "up" ? "column-reverse" : "column",
|
|
4515
|
+
children: rows
|
|
4516
|
+
}
|
|
4517
|
+
);
|
|
4518
|
+
}
|
|
4519
|
+
|
|
4520
|
+
// src/design-system/LoadingState.tsx
|
|
4521
|
+
var import_ink_renderer33 = require("@claude-code-kit/ink-renderer");
|
|
4522
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
4523
|
+
function LoadingState({
|
|
4524
|
+
message,
|
|
4525
|
+
bold = false,
|
|
4526
|
+
dimColor = false,
|
|
4527
|
+
subtitle
|
|
4528
|
+
}) {
|
|
4529
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_ink_renderer33.Box, { flexDirection: "column", children: [
|
|
4530
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_ink_renderer33.Box, { flexDirection: "row", children: [
|
|
4531
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Spinner, {}),
|
|
4532
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_ink_renderer33.Text, { bold, dimColor, children: [
|
|
4533
|
+
" ",
|
|
4534
|
+
message
|
|
4535
|
+
] })
|
|
4536
|
+
] }),
|
|
4537
|
+
subtitle && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_ink_renderer33.Text, { dimColor: true, children: subtitle })
|
|
4538
|
+
] });
|
|
4539
|
+
}
|
|
4540
|
+
|
|
4541
|
+
// src/design-system/Ratchet.tsx
|
|
4542
|
+
var import_react24 = require("react");
|
|
4543
|
+
var import_ink_renderer34 = require("@claude-code-kit/ink-renderer");
|
|
4544
|
+
var import_ink_renderer35 = require("@claude-code-kit/ink-renderer");
|
|
4545
|
+
var import_ink_renderer36 = require("@claude-code-kit/ink-renderer");
|
|
4546
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
4547
|
+
function Ratchet({
|
|
4548
|
+
children,
|
|
4549
|
+
lock = "always"
|
|
4550
|
+
}) {
|
|
4551
|
+
const [viewportRef, { isVisible }] = (0, import_ink_renderer35.useTerminalViewport)();
|
|
4552
|
+
const terminalSize = (0, import_react24.useContext)(import_ink_renderer34.TerminalSizeContext);
|
|
4553
|
+
const rows = terminalSize?.rows ?? 24;
|
|
4554
|
+
const innerRef = (0, import_react24.useRef)(null);
|
|
4555
|
+
const maxHeight = (0, import_react24.useRef)(0);
|
|
4556
|
+
const [minHeight, setMinHeight] = (0, import_react24.useState)(0);
|
|
4557
|
+
const outerRef = (0, import_react24.useCallback)(
|
|
4558
|
+
(el) => {
|
|
4559
|
+
viewportRef(el);
|
|
4560
|
+
},
|
|
4561
|
+
[viewportRef]
|
|
4562
|
+
);
|
|
4563
|
+
const engaged = lock === "always" || !isVisible;
|
|
4564
|
+
(0, import_react24.useLayoutEffect)(() => {
|
|
4565
|
+
if (!innerRef.current) {
|
|
4566
|
+
return;
|
|
4567
|
+
}
|
|
4568
|
+
const { height } = (0, import_ink_renderer36.measureElement)(innerRef.current);
|
|
4569
|
+
if (height > maxHeight.current) {
|
|
4570
|
+
maxHeight.current = Math.min(height, rows);
|
|
4571
|
+
setMinHeight(maxHeight.current);
|
|
4572
|
+
}
|
|
4573
|
+
});
|
|
4574
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_ink_renderer36.Box, { minHeight: engaged ? minHeight : void 0, ref: outerRef, children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_ink_renderer36.Box, { ref: innerRef, flexDirection: "column", children }) });
|
|
4575
|
+
}
|
|
4576
|
+
|
|
4577
|
+
// src/design-system/Tabs.tsx
|
|
4578
|
+
var import_react25 = require("react");
|
|
4579
|
+
var import_ink_renderer37 = require("@claude-code-kit/ink-renderer");
|
|
4580
|
+
var import_ink_renderer38 = require("@claude-code-kit/ink-renderer");
|
|
4581
|
+
var import_ink_renderer39 = require("@claude-code-kit/ink-renderer");
|
|
4582
|
+
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
4583
|
+
var TabsContext = (0, import_react25.createContext)({
|
|
4584
|
+
selectedTab: void 0,
|
|
4585
|
+
width: void 0
|
|
4586
|
+
});
|
|
4587
|
+
function Tabs({
|
|
4588
|
+
title,
|
|
4589
|
+
color: color2,
|
|
4590
|
+
defaultTab,
|
|
4591
|
+
children,
|
|
4592
|
+
hidden,
|
|
4593
|
+
useFullWidth,
|
|
4594
|
+
selectedTab: controlledSelectedTab,
|
|
4595
|
+
onTabChange,
|
|
4596
|
+
banner,
|
|
4597
|
+
disableNavigation
|
|
4598
|
+
}) {
|
|
4599
|
+
const terminalSize = (0, import_react25.useContext)(import_ink_renderer37.TerminalSizeContext);
|
|
4600
|
+
const terminalWidth = terminalSize?.columns ?? 80;
|
|
4601
|
+
const tabs = children.map((child) => [
|
|
4602
|
+
child.props.id ?? child.props.title,
|
|
4603
|
+
child.props.title
|
|
4604
|
+
]);
|
|
4605
|
+
const defaultTabIndex = defaultTab ? tabs.findIndex((tab) => defaultTab === tab[0]) : 0;
|
|
4606
|
+
const isControlled = controlledSelectedTab !== void 0;
|
|
4607
|
+
const [internalSelectedTab, setInternalSelectedTab] = (0, import_react25.useState)(
|
|
4608
|
+
defaultTabIndex !== -1 ? defaultTabIndex : 0
|
|
4609
|
+
);
|
|
4610
|
+
const controlledTabIndex = isControlled ? tabs.findIndex((tab) => tab[0] === controlledSelectedTab) : -1;
|
|
4611
|
+
const selectedTabIndex = isControlled ? controlledTabIndex !== -1 ? controlledTabIndex : 0 : internalSelectedTab;
|
|
4612
|
+
const handleTabChange = (0, import_react25.useCallback)(
|
|
4613
|
+
(offset) => {
|
|
4614
|
+
const newIndex = (selectedTabIndex + tabs.length + offset) % tabs.length;
|
|
4615
|
+
const newTabId = tabs[newIndex]?.[0];
|
|
4616
|
+
if (isControlled && onTabChange && newTabId) {
|
|
4617
|
+
onTabChange(newTabId);
|
|
4618
|
+
} else {
|
|
4619
|
+
setInternalSelectedTab(newIndex);
|
|
4620
|
+
}
|
|
4621
|
+
},
|
|
4622
|
+
[selectedTabIndex, tabs, isControlled, onTabChange]
|
|
4623
|
+
);
|
|
4624
|
+
(0, import_ink_renderer39.useInput)(
|
|
4625
|
+
(0, import_react25.useCallback)(
|
|
4626
|
+
(_input, key) => {
|
|
4627
|
+
if (hidden || disableNavigation) return;
|
|
4628
|
+
if (key.tab && !key.shift) {
|
|
4629
|
+
handleTabChange(1);
|
|
4630
|
+
} else if (key.tab && key.shift) {
|
|
4631
|
+
handleTabChange(-1);
|
|
4632
|
+
} else if (key.leftArrow) {
|
|
4633
|
+
handleTabChange(-1);
|
|
4634
|
+
} else if (key.rightArrow) {
|
|
4635
|
+
handleTabChange(1);
|
|
4636
|
+
}
|
|
4637
|
+
},
|
|
4638
|
+
[hidden, disableNavigation, handleTabChange]
|
|
4639
|
+
)
|
|
4640
|
+
);
|
|
4641
|
+
const titleWidth = title ? (0, import_ink_renderer38.stringWidth)(title) + 1 : 0;
|
|
4642
|
+
const tabsWidth = tabs.reduce(
|
|
4643
|
+
(sum, [, tabTitle]) => sum + (tabTitle ? (0, import_ink_renderer38.stringWidth)(tabTitle) : 0) + 3,
|
|
4644
|
+
0
|
|
4645
|
+
);
|
|
4646
|
+
const usedWidth = titleWidth + tabsWidth;
|
|
4647
|
+
const spacerWidth = useFullWidth ? Math.max(0, terminalWidth - usedWidth) : 0;
|
|
4648
|
+
const contentWidth = useFullWidth ? terminalWidth : void 0;
|
|
4649
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
4650
|
+
TabsContext.Provider,
|
|
4651
|
+
{
|
|
4652
|
+
value: {
|
|
4653
|
+
selectedTab: tabs[selectedTabIndex]?.[0],
|
|
4654
|
+
width: contentWidth
|
|
4655
|
+
},
|
|
4656
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_ink_renderer39.Box, { flexDirection: "column", children: [
|
|
4657
|
+
!hidden && /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_ink_renderer39.Box, { flexDirection: "row", gap: 1, children: [
|
|
4658
|
+
title !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_ink_renderer39.Text, { bold: true, color: color2, children: title }),
|
|
4659
|
+
tabs.map(([id, tabTitle], i) => {
|
|
4660
|
+
const isCurrent = selectedTabIndex === i;
|
|
4661
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
|
|
4662
|
+
import_ink_renderer39.Text,
|
|
4663
|
+
{
|
|
4664
|
+
inverse: isCurrent,
|
|
4665
|
+
bold: isCurrent,
|
|
4666
|
+
children: [
|
|
4667
|
+
" ",
|
|
4668
|
+
tabTitle,
|
|
4669
|
+
" "
|
|
4670
|
+
]
|
|
4671
|
+
},
|
|
4672
|
+
id
|
|
4673
|
+
);
|
|
4674
|
+
}),
|
|
4675
|
+
spacerWidth > 0 && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_ink_renderer39.Text, { children: " ".repeat(spacerWidth) })
|
|
4676
|
+
] }),
|
|
4677
|
+
banner,
|
|
4678
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
4679
|
+
import_ink_renderer39.Box,
|
|
4680
|
+
{
|
|
4681
|
+
width: contentWidth,
|
|
4682
|
+
marginTop: hidden ? 0 : 1,
|
|
4683
|
+
children
|
|
4684
|
+
}
|
|
4685
|
+
)
|
|
4686
|
+
] })
|
|
4687
|
+
}
|
|
4688
|
+
);
|
|
4689
|
+
}
|
|
4690
|
+
function Tab({ title, id, children }) {
|
|
4691
|
+
const { selectedTab, width } = (0, import_react25.useContext)(TabsContext);
|
|
4692
|
+
if (selectedTab !== (id ?? title)) {
|
|
4693
|
+
return null;
|
|
4694
|
+
}
|
|
4695
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_ink_renderer39.Box, { width, children });
|
|
4696
|
+
}
|
|
4697
|
+
function useTabsWidth() {
|
|
4698
|
+
const { width } = (0, import_react25.useContext)(TabsContext);
|
|
4699
|
+
return width;
|
|
4700
|
+
}
|
|
4701
|
+
|
|
4702
|
+
// src/useVirtualScroll.ts
|
|
4703
|
+
var import_react26 = __toESM(require("react"));
|
|
4704
|
+
var import_ink_renderer40 = require("@claude-code-kit/ink-renderer");
|
|
4705
|
+
function clamp2(value, min, max) {
|
|
4706
|
+
return Math.max(min, Math.min(max, value));
|
|
4707
|
+
}
|
|
4708
|
+
function useVirtualScroll(options) {
|
|
4709
|
+
const {
|
|
4710
|
+
itemCount,
|
|
4711
|
+
estimatedItemHeight = 3,
|
|
4712
|
+
overscan = 20,
|
|
4713
|
+
viewportHeight
|
|
4714
|
+
} = options;
|
|
4715
|
+
const totalHeight = itemCount * estimatedItemHeight;
|
|
4716
|
+
const maxOffset = Math.max(0, totalHeight - viewportHeight);
|
|
4717
|
+
const [scrollOffset, setScrollOffset] = (0, import_react26.useState)(0);
|
|
4718
|
+
const clampedOffset = clamp2(scrollOffset, 0, maxOffset);
|
|
4719
|
+
const rawStart = Math.floor(clampedOffset / estimatedItemHeight);
|
|
4720
|
+
const rawEnd = Math.ceil((clampedOffset + viewportHeight) / estimatedItemHeight);
|
|
4721
|
+
const startIndex = clamp2(rawStart - overscan, 0, itemCount);
|
|
4722
|
+
const endIndex = clamp2(rawEnd + overscan, 0, itemCount);
|
|
4723
|
+
const visibleItems = endIndex - startIndex;
|
|
4724
|
+
const scrollTo = (0, import_react26.useCallback)(
|
|
4725
|
+
(index) => {
|
|
4726
|
+
const targetOffset = clamp2(index * estimatedItemHeight, 0, maxOffset);
|
|
4727
|
+
setScrollOffset(targetOffset);
|
|
4728
|
+
},
|
|
4729
|
+
[estimatedItemHeight, maxOffset]
|
|
4730
|
+
);
|
|
4731
|
+
const scrollToEnd = (0, import_react26.useCallback)(() => {
|
|
4732
|
+
setScrollOffset(maxOffset);
|
|
4733
|
+
}, [maxOffset]);
|
|
4734
|
+
const onScroll = (0, import_react26.useCallback)(
|
|
4735
|
+
(delta) => {
|
|
4736
|
+
setScrollOffset((prev) => clamp2(prev + delta * estimatedItemHeight, 0, maxOffset));
|
|
4737
|
+
},
|
|
4738
|
+
[estimatedItemHeight, maxOffset]
|
|
4739
|
+
);
|
|
4740
|
+
const isAtTop = clampedOffset <= 0;
|
|
4741
|
+
const isAtEnd = clampedOffset >= maxOffset;
|
|
4742
|
+
return (0, import_react26.useMemo)(
|
|
4743
|
+
() => ({
|
|
4744
|
+
startIndex,
|
|
4745
|
+
endIndex,
|
|
4746
|
+
visibleItems,
|
|
4747
|
+
totalHeight,
|
|
4748
|
+
scrollOffset: clampedOffset,
|
|
4749
|
+
scrollTo,
|
|
4750
|
+
scrollToEnd,
|
|
4751
|
+
onScroll,
|
|
4752
|
+
isAtTop,
|
|
4753
|
+
isAtEnd
|
|
4754
|
+
}),
|
|
4755
|
+
[
|
|
4756
|
+
startIndex,
|
|
4757
|
+
endIndex,
|
|
4758
|
+
visibleItems,
|
|
4759
|
+
totalHeight,
|
|
4760
|
+
clampedOffset,
|
|
4761
|
+
scrollTo,
|
|
4762
|
+
scrollToEnd,
|
|
4763
|
+
onScroll,
|
|
4764
|
+
isAtTop,
|
|
4765
|
+
isAtEnd
|
|
4766
|
+
]
|
|
4767
|
+
);
|
|
4768
|
+
}
|
|
4769
|
+
function VirtualList(props) {
|
|
4770
|
+
const { items, renderItem, viewportHeight, estimatedItemHeight = 3, overscan = 20 } = props;
|
|
4771
|
+
const { startIndex, endIndex, totalHeight } = useVirtualScroll({
|
|
4772
|
+
itemCount: items.length,
|
|
4773
|
+
estimatedItemHeight,
|
|
4774
|
+
overscan,
|
|
4775
|
+
viewportHeight
|
|
4776
|
+
});
|
|
4777
|
+
const topPad = startIndex * estimatedItemHeight;
|
|
4778
|
+
const renderedHeight = (endIndex - startIndex) * estimatedItemHeight;
|
|
4779
|
+
const bottomPad = Math.max(0, totalHeight - topPad - renderedHeight);
|
|
4780
|
+
const visibleSlice = [];
|
|
4781
|
+
for (let i = startIndex; i < endIndex && i < items.length; i++) {
|
|
4782
|
+
visibleSlice.push(renderItem(items[i], i));
|
|
4783
|
+
}
|
|
4784
|
+
return import_react26.default.createElement(
|
|
4785
|
+
import_ink_renderer40.Box,
|
|
4786
|
+
{
|
|
4787
|
+
flexDirection: "column",
|
|
4788
|
+
height: viewportHeight,
|
|
4789
|
+
overflow: "hidden"
|
|
4790
|
+
},
|
|
4791
|
+
topPad > 0 ? import_react26.default.createElement(import_ink_renderer40.Box, { height: topPad, key: "__virtual-top" }) : null,
|
|
4792
|
+
...visibleSlice,
|
|
4793
|
+
bottomPad > 0 ? import_react26.default.createElement(import_ink_renderer40.Box, { height: bottomPad, key: "__virtual-bottom" }) : null
|
|
4794
|
+
);
|
|
4795
|
+
}
|
|
4796
|
+
|
|
4797
|
+
// src/WelcomeScreen.tsx
|
|
4798
|
+
var import_ink_renderer41 = require("@claude-code-kit/ink-renderer");
|
|
4799
|
+
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
4800
|
+
var DEFAULT_COLOR2 = "#DA7756";
|
|
4801
|
+
function ClawdLogo({ color: color2 = DEFAULT_COLOR2 }) {
|
|
4802
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_ink_renderer41.Box, { flexDirection: "column", children: [
|
|
4803
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_ink_renderer41.Text, { color: color2, children: " \u2590\u259B\u2588\u2588\u2588\u259C\u258C" }),
|
|
4804
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_ink_renderer41.Text, { color: color2, children: "\u259D\u259C\u2588\u2588\u2588\u2588\u2588\u259B\u2598" }),
|
|
4805
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_ink_renderer41.Text, { color: color2, children: " \u2598\u2598 \u259D\u259D " })
|
|
4806
|
+
] });
|
|
4807
|
+
}
|
|
4808
|
+
function WelcomeScreen({
|
|
4809
|
+
appName,
|
|
4810
|
+
subtitle,
|
|
4811
|
+
version,
|
|
4812
|
+
tips,
|
|
4813
|
+
logo,
|
|
4814
|
+
model,
|
|
4815
|
+
color: color2 = DEFAULT_COLOR2
|
|
4816
|
+
}) {
|
|
4817
|
+
const logoNode = logo ?? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ClawdLogo, { color: color2 });
|
|
4818
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_ink_renderer41.Box, { flexDirection: "column", gap: 1, marginTop: 1, marginLeft: 1, children: [
|
|
4819
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_ink_renderer41.Box, { flexDirection: "row", gap: 2, alignItems: "flex-start", children: [
|
|
4820
|
+
logoNode,
|
|
4821
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_ink_renderer41.Box, { flexDirection: "column", justifyContent: "center", children: [
|
|
4822
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_ink_renderer41.Box, { flexDirection: "row", gap: 1, children: [
|
|
4823
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_ink_renderer41.Text, { bold: true, color: color2, children: appName }),
|
|
4824
|
+
version && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_ink_renderer41.Text, { dimColor: true, children: `v${version}` })
|
|
4825
|
+
] }),
|
|
4826
|
+
subtitle && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_ink_renderer41.Text, { dimColor: true, children: subtitle }),
|
|
4827
|
+
model && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_ink_renderer41.Text, { dimColor: true, children: model })
|
|
4828
|
+
] })
|
|
4829
|
+
] }),
|
|
4830
|
+
tips && tips.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_ink_renderer41.Box, { flexDirection: "column", gap: 0, children: [
|
|
4831
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_ink_renderer41.Text, { dimColor: true, children: "Tips:" }),
|
|
4832
|
+
tips.map((tip, i) => /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_ink_renderer41.Text, { dimColor: true, children: ` - ${tip}` }, i))
|
|
4833
|
+
] })
|
|
4834
|
+
] });
|
|
4835
|
+
}
|
|
4836
|
+
|
|
4837
|
+
// src/agent/useAgent.ts
|
|
4838
|
+
var import_react27 = require("react");
|
|
4839
|
+
var _msgId = 0;
|
|
4840
|
+
function nextId() {
|
|
4841
|
+
return `msg-${++_msgId}-${Date.now()}`;
|
|
4842
|
+
}
|
|
4843
|
+
function toolCallToContent(tc) {
|
|
4844
|
+
return {
|
|
4845
|
+
type: "tool_use",
|
|
4846
|
+
toolName: tc.name,
|
|
4847
|
+
input: JSON.stringify(tc.input, null, 2),
|
|
4848
|
+
status: "running"
|
|
4849
|
+
};
|
|
4850
|
+
}
|
|
4851
|
+
function useAgent({ agent, onError }) {
|
|
4852
|
+
const [messages, setMessages] = (0, import_react27.useState)([]);
|
|
4853
|
+
const [isLoading, setIsLoading] = (0, import_react27.useState)(false);
|
|
4854
|
+
const [streamingContent, setStreamingContent] = (0, import_react27.useState)(null);
|
|
4855
|
+
const [permissionRequest, setPermissionRequest] = (0, import_react27.useState)(null);
|
|
4856
|
+
const isRunningRef = (0, import_react27.useRef)(false);
|
|
4857
|
+
const toolMsgMap = (0, import_react27.useRef)(/* @__PURE__ */ new Map());
|
|
4858
|
+
(0, import_react27.useEffect)(() => {
|
|
4859
|
+
agent.setPermissionHandler(async (request) => {
|
|
4860
|
+
return new Promise((resolve) => {
|
|
4861
|
+
setPermissionRequest({
|
|
4862
|
+
toolName: request.tool,
|
|
4863
|
+
description: `Tool "${request.tool}" wants to execute`,
|
|
4864
|
+
details: JSON.stringify(request.input, null, 2),
|
|
4865
|
+
resolve: (decision) => {
|
|
4866
|
+
setPermissionRequest(null);
|
|
4867
|
+
resolve({ decision });
|
|
4868
|
+
}
|
|
4869
|
+
});
|
|
4870
|
+
});
|
|
4871
|
+
});
|
|
4872
|
+
}, [agent]);
|
|
4873
|
+
const cancel = (0, import_react27.useCallback)(() => {
|
|
4874
|
+
agent.abort();
|
|
4875
|
+
isRunningRef.current = false;
|
|
4876
|
+
setIsLoading(false);
|
|
4877
|
+
setStreamingContent(null);
|
|
4878
|
+
setPermissionRequest(null);
|
|
4879
|
+
}, [agent]);
|
|
4880
|
+
const clearMessages = (0, import_react27.useCallback)(() => {
|
|
4881
|
+
agent.clearMessages();
|
|
4882
|
+
setMessages([]);
|
|
4883
|
+
setStreamingContent(null);
|
|
4884
|
+
setPermissionRequest(null);
|
|
4885
|
+
}, [agent]);
|
|
4886
|
+
const submit = (0, import_react27.useCallback)(
|
|
4887
|
+
(input) => {
|
|
4888
|
+
if (isRunningRef.current) return;
|
|
4889
|
+
const trimmed = input.trim();
|
|
4890
|
+
if (!trimmed) return;
|
|
4891
|
+
const userMsg = {
|
|
4892
|
+
id: nextId(),
|
|
4893
|
+
role: "user",
|
|
4894
|
+
content: trimmed,
|
|
4895
|
+
timestamp: Date.now()
|
|
4896
|
+
};
|
|
4897
|
+
setMessages((prev) => [...prev, userMsg]);
|
|
4898
|
+
isRunningRef.current = true;
|
|
4899
|
+
setIsLoading(true);
|
|
4900
|
+
setStreamingContent(null);
|
|
4901
|
+
(async () => {
|
|
4902
|
+
let accumulated = "";
|
|
4903
|
+
try {
|
|
4904
|
+
for await (const event of agent.run(trimmed)) {
|
|
4905
|
+
switch (event.type) {
|
|
4906
|
+
case "text": {
|
|
4907
|
+
accumulated += event.text;
|
|
4908
|
+
setStreamingContent(accumulated);
|
|
4909
|
+
break;
|
|
4910
|
+
}
|
|
4911
|
+
case "tool_call": {
|
|
4912
|
+
const msgId = nextId();
|
|
4913
|
+
toolMsgMap.current.set(event.toolCall.id, msgId);
|
|
4914
|
+
const toolMsg = {
|
|
4915
|
+
id: msgId,
|
|
4916
|
+
role: "assistant",
|
|
4917
|
+
content: [toolCallToContent(event.toolCall)],
|
|
4918
|
+
timestamp: Date.now()
|
|
4919
|
+
};
|
|
4920
|
+
setMessages((prev) => [...prev, toolMsg]);
|
|
4921
|
+
break;
|
|
4922
|
+
}
|
|
4923
|
+
case "tool_result": {
|
|
4924
|
+
const targetId = toolMsgMap.current.get(event.toolCallId);
|
|
4925
|
+
if (targetId) {
|
|
4926
|
+
setMessages(
|
|
4927
|
+
(prev) => prev.map((m) => {
|
|
4928
|
+
if (m.id !== targetId) return m;
|
|
4929
|
+
const contents = Array.isArray(m.content) ? m.content : [];
|
|
4930
|
+
return {
|
|
4931
|
+
...m,
|
|
4932
|
+
content: contents.map((c) => {
|
|
4933
|
+
if (c.type !== "tool_use") return c;
|
|
4934
|
+
return {
|
|
4935
|
+
...c,
|
|
4936
|
+
result: event.result.content,
|
|
4937
|
+
status: event.result.isError ? "error" : "success"
|
|
4938
|
+
};
|
|
4939
|
+
})
|
|
4940
|
+
};
|
|
4941
|
+
})
|
|
4942
|
+
);
|
|
4943
|
+
toolMsgMap.current.delete(event.toolCallId);
|
|
4944
|
+
}
|
|
4945
|
+
break;
|
|
4946
|
+
}
|
|
4947
|
+
case "error": {
|
|
4948
|
+
onError?.(event.error);
|
|
4949
|
+
break;
|
|
4950
|
+
}
|
|
4951
|
+
case "done": {
|
|
4952
|
+
if (accumulated.length > 0) {
|
|
4953
|
+
const assistantMsg = {
|
|
4954
|
+
id: nextId(),
|
|
4955
|
+
role: "assistant",
|
|
4956
|
+
content: accumulated,
|
|
4957
|
+
timestamp: Date.now()
|
|
4958
|
+
};
|
|
4959
|
+
setMessages((prev) => [...prev, assistantMsg]);
|
|
4960
|
+
}
|
|
4961
|
+
accumulated = "";
|
|
4962
|
+
setStreamingContent(null);
|
|
4963
|
+
break;
|
|
4964
|
+
}
|
|
4965
|
+
}
|
|
4966
|
+
}
|
|
4967
|
+
} catch (err) {
|
|
4968
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
4969
|
+
onError?.(error);
|
|
4970
|
+
} finally {
|
|
4971
|
+
isRunningRef.current = false;
|
|
4972
|
+
setIsLoading(false);
|
|
4973
|
+
setStreamingContent(null);
|
|
4974
|
+
}
|
|
4975
|
+
})();
|
|
4976
|
+
},
|
|
4977
|
+
[agent, onError]
|
|
4978
|
+
);
|
|
4979
|
+
return {
|
|
4980
|
+
messages,
|
|
4981
|
+
isLoading,
|
|
4982
|
+
streamingContent,
|
|
4983
|
+
permissionRequest,
|
|
4984
|
+
submit,
|
|
4985
|
+
cancel,
|
|
4986
|
+
clearMessages
|
|
4987
|
+
};
|
|
4988
|
+
}
|
|
4989
|
+
|
|
4990
|
+
// src/agent/AgentProvider.tsx
|
|
4991
|
+
var import_react28 = require("react");
|
|
4992
|
+
var import_jsx_runtime31 = require("react/jsx-runtime");
|
|
4993
|
+
var AgentContext = (0, import_react28.createContext)(null);
|
|
4994
|
+
function AgentProvider({
|
|
4995
|
+
agent,
|
|
4996
|
+
model = "unknown",
|
|
4997
|
+
onError,
|
|
4998
|
+
children
|
|
4999
|
+
}) {
|
|
5000
|
+
const agentState = useAgent({ agent, onError });
|
|
5001
|
+
const value = (0, import_react28.useMemo)(
|
|
5002
|
+
() => ({
|
|
5003
|
+
...agentState,
|
|
5004
|
+
agent,
|
|
5005
|
+
model
|
|
5006
|
+
}),
|
|
5007
|
+
[agentState, agent, model]
|
|
5008
|
+
);
|
|
5009
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(AgentContext.Provider, { value, children });
|
|
5010
|
+
}
|
|
5011
|
+
function useAgentContext() {
|
|
5012
|
+
const ctx = (0, import_react28.useContext)(AgentContext);
|
|
5013
|
+
if (!ctx) {
|
|
5014
|
+
throw new Error(
|
|
5015
|
+
"useAgentContext must be used within an <AgentProvider>. Wrap your component tree with <AgentProvider agent={agent}>."
|
|
5016
|
+
);
|
|
5017
|
+
}
|
|
5018
|
+
return ctx;
|
|
5019
|
+
}
|
|
5020
|
+
|
|
5021
|
+
// src/agent/AgentREPL.tsx
|
|
5022
|
+
var import_react29 = require("react");
|
|
5023
|
+
var import_jsx_runtime32 = require("react/jsx-runtime");
|
|
5024
|
+
function AgentREPLInner({
|
|
5025
|
+
commands,
|
|
5026
|
+
welcome,
|
|
5027
|
+
placeholder,
|
|
5028
|
+
onExit
|
|
5029
|
+
}) {
|
|
5030
|
+
const {
|
|
5031
|
+
messages,
|
|
5032
|
+
isLoading,
|
|
5033
|
+
streamingContent,
|
|
5034
|
+
permissionRequest,
|
|
5035
|
+
submit,
|
|
5036
|
+
model,
|
|
5037
|
+
clearMessages
|
|
5038
|
+
} = useAgentContext();
|
|
5039
|
+
const permissionState = (0, import_react29.useMemo)(() => {
|
|
5040
|
+
if (!permissionRequest) return void 0;
|
|
5041
|
+
return {
|
|
5042
|
+
toolName: permissionRequest.toolName,
|
|
5043
|
+
description: permissionRequest.description,
|
|
5044
|
+
details: permissionRequest.details,
|
|
5045
|
+
onDecision: (action) => {
|
|
5046
|
+
permissionRequest.resolve(action === "deny" ? "deny" : "allow");
|
|
5047
|
+
}
|
|
5048
|
+
};
|
|
5049
|
+
}, [permissionRequest]);
|
|
5050
|
+
const allCommands = (0, import_react29.useMemo)(() => {
|
|
5051
|
+
const builtIn = [
|
|
5052
|
+
{
|
|
5053
|
+
name: "clear",
|
|
5054
|
+
description: "Clear conversation history",
|
|
5055
|
+
onExecute: () => clearMessages()
|
|
5056
|
+
}
|
|
5057
|
+
];
|
|
5058
|
+
return [...builtIn, ...commands ?? []];
|
|
5059
|
+
}, [commands, clearMessages]);
|
|
5060
|
+
const handleSubmit = (0, import_react29.useCallback)(
|
|
5061
|
+
async (input) => {
|
|
5062
|
+
submit(input);
|
|
5063
|
+
},
|
|
5064
|
+
[submit]
|
|
5065
|
+
);
|
|
5066
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
5067
|
+
REPL,
|
|
5068
|
+
{
|
|
5069
|
+
onSubmit: handleSubmit,
|
|
5070
|
+
onExit,
|
|
5071
|
+
messages,
|
|
5072
|
+
isLoading,
|
|
5073
|
+
streamingContent,
|
|
5074
|
+
permissionRequest: permissionState,
|
|
5075
|
+
commands: allCommands,
|
|
5076
|
+
model,
|
|
5077
|
+
welcome,
|
|
5078
|
+
placeholder
|
|
5079
|
+
}
|
|
5080
|
+
);
|
|
5081
|
+
}
|
|
5082
|
+
function AgentREPL({
|
|
5083
|
+
agent,
|
|
5084
|
+
model,
|
|
5085
|
+
commands,
|
|
5086
|
+
welcome,
|
|
5087
|
+
placeholder,
|
|
5088
|
+
onError,
|
|
5089
|
+
onExit
|
|
5090
|
+
}) {
|
|
5091
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(AgentProvider, { agent, model, onError, children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
5092
|
+
AgentREPLInner,
|
|
5093
|
+
{
|
|
5094
|
+
commands,
|
|
5095
|
+
welcome,
|
|
5096
|
+
placeholder,
|
|
5097
|
+
onExit
|
|
5098
|
+
}
|
|
5099
|
+
) });
|
|
5100
|
+
}
|
|
5101
|
+
|
|
5102
|
+
// src/AuthFlow.tsx
|
|
5103
|
+
var import_react30 = require("react");
|
|
5104
|
+
var import_ink_renderer42 = require("@claude-code-kit/ink-renderer");
|
|
5105
|
+
var import_jsx_runtime33 = require("react/jsx-runtime");
|
|
5106
|
+
function CredentialInput({
|
|
5107
|
+
label,
|
|
5108
|
+
masked,
|
|
5109
|
+
onSubmit,
|
|
5110
|
+
onCancel
|
|
5111
|
+
}) {
|
|
5112
|
+
const [value, setValue] = (0, import_react30.useState)("");
|
|
5113
|
+
const [cursor, setCursor] = (0, import_react30.useState)(0);
|
|
5114
|
+
(0, import_ink_renderer42.useInput)((input, key) => {
|
|
5115
|
+
if (key.escape) {
|
|
5116
|
+
onCancel?.();
|
|
5117
|
+
return;
|
|
5118
|
+
}
|
|
5119
|
+
if (key.return) {
|
|
5120
|
+
if (value.length > 0) onSubmit(value);
|
|
5121
|
+
return;
|
|
5122
|
+
}
|
|
5123
|
+
if (key.backspace) {
|
|
5124
|
+
if (cursor > 0) {
|
|
5125
|
+
setValue((v) => v.slice(0, cursor - 1) + v.slice(cursor));
|
|
5126
|
+
setCursor((c) => c - 1);
|
|
5127
|
+
}
|
|
5128
|
+
return;
|
|
5129
|
+
}
|
|
5130
|
+
if (key.leftArrow) {
|
|
5131
|
+
setCursor((c) => Math.max(0, c - 1));
|
|
5132
|
+
return;
|
|
5133
|
+
}
|
|
5134
|
+
if (key.rightArrow) {
|
|
5135
|
+
setCursor((c) => Math.min(value.length, c + 1));
|
|
5136
|
+
return;
|
|
5137
|
+
}
|
|
5138
|
+
if (key.ctrl || key.meta) return;
|
|
5139
|
+
if (input.length > 0) {
|
|
5140
|
+
setValue((v) => v.slice(0, cursor) + input + v.slice(cursor));
|
|
5141
|
+
setCursor((c) => c + input.length);
|
|
5142
|
+
}
|
|
5143
|
+
});
|
|
5144
|
+
const display = masked ? "*".repeat(value.length) : value;
|
|
5145
|
+
const before = display.slice(0, cursor);
|
|
5146
|
+
const at = cursor < display.length ? display[cursor] : " ";
|
|
5147
|
+
const after = cursor < display.length ? display.slice(cursor + 1) : "";
|
|
5148
|
+
return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_ink_renderer42.Box, { flexDirection: "column", children: [
|
|
5149
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_ink_renderer42.Text, { bold: true, children: label }),
|
|
5150
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_ink_renderer42.Box, { children: [
|
|
5151
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_ink_renderer42.Text, { color: "cyan", children: "> " }),
|
|
5152
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_ink_renderer42.Text, { children: [
|
|
5153
|
+
before,
|
|
5154
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_ink_renderer42.Text, { inverse: true, children: at }),
|
|
5155
|
+
after
|
|
5156
|
+
] })
|
|
5157
|
+
] }),
|
|
5158
|
+
value.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_ink_renderer42.Text, { dimColor: true, children: " Type your credential and press Enter" })
|
|
5159
|
+
] });
|
|
5160
|
+
}
|
|
5161
|
+
function AuthFlowUI({
|
|
5162
|
+
auth,
|
|
5163
|
+
onComplete,
|
|
5164
|
+
onCancel,
|
|
5165
|
+
title = "Authentication"
|
|
5166
|
+
}) {
|
|
5167
|
+
const [phase, setPhase] = (0, import_react30.useState)({ type: "select-provider" });
|
|
5168
|
+
const [baseURL, setBaseURL] = (0, import_react30.useState)();
|
|
5169
|
+
const [error, setError] = (0, import_react30.useState)();
|
|
5170
|
+
const flowState = auth.interactive();
|
|
5171
|
+
const providerOptions = (flowState.providers ?? []).map((p) => ({
|
|
5172
|
+
value: p.name,
|
|
5173
|
+
label: `${p.displayName}`,
|
|
5174
|
+
description: p.description
|
|
5175
|
+
}));
|
|
5176
|
+
const handleProviderSelect = (0, import_react30.useCallback)((providerName) => {
|
|
5177
|
+
setError(void 0);
|
|
5178
|
+
try {
|
|
5179
|
+
const state = auth.selectProvider(providerName);
|
|
5180
|
+
if (state.step === "done" && state.result) {
|
|
5181
|
+
onComplete(state.result.provider, state.result.providerName, state.result.model);
|
|
5182
|
+
setPhase({ type: "done" });
|
|
5183
|
+
return;
|
|
5184
|
+
}
|
|
5185
|
+
if (state.step === "input-credentials" && state.currentAuthMethod) {
|
|
5186
|
+
const method = state.currentAuthMethod;
|
|
5187
|
+
const needsBaseURL = method.type === "base-url-key" && !method.defaultBaseURL;
|
|
5188
|
+
setPhase({
|
|
5189
|
+
type: "input-credentials",
|
|
5190
|
+
providerName,
|
|
5191
|
+
method,
|
|
5192
|
+
needsBaseURL
|
|
5193
|
+
});
|
|
5194
|
+
return;
|
|
5195
|
+
}
|
|
5196
|
+
if (state.step === "select-model" && state.models) {
|
|
5197
|
+
setPhase({
|
|
5198
|
+
type: "select-model",
|
|
5199
|
+
providerName,
|
|
5200
|
+
method: state.currentAuthMethod,
|
|
5201
|
+
models: state.models,
|
|
5202
|
+
defaultModel: state.currentModel
|
|
5203
|
+
});
|
|
5204
|
+
return;
|
|
5205
|
+
}
|
|
5206
|
+
if (state.step === "select-auth-method" && state.authMethods) {
|
|
5207
|
+
const method = state.authMethods[0];
|
|
5208
|
+
const needsBaseURL = method.type === "base-url-key" && !("defaultBaseURL" in method && method.defaultBaseURL);
|
|
5209
|
+
setPhase({
|
|
5210
|
+
type: "input-credentials",
|
|
5211
|
+
providerName,
|
|
5212
|
+
method,
|
|
5213
|
+
needsBaseURL: needsBaseURL && method.type === "base-url-key"
|
|
5214
|
+
});
|
|
5215
|
+
return;
|
|
5216
|
+
}
|
|
5217
|
+
} catch (err) {
|
|
5218
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
5219
|
+
}
|
|
5220
|
+
}, [auth, onComplete]);
|
|
5221
|
+
const handleBaseURLSubmit = (0, import_react30.useCallback)((url) => {
|
|
5222
|
+
setBaseURL(url);
|
|
5223
|
+
}, []);
|
|
5224
|
+
const handleCredentialSubmit = (0, import_react30.useCallback)(async (apiKey) => {
|
|
5225
|
+
if (phase.type !== "input-credentials") return;
|
|
5226
|
+
setError(void 0);
|
|
5227
|
+
try {
|
|
5228
|
+
const credentials = {
|
|
5229
|
+
apiKey,
|
|
5230
|
+
baseURL: baseURL || (phase.method.type === "base-url-key" ? phase.method.defaultBaseURL : void 0)
|
|
5231
|
+
};
|
|
5232
|
+
const state = await auth.inputCredentials(phase.providerName, phase.method, credentials);
|
|
5233
|
+
if (state.step === "done" && state.result) {
|
|
5234
|
+
onComplete(state.result.provider, state.result.providerName, state.result.model);
|
|
5235
|
+
setPhase({ type: "done" });
|
|
5236
|
+
return;
|
|
5237
|
+
}
|
|
5238
|
+
if (state.step === "select-model" && state.models) {
|
|
5239
|
+
setPhase({
|
|
5240
|
+
type: "select-model",
|
|
5241
|
+
providerName: phase.providerName,
|
|
5242
|
+
method: phase.method,
|
|
5243
|
+
models: state.models,
|
|
5244
|
+
defaultModel: state.currentModel
|
|
5245
|
+
});
|
|
5246
|
+
return;
|
|
5247
|
+
}
|
|
5248
|
+
} catch (err) {
|
|
5249
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
5250
|
+
}
|
|
5251
|
+
}, [auth, phase, baseURL, onComplete]);
|
|
5252
|
+
const handleModelSelect = (0, import_react30.useCallback)(async (model) => {
|
|
5253
|
+
if (phase.type !== "select-model") return;
|
|
5254
|
+
setError(void 0);
|
|
5255
|
+
try {
|
|
5256
|
+
const state = await auth.selectModel(phase.providerName, phase.method, model);
|
|
5257
|
+
if (state.step === "done" && state.result) {
|
|
5258
|
+
onComplete(state.result.provider, state.result.providerName, state.result.model);
|
|
5259
|
+
setPhase({ type: "done" });
|
|
5260
|
+
}
|
|
5261
|
+
} catch (err) {
|
|
5262
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
5263
|
+
}
|
|
5264
|
+
}, [auth, phase, onComplete]);
|
|
5265
|
+
const handleCancel = (0, import_react30.useCallback)(() => {
|
|
5266
|
+
if (phase.type === "select-provider") {
|
|
5267
|
+
onCancel?.();
|
|
5268
|
+
} else {
|
|
5269
|
+
setPhase({ type: "select-provider" });
|
|
5270
|
+
setBaseURL(void 0);
|
|
5271
|
+
setError(void 0);
|
|
5272
|
+
}
|
|
5273
|
+
}, [phase, onCancel]);
|
|
5274
|
+
if (phase.type === "done") {
|
|
5275
|
+
return null;
|
|
5276
|
+
}
|
|
5277
|
+
return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_ink_renderer42.Box, { flexDirection: "column", marginTop: 1, marginLeft: 1, children: [
|
|
5278
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_ink_renderer42.Box, { marginBottom: 1, children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_ink_renderer42.Text, { bold: true, color: "#DA7756", children: title }) }),
|
|
5279
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Divider, {}),
|
|
5280
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_ink_renderer42.Box, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_ink_renderer42.Text, { color: "red", children: [
|
|
5281
|
+
"Error: ",
|
|
5282
|
+
error
|
|
5283
|
+
] }) }),
|
|
5284
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_ink_renderer42.Box, { marginTop: 1, children: [
|
|
5285
|
+
phase.type === "select-provider" && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
5286
|
+
Select,
|
|
5287
|
+
{
|
|
5288
|
+
title: "Select a provider:",
|
|
5289
|
+
options: providerOptions,
|
|
5290
|
+
onChange: handleProviderSelect,
|
|
5291
|
+
onCancel: handleCancel
|
|
5292
|
+
}
|
|
5293
|
+
),
|
|
5294
|
+
phase.type === "input-credentials" && phase.method.type === "base-url-key" && phase.needsBaseURL && !baseURL && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
5295
|
+
CredentialInput,
|
|
5296
|
+
{
|
|
5297
|
+
label: "Enter Base URL:",
|
|
5298
|
+
masked: false,
|
|
5299
|
+
onSubmit: handleBaseURLSubmit,
|
|
5300
|
+
onCancel: handleCancel
|
|
5301
|
+
}
|
|
5302
|
+
),
|
|
5303
|
+
phase.type === "input-credentials" && !(phase.method.type === "base-url-key" && phase.needsBaseURL && !baseURL) && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
5304
|
+
CredentialInput,
|
|
5305
|
+
{
|
|
5306
|
+
label: phase.method.type === "api-key" || phase.method.type === "base-url-key" ? phase.method.inputLabel ?? "Enter API Key:" : "Enter API Key:",
|
|
5307
|
+
masked: true,
|
|
5308
|
+
onSubmit: handleCredentialSubmit,
|
|
5309
|
+
onCancel: handleCancel
|
|
5310
|
+
}
|
|
5311
|
+
),
|
|
5312
|
+
phase.type === "select-model" && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
5313
|
+
Select,
|
|
5314
|
+
{
|
|
5315
|
+
title: "Select a model:",
|
|
5316
|
+
options: phase.models.map((m) => ({
|
|
5317
|
+
value: m,
|
|
5318
|
+
label: m,
|
|
5319
|
+
description: m === phase.defaultModel ? "(default)" : void 0
|
|
5320
|
+
})),
|
|
5321
|
+
defaultValue: phase.defaultModel,
|
|
5322
|
+
onChange: handleModelSelect,
|
|
5323
|
+
onCancel: handleCancel
|
|
5324
|
+
}
|
|
5325
|
+
)
|
|
5326
|
+
] }),
|
|
5327
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_ink_renderer42.Box, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_ink_renderer42.Text, { dimColor: true, children: [
|
|
5328
|
+
"Esc to ",
|
|
5329
|
+
phase.type === "select-provider" ? "cancel" : "go back"
|
|
5330
|
+
] }) })
|
|
5331
|
+
] });
|
|
5332
|
+
}
|
|
2392
5333
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2393
5334
|
0 && (module.exports = {
|
|
5335
|
+
AgentContext,
|
|
5336
|
+
AgentProvider,
|
|
5337
|
+
AgentREPL,
|
|
5338
|
+
AuthFlowUI,
|
|
5339
|
+
BashPermissionContent,
|
|
5340
|
+
Byline,
|
|
5341
|
+
ClawdLogo,
|
|
2394
5342
|
CommandRegistry,
|
|
2395
5343
|
DEFAULT_BINDINGS,
|
|
5344
|
+
Dialog,
|
|
5345
|
+
DiffView,
|
|
2396
5346
|
Divider,
|
|
5347
|
+
FileEditPermissionContent,
|
|
5348
|
+
FuzzyPicker,
|
|
2397
5349
|
KeybindingSetup,
|
|
5350
|
+
KeyboardShortcutHint,
|
|
5351
|
+
ListItem,
|
|
5352
|
+
LoadingState,
|
|
5353
|
+
Markdown,
|
|
5354
|
+
MarkdownTable,
|
|
2398
5355
|
MessageList,
|
|
2399
5356
|
MultiSelect,
|
|
5357
|
+
Pane,
|
|
5358
|
+
PermissionRequest,
|
|
2400
5359
|
ProgressBar,
|
|
2401
5360
|
PromptInput,
|
|
2402
5361
|
REPL,
|
|
5362
|
+
Ratchet,
|
|
5363
|
+
SearchOverlay,
|
|
2403
5364
|
Select,
|
|
2404
5365
|
Spinner,
|
|
2405
5366
|
StatusIcon,
|
|
2406
5367
|
StatusLine,
|
|
5368
|
+
StreamingMarkdown,
|
|
2407
5369
|
StreamingText,
|
|
5370
|
+
Tab,
|
|
5371
|
+
Tabs,
|
|
5372
|
+
TextHoverColorContext,
|
|
5373
|
+
ThemeProvider,
|
|
5374
|
+
ThemedBox,
|
|
5375
|
+
ThemedText,
|
|
5376
|
+
VirtualList,
|
|
5377
|
+
WelcomeScreen,
|
|
2408
5378
|
clearCommand,
|
|
5379
|
+
color,
|
|
2409
5380
|
createCommandRegistry,
|
|
2410
5381
|
defineCommand,
|
|
2411
5382
|
defineJSXCommand,
|
|
2412
5383
|
defineLocalCommand,
|
|
2413
5384
|
exitCommand,
|
|
5385
|
+
getTheme,
|
|
2414
5386
|
helpCommand,
|
|
5387
|
+
parseUnifiedDiff,
|
|
5388
|
+
useAgent,
|
|
5389
|
+
useAgentContext,
|
|
5390
|
+
useDoublePress,
|
|
2415
5391
|
useKeybinding,
|
|
2416
5392
|
useKeybindings,
|
|
5393
|
+
usePreviewTheme,
|
|
5394
|
+
useSearch,
|
|
2417
5395
|
useStatusLine,
|
|
5396
|
+
useTabsWidth,
|
|
5397
|
+
useTerminalSize,
|
|
5398
|
+
useTheme,
|
|
5399
|
+
useThemeSetting,
|
|
5400
|
+
useVirtualScroll,
|
|
2418
5401
|
...require("@claude-code-kit/ink-renderer")
|
|
2419
5402
|
});
|