@robota-sdk/agent-transport 3.0.0-beta.64 → 3.0.0-beta.66

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 (142) hide show
  1. package/README.md +97 -0
  2. package/dist/node/chunk-Bmb41Sf3.cjs +1 -0
  3. package/dist/node/headless/index.cjs +1 -1
  4. package/dist/node/headless/index.d.ts +2 -2
  5. package/dist/node/headless/index.js +1 -1
  6. package/dist/node/headless-B8yWkXW_.js +15 -0
  7. package/dist/node/headless-B8yWkXW_.js.map +1 -0
  8. package/dist/node/headless-Dp3kQVmo.cjs +14 -0
  9. package/dist/node/http/index.cjs +1 -1
  10. package/dist/node/http/index.d.ts +1 -1
  11. package/dist/node/http/index.js +1 -1
  12. package/dist/node/{http-DwO1AHG-.js → http-Br10Ps8m.js} +1 -1
  13. package/dist/node/http-Br10Ps8m.js.map +1 -0
  14. package/dist/node/http-Da6Kw4oy.cjs +1 -0
  15. package/dist/node/{index-Y0zHb1Bz.d.ts → index-C5KNEBO9.d.ts} +1 -1
  16. package/dist/node/{index-B_rcr14p.d.ts.map → index-C5KNEBO9.d.ts.map} +1 -1
  17. package/dist/node/{index-B_rcr14p.d.ts → index-C7DvsmEg.d.ts} +2 -2
  18. package/dist/node/{index-Y0zHb1Bz.d.ts.map → index-C7DvsmEg.d.ts.map} +1 -1
  19. package/dist/node/index-C9LWCL4l.d.ts.map +1 -1
  20. package/dist/node/{index-D34WUfFH.d.ts → index-CP7kaYMg.d.ts} +17 -2
  21. package/dist/node/index-CP7kaYMg.d.ts.map +1 -0
  22. package/dist/node/{index-CAr3ioVh.d.ts → index-CQsMNXAh.d.ts} +19 -16
  23. package/dist/node/index-CQsMNXAh.d.ts.map +1 -0
  24. package/dist/node/{index-nBlMTFkZ.d.ts → index-DOA2KIYt.d.ts} +2 -2
  25. package/dist/node/{index-nBlMTFkZ.d.ts.map → index-DOA2KIYt.d.ts.map} +1 -1
  26. package/dist/node/{index-k3TUjA-T.d.ts → index-Gby9H4q2.d.ts} +17 -2
  27. package/dist/node/index-Gby9H4q2.d.ts.map +1 -0
  28. package/dist/node/{index-CEs25wVk.d.ts → index-X2Zg8FEY.d.ts} +2 -2
  29. package/dist/node/{index-CEs25wVk.d.ts.map → index-X2Zg8FEY.d.ts.map} +1 -1
  30. package/dist/node/{index--Ti9NzQX.d.ts → index-rGmGTQ9o.d.ts} +19 -16
  31. package/dist/node/index-rGmGTQ9o.d.ts.map +1 -0
  32. package/dist/node/{index-CvXLpjJO.d.ts → index-yvGShbDx.d.ts} +2 -2
  33. package/dist/node/{index-CvXLpjJO.d.ts.map → index-yvGShbDx.d.ts.map} +1 -1
  34. package/dist/node/index.cjs +1 -1
  35. package/dist/node/index.d.ts +28 -6
  36. package/dist/node/index.d.ts.map +1 -0
  37. package/dist/node/index.js +2 -1
  38. package/dist/node/index.js.map +1 -0
  39. package/dist/node/mcp/index.cjs +1 -1
  40. package/dist/node/mcp/index.d.ts +1 -1
  41. package/dist/node/mcp/index.js +1 -1
  42. package/dist/node/{mcp-BXBwF6Wu.js → mcp-BAujHOMr.js} +1 -1
  43. package/dist/node/mcp-BAujHOMr.js.map +1 -0
  44. package/dist/node/mcp-Bl8jUfev.cjs +1 -0
  45. package/dist/node/tui/index.cjs +1 -1
  46. package/dist/node/tui/index.d.ts +2 -2
  47. package/dist/node/tui/index.js +1 -1
  48. package/dist/node/tui-B8G3yHrL.cjs +24 -0
  49. package/dist/node/tui-DUIfVw3G.js +25 -0
  50. package/dist/node/tui-DUIfVw3G.js.map +1 -0
  51. package/dist/node/ws/index.cjs +1 -1
  52. package/dist/node/ws/index.d.ts +1 -1
  53. package/dist/node/ws/index.js +1 -1
  54. package/dist/node/{ws-B-oRccFl.js → ws-BWel8nzl.js} +1 -1
  55. package/dist/node/ws-BWel8nzl.js.map +1 -0
  56. package/dist/node/ws-tCjj2gPu.cjs +1 -0
  57. package/package.json +19 -18
  58. package/src/headless/cli-input.ts +50 -0
  59. package/src/headless/headless-runner.ts +2 -1
  60. package/src/headless/headless-stream-json.ts +1 -0
  61. package/src/headless/headless-transport.ts +3 -2
  62. package/src/headless/index.ts +2 -0
  63. package/src/headless/print-terminal.ts +57 -0
  64. package/src/http/http-transport.ts +3 -3
  65. package/src/http/routes.ts +2 -1
  66. package/src/index.ts +2 -1
  67. package/src/mcp/mcp-server.ts +1 -0
  68. package/src/mcp/mcp-transport.ts +3 -2
  69. package/src/transport-registry.ts +100 -0
  70. package/src/tui/App.tsx +52 -31
  71. package/src/tui/BackgroundTaskPanel.tsx +4 -2
  72. package/src/tui/CjkTextInput.tsx +3 -2
  73. package/src/tui/ConfirmPrompt.tsx +2 -1
  74. package/src/tui/ExecutionWorkspaceDetailPane.tsx +7 -5
  75. package/src/tui/ExecutionWorkspaceSwitcher.tsx +8 -6
  76. package/src/tui/InputArea.tsx +72 -12
  77. package/src/tui/InteractivePrompt.tsx +5 -3
  78. package/src/tui/ListPicker.tsx +2 -1
  79. package/src/tui/MenuSelect.tsx +2 -1
  80. package/src/tui/MessageList.tsx +8 -6
  81. package/src/tui/PermissionPrompt.tsx +5 -3
  82. package/src/tui/PluginTUI.tsx +5 -3
  83. package/src/tui/SessionPicker.tsx +4 -2
  84. package/src/tui/SessionStatusBar.tsx +7 -3
  85. package/src/tui/SlashAutocomplete.tsx +6 -6
  86. package/src/tui/StatusBar.tsx +5 -3
  87. package/src/tui/StreamingIndicator.tsx +4 -2
  88. package/src/tui/TextPrompt.tsx +2 -1
  89. package/src/tui/ToolCommandOutput.tsx +4 -2
  90. package/src/tui/ToolDiffBlock.tsx +4 -2
  91. package/src/tui/TransportTUI.tsx +3 -2
  92. package/src/tui/UpdateNotice.tsx +1 -1
  93. package/src/tui/UsageSummaryEntry.tsx +3 -2
  94. package/src/tui/WaveText.tsx +1 -1
  95. package/src/tui/__tests__/fixtures/provider-setup-prompt-driver.tsx +7 -4
  96. package/src/tui/__tests__/input-area-flow.test.ts +19 -0
  97. package/src/tui/background-task-row-format.ts +2 -1
  98. package/src/tui/command-interaction-registry.ts +66 -0
  99. package/src/tui/command-interaction.ts +9 -0
  100. package/src/tui/create-default-tui-cli-adapter.ts +42 -0
  101. package/src/tui/flows/input-area-flow.ts +10 -2
  102. package/src/tui/hooks/command-effect-handler.ts +4 -3
  103. package/src/tui/hooks/side-effects-types.ts +1 -1
  104. package/src/tui/hooks/use-interactive-session-init.ts +4 -2
  105. package/src/tui/hooks/useAutocomplete.ts +1 -0
  106. package/src/tui/hooks/useInteractiveSession.ts +22 -19
  107. package/src/tui/hooks/usePermissionQueue.ts +2 -1
  108. package/src/tui/hooks/usePluginCallbacks.ts +1 -0
  109. package/src/tui/hooks/usePluginScreenData.ts +2 -1
  110. package/src/tui/hooks/useSideEffects.ts +8 -6
  111. package/src/tui/hooks/useSlashRouting.ts +4 -3
  112. package/src/tui/hooks/useStatusLineSettings.ts +4 -2
  113. package/src/tui/index.ts +11 -1
  114. package/src/tui/interactions/CommandConfirm.tsx +36 -0
  115. package/src/tui/interactions/CommandPicker.tsx +77 -0
  116. package/src/tui/render-markdown.ts +2 -1
  117. package/src/tui/render.tsx +12 -26
  118. package/src/tui/tui-cli-adapter-context.tsx +1 -0
  119. package/src/tui/tui-cli-adapter.ts +1 -1
  120. package/src/tui/tui-transport.ts +5 -4
  121. package/src/tui/utils/edit-diff.ts +1 -0
  122. package/src/tui/utils/tool-call-extractor.ts +1 -0
  123. package/src/ws/ws-background-messages.ts +1 -1
  124. package/src/ws/ws-handler.ts +6 -5
  125. package/src/ws/ws-transport-configurable.ts +6 -3
  126. package/src/ws/ws-transport.ts +3 -2
  127. package/dist/node/headless-CWEpJXFK.js +0 -7
  128. package/dist/node/headless-CWEpJXFK.js.map +0 -1
  129. package/dist/node/headless-CsZFelG9.cjs +0 -6
  130. package/dist/node/http-CM3TJhrF.cjs +0 -1
  131. package/dist/node/http-DwO1AHG-.js.map +0 -1
  132. package/dist/node/index--Ti9NzQX.d.ts.map +0 -1
  133. package/dist/node/index-CAr3ioVh.d.ts.map +0 -1
  134. package/dist/node/index-D34WUfFH.d.ts.map +0 -1
  135. package/dist/node/index-k3TUjA-T.d.ts.map +0 -1
  136. package/dist/node/mcp-BXBwF6Wu.js.map +0 -1
  137. package/dist/node/mcp-DcHuGokt.cjs +0 -1
  138. package/dist/node/tui-CeD_6rSo.cjs +0 -24
  139. package/dist/node/tui-zmDTPk4b.js +0 -25
  140. package/dist/node/tui-zmDTPk4b.js.map +0 -1
  141. package/dist/node/ws-B-oRccFl.js.map +0 -1
  142. package/dist/node/ws-COnIgnmn.cjs +0 -1
