@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,123 +0,0 @@
1
- import type {
2
- IExecutionDetailRecord,
3
- IExecutionWorkspaceEntry,
4
- IExecutionWorkspaceSnapshot,
5
- TExecutionWorkspaceStatus,
6
- } from '@robota-sdk/agent-interface-transport';
7
-
8
- const ACTIVE_STATUSES: readonly TExecutionWorkspaceStatus[] = [
9
- 'active',
10
- 'queued',
11
- 'running',
12
- 'waiting_permission',
13
- 'sleeping',
14
- ];
15
- const DETAIL_RECORD_TEXT_LIMIT = 160;
16
- const PREVIEW_WHITESPACE = /\s+/g;
17
- const PREVIEW_SEPARATOR = ' ';
18
-
19
- export interface IExecutionWorkspaceEntryRow {
20
- id: string;
21
- radio: '●' | '○';
22
- title: string;
23
- subtitle?: string;
24
- statusLabel: string;
25
- preview?: string;
26
- color: string;
27
- isSelected: boolean;
28
- accessibleText: string;
29
- }
30
-
31
- export interface IExecutionWorkspaceEntryRowOptions {
32
- selectedEntryId?: string;
33
- }
34
-
35
- export function getDefaultBackgroundWorkspaceEntries(
36
- snapshot: IExecutionWorkspaceSnapshot | null,
37
- ): IExecutionWorkspaceEntry[] {
38
- return (snapshot?.entries ?? []).filter(
39
- (entry) => entry.kind === 'background_task' && entry.visibility === 'default',
40
- );
41
- }
42
-
43
- export function countActiveBackgroundWorkspaceEntries(
44
- snapshot: IExecutionWorkspaceSnapshot | null,
45
- ): number {
46
- return getDefaultBackgroundWorkspaceEntries(snapshot).filter((entry) =>
47
- ACTIVE_STATUSES.includes(entry.status),
48
- ).length;
49
- }
50
-
51
- export function formatExecutionWorkspaceEntryRow(
52
- entry: IExecutionWorkspaceEntry,
53
- options: IExecutionWorkspaceEntryRowOptions = {},
54
- ): IExecutionWorkspaceEntryRow {
55
- const isSelected = entry.id === options.selectedEntryId;
56
- const row = {
57
- id: entry.id,
58
- radio: isSelected ? '●' : '○',
59
- title: formatEntryTitle(entry),
60
- subtitle: formatEntrySubtitle(entry),
61
- statusLabel: formatStatusLabel(entry.status),
62
- preview: trimPreview(entry.preview ?? entry.currentAction),
63
- color: getEntryColor(entry),
64
- isSelected,
65
- } satisfies Omit<IExecutionWorkspaceEntryRow, 'accessibleText'>;
66
- return { ...row, accessibleText: formatAccessibleText(row) };
67
- }
68
-
69
- export function formatExecutionDetailRecord(record: IExecutionDetailRecord): string {
70
- const text = record.text.trim().replace(PREVIEW_WHITESPACE, PREVIEW_SEPARATOR);
71
- if (!text) return record.kind;
72
- return text.length > DETAIL_RECORD_TEXT_LIMIT
73
- ? `${text.slice(0, DETAIL_RECORD_TEXT_LIMIT)}...`
74
- : text;
75
- }
76
-
77
- function formatEntryTitle(entry: IExecutionWorkspaceEntry): string {
78
- if (entry.kind === 'main_thread') return entry.title;
79
- if (entry.kind === 'background_group') return `${entry.title} group`;
80
- if (entry.taskKind === 'agent') return `${entry.title} agent`;
81
- if (entry.taskKind === 'process') return entry.title || 'Process';
82
- if (entry.taskKind === 'scheduled') return entry.title || 'Scheduled';
83
- return entry.title;
84
- }
85
-
86
- function formatEntrySubtitle(entry: IExecutionWorkspaceEntry): string | undefined {
87
- if (entry.kind === 'main_thread') return entry.subtitle;
88
- const parts = [
89
- entry.taskKind,
90
- entry.subtitle,
91
- entry.attention === 'none' ? undefined : entry.attention,
92
- ];
93
- return (
94
- parts
95
- .filter((part): part is string => typeof part === 'string' && part.length > 0)
96
- .join(' · ') || undefined
97
- );
98
- }
99
-
100
- function formatStatusLabel(status: TExecutionWorkspaceStatus): string {
101
- return status.replace(/_/g, ' ');
102
- }
103
-
104
- function getEntryColor(entry: IExecutionWorkspaceEntry): string {
105
- if (entry.attention === 'failed' || entry.status === 'failed') return 'red';
106
- if (entry.attention === 'permission' || entry.status === 'waiting_permission') return 'yellow';
107
- if (entry.status === 'completed') return 'green';
108
- if (entry.status === 'cancelled') return 'yellow';
109
- if (ACTIVE_STATUSES.includes(entry.status)) return 'cyan';
110
- return 'white';
111
- }
112
-
113
- function trimPreview(value: string | undefined): string | undefined {
114
- const preview = value?.trim().replace(PREVIEW_WHITESPACE, PREVIEW_SEPARATOR);
115
- return preview || undefined;
116
- }
117
-
118
- function formatAccessibleText(row: Omit<IExecutionWorkspaceEntryRow, 'accessibleText'>): string {
119
- const parts = [row.radio, row.title, row.statusLabel, row.subtitle, row.preview];
120
- return parts
121
- .filter((part): part is string => typeof part === 'string' && part.length > 0)
122
- .join(' · ');
123
- }
@@ -1,285 +0,0 @@
1
- import stringWidth from 'string-width';
2
-
3
- const PASTE_START = '[200~';
4
- const PASTE_END = '[201~';
5
- const LAST_ASCII_CONTROL_CODE = 0x1f;
6
- const DELETE_CONTROL_CODE = 0x7f;
7
-
8
- export interface ICjkTextInputFlowState {
9
- value: string;
10
- cursor: number;
11
- isPasting: boolean;
12
- pasteBuffer: string;
13
- }
14
-
15
- export interface ICjkTextInputKey {
16
- ctrl?: boolean;
17
- tab?: boolean;
18
- shift?: boolean;
19
- upArrow?: boolean;
20
- downArrow?: boolean;
21
- return?: boolean;
22
- leftArrow?: boolean;
23
- rightArrow?: boolean;
24
- backspace?: boolean;
25
- delete?: boolean;
26
- }
27
-
28
- export interface ICjkTextInputFlowOptions {
29
- availableWidth?: number;
30
- canPaste: boolean;
31
- enableVerticalNavigation?: boolean;
32
- }
33
-
34
- export type TCjkTextInputEffect =
35
- | { type: 'none' }
36
- | { type: 'change'; value: string }
37
- | { type: 'submit'; value: string }
38
- | { type: 'paste'; text: string; cursor: number }
39
- | { type: 'render' };
40
-
41
- interface ICjkTextInputFlowResult {
42
- state: ICjkTextInputFlowState;
43
- effect: TCjkTextInputEffect;
44
- }
45
-
46
- export function createCjkTextInputFlowState(value: string): ICjkTextInputFlowState {
47
- return { value, cursor: value.length, isPasting: false, pasteBuffer: '' };
48
- }
49
-
50
- export function syncCjkTextInputFlowState(
51
- state: ICjkTextInputFlowState,
52
- value: string,
53
- cursorHint: number | null,
54
- ): ICjkTextInputFlowState {
55
- if (value === state.value) {
56
- return state;
57
- }
58
- return {
59
- ...state,
60
- value,
61
- cursor: cursorHint != null ? Math.min(cursorHint, value.length) : value.length,
62
- };
63
- }
64
-
65
- export function applyCjkTextInput(
66
- state: ICjkTextInputFlowState,
67
- input: string,
68
- key: ICjkTextInputKey,
69
- options: ICjkTextInputFlowOptions,
70
- ): ICjkTextInputFlowResult {
71
- const pasteResult = applyPasteBoundaryInput(state, input, options);
72
- if (pasteResult !== undefined) return pasteResult;
73
- const controlResult = applyControlInput(state, input, key, options);
74
- if (controlResult !== undefined) return controlResult;
75
- const cursorResult = applyCursorInput(state, key, options);
76
- if (cursorResult !== undefined) return cursorResult;
77
- return insertPrintableInput(state, input);
78
- }
79
-
80
- export function applyCjkTextPaste(
81
- state: ICjkTextInputFlowState,
82
- text: string,
83
- options: ICjkTextInputFlowOptions,
84
- ): ICjkTextInputFlowResult {
85
- const normalizedText = text.replace(/\r\n?/g, '\n');
86
- if (normalizedText.length === 0) {
87
- return { state, effect: { type: 'none' } };
88
- }
89
- if (normalizedText.includes('\n') && options.canPaste) {
90
- return { state, effect: { type: 'paste', text: normalizedText, cursor: state.cursor } };
91
- }
92
- return insertPrintableInput(state, normalizedText);
93
- }
94
-
95
- function applyPasteBoundaryInput(
96
- state: ICjkTextInputFlowState,
97
- input: string,
98
- options: ICjkTextInputFlowOptions,
99
- ): ICjkTextInputFlowResult | undefined {
100
- if (input === PASTE_START || input.startsWith(PASTE_START)) {
101
- return startBracketedPaste(state, input);
102
- }
103
- if (state.isPasting) {
104
- return continueBracketedPaste(state, input, options);
105
- }
106
- return undefined;
107
- }
108
-
109
- function applyControlInput(
110
- state: ICjkTextInputFlowState,
111
- input: string,
112
- key: ICjkTextInputKey,
113
- options: ICjkTextInputFlowOptions,
114
- ): ICjkTextInputFlowResult | undefined {
115
- if ((key.ctrl === true && input === 'c') || key.tab === true) {
116
- return { state, effect: { type: 'none' } };
117
- }
118
- if (key.return === true) {
119
- return { state, effect: { type: 'submit', value: state.value } };
120
- }
121
- if (input.length > 1 && (input.includes('\n') || input.includes('\r')) && options.canPaste) {
122
- return {
123
- state,
124
- effect: { type: 'paste', text: input.replace(/\r\n?/g, '\n'), cursor: state.cursor },
125
- };
126
- }
127
- return undefined;
128
- }
129
-
130
- function applyCursorInput(
131
- state: ICjkTextInputFlowState,
132
- key: ICjkTextInputKey,
133
- options: ICjkTextInputFlowOptions,
134
- ): ICjkTextInputFlowResult | undefined {
135
- if (key.upArrow === true || key.downArrow === true) {
136
- if (options.enableVerticalNavigation === false) {
137
- return { state, effect: { type: 'none' } };
138
- }
139
- return moveCursorVertically(
140
- state,
141
- key.upArrow === true ? 'up' : 'down',
142
- options.availableWidth,
143
- );
144
- }
145
- if (key.leftArrow === true) {
146
- return moveCursorHorizontally(state, 'left');
147
- }
148
- if (key.rightArrow === true) {
149
- return moveCursorHorizontally(state, 'right');
150
- }
151
- if (key.backspace === true || key.delete === true) {
152
- return deleteBeforeCursor(state);
153
- }
154
- return undefined;
155
- }
156
-
157
- export function filterPrintable(input: string | null | undefined): string {
158
- if (!input || input.length === 0) return '';
159
- let output = '';
160
- for (const char of input) {
161
- const code = char.charCodeAt(0);
162
- if (code > LAST_ASCII_CONTROL_CODE && code !== DELETE_CONTROL_CODE) {
163
- output += char;
164
- }
165
- }
166
- return output;
167
- }
168
-
169
- export function insertAtCursor(
170
- value: string,
171
- cursor: number,
172
- input: string,
173
- ): { value: string; cursor: number } {
174
- const next = value.slice(0, cursor) + input + value.slice(cursor);
175
- return { value: next, cursor: cursor + input.length };
176
- }
177
-
178
- export function displayOffset(chars: string[], charIndex: number, width: number): number {
179
- let offset = 0;
180
- for (let i = 0; i < charIndex && i < chars.length; i++) {
181
- const w = stringWidth(chars[i]!);
182
- const col = offset % width;
183
- if (col + w > width) offset += width - col;
184
- offset += w;
185
- }
186
- return offset;
187
- }
188
-
189
- export function charIndexAtDisplayOffset(chars: string[], target: number, width: number): number {
190
- let offset = 0;
191
- for (let i = 0; i < chars.length; i++) {
192
- if (offset >= target) return i;
193
- const w = stringWidth(chars[i]!);
194
- const col = offset % width;
195
- if (col + w > width) offset += width - col;
196
- offset += w;
197
- }
198
- return chars.length;
199
- }
200
-
201
- function startBracketedPaste(
202
- state: ICjkTextInputFlowState,
203
- input: string,
204
- ): ICjkTextInputFlowResult {
205
- return {
206
- state: { ...state, isPasting: true, pasteBuffer: input.slice(PASTE_START.length) },
207
- effect: { type: 'none' },
208
- };
209
- }
210
-
211
- function continueBracketedPaste(
212
- state: ICjkTextInputFlowState,
213
- input: string,
214
- options: ICjkTextInputFlowOptions,
215
- ): ICjkTextInputFlowResult {
216
- if (input !== PASTE_END && !input.includes(PASTE_END)) {
217
- return {
218
- state: { ...state, pasteBuffer: state.pasteBuffer + input },
219
- effect: { type: 'none' },
220
- };
221
- }
222
- const beforeMarker = input.split(PASTE_END)[0] ?? '';
223
- const nextState = { ...state, isPasting: false, pasteBuffer: '' };
224
- return applyCjkTextPaste(nextState, state.pasteBuffer + beforeMarker, options);
225
- }
226
-
227
- function moveCursorVertically(
228
- state: ICjkTextInputFlowState,
229
- direction: 'up' | 'down',
230
- availableWidth: number | undefined,
231
- ): ICjkTextInputFlowResult {
232
- if (!availableWidth || availableWidth <= 0) {
233
- return { state, effect: { type: 'none' } };
234
- }
235
- const chars = [...state.value];
236
- const offset = displayOffset(chars, state.cursor, availableWidth);
237
- const target = direction === 'up' ? offset - availableWidth : offset + availableWidth;
238
- if (target < 0) {
239
- return { state, effect: { type: 'none' } };
240
- }
241
- const cursor = charIndexAtDisplayOffset(chars, target, availableWidth);
242
- if (cursor === state.cursor) {
243
- return { state, effect: { type: 'none' } };
244
- }
245
- return { state: { ...state, cursor }, effect: { type: 'render' } };
246
- }
247
-
248
- function moveCursorHorizontally(
249
- state: ICjkTextInputFlowState,
250
- direction: 'left' | 'right',
251
- ): ICjkTextInputFlowResult {
252
- if (direction === 'left' && state.cursor > 0) {
253
- return { state: { ...state, cursor: state.cursor - 1 }, effect: { type: 'render' } };
254
- }
255
- if (direction === 'right' && state.cursor < state.value.length) {
256
- return { state: { ...state, cursor: state.cursor + 1 }, effect: { type: 'render' } };
257
- }
258
- return { state, effect: { type: 'none' } };
259
- }
260
-
261
- function deleteBeforeCursor(state: ICjkTextInputFlowState): ICjkTextInputFlowResult {
262
- if (state.cursor === 0) {
263
- return { state, effect: { type: 'none' } };
264
- }
265
- const value = state.value.slice(0, state.cursor - 1) + state.value.slice(state.cursor);
266
- return {
267
- state: { ...state, value, cursor: state.cursor - 1 },
268
- effect: { type: 'change', value },
269
- };
270
- }
271
-
272
- function insertPrintableInput(
273
- state: ICjkTextInputFlowState,
274
- input: string,
275
- ): ICjkTextInputFlowResult {
276
- const printable = filterPrintable(input);
277
- if (printable.length === 0) {
278
- return { state, effect: { type: 'none' } };
279
- }
280
- const result = insertAtCursor(state.value, state.cursor, printable);
281
- return {
282
- state: { ...state, value: result.value, cursor: result.cursor },
283
- effect: { type: 'change', value: result.value },
284
- };
285
- }
@@ -1,45 +0,0 @@
1
- import {
2
- applySelectionInput,
3
- getDirectionalSelectionInputAction,
4
- type ISelectionFlowState,
5
- type ISelectionInputKey,
6
- type TSelectionEffect,
7
- type TSelectionInputAction,
8
- } from './selection-flow.js';
9
-
10
- export type TConfirmPromptInputAction = TSelectionInputAction | { type: 'shortcut'; index: number };
11
-
12
- export function getConfirmPromptInputAction(
13
- input: string,
14
- key: ISelectionInputKey,
15
- optionCount: number,
16
- ): TConfirmPromptInputAction | undefined {
17
- const action = getDirectionalSelectionInputAction({ ...key, escape: false });
18
- if (action !== undefined) {
19
- return action;
20
- }
21
- if (optionCount === 2 && input === 'y') {
22
- return { type: 'shortcut', index: 0 };
23
- }
24
- if (optionCount === 2 && input === 'n') {
25
- return { type: 'shortcut', index: 1 };
26
- }
27
- return undefined;
28
- }
29
-
30
- export function applyConfirmPromptInput(
31
- state: ISelectionFlowState,
32
- action: TConfirmPromptInputAction,
33
- optionCount: number,
34
- ): { state: ISelectionFlowState; effect: TSelectionEffect } {
35
- if (state.resolved) {
36
- return { state, effect: { type: 'none' } };
37
- }
38
- if (typeof action !== 'string') {
39
- return {
40
- state: { ...state, selectedIndex: action.index, resolved: true },
41
- effect: { type: 'select', index: action.index },
42
- };
43
- }
44
- return applySelectionInput(state, action, { itemCount: optionCount });
45
- }
@@ -1,189 +0,0 @@
1
- import { isSlashCommand, tokeniseSlashCommand } from '@robota-sdk/agent-framework';
2
-
3
- import type { IHistoryEntry, TUniversalValue } from '@robota-sdk/agent-core';
4
- import type { ICommand } from '@robota-sdk/agent-interface-transport';
5
-
6
- export interface IAutocompleteInputKey {
7
- upArrow?: boolean;
8
- downArrow?: boolean;
9
- escape?: boolean;
10
- tab?: boolean;
11
- backspace?: boolean;
12
- delete?: boolean;
13
- }
14
-
15
- export type TAutocompletePopupAction = 'previous' | 'next' | 'close' | 'complete';
16
- export type TPendingPromptInputAction = 'cancelQueue';
17
- export type TPromptHistoryInputAction = 'previous' | 'next';
18
-
19
- export type TCommandSelectionResult =
20
- | { type: 'insert'; value: string; selectedIndex?: number }
21
- | { type: 'submit'; value: string };
22
-
23
- export interface IPasteLabelChange {
24
- value: string;
25
- cursorHint: number;
26
- label: string;
27
- lineCount: number;
28
- }
29
-
30
- export interface IPromptHistoryNavigationState {
31
- selectedIndex: number | null;
32
- draft: string;
33
- }
34
-
35
- export interface IPromptHistoryNavigationResult {
36
- value: string;
37
- cursorHint: number;
38
- state: IPromptHistoryNavigationState;
39
- }
40
-
41
- export function getAutocompletePopupAction(
42
- key: IAutocompleteInputKey,
43
- ): TAutocompletePopupAction | undefined {
44
- if (key.upArrow === true) return 'previous';
45
- if (key.downArrow === true) return 'next';
46
- if (key.escape === true) return 'close';
47
- if (key.tab === true) return 'complete';
48
- return undefined;
49
- }
50
-
51
- export function getPendingPromptInputAction(
52
- key: IAutocompleteInputKey,
53
- ): TPendingPromptInputAction | undefined {
54
- if (key.backspace === true || key.delete === true) {
55
- return 'cancelQueue';
56
- }
57
- return undefined;
58
- }
59
-
60
- export function getPromptHistoryInputAction(
61
- key: IAutocompleteInputKey,
62
- ): TPromptHistoryInputAction | undefined {
63
- if (key.upArrow === true) return 'previous';
64
- if (key.downArrow === true) return 'next';
65
- return undefined;
66
- }
67
-
68
- export function createPromptHistoryNavigationState(): IPromptHistoryNavigationState {
69
- return { selectedIndex: null, draft: '' };
70
- }
71
-
72
- export function navigatePromptHistory(
73
- value: string,
74
- history: readonly string[],
75
- state: IPromptHistoryNavigationState,
76
- action: TPromptHistoryInputAction,
77
- ): IPromptHistoryNavigationResult {
78
- if (history.length === 0) {
79
- return { value, cursorHint: value.length, state };
80
- }
81
-
82
- if (action === 'previous') {
83
- const selectedIndex =
84
- state.selectedIndex === null ? history.length - 1 : Math.max(0, state.selectedIndex - 1);
85
- const nextValue = history[selectedIndex] ?? value;
86
- return {
87
- value: nextValue,
88
- cursorHint: nextValue.length,
89
- state: { selectedIndex, draft: state.selectedIndex === null ? value : state.draft },
90
- };
91
- }
92
-
93
- if (state.selectedIndex === null) {
94
- return { value, cursorHint: value.length, state };
95
- }
96
-
97
- if (state.selectedIndex < history.length - 1) {
98
- const selectedIndex = state.selectedIndex + 1;
99
- const nextValue = history[selectedIndex] ?? value;
100
- return {
101
- value: nextValue,
102
- cursorHint: nextValue.length,
103
- state: { ...state, selectedIndex },
104
- };
105
- }
106
-
107
- return {
108
- value: state.draft,
109
- cursorHint: state.draft.length,
110
- state: createPromptHistoryNavigationState(),
111
- };
112
- }
113
-
114
- export function appendPromptHistory(history: readonly string[], value: string): string[] {
115
- const prompt = value.trim();
116
- if (prompt.length === 0) return [...history];
117
- if (history[history.length - 1] === prompt) return [...history];
118
- return [...history, prompt];
119
- }
120
-
121
- export function extractPromptHistory(entries: readonly IHistoryEntry[]): string[] {
122
- let prompts: string[] = [];
123
- for (const entry of entries) {
124
- if (entry.category !== 'chat' || entry.type !== 'user') continue;
125
- const data = entry.data as Record<string, TUniversalValue> | undefined;
126
- if (typeof data?.content !== 'string') continue;
127
- prompts = appendPromptHistory(prompts, data.content);
128
- }
129
- return prompts;
130
- }
131
-
132
- export function moveAutocompleteSelection(
133
- selectedIndex: number,
134
- commandCount: number,
135
- direction: 'previous' | 'next',
136
- ): number {
137
- if (commandCount === 0) return 0;
138
- if (direction === 'previous') {
139
- return selectedIndex > 0 ? selectedIndex - 1 : commandCount - 1;
140
- }
141
- return selectedIndex < commandCount - 1 ? selectedIndex + 1 : 0;
142
- }
143
-
144
- export function resolveTabCompletion(value: string, command: ICommand): TCommandSelectionResult {
145
- // Subcommand mode: '/parent filter' — space present after command name
146
- if (isSlashCommand(value) && value.slice(1).includes(' ')) {
147
- const { name } = tokeniseSlashCommand(value);
148
- return { type: 'insert', value: `/${name} ${command.name} ` };
149
- }
150
- if (command.subcommands && command.subcommands.length > 0) {
151
- return { type: 'insert', value: `/${command.name} `, selectedIndex: 0 };
152
- }
153
- return { type: 'insert', value: `/${command.name} ` };
154
- }
155
-
156
- export function resolveEnterCommandSelection(
157
- value: string,
158
- command: ICommand,
159
- ): TCommandSelectionResult {
160
- // Subcommand mode: '/parent filter' — space present after command name
161
- if (isSlashCommand(value) && value.slice(1).includes(' ')) {
162
- const { name } = tokeniseSlashCommand(value);
163
- return { type: 'submit', value: `/${name} ${command.name}` };
164
- }
165
- if (command.subcommands && command.subcommands.length > 0) {
166
- return { type: 'insert', value: `/${command.name} `, selectedIndex: 0 };
167
- }
168
- return { type: 'submit', value: `/${command.name}` };
169
- }
170
-
171
- export function createPasteLabelChange(
172
- value: string,
173
- cursorPosition: number,
174
- pasteId: number,
175
- text: string,
176
- ): IPasteLabelChange {
177
- const lineCount = text.split('\n').length;
178
- const label = `[Pasted text #${pasteId} +${lineCount} lines]`;
179
- return {
180
- value: value.slice(0, cursorPosition) + label + value.slice(cursorPosition),
181
- cursorHint: cursorPosition + label.length,
182
- label,
183
- lineCount,
184
- };
185
- }
186
-
187
- export function shouldSubmitInput(text: string): boolean {
188
- return text.trim().length > 0;
189
- }