centaurus-cli 3.1.3 → 3.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli-adapter.js +685 -153
- package/dist/cli-adapter.js.map +1 -1
- package/dist/config/defaultConfig.js +1 -4
- package/dist/config/defaultConfig.js.map +1 -1
- package/dist/config/models.js +4 -0
- package/dist/config/models.js.map +1 -1
- package/dist/config/slash-commands.js +66 -2
- package/dist/config/slash-commands.js.map +1 -1
- package/dist/config/types.js +4 -4
- package/dist/config/types.js.map +1 -1
- package/dist/index.js +36 -0
- package/dist/index.js.map +1 -1
- package/dist/services/ai-context-injector.js +109 -0
- package/dist/services/ai-context-injector.js.map +1 -1
- package/dist/services/api-client.js.map +1 -1
- package/dist/services/background-task-manager.js +59 -0
- package/dist/services/background-task-manager.js.map +1 -1
- package/dist/services/local-chat-storage.js +2 -0
- package/dist/services/local-chat-storage.js.map +1 -1
- package/dist/services/skill-storage.js +141 -0
- package/dist/services/skill-storage.js.map +1 -0
- package/dist/services/sub-agent-manager.js +49 -8
- package/dist/services/sub-agent-manager.js.map +1 -1
- package/dist/services/warpify-detector.js +17 -5
- package/dist/services/warpify-detector.js.map +1 -1
- package/dist/tools/background-command.js +5 -2
- package/dist/tools/background-command.js.map +1 -1
- package/dist/tools/command.js +367 -109
- package/dist/tools/command.js.map +1 -1
- package/dist/tools/file-ops.js +23 -6
- package/dist/tools/file-ops.js.map +1 -1
- package/dist/tools/plan-mode.js +184 -336
- package/dist/tools/plan-mode.js.map +1 -1
- package/dist/tools/sub-agent.js +24 -5
- package/dist/tools/sub-agent.js.map +1 -1
- package/dist/tools/todo-list.js +157 -0
- package/dist/tools/todo-list.js.map +1 -0
- package/dist/types/skill.js +30 -0
- package/dist/types/skill.js.map +1 -0
- package/dist/ui/components/App.js +956 -162
- package/dist/ui/components/App.js.map +1 -1
- package/dist/ui/components/AuthScreen.js +3 -1
- package/dist/ui/components/AuthScreen.js.map +1 -1
- package/dist/ui/components/AuthWelcomeScreen.js +3 -1
- package/dist/ui/components/AuthWelcomeScreen.js.map +1 -1
- package/dist/ui/components/CodeBlock.js +3 -1
- package/dist/ui/components/CodeBlock.js.map +1 -1
- package/dist/ui/components/CompactShellPreview.js +44 -0
- package/dist/ui/components/CompactShellPreview.js.map +1 -0
- package/dist/ui/components/ConfigViewer.js +3 -1
- package/dist/ui/components/ConfigViewer.js.map +1 -1
- package/dist/ui/components/ConfirmPrompt.js +3 -1
- package/dist/ui/components/ConfirmPrompt.js.map +1 -1
- package/dist/ui/components/ConnectionStatusMessage.js +3 -1
- package/dist/ui/components/ConnectionStatusMessage.js.map +1 -1
- package/dist/ui/components/DetailedPlanReviewScreen.js +84 -74
- package/dist/ui/components/DetailedPlanReviewScreen.js.map +1 -1
- package/dist/ui/components/DiffViewer.js +6 -3
- package/dist/ui/components/DiffViewer.js.map +1 -1
- package/dist/ui/components/FileCreationPreview.js.map +1 -1
- package/dist/ui/components/FileTagAutocomplete.js +4 -2
- package/dist/ui/components/FileTagAutocomplete.js.map +1 -1
- package/dist/ui/components/InputBox.js +243 -40
- package/dist/ui/components/InputBox.js.map +1 -1
- package/dist/ui/components/InteractiveShell.js +5 -3
- package/dist/ui/components/InteractiveShell.js.map +1 -1
- package/dist/ui/components/KeyboardHelp.js +4 -1
- package/dist/ui/components/KeyboardHelp.js.map +1 -1
- package/dist/ui/components/LoadingIndicator.js +3 -1
- package/dist/ui/components/LoadingIndicator.js.map +1 -1
- package/dist/ui/components/MCPAddScreen.js +63 -13
- package/dist/ui/components/MCPAddScreen.js.map +1 -1
- package/dist/ui/components/MarkdownRenderer.js +3 -1
- package/dist/ui/components/MarkdownRenderer.js.map +1 -1
- package/dist/ui/components/MessageDisplay.js +9 -7
- package/dist/ui/components/MessageDisplay.js.map +1 -1
- package/dist/ui/components/ModelPicker.js +170 -0
- package/dist/ui/components/ModelPicker.js.map +1 -0
- package/dist/ui/components/MonitorModeAIPanel.js +3 -1
- package/dist/ui/components/MonitorModeAIPanel.js.map +1 -1
- package/dist/ui/components/PlanAcceptedMessage.js +12 -6
- package/dist/ui/components/PlanAcceptedMessage.js.map +1 -1
- package/dist/ui/components/PlanQuestionMessage.js +37 -0
- package/dist/ui/components/PlanQuestionMessage.js.map +1 -0
- package/dist/ui/components/PlanQuestionScreen.js +138 -0
- package/dist/ui/components/PlanQuestionScreen.js.map +1 -0
- package/dist/ui/components/PlanReviewScreen.js +7 -9
- package/dist/ui/components/PlanReviewScreen.js.map +1 -1
- package/dist/ui/components/RulesEditorScreen.js +65 -28
- package/dist/ui/components/RulesEditorScreen.js.map +1 -1
- package/dist/ui/components/SelectPrompt.js +3 -1
- package/dist/ui/components/SelectPrompt.js.map +1 -1
- package/dist/ui/components/SkillCreatorScreen.js +217 -0
- package/dist/ui/components/SkillCreatorScreen.js.map +1 -0
- package/dist/ui/components/SlashCommandAutocomplete.js +4 -2
- package/dist/ui/components/SlashCommandAutocomplete.js.map +1 -1
- package/dist/ui/components/StatusBar.js +4 -2
- package/dist/ui/components/StatusBar.js.map +1 -1
- package/dist/ui/components/StreamingMessageDisplay.js +5 -3
- package/dist/ui/components/StreamingMessageDisplay.js.map +1 -1
- package/dist/ui/components/SubAgentListScreen.js +65 -0
- package/dist/ui/components/SubAgentListScreen.js.map +1 -0
- package/dist/ui/components/SubAgentViewScreen.js +123 -0
- package/dist/ui/components/SubAgentViewScreen.js.map +1 -0
- package/dist/ui/components/TaskCompletedMessage.js +40 -8
- package/dist/ui/components/TaskCompletedMessage.js.map +1 -1
- package/dist/ui/components/TaskProgressIndicator.js +6 -4
- package/dist/ui/components/TaskProgressIndicator.js.map +1 -1
- package/dist/ui/components/TextEditor.js +297 -0
- package/dist/ui/components/TextEditor.js.map +1 -0
- package/dist/ui/components/TodoListMessage.js +59 -0
- package/dist/ui/components/TodoListMessage.js.map +1 -0
- package/dist/ui/components/ToolExecutionMessage.js +134 -84
- package/dist/ui/components/ToolExecutionMessage.js.map +1 -1
- package/dist/ui/components/ToolExecutionStatus.js +3 -1
- package/dist/ui/components/ToolExecutionStatus.js.map +1 -1
- package/dist/ui/components/WelcomeBanner.js +33 -33
- package/dist/ui/components/WelcomeBanner.js.map +1 -1
- package/dist/ui/components/WorkflowCreatorScreen.js +5 -3
- package/dist/ui/components/WorkflowCreatorScreen.js.map +1 -1
- package/dist/ui/theme.js +97 -0
- package/dist/ui/theme.js.map +1 -0
- package/dist/ui/utils/chat-history-limit.js +247 -0
- package/dist/ui/utils/chat-history-limit.js.map +1 -0
- package/dist/utils/chat-formatter.js +22 -9
- package/dist/utils/chat-formatter.js.map +1 -1
- package/dist/utils/input-classifier.js +11 -1
- package/dist/utils/input-classifier.js.map +1 -1
- package/dist/utils/output-truncation.js +175 -0
- package/dist/utils/output-truncation.js.map +1 -0
- package/dist/utils/rule-reference-resolver.js +3 -3
- package/dist/utils/rule-reference-resolver.js.map +1 -1
- package/dist/utils/tunnel-commands-manager.js +134 -0
- package/dist/utils/tunnel-commands-manager.js.map +1 -0
- package/package.json +91 -90
- package/postinstall.js +4 -11
- package/dist/ui/components/MultiLineInput.js +0 -255
- package/dist/ui/components/MultiLineInput.js.map +0 -1
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import React, { useState, useEffect, useRef, useCallback } from "react";
|
|
2
|
+
import { Box, Text, useStdin } from "ink";
|
|
3
|
+
import * as readline from "readline";
|
|
4
|
+
function getVisualLines(text, w) {
|
|
5
|
+
if (w < 1) w = 1;
|
|
6
|
+
const result = [];
|
|
7
|
+
const logical = text.split("\n");
|
|
8
|
+
let off = 0;
|
|
9
|
+
for (let li = 0; li < logical.length; li++) {
|
|
10
|
+
const ln = logical[li];
|
|
11
|
+
const isLast = li === logical.length - 1;
|
|
12
|
+
if (ln.length === 0) {
|
|
13
|
+
result.push({ start: off, end: off, hard: true });
|
|
14
|
+
off += isLast ? 0 : 1;
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
let rem = ln;
|
|
18
|
+
let ls = off;
|
|
19
|
+
while (rem.length > 0) {
|
|
20
|
+
if (rem.length <= w) {
|
|
21
|
+
result.push({ start: ls, end: ls + rem.length, hard: true });
|
|
22
|
+
ls += rem.length;
|
|
23
|
+
rem = "";
|
|
24
|
+
} else {
|
|
25
|
+
let split = w;
|
|
26
|
+
const sp = rem.lastIndexOf(" ", w);
|
|
27
|
+
if (sp > 0) split = sp + 1;
|
|
28
|
+
result.push({ start: ls, end: ls + split, hard: false });
|
|
29
|
+
ls += split;
|
|
30
|
+
rem = rem.slice(split);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
off += ln.length + (isLast ? 0 : 1);
|
|
34
|
+
}
|
|
35
|
+
if (result.length === 0) {
|
|
36
|
+
result.push({ start: 0, end: 0, hard: true });
|
|
37
|
+
}
|
|
38
|
+
return result;
|
|
39
|
+
}
|
|
40
|
+
function lineOf(vl, pos) {
|
|
41
|
+
for (let i = vl.length - 1; i >= 0; i--) {
|
|
42
|
+
if (pos >= vl[i].start) return i;
|
|
43
|
+
}
|
|
44
|
+
return 0;
|
|
45
|
+
}
|
|
46
|
+
function wbLeft(t, p) {
|
|
47
|
+
if (p <= 0) return 0;
|
|
48
|
+
let i = p - 1;
|
|
49
|
+
while (i > 0 && /[\s\n]/.test(t[i])) i--;
|
|
50
|
+
while (i > 0 && !/[\s\n]/.test(t[i - 1])) i--;
|
|
51
|
+
return Math.max(0, i);
|
|
52
|
+
}
|
|
53
|
+
function wbRight(t, p) {
|
|
54
|
+
const n = t.length;
|
|
55
|
+
if (p >= n) return n;
|
|
56
|
+
let i = p;
|
|
57
|
+
while (i < n && !/[\s\n]/.test(t[i])) i++;
|
|
58
|
+
while (i < n && /[\s\n]/.test(t[i])) i++;
|
|
59
|
+
return i;
|
|
60
|
+
}
|
|
61
|
+
const TextEditor = ({
|
|
62
|
+
value,
|
|
63
|
+
onChange,
|
|
64
|
+
placeholder = "",
|
|
65
|
+
isActive = true,
|
|
66
|
+
minHeight = 3,
|
|
67
|
+
maxHeight = 15,
|
|
68
|
+
tabHandledExternally = false,
|
|
69
|
+
width: widthProp
|
|
70
|
+
}) => {
|
|
71
|
+
const { stdin, setRawMode } = useStdin();
|
|
72
|
+
const valRef = useRef(value);
|
|
73
|
+
const curRef = useRef(value.length);
|
|
74
|
+
const stickyRef = useRef(null);
|
|
75
|
+
const undoRef = useRef([]);
|
|
76
|
+
const activeRef = useRef(isActive);
|
|
77
|
+
const widthRef = useRef(widthProp || Math.max(20, (process.stdout.columns || 80) - 10));
|
|
78
|
+
const tabExternalRef = useRef(tabHandledExternally);
|
|
79
|
+
const onChangeRef = useRef(onChange);
|
|
80
|
+
const emitInitRef = useRef(false);
|
|
81
|
+
useEffect(() => {
|
|
82
|
+
activeRef.current = isActive;
|
|
83
|
+
}, [isActive]);
|
|
84
|
+
useEffect(() => {
|
|
85
|
+
tabExternalRef.current = tabHandledExternally;
|
|
86
|
+
}, [tabHandledExternally]);
|
|
87
|
+
useEffect(() => {
|
|
88
|
+
onChangeRef.current = onChange;
|
|
89
|
+
}, [onChange]);
|
|
90
|
+
useEffect(() => {
|
|
91
|
+
widthRef.current = widthProp || Math.max(20, (process.stdout.columns || 80) - 10);
|
|
92
|
+
}, [widthProp]);
|
|
93
|
+
const [, setTick] = useState(0);
|
|
94
|
+
const rerender = useCallback(() => setTick((t) => t + 1), []);
|
|
95
|
+
useEffect(() => {
|
|
96
|
+
if (value !== valRef.current) {
|
|
97
|
+
valRef.current = value;
|
|
98
|
+
if (curRef.current > value.length) curRef.current = value.length;
|
|
99
|
+
rerender();
|
|
100
|
+
}
|
|
101
|
+
}, [value, rerender]);
|
|
102
|
+
const pushUndo = () => {
|
|
103
|
+
undoRef.current = [...undoRef.current.slice(-50), { v: valRef.current, c: curRef.current }];
|
|
104
|
+
};
|
|
105
|
+
const apply = useCallback((nv, nc) => {
|
|
106
|
+
valRef.current = nv;
|
|
107
|
+
curRef.current = Math.max(0, Math.min(nc, nv.length));
|
|
108
|
+
stickyRef.current = null;
|
|
109
|
+
onChangeRef.current(nv);
|
|
110
|
+
rerender();
|
|
111
|
+
}, [rerender]);
|
|
112
|
+
const moveCursor = useCallback((nc) => {
|
|
113
|
+
curRef.current = Math.max(0, Math.min(nc, valRef.current.length));
|
|
114
|
+
stickyRef.current = null;
|
|
115
|
+
rerender();
|
|
116
|
+
}, [rerender]);
|
|
117
|
+
const moveCursorSticky = useCallback((nc, col) => {
|
|
118
|
+
curRef.current = Math.max(0, Math.min(nc, valRef.current.length));
|
|
119
|
+
if (stickyRef.current === null) stickyRef.current = col;
|
|
120
|
+
rerender();
|
|
121
|
+
}, [rerender]);
|
|
122
|
+
useEffect(() => {
|
|
123
|
+
if (!stdin) return;
|
|
124
|
+
setRawMode(true);
|
|
125
|
+
if (!emitInitRef.current) {
|
|
126
|
+
readline.emitKeypressEvents(stdin);
|
|
127
|
+
emitInitRef.current = true;
|
|
128
|
+
}
|
|
129
|
+
const handler = (_str, key) => {
|
|
130
|
+
if (!activeRef.current || !key) return;
|
|
131
|
+
const v2 = valRef.current;
|
|
132
|
+
const c2 = curRef.current;
|
|
133
|
+
const W2 = widthRef.current;
|
|
134
|
+
const vl2 = getVisualLines(v2, W2);
|
|
135
|
+
const li = lineOf(vl2, c2);
|
|
136
|
+
const ln = vl2[li];
|
|
137
|
+
const col = c2 - (ln?.start ?? 0);
|
|
138
|
+
const name = key.name || "";
|
|
139
|
+
const ctrl = !!key.ctrl;
|
|
140
|
+
const meta = !!key.meta;
|
|
141
|
+
const shift = !!key.shift;
|
|
142
|
+
if (meta && name === "b") {
|
|
143
|
+
moveCursor(wbLeft(v2, c2));
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
if (meta && name === "f") {
|
|
147
|
+
moveCursor(wbRight(v2, c2));
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
if (name === "left") {
|
|
151
|
+
if (ctrl || meta) moveCursor(wbLeft(v2, c2));
|
|
152
|
+
else moveCursor(c2 - 1);
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
if (name === "right") {
|
|
156
|
+
if (ctrl || meta) moveCursor(wbRight(v2, c2));
|
|
157
|
+
else moveCursor(c2 + 1);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
if (name === "up" && li > 0) {
|
|
161
|
+
const tgt = vl2[li - 1];
|
|
162
|
+
const sc = stickyRef.current ?? col;
|
|
163
|
+
moveCursorSticky(tgt.start + Math.min(sc, tgt.end - tgt.start), col);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
if (name === "down" && li < vl2.length - 1) {
|
|
167
|
+
const tgt = vl2[li + 1];
|
|
168
|
+
const sc = stickyRef.current ?? col;
|
|
169
|
+
moveCursorSticky(tgt.start + Math.min(sc, tgt.end - tgt.start), col);
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
if (name === "up" || name === "down") return;
|
|
173
|
+
if (name === "home" || ctrl && name === "a") {
|
|
174
|
+
moveCursor(ln?.start ?? 0);
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
if (name === "end" || ctrl && name === "e") {
|
|
178
|
+
moveCursor(ln?.end ?? v2.length);
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
if (meta && name === "backspace") {
|
|
182
|
+
if (c2 > 0) {
|
|
183
|
+
pushUndo();
|
|
184
|
+
const ws = wbLeft(v2, c2);
|
|
185
|
+
apply(v2.slice(0, ws) + v2.slice(c2), ws);
|
|
186
|
+
}
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
if (name === "backspace") {
|
|
190
|
+
if (c2 > 0) {
|
|
191
|
+
pushUndo();
|
|
192
|
+
apply(v2.slice(0, c2 - 1) + v2.slice(c2), c2 - 1);
|
|
193
|
+
}
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
if (name === "delete" || ctrl && name === "d") {
|
|
197
|
+
if (c2 < v2.length) {
|
|
198
|
+
pushUndo();
|
|
199
|
+
apply(v2.slice(0, c2) + v2.slice(c2 + 1), c2);
|
|
200
|
+
}
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
if (ctrl && name === "k" && ln) {
|
|
204
|
+
pushUndo();
|
|
205
|
+
if (c2 >= ln.end && c2 < v2.length && v2[c2] === "\n") {
|
|
206
|
+
apply(v2.slice(0, c2) + v2.slice(c2 + 1), c2);
|
|
207
|
+
} else {
|
|
208
|
+
apply(v2.slice(0, c2) + v2.slice(ln.end), c2);
|
|
209
|
+
}
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
if (ctrl && name === "u" && ln) {
|
|
213
|
+
pushUndo();
|
|
214
|
+
apply(v2.slice(0, ln.start) + v2.slice(c2), ln.start);
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
if (ctrl && name === "w" && c2 > 0) {
|
|
218
|
+
pushUndo();
|
|
219
|
+
const ws = wbLeft(v2, c2);
|
|
220
|
+
apply(v2.slice(0, ws) + v2.slice(c2), ws);
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
if (ctrl && name === "z") {
|
|
224
|
+
const stack = undoRef.current;
|
|
225
|
+
if (stack.length > 0) {
|
|
226
|
+
const prev = stack[stack.length - 1];
|
|
227
|
+
undoRef.current = stack.slice(0, -1);
|
|
228
|
+
apply(prev.v, prev.c);
|
|
229
|
+
}
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
if (name === "return") {
|
|
233
|
+
pushUndo();
|
|
234
|
+
apply(v2.slice(0, c2) + "\n" + v2.slice(c2), c2 + 1);
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
if (!name && _str && (_str === "\x1B\r" || _str === "\x1B\n")) {
|
|
238
|
+
pushUndo();
|
|
239
|
+
apply(v2.slice(0, c2) + "\n" + v2.slice(c2), c2 + 1);
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
if (name === "tab") {
|
|
243
|
+
if (!tabExternalRef.current) {
|
|
244
|
+
pushUndo();
|
|
245
|
+
apply(v2.slice(0, c2) + " " + v2.slice(c2), c2 + 2);
|
|
246
|
+
}
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
if (name === "escape") return;
|
|
250
|
+
if (ctrl || meta) return;
|
|
251
|
+
const ch = key.sequence || _str;
|
|
252
|
+
if (ch && ch.length > 0 && ch.charCodeAt(0) >= 32) {
|
|
253
|
+
pushUndo();
|
|
254
|
+
const txt = ch.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
255
|
+
apply(v2.slice(0, c2) + txt + v2.slice(c2), c2 + txt.length);
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
stdin.on("keypress", handler);
|
|
259
|
+
return () => {
|
|
260
|
+
stdin.off("keypress", handler);
|
|
261
|
+
};
|
|
262
|
+
}, [stdin, setRawMode, apply, moveCursor, moveCursorSticky, rerender]);
|
|
263
|
+
const v = valRef.current;
|
|
264
|
+
const c = curRef.current;
|
|
265
|
+
const W = widthRef.current;
|
|
266
|
+
const vl = getVisualLines(v, W);
|
|
267
|
+
const total = vl.length;
|
|
268
|
+
const curLine = lineOf(vl, c);
|
|
269
|
+
const vpH = Math.min(Math.max(total, minHeight), maxHeight);
|
|
270
|
+
let start = 0;
|
|
271
|
+
if (curLine >= start + vpH) start = curLine - vpH + 1;
|
|
272
|
+
if (curLine < start) start = curLine;
|
|
273
|
+
const end = Math.min(start + vpH, total);
|
|
274
|
+
const empty = v.length === 0;
|
|
275
|
+
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, start > 0 && /* @__PURE__ */ React.createElement(Text, { color: "#555" }, "\u2191 ", start, " more"), Array.from({ length: vpH }, (_, vi) => {
|
|
276
|
+
const idx = start + vi;
|
|
277
|
+
if (idx >= total) return /* @__PURE__ */ React.createElement(Text, { key: `f${vi}` }, " ");
|
|
278
|
+
const ln = vl[idx];
|
|
279
|
+
const text = v.slice(ln.start, ln.end);
|
|
280
|
+
const isCur = idx === curLine;
|
|
281
|
+
const cc = c - ln.start;
|
|
282
|
+
if (empty && idx === 0) {
|
|
283
|
+
return /* @__PURE__ */ React.createElement(Text, { key: "ph" }, /* @__PURE__ */ React.createElement(Text, { inverse: true }, " "), /* @__PURE__ */ React.createElement(Text, { color: "#555" }, placeholder));
|
|
284
|
+
}
|
|
285
|
+
if (!isCur) {
|
|
286
|
+
return /* @__PURE__ */ React.createElement(Text, { key: `l${idx}` }, text || " ");
|
|
287
|
+
}
|
|
288
|
+
const before = text.slice(0, cc);
|
|
289
|
+
const cursorChar = cc < text.length ? text[cc] : " ";
|
|
290
|
+
const after = cc < text.length ? text.slice(cc + 1) : "";
|
|
291
|
+
return /* @__PURE__ */ React.createElement(Text, { key: `l${idx}` }, before, /* @__PURE__ */ React.createElement(Text, { inverse: true }, cursorChar), after);
|
|
292
|
+
}), end < total && /* @__PURE__ */ React.createElement(Text, { color: "#555" }, "\u2193 ", total - end, " more"));
|
|
293
|
+
};
|
|
294
|
+
export {
|
|
295
|
+
TextEditor
|
|
296
|
+
};
|
|
297
|
+
//# sourceMappingURL=TextEditor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/ui/components/TextEditor.tsx"],"sourcesContent":["/**\r\n * TextEditor — A robust multi-line text editor component for Ink.\r\n *\r\n * Uses raw stdin via readline.emitKeypressEvents for reliable key detection\r\n * instead of Ink's useInput which has limitations with modifier combos.\r\n *\r\n * Key bindings:\r\n * ← / → Move cursor left/right\r\n * ↑ / ↓ Move cursor up/down (visual lines, sticky column)\r\n * Ctrl+← / Ctrl+→ Word jump (also Option+← / Option+→ on macOS)\r\n * Ctrl+A / Home Start of line\r\n * Ctrl+E / End End of line\r\n * Enter Insert newline\r\n * Backspace Delete char before cursor\r\n * Delete / Ctrl+D Forward-delete\r\n * Ctrl+K Kill to end of line\r\n * Ctrl+U Kill to start of line\r\n * Ctrl+W Delete word back\r\n * Ctrl+Z Undo\r\n * Tab Insert 2 spaces (configurable)\r\n */\r\n\r\nimport React, { useState, useEffect, useRef, useCallback } from 'react';\r\nimport { Box, Text, useStdin } from 'ink';\r\nimport * as readline from 'readline';\r\n\r\ninterface TextEditorProps {\r\n value: string;\r\n onChange: (value: string) => void;\r\n placeholder?: string;\r\n isActive?: boolean;\r\n minHeight?: number;\r\n maxHeight?: number;\r\n tabHandledExternally?: boolean;\r\n width?: number;\r\n}\r\n\r\n// ── Visual line computation ──────────────────────────────────────────\r\n\r\ninterface VLine {\r\n start: number;\r\n end: number;\r\n hard: boolean;\r\n}\r\n\r\nfunction getVisualLines(text: string, w: number): VLine[] {\r\n if (w < 1) w = 1;\r\n const result: VLine[] = [];\r\n const logical = text.split('\\n');\r\n let off = 0;\r\n\r\n for (let li = 0; li < logical.length; li++) {\r\n const ln = logical[li];\r\n const isLast = li === logical.length - 1;\r\n\r\n if (ln.length === 0) {\r\n result.push({ start: off, end: off, hard: true });\r\n off += isLast ? 0 : 1;\r\n continue;\r\n }\r\n\r\n let rem = ln;\r\n let ls = off;\r\n while (rem.length > 0) {\r\n if (rem.length <= w) {\r\n result.push({ start: ls, end: ls + rem.length, hard: true });\r\n ls += rem.length;\r\n rem = '';\r\n } else {\r\n let split = w;\r\n const sp = rem.lastIndexOf(' ', w);\r\n if (sp > 0) split = sp + 1;\r\n result.push({ start: ls, end: ls + split, hard: false });\r\n ls += split;\r\n rem = rem.slice(split);\r\n }\r\n }\r\n\r\n off += ln.length + (isLast ? 0 : 1);\r\n }\r\n\r\n if (result.length === 0) {\r\n result.push({ start: 0, end: 0, hard: true });\r\n }\r\n\r\n return result;\r\n}\r\n\r\nfunction lineOf(vl: VLine[], pos: number): number {\r\n for (let i = vl.length - 1; i >= 0; i--) {\r\n if (pos >= vl[i].start) return i;\r\n }\r\n return 0;\r\n}\r\n\r\n// ── Word boundaries ──────────────────────────────────────────────────\r\n\r\nfunction wbLeft(t: string, p: number): number {\r\n if (p <= 0) return 0;\r\n let i = p - 1;\r\n while (i > 0 && /[\\s\\n]/.test(t[i])) i--;\r\n while (i > 0 && !/[\\s\\n]/.test(t[i - 1])) i--;\r\n return Math.max(0, i);\r\n}\r\n\r\nfunction wbRight(t: string, p: number): number {\r\n const n = t.length;\r\n if (p >= n) return n;\r\n let i = p;\r\n while (i < n && !/[\\s\\n]/.test(t[i])) i++;\r\n while (i < n && /[\\s\\n]/.test(t[i])) i++;\r\n return i;\r\n}\r\n\r\n// ── Component ────────────────────────────────────────────────────────\r\n\r\nexport const TextEditor: React.FC<TextEditorProps> = ({\r\n value,\r\n onChange,\r\n placeholder = '',\r\n isActive = true,\r\n minHeight = 3,\r\n maxHeight = 15,\r\n tabHandledExternally = false,\r\n width: widthProp,\r\n}) => {\r\n const { stdin, setRawMode } = useStdin();\r\n\r\n // Refs for authoritative state (avoids stale closures)\r\n const valRef = useRef(value);\r\n const curRef = useRef(value.length);\r\n const stickyRef = useRef<number | null>(null);\r\n const undoRef = useRef<Array<{ v: string; c: number }>>([]);\r\n const activeRef = useRef(isActive);\r\n const widthRef = useRef(widthProp || Math.max(20, (process.stdout.columns || 80) - 10));\r\n const tabExternalRef = useRef(tabHandledExternally);\r\n const onChangeRef = useRef(onChange);\r\n const emitInitRef = useRef(false);\r\n\r\n // Keep refs in sync\r\n useEffect(() => { activeRef.current = isActive; }, [isActive]);\r\n useEffect(() => { tabExternalRef.current = tabHandledExternally; }, [tabHandledExternally]);\r\n useEffect(() => { onChangeRef.current = onChange; }, [onChange]);\r\n useEffect(() => {\r\n widthRef.current = widthProp || Math.max(20, (process.stdout.columns || 80) - 10);\r\n }, [widthProp]);\r\n\r\n // Render-trigger\r\n const [, setTick] = useState(0);\r\n const rerender = useCallback(() => setTick(t => t + 1), []);\r\n\r\n // Sync prop → ref when parent changes value externally\r\n useEffect(() => {\r\n if (value !== valRef.current) {\r\n valRef.current = value;\r\n if (curRef.current > value.length) curRef.current = value.length;\r\n rerender();\r\n }\r\n }, [value, rerender]);\r\n\r\n // ── Helpers ──\r\n\r\n const pushUndo = () => {\r\n undoRef.current = [...undoRef.current.slice(-50), { v: valRef.current, c: curRef.current }];\r\n };\r\n\r\n const apply = useCallback((nv: string, nc: number) => {\r\n valRef.current = nv;\r\n curRef.current = Math.max(0, Math.min(nc, nv.length));\r\n stickyRef.current = null;\r\n onChangeRef.current(nv);\r\n rerender();\r\n }, [rerender]);\r\n\r\n const moveCursor = useCallback((nc: number) => {\r\n curRef.current = Math.max(0, Math.min(nc, valRef.current.length));\r\n stickyRef.current = null;\r\n rerender();\r\n }, [rerender]);\r\n\r\n const moveCursorSticky = useCallback((nc: number, col: number) => {\r\n curRef.current = Math.max(0, Math.min(nc, valRef.current.length));\r\n if (stickyRef.current === null) stickyRef.current = col;\r\n rerender();\r\n }, [rerender]);\r\n\r\n // ── Raw stdin keypress handler ──\r\n\r\n useEffect(() => {\r\n if (!stdin) return;\r\n\r\n setRawMode(true);\r\n\r\n // Only call emitKeypressEvents once per stdin stream\r\n if (!emitInitRef.current) {\r\n readline.emitKeypressEvents(stdin);\r\n emitInitRef.current = true;\r\n }\r\n\r\n const handler = (_str: string | undefined, key: any) => {\r\n if (!activeRef.current || !key) return;\r\n\r\n const v = valRef.current;\r\n const c = curRef.current;\r\n const W = widthRef.current;\r\n const vl = getVisualLines(v, W);\r\n const li = lineOf(vl, c);\r\n const ln = vl[li];\r\n const col = c - (ln?.start ?? 0);\r\n\r\n const name = key.name || '';\r\n const ctrl = !!key.ctrl;\r\n const meta = !!key.meta;\r\n const shift = !!key.shift;\r\n\r\n // ── Navigation ──\r\n\r\n // macOS Option+Left sends ESC+b (meta+b = word-back)\r\n // macOS Option+Right sends ESC+f (meta+f = word-forward)\r\n if (meta && name === 'b') { moveCursor(wbLeft(v, c)); return; }\r\n if (meta && name === 'f') { moveCursor(wbRight(v, c)); return; }\r\n\r\n if (name === 'left') {\r\n if (ctrl || meta) moveCursor(wbLeft(v, c));\r\n else moveCursor(c - 1);\r\n return;\r\n }\r\n if (name === 'right') {\r\n if (ctrl || meta) moveCursor(wbRight(v, c));\r\n else moveCursor(c + 1);\r\n return;\r\n }\r\n if (name === 'up' && li > 0) {\r\n const tgt = vl[li - 1];\r\n const sc = stickyRef.current ?? col;\r\n moveCursorSticky(tgt.start + Math.min(sc, tgt.end - tgt.start), col);\r\n return;\r\n }\r\n if (name === 'down' && li < vl.length - 1) {\r\n const tgt = vl[li + 1];\r\n const sc = stickyRef.current ?? col;\r\n moveCursorSticky(tgt.start + Math.min(sc, tgt.end - tgt.start), col);\r\n return;\r\n }\r\n if (name === 'up' || name === 'down') return;\r\n\r\n // Home / End (actual keys + Ctrl+A/E)\r\n if (name === 'home' || (ctrl && name === 'a')) {\r\n moveCursor(ln?.start ?? 0);\r\n return;\r\n }\r\n if (name === 'end' || (ctrl && name === 'e')) {\r\n moveCursor(ln?.end ?? v.length);\r\n return;\r\n }\r\n\r\n // ── Deletion ──\r\n\r\n // Option+Backspace (meta+backspace) — delete word back\r\n if (meta && name === 'backspace') {\r\n if (c > 0) { pushUndo(); const ws = wbLeft(v, c); apply(v.slice(0, ws) + v.slice(c), ws); }\r\n return;\r\n }\r\n\r\n if (name === 'backspace') {\r\n if (c > 0) { pushUndo(); apply(v.slice(0, c - 1) + v.slice(c), c - 1); }\r\n return;\r\n }\r\n if (name === 'delete' || (ctrl && name === 'd')) {\r\n if (c < v.length) { pushUndo(); apply(v.slice(0, c) + v.slice(c + 1), c); }\r\n return;\r\n }\r\n // Ctrl+K — kill to EOL\r\n if (ctrl && name === 'k' && ln) {\r\n pushUndo();\r\n if (c >= ln.end && c < v.length && v[c] === '\\n') {\r\n apply(v.slice(0, c) + v.slice(c + 1), c);\r\n } else {\r\n apply(v.slice(0, c) + v.slice(ln.end), c);\r\n }\r\n return;\r\n }\r\n // Ctrl+U — kill to BOL\r\n if (ctrl && name === 'u' && ln) {\r\n pushUndo();\r\n apply(v.slice(0, ln.start) + v.slice(c), ln.start);\r\n return;\r\n }\r\n // Ctrl+W — delete word back\r\n if (ctrl && name === 'w' && c > 0) {\r\n pushUndo();\r\n const ws = wbLeft(v, c);\r\n apply(v.slice(0, ws) + v.slice(c), ws);\r\n return;\r\n }\r\n\r\n // Ctrl+Z — undo\r\n if (ctrl && name === 'z') {\r\n const stack = undoRef.current;\r\n if (stack.length > 0) {\r\n const prev = stack[stack.length - 1];\r\n undoRef.current = stack.slice(0, -1);\r\n apply(prev.v, prev.c);\r\n }\r\n return;\r\n }\r\n\r\n // ── Insertion ──\r\n\r\n // Enter / Return — insert newline\r\n // Also handle Shift+Enter (some terminals send this as a different sequence)\r\n if (name === 'return') {\r\n pushUndo();\r\n apply(v.slice(0, c) + '\\n' + v.slice(c), c + 1);\r\n return;\r\n }\r\n\r\n // Catch Shift+Enter / Ctrl+Enter raw sequences that some terminals send\r\n // These may come through as raw _str without a proper key.name\r\n if (!name && _str && (_str === '\\x1b\\r' || _str === '\\x1b\\n')) {\r\n pushUndo();\r\n apply(v.slice(0, c) + '\\n' + v.slice(c), c + 1);\r\n return;\r\n }\r\n\r\n // Tab\r\n if (name === 'tab') {\r\n if (!tabExternalRef.current) {\r\n pushUndo();\r\n apply(v.slice(0, c) + ' ' + v.slice(c), c + 2);\r\n }\r\n return;\r\n }\r\n\r\n // Escape — let parent handle\r\n if (name === 'escape') return;\r\n\r\n // Skip other ctrl/meta combos\r\n if (ctrl || meta) return;\r\n\r\n // Regular character — use the sequence which contains the actual typed char(s)\r\n const ch = key.sequence || _str;\r\n if (ch && ch.length > 0 && ch.charCodeAt(0) >= 32) {\r\n pushUndo();\r\n const txt = ch.replace(/\\r\\n/g, '\\n').replace(/\\r/g, '\\n');\r\n apply(v.slice(0, c) + txt + v.slice(c), c + txt.length);\r\n }\r\n };\r\n\r\n stdin.on('keypress', handler);\r\n return () => {\r\n stdin.off('keypress', handler);\r\n };\r\n }, [stdin, setRawMode, apply, moveCursor, moveCursorSticky, rerender]);\r\n\r\n // ── Render ──\r\n\r\n const v = valRef.current;\r\n const c = curRef.current;\r\n const W = widthRef.current;\r\n const vl = getVisualLines(v, W);\r\n const total = vl.length;\r\n const curLine = lineOf(vl, c);\r\n const vpH = Math.min(Math.max(total, minHeight), maxHeight);\r\n\r\n let start = 0;\r\n if (curLine >= start + vpH) start = curLine - vpH + 1;\r\n if (curLine < start) start = curLine;\r\n const end = Math.min(start + vpH, total);\r\n\r\n const empty = v.length === 0;\r\n\r\n return (\r\n <Box flexDirection=\"column\">\r\n {start > 0 && <Text color=\"#555\">↑ {start} more</Text>}\r\n {Array.from({ length: vpH }, (_, vi) => {\r\n const idx = start + vi;\r\n if (idx >= total) return <Text key={`f${vi}`}> </Text>;\r\n\r\n const ln = vl[idx];\r\n const text = v.slice(ln.start, ln.end);\r\n const isCur = idx === curLine;\r\n const cc = c - ln.start;\r\n\r\n if (empty && idx === 0) {\r\n return (\r\n <Text key=\"ph\">\r\n <Text inverse> </Text>\r\n <Text color=\"#555\">{placeholder}</Text>\r\n </Text>\r\n );\r\n }\r\n\r\n if (!isCur) {\r\n return <Text key={`l${idx}`}>{text || ' '}</Text>;\r\n }\r\n\r\n const before = text.slice(0, cc);\r\n const cursorChar = cc < text.length ? text[cc] : ' ';\r\n const after = cc < text.length ? text.slice(cc + 1) : '';\r\n\r\n return (\r\n <Text key={`l${idx}`}>\r\n {before}<Text inverse>{cursorChar}</Text>{after}\r\n </Text>\r\n );\r\n })}\r\n {end < total && <Text color=\"#555\">↓ {total - end} more</Text>}\r\n </Box>\r\n );\r\n};\r\n"],"mappings":"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","names":["v","c","W","vl"]}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Box, Text } from "ink";
|
|
3
|
+
import { useTheme } from "../theme.js";
|
|
4
|
+
const TodoListMessage = ({
|
|
5
|
+
todos,
|
|
6
|
+
completedCount,
|
|
7
|
+
totalCount
|
|
8
|
+
}) => {
|
|
9
|
+
const theme = useTheme();
|
|
10
|
+
return /* @__PURE__ */ React.createElement(
|
|
11
|
+
Box,
|
|
12
|
+
{
|
|
13
|
+
flexDirection: "column",
|
|
14
|
+
borderStyle: "round",
|
|
15
|
+
borderColor: theme.accent,
|
|
16
|
+
paddingX: 1,
|
|
17
|
+
paddingY: 0,
|
|
18
|
+
marginY: 0,
|
|
19
|
+
alignSelf: "flex-start"
|
|
20
|
+
},
|
|
21
|
+
/* @__PURE__ */ React.createElement(Box, { marginBottom: 0 }, /* @__PURE__ */ React.createElement(Text, { color: theme.accent, bold: true }, "\u2630", " Todo List"), /* @__PURE__ */ React.createElement(Text, { color: "#888888" }, " ", "\u2014", " ", completedCount, "/", totalCount, " completed")),
|
|
22
|
+
todos && todos.length > 0 && /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginTop: 0 }, todos.map((item, index) => {
|
|
23
|
+
const isCompleted = item.status === "completed";
|
|
24
|
+
const isInProgress = item.status === "in_progress";
|
|
25
|
+
let marker;
|
|
26
|
+
if (isCompleted) {
|
|
27
|
+
marker = /* @__PURE__ */ React.createElement(Text, { color: "#00cc66" }, "\u2713", " ");
|
|
28
|
+
} else if (isInProgress) {
|
|
29
|
+
marker = /* @__PURE__ */ React.createElement(Text, { color: "#f59e0b" }, "\u25D4", " ");
|
|
30
|
+
} else {
|
|
31
|
+
marker = /* @__PURE__ */ React.createElement(Text, { color: "#555555" }, " ");
|
|
32
|
+
}
|
|
33
|
+
let textColor;
|
|
34
|
+
if (isCompleted) {
|
|
35
|
+
textColor = "#888888";
|
|
36
|
+
} else if (isInProgress) {
|
|
37
|
+
textColor = "#f59e0b";
|
|
38
|
+
} else {
|
|
39
|
+
textColor = "#555555";
|
|
40
|
+
}
|
|
41
|
+
return /* @__PURE__ */ React.createElement(Box, { key: item.id }, marker, /* @__PURE__ */ React.createElement(
|
|
42
|
+
Text,
|
|
43
|
+
{
|
|
44
|
+
color: textColor,
|
|
45
|
+
wrap: "truncate-end"
|
|
46
|
+
},
|
|
47
|
+
index + 1,
|
|
48
|
+
". ",
|
|
49
|
+
item.content
|
|
50
|
+
));
|
|
51
|
+
}))
|
|
52
|
+
);
|
|
53
|
+
};
|
|
54
|
+
var TodoListMessage_default = TodoListMessage;
|
|
55
|
+
export {
|
|
56
|
+
TodoListMessage,
|
|
57
|
+
TodoListMessage_default as default
|
|
58
|
+
};
|
|
59
|
+
//# sourceMappingURL=TodoListMessage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/ui/components/TodoListMessage.tsx"],"sourcesContent":["/**\r\n * TodoListMessage Component\r\n * Displays the AI's todo list with status markers for each item.\r\n * - Completed items get a green tick mark\r\n * - In-progress items get a yellow spinner marker\r\n * - Pending items have a dim dot marker\r\n * Wrapped in a bordered box for visual consistency in the chat.\r\n * Uses the same visual style as the plan mode task list.\r\n */\r\n\r\nimport React from 'react';\r\nimport { Box, Text } from 'ink';\r\nimport { useTheme } from '../theme.js';\r\n\r\ninterface TodoItemStatus {\r\n id: string;\r\n content: string;\r\n status: 'pending' | 'in_progress' | 'completed';\r\n}\r\n\r\ninterface TodoListMessageProps {\r\n todos: TodoItemStatus[];\r\n completedCount: number;\r\n totalCount: number;\r\n}\r\n\r\nexport const TodoListMessage: React.FC<TodoListMessageProps> = ({\r\n todos,\r\n completedCount,\r\n totalCount,\r\n}) => {\r\n const theme = useTheme();\r\n\r\n return (\r\n <Box\r\n flexDirection=\"column\"\r\n borderStyle=\"round\"\r\n borderColor={theme.accent}\r\n paddingX={1}\r\n paddingY={0}\r\n marginY={0}\r\n alignSelf=\"flex-start\"\r\n >\r\n {/* Header */}\r\n <Box marginBottom={0}>\r\n <Text color={theme.accent} bold>{'☰'} Todo List</Text>\r\n <Text color=\"#888888\"> {'\\u2014'} {completedCount}/{totalCount} completed</Text>\r\n </Box>\r\n\r\n {/* Todo Items List */}\r\n {todos && todos.length > 0 && (\r\n <Box flexDirection=\"column\" marginTop={0}>\r\n {todos.map((item, index) => {\r\n const isCompleted = item.status === 'completed';\r\n const isInProgress = item.status === 'in_progress';\r\n\r\n let marker: React.ReactNode;\r\n if (isCompleted) {\r\n marker = <Text color=\"#00cc66\">{'\\u2713'} </Text>;\r\n } else if (isInProgress) {\r\n marker = <Text color=\"#f59e0b\">{'\\u25D4'} </Text>;\r\n } else {\r\n marker = <Text color=\"#555555\">{' '}</Text>;\r\n }\r\n\r\n let textColor: string;\r\n if (isCompleted) {\r\n textColor = '#888888';\r\n } else if (isInProgress) {\r\n textColor = '#f59e0b';\r\n } else {\r\n textColor = '#555555';\r\n }\r\n\r\n return (\r\n <Box key={item.id}>\r\n {marker}\r\n <Text\r\n color={textColor}\r\n wrap=\"truncate-end\"\r\n >\r\n {index + 1}. {item.content}\r\n </Text>\r\n </Box>\r\n );\r\n })}\r\n </Box>\r\n )}\r\n </Box>\r\n );\r\n};\r\n\r\nexport default TodoListMessage;\r\n"],"mappings":"AAUA,OAAO,WAAW;AAClB,SAAS,KAAK,YAAY;AAC1B,SAAS,gBAAgB;AAclB,MAAM,kBAAkD,CAAC;AAAA,EAC5D;AAAA,EACA;AAAA,EACA;AACJ,MAAM;AACF,QAAM,QAAQ,SAAS;AAEvB,SACI;AAAA,IAAC;AAAA;AAAA,MACG,eAAc;AAAA,MACd,aAAY;AAAA,MACZ,aAAa,MAAM;AAAA,MACnB,UAAU;AAAA,MACV,UAAU;AAAA,MACV,SAAS;AAAA,MACT,WAAU;AAAA;AAAA,IAGV,oCAAC,OAAI,cAAc,KACf,oCAAC,QAAK,OAAO,MAAM,QAAQ,MAAI,QAAE,UAAI,YAAU,GAC/C,oCAAC,QAAK,OAAM,aAAU,KAAE,UAAS,KAAE,gBAAe,KAAE,YAAW,YAAU,CAC7E;AAAA,IAGC,SAAS,MAAM,SAAS,KACrB,oCAAC,OAAI,eAAc,UAAS,WAAW,KAClC,MAAM,IAAI,CAAC,MAAM,UAAU;AACxB,YAAM,cAAc,KAAK,WAAW;AACpC,YAAM,eAAe,KAAK,WAAW;AAErC,UAAI;AACJ,UAAI,aAAa;AACb,iBAAS,oCAAC,QAAK,OAAM,aAAW,UAAS,GAAC;AAAA,MAC9C,WAAW,cAAc;AACrB,iBAAS,oCAAC,QAAK,OAAM,aAAW,UAAS,GAAC;AAAA,MAC9C,OAAO;AACH,iBAAS,oCAAC,QAAK,OAAM,aAAW,IAAK;AAAA,MACzC;AAEA,UAAI;AACJ,UAAI,aAAa;AACb,oBAAY;AAAA,MAChB,WAAW,cAAc;AACrB,oBAAY;AAAA,MAChB,OAAO;AACH,oBAAY;AAAA,MAChB;AAEA,aACI,oCAAC,OAAI,KAAK,KAAK,MACV,QACD;AAAA,QAAC;AAAA;AAAA,UACG,OAAO;AAAA,UACP,MAAK;AAAA;AAAA,QAEJ,QAAQ;AAAA,QAAE;AAAA,QAAG,KAAK;AAAA,MACvB,CACJ;AAAA,IAER,CAAC,CACL;AAAA,EAER;AAER;AAEA,IAAO,0BAAQ;","names":[]}
|