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.
Files changed (138) hide show
  1. package/dist/cli-adapter.js +685 -153
  2. package/dist/cli-adapter.js.map +1 -1
  3. package/dist/config/defaultConfig.js +1 -4
  4. package/dist/config/defaultConfig.js.map +1 -1
  5. package/dist/config/models.js +4 -0
  6. package/dist/config/models.js.map +1 -1
  7. package/dist/config/slash-commands.js +66 -2
  8. package/dist/config/slash-commands.js.map +1 -1
  9. package/dist/config/types.js +4 -4
  10. package/dist/config/types.js.map +1 -1
  11. package/dist/index.js +36 -0
  12. package/dist/index.js.map +1 -1
  13. package/dist/services/ai-context-injector.js +109 -0
  14. package/dist/services/ai-context-injector.js.map +1 -1
  15. package/dist/services/api-client.js.map +1 -1
  16. package/dist/services/background-task-manager.js +59 -0
  17. package/dist/services/background-task-manager.js.map +1 -1
  18. package/dist/services/local-chat-storage.js +2 -0
  19. package/dist/services/local-chat-storage.js.map +1 -1
  20. package/dist/services/skill-storage.js +141 -0
  21. package/dist/services/skill-storage.js.map +1 -0
  22. package/dist/services/sub-agent-manager.js +49 -8
  23. package/dist/services/sub-agent-manager.js.map +1 -1
  24. package/dist/services/warpify-detector.js +17 -5
  25. package/dist/services/warpify-detector.js.map +1 -1
  26. package/dist/tools/background-command.js +5 -2
  27. package/dist/tools/background-command.js.map +1 -1
  28. package/dist/tools/command.js +367 -109
  29. package/dist/tools/command.js.map +1 -1
  30. package/dist/tools/file-ops.js +23 -6
  31. package/dist/tools/file-ops.js.map +1 -1
  32. package/dist/tools/plan-mode.js +184 -336
  33. package/dist/tools/plan-mode.js.map +1 -1
  34. package/dist/tools/sub-agent.js +24 -5
  35. package/dist/tools/sub-agent.js.map +1 -1
  36. package/dist/tools/todo-list.js +157 -0
  37. package/dist/tools/todo-list.js.map +1 -0
  38. package/dist/types/skill.js +30 -0
  39. package/dist/types/skill.js.map +1 -0
  40. package/dist/ui/components/App.js +956 -162
  41. package/dist/ui/components/App.js.map +1 -1
  42. package/dist/ui/components/AuthScreen.js +3 -1
  43. package/dist/ui/components/AuthScreen.js.map +1 -1
  44. package/dist/ui/components/AuthWelcomeScreen.js +3 -1
  45. package/dist/ui/components/AuthWelcomeScreen.js.map +1 -1
  46. package/dist/ui/components/CodeBlock.js +3 -1
  47. package/dist/ui/components/CodeBlock.js.map +1 -1
  48. package/dist/ui/components/CompactShellPreview.js +44 -0
  49. package/dist/ui/components/CompactShellPreview.js.map +1 -0
  50. package/dist/ui/components/ConfigViewer.js +3 -1
  51. package/dist/ui/components/ConfigViewer.js.map +1 -1
  52. package/dist/ui/components/ConfirmPrompt.js +3 -1
  53. package/dist/ui/components/ConfirmPrompt.js.map +1 -1
  54. package/dist/ui/components/ConnectionStatusMessage.js +3 -1
  55. package/dist/ui/components/ConnectionStatusMessage.js.map +1 -1
  56. package/dist/ui/components/DetailedPlanReviewScreen.js +84 -74
  57. package/dist/ui/components/DetailedPlanReviewScreen.js.map +1 -1
  58. package/dist/ui/components/DiffViewer.js +6 -3
  59. package/dist/ui/components/DiffViewer.js.map +1 -1
  60. package/dist/ui/components/FileCreationPreview.js.map +1 -1
  61. package/dist/ui/components/FileTagAutocomplete.js +4 -2
  62. package/dist/ui/components/FileTagAutocomplete.js.map +1 -1
  63. package/dist/ui/components/InputBox.js +243 -40
  64. package/dist/ui/components/InputBox.js.map +1 -1
  65. package/dist/ui/components/InteractiveShell.js +5 -3
  66. package/dist/ui/components/InteractiveShell.js.map +1 -1
  67. package/dist/ui/components/KeyboardHelp.js +4 -1
  68. package/dist/ui/components/KeyboardHelp.js.map +1 -1
  69. package/dist/ui/components/LoadingIndicator.js +3 -1
  70. package/dist/ui/components/LoadingIndicator.js.map +1 -1
  71. package/dist/ui/components/MCPAddScreen.js +63 -13
  72. package/dist/ui/components/MCPAddScreen.js.map +1 -1
  73. package/dist/ui/components/MarkdownRenderer.js +3 -1
  74. package/dist/ui/components/MarkdownRenderer.js.map +1 -1
  75. package/dist/ui/components/MessageDisplay.js +9 -7
  76. package/dist/ui/components/MessageDisplay.js.map +1 -1
  77. package/dist/ui/components/ModelPicker.js +170 -0
  78. package/dist/ui/components/ModelPicker.js.map +1 -0
  79. package/dist/ui/components/MonitorModeAIPanel.js +3 -1
  80. package/dist/ui/components/MonitorModeAIPanel.js.map +1 -1
  81. package/dist/ui/components/PlanAcceptedMessage.js +12 -6
  82. package/dist/ui/components/PlanAcceptedMessage.js.map +1 -1
  83. package/dist/ui/components/PlanQuestionMessage.js +37 -0
  84. package/dist/ui/components/PlanQuestionMessage.js.map +1 -0
  85. package/dist/ui/components/PlanQuestionScreen.js +138 -0
  86. package/dist/ui/components/PlanQuestionScreen.js.map +1 -0
  87. package/dist/ui/components/PlanReviewScreen.js +7 -9
  88. package/dist/ui/components/PlanReviewScreen.js.map +1 -1
  89. package/dist/ui/components/RulesEditorScreen.js +65 -28
  90. package/dist/ui/components/RulesEditorScreen.js.map +1 -1
  91. package/dist/ui/components/SelectPrompt.js +3 -1
  92. package/dist/ui/components/SelectPrompt.js.map +1 -1
  93. package/dist/ui/components/SkillCreatorScreen.js +217 -0
  94. package/dist/ui/components/SkillCreatorScreen.js.map +1 -0
  95. package/dist/ui/components/SlashCommandAutocomplete.js +4 -2
  96. package/dist/ui/components/SlashCommandAutocomplete.js.map +1 -1
  97. package/dist/ui/components/StatusBar.js +4 -2
  98. package/dist/ui/components/StatusBar.js.map +1 -1
  99. package/dist/ui/components/StreamingMessageDisplay.js +5 -3
  100. package/dist/ui/components/StreamingMessageDisplay.js.map +1 -1
  101. package/dist/ui/components/SubAgentListScreen.js +65 -0
  102. package/dist/ui/components/SubAgentListScreen.js.map +1 -0
  103. package/dist/ui/components/SubAgentViewScreen.js +123 -0
  104. package/dist/ui/components/SubAgentViewScreen.js.map +1 -0
  105. package/dist/ui/components/TaskCompletedMessage.js +40 -8
  106. package/dist/ui/components/TaskCompletedMessage.js.map +1 -1
  107. package/dist/ui/components/TaskProgressIndicator.js +6 -4
  108. package/dist/ui/components/TaskProgressIndicator.js.map +1 -1
  109. package/dist/ui/components/TextEditor.js +297 -0
  110. package/dist/ui/components/TextEditor.js.map +1 -0
  111. package/dist/ui/components/TodoListMessage.js +59 -0
  112. package/dist/ui/components/TodoListMessage.js.map +1 -0
  113. package/dist/ui/components/ToolExecutionMessage.js +134 -84
  114. package/dist/ui/components/ToolExecutionMessage.js.map +1 -1
  115. package/dist/ui/components/ToolExecutionStatus.js +3 -1
  116. package/dist/ui/components/ToolExecutionStatus.js.map +1 -1
  117. package/dist/ui/components/WelcomeBanner.js +33 -33
  118. package/dist/ui/components/WelcomeBanner.js.map +1 -1
  119. package/dist/ui/components/WorkflowCreatorScreen.js +5 -3
  120. package/dist/ui/components/WorkflowCreatorScreen.js.map +1 -1
  121. package/dist/ui/theme.js +97 -0
  122. package/dist/ui/theme.js.map +1 -0
  123. package/dist/ui/utils/chat-history-limit.js +247 -0
  124. package/dist/ui/utils/chat-history-limit.js.map +1 -0
  125. package/dist/utils/chat-formatter.js +22 -9
  126. package/dist/utils/chat-formatter.js.map +1 -1
  127. package/dist/utils/input-classifier.js +11 -1
  128. package/dist/utils/input-classifier.js.map +1 -1
  129. package/dist/utils/output-truncation.js +175 -0
  130. package/dist/utils/output-truncation.js.map +1 -0
  131. package/dist/utils/rule-reference-resolver.js +3 -3
  132. package/dist/utils/rule-reference-resolver.js.map +1 -1
  133. package/dist/utils/tunnel-commands-manager.js +134 -0
  134. package/dist/utils/tunnel-commands-manager.js.map +1 -0
  135. package/package.json +91 -90
  136. package/postinstall.js +4 -11
  137. package/dist/ui/components/MultiLineInput.js +0 -255
  138. 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":"AAsBA,OAAO,SAAS,UAAU,WAAW,QAAQ,mBAAmB;AAChE,SAAS,KAAK,MAAM,gBAAgB;AACpC,YAAY,cAAc;AAqB1B,SAAS,eAAe,MAAc,GAAoB;AACxD,MAAI,IAAI,EAAG,KAAI;AACf,QAAM,SAAkB,CAAC;AACzB,QAAM,UAAU,KAAK,MAAM,IAAI;AAC/B,MAAI,MAAM;AAEV,WAAS,KAAK,GAAG,KAAK,QAAQ,QAAQ,MAAM;AAC1C,UAAM,KAAK,QAAQ,EAAE;AACrB,UAAM,SAAS,OAAO,QAAQ,SAAS;AAEvC,QAAI,GAAG,WAAW,GAAG;AACnB,aAAO,KAAK,EAAE,OAAO,KAAK,KAAK,KAAK,MAAM,KAAK,CAAC;AAChD,aAAO,SAAS,IAAI;AACpB;AAAA,IACF;AAEA,QAAI,MAAM;AACV,QAAI,KAAK;AACT,WAAO,IAAI,SAAS,GAAG;AACrB,UAAI,IAAI,UAAU,GAAG;AACnB,eAAO,KAAK,EAAE,OAAO,IAAI,KAAK,KAAK,IAAI,QAAQ,MAAM,KAAK,CAAC;AAC3D,cAAM,IAAI;AACV,cAAM;AAAA,MACR,OAAO;AACL,YAAI,QAAQ;AACZ,cAAM,KAAK,IAAI,YAAY,KAAK,CAAC;AACjC,YAAI,KAAK,EAAG,SAAQ,KAAK;AACzB,eAAO,KAAK,EAAE,OAAO,IAAI,KAAK,KAAK,OAAO,MAAM,MAAM,CAAC;AACvD,cAAM;AACN,cAAM,IAAI,MAAM,KAAK;AAAA,MACvB;AAAA,IACF;AAEA,WAAO,GAAG,UAAU,SAAS,IAAI;AAAA,EACnC;AAEA,MAAI,OAAO,WAAW,GAAG;AACvB,WAAO,KAAK,EAAE,OAAO,GAAG,KAAK,GAAG,MAAM,KAAK,CAAC;AAAA,EAC9C;AAEA,SAAO;AACT;AAEA,SAAS,OAAO,IAAa,KAAqB;AAChD,WAAS,IAAI,GAAG,SAAS,GAAG,KAAK,GAAG,KAAK;AACvC,QAAI,OAAO,GAAG,CAAC,EAAE,MAAO,QAAO;AAAA,EACjC;AACA,SAAO;AACT;AAIA,SAAS,OAAO,GAAW,GAAmB;AAC5C,MAAI,KAAK,EAAG,QAAO;AACnB,MAAI,IAAI,IAAI;AACZ,SAAO,IAAI,KAAK,SAAS,KAAK,EAAE,CAAC,CAAC,EAAG;AACrC,SAAO,IAAI,KAAK,CAAC,SAAS,KAAK,EAAE,IAAI,CAAC,CAAC,EAAG;AAC1C,SAAO,KAAK,IAAI,GAAG,CAAC;AACtB;AAEA,SAAS,QAAQ,GAAW,GAAmB;AAC7C,QAAM,IAAI,EAAE;AACZ,MAAI,KAAK,EAAG,QAAO;AACnB,MAAI,IAAI;AACR,SAAO,IAAI,KAAK,CAAC,SAAS,KAAK,EAAE,CAAC,CAAC,EAAG;AACtC,SAAO,IAAI,KAAK,SAAS,KAAK,EAAE,CAAC,CAAC,EAAG;AACrC,SAAO;AACT;AAIO,MAAM,aAAwC,CAAC;AAAA,EACpD;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,uBAAuB;AAAA,EACvB,OAAO;AACT,MAAM;AACJ,QAAM,EAAE,OAAO,WAAW,IAAI,SAAS;AAGvC,QAAM,SAAS,OAAO,KAAK;AAC3B,QAAM,SAAS,OAAO,MAAM,MAAM;AAClC,QAAM,YAAY,OAAsB,IAAI;AAC5C,QAAM,UAAU,OAAwC,CAAC,CAAC;AAC1D,QAAM,YAAY,OAAO,QAAQ;AACjC,QAAM,WAAW,OAAO,aAAa,KAAK,IAAI,KAAK,QAAQ,OAAO,WAAW,MAAM,EAAE,CAAC;AACtF,QAAM,iBAAiB,OAAO,oBAAoB;AAClD,QAAM,cAAc,OAAO,QAAQ;AACnC,QAAM,cAAc,OAAO,KAAK;AAGhC,YAAU,MAAM;AAAE,cAAU,UAAU;AAAA,EAAU,GAAG,CAAC,QAAQ,CAAC;AAC7D,YAAU,MAAM;AAAE,mBAAe,UAAU;AAAA,EAAsB,GAAG,CAAC,oBAAoB,CAAC;AAC1F,YAAU,MAAM;AAAE,gBAAY,UAAU;AAAA,EAAU,GAAG,CAAC,QAAQ,CAAC;AAC/D,YAAU,MAAM;AACd,aAAS,UAAU,aAAa,KAAK,IAAI,KAAK,QAAQ,OAAO,WAAW,MAAM,EAAE;AAAA,EAClF,GAAG,CAAC,SAAS,CAAC;AAGd,QAAM,CAAC,EAAE,OAAO,IAAI,SAAS,CAAC;AAC9B,QAAM,WAAW,YAAY,MAAM,QAAQ,OAAK,IAAI,CAAC,GAAG,CAAC,CAAC;AAG1D,YAAU,MAAM;AACd,QAAI,UAAU,OAAO,SAAS;AAC5B,aAAO,UAAU;AACjB,UAAI,OAAO,UAAU,MAAM,OAAQ,QAAO,UAAU,MAAM;AAC1D,eAAS;AAAA,IACX;AAAA,EACF,GAAG,CAAC,OAAO,QAAQ,CAAC;AAIpB,QAAM,WAAW,MAAM;AACrB,YAAQ,UAAU,CAAC,GAAG,QAAQ,QAAQ,MAAM,GAAG,GAAG,EAAE,GAAG,OAAO,SAAS,GAAG,OAAO,QAAQ,CAAC;AAAA,EAC5F;AAEA,QAAM,QAAQ,YAAY,CAAC,IAAY,OAAe;AACpD,WAAO,UAAU;AACjB,WAAO,UAAU,KAAK,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,MAAM,CAAC;AACpD,cAAU,UAAU;AACpB,gBAAY,QAAQ,EAAE;AACtB,aAAS;AAAA,EACX,GAAG,CAAC,QAAQ,CAAC;AAEb,QAAM,aAAa,YAAY,CAAC,OAAe;AAC7C,WAAO,UAAU,KAAK,IAAI,GAAG,KAAK,IAAI,IAAI,OAAO,QAAQ,MAAM,CAAC;AAChE,cAAU,UAAU;AACpB,aAAS;AAAA,EACX,GAAG,CAAC,QAAQ,CAAC;AAEb,QAAM,mBAAmB,YAAY,CAAC,IAAY,QAAgB;AAChE,WAAO,UAAU,KAAK,IAAI,GAAG,KAAK,IAAI,IAAI,OAAO,QAAQ,MAAM,CAAC;AAChE,QAAI,UAAU,YAAY,KAAM,WAAU,UAAU;AACpD,aAAS;AAAA,EACX,GAAG,CAAC,QAAQ,CAAC;AAIb,YAAU,MAAM;AACd,QAAI,CAAC,MAAO;AAEZ,eAAW,IAAI;AAGf,QAAI,CAAC,YAAY,SAAS;AACxB,eAAS,mBAAmB,KAAK;AACjC,kBAAY,UAAU;AAAA,IACxB;AAEA,UAAM,UAAU,CAAC,MAA0B,QAAa;AACtD,UAAI,CAAC,UAAU,WAAW,CAAC,IAAK;AAEhC,YAAMA,KAAI,OAAO;AACjB,YAAMC,KAAI,OAAO;AACjB,YAAMC,KAAI,SAAS;AACnB,YAAMC,MAAK,eAAeH,IAAGE,EAAC;AAC9B,YAAM,KAAK,OAAOC,KAAIF,EAAC;AACvB,YAAM,KAAKE,IAAG,EAAE;AAChB,YAAM,MAAMF,MAAK,IAAI,SAAS;AAE9B,YAAM,OAAO,IAAI,QAAQ;AACzB,YAAM,OAAO,CAAC,CAAC,IAAI;AACnB,YAAM,OAAO,CAAC,CAAC,IAAI;AACnB,YAAM,QAAQ,CAAC,CAAC,IAAI;AAMpB,UAAI,QAAQ,SAAS,KAAK;AAAE,mBAAW,OAAOD,IAAGC,EAAC,CAAC;AAAG;AAAA,MAAQ;AAC9D,UAAI,QAAQ,SAAS,KAAK;AAAE,mBAAW,QAAQD,IAAGC,EAAC,CAAC;AAAG;AAAA,MAAQ;AAE/D,UAAI,SAAS,QAAQ;AACnB,YAAI,QAAQ,KAAM,YAAW,OAAOD,IAAGC,EAAC,CAAC;AAAA,YACpC,YAAWA,KAAI,CAAC;AACrB;AAAA,MACF;AACA,UAAI,SAAS,SAAS;AACpB,YAAI,QAAQ,KAAM,YAAW,QAAQD,IAAGC,EAAC,CAAC;AAAA,YACrC,YAAWA,KAAI,CAAC;AACrB;AAAA,MACF;AACA,UAAI,SAAS,QAAQ,KAAK,GAAG;AAC3B,cAAM,MAAME,IAAG,KAAK,CAAC;AACrB,cAAM,KAAK,UAAU,WAAW;AAChC,yBAAiB,IAAI,QAAQ,KAAK,IAAI,IAAI,IAAI,MAAM,IAAI,KAAK,GAAG,GAAG;AACnE;AAAA,MACF;AACA,UAAI,SAAS,UAAU,KAAKA,IAAG,SAAS,GAAG;AACzC,cAAM,MAAMA,IAAG,KAAK,CAAC;AACrB,cAAM,KAAK,UAAU,WAAW;AAChC,yBAAiB,IAAI,QAAQ,KAAK,IAAI,IAAI,IAAI,MAAM,IAAI,KAAK,GAAG,GAAG;AACnE;AAAA,MACF;AACA,UAAI,SAAS,QAAQ,SAAS,OAAQ;AAGtC,UAAI,SAAS,UAAW,QAAQ,SAAS,KAAM;AAC7C,mBAAW,IAAI,SAAS,CAAC;AACzB;AAAA,MACF;AACA,UAAI,SAAS,SAAU,QAAQ,SAAS,KAAM;AAC5C,mBAAW,IAAI,OAAOH,GAAE,MAAM;AAC9B;AAAA,MACF;AAKA,UAAI,QAAQ,SAAS,aAAa;AAChC,YAAIC,KAAI,GAAG;AAAE,mBAAS;AAAG,gBAAM,KAAK,OAAOD,IAAGC,EAAC;AAAG,gBAAMD,GAAE,MAAM,GAAG,EAAE,IAAIA,GAAE,MAAMC,EAAC,GAAG,EAAE;AAAA,QAAG;AAC1F;AAAA,MACF;AAEA,UAAI,SAAS,aAAa;AACxB,YAAIA,KAAI,GAAG;AAAE,mBAAS;AAAG,gBAAMD,GAAE,MAAM,GAAGC,KAAI,CAAC,IAAID,GAAE,MAAMC,EAAC,GAAGA,KAAI,CAAC;AAAA,QAAG;AACvE;AAAA,MACF;AACA,UAAI,SAAS,YAAa,QAAQ,SAAS,KAAM;AAC/C,YAAIA,KAAID,GAAE,QAAQ;AAAE,mBAAS;AAAG,gBAAMA,GAAE,MAAM,GAAGC,EAAC,IAAID,GAAE,MAAMC,KAAI,CAAC,GAAGA,EAAC;AAAA,QAAG;AAC1E;AAAA,MACF;AAEA,UAAI,QAAQ,SAAS,OAAO,IAAI;AAC9B,iBAAS;AACT,YAAIA,MAAK,GAAG,OAAOA,KAAID,GAAE,UAAUA,GAAEC,EAAC,MAAM,MAAM;AAChD,gBAAMD,GAAE,MAAM,GAAGC,EAAC,IAAID,GAAE,MAAMC,KAAI,CAAC,GAAGA,EAAC;AAAA,QACzC,OAAO;AACL,gBAAMD,GAAE,MAAM,GAAGC,EAAC,IAAID,GAAE,MAAM,GAAG,GAAG,GAAGC,EAAC;AAAA,QAC1C;AACA;AAAA,MACF;AAEA,UAAI,QAAQ,SAAS,OAAO,IAAI;AAC9B,iBAAS;AACT,cAAMD,GAAE,MAAM,GAAG,GAAG,KAAK,IAAIA,GAAE,MAAMC,EAAC,GAAG,GAAG,KAAK;AACjD;AAAA,MACF;AAEA,UAAI,QAAQ,SAAS,OAAOA,KAAI,GAAG;AACjC,iBAAS;AACT,cAAM,KAAK,OAAOD,IAAGC,EAAC;AACtB,cAAMD,GAAE,MAAM,GAAG,EAAE,IAAIA,GAAE,MAAMC,EAAC,GAAG,EAAE;AACrC;AAAA,MACF;AAGA,UAAI,QAAQ,SAAS,KAAK;AACxB,cAAM,QAAQ,QAAQ;AACtB,YAAI,MAAM,SAAS,GAAG;AACpB,gBAAM,OAAO,MAAM,MAAM,SAAS,CAAC;AACnC,kBAAQ,UAAU,MAAM,MAAM,GAAG,EAAE;AACnC,gBAAM,KAAK,GAAG,KAAK,CAAC;AAAA,QACtB;AACA;AAAA,MACF;AAMA,UAAI,SAAS,UAAU;AACrB,iBAAS;AACT,cAAMD,GAAE,MAAM,GAAGC,EAAC,IAAI,OAAOD,GAAE,MAAMC,EAAC,GAAGA,KAAI,CAAC;AAC9C;AAAA,MACF;AAIA,UAAI,CAAC,QAAQ,SAAS,SAAS,YAAY,SAAS,WAAW;AAC7D,iBAAS;AACT,cAAMD,GAAE,MAAM,GAAGC,EAAC,IAAI,OAAOD,GAAE,MAAMC,EAAC,GAAGA,KAAI,CAAC;AAC9C;AAAA,MACF;AAGA,UAAI,SAAS,OAAO;AAClB,YAAI,CAAC,eAAe,SAAS;AAC3B,mBAAS;AACT,gBAAMD,GAAE,MAAM,GAAGC,EAAC,IAAI,OAAOD,GAAE,MAAMC,EAAC,GAAGA,KAAI,CAAC;AAAA,QAChD;AACA;AAAA,MACF;AAGA,UAAI,SAAS,SAAU;AAGvB,UAAI,QAAQ,KAAM;AAGlB,YAAM,KAAK,IAAI,YAAY;AAC3B,UAAI,MAAM,GAAG,SAAS,KAAK,GAAG,WAAW,CAAC,KAAK,IAAI;AACjD,iBAAS;AACT,cAAM,MAAM,GAAG,QAAQ,SAAS,IAAI,EAAE,QAAQ,OAAO,IAAI;AACzD,cAAMD,GAAE,MAAM,GAAGC,EAAC,IAAI,MAAMD,GAAE,MAAMC,EAAC,GAAGA,KAAI,IAAI,MAAM;AAAA,MACxD;AAAA,IACF;AAEA,UAAM,GAAG,YAAY,OAAO;AAC5B,WAAO,MAAM;AACX,YAAM,IAAI,YAAY,OAAO;AAAA,IAC/B;AAAA,EACF,GAAG,CAAC,OAAO,YAAY,OAAO,YAAY,kBAAkB,QAAQ,CAAC;AAIrE,QAAM,IAAI,OAAO;AACjB,QAAM,IAAI,OAAO;AACjB,QAAM,IAAI,SAAS;AACnB,QAAM,KAAK,eAAe,GAAG,CAAC;AAC9B,QAAM,QAAQ,GAAG;AACjB,QAAM,UAAU,OAAO,IAAI,CAAC;AAC5B,QAAM,MAAM,KAAK,IAAI,KAAK,IAAI,OAAO,SAAS,GAAG,SAAS;AAE1D,MAAI,QAAQ;AACZ,MAAI,WAAW,QAAQ,IAAK,SAAQ,UAAU,MAAM;AACpD,MAAI,UAAU,MAAO,SAAQ;AAC7B,QAAM,MAAM,KAAK,IAAI,QAAQ,KAAK,KAAK;AAEvC,QAAM,QAAQ,EAAE,WAAW;AAE3B,SACE,oCAAC,OAAI,eAAc,YAChB,QAAQ,KAAK,oCAAC,QAAK,OAAM,UAAO,WAAG,OAAM,OAAK,GAC9C,MAAM,KAAK,EAAE,QAAQ,IAAI,GAAG,CAAC,GAAG,OAAO;AACtC,UAAM,MAAM,QAAQ;AACpB,QAAI,OAAO,MAAO,QAAO,oCAAC,QAAK,KAAK,IAAI,EAAE,MAAI,GAAC;AAE/C,UAAM,KAAK,GAAG,GAAG;AACjB,UAAM,OAAO,EAAE,MAAM,GAAG,OAAO,GAAG,GAAG;AACrC,UAAM,QAAQ,QAAQ;AACtB,UAAM,KAAK,IAAI,GAAG;AAElB,QAAI,SAAS,QAAQ,GAAG;AACtB,aACE,oCAAC,QAAK,KAAI,QACR,oCAAC,QAAK,SAAO,QAAC,GAAC,GACf,oCAAC,QAAK,OAAM,UAAQ,WAAY,CAClC;AAAA,IAEJ;AAEA,QAAI,CAAC,OAAO;AACV,aAAO,oCAAC,QAAK,KAAK,IAAI,GAAG,MAAK,QAAQ,GAAI;AAAA,IAC5C;AAEA,UAAM,SAAS,KAAK,MAAM,GAAG,EAAE;AAC/B,UAAM,aAAa,KAAK,KAAK,SAAS,KAAK,EAAE,IAAI;AACjD,UAAM,QAAQ,KAAK,KAAK,SAAS,KAAK,MAAM,KAAK,CAAC,IAAI;AAEtD,WACE,oCAAC,QAAK,KAAK,IAAI,GAAG,MACf,QAAO,oCAAC,QAAK,SAAO,QAAE,UAAW,GAAQ,KAC5C;AAAA,EAEJ,CAAC,GACA,MAAM,SAAS,oCAAC,QAAK,OAAM,UAAO,WAAG,QAAQ,KAAI,OAAK,CACzD;AAEJ;","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":[]}