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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (197) hide show
  1. package/README.md +10 -10
  2. package/dist/node/headless/index.cjs +1 -1
  3. package/dist/node/headless/index.d.ts +1 -1
  4. package/dist/node/headless/index.js +1 -1
  5. package/dist/node/headless-OnpVk4-k.cjs +15 -0
  6. package/dist/node/{headless-D02zUEGh.js → headless-mRYilLfC.js} +2 -2
  7. package/dist/node/{headless-D02zUEGh.js.map → headless-mRYilLfC.js.map} +1 -1
  8. package/dist/node/{index-DE3-dHqw.d.ts → index-CYl7ksS6.d.ts} +12 -2
  9. package/dist/node/{index-DE3-dHqw.d.ts.map → index-CYl7ksS6.d.ts.map} +1 -1
  10. package/dist/node/{index-WKTgvhlg.d.ts → index-E8Gx4-lc.d.ts} +12 -2
  11. package/dist/node/{index-WKTgvhlg.d.ts.map → index-E8Gx4-lc.d.ts.map} +1 -1
  12. package/dist/node/index.cjs +1 -1
  13. package/dist/node/index.d.ts +2 -7
  14. package/dist/node/index.d.ts.map +1 -1
  15. package/dist/node/index.js +1 -1
  16. package/dist/node/index.js.map +1 -1
  17. package/package.json +7 -75
  18. package/src/headless/HeadlessInteractionChannel.ts +21 -1
  19. package/src/index.ts +1 -5
  20. package/src/transport-registry.ts +0 -9
  21. package/dist/node/headless-BeHAOlIM.cjs +0 -15
  22. package/dist/node/http/index.cjs +0 -1
  23. package/dist/node/http/index.d.ts +0 -2
  24. package/dist/node/http/index.js +0 -1
  25. package/dist/node/http-2Jiuflc1.js +0 -2
  26. package/dist/node/http-2Jiuflc1.js.map +0 -1
  27. package/dist/node/http-CBAvefLw.cjs +0 -1
  28. package/dist/node/index-BQLN_Lc9.d.ts +0 -78
  29. package/dist/node/index-BQLN_Lc9.d.ts.map +0 -1
  30. package/dist/node/index-BnAGE-u9.d.ts +0 -33
  31. package/dist/node/index-BnAGE-u9.d.ts.map +0 -1
  32. package/dist/node/index-BrQ4gGw0.d.ts +0 -213
  33. package/dist/node/index-BrQ4gGw0.d.ts.map +0 -1
  34. package/dist/node/index-CoeBF21y.d.ts +0 -213
  35. package/dist/node/index-CoeBF21y.d.ts.map +0 -1
  36. package/dist/node/index-DHt-2VQ-.d.ts +0 -46
  37. package/dist/node/index-DHt-2VQ-.d.ts.map +0 -1
  38. package/dist/node/index-DMwKN5Le.d.ts +0 -33
  39. package/dist/node/index-DMwKN5Le.d.ts.map +0 -1
  40. package/dist/node/index-IvYaYY6v.d.ts +0 -78
  41. package/dist/node/index-IvYaYY6v.d.ts.map +0 -1
  42. package/dist/node/index-c0M42fsA.d.ts +0 -46
  43. package/dist/node/index-c0M42fsA.d.ts.map +0 -1
  44. package/dist/node/mcp/index.cjs +0 -1
  45. package/dist/node/mcp/index.d.ts +0 -2
  46. package/dist/node/mcp/index.js +0 -1
  47. package/dist/node/mcp-BOglBJNy.cjs +0 -1
  48. package/dist/node/mcp-D3BBVK7C.js +0 -2
  49. package/dist/node/mcp-D3BBVK7C.js.map +0 -1
  50. package/dist/node/rolldown-runtime-CMqjfN_6.cjs +0 -1
  51. package/dist/node/tui/index.cjs +0 -1
  52. package/dist/node/tui/index.d.ts +0 -2
  53. package/dist/node/tui/index.js +0 -1
  54. package/dist/node/tui-Btb1q88j.js +0 -25
  55. package/dist/node/tui-Btb1q88j.js.map +0 -1
  56. package/dist/node/tui-SbUT7Zlt.cjs +0 -24
  57. package/dist/node/ws/index.cjs +0 -1
  58. package/dist/node/ws/index.d.ts +0 -2
  59. package/dist/node/ws/index.js +0 -1
  60. package/dist/node/ws-Dc2RUwVs.js +0 -2
  61. package/dist/node/ws-Dc2RUwVs.js.map +0 -1
  62. package/dist/node/ws-QNMQn5kg.cjs +0 -1
  63. package/src/http/__tests__/http-transport.test.ts +0 -55
  64. package/src/http/__tests__/routes.test.ts +0 -168
  65. package/src/http/http-transport.ts +0 -41
  66. package/src/http/index.ts +0 -4
  67. package/src/http/routes.ts +0 -152
  68. package/src/mcp/__tests__/mcp-server.test.ts +0 -66
  69. package/src/mcp/__tests__/mcp-transport.test.ts +0 -46
  70. package/src/mcp/index.ts +0 -4
  71. package/src/mcp/mcp-server.ts +0 -163
  72. package/src/mcp/mcp-transport.ts +0 -48
  73. package/src/tui/App.tsx +0 -488
  74. package/src/tui/BackgroundTaskPanel.tsx +0 -36
  75. package/src/tui/CjkTextInput.tsx +0 -199
  76. package/src/tui/ConfirmPrompt.tsx +0 -70
  77. package/src/tui/ContextWarningBanner.tsx +0 -34
  78. package/src/tui/ExecutionWorkspaceDetailPane.tsx +0 -64
  79. package/src/tui/ExecutionWorkspaceSwitcher.tsx +0 -187
  80. package/src/tui/InputArea.tsx +0 -310
  81. package/src/tui/InteractivePrompt.tsx +0 -59
  82. package/src/tui/ListPicker.tsx +0 -95
  83. package/src/tui/MenuSelect.tsx +0 -104
  84. package/src/tui/MessageList.tsx +0 -284
  85. package/src/tui/PermissionPrompt.tsx +0 -86
  86. package/src/tui/PluginTUI.tsx +0 -258
  87. package/src/tui/SessionPicker.tsx +0 -68
  88. package/src/tui/SessionStatusBar.tsx +0 -70
  89. package/src/tui/SlashAutocomplete.tsx +0 -110
  90. package/src/tui/StatusBar.tsx +0 -209
  91. package/src/tui/StreamingIndicator.tsx +0 -93
  92. package/src/tui/TextPrompt.tsx +0 -81
  93. package/src/tui/ToolCommandOutput.tsx +0 -39
  94. package/src/tui/ToolDiffBlock.tsx +0 -32
  95. package/src/tui/TransportTUI.tsx +0 -117
  96. package/src/tui/TuiInteractionChannel.ts +0 -483
  97. package/src/tui/UpdateNotice.tsx +0 -14
  98. package/src/tui/UsageSummaryEntry.tsx +0 -39
  99. package/src/tui/WaveText.tsx +0 -44
  100. package/src/tui/__tests__/InteractivePrompt.test.tsx +0 -82
  101. package/src/tui/__tests__/ListPicker.test.tsx +0 -159
  102. package/src/tui/__tests__/MenuSelect.test.tsx +0 -103
  103. package/src/tui/__tests__/PluginTUI.test.tsx +0 -167
  104. package/src/tui/__tests__/SlashAutocomplete.test.tsx +0 -140
  105. package/src/tui/__tests__/TextPrompt.test.tsx +0 -98
  106. package/src/tui/__tests__/TuiInteractionChannel.display-contract.test.ts +0 -239
  107. package/src/tui/__tests__/TuiInteractionChannel.lifecycle.test.ts +0 -297
  108. package/src/tui/__tests__/TuiInteractionChannel.requestAction.test.ts +0 -124
  109. package/src/tui/__tests__/UpdateNotice.test.tsx +0 -15
  110. package/src/tui/__tests__/abort-after-permission.test.tsx +0 -169
  111. package/src/tui/__tests__/abort-streaming-e2e.test.tsx +0 -183
  112. package/src/tui/__tests__/background-task-panel.test.tsx +0 -53
  113. package/src/tui/__tests__/background-task-row-format.test.ts +0 -59
  114. package/src/tui/__tests__/channel-factory-integration.test.ts +0 -138
  115. package/src/tui/__tests__/cjk-text-input-flow.test.ts +0 -109
  116. package/src/tui/__tests__/cjk-text-input.test.ts +0 -191
  117. package/src/tui/__tests__/command-effect-handler.test.ts +0 -127
  118. package/src/tui/__tests__/command-output-summary.test.ts +0 -95
  119. package/src/tui/__tests__/compact-event-bridge.test.ts +0 -20
  120. package/src/tui/__tests__/confirm-permission-flow.test.ts +0 -130
  121. package/src/tui/__tests__/confirm-prompt.test.tsx +0 -87
  122. package/src/tui/__tests__/execution-workspace-switcher.test.tsx +0 -110
  123. package/src/tui/__tests__/execution-workspace-view-model.test.ts +0 -93
  124. package/src/tui/__tests__/fixtures/provider-setup-prompt-driver.tsx +0 -125
  125. package/src/tui/__tests__/input-area-flow.test.ts +0 -164
  126. package/src/tui/__tests__/message-list-rendering.test.tsx +0 -353
  127. package/src/tui/__tests__/prompt-queue.test.tsx +0 -255
  128. package/src/tui/__tests__/provider-setup-pty-e2e.test.ts +0 -233
  129. package/src/tui/__tests__/pty/pty-driver.ts +0 -135
  130. package/src/tui/__tests__/pty/tui-pty.ptytest.ts +0 -61
  131. package/src/tui/__tests__/render-channel-options.test.ts +0 -32
  132. package/src/tui/__tests__/render-markdown.test.ts +0 -72
  133. package/src/tui/__tests__/selection-flow.test.ts +0 -61
  134. package/src/tui/__tests__/session-init-poller.test.ts +0 -102
  135. package/src/tui/__tests__/session-naming.test.ts +0 -64
  136. package/src/tui/__tests__/session-switch-channel.test.tsx +0 -307
  137. package/src/tui/__tests__/slash-routing-effects.test.ts +0 -228
  138. package/src/tui/__tests__/status-activity.test.ts +0 -71
  139. package/src/tui/__tests__/status-bar.test.tsx +0 -158
  140. package/src/tui/__tests__/streaming-indicator.test.tsx +0 -137
  141. package/src/tui/__tests__/text-prompt-flow.test.ts +0 -77
  142. package/src/tui/__tests__/tui-channel-init-failure.test.ts +0 -57
  143. package/src/tui/__tests__/tui-state-manager.test.ts +0 -401
  144. package/src/tui/background-task-row-format.ts +0 -53
  145. package/src/tui/command-interaction.ts +0 -9
  146. package/src/tui/command-output-summary.ts +0 -122
  147. package/src/tui/create-default-tui-cli-adapter.ts +0 -41
  148. package/src/tui/execution-workspace-view-model.ts +0 -123
  149. package/src/tui/flows/cjk-text-input-flow.ts +0 -285
  150. package/src/tui/flows/confirm-prompt-flow.ts +0 -45
  151. package/src/tui/flows/input-area-flow.ts +0 -189
  152. package/src/tui/flows/permission-prompt-flow.ts +0 -85
  153. package/src/tui/flows/selection-flow.ts +0 -126
  154. package/src/tui/flows/session-init-poller.ts +0 -77
  155. package/src/tui/flows/text-prompt-flow.ts +0 -98
  156. package/src/tui/hooks/command-effect-handler.ts +0 -97
  157. package/src/tui/hooks/command-effect-queue.ts +0 -39
  158. package/src/tui/hooks/side-effects-types.ts +0 -35
  159. package/src/tui/hooks/useAutocomplete.ts +0 -87
  160. package/src/tui/hooks/usePluginCallbacks.ts +0 -31
  161. package/src/tui/hooks/usePluginScreenData.ts +0 -85
  162. package/src/tui/hooks/useSideEffects.ts +0 -175
  163. package/src/tui/hooks/useSlashRouting.ts +0 -118
  164. package/src/tui/hooks/useStatusLineSettings.ts +0 -37
  165. package/src/tui/hooks/useTuiChannel.ts +0 -95
  166. package/src/tui/index.ts +0 -14
  167. package/src/tui/interactions/CommandConfirm.tsx +0 -36
  168. package/src/tui/interactions/CommandPicker.tsx +0 -77
  169. package/src/tui/interactions/__tests__/CommandConfirm.test.tsx +0 -124
  170. package/src/tui/interactions/__tests__/CommandPicker.test.tsx +0 -138
  171. package/src/tui/plugin-tui-handlers.ts +0 -163
  172. package/src/tui/render-markdown.ts +0 -130
  173. package/src/tui/render.tsx +0 -117
  174. package/src/tui/session-naming.ts +0 -33
  175. package/src/tui/status-activity.ts +0 -63
  176. package/src/tui/tui-cli-adapter-context.tsx +0 -13
  177. package/src/tui/tui-cli-adapter.ts +0 -25
  178. package/src/tui/tui-state-manager.ts +0 -226
  179. package/src/tui/tui-transport.ts +0 -35
  180. package/src/tui/types.ts +0 -15
  181. package/src/tui/utils/__tests__/edit-diff.test.ts +0 -426
  182. package/src/tui/utils/__tests__/paste-detection.test.ts +0 -116
  183. package/src/tui/utils/__tests__/paste-labels.test.ts +0 -46
  184. package/src/tui/utils/__tests__/tool-call-extractor.test.ts +0 -227
  185. package/src/tui/utils/__tests__/tool-diff-summary.test.ts +0 -104
  186. package/src/tui/utils/edit-diff.ts +0 -153
  187. package/src/tui/utils/paste-labels.ts +0 -9
  188. package/src/tui/utils/tool-call-extractor.ts +0 -92
  189. package/src/tui/utils/tool-diff-summary.ts +0 -75
  190. package/src/ws/__tests__/ws-handler.test.ts +0 -409
  191. package/src/ws/__tests__/ws-transport.test.ts +0 -53
  192. package/src/ws/index.ts +0 -13
  193. package/src/ws/ws-background-messages.ts +0 -170
  194. package/src/ws/ws-handler.ts +0 -280
  195. package/src/ws/ws-protocol.ts +0 -78
  196. package/src/ws/ws-transport-configurable.ts +0 -128
  197. package/src/ws/ws-transport.ts +0 -42
