@bbclaw/cli 0.1.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/dist/auth/authStore.d.ts +17 -0
- package/dist/auth/authStore.d.ts.map +1 -0
- package/dist/auth/authStore.js +40 -0
- package/dist/auth/authStore.js.map +1 -0
- package/dist/auth/client.d.ts +23 -0
- package/dist/auth/client.d.ts.map +1 -0
- package/dist/auth/client.js +50 -0
- package/dist/auth/client.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +401 -0
- package/dist/index.js.map +1 -0
- package/dist/repl/App.d.ts +10 -0
- package/dist/repl/App.d.ts.map +1 -0
- package/dist/repl/App.js +86 -0
- package/dist/repl/App.js.map +1 -0
- package/dist/repl/Input.d.ts +25 -0
- package/dist/repl/Input.d.ts.map +1 -0
- package/dist/repl/Input.js +162 -0
- package/dist/repl/Input.js.map +1 -0
- package/dist/repl/MessageList.d.ts +8 -0
- package/dist/repl/MessageList.d.ts.map +1 -0
- package/dist/repl/MessageList.js +63 -0
- package/dist/repl/MessageList.js.map +1 -0
- package/dist/repl/ToolApprovalPrompt.d.ts +10 -0
- package/dist/repl/ToolApprovalPrompt.d.ts.map +1 -0
- package/dist/repl/ToolApprovalPrompt.js +34 -0
- package/dist/repl/ToolApprovalPrompt.js.map +1 -0
- package/dist/repl/animations.d.ts +24 -0
- package/dist/repl/animations.d.ts.map +1 -0
- package/dist/repl/animations.js +79 -0
- package/dist/repl/animations.js.map +1 -0
- package/dist/repl/runRepl.d.ts +4 -0
- package/dist/repl/runRepl.d.ts.map +1 -0
- package/dist/repl/runRepl.js +44 -0
- package/dist/repl/runRepl.js.map +1 -0
- package/dist/repl/sessionStore.d.ts +31 -0
- package/dist/repl/sessionStore.d.ts.map +1 -0
- package/dist/repl/sessionStore.js +79 -0
- package/dist/repl/sessionStore.js.map +1 -0
- package/dist/repl/slashCommands.d.ts +61 -0
- package/dist/repl/slashCommands.d.ts.map +1 -0
- package/dist/repl/slashCommands.js +328 -0
- package/dist/repl/slashCommands.js.map +1 -0
- package/dist/repl/useChat.d.ts +65 -0
- package/dist/repl/useChat.d.ts.map +1 -0
- package/dist/repl/useChat.js +517 -0
- package/dist/repl/useChat.js.map +1 -0
- package/dist/tools/Bash.d.ts +11 -0
- package/dist/tools/Bash.d.ts.map +1 -0
- package/dist/tools/Bash.js +61 -0
- package/dist/tools/Bash.js.map +1 -0
- package/dist/tools/Read.d.ts +11 -0
- package/dist/tools/Read.d.ts.map +1 -0
- package/dist/tools/Read.js +39 -0
- package/dist/tools/Read.js.map +1 -0
- package/dist/tools/Write.d.ts +12 -0
- package/dist/tools/Write.d.ts.map +1 -0
- package/dist/tools/Write.js +42 -0
- package/dist/tools/Write.js.map +1 -0
- package/dist/tools/index.d.ts +15 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +35 -0
- package/dist/tools/index.js.map +1 -0
- package/package.json +35 -0
package/dist/repl/App.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text, useApp, useInput } from 'ink';
|
|
3
|
+
import { useCallback, useMemo } from 'react';
|
|
4
|
+
import { useCountdown, useElapsedSeconds, useSpinner } from './animations.js';
|
|
5
|
+
import { Input } from './Input.js';
|
|
6
|
+
import { MessageList } from './MessageList.js';
|
|
7
|
+
import { dispatchSlash } from './slashCommands.js';
|
|
8
|
+
import { ToolApprovalPrompt } from './ToolApprovalPrompt.js';
|
|
9
|
+
import { useChat } from './useChat.js';
|
|
10
|
+
export const App = ({ registry, initialSession }) => {
|
|
11
|
+
const { exit } = useApp();
|
|
12
|
+
const chat = useChat({ registry, initialSession });
|
|
13
|
+
useInput((_, key) => {
|
|
14
|
+
if (key.ctrl && _ === 'c') {
|
|
15
|
+
if (chat.status !== 'idle')
|
|
16
|
+
chat.cancel();
|
|
17
|
+
else
|
|
18
|
+
exit();
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
const handleSubmit = useCallback(async (text) => {
|
|
22
|
+
const trimmed = text.trim();
|
|
23
|
+
if (!trimmed)
|
|
24
|
+
return;
|
|
25
|
+
if (trimmed.startsWith('/')) {
|
|
26
|
+
const ctx = {
|
|
27
|
+
registry,
|
|
28
|
+
currentProviderId: chat.providerId,
|
|
29
|
+
currentModel: chat.model,
|
|
30
|
+
setProvider: chat.setProvider,
|
|
31
|
+
setModel: chat.setModel,
|
|
32
|
+
clearLog: chat.clearLog,
|
|
33
|
+
addNote: chat.addNote,
|
|
34
|
+
retryLast: chat.retryLast,
|
|
35
|
+
loadState: chat.loadState,
|
|
36
|
+
snapshot: chat.snapshot,
|
|
37
|
+
alwaysAllowed: chat.alwaysAllowed,
|
|
38
|
+
startLoop: chat.startLoop,
|
|
39
|
+
stopLoop: chat.stopLoop,
|
|
40
|
+
isLooping: () => chat.loop !== null,
|
|
41
|
+
exit,
|
|
42
|
+
};
|
|
43
|
+
await dispatchSlash(trimmed, ctx);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
await chat.send(trimmed);
|
|
47
|
+
}, [chat, exit, registry]);
|
|
48
|
+
const header = useMemo(() => {
|
|
49
|
+
const p = chat.currentProvider;
|
|
50
|
+
const model = chat.model ?? p.defaultModel ?? '(no model)';
|
|
51
|
+
return `BBClaw · ${p.displayName} [${p.id}] · ${model}`;
|
|
52
|
+
}, [chat.currentProvider, chat.model]);
|
|
53
|
+
const usageLine = useMemo(() => {
|
|
54
|
+
const { inputTokens, outputTokens } = chat.usage;
|
|
55
|
+
if (inputTokens === 0 && outputTokens === 0)
|
|
56
|
+
return null;
|
|
57
|
+
return `↑ ${inputTokens} ↓ ${outputTokens} · session ${chat.sessionId}`;
|
|
58
|
+
}, [chat.usage, chat.sessionId]);
|
|
59
|
+
const spinner = useSpinner(chat.status !== 'idle');
|
|
60
|
+
const elapsed = useElapsedSeconds(chat.status === 'streaming');
|
|
61
|
+
const toolElapsed = useElapsedSeconds(chat.runningTool !== null);
|
|
62
|
+
const loopElapsed = useElapsedSeconds(chat.loop !== null);
|
|
63
|
+
const loopCountdown = useCountdown(chat.loop?.nextFireAt ?? null);
|
|
64
|
+
const statusLine = useMemo(() => {
|
|
65
|
+
if (chat.status === 'streaming')
|
|
66
|
+
return `${spinner} streaming · ${elapsed.toFixed(1)}s`;
|
|
67
|
+
if (chat.status === 'awaiting-approval')
|
|
68
|
+
return `${spinner} awaiting approval (y/n/a)`;
|
|
69
|
+
return '› ready';
|
|
70
|
+
}, [chat.status, spinner, elapsed]);
|
|
71
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { children: _jsx(Text, { color: "yellow", bold: true, children: header }) }), _jsx(Box, { children: _jsx(Text, { color: "gray", children: "type /help \u00B7 \u2191\u2193 history \u00B7 Ctrl+J newline \u00B7 Ctrl+C cancel \u00B7 /quit to exit" }) }), usageLine && (_jsx(Box, { children: _jsx(Text, { color: "gray", children: usageLine }) })), chat.loop && (_jsx(Box, { children: _jsxs(Text, { color: "magenta", children: ["\uD83D\uDD01 Loop \u00B7 iter ", chat.loop.iteration, " \u00B7 ", formatElapsed(loopElapsed), " elapsed", loopCountdown != null && chat.status === 'idle'
|
|
72
|
+
? ` · next in ${loopCountdown}s`
|
|
73
|
+
: '', ' · ', _jsx(Text, { color: "gray", children: "/unloop to stop" })] }) })), _jsx(MessageList, { log: chat.log }), chat.status === 'streaming' && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Box, { children: _jsxs(Text, { color: "green", bold: true, children: [spinner, " assistant"] }) }), chat.streamingText.length > 0 ? (_jsx(Text, { children: chat.streamingText })) : (_jsx(Text, { color: "gray", italic: true, children: "thinking\u2026" }))] })), chat.runningTool && (_jsxs(Box, { marginTop: 1, children: [_jsxs(Text, { color: "yellow", children: [spinner, " running ", chat.runningTool.name, "\u2026"] }), _jsxs(Text, { color: "gray", children: [" (", toolElapsed.toFixed(1), "s)"] })] })), chat.status === 'awaiting-approval' && chat.pendingTool && (_jsx(ToolApprovalPrompt, { pending: chat.pendingTool, onRespond: chat.respondToApproval, alreadyAllowed: chat.alwaysAllowed() })), _jsx(Input, { onSubmit: handleSubmit, disabled: chat.status !== 'idle', history: chat.history }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: chat.status === 'idle' ? 'gray' : 'cyan', children: statusLine }) })] }));
|
|
74
|
+
};
|
|
75
|
+
function formatElapsed(seconds) {
|
|
76
|
+
if (seconds < 60)
|
|
77
|
+
return `${seconds.toFixed(0)}s`;
|
|
78
|
+
const m = Math.floor(seconds / 60);
|
|
79
|
+
const s = Math.floor(seconds % 60);
|
|
80
|
+
if (m < 60)
|
|
81
|
+
return s === 0 ? `${m}m` : `${m}m${s}s`;
|
|
82
|
+
const h = Math.floor(m / 60);
|
|
83
|
+
const mm = m % 60;
|
|
84
|
+
return mm === 0 ? `${h}h` : `${h}h${mm}m`;
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=App.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"App.js","sourceRoot":"","sources":["../../src/repl/App.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type FC } from 'react';
|
|
2
|
+
interface InputProps {
|
|
3
|
+
/** Called when user presses Enter on a non-empty buffer. */
|
|
4
|
+
onSubmit: (text: string) => void;
|
|
5
|
+
/** Hide the input + cursor when true (e.g. while streaming). */
|
|
6
|
+
disabled?: boolean;
|
|
7
|
+
/** Placeholder shown when buffer is empty. */
|
|
8
|
+
placeholder?: string;
|
|
9
|
+
/**
|
|
10
|
+
* Read-only history of past prompts, latest at the end. Up/Down arrows
|
|
11
|
+
* navigate through it. The current draft is stashed when entering history
|
|
12
|
+
* and restored when navigating past the latest entry.
|
|
13
|
+
*/
|
|
14
|
+
history: string[];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Custom Ink input. All state is held in refs and the component force-renders
|
|
18
|
+
* after each mutation. This is intentional: ink-testing-library (and a fast
|
|
19
|
+
* typist on a real terminal) can fire multiple useInput events before React
|
|
20
|
+
* commits a render, and any useState/useReducer-based version was reading
|
|
21
|
+
* stale closure values between writes. Refs sidestep the whole problem.
|
|
22
|
+
*/
|
|
23
|
+
export declare const Input: FC<InputProps>;
|
|
24
|
+
export {};
|
|
25
|
+
//# sourceMappingURL=Input.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Input.d.ts","sourceRoot":"","sources":["../../src/repl/Input.tsx"],"names":[],"mappings":"AACA,OAAO,EAAsB,KAAK,EAAE,EAAE,MAAM,OAAO,CAAA;AAGnD,UAAU,UAAU;IAClB,4DAA4D;IAC5D,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAChC,gEAAgE;IAChE,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,8CAA8C;IAC9C,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;OAIG;IACH,OAAO,EAAE,MAAM,EAAE,CAAA;CAClB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,KAAK,EAAE,EAAE,CAAC,UAAU,CAiLhC,CAAA"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text, useInput } from 'ink';
|
|
3
|
+
import { useReducer, useRef } from 'react';
|
|
4
|
+
import { useBlink } from './animations.js';
|
|
5
|
+
/**
|
|
6
|
+
* Custom Ink input. All state is held in refs and the component force-renders
|
|
7
|
+
* after each mutation. This is intentional: ink-testing-library (and a fast
|
|
8
|
+
* typist on a real terminal) can fire multiple useInput events before React
|
|
9
|
+
* commits a render, and any useState/useReducer-based version was reading
|
|
10
|
+
* stale closure values between writes. Refs sidestep the whole problem.
|
|
11
|
+
*/
|
|
12
|
+
export const Input = ({ onSubmit, disabled, placeholder, history }) => {
|
|
13
|
+
const textRef = useRef('');
|
|
14
|
+
const cursorRef = useRef(0);
|
|
15
|
+
const historyIdxRef = useRef(null);
|
|
16
|
+
const stashedRef = useRef('');
|
|
17
|
+
const historyRef = useRef(history);
|
|
18
|
+
historyRef.current = history;
|
|
19
|
+
const [, force] = useReducer((n) => n + 1, 0);
|
|
20
|
+
const blinkOn = useBlink(!disabled);
|
|
21
|
+
const insert = (ch) => {
|
|
22
|
+
const t = textRef.current;
|
|
23
|
+
const c = cursorRef.current;
|
|
24
|
+
textRef.current = t.slice(0, c) + ch + t.slice(c);
|
|
25
|
+
cursorRef.current = c + ch.length;
|
|
26
|
+
historyIdxRef.current = null;
|
|
27
|
+
force();
|
|
28
|
+
};
|
|
29
|
+
const backspace = () => {
|
|
30
|
+
const c = cursorRef.current;
|
|
31
|
+
if (c === 0)
|
|
32
|
+
return;
|
|
33
|
+
const t = textRef.current;
|
|
34
|
+
textRef.current = t.slice(0, c - 1) + t.slice(c);
|
|
35
|
+
cursorRef.current = c - 1;
|
|
36
|
+
historyIdxRef.current = null;
|
|
37
|
+
force();
|
|
38
|
+
};
|
|
39
|
+
const submit = () => {
|
|
40
|
+
const t = textRef.current;
|
|
41
|
+
const trimmed = t.replace(/\s+$/, '');
|
|
42
|
+
if (trimmed.length === 0)
|
|
43
|
+
return;
|
|
44
|
+
textRef.current = '';
|
|
45
|
+
cursorRef.current = 0;
|
|
46
|
+
historyIdxRef.current = null;
|
|
47
|
+
stashedRef.current = '';
|
|
48
|
+
force();
|
|
49
|
+
onSubmit(t);
|
|
50
|
+
};
|
|
51
|
+
const moveCursor = (delta) => {
|
|
52
|
+
cursorRef.current = Math.max(0, Math.min(textRef.current.length, cursorRef.current + delta));
|
|
53
|
+
force();
|
|
54
|
+
};
|
|
55
|
+
const navigateHistory = (direction) => {
|
|
56
|
+
const list = historyRef.current;
|
|
57
|
+
if (list.length === 0)
|
|
58
|
+
return;
|
|
59
|
+
if (historyIdxRef.current === null) {
|
|
60
|
+
if (direction !== -1)
|
|
61
|
+
return;
|
|
62
|
+
const idx = list.length - 1;
|
|
63
|
+
const entry = list[idx];
|
|
64
|
+
if (entry === undefined)
|
|
65
|
+
return;
|
|
66
|
+
stashedRef.current = textRef.current;
|
|
67
|
+
historyIdxRef.current = idx;
|
|
68
|
+
textRef.current = entry;
|
|
69
|
+
cursorRef.current = entry.length;
|
|
70
|
+
force();
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const next = historyIdxRef.current + direction;
|
|
74
|
+
if (next < 0)
|
|
75
|
+
return;
|
|
76
|
+
if (next >= list.length) {
|
|
77
|
+
historyIdxRef.current = null;
|
|
78
|
+
textRef.current = stashedRef.current;
|
|
79
|
+
cursorRef.current = stashedRef.current.length;
|
|
80
|
+
force();
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const entry = list[next];
|
|
84
|
+
if (entry === undefined)
|
|
85
|
+
return;
|
|
86
|
+
historyIdxRef.current = next;
|
|
87
|
+
textRef.current = entry;
|
|
88
|
+
cursorRef.current = entry.length;
|
|
89
|
+
force();
|
|
90
|
+
};
|
|
91
|
+
useInput((input, key) => {
|
|
92
|
+
if (disabled)
|
|
93
|
+
return;
|
|
94
|
+
if (key.return) {
|
|
95
|
+
if (textRef.current.endsWith('\\')) {
|
|
96
|
+
const t = textRef.current;
|
|
97
|
+
textRef.current = `${t.slice(0, -1)}\n`;
|
|
98
|
+
cursorRef.current = textRef.current.length;
|
|
99
|
+
historyIdxRef.current = null;
|
|
100
|
+
force();
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
if (key.ctrl) {
|
|
104
|
+
insert('\n');
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
submit();
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
if (key.ctrl && input === 'j') {
|
|
111
|
+
insert('\n');
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
if (key.upArrow) {
|
|
115
|
+
navigateHistory(-1);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if (key.downArrow) {
|
|
119
|
+
navigateHistory(1);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
if (key.leftArrow) {
|
|
123
|
+
moveCursor(-1);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
if (key.rightArrow) {
|
|
127
|
+
moveCursor(1);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
if (key.backspace || key.delete) {
|
|
131
|
+
backspace();
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
if (key.ctrl || key.meta)
|
|
135
|
+
return;
|
|
136
|
+
if (input && input.length > 0)
|
|
137
|
+
insert(input);
|
|
138
|
+
}, { isActive: !disabled });
|
|
139
|
+
if (disabled) {
|
|
140
|
+
return (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "gray", children: "\u2026" }) }));
|
|
141
|
+
}
|
|
142
|
+
const text = textRef.current;
|
|
143
|
+
const cursor = cursorRef.current;
|
|
144
|
+
if (text.length === 0) {
|
|
145
|
+
return (_jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: "magenta", children: "\u203A " }), _jsx(Text, { color: "gray", children: placeholder ?? 'type a message, / for commands, ↑/↓ for history' }), blinkOn ? _jsx(Text, { inverse: true, children: " " }) : _jsx(Text, { children: " " })] }));
|
|
146
|
+
}
|
|
147
|
+
const before = text.slice(0, cursor);
|
|
148
|
+
const at = text.slice(cursor, cursor + 1) || ' ';
|
|
149
|
+
const after = text.slice(cursor + 1);
|
|
150
|
+
const beforeLines = before.split('\n');
|
|
151
|
+
const afterLines = after.split('\n');
|
|
152
|
+
const cursorChar = at === '\n' ? ' ' : at;
|
|
153
|
+
return (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [beforeLines.map((line, i) => {
|
|
154
|
+
const isLast = i === beforeLines.length - 1;
|
|
155
|
+
if (!isLast)
|
|
156
|
+
return _jsx(PromptLine, { prefix: i === 0 ? '› ' : ' ', text: line }, `b-${i}`);
|
|
157
|
+
const afterFirst = afterLines[0] ?? '';
|
|
158
|
+
return (_jsxs(Box, { flexDirection: "row", children: [_jsx(Text, { color: "magenta", children: i === 0 ? '› ' : ' ' }), _jsx(Text, { children: line }), blinkOn ? _jsx(Text, { inverse: true, children: cursorChar }) : _jsx(Text, { children: cursorChar }), _jsx(Text, { children: afterFirst })] }, `cursor-row-${i}`));
|
|
159
|
+
}), afterLines.slice(1).map((line, i) => (_jsx(PromptLine, { prefix: " ", text: line }, `a-${i}`)))] }));
|
|
160
|
+
};
|
|
161
|
+
const PromptLine = ({ prefix, text }) => (_jsxs(Box, { flexDirection: "row", children: [_jsx(Text, { color: "magenta", children: prefix }), _jsx(Text, { children: text })] }));
|
|
162
|
+
//# sourceMappingURL=Input.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Input.js","sourceRoot":"","sources":["../../src/repl/Input.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../src/repl/MessageList.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAA;AAC/B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAElD,UAAU,gBAAgB;IACxB,GAAG,EAAE,QAAQ,EAAE,CAAA;CAChB;AAED,eAAO,MAAM,WAAW,EAAE,EAAE,CAAC,gBAAgB,CAS5C,CAAA"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from 'ink';
|
|
3
|
+
export const MessageList = ({ log }) => {
|
|
4
|
+
if (log.length === 0)
|
|
5
|
+
return null;
|
|
6
|
+
return (_jsx(Box, { flexDirection: "column", children: log.map((entry, i) => (_jsx(LogRow, { entry: entry }, i))) }));
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Compact noisy errors to one informative line plus a short hint. Library
|
|
10
|
+
* errors (Playwright especially) often include a multi-line ASCII box with
|
|
11
|
+
* install instructions — useful once, but every subsequent message looks
|
|
12
|
+
* like garbage in a chat log. We keep the first non-empty sentence and a
|
|
13
|
+
* single follow-up hint, if a recognizable one is present.
|
|
14
|
+
*/
|
|
15
|
+
function compactErrorText(text) {
|
|
16
|
+
const lines = text.split('\n');
|
|
17
|
+
// Strip ASCII-box decorations (Playwright's `╔═══...═══╗`, etc).
|
|
18
|
+
const cleaned = lines
|
|
19
|
+
.map((l) => l.replace(/[╔╗║╚╝═╠╣╬│─┌┐└┘├┤┬┴┼]/g, '').trim())
|
|
20
|
+
.filter((l) => l.length > 0);
|
|
21
|
+
if (cleaned.length <= 2)
|
|
22
|
+
return cleaned.join(' ');
|
|
23
|
+
const first = cleaned[0] ?? '';
|
|
24
|
+
// Look for a `<3 something Team` signature or install hint to attach.
|
|
25
|
+
const hint = cleaned.find((l) => /install|run.*command|please run|<3/i.test(l));
|
|
26
|
+
if (hint && hint !== first)
|
|
27
|
+
return `${first} — hint: ${hint}`;
|
|
28
|
+
return first;
|
|
29
|
+
}
|
|
30
|
+
const LogRow = ({ entry }) => {
|
|
31
|
+
switch (entry.kind) {
|
|
32
|
+
case 'user':
|
|
33
|
+
return (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { color: "cyan", bold: true, children: "you" }), _jsx(Text, { children: entry.text })] }));
|
|
34
|
+
case 'assistant':
|
|
35
|
+
return (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { color: "green", bold: true, children: "assistant" }), _jsx(Text, { children: entry.text })] }));
|
|
36
|
+
case 'tool-use': {
|
|
37
|
+
let preview;
|
|
38
|
+
try {
|
|
39
|
+
preview = JSON.stringify(entry.input);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
preview = String(entry.input);
|
|
43
|
+
}
|
|
44
|
+
if (preview.length > 120)
|
|
45
|
+
preview = `${preview.slice(0, 120)}…`;
|
|
46
|
+
return (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Text, { color: "yellow", bold: true, children: ["\uD83D\uDD27 ", entry.name] }), _jsxs(Text, { color: "gray", children: ["input: ", preview] })] }));
|
|
47
|
+
}
|
|
48
|
+
case 'tool-result': {
|
|
49
|
+
const max = 400;
|
|
50
|
+
const out = entry.output.length <= max
|
|
51
|
+
? entry.output
|
|
52
|
+
: `${entry.output.slice(0, max)}\n…(${entry.output.length - max} more chars)`;
|
|
53
|
+
const label = entry.isError ? '↳ error' : '↳ result';
|
|
54
|
+
const color = entry.isError ? 'red' : 'cyan';
|
|
55
|
+
return (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Text, { color: color, bold: true, children: [label, " \u00B7 ", entry.toolName] }), _jsx(Text, { color: entry.isError ? 'red' : undefined, children: out })] }));
|
|
56
|
+
}
|
|
57
|
+
case 'note':
|
|
58
|
+
return (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "gray", children: entry.text }) }));
|
|
59
|
+
case 'error':
|
|
60
|
+
return (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "red", children: ["error: ", compactErrorText(entry.text)] }) }));
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
//# sourceMappingURL=MessageList.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MessageList.js","sourceRoot":"","sources":["../../src/repl/MessageList.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type FC } from 'react';
|
|
2
|
+
import type { ApprovalDecision, PendingTool } from './useChat.js';
|
|
3
|
+
interface ToolApprovalPromptProps {
|
|
4
|
+
pending: PendingTool;
|
|
5
|
+
onRespond: (decision: ApprovalDecision) => void;
|
|
6
|
+
alreadyAllowed: string[];
|
|
7
|
+
}
|
|
8
|
+
export declare const ToolApprovalPrompt: FC<ToolApprovalPromptProps>;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=ToolApprovalPrompt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ToolApprovalPrompt.d.ts","sourceRoot":"","sources":["../../src/repl/ToolApprovalPrompt.tsx"],"names":[],"mappings":"AACA,OAAO,EAAW,KAAK,EAAE,EAAE,MAAM,OAAO,CAAA;AAExC,OAAO,KAAK,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAEjE,UAAU,uBAAuB;IAC/B,OAAO,EAAE,WAAW,CAAA;IACpB,SAAS,EAAE,CAAC,QAAQ,EAAE,gBAAgB,KAAK,IAAI,CAAA;IAC/C,cAAc,EAAE,MAAM,EAAE,CAAA;CACzB;AAED,eAAO,MAAM,kBAAkB,EAAE,EAAE,CAAC,uBAAuB,CA2D1D,CAAA"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text, useInput } from 'ink';
|
|
3
|
+
import { useMemo } from 'react';
|
|
4
|
+
import { useBlink } from './animations.js';
|
|
5
|
+
export const ToolApprovalPrompt = ({ pending, onRespond, alreadyAllowed, }) => {
|
|
6
|
+
const inputJson = useMemo(() => {
|
|
7
|
+
try {
|
|
8
|
+
const pretty = JSON.stringify(pending.input, null, 2);
|
|
9
|
+
if (pretty.length <= 400)
|
|
10
|
+
return pretty;
|
|
11
|
+
return `${pretty.slice(0, 400)}\n…(${pretty.length - 400} more chars)`;
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return String(pending.input);
|
|
15
|
+
}
|
|
16
|
+
}, [pending.input]);
|
|
17
|
+
useInput((input) => {
|
|
18
|
+
const key = input.toLowerCase();
|
|
19
|
+
if (key === 'y')
|
|
20
|
+
onRespond('approve');
|
|
21
|
+
else if (key === 'n')
|
|
22
|
+
onRespond('deny');
|
|
23
|
+
else if (key === 'a')
|
|
24
|
+
onRespond('allow-all');
|
|
25
|
+
});
|
|
26
|
+
// Breathing border: alternate between two yellows on ~700ms to draw the
|
|
27
|
+
// eye without strobing. Slower than spinners so it doesn't feel anxious.
|
|
28
|
+
const bright = useBlink(true, 700);
|
|
29
|
+
const allowHint = alreadyAllowed.length > 0
|
|
30
|
+
? ` (auto-approved this session: ${alreadyAllowed.join(', ')})`
|
|
31
|
+
: '';
|
|
32
|
+
return (_jsxs(Box, { flexDirection: "column", marginTop: 1, borderStyle: "round", borderColor: bright ? 'yellowBright' : 'yellow', paddingX: 1, children: [_jsxs(Box, { children: [_jsxs(Text, { color: "yellow", bold: true, children: ["\uD83D\uDD27 ", pending.name] }), _jsx(Text, { color: "gray", children: " \u00B7 approval required" })] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { children: inputJson }) }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: "cyan", children: "[y]" }), _jsx(Text, { children: " approve " }), _jsx(Text, { color: "red", children: "[n]" }), _jsx(Text, { children: " deny " }), _jsx(Text, { color: "green", children: "[a]" }), _jsxs(Text, { children: [" always allow ", pending.name, " this session"] }), _jsx(Text, { color: "gray", children: allowHint })] })] }));
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=ToolApprovalPrompt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ToolApprovalPrompt.js","sourceRoot":"","sources":["../../src/repl/ToolApprovalPrompt.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,KAAK,CAAA;AACzC,OAAO,EAAE,OAAO,EAAW,MAAM,OAAO,CAAA;AACxC,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAS1C,MAAM,CAAC,MAAM,kBAAkB,GAAgC,CAAC,EAC9D,OAAO,EACP,SAAS,EACT,cAAc,GACf,EAAE,EAAE;IACH,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,EAAE;QAC7B,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;YACrD,IAAI,MAAM,CAAC,MAAM,IAAI,GAAG;gBAAE,OAAO,MAAM,CAAA;YACvC,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,OAAO,MAAM,CAAC,MAAM,GAAG,GAAG,cAAc,CAAA;QACxE,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;QAC9B,CAAC;IACH,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAA;IAEnB,QAAQ,CAAC,CAAC,KAAK,EAAE,EAAE;QACjB,MAAM,GAAG,GAAG,KAAK,CAAC,WAAW,EAAE,CAAA;QAC/B,IAAI,GAAG,KAAK,GAAG;YAAE,SAAS,CAAC,SAAS,CAAC,CAAA;aAChC,IAAI,GAAG,KAAK,GAAG;YAAE,SAAS,CAAC,MAAM,CAAC,CAAA;aAClC,IAAI,GAAG,KAAK,GAAG;YAAE,SAAS,CAAC,WAAW,CAAC,CAAA;IAC9C,CAAC,CAAC,CAAA;IAEF,wEAAwE;IACxE,yEAAyE;IACzE,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;IAElC,MAAM,SAAS,GACb,cAAc,CAAC,MAAM,GAAG,CAAC;QACvB,CAAC,CAAC,kCAAkC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;QAChE,CAAC,CAAC,EAAE,CAAA;IAER,OAAO,CACL,MAAC,GAAG,IACF,aAAa,EAAC,QAAQ,EACtB,SAAS,EAAE,CAAC,EACZ,WAAW,EAAC,OAAO,EACnB,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,QAAQ,EAC/C,QAAQ,EAAE,CAAC,aAEX,MAAC,GAAG,eACF,MAAC,IAAI,IAAC,KAAK,EAAC,QAAQ,EAAC,IAAI,oCACnB,OAAO,CAAC,IAAI,IACX,EACP,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,2CAA6B,IAC3C,EACN,KAAC,GAAG,IAAC,SAAS,EAAE,CAAC,YACf,KAAC,IAAI,cAAE,SAAS,GAAQ,GACpB,EACN,MAAC,GAAG,IAAC,SAAS,EAAE,CAAC,aACf,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,oBAAW,EAC7B,KAAC,IAAI,8BAAmB,EACxB,KAAC,IAAI,IAAC,KAAK,EAAC,KAAK,oBAAW,EAC5B,KAAC,IAAI,2BAAgB,EACrB,KAAC,IAAI,IAAC,KAAK,EAAC,OAAO,oBAAW,EAC9B,MAAC,IAAI,iCAAgB,OAAO,CAAC,IAAI,qBAAqB,EACtD,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,YAAE,SAAS,GAAQ,IACjC,IACF,CACP,CAAA;AACH,CAAC,CAAA"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns a rotating character that advances every `intervalMs` while active.
|
|
3
|
+
* When inactive the timer is cleared, but the last frame stays so the caller
|
|
4
|
+
* can conditionally render it without flicker. Default 80ms — slow enough to
|
|
5
|
+
* read, fast enough to feel alive.
|
|
6
|
+
*/
|
|
7
|
+
export declare function useSpinner(active: boolean, intervalMs?: number): string;
|
|
8
|
+
/**
|
|
9
|
+
* Returns seconds elapsed since `active` became true, updating once per
|
|
10
|
+
* `tickMs`. Resets to 0 when `active` flips back to false. Use to show
|
|
11
|
+
* "streaming · 3.2s" style live counters without leaking timers.
|
|
12
|
+
*/
|
|
13
|
+
export declare function useElapsedSeconds(active: boolean, tickMs?: number): number;
|
|
14
|
+
/**
|
|
15
|
+
* Toggles between true/false on an interval. Used for cursor blink.
|
|
16
|
+
*/
|
|
17
|
+
export declare function useBlink(active: boolean, intervalMs?: number): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Returns the seconds-remaining until `targetMs` (a Date.now()-aligned ms
|
|
20
|
+
* timestamp). Returns null when target is null or in the past. Updates every
|
|
21
|
+
* second so countdown displays don't tick faster than they need to.
|
|
22
|
+
*/
|
|
23
|
+
export declare function useCountdown(targetMs: number | null): number | null;
|
|
24
|
+
//# sourceMappingURL=animations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"animations.d.ts","sourceRoot":"","sources":["../../src/repl/animations.ts"],"names":[],"mappings":"AAKA;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE,UAAU,SAAK,GAAG,MAAM,CAUnE;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,SAAM,GAAG,MAAM,CAcvE;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,UAAU,SAAM,GAAG,OAAO,CAWnE;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAgBnE"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
/** Braille dot frames — classic terminal spinner pattern. */
|
|
3
|
+
const SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
4
|
+
/**
|
|
5
|
+
* Returns a rotating character that advances every `intervalMs` while active.
|
|
6
|
+
* When inactive the timer is cleared, but the last frame stays so the caller
|
|
7
|
+
* can conditionally render it without flicker. Default 80ms — slow enough to
|
|
8
|
+
* read, fast enough to feel alive.
|
|
9
|
+
*/
|
|
10
|
+
export function useSpinner(active, intervalMs = 80) {
|
|
11
|
+
const [frame, setFrame] = useState(0);
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
if (!active)
|
|
14
|
+
return;
|
|
15
|
+
const t = setInterval(() => {
|
|
16
|
+
setFrame((f) => (f + 1) % SPINNER_FRAMES.length);
|
|
17
|
+
}, intervalMs);
|
|
18
|
+
return () => clearInterval(t);
|
|
19
|
+
}, [active, intervalMs]);
|
|
20
|
+
return SPINNER_FRAMES[frame] ?? SPINNER_FRAMES[0];
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Returns seconds elapsed since `active` became true, updating once per
|
|
24
|
+
* `tickMs`. Resets to 0 when `active` flips back to false. Use to show
|
|
25
|
+
* "streaming · 3.2s" style live counters without leaking timers.
|
|
26
|
+
*/
|
|
27
|
+
export function useElapsedSeconds(active, tickMs = 100) {
|
|
28
|
+
const [seconds, setSeconds] = useState(0);
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
if (!active) {
|
|
31
|
+
setSeconds(0);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const start = Date.now();
|
|
35
|
+
const t = setInterval(() => {
|
|
36
|
+
setSeconds((Date.now() - start) / 1000);
|
|
37
|
+
}, tickMs);
|
|
38
|
+
return () => clearInterval(t);
|
|
39
|
+
}, [active, tickMs]);
|
|
40
|
+
return seconds;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Toggles between true/false on an interval. Used for cursor blink.
|
|
44
|
+
*/
|
|
45
|
+
export function useBlink(active, intervalMs = 500) {
|
|
46
|
+
const [on, setOn] = useState(true);
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
if (!active) {
|
|
49
|
+
setOn(true);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const t = setInterval(() => setOn((v) => !v), intervalMs);
|
|
53
|
+
return () => clearInterval(t);
|
|
54
|
+
}, [active, intervalMs]);
|
|
55
|
+
return on;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Returns the seconds-remaining until `targetMs` (a Date.now()-aligned ms
|
|
59
|
+
* timestamp). Returns null when target is null or in the past. Updates every
|
|
60
|
+
* second so countdown displays don't tick faster than they need to.
|
|
61
|
+
*/
|
|
62
|
+
export function useCountdown(targetMs) {
|
|
63
|
+
const [remaining, setRemaining] = useState(null);
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
if (targetMs == null) {
|
|
66
|
+
setRemaining(null);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const update = () => {
|
|
70
|
+
const left = Math.max(0, Math.ceil((targetMs - Date.now()) / 1000));
|
|
71
|
+
setRemaining(left);
|
|
72
|
+
};
|
|
73
|
+
update();
|
|
74
|
+
const t = setInterval(update, 1000);
|
|
75
|
+
return () => clearInterval(t);
|
|
76
|
+
}, [targetMs]);
|
|
77
|
+
return remaining;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=animations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"animations.js","sourceRoot":"","sources":["../../src/repl/animations.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runRepl.d.ts","sourceRoot":"","sources":["../../src/repl/runRepl.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAGpD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAEpD,wBAAsB,OAAO,CAC3B,QAAQ,EAAE,gBAAgB,EAC1B,cAAc,CAAC,EAAE,WAAW,GAC3B,OAAO,CAAC,IAAI,CAAC,CAsCf"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { render } from 'ink';
|
|
3
|
+
import { App } from './App.js';
|
|
4
|
+
export async function runRepl(registry, initialSession) {
|
|
5
|
+
const instance = render(_jsx(App, { registry: registry, initialSession: initialSession }), {
|
|
6
|
+
exitOnCtrlC: false,
|
|
7
|
+
});
|
|
8
|
+
// External signals (SIGTERM from `kill`, SIGHUP from closing the terminal)
|
|
9
|
+
// must still clean up browser contexts and other long-lived resources. Ink's
|
|
10
|
+
// exitOnCtrlC=false means SIGINT delivered through the controlling TTY is
|
|
11
|
+
// captured by the raw-mode reader and surfaces as a Ctrl+C input event we
|
|
12
|
+
// already handle in App. The process-level handlers below cover the cases
|
|
13
|
+
// where the kernel delivers a signal directly (kill -TERM, parent shell
|
|
14
|
+
// hangup, IDE process termination, etc.).
|
|
15
|
+
let shuttingDown = false;
|
|
16
|
+
const shutdown = async (sig) => {
|
|
17
|
+
if (shuttingDown)
|
|
18
|
+
return;
|
|
19
|
+
shuttingDown = true;
|
|
20
|
+
try {
|
|
21
|
+
instance.unmount();
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
// Ink may already be unmounted.
|
|
25
|
+
}
|
|
26
|
+
await registry.closeAll().catch(() => { });
|
|
27
|
+
process.exit(sig === 'SIGINT' ? 130 : 143);
|
|
28
|
+
};
|
|
29
|
+
process.once('SIGTERM', shutdown);
|
|
30
|
+
process.once('SIGHUP', shutdown);
|
|
31
|
+
// SIGINT is normally consumed by ink's raw-mode input loop, but if the user
|
|
32
|
+
// is starting up before raw mode is established, fall back to clean exit.
|
|
33
|
+
process.once('SIGINT', shutdown);
|
|
34
|
+
try {
|
|
35
|
+
await instance.waitUntilExit();
|
|
36
|
+
}
|
|
37
|
+
finally {
|
|
38
|
+
process.removeListener('SIGTERM', shutdown);
|
|
39
|
+
process.removeListener('SIGHUP', shutdown);
|
|
40
|
+
process.removeListener('SIGINT', shutdown);
|
|
41
|
+
await registry.closeAll();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=runRepl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runRepl.js","sourceRoot":"","sources":["../../src/repl/runRepl.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAA;AAC5B,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAG9B,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,QAA0B,EAC1B,cAA4B;IAE5B,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAC,GAAG,IAAC,QAAQ,EAAE,QAAQ,EAAE,cAAc,EAAE,cAAc,GAAI,EAAE;QACnF,WAAW,EAAE,KAAK;KACnB,CAAC,CAAA;IAEF,2EAA2E;IAC3E,6EAA6E;IAC7E,0EAA0E;IAC1E,0EAA0E;IAC1E,0EAA0E;IAC1E,wEAAwE;IACxE,0CAA0C;IAC1C,IAAI,YAAY,GAAG,KAAK,CAAA;IACxB,MAAM,QAAQ,GAAG,KAAK,EAAE,GAAmB,EAAiB,EAAE;QAC5D,IAAI,YAAY;YAAE,OAAM;QACxB,YAAY,GAAG,IAAI,CAAA;QACnB,IAAI,CAAC;YACH,QAAQ,CAAC,OAAO,EAAE,CAAA;QACpB,CAAC;QAAC,MAAM,CAAC;YACP,gCAAgC;QAClC,CAAC;QACD,MAAM,QAAQ,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;QACzC,OAAO,CAAC,IAAI,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;IAC5C,CAAC,CAAA;IACD,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAA;IACjC,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAA;IAChC,4EAA4E;IAC5E,0EAA0E;IAC1E,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAA;IAEhC,IAAI,CAAC;QACH,MAAM,QAAQ,CAAC,aAAa,EAAE,CAAA;IAChC,CAAC;YAAS,CAAC;QACT,OAAO,CAAC,cAAc,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAA;QAC3C,OAAO,CAAC,cAAc,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAA;QAC1C,OAAO,CAAC,cAAc,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAA;QAC1C,MAAM,QAAQ,CAAC,QAAQ,EAAE,CAAA;IAC3B,CAAC;AACH,CAAC"}
|