@robota-sdk/agent-transport 3.0.0-beta.74 → 3.0.0-beta.76

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 (197) hide show
  1. package/README.md +10 -10
  2. package/dist/node/headless/index.cjs +1 -1
  3. package/dist/node/headless/index.d.ts +1 -1
  4. package/dist/node/headless/index.js +1 -1
  5. package/dist/node/headless-OnpVk4-k.cjs +15 -0
  6. package/dist/node/{headless-D02zUEGh.js → headless-mRYilLfC.js} +2 -2
  7. package/dist/node/{headless-D02zUEGh.js.map → headless-mRYilLfC.js.map} +1 -1
  8. package/dist/node/{index-DE3-dHqw.d.ts → index-CYl7ksS6.d.ts} +12 -2
  9. package/dist/node/{index-DE3-dHqw.d.ts.map → index-CYl7ksS6.d.ts.map} +1 -1
  10. package/dist/node/{index-WKTgvhlg.d.ts → index-E8Gx4-lc.d.ts} +12 -2
  11. package/dist/node/{index-WKTgvhlg.d.ts.map → index-E8Gx4-lc.d.ts.map} +1 -1
  12. package/dist/node/index.cjs +1 -1
  13. package/dist/node/index.d.ts +2 -7
  14. package/dist/node/index.d.ts.map +1 -1
  15. package/dist/node/index.js +1 -1
  16. package/dist/node/index.js.map +1 -1
  17. package/package.json +7 -75
  18. package/src/headless/HeadlessInteractionChannel.ts +21 -1
  19. package/src/index.ts +1 -5
  20. package/src/transport-registry.ts +0 -9
  21. package/dist/node/headless-BeHAOlIM.cjs +0 -15
  22. package/dist/node/http/index.cjs +0 -1
  23. package/dist/node/http/index.d.ts +0 -2
  24. package/dist/node/http/index.js +0 -1
  25. package/dist/node/http-2Jiuflc1.js +0 -2
  26. package/dist/node/http-2Jiuflc1.js.map +0 -1
  27. package/dist/node/http-CBAvefLw.cjs +0 -1
  28. package/dist/node/index-BQLN_Lc9.d.ts +0 -78
  29. package/dist/node/index-BQLN_Lc9.d.ts.map +0 -1
  30. package/dist/node/index-BnAGE-u9.d.ts +0 -33
  31. package/dist/node/index-BnAGE-u9.d.ts.map +0 -1
  32. package/dist/node/index-BrQ4gGw0.d.ts +0 -213
  33. package/dist/node/index-BrQ4gGw0.d.ts.map +0 -1
  34. package/dist/node/index-CoeBF21y.d.ts +0 -213
  35. package/dist/node/index-CoeBF21y.d.ts.map +0 -1
  36. package/dist/node/index-DHt-2VQ-.d.ts +0 -46
  37. package/dist/node/index-DHt-2VQ-.d.ts.map +0 -1
  38. package/dist/node/index-DMwKN5Le.d.ts +0 -33
  39. package/dist/node/index-DMwKN5Le.d.ts.map +0 -1
  40. package/dist/node/index-IvYaYY6v.d.ts +0 -78
  41. package/dist/node/index-IvYaYY6v.d.ts.map +0 -1
  42. package/dist/node/index-c0M42fsA.d.ts +0 -46
  43. package/dist/node/index-c0M42fsA.d.ts.map +0 -1
  44. package/dist/node/mcp/index.cjs +0 -1
  45. package/dist/node/mcp/index.d.ts +0 -2
  46. package/dist/node/mcp/index.js +0 -1
  47. package/dist/node/mcp-BOglBJNy.cjs +0 -1
  48. package/dist/node/mcp-D3BBVK7C.js +0 -2
  49. package/dist/node/mcp-D3BBVK7C.js.map +0 -1
  50. package/dist/node/rolldown-runtime-CMqjfN_6.cjs +0 -1
  51. package/dist/node/tui/index.cjs +0 -1
  52. package/dist/node/tui/index.d.ts +0 -2
  53. package/dist/node/tui/index.js +0 -1
  54. package/dist/node/tui-Btb1q88j.js +0 -25
  55. package/dist/node/tui-Btb1q88j.js.map +0 -1
  56. package/dist/node/tui-SbUT7Zlt.cjs +0 -24
  57. package/dist/node/ws/index.cjs +0 -1
  58. package/dist/node/ws/index.d.ts +0 -2
  59. package/dist/node/ws/index.js +0 -1
  60. package/dist/node/ws-Dc2RUwVs.js +0 -2
  61. package/dist/node/ws-Dc2RUwVs.js.map +0 -1
  62. package/dist/node/ws-QNMQn5kg.cjs +0 -1
  63. package/src/http/__tests__/http-transport.test.ts +0 -55
  64. package/src/http/__tests__/routes.test.ts +0 -168
  65. package/src/http/http-transport.ts +0 -41
  66. package/src/http/index.ts +0 -4
  67. package/src/http/routes.ts +0 -152
  68. package/src/mcp/__tests__/mcp-server.test.ts +0 -66
  69. package/src/mcp/__tests__/mcp-transport.test.ts +0 -46
  70. package/src/mcp/index.ts +0 -4
  71. package/src/mcp/mcp-server.ts +0 -163
  72. package/src/mcp/mcp-transport.ts +0 -48
  73. package/src/tui/App.tsx +0 -488
  74. package/src/tui/BackgroundTaskPanel.tsx +0 -36
  75. package/src/tui/CjkTextInput.tsx +0 -199
  76. package/src/tui/ConfirmPrompt.tsx +0 -70
  77. package/src/tui/ContextWarningBanner.tsx +0 -34
  78. package/src/tui/ExecutionWorkspaceDetailPane.tsx +0 -64
  79. package/src/tui/ExecutionWorkspaceSwitcher.tsx +0 -187
  80. package/src/tui/InputArea.tsx +0 -310
  81. package/src/tui/InteractivePrompt.tsx +0 -59
  82. package/src/tui/ListPicker.tsx +0 -95
  83. package/src/tui/MenuSelect.tsx +0 -104
  84. package/src/tui/MessageList.tsx +0 -284
  85. package/src/tui/PermissionPrompt.tsx +0 -86
  86. package/src/tui/PluginTUI.tsx +0 -258
  87. package/src/tui/SessionPicker.tsx +0 -68
  88. package/src/tui/SessionStatusBar.tsx +0 -70
  89. package/src/tui/SlashAutocomplete.tsx +0 -110
  90. package/src/tui/StatusBar.tsx +0 -209
  91. package/src/tui/StreamingIndicator.tsx +0 -93
  92. package/src/tui/TextPrompt.tsx +0 -81
  93. package/src/tui/ToolCommandOutput.tsx +0 -39
  94. package/src/tui/ToolDiffBlock.tsx +0 -32
  95. package/src/tui/TransportTUI.tsx +0 -117
  96. package/src/tui/TuiInteractionChannel.ts +0 -483
  97. package/src/tui/UpdateNotice.tsx +0 -14
  98. package/src/tui/UsageSummaryEntry.tsx +0 -39
  99. package/src/tui/WaveText.tsx +0 -44
  100. package/src/tui/__tests__/InteractivePrompt.test.tsx +0 -82
  101. package/src/tui/__tests__/ListPicker.test.tsx +0 -159
  102. package/src/tui/__tests__/MenuSelect.test.tsx +0 -103
  103. package/src/tui/__tests__/PluginTUI.test.tsx +0 -167
  104. package/src/tui/__tests__/SlashAutocomplete.test.tsx +0 -140
  105. package/src/tui/__tests__/TextPrompt.test.tsx +0 -98
  106. package/src/tui/__tests__/TuiInteractionChannel.display-contract.test.ts +0 -239
  107. package/src/tui/__tests__/TuiInteractionChannel.lifecycle.test.ts +0 -297
  108. package/src/tui/__tests__/TuiInteractionChannel.requestAction.test.ts +0 -124
  109. package/src/tui/__tests__/UpdateNotice.test.tsx +0 -15
  110. package/src/tui/__tests__/abort-after-permission.test.tsx +0 -169
  111. package/src/tui/__tests__/abort-streaming-e2e.test.tsx +0 -183
  112. package/src/tui/__tests__/background-task-panel.test.tsx +0 -53
  113. package/src/tui/__tests__/background-task-row-format.test.ts +0 -59
  114. package/src/tui/__tests__/channel-factory-integration.test.ts +0 -138
  115. package/src/tui/__tests__/cjk-text-input-flow.test.ts +0 -109
  116. package/src/tui/__tests__/cjk-text-input.test.ts +0 -191
  117. package/src/tui/__tests__/command-effect-handler.test.ts +0 -127
  118. package/src/tui/__tests__/command-output-summary.test.ts +0 -95
  119. package/src/tui/__tests__/compact-event-bridge.test.ts +0 -20
  120. package/src/tui/__tests__/confirm-permission-flow.test.ts +0 -130
  121. package/src/tui/__tests__/confirm-prompt.test.tsx +0 -87
  122. package/src/tui/__tests__/execution-workspace-switcher.test.tsx +0 -110
  123. package/src/tui/__tests__/execution-workspace-view-model.test.ts +0 -93
  124. package/src/tui/__tests__/fixtures/provider-setup-prompt-driver.tsx +0 -125
  125. package/src/tui/__tests__/input-area-flow.test.ts +0 -164
  126. package/src/tui/__tests__/message-list-rendering.test.tsx +0 -353
  127. package/src/tui/__tests__/prompt-queue.test.tsx +0 -255
  128. package/src/tui/__tests__/provider-setup-pty-e2e.test.ts +0 -233
  129. package/src/tui/__tests__/pty/pty-driver.ts +0 -135
  130. package/src/tui/__tests__/pty/tui-pty.ptytest.ts +0 -61
  131. package/src/tui/__tests__/render-channel-options.test.ts +0 -32
  132. package/src/tui/__tests__/render-markdown.test.ts +0 -72
  133. package/src/tui/__tests__/selection-flow.test.ts +0 -61
  134. package/src/tui/__tests__/session-init-poller.test.ts +0 -102
  135. package/src/tui/__tests__/session-naming.test.ts +0 -64
  136. package/src/tui/__tests__/session-switch-channel.test.tsx +0 -307
  137. package/src/tui/__tests__/slash-routing-effects.test.ts +0 -228
  138. package/src/tui/__tests__/status-activity.test.ts +0 -71
  139. package/src/tui/__tests__/status-bar.test.tsx +0 -158
  140. package/src/tui/__tests__/streaming-indicator.test.tsx +0 -137
  141. package/src/tui/__tests__/text-prompt-flow.test.ts +0 -77
  142. package/src/tui/__tests__/tui-channel-init-failure.test.ts +0 -57
  143. package/src/tui/__tests__/tui-state-manager.test.ts +0 -401
  144. package/src/tui/background-task-row-format.ts +0 -53
  145. package/src/tui/command-interaction.ts +0 -9
  146. package/src/tui/command-output-summary.ts +0 -122
  147. package/src/tui/create-default-tui-cli-adapter.ts +0 -41
  148. package/src/tui/execution-workspace-view-model.ts +0 -123
  149. package/src/tui/flows/cjk-text-input-flow.ts +0 -285
  150. package/src/tui/flows/confirm-prompt-flow.ts +0 -45
  151. package/src/tui/flows/input-area-flow.ts +0 -189
  152. package/src/tui/flows/permission-prompt-flow.ts +0 -85
  153. package/src/tui/flows/selection-flow.ts +0 -126
  154. package/src/tui/flows/session-init-poller.ts +0 -77
  155. package/src/tui/flows/text-prompt-flow.ts +0 -98
  156. package/src/tui/hooks/command-effect-handler.ts +0 -97
  157. package/src/tui/hooks/command-effect-queue.ts +0 -39
  158. package/src/tui/hooks/side-effects-types.ts +0 -35
  159. package/src/tui/hooks/useAutocomplete.ts +0 -87
  160. package/src/tui/hooks/usePluginCallbacks.ts +0 -31
  161. package/src/tui/hooks/usePluginScreenData.ts +0 -85
  162. package/src/tui/hooks/useSideEffects.ts +0 -175
  163. package/src/tui/hooks/useSlashRouting.ts +0 -118
  164. package/src/tui/hooks/useStatusLineSettings.ts +0 -37
  165. package/src/tui/hooks/useTuiChannel.ts +0 -95
  166. package/src/tui/index.ts +0 -14
  167. package/src/tui/interactions/CommandConfirm.tsx +0 -36
  168. package/src/tui/interactions/CommandPicker.tsx +0 -77
  169. package/src/tui/interactions/__tests__/CommandConfirm.test.tsx +0 -124
  170. package/src/tui/interactions/__tests__/CommandPicker.test.tsx +0 -138
  171. package/src/tui/plugin-tui-handlers.ts +0 -163
  172. package/src/tui/render-markdown.ts +0 -130
  173. package/src/tui/render.tsx +0 -117
  174. package/src/tui/session-naming.ts +0 -33
  175. package/src/tui/status-activity.ts +0 -63
  176. package/src/tui/tui-cli-adapter-context.tsx +0 -13
  177. package/src/tui/tui-cli-adapter.ts +0 -25
  178. package/src/tui/tui-state-manager.ts +0 -226
  179. package/src/tui/tui-transport.ts +0 -35
  180. package/src/tui/types.ts +0 -15
  181. package/src/tui/utils/__tests__/edit-diff.test.ts +0 -426
  182. package/src/tui/utils/__tests__/paste-detection.test.ts +0 -116
  183. package/src/tui/utils/__tests__/paste-labels.test.ts +0 -46
  184. package/src/tui/utils/__tests__/tool-call-extractor.test.ts +0 -227
  185. package/src/tui/utils/__tests__/tool-diff-summary.test.ts +0 -104
  186. package/src/tui/utils/edit-diff.ts +0 -153
  187. package/src/tui/utils/paste-labels.ts +0 -9
  188. package/src/tui/utils/tool-call-extractor.ts +0 -92
  189. package/src/tui/utils/tool-diff-summary.ts +0 -75
  190. package/src/ws/__tests__/ws-handler.test.ts +0 -409
  191. package/src/ws/__tests__/ws-transport.test.ts +0 -53
  192. package/src/ws/index.ts +0 -13
  193. package/src/ws/ws-background-messages.ts +0 -170
  194. package/src/ws/ws-handler.ts +0 -280
  195. package/src/ws/ws-protocol.ts +0 -78
  196. package/src/ws/ws-transport-configurable.ts +0 -128
  197. package/src/ws/ws-transport.ts +0 -42