@@ -1,124 +0,0 @@
1
- import React from 'react';
2
- import { render } from 'ink-testing-library';
3
- import { describe, it, expect } from 'vitest';
4
-
5
- import CommandConfirm from '../CommandConfirm.js';
6
-
7
- import type { ITuiConfirmInteraction } from '../../command-interaction.js';
8
-
9
- const delay = (ms: number): Promise<void> => new Promise((r) => setTimeout(r, ms));
10
-
11
- function makeInteraction(message: string): ITuiConfirmInteraction {
12
- return { onMissingArgs: 'confirm', message };
13
- }
14
-
15
- describe('CommandConfirm', () => {
16
- it('renders the message text', () => {
17
- const { lastFrame } = render(
18
- <CommandConfirm
19
- commandName="exit"
20
- interaction={makeInteraction('Exit the session?')}
21
- onConfirm={() => {}}
22
- onCancel={() => {}}
23
- />,
24
- );
25
- expect(lastFrame()).toContain('Exit the session?');
26
- });
27
-
28
- it('calls onConfirm when y is pressed', () => {
29
- let confirmed = false;
30
- const { stdin } = render(
31
- <CommandConfirm
32
- commandName="exit"
33
- interaction={makeInteraction('Exit?')}
34
- onConfirm={() => {
35
- confirmed = true;
36
- }}
37
- onCancel={() => {}}
38
- />,
39
- );
40
- stdin.write('y');
41
- expect(confirmed).toBe(true);
42
- });
43
-
44
- it('calls onConfirm when Y is pressed', () => {
45
- let confirmed = false;
46
- const { stdin } = render(
47
- <CommandConfirm
48
- commandName="exit"
49
- interaction={makeInteraction('Exit?')}
50
- onConfirm={() => {
51
- confirmed = true;
52
- }}
53
- onCancel={() => {}}
54
- />,
55
- );
56
- stdin.write('Y');
57
- expect(confirmed).toBe(true);
58
- });
59
-
60
- it('calls onConfirm on Enter', () => {
61
- let confirmed = false;
62
- const { stdin } = render(
63
- <CommandConfirm
64
- commandName="exit"
65
- interaction={makeInteraction('Exit?')}
66
- onConfirm={() => {
67
- confirmed = true;
68
- }}
69
- onCancel={() => {}}
70
- />,
71
- );
72
- stdin.write('\r');
73
- expect(confirmed).toBe(true);
74
- });
75
-
76
- it('calls onCancel when n is pressed', () => {
77
- let cancelled = false;
78
- const { stdin } = render(
79
- <CommandConfirm
80
- commandName="exit"
81
- interaction={makeInteraction('Exit?')}
82
- onConfirm={() => {}}
83
- onCancel={() => {
84
- cancelled = true;
85
- }}
86
- />,
87
- );
88
- stdin.write('n');
89
- expect(cancelled).toBe(true);
90
- });
91
-
92
- it('calls onCancel when N is pressed', () => {
93
- let cancelled = false;
94
- const { stdin } = render(
95
- <CommandConfirm
96
- commandName="exit"
97
- interaction={makeInteraction('Exit?')}
98
- onConfirm={() => {}}
99
- onCancel={() => {
100
- cancelled = true;
101
- }}
102
- />,
103
- );
104
- stdin.write('N');
105
- expect(cancelled).toBe(true);
106
- });
107
-
108
- it('calls onCancel on Escape', async () => {
109
- let cancelled = false;
110
- const { stdin } = render(
111
- <CommandConfirm
112
- commandName="exit"
113
- interaction={makeInteraction('Exit?')}
114
- onConfirm={() => {}}
115
- onCancel={() => {
116
- cancelled = true;
117
- }}
118
- />,
119
- );
120
- stdin.write('\x1b');
121
- await delay(50);
122
- expect(cancelled).toBe(true);
123
- });
124
- });
@@ -1,138 +0,0 @@
1
- import React from 'react';
2
- import { render } from 'ink-testing-library';
3
- import { describe, it, expect, vi } from 'vitest';
4
-
5
- import CommandPicker from '../CommandPicker.js';
6
-
7
- import type { ITuiPickerInteraction, ITuiPickerItem } from '../../command-interaction.js';
8
-
9
- const delay = (ms: number): Promise<void> => new Promise((r) => setTimeout(r, ms));
10
-
11
- function makeInteraction(items: ITuiPickerItem[]): ITuiPickerInteraction {
12
- return {
13
- onMissingArgs: 'picker',
14
- getItems: () => items,
15
- };
16
- }
17
-
18
- const ITEMS: ITuiPickerItem[] = [
19
- { label: 'plan', value: 'plan', description: 'Plan mode' },
20
- { label: 'default', value: 'default', description: 'Default mode' },
21
- { label: 'auto', value: 'auto' },
22
- ];
23
-
24
- describe('CommandPicker', () => {
25
- it('renders all item labels', () => {
26
- const { lastFrame } = render(
27
- <CommandPicker
28
- commandName="mode"
29
- interaction={makeInteraction(ITEMS)}
30
- onSelect={() => {}}
31
- onCancel={() => {}}
32
- />,
33
- );
34
- const frame = lastFrame()!;
35
- expect(frame).toContain('plan');
36
- expect(frame).toContain('default');
37
- expect(frame).toContain('auto');
38
- });
39
-
40
- it('highlights first item by default', () => {
41
- const { lastFrame } = render(
42
- <CommandPicker
43
- commandName="mode"
44
- interaction={makeInteraction(ITEMS)}
45
- onSelect={() => {}}
46
- onCancel={() => {}}
47
- />,
48
- );
49
- const frame = lastFrame()!;
50
- expect(frame).toContain('▸ plan');
51
- });
52
-
53
- it('calls onSelect with first item on Enter', () => {
54
- const onSelect = vi.fn();
55
- const { stdin } = render(
56
- <CommandPicker
57
- commandName="mode"
58
- interaction={makeInteraction(ITEMS)}
59
- onSelect={onSelect}
60
- onCancel={() => {}}
61
- />,
62
- );
63
- stdin.write('\r');
64
- expect(onSelect).toHaveBeenCalledWith(ITEMS[0]);
65
- });
66
-
67
- it('moves highlight down on arrow-down then selects on Enter', async () => {
68
- let selected: ITuiPickerItem | undefined;
69
- const { stdin } = render(
70
- <CommandPicker
71
- commandName="mode"
72
- interaction={makeInteraction(ITEMS)}
73
- onSelect={(item) => {
74
- selected = item;
75
- }}
76
- onCancel={() => {}}
77
- />,
78
- );
79
- stdin.write('\x1B[B'); // ↓
80
- await delay(50);
81
- stdin.write('\r');
82
- expect(selected).toEqual(ITEMS[1]);
83
- });
84
-
85
- it('calls onCancel on Escape', async () => {
86
- let cancelled = false;
87
- const { stdin } = render(
88
- <CommandPicker
89
- commandName="mode"
90
- interaction={makeInteraction(ITEMS)}
91
- onSelect={() => {}}
92
- onCancel={() => {
93
- cancelled = true;
94
- }}
95
- />,
96
- );
97
- stdin.write('\x1b');
98
- await delay(50);
99
- expect(cancelled).toBe(true);
100
- });
101
-
102
- it('calls onCancel on q', () => {
103
- const onCancel = vi.fn();
104
- const { stdin } = render(
105
- <CommandPicker
106
- commandName="mode"
107
- interaction={makeInteraction(ITEMS)}
108
- onSelect={() => {}}
109
- onCancel={onCancel}
110
- />,
111
- );
112
- stdin.write('q');
113
- expect(onCancel).toHaveBeenCalled();
114
- });
115
-
116
- it('wraps highlight from last to first on arrow-down at bottom', async () => {
117
- let selected: ITuiPickerItem | undefined;
118
- const { stdin } = render(
119
- <CommandPicker
120
- commandName="mode"
121
- interaction={makeInteraction(ITEMS)}
122
- onSelect={(item) => {
123
- selected = item;
124
- }}
125
- onCancel={() => {}}
126
- />,
127
- );
128
- // Navigate to last item (index 2)
129
- stdin.write('\x1B[B'); // ↓ to index 1
130
- await delay(50);
131
- stdin.write('\x1B[B'); // ↓ to index 2
132
- await delay(50);
133
- stdin.write('\x1B[B'); // ↓ wraps to index 0
134
- await delay(50);
135
- stdin.write('\r');
136
- expect(selected).toEqual(ITEMS[0]);
137
- });
138
- });
@@ -1,163 +0,0 @@
1
- /**
2
- * Screen-specific selection handlers for PluginTUI.
3
- * Extracted to keep PluginTUI.tsx under 300 lines.
4
- */
5
-
6
- import type { IMenuSelectItem } from './MenuSelect.js';
7
- import type { ICommandPluginAdapter } from '@robota-sdk/agent-interface-transport';
8
-
9
- interface IConfirmState {
10
- message: string;
11
- onConfirm: () => void;
12
- onCancel: () => void;
13
- }
14
-
15
- interface IMenuContext {
16
- marketplace?: string;
17
- pluginId?: string;
18
- }
19
-
20
- interface INavActions {
21
- push: (state: { screen: string; context?: IMenuContext }) => void;
22
- pop: () => void;
23
- popN: (n: number) => void;
24
- notify: (content: string) => void;
25
- setConfirm: (state: IConfirmState | undefined) => void;
26
- refresh: () => void;
27
- }
28
-
29
- export function handleMainSelect(value: string, nav: Pick<INavActions, 'push'>): void {
30
- if (value === 'marketplace') {
31
- nav.push({ screen: 'marketplace-list' });
32
- } else if (value === 'installed') {
33
- nav.push({ screen: 'installed-list' });
34
- }
35
- }
36
-
37
- export function handleMarketplaceListSelect(value: string, nav: Pick<INavActions, 'push'>): void {
38
- if (value === '__add__') {
39
- nav.push({ screen: 'marketplace-add' });
40
- } else {
41
- nav.push({ screen: 'marketplace-action', context: { marketplace: value } });
42
- }
43
- }
44
-
45
- export function handleMarketplaceActionSelect(
46
- value: string,
47
- marketplace: string,
48
- callbacks: ICommandPluginAdapter,
49
- nav: Pick<INavActions, 'push' | 'pop' | 'popN' | 'notify' | 'setConfirm'>,
50
- ): void {
51
- if (value === 'browse') {
52
- nav.push({ screen: 'marketplace-browse', context: { marketplace } });
53
- } else if (value === 'update') {
54
- callbacks
55
- .marketplaceUpdate(marketplace)
56
- .then(() => {
57
- nav.notify(`Updated marketplace "${marketplace}".`);
58
- nav.pop();
59
- })
60
- .catch((err) => {
61
- nav.notify(`Error: ${err instanceof Error ? err.message : String(err)}`);
62
- });
63
- } else if (value === 'remove') {
64
- nav.setConfirm({
65
- message: `Remove marketplace "${marketplace}" and all its plugins?`,
66
- onConfirm: () => {
67
- nav.setConfirm(undefined);
68
- callbacks
69
- .marketplaceRemove(marketplace)
70
- .then(() => {
71
- nav.notify(`Removed marketplace "${marketplace}".`);
72
- nav.popN(2);
73
- })
74
- .catch((err) => {
75
- nav.notify(`Error: ${err instanceof Error ? err.message : String(err)}`);
76
- });
77
- },
78
- onCancel: () => nav.setConfirm(undefined),
79
- });
80
- }
81
- }
82
-
83
- export function handleMarketplaceBrowseSelect(
84
- value: string,
85
- marketplace: string,
86
- items: IMenuSelectItem[],
87
- nav: Pick<INavActions, 'push'>,
88
- ): void {
89
- const fullId = `${value}@${marketplace}`;
90
- const item = items.find((i) => i.value === value);
91
- if (item?.hint === 'installed') {
92
- nav.push({ screen: 'installed-action', context: { pluginId: fullId } });
93
- } else {
94
- nav.push({ screen: 'marketplace-install-scope', context: { marketplace, pluginId: fullId } });
95
- }
96
- }
97
-
98
- export function handleInstallScopeSelect(
99
- value: string,
100
- pluginId: string,
101
- callbacks: ICommandPluginAdapter,
102
- nav: Pick<INavActions, 'popN' | 'notify'>,
103
- ): void {
104
- const scope = value as 'user' | 'project';
105
- callbacks
106
- .install(pluginId, scope)
107
- .then(() => {
108
- nav.notify(`Installed plugin "${pluginId}" (${scope} scope).`);
109
- nav.popN(2);
110
- })
111
- .catch((err) => {
112
- nav.notify(`Error: ${err instanceof Error ? err.message : String(err)}`);
113
- });
114
- }
115
-
116
- export function handleInstalledListSelect(
117
- value: string,
118
- callbacks: ICommandPluginAdapter,
119
- nav: Pick<INavActions, 'notify' | 'setConfirm' | 'refresh'>,
120
- ): void {
121
- nav.setConfirm({
122
- message: `Uninstall plugin "${value}"?`,
123
- onConfirm: () => {
124
- nav.setConfirm(undefined);
125
- callbacks
126
- .uninstall(value)
127
- .then(() => {
128
- nav.notify(`Uninstalled plugin "${value}".`);
129
- nav.refresh();
130
- })
131
- .catch((err) => {
132
- nav.notify(`Error: ${err instanceof Error ? err.message : String(err)}`);
133
- });
134
- },
135
- onCancel: () => nav.setConfirm(undefined),
136
- });
137
- }
138
-
139
- export function handleInstalledActionSelect(
140
- value: string,
141
- pluginId: string,
142
- callbacks: ICommandPluginAdapter,
143
- nav: Pick<INavActions, 'popN' | 'notify' | 'setConfirm'>,
144
- ): void {
145
- if (value === 'uninstall') {
146
- nav.setConfirm({
147
- message: `Uninstall plugin "${pluginId}"?`,
148
- onConfirm: () => {
149
- nav.setConfirm(undefined);
150
- callbacks
151
- .uninstall(pluginId)
152
- .then(() => {
153
- nav.notify(`Uninstalled plugin "${pluginId}".`);
154
- nav.popN(2);
155
- })
156
- .catch((err) => {
157
- nav.notify(`Error: ${err instanceof Error ? err.message : String(err)}`);
158
- });
159
- },
160
- onCancel: () => nav.setConfirm(undefined),
161
- });
162
- }
163
- }
@@ -1,130 +0,0 @@
1
- import { marked } from 'marked';
2
- // @ts-expect-error — marked-terminal has no type declarations
3
- import TerminalRenderer from 'marked-terminal';
4
-
5
- import type { Renderer } from 'marked';
6
-
7
- const ANSI_LIGHT_RED = '\u001b[38;5;210m';
8
- const ANSI_LIGHT_GREEN = '\u001b[38;5;120m';
9
- const ANSI_CYAN = '\u001b[36m';
10
- const ANSI_DIM = '\u001b[2m';
11
- const ANSI_DARK_RED_BACKGROUND = '\u001b[48;5;52m';
12
- const ANSI_DARK_GREEN_BACKGROUND = '\u001b[48;5;22m';
13
- const ANSI_RESET = '\u001b[0m';
14
- const CODE_BLOCK_INDENT = ' ';
15
- const ZERO_COLOR = '0';
16
-
17
- interface IRenderMarkdownOptions {
18
- color?: boolean;
19
- codeBlockWidth?: number;
20
- }
21
-
22
- interface ITerminalRendererOptions {
23
- code?: (text: string) => string;
24
- }
25
-
26
- interface IHighlightOptions {
27
- ignoreIllegals?: boolean;
28
- }
29
-
30
- type TTerminalRendererConstructor = new (
31
- options?: ITerminalRendererOptions,
32
- highlightOptions?: IHighlightOptions,
33
- ) => Renderer;
34
-
35
- const TerminalRendererConstructor = TerminalRenderer as TTerminalRendererConstructor;
36
-
37
- function shouldUseColor(option: boolean | undefined): boolean {
38
- if (option !== undefined) {
39
- return option;
40
- }
41
- if (process.env.NO_COLOR || process.env.FORCE_COLOR === ZERO_COLOR) {
42
- return false;
43
- }
44
- if (process.env.FORCE_COLOR) {
45
- return true;
46
- }
47
- return Boolean(process.stdout.isTTY);
48
- }
49
-
50
- function isDiffLanguage(language: string | undefined): boolean {
51
- return language?.trim().toLowerCase() === 'diff';
52
- }
53
-
54
- function styleAddedOrRemovedDiffRow(line: string, rowWidth: number, color: boolean): string {
55
- const row = `${CODE_BLOCK_INDENT}${line}`.padEnd(rowWidth);
56
- if (!color) {
57
- return row.trimEnd();
58
- }
59
- if (line.startsWith('+')) {
60
- return `${ANSI_DARK_GREEN_BACKGROUND}${ANSI_LIGHT_GREEN}${row}${ANSI_RESET}`;
61
- }
62
- if (line.startsWith('-')) {
63
- return `${ANSI_DARK_RED_BACKGROUND}${ANSI_LIGHT_RED}${row}${ANSI_RESET}`;
64
- }
65
- return row.trimEnd();
66
- }
67
-
68
- function colorizeDiffLine(line: string, color: boolean, rowWidth: number): string {
69
- if (line.startsWith('+') || line.startsWith('-')) {
70
- return styleAddedOrRemovedDiffRow(line, rowWidth, color);
71
- }
72
- const row = `${CODE_BLOCK_INDENT}${line}`;
73
- if (!color) {
74
- return row;
75
- }
76
- if (line.startsWith('@@')) {
77
- return `${ANSI_CYAN}${row}${ANSI_RESET}`;
78
- }
79
- if (line.startsWith('diff ') || line.startsWith('index ')) {
80
- return `${ANSI_DIM}${row}${ANSI_RESET}`;
81
- }
82
- return row;
83
- }
84
-
85
- function resolveDiffRowWidth(lines: readonly string[], requestedWidth: number | undefined): number {
86
- const minimumWidth = lines.reduce(
87
- (maxWidth, line) => Math.max(maxWidth, CODE_BLOCK_INDENT.length + line.length),
88
- 0,
89
- );
90
- if (requestedWidth === undefined) {
91
- return minimumWidth;
92
- }
93
- return Math.max(minimumWidth, requestedWidth);
94
- }
95
-
96
- function renderDiffCodeBlock(
97
- code: string,
98
- color: boolean,
99
- codeBlockWidth: number | undefined,
100
- ): string {
101
- const lines = code.split('\n');
102
- const rowWidth = resolveDiffRowWidth(lines, codeBlockWidth);
103
- const body = lines.map((line) => colorizeDiffLine(line, color, rowWidth)).join('\n');
104
- return `${body}\n\n`;
105
- }
106
-
107
- function createTerminalRenderer(color: boolean, codeBlockWidth: number | undefined): Renderer {
108
- const renderer = new TerminalRendererConstructor(undefined, { ignoreIllegals: true });
109
- const renderCode = renderer.code.bind(renderer);
110
-
111
- renderer.code = (code: string, language: string | undefined, escaped: boolean): string => {
112
- if (isDiffLanguage(language)) {
113
- return renderDiffCodeBlock(code, color, codeBlockWidth);
114
- }
115
- return renderCode(code, language, escaped);
116
- };
117
-
118
- return renderer;
119
- }
120
-
121
- /**
122
- * Render markdown to a terminal-formatted string with colors, bold, etc.
123
- * Returns the rendered string (may include ANSI escape codes).
124
- */
125
- export function renderMarkdown(md: string, options: IRenderMarkdownOptions = {}): string {
126
- const result = marked.parse(md, {
127
- renderer: createTerminalRenderer(shouldUseColor(options.color), options.codeBlockWidth),
128
- });
129
- return typeof result === 'string' ? result.trimEnd() : md;
130
- }
@@ -1,117 +0,0 @@
1
- /**
2
- * Ink render entry point.
3
- */
4
-
5
- import { render } from 'ink';
6
- import React from 'react';
7
-
8
- import App from './App.js';
9
- import { TuiInteractionChannel } from './TuiInteractionChannel.js';
10
-
11
- import type { ITuiCliAdapter } from './tui-cli-adapter.js';
12
- import type { IAIProvider } from '@robota-sdk/agent-core';
13
- import type { TPermissionMode } from '@robota-sdk/agent-core';
14
- import type {
15
- IBackgroundTaskRunner,
16
- ICommandHostAdapters,
17
- ICommandModule,
18
- TSubagentRunnerFactory,
19
- TShellExecFn,
20
- CommandRegistry,
21
- } from '@robota-sdk/agent-framework';
22
- import type {
23
- IInteractiveSession,
24
- IInteractiveSessionStore,
25
- ITransportRegistryView,
26
- } from '@robota-sdk/agent-interface-transport';
27
-
28
- export interface IRenderOptions {
29
- cwd: string;
30
- provider: IAIProvider;
31
- providerOverride?: string | undefined;
32
- providerType?: string | undefined;
33
- modelId?: string;
34
- language?: string;
35
- permissionMode?: TPermissionMode;
36
- maxTurns?: number;
37
- allowedTools?: string[];
38
- deniedTools?: string[];
39
- version?: string;
40
- sessionStore?: IInteractiveSessionStore;
41
- resumeSessionId?: string;
42
- showSessionPickerOnStart?: boolean;
43
- forkSession?: boolean;
44
- sessionName?: string;
45
- backgroundTaskRunners?: IBackgroundTaskRunner[];
46
- subagentRunnerFactory?: TSubagentRunnerFactory;
47
- commandModules?: readonly ICommandModule[];
48
- commandHostAdapters?: ICommandHostAdapters;
49
- shellExec?: TShellExecFn;
50
- startupUpdateNotice?: Promise<string | undefined>;
51
- transportRegistry?: ITransportRegistryView<IInteractiveSession>;
52
- cliAdapter: ITuiCliAdapter;
53
- reloadPluginCommandSource?: (registry: CommandRegistry) => void;
54
- agentName?: string;
55
- }
56
-
57
- /** Map render options to TuiInteractionChannel constructor options. */
58
- export function toChannelOptions(
59
- options: IRenderOptions,
60
- resumeSessionId?: string,
61
- ): ConstructorParameters<typeof TuiInteractionChannel>[0] {
62
- return {
63
- cwd: options.cwd,
64
- provider: options.provider,
65
- permissionMode: options.permissionMode,
66
- maxTurns: options.maxTurns,
67
- allowedTools: options.allowedTools,
68
- deniedTools: options.deniedTools,
69
- sessionStore: options.sessionStore,
70
- resumeSessionId,
71
- forkSession: options.forkSession,
72
- sessionName: options.sessionName,
73
- backgroundTaskRunners: options.backgroundTaskRunners,
74
- subagentRunnerFactory: options.subagentRunnerFactory,
75
- commandModules: options.commandModules,
76
- commandHostAdapters: options.commandHostAdapters,
77
- shellExec: options.shellExec,
78
- transportRegistry: options.transportRegistry,
79
- language: options.language,
80
- reloadPluginCommandSource: options.reloadPluginCommandSource,
81
- agentName: options.agentName,
82
- };
83
- }
84
-
85
- export async function renderApp(options: IRenderOptions): Promise<void> {
86
- process.on('unhandledRejection', (reason) => {
87
- process.stderr.write(`\n[UNHANDLED REJECTION] ${reason}\n`);
88
- if (reason instanceof Error) {
89
- process.stderr.write(`${reason.stack}\n`);
90
- }
91
- });
92
-
93
- // Single-owner lifecycle (CLI-B12): render.tsx supplies only the factory;
94
- // App creates, replaces, and stops channels exclusively through React state.
95
- const createChannel = (resumeSessionId?: string): TuiInteractionChannel =>
96
- new TuiInteractionChannel(toChannelOptions(options, resumeSessionId));
97
-
98
- const instance = render(
99
- <App
100
- cwd={options.cwd}
101
- createChannel={createChannel}
102
- providerOverride={options.providerOverride}
103
- providerType={options.providerType}
104
- modelId={options.modelId}
105
- permissionMode={options.permissionMode}
106
- version={options.version}
107
- sessionStore={options.sessionStore}
108
- resumeSessionId={options.resumeSessionId}
109
- showSessionPickerOnStart={options.showSessionPickerOnStart}
110
- startupUpdateNotice={options.startupUpdateNotice}
111
- transportRegistry={options.transportRegistry}
112
- cliAdapter={options.cliAdapter}
113
- />,
114
- { exitOnCtrlC: false },
115
- );
116
- await instance.waitUntilExit();
117
- }
@@ -1,33 +0,0 @@
1
- import { createSystemMessage, createUserMessage } from '@robota-sdk/agent-core';
2
-
3
- import type { IAIProvider } from '@robota-sdk/agent-core';
4
-
5
- const SYSTEM_PROMPT =
6
- 'You generate short session titles. Respond with ONLY a 3-5 word lowercase-hyphenated title (e.g. refactor-auth-middleware). No explanation, no punctuation, no quotes.';
7
-
8
- const MAX_FIRST_MESSAGE_CHARS = 200;
9
-
10
- function sanitizeName(raw: string): string {
11
- return raw
12
- .toLowerCase()
13
- .replace(/[^a-z0-9\s-]/g, '')
14
- .trim()
15
- .replace(/\s+/g, '-')
16
- .replace(/-+/g, '-')
17
- .slice(0, 60);
18
- }
19
-
20
- export async function generateSessionName(
21
- provider: IAIProvider,
22
- firstMessage: string,
23
- ): Promise<string> {
24
- const truncated = firstMessage.slice(0, MAX_FIRST_MESSAGE_CHARS);
25
- const response = await provider.chat(
26
- [createSystemMessage(SYSTEM_PROMPT), createUserMessage(truncated)],
27
- { maxTokens: 20 },
28
- );
29
- const raw = typeof response.content === 'string' ? response.content : '';
30
- const name = sanitizeName(raw);
31
- if (!name || name.length < 3) return sanitizeName(firstMessage);
32
- return name;
33
- }