@@ -11,9 +11,10 @@
11
11
  * Drop-in replacement: same props as ink-text-input.
12
12
  */
13
13
 
14
- import React, { useRef, useState } from 'react';
15
- import { Text, useInput, usePaste } from 'ink';
16
14
  import chalk from 'chalk';
15
+ import { Text, useInput, usePaste } from 'ink';
16
+ import React, { useRef, useState } from 'react';
17
+
17
18
  import {
18
19
  applyCjkTextInput,
19
20
  applyCjkTextPaste,
@@ -3,8 +3,9 @@
3
3
  * Used by model change, permission prompts, and other yes/no confirmations.
4
4
  */
5
5
 
6
- import React, { useState, useRef, useCallback } from 'react';
7
6
  import { Box, Text, useInput } from 'ink';
7
+ import React, { useState, useRef, useCallback } from 'react';
8
+
8
9
  import {
9
10
  applyConfirmPromptInput,
10
11
  getConfirmPromptInputAction,
@@ -1,14 +1,16 @@
1
- import React from 'react';
2
1
  import { Box, Text } from 'ink';
2
+ import React from 'react';
3
+
4
+ import {
5
+ formatExecutionDetailRecord,
6
+ formatExecutionWorkspaceEntryRow,
7
+ } from './execution-workspace-view-model.js';
8
+
3
9
  import type {
4
10
  IExecutionDetailPage,
5
11
  IExecutionWorkspaceEntry,
6
12
  TExecutionDetailRecordKind,
7
13
  } from '@robota-sdk/agent-framework';
8
- import {
9
- formatExecutionDetailRecord,
10
- formatExecutionWorkspaceEntryRow,
11
- } from './execution-workspace-view-model.js';
12
14
 
13
15
  const MAX_VISIBLE_DETAIL_RECORDS = 12;
14
16
 
@@ -1,9 +1,7 @@
1
- import React, { useEffect, useRef, useState } from 'react';
2
1
  import { Box, Text, useInput } from 'ink';
3
- import type {
4
- IExecutionWorkspaceEntry,
5
- IExecutionWorkspaceSnapshot,
6
- } from '@robota-sdk/agent-framework';
2
+ import React, { useEffect, useRef, useState } from 'react';
3
+
4
+ import { formatExecutionWorkspaceEntryRow } from './execution-workspace-view-model.js';
7
5
  import {
8
6
  applySelectionInput,
9
7
  createSelectionFlowState,
@@ -12,7 +10,11 @@ import {
12
10
  type ISelectionFlowState,
13
11
  type TSelectionInputAction,
14
12
  } from './flows/selection-flow.js';
15
- import { formatExecutionWorkspaceEntryRow } from './execution-workspace-view-model.js';
13
+
14
+ import type {
15
+ IExecutionWorkspaceEntry,
16
+ IExecutionWorkspaceSnapshot,
17
+ } from '@robota-sdk/agent-framework';
16
18
 
17
19
  const MAX_VISIBLE_WORKSPACE_ENTRIES = 8;
18
20
 
@@ -1,15 +1,17 @@
1
+ import { Box, Text, useInput, useWindowSize } from 'ink';
1
2
  import React, { useState, useCallback, useRef, useMemo } from 'react';
2
3
 
3
4
  const PENDING_PROMPT_DISPLAY_MAX = 50;
4
5
  const PENDING_PROMPT_TAIL_KEEP = 47;
5
- import { Box, Text, useInput, useWindowSize } from 'ink';
6
- import type { IHistoryEntry } from '@robota-sdk/agent-core';
7
- import type { CommandRegistry, ICommand } from '@robota-sdk/agent-framework';
6
+
8
7
  import CjkTextInput from './CjkTextInput.js';
9
- import WaveText from './WaveText.js';
10
- import SlashAutocomplete from './SlashAutocomplete.js';
11
- import { expandPasteLabels } from './utils/paste-labels.js';
12
- import { useAutocomplete } from './hooks/useAutocomplete.js';
8
+ import { resolveCommandInteraction } from './command-interaction-registry.js';
9
+ import {
10
+ isPickerInteraction,
11
+ isConfirmInteraction,
12
+ type ITuiCommandInteraction,
13
+ type ITuiPickerItem,
14
+ } from './command-interaction.js';
13
15
  import {
14
16
  appendPromptHistory,
15
17
  createPasteLabelChange,
@@ -24,6 +26,20 @@ import {
24
26
  resolveTabCompletion,
25
27
  shouldSubmitInput,
26
28
  } from './flows/input-area-flow.js';
29
+ import { useAutocomplete } from './hooks/useAutocomplete.js';
30
+ import CommandConfirm from './interactions/CommandConfirm.js';
31
+ import CommandPicker from './interactions/CommandPicker.js';
32
+ import SlashAutocomplete from './SlashAutocomplete.js';
33
+ import { expandPasteLabels } from './utils/paste-labels.js';
34
+ import WaveText from './WaveText.js';
35
+
36
+ import type { IHistoryEntry } from '@robota-sdk/agent-core';
37
+ import type { CommandRegistry, ICommand } from '@robota-sdk/agent-framework';
38
+
39
+ interface IActiveInteraction {
40
+ commandName: string;
41
+ interaction: ITuiCommandInteraction;
42
+ }
27
43
 
28
44
  interface IProps {
29
45
  onSubmit: (value: string) => void;
@@ -68,6 +84,7 @@ export default function InputArea({
68
84
  }: IProps): React.ReactElement {
69
85
  const [value, setValue] = useState('');
70
86
  const [cursorHint, setCursorHint] = useState<number | null>(null);
87
+ const [activeInteraction, setActiveInteraction] = useState<IActiveInteraction | null>(null);
71
88
  const [historyState, setHistoryState] = useState(createPromptHistoryNavigationState);
72
89
  const [localPromptHistory, setLocalPromptHistory] = useState<string[]>([]);
73
90
  const restoredPromptHistory = useMemo(() => extractPromptHistory(history ?? []), [history]);
@@ -139,7 +156,8 @@ export default function InputArea({
139
156
  /** Enter: insert and execute command immediately */
140
157
  const enterSelectCommand = useCallback(
141
158
  (cmd: ICommand): void => {
142
- const result = resolveEnterCommandSelection(value, cmd);
159
+ const interaction = resolveCommandInteraction(cmd.name);
160
+ const result = resolveEnterCommandSelection(value, cmd, interaction);
143
161
  if (result.type === 'insert') {
144
162
  setValue(result.value);
145
163
  if (result.selectedIndex !== undefined) {
@@ -147,10 +165,17 @@ export default function InputArea({
147
165
  }
148
166
  return;
149
167
  }
150
- setValue('');
151
- submitPrompt(result.value);
168
+ if (result.type === 'open-interaction' && interaction?.onMissingArgs) {
169
+ setShowPopup(false);
170
+ setActiveInteraction({ commandName: result.commandName, interaction });
171
+ return;
172
+ }
173
+ if (result.type === 'submit') {
174
+ setValue('');
175
+ submitPrompt(result.value);
176
+ }
152
177
  },
153
- [value, submitPrompt, setSelectedIndex],
178
+ [value, submitPrompt, setSelectedIndex, setShowPopup],
154
179
  );
155
180
 
156
181
  const handleSubmit = useCallback(
@@ -238,9 +263,44 @@ export default function InputArea({
238
263
  return { left: '┌' + '─'.repeat(innerWidth), label: '', right: '┐' };
239
264
  })();
240
265
 
266
+ const handlePickerSelect = useCallback(
267
+ (item: ITuiPickerItem): void => {
268
+ if (!activeInteraction) return;
269
+ setActiveInteraction(null);
270
+ submitPrompt(`/${activeInteraction.commandName} ${item.value}`);
271
+ },
272
+ [activeInteraction, submitPrompt],
273
+ );
274
+
275
+ const handleConfirm = useCallback((): void => {
276
+ if (!activeInteraction) return;
277
+ setActiveInteraction(null);
278
+ submitPrompt(`/${activeInteraction.commandName}`);
279
+ }, [activeInteraction, submitPrompt]);
280
+
281
+ const handleInteractionCancel = useCallback((): void => {
282
+ setActiveInteraction(null);
283
+ }, []);
284
+
241
285
  return (
242
286
  <Box flexDirection="column">
243
- {showPopup && (
287
+ {activeInteraction && isPickerInteraction(activeInteraction.interaction) && (
288
+ <CommandPicker
289
+ commandName={activeInteraction.commandName}
290
+ interaction={activeInteraction.interaction}
291
+ onSelect={handlePickerSelect}
292
+ onCancel={handleInteractionCancel}
293
+ />
294
+ )}
295
+ {activeInteraction && isConfirmInteraction(activeInteraction.interaction) && (
296
+ <CommandConfirm
297
+ commandName={activeInteraction.commandName}
298
+ interaction={activeInteraction.interaction}
299
+ onConfirm={handleConfirm}
300
+ onCancel={handleInteractionCancel}
301
+ />
302
+ )}
303
+ {!activeInteraction && showPopup && (
244
304
  <SlashAutocomplete
245
305
  commands={filteredCommands}
246
306
  selectedIndex={selectedIndex}
@@ -1,11 +1,13 @@
1
- import React from 'react';
2
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
+
3
7
  import type {
4
8
  TCommandInteractionPrompt as TInteractivePrompt,
5
9
  ICommandChoicePromptOption as IChoicePromptOption,
6
10
  } from '@robota-sdk/agent-framework';
7
- import ListPicker from './ListPicker.js';
8
- import TextPrompt from './TextPrompt.js';
9
11
 
10
12
  interface IInteractivePromptProps {
11
13
  prompt: TInteractivePrompt;
@@ -4,8 +4,9 @@
4
4
  * Shows a limited number of items at a time; scrolls as the cursor moves.
5
5
  */
6
6
 
7
- import React, { useState, useRef, useCallback } from 'react';
8
7
  import { Box, Text, useInput } from 'ink';
8
+ import React, { useState, useRef, useCallback } from 'react';
9
+
9
10
  import {
10
11
  applySelectionInput,
11
12
  createSelectionFlowState,
@@ -1,5 +1,6 @@
1
- import React, { useState, useCallback, useRef } from 'react';
2
1
  import { Box, Text, useInput } from 'ink';
2
+ import React, { useState, useCallback, useRef } from 'react';
3
+
3
4
  import {
4
5
  applySelectionInput,
5
6
  createSelectionFlowState,
@@ -1,13 +1,15 @@
1
- import React from 'react';
2
- import { Box, Text } from 'ink';
3
- import type { IHistoryEntry, TUniversalMessage, TUniversalValue } from '@robota-sdk/agent-core';
4
1
  import { isToolMessage, isAssistantMessage } from '@robota-sdk/agent-core';
2
+ import { Box, Text } from 'ink';
3
+ import React from 'react';
4
+
5
+ import { formatCommandOutputSummary } from './command-output-summary.js';
5
6
  import { renderMarkdown } from './render-markdown.js';
6
- import type { IToolCallSummary } from './utils/tool-call-extractor.js';
7
+ import ToolCommandOutput from './ToolCommandOutput.js';
7
8
  import ToolDiffBlock from './ToolDiffBlock.js';
8
9
  import UsageSummaryEntry from './UsageSummaryEntry.js';
9
- import { formatCommandOutputSummary } from './command-output-summary.js';
10
- import ToolCommandOutput from './ToolCommandOutput.js';
10
+
11
+ import type { IToolCallSummary } from './utils/tool-call-extractor.js';
12
+ import type { IHistoryEntry, TUniversalMessage, TUniversalValue } from '@robota-sdk/agent-core';
11
13
 
12
14
  interface IProps {
13
15
  history: IHistoryEntry[];
@@ -1,7 +1,6 @@
1
- import React from 'react';
2
1
  import { Box, Text, useInput } from 'ink';
3
- import type { IPermissionRequest } from './types.js';
4
- import type { TToolArgs } from '@robota-sdk/agent-core';
2
+ import React from 'react';
3
+
5
4
  import {
6
5
  applyPermissionPromptInput,
7
6
  getPermissionPromptInputAction,
@@ -10,6 +9,9 @@ import {
10
9
  } from './flows/permission-prompt-flow.js';
11
10
  import { createSelectionFlowState, type ISelectionFlowState } from './flows/selection-flow.js';
12
11
 
12
+ import type { IPermissionRequest } from './types.js';
13
+ import type { TToolArgs } from '@robota-sdk/agent-core';
14
+
13
15
  interface IProps {
14
16
  request: IPermissionRequest;
15
17
  }
@@ -4,9 +4,10 @@
4
4
  */
5
5
 
6
6
  import React, { useState, useCallback } from 'react';
7
- import MenuSelect from './MenuSelect.js';
8
- import TextPrompt from './TextPrompt.js';
7
+
9
8
  import ConfirmPrompt from './ConfirmPrompt.js';
9
+ import { usePluginScreenData } from './hooks/usePluginScreenData.js';
10
+ import MenuSelect from './MenuSelect.js';
10
11
  import {
11
12
  handleMainSelect,
12
13
  handleMarketplaceListSelect,
@@ -16,9 +17,10 @@ import {
16
17
  handleInstalledListSelect,
17
18
  handleInstalledActionSelect,
18
19
  } from './plugin-tui-handlers.js';
20
+ import TextPrompt from './TextPrompt.js';
21
+
19
22
  import type { IMenuSelectItem } from './MenuSelect.js';
20
23
  import type { ICommandPluginAdapter } from '@robota-sdk/agent-framework';
21
- import { usePluginScreenData } from './hooks/usePluginScreenData.js';
22
24
 
23
25
  type TScreenId =
24
26
  | 'main'
@@ -3,11 +3,13 @@
3
3
  * Shows a list of sessions for the current cwd.
4
4
  */
5
5
 
6
- import React from 'react';
7
6
  import { Box, Text } from 'ink';
8
- import type { IResumableSessionSummary } from '@robota-sdk/agent-framework';
7
+ import React from 'react';
8
+
9
9
  import ListPicker from './ListPicker.js';
10
10
 
11
+ import type { IResumableSessionSummary } from '@robota-sdk/agent-framework';
12
+
11
13
  const SESSION_ID_DISPLAY_LENGTH = 8;
12
14
  const SESSION_PREVIEW_DISPLAY_LENGTH = 60;
13
15
 
@@ -1,8 +1,10 @@
1
1
  import React, { useMemo } from 'react';
2
+
3
+ import StatusBar from './StatusBar.js';
4
+ import { useTuiCliAdapter } from './tui-cli-adapter-context.js';
5
+
2
6
  import type { TPermissionMode } from '@robota-sdk/agent-core';
3
7
  import type { IStatusLineCommandSettings } from '@robota-sdk/agent-framework';
4
- import { useTuiCliAdapter } from './tui-cli-adapter-context.js';
5
- import StatusBar from './StatusBar.js';
6
8
 
7
9
  interface IProps {
8
10
  cwd: string;
@@ -18,6 +20,7 @@ interface IProps {
18
20
  sessionName?: string;
19
21
  settings: IStatusLineCommandSettings;
20
22
  activeAgentLabel?: string;
23
+ gitRefreshToken?: number;
21
24
  }
22
25
 
23
26
  export default function SessionStatusBar({
@@ -34,9 +37,10 @@ export default function SessionStatusBar({
34
37
  sessionName,
35
38
  settings,
36
39
  activeAgentLabel,
40
+ gitRefreshToken,
37
41
  }: IProps): React.ReactElement | null {
38
42
  const cliAdapter = useTuiCliAdapter();
39
- const gitBranch = useMemo(() => cliAdapter.getGitBranch(cwd), [cliAdapter, cwd]);
43
+ const gitBranch = useMemo(() => cliAdapter.getGitBranch(cwd), [cliAdapter, cwd, gitRefreshToken]);
40
44
  const providerDisplayName = useMemo(
41
45
  () =>
42
46
  providerType !== undefined ? cliAdapter.getProviderDisplayName(providerType) : undefined,
@@ -1,5 +1,6 @@
1
- import React, { useState, useEffect } from 'react';
2
1
  import { Box, Text, useStdout } from 'ink';
2
+ import React, { useState, useEffect } from 'react';
3
+
3
4
  import type { ICommand } from '@robota-sdk/agent-framework';
4
5
 
5
6
  interface IProps {
@@ -21,11 +22,11 @@ const NAME_COL_MAX = 20;
21
22
 
22
23
  function useRowWidth(): number {
23
24
  const { stdout } = useStdout();
24
- const measure = () => Math.max(MIN_ROW_WIDTH, (stdout.columns ?? 80) - OUTER_CHROME);
25
+ const measure = (): number => Math.max(MIN_ROW_WIDTH, (stdout.columns ?? 80) - OUTER_CHROME);
25
26
  const [width, setWidth] = useState(measure);
26
27
 
27
28
  useEffect(() => {
28
- const onResize = () => setWidth(measure());
29
+ const onResize = (): void => setWidth(measure());
29
30
  stdout.on('resize', onResize);
30
31
  return () => {
31
32
  stdout.off('resize', onResize);
@@ -51,8 +52,7 @@ function CommandRow(props: {
51
52
  const indicator = isSelected ? '▸ ' : ' ';
52
53
  const nameColor = isSelected ? 'cyan' : undefined;
53
54
  const dimmed = !isSelected;
54
- const displayLabel = cmd.displayName ?? cmd.name;
55
- const namePart = capName(displayLabel, nameColWidth);
55
+ const namePart = capName(cmd.name, nameColWidth);
56
56
  const text = showSlash
57
57
  ? `${indicator}/${namePart} ${cmd.description ?? ''}`
58
58
  : `${indicator}${namePart} ${cmd.description ?? ''}`;
@@ -82,7 +82,7 @@ export default function SlashAutocomplete({
82
82
 
83
83
  const nameColWidth = Math.min(
84
84
  NAME_COL_MAX,
85
- Math.max(...visibleCommands.map((c) => (c.displayName ?? c.name).length)),
85
+ Math.max(...visibleCommands.map((c) => c.name.length)),
86
86
  );
87
87
 
88
88
  return (
@@ -1,9 +1,11 @@
1
- import React from 'react';
2
- import { Box, Text } from 'ink';
3
- import type { TPermissionMode } from '@robota-sdk/agent-core';
4
1
  import { formatTokenCount } from '@robota-sdk/agent-core';
2
+ import { Box, Text } from 'ink';
3
+ import React from 'react';
4
+
5
5
  import { formatStatusActivity } from './status-activity.js';
6
6
 
7
+ import type { TPermissionMode } from '@robota-sdk/agent-core';
8
+
7
9
  /** Threshold boundaries for context percentage color coding */
8
10
  const CONTEXT_YELLOW_THRESHOLD = 70;
9
11
  const CONTEXT_RED_THRESHOLD = 90;
@@ -3,12 +3,14 @@
3
3
  * Displayed during session.run() execution.
4
4
  */
5
5
 
6
- import React from 'react';
7
6
  import { Box, Text } from 'ink';
8
- import type { IToolState } from '@robota-sdk/agent-framework';
7
+ import React from 'react';
8
+
9
9
  import { renderMarkdown } from './render-markdown.js';
10
10
  import ToolDiffBlock from './ToolDiffBlock.js';
11
11
 
12
+ import type { IToolState } from '@robota-sdk/agent-framework';
13
+
12
14
  function getToolStyle(t: IToolState): {
13
15
  color: string;
14
16
  icon: string;
@@ -1,5 +1,6 @@
1
- import React, { useState, useRef, useCallback } from 'react';
2
1
  import { Box, Text, useInput } from 'ink';
2
+ import React, { useState, useRef, useCallback } from 'react';
3
+
3
4
  import {
4
5
  applyTextPromptInput,
5
6
  createTextPromptFlowState,
@@ -1,8 +1,10 @@
1
- import React from 'react';
2
1
  import { Box, Text } from 'ink';
3
- import type { ICommandOutputInput } from './command-output-summary.js';
2
+ import React from 'react';
3
+
4
4
  import { formatCommandOutputSummary } from './command-output-summary.js';
5
5
 
6
+ import type { ICommandOutputInput } from './command-output-summary.js';
7
+
6
8
  interface IProps {
7
9
  tool: ICommandOutputInput;
8
10
  }
@@ -1,7 +1,9 @@
1
- import React from 'react';
2
1
  import { Box, Text } from 'ink';
3
- import { buildToolDiffSummary } from './utils/tool-diff-summary.js';
2
+ import React from 'react';
3
+
4
4
  import { renderMarkdown } from './render-markdown.js';
5
+ import { buildToolDiffSummary } from './utils/tool-diff-summary.js';
6
+
5
7
  import type { IDiffLine } from './utils/edit-diff.js';
6
8
 
7
9
  interface IProps {
@@ -4,13 +4,14 @@
4
4
  * Arrow keys navigate the list, space toggles enabled/disabled, enter/esc closes.
5
5
  */
6
6
 
7
- import React, { useState, useCallback } from 'react';
8
7
  import { Box, Text, useInput } from 'ink';
8
+ import React, { useState, useCallback } from 'react';
9
+
10
+ import type { IInteractiveSession } from '@robota-sdk/agent-framework';
9
11
  import type {
10
12
  ITransportEntry,
11
13
  ITransportRegistryView,
12
14
  } from '@robota-sdk/agent-interface-transport';
13
- import type { IInteractiveSession } from '@robota-sdk/agent-framework';
14
15
 
15
16
  const TRANSPORT_NAME_WIDTH = 18;
16
17
 
@@ -1,5 +1,5 @@
1
- import React from 'react';
2
1
  import { Box, Text } from 'ink';
2
+ import React from 'react';
3
3
 
4
4
  interface IProps {
5
5
  message: string;
@@ -1,7 +1,8 @@
1
- import React from 'react';
1
+ import { formatTokenCount } from '@robota-sdk/agent-core';
2
2
  import { Box, Text } from 'ink';
3
+ import React from 'react';
4
+
3
5
  import type { IHistoryEntry } from '@robota-sdk/agent-core';
4
- import { formatTokenCount } from '@robota-sdk/agent-core';
5
6
  import type { IUsageSnapshot } from '@robota-sdk/agent-framework';
6
7
 
7
8
  const TOKEN_COMPACT_THRESHOLD = 1000;
@@ -4,8 +4,8 @@
4
4
  * Colors stay in a narrow range (dim grays) to avoid harsh contrast.
5
5
  */
6
6
 
7
- import React, { useState, useEffect } from 'react';
8
7
  import { Text } from 'ink';
8
+ import React, { useState, useEffect } from 'react';
9
9
 
10
10
  // Subtle gray tones — minimal contrast, soft wave
11
11
  const WAVE_COLORS = ['#666666', '#888888', '#aaaaaa', '#888888'] as const;
@@ -1,8 +1,5 @@
1
- import React from 'react';
2
1
  import { writeFileSync } from 'node:fs';
3
- import { render, useApp } from 'ink';
4
- import InteractivePrompt from '../../InteractivePrompt.js';
5
- import type { TCommandInteractionPrompt as TInteractivePrompt } from '@robota-sdk/agent-framework';
2
+
6
3
  import {
7
4
  createProviderSetupFlow,
8
5
  formatProviderSetupHelpLinks,
@@ -12,7 +9,13 @@ import {
12
9
  type IProviderSetupFlowState,
13
10
  type TProviderSetupType,
14
11
  } from '@robota-sdk/agent-command';
12
+ import { render, useApp } from 'ink';
13
+ import React from 'react';
14
+
15
+ import InteractivePrompt from '../../InteractivePrompt.js';
16
+
15
17
  import type { IAIProvider, IProviderDefinition } from '@robota-sdk/agent-core';
18
+ import type { TCommandInteractionPrompt as TInteractivePrompt } from '@robota-sdk/agent-framework';
16
19
 
17
20
  const openaiDefaults = {
18
21
  apiKey: '$ENV:OPENAI_API_KEY',
@@ -14,6 +14,7 @@ import {
14
14
  shouldSubmitInput,
15
15
  } from '../flows/input-area-flow.js';
16
16
  import type { ICommand } from '@robota-sdk/agent-framework';
17
+ import type { ITuiPickerInteraction } from '../command-interaction.js';
17
18
  import {
18
19
  createAssistantMessage,
19
20
  createSystemMessage,
@@ -66,6 +67,24 @@ describe('input area flow', () => {
66
67
  expect(result).toEqual({ type: 'submit', value: '/help' });
67
68
  });
68
69
 
70
+ it('Given interaction declared and no args When enter selects command Then open-interaction is returned', () => {
71
+ const result = resolveEnterCommandSelection('/ex', command('exit'), {
72
+ onMissingArgs: 'confirm',
73
+ });
74
+
75
+ expect(result).toEqual({ type: 'open-interaction', commandName: 'exit' });
76
+ });
77
+
78
+ it('Given interaction declared but subcommand selected (args present) When enter selects Then submits', () => {
79
+ const pickerInteraction: ITuiPickerInteraction = {
80
+ onMissingArgs: 'picker',
81
+ getItems: () => [],
82
+ };
83
+ const result = resolveEnterCommandSelection('/mode plan', command('plan'), pickerInteraction);
84
+
85
+ expect(result).toEqual({ type: 'submit', value: '/mode plan' });
86
+ });
87
+
69
88
  it('Given multiline paste When label change is created Then label is inserted at cursor', () => {
70
89
  const result = createPasteLabelChange('abef', 2, 7, 'c\nd\ne');
71
90
 
@@ -1,6 +1,7 @@
1
- import type { IExecutionWorkspaceEntry } from '@robota-sdk/agent-framework';
2
1
  import { formatExecutionWorkspaceEntryRow } from './execution-workspace-view-model.js';
3
2
 
3
+ import type { IExecutionWorkspaceEntry } from '@robota-sdk/agent-framework';
4
+
4
5
  export interface IBackgroundTaskRow {
5
6
  connector: '├' | '└';
6
7
  marker: '□' | '■';
@@ -0,0 +1,66 @@
1
+ import type { ITuiPickerItem, TAnyTuiCommandInteraction } from './command-interaction.js';
2
+
3
+ function getModeItems(): ITuiPickerItem[] {
4
+ return [
5
+ { label: 'plan', value: 'plan', description: 'Plan only, no execution' },
6
+ { label: 'default', value: 'default', description: 'Ask before risky actions' },
7
+ { label: 'acceptEdits', value: 'acceptEdits', description: 'Auto-approve file edits' },
8
+ {
9
+ label: 'bypassPermissions',
10
+ value: 'bypassPermissions',
11
+ description: 'Skip all permission checks',
12
+ },
13
+ ];
14
+ }
15
+
16
+ function getLanguageItems(): ITuiPickerItem[] {
17
+ return [
18
+ { label: 'ko Korean', value: 'ko', description: '한국어' },
19
+ { label: 'en English', value: 'en', description: 'English' },
20
+ { label: 'ja Japanese', value: 'ja', description: '日本語' },
21
+ { label: 'zh Chinese', value: 'zh', description: '中文' },
22
+ ];
23
+ }
24
+
25
+ function getProviderSubcommandItems(): ITuiPickerItem[] {
26
+ return [
27
+ { label: 'current', value: 'current', description: 'Show current provider' },
28
+ { label: 'list', value: 'list', description: 'List available providers' },
29
+ { label: 'use', value: 'use', description: 'Switch to a provider' },
30
+ { label: 'add', value: 'add', description: 'Add a new provider' },
31
+ { label: 'test', value: 'test', description: 'Test provider connection' },
32
+ ];
33
+ }
34
+
35
+ const BUILT_IN_INTERACTIONS: Record<string, TAnyTuiCommandInteraction | undefined> = {
36
+ agent: undefined,
37
+ background: undefined,
38
+ clear: { onMissingArgs: 'confirm', message: 'Clear conversation history?' },
39
+ compact: undefined,
40
+ context: undefined,
41
+ cost: undefined,
42
+ exit: { onMissingArgs: 'confirm', message: 'Exit the session?' },
43
+ help: undefined,
44
+ language: { onMissingArgs: 'picker', getItems: getLanguageItems },
45
+ memory: undefined,
46
+ mode: { onMissingArgs: 'picker', getItems: getModeItems },
47
+ model: undefined,
48
+ permissions: undefined,
49
+ plugin: undefined,
50
+ provider: { onMissingArgs: 'picker', getItems: getProviderSubcommandItems },
51
+ rename: undefined,
52
+ reset: undefined,
53
+ resume: undefined,
54
+ rewind: undefined,
55
+ settings: undefined,
56
+ skills: undefined,
57
+ statusline: undefined,
58
+ 'user-local': undefined,
59
+ 'validate-session': undefined,
60
+ };
61
+
62
+ export function resolveCommandInteraction(
63
+ commandName: string,
64
+ ): TAnyTuiCommandInteraction | undefined {
65
+ return BUILT_IN_INTERACTIONS[commandName];
66
+ }