@@ -1,310 +0,0 @@
1
- import React, { useState, useCallback, useRef, useMemo } from 'react';
2
-
3
- const PENDING_PROMPT_DISPLAY_MAX = 50;
4
- const PENDING_PROMPT_TAIL_KEEP = 47;
5
- import { Box, Text, useInput, useWindowSize } from 'ink';
6
-
7
- import CjkTextInput from './CjkTextInput.js';
8
- import {
9
- appendPromptHistory,
10
- createPasteLabelChange,
11
- createPromptHistoryNavigationState,
12
- extractPromptHistory,
13
- getAutocompletePopupAction,
14
- getPendingPromptInputAction,
15
- getPromptHistoryInputAction,
16
- moveAutocompleteSelection,
17
- navigatePromptHistory,
18
- resolveEnterCommandSelection,
19
- resolveTabCompletion,
20
- shouldSubmitInput,
21
- } from './flows/input-area-flow.js';
22
- import { useAutocomplete } from './hooks/useAutocomplete.js';
23
- import SlashAutocomplete from './SlashAutocomplete.js';
24
- import { expandPasteLabels } from './utils/paste-labels.js';
25
- import WaveText from './WaveText.js';
26
-
27
- import type { IHistoryEntry } from '@robota-sdk/agent-core';
28
- import type { CommandRegistry } from '@robota-sdk/agent-framework';
29
- import type { ICommand } from '@robota-sdk/agent-interface-transport';
30
-
31
- interface IProps {
32
- onSubmit: (value: string) => void;
33
- onCancelQueue?: () => void;
34
- isDisabled: boolean;
35
- isAborting?: boolean;
36
- pendingPrompt?: string | null;
37
- registry?: CommandRegistry;
38
- sessionName?: string;
39
- history?: readonly IHistoryEntry[];
40
- }
41
-
42
- /**
43
- * Known limitation: Korean IME last character may be dropped on Enter.
44
- * This is an Ink raw mode limitation — no compositionstart/compositionend
45
- * events are available in terminal raw mode.
46
- * Reference: https://github.com/anthropics/claude-code/issues/3045
47
- */
48
- /**
49
- * Layout constants for InputArea (columns).
50
- * Used to compute available text width from terminal columns.
51
- *
52
- * Side borders removed — only top/bottom horizontal lines remain.
53
- * paddingLeft={1} adds 1 column inside the box.
54
- * Prompt "> " takes 2 columns.
55
- */
56
- const BORDER_HORIZONTAL = 0;
57
- const PADDING_LEFT = 1;
58
- const PROMPT_WIDTH = 2;
59
- const INPUT_AREA_OVERHEAD = BORDER_HORIZONTAL + PADDING_LEFT + PROMPT_WIDTH;
60
- const DEFAULT_TERMINAL_COLUMNS = 80;
61
-
62
- export default function InputArea({
63
- onSubmit,
64
- onCancelQueue,
65
- isDisabled,
66
- isAborting,
67
- pendingPrompt,
68
- registry,
69
- sessionName,
70
- history,
71
- }: IProps): React.ReactElement {
72
- const [value, setValue] = useState('');
73
- const [cursorHint, setCursorHint] = useState<number | null>(null);
74
- const [historyState, setHistoryState] = useState(createPromptHistoryNavigationState);
75
- const [localPromptHistory, setLocalPromptHistory] = useState<string[]>([]);
76
- const restoredPromptHistory = useMemo(() => extractPromptHistory(history ?? []), [history]);
77
- const promptHistory = useMemo(
78
- () =>
79
- localPromptHistory.reduce<string[]>(
80
- (prompts, prompt) => appendPromptHistory(prompts, prompt),
81
- restoredPromptHistory,
82
- ),
83
- [restoredPromptHistory, localPromptHistory],
84
- );
85
- const pasteStore = useRef<Map<number, string>>(new Map());
86
- const { columns } = useWindowSize();
87
- const terminalColumns = columns > 0 ? columns : DEFAULT_TERMINAL_COLUMNS;
88
- const availableWidth = Math.max(1, terminalColumns - INPUT_AREA_OVERHEAD);
89
- const pasteIdRef = useRef(0);
90
-
91
- const {
92
- showPopup,
93
- filteredCommands,
94
- selectedIndex,
95
- setSelectedIndex,
96
- isSubcommandMode,
97
- setShowPopup,
98
- } = useAutocomplete(value, registry);
99
-
100
- const handlePaste = useCallback((text: string, cursorPosition: number) => {
101
- pasteIdRef.current += 1;
102
- const id = pasteIdRef.current;
103
- pasteStore.current.set(id, text);
104
- setValue((prev) => {
105
- const change = createPasteLabelChange(prev, cursorPosition, id, text);
106
- setCursorHint(change.cursorHint);
107
- return change.value;
108
- });
109
- }, []);
110
-
111
- const resetHistoryNavigation = useCallback(() => {
112
- setHistoryState(createPromptHistoryNavigationState());
113
- }, []);
114
-
115
- const recordPromptHistory = useCallback((prompt: string): void => {
116
- setLocalPromptHistory((prev) => appendPromptHistory(prev, prompt));
117
- }, []);
118
-
119
- const submitPrompt = useCallback(
120
- (prompt: string): void => {
121
- recordPromptHistory(prompt);
122
- resetHistoryNavigation();
123
- onSubmit(prompt);
124
- },
125
- [onSubmit, recordPromptHistory, resetHistoryNavigation],
126
- );
127
-
128
- /** Tab: insert command into input field without executing */
129
- const tabCompleteCommand = useCallback(
130
- (cmd: ICommand): void => {
131
- const result = resolveTabCompletion(value, cmd);
132
- if (result.type === 'insert') {
133
- setValue(result.value);
134
- if (result.selectedIndex !== undefined) {
135
- setSelectedIndex(result.selectedIndex);
136
- }
137
- }
138
- },
139
- [value, setSelectedIndex],
140
- );
141
-
142
- /** Enter: insert and execute command immediately */
143
- const enterSelectCommand = useCallback(
144
- (cmd: ICommand): void => {
145
- const result = resolveEnterCommandSelection(value, cmd);
146
- if (result.type === 'insert') {
147
- setValue(result.value);
148
- if (result.selectedIndex !== undefined) {
149
- setSelectedIndex(result.selectedIndex);
150
- }
151
- return;
152
- }
153
- if (result.type === 'submit') {
154
- setValue('');
155
- submitPrompt(result.value);
156
- }
157
- },
158
- [value, submitPrompt, setSelectedIndex],
159
- );
160
-
161
- const handleSubmit = useCallback(
162
- (text: string): void => {
163
- if (!shouldSubmitInput(text)) return;
164
-
165
- if (showPopup && filteredCommands[selectedIndex]) {
166
- enterSelectCommand(filteredCommands[selectedIndex]);
167
- return;
168
- }
169
-
170
- // Expand paste labels before submitting
171
- const expanded = expandPasteLabels(text.trim(), pasteStore.current);
172
-
173
- setValue('');
174
- // Reset paste state
175
- pasteStore.current.clear();
176
- pasteIdRef.current = 0;
177
-
178
- submitPrompt(expanded);
179
- },
180
- [showPopup, filteredCommands, selectedIndex, enterSelectCommand, submitPrompt],
181
- );
182
-
183
- useInput(
184
- (
185
- _input: string,
186
- key: { upArrow: boolean; downArrow: boolean; escape: boolean; tab: boolean },
187
- ) => {
188
- if (!showPopup) return;
189
- const action = getAutocompletePopupAction(key);
190
- if (action === 'previous' || action === 'next') {
191
- setSelectedIndex((prev) =>
192
- moveAutocompleteSelection(prev, filteredCommands.length, action),
193
- );
194
- } else if (action === 'close') {
195
- setShowPopup(false);
196
- } else if (action === 'complete') {
197
- const cmd = filteredCommands[selectedIndex];
198
- if (cmd) tabCompleteCommand(cmd);
199
- }
200
- },
201
- { isActive: showPopup && !isDisabled },
202
- );
203
-
204
- useInput(
205
- (_input, key) => {
206
- const action = getPromptHistoryInputAction(key);
207
- if (!action) return;
208
- const result = navigatePromptHistory(value, promptHistory, historyState, action);
209
- setValue(result.value);
210
- setCursorHint(result.cursorHint);
211
- setHistoryState(result.state);
212
- },
213
- { isActive: !showPopup && !isDisabled && !pendingPrompt },
214
- );
215
-
216
- // Backspace cancels queued prompt
217
- useInput(
218
- (_input, key) => {
219
- if (getPendingPromptInputAction(key) === 'cancelQueue' && pendingPrompt) {
220
- onCancelQueue?.();
221
- }
222
- },
223
- { isActive: !!pendingPrompt },
224
- );
225
-
226
- const borderColor = isAborting
227
- ? 'yellow'
228
- : pendingPrompt
229
- ? 'cyan'
230
- : isDisabled
231
- ? 'gray'
232
- : 'green';
233
- const innerWidth = Math.max(1, terminalColumns - BORDER_HORIZONTAL);
234
-
235
- // Build top border with optional session name title (right-aligned, 2 chars from edge)
236
- const topBorder = (() => {
237
- if (sessionName) {
238
- const label = ` "${sessionName}" `;
239
- const rightPad = 2;
240
- const leftLen = Math.max(0, innerWidth - label.length - rightPad);
241
- return { left: '─'.repeat(leftLen), label, right: '─'.repeat(rightPad) };
242
- }
243
- return { left: '─'.repeat(innerWidth), label: '', right: '' };
244
- })();
245
-
246
- return (
247
- <Box flexDirection="column">
248
- {showPopup && (
249
- <SlashAutocomplete
250
- commands={filteredCommands}
251
- selectedIndex={selectedIndex}
252
- visible={showPopup}
253
- isSubcommandMode={isSubcommandMode}
254
- />
255
- )}
256
- <Text color={borderColor}>
257
- {topBorder.left}
258
- {topBorder.label ? (
259
- <Text backgroundColor={borderColor} color="black" bold>
260
- {topBorder.label}
261
- </Text>
262
- ) : null}
263
- {topBorder.right}
264
- </Text>
265
- <Box
266
- borderStyle="single"
267
- borderTop={false}
268
- borderLeft={false}
269
- borderRight={false}
270
- borderColor={borderColor}
271
- paddingLeft={1}
272
- >
273
- {isAborting ? (
274
- <Text color="yellow"> Interrupting...</Text>
275
- ) : pendingPrompt ? (
276
- <Text color="cyan">
277
- {' '}
278
- Queued:{' '}
279
- {pendingPrompt.length > PENDING_PROMPT_DISPLAY_MAX
280
- ? pendingPrompt.slice(0, PENDING_PROMPT_TAIL_KEEP) + '...'
281
- : pendingPrompt}{' '}
282
- <Text dimColor>(Backspace to cancel)</Text>
283
- </Text>
284
- ) : isDisabled ? (
285
- <WaveText text=" Waiting for response... (ESC to interrupt)" />
286
- ) : (
287
- <Box>
288
- <Text color="green" bold>
289
- {'> '}
290
- </Text>
291
- <CjkTextInput
292
- value={value}
293
- onChange={(v) => {
294
- setValue(v);
295
- resetHistoryNavigation();
296
- setCursorHint(null); // reset after normal typing
297
- }}
298
- onSubmit={handleSubmit}
299
- onPaste={handlePaste}
300
- placeholder="Type a message or /help"
301
- availableWidth={availableWidth}
302
- cursorHint={cursorHint}
303
- enableVerticalNavigation={false}
304
- />
305
- </Box>
306
- )}
307
- </Box>
308
- </Box>
309
- );
310
- }
@@ -1,59 +0,0 @@
1
- import { Box, Text } from 'ink';
2
- import React from 'react';
3
-
4
- import ListPicker from './ListPicker.js';
5
- import TextPrompt from './TextPrompt.js';
6
-
7
- import type {
8
- ICommandChoicePromptOption as IChoicePromptOption,
9
- TCommandInteractionPrompt as TInteractivePrompt,
10
- } from '@robota-sdk/agent-interface-transport';
11
-
12
- interface IInteractivePromptProps {
13
- prompt: TInteractivePrompt;
14
- onSubmit: (value: string) => void;
15
- onCancel: () => void;
16
- }
17
-
18
- export default function InteractivePrompt({
19
- prompt,
20
- onSubmit,
21
- onCancel,
22
- }: IInteractivePromptProps): React.ReactElement {
23
- if (prompt.kind === 'text') {
24
- return (
25
- <TextPrompt
26
- key={`text:${prompt.title}`}
27
- title={prompt.title}
28
- description={prompt.description}
29
- placeholder={prompt.placeholder}
30
- allowEmpty={prompt.allowEmpty}
31
- masked={prompt.masked}
32
- validate={prompt.validate}
33
- onSubmit={onSubmit}
34
- onCancel={onCancel}
35
- />
36
- );
37
- }
38
-
39
- return (
40
- <Box flexDirection="column">
41
- <Text bold>{prompt.title}</Text>
42
- {prompt.description !== undefined && prompt.description.length > 0 && (
43
- <Text dimColor>{prompt.description}</Text>
44
- )}
45
- <ListPicker<IChoicePromptOption>
46
- items={[...prompt.options]}
47
- maxVisible={prompt.maxVisible}
48
- renderItem={(option, isSelected) => (
49
- <Text color={isSelected ? 'cyan' : undefined}>
50
- {isSelected ? '> ' : ' '}
51
- {option.label}
52
- </Text>
53
- )}
54
- onSelect={(option) => onSubmit(option.value)}
55
- onCancel={onCancel}
56
- />
57
- </Box>
58
- );
59
- }
@@ -1,95 +0,0 @@
1
- /**
2
- * Generic list picker with arrow-key navigation and viewport scrolling.
3
- * Renders items via a user-supplied renderItem function.
4
- * Shows a limited number of items at a time; scrolls as the cursor moves.
5
- */
6
-
7
- import { Box, Text, useInput } from 'ink';
8
- import React, { useState, useRef, useCallback } from 'react';
9
-
10
- import {
11
- applySelectionInput,
12
- createSelectionFlowState,
13
- getVerticalSelectionInputAction,
14
- normalizeSelectionState,
15
- type ISelectionFlowState,
16
- type TSelectionInputAction,
17
- } from './flows/selection-flow.js';
18
-
19
- /** Default number of visible items */
20
- const DEFAULT_MAX_VISIBLE = 3;
21
-
22
- export interface IListPickerProps<T> {
23
- /** Items to display in the list */
24
- items: T[];
25
- /** Render function for each item — receives the item and whether it is currently selected */
26
- renderItem: (item: T, isSelected: boolean) => React.ReactElement;
27
- /** Called when the user presses Enter on the highlighted item */
28
- onSelect: (item: T) => void;
29
- /** Called when the user presses Escape */
30
- onCancel: () => void;
31
- /** Maximum number of items visible at once (default: 10) */
32
- maxVisible?: number;
33
- }
34
-
35
- export default function ListPicker<T>({
36
- items,
37
- renderItem,
38
- onSelect,
39
- onCancel,
40
- maxVisible = DEFAULT_MAX_VISIBLE,
41
- }: IListPickerProps<T>): React.ReactElement {
42
- const [state, setState] = useState<ISelectionFlowState>(() => createSelectionFlowState());
43
- const stateRef = useRef(state);
44
- const applyAction = useCallback(
45
- (action: TSelectionInputAction): void => {
46
- const result = applySelectionInput(stateRef.current, action, {
47
- itemCount: items.length,
48
- maxVisible,
49
- });
50
- stateRef.current = result.state;
51
- setState(result.state);
52
- if (result.effect.type === 'cancel') {
53
- onCancel();
54
- } else if (result.effect.type === 'select') {
55
- const item = items[result.effect.index];
56
- if (item !== undefined) {
57
- onSelect(item);
58
- }
59
- }
60
- },
61
- [items, maxVisible, onCancel, onSelect],
62
- );
63
-
64
- useInput((_input, key) => {
65
- const action = getVerticalSelectionInputAction(key);
66
- if (action !== undefined) {
67
- applyAction(action);
68
- }
69
- });
70
-
71
- if (items.length === 0) {
72
- return <Box />;
73
- }
74
-
75
- const normalizedState = normalizeSelectionState(state, { itemCount: items.length, maxVisible });
76
- if (normalizedState !== state) {
77
- stateRef.current = normalizedState;
78
- }
79
- const { selectedIndex, scrollOffset } = normalizedState;
80
- const visibleItems = items.slice(scrollOffset, scrollOffset + maxVisible);
81
- const hasMore = scrollOffset + maxVisible < items.length;
82
- const hasLess = scrollOffset > 0;
83
-
84
- return (
85
- <Box flexDirection="column">
86
- {hasLess && <Text dimColor> ↑ {scrollOffset} more above</Text>}
87
- {visibleItems.map((item, index) => (
88
- <Box key={scrollOffset + index} marginBottom={1}>
89
- {renderItem(item, scrollOffset + index === selectedIndex)}
90
- </Box>
91
- ))}
92
- {hasMore && <Text dimColor> ↓ {items.length - scrollOffset - maxVisible} more below</Text>}
93
- </Box>
94
- );
95
- }
@@ -1,104 +0,0 @@
1
- import { Box, Text, useInput } from 'ink';
2
- import React, { useState, useCallback, useRef } from 'react';
3
-
4
- import {
5
- applySelectionInput,
6
- createSelectionFlowState,
7
- getVerticalSelectionInputAction,
8
- normalizeSelectionState,
9
- type ISelectionFlowState,
10
- type TSelectionInputAction,
11
- } from './flows/selection-flow.js';
12
-
13
- export interface IMenuSelectItem {
14
- label: string;
15
- value: string;
16
- hint?: string;
17
- }
18
-
19
- interface IProps {
20
- title: string;
21
- items: IMenuSelectItem[];
22
- onSelect: (value: string) => void;
23
- onBack: () => void;
24
- loading?: boolean;
25
- error?: string;
26
- }
27
-
28
- export default function MenuSelect({
29
- title,
30
- items,
31
- onSelect,
32
- onBack,
33
- loading,
34
- error,
35
- }: IProps): React.ReactElement {
36
- const [state, setState] = useState<ISelectionFlowState>(() => createSelectionFlowState());
37
- const stateRef = useRef(state);
38
- const isEnabled = !loading && !error;
39
- const applyAction = useCallback(
40
- (action: TSelectionInputAction): void => {
41
- const result = applySelectionInput(stateRef.current, action, {
42
- itemCount: items.length,
43
- enabled: isEnabled,
44
- });
45
- stateRef.current = result.state;
46
- setState(result.state);
47
- if (result.effect.type === 'cancel') {
48
- onBack();
49
- } else if (result.effect.type === 'select') {
50
- const item = items[result.effect.index];
51
- if (item !== undefined) {
52
- onSelect(item.value);
53
- }
54
- }
55
- },
56
- [isEnabled, items, onBack, onSelect],
57
- );
58
-
59
- useInput((input, key) => {
60
- const action = getVerticalSelectionInputAction(key);
61
- if (action !== undefined) {
62
- applyAction(action);
63
- }
64
- });
65
-
66
- const normalizedState = normalizeSelectionState(state, { itemCount: items.length });
67
- if (normalizedState !== state) {
68
- stateRef.current = normalizedState;
69
- }
70
- const selected = normalizedState.selectedIndex;
71
-
72
- return (
73
- <Box flexDirection="column" borderStyle="round" borderColor="yellow" paddingX={1}>
74
- <Text color="yellow" bold>
75
- {title}
76
- </Text>
77
- {loading && (
78
- <Box marginTop={1}>
79
- <Text dimColor>Loading...</Text>
80
- </Box>
81
- )}
82
- {error && (
83
- <Box marginTop={1} flexDirection="column">
84
- <Text color="red">{error}</Text>
85
- <Text dimColor>Press Esc to go back</Text>
86
- </Box>
87
- )}
88
- {!loading && !error && (
89
- <Box flexDirection="column" marginTop={1}>
90
- {items.map((item, i) => (
91
- <Box key={item.value}>
92
- <Text color={i === selected ? 'cyan' : undefined} bold={i === selected}>
93
- {i === selected ? '> ' : ' '}
94
- {item.label}
95
- </Text>
96
- {item.hint && <Text dimColor> {item.hint}</Text>}
97
- </Box>
98
- ))}
99
- </Box>
100
- )}
101
- <Text dimColor>{loading || error ? '' : ' ↑↓ Navigate Enter Select Esc Back'}</Text>
102
- </Box>
103
- );
104
- }