@robota-sdk/agent-transport 3.0.0-beta.75 → 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 (187) hide show
  1. package/README.md +10 -10
  2. package/dist/node/headless/index.cjs +1 -1
  3. package/dist/node/{headless-CT2ibQnr.cjs → headless-OnpVk4-k.cjs} +7 -7
  4. package/dist/node/index.cjs +1 -1
  5. package/dist/node/index.d.ts +1 -6
  6. package/dist/node/index.d.ts.map +1 -1
  7. package/dist/node/index.js +1 -1
  8. package/dist/node/index.js.map +1 -1
  9. package/package.json +7 -75
  10. package/src/index.ts +1 -5
  11. package/src/transport-registry.ts +0 -9
  12. package/dist/node/http/index.cjs +0 -1
  13. package/dist/node/http/index.d.ts +0 -2
  14. package/dist/node/http/index.js +0 -1
  15. package/dist/node/http-2Jiuflc1.js +0 -2
  16. package/dist/node/http-2Jiuflc1.js.map +0 -1
  17. package/dist/node/http-CBAvefLw.cjs +0 -1
  18. package/dist/node/index-BNccqSpv.d.ts +0 -86
  19. package/dist/node/index-BNccqSpv.d.ts.map +0 -1
  20. package/dist/node/index-BUhHIf7X.d.ts +0 -86
  21. package/dist/node/index-BUhHIf7X.d.ts.map +0 -1
  22. package/dist/node/index-BnAGE-u9.d.ts +0 -33
  23. package/dist/node/index-BnAGE-u9.d.ts.map +0 -1
  24. package/dist/node/index-BrQ4gGw0.d.ts +0 -213
  25. package/dist/node/index-BrQ4gGw0.d.ts.map +0 -1
  26. package/dist/node/index-CoeBF21y.d.ts +0 -213
  27. package/dist/node/index-CoeBF21y.d.ts.map +0 -1
  28. package/dist/node/index-DHt-2VQ-.d.ts +0 -46
  29. package/dist/node/index-DHt-2VQ-.d.ts.map +0 -1
  30. package/dist/node/index-DMwKN5Le.d.ts +0 -33
  31. package/dist/node/index-DMwKN5Le.d.ts.map +0 -1
  32. package/dist/node/index-c0M42fsA.d.ts +0 -46
  33. package/dist/node/index-c0M42fsA.d.ts.map +0 -1
  34. package/dist/node/mcp/index.cjs +0 -1
  35. package/dist/node/mcp/index.d.ts +0 -2
  36. package/dist/node/mcp/index.js +0 -1
  37. package/dist/node/mcp-BOglBJNy.cjs +0 -1
  38. package/dist/node/mcp-D3BBVK7C.js +0 -2
  39. package/dist/node/mcp-D3BBVK7C.js.map +0 -1
  40. package/dist/node/rolldown-runtime-CMqjfN_6.cjs +0 -1
  41. package/dist/node/tui/index.cjs +0 -1
  42. package/dist/node/tui/index.d.ts +0 -2
  43. package/dist/node/tui/index.js +0 -1
  44. package/dist/node/tui-CcH5EsQh.js +0 -25
  45. package/dist/node/tui-CcH5EsQh.js.map +0 -1
  46. package/dist/node/tui-DznRbcku.cjs +0 -24
  47. package/dist/node/ws/index.cjs +0 -1
  48. package/dist/node/ws/index.d.ts +0 -2
  49. package/dist/node/ws/index.js +0 -1
  50. package/dist/node/ws-Dc2RUwVs.js +0 -2
  51. package/dist/node/ws-Dc2RUwVs.js.map +0 -1
  52. package/dist/node/ws-QNMQn5kg.cjs +0 -1
  53. package/src/http/__tests__/http-transport.test.ts +0 -55
  54. package/src/http/__tests__/routes.test.ts +0 -168
  55. package/src/http/http-transport.ts +0 -41
  56. package/src/http/index.ts +0 -4
  57. package/src/http/routes.ts +0 -152
  58. package/src/mcp/__tests__/mcp-server.test.ts +0 -66
  59. package/src/mcp/__tests__/mcp-transport.test.ts +0 -46
  60. package/src/mcp/index.ts +0 -4
  61. package/src/mcp/mcp-server.ts +0 -163
  62. package/src/mcp/mcp-transport.ts +0 -48
  63. package/src/tui/App.tsx +0 -491
  64. package/src/tui/BackgroundTaskPanel.tsx +0 -36
  65. package/src/tui/CjkTextInput.tsx +0 -199
  66. package/src/tui/ConfirmPrompt.tsx +0 -70
  67. package/src/tui/ContextWarningBanner.tsx +0 -34
  68. package/src/tui/ExecutionWorkspaceDetailPane.tsx +0 -64
  69. package/src/tui/ExecutionWorkspaceSwitcher.tsx +0 -187
  70. package/src/tui/InputArea.tsx +0 -310
  71. package/src/tui/InteractivePrompt.tsx +0 -59
  72. package/src/tui/ListPicker.tsx +0 -95
  73. package/src/tui/MenuSelect.tsx +0 -104
  74. package/src/tui/MessageList.tsx +0 -284
  75. package/src/tui/PermissionPrompt.tsx +0 -86
  76. package/src/tui/PluginTUI.tsx +0 -258
  77. package/src/tui/SessionPicker.tsx +0 -68
  78. package/src/tui/SessionStatusBar.tsx +0 -73
  79. package/src/tui/SlashAutocomplete.tsx +0 -110
  80. package/src/tui/StatusBar.tsx +0 -236
  81. package/src/tui/StreamingIndicator.tsx +0 -93
  82. package/src/tui/TextPrompt.tsx +0 -81
  83. package/src/tui/ToolCommandOutput.tsx +0 -39
  84. package/src/tui/ToolDiffBlock.tsx +0 -32
  85. package/src/tui/TransportTUI.tsx +0 -117
  86. package/src/tui/TuiInteractionChannel.ts +0 -495
  87. package/src/tui/UpdateNotice.tsx +0 -14
  88. package/src/tui/UsageSummaryEntry.tsx +0 -39
  89. package/src/tui/WaveText.tsx +0 -44
  90. package/src/tui/__tests__/InteractivePrompt.test.tsx +0 -82
  91. package/src/tui/__tests__/ListPicker.test.tsx +0 -159
  92. package/src/tui/__tests__/MenuSelect.test.tsx +0 -103
  93. package/src/tui/__tests__/PluginTUI.test.tsx +0 -167
  94. package/src/tui/__tests__/SlashAutocomplete.test.tsx +0 -140
  95. package/src/tui/__tests__/TextPrompt.test.tsx +0 -98
  96. package/src/tui/__tests__/TuiInteractionChannel.display-contract.test.ts +0 -239
  97. package/src/tui/__tests__/TuiInteractionChannel.lifecycle.test.ts +0 -297
  98. package/src/tui/__tests__/TuiInteractionChannel.requestAction.test.ts +0 -124
  99. package/src/tui/__tests__/UpdateNotice.test.tsx +0 -15
  100. package/src/tui/__tests__/abort-after-permission.test.tsx +0 -169
  101. package/src/tui/__tests__/abort-streaming-e2e.test.tsx +0 -183
  102. package/src/tui/__tests__/background-task-panel.test.tsx +0 -53
  103. package/src/tui/__tests__/background-task-row-format.test.ts +0 -59
  104. package/src/tui/__tests__/channel-factory-integration.test.ts +0 -138
  105. package/src/tui/__tests__/cjk-text-input-flow.test.ts +0 -109
  106. package/src/tui/__tests__/cjk-text-input.test.ts +0 -191
  107. package/src/tui/__tests__/command-effect-handler.test.ts +0 -127
  108. package/src/tui/__tests__/command-output-summary.test.ts +0 -95
  109. package/src/tui/__tests__/compact-event-bridge.test.ts +0 -20
  110. package/src/tui/__tests__/confirm-permission-flow.test.ts +0 -130
  111. package/src/tui/__tests__/confirm-prompt.test.tsx +0 -87
  112. package/src/tui/__tests__/execution-workspace-switcher.test.tsx +0 -110
  113. package/src/tui/__tests__/execution-workspace-view-model.test.ts +0 -93
  114. package/src/tui/__tests__/fixtures/provider-setup-prompt-driver.tsx +0 -125
  115. package/src/tui/__tests__/input-area-flow.test.ts +0 -164
  116. package/src/tui/__tests__/message-list-rendering.test.tsx +0 -353
  117. package/src/tui/__tests__/prompt-queue.test.tsx +0 -255
  118. package/src/tui/__tests__/provider-setup-pty-e2e.test.ts +0 -233
  119. package/src/tui/__tests__/pty/pty-driver.ts +0 -135
  120. package/src/tui/__tests__/pty/tui-pty.ptytest.ts +0 -61
  121. package/src/tui/__tests__/render-channel-options.test.ts +0 -32
  122. package/src/tui/__tests__/render-markdown.test.ts +0 -72
  123. package/src/tui/__tests__/selection-flow.test.ts +0 -61
  124. package/src/tui/__tests__/session-init-poller.test.ts +0 -102
  125. package/src/tui/__tests__/session-naming.test.ts +0 -64
  126. package/src/tui/__tests__/session-switch-channel.test.tsx +0 -307
  127. package/src/tui/__tests__/slash-routing-effects.test.ts +0 -228
  128. package/src/tui/__tests__/status-activity.test.ts +0 -71
  129. package/src/tui/__tests__/status-bar.test.tsx +0 -177
  130. package/src/tui/__tests__/streaming-indicator.test.tsx +0 -137
  131. package/src/tui/__tests__/text-prompt-flow.test.ts +0 -77
  132. package/src/tui/__tests__/tui-channel-init-failure.test.ts +0 -57
  133. package/src/tui/__tests__/tui-state-manager.test.ts +0 -401
  134. package/src/tui/background-task-row-format.ts +0 -53
  135. package/src/tui/command-interaction.ts +0 -9
  136. package/src/tui/command-output-summary.ts +0 -122
  137. package/src/tui/create-default-tui-cli-adapter.ts +0 -41
  138. package/src/tui/execution-workspace-view-model.ts +0 -123
  139. package/src/tui/flows/cjk-text-input-flow.ts +0 -285
  140. package/src/tui/flows/confirm-prompt-flow.ts +0 -45
  141. package/src/tui/flows/input-area-flow.ts +0 -189
  142. package/src/tui/flows/permission-prompt-flow.ts +0 -85
  143. package/src/tui/flows/selection-flow.ts +0 -126
  144. package/src/tui/flows/session-init-poller.ts +0 -77
  145. package/src/tui/flows/text-prompt-flow.ts +0 -98
  146. package/src/tui/hooks/command-effect-handler.ts +0 -97
  147. package/src/tui/hooks/command-effect-queue.ts +0 -39
  148. package/src/tui/hooks/side-effects-types.ts +0 -35
  149. package/src/tui/hooks/useAutocomplete.ts +0 -87
  150. package/src/tui/hooks/usePluginCallbacks.ts +0 -31
  151. package/src/tui/hooks/usePluginScreenData.ts +0 -85
  152. package/src/tui/hooks/useSideEffects.ts +0 -175
  153. package/src/tui/hooks/useSlashRouting.ts +0 -118
  154. package/src/tui/hooks/useStatusLineSettings.ts +0 -37
  155. package/src/tui/hooks/useTuiChannel.ts +0 -95
  156. package/src/tui/index.ts +0 -14
  157. package/src/tui/interactions/CommandConfirm.tsx +0 -36
  158. package/src/tui/interactions/CommandPicker.tsx +0 -77
  159. package/src/tui/interactions/__tests__/CommandConfirm.test.tsx +0 -124
  160. package/src/tui/interactions/__tests__/CommandPicker.test.tsx +0 -138
  161. package/src/tui/plugin-tui-handlers.ts +0 -163
  162. package/src/tui/render-markdown.ts +0 -130
  163. package/src/tui/render.tsx +0 -129
  164. package/src/tui/session-naming.ts +0 -33
  165. package/src/tui/status-activity.ts +0 -63
  166. package/src/tui/tui-cli-adapter-context.tsx +0 -13
  167. package/src/tui/tui-cli-adapter.ts +0 -25
  168. package/src/tui/tui-state-manager.ts +0 -226
  169. package/src/tui/tui-transport.ts +0 -35
  170. package/src/tui/types.ts +0 -15
  171. package/src/tui/utils/__tests__/edit-diff.test.ts +0 -426
  172. package/src/tui/utils/__tests__/paste-detection.test.ts +0 -116
  173. package/src/tui/utils/__tests__/paste-labels.test.ts +0 -46
  174. package/src/tui/utils/__tests__/tool-call-extractor.test.ts +0 -227
  175. package/src/tui/utils/__tests__/tool-diff-summary.test.ts +0 -104
  176. package/src/tui/utils/edit-diff.ts +0 -153
  177. package/src/tui/utils/paste-labels.ts +0 -9
  178. package/src/tui/utils/tool-call-extractor.ts +0 -92
  179. package/src/tui/utils/tool-diff-summary.ts +0 -75
  180. package/src/ws/__tests__/ws-handler.test.ts +0 -409
  181. package/src/ws/__tests__/ws-transport.test.ts +0 -53
  182. package/src/ws/index.ts +0 -13
  183. package/src/ws/ws-background-messages.ts +0 -170
  184. package/src/ws/ws-handler.ts +0 -280
  185. package/src/ws/ws-protocol.ts +0 -78
  186. package/src/ws/ws-transport-configurable.ts +0 -128
  187. 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
- }