@aria-cli/cli 1.0.57 → 1.0.58

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 (319) hide show
  1. package/bin/aria.mjs +2 -2
  2. package/package.json +17 -76
  3. package/dist/.tsbuildinfo +0 -1
  4. package/dist/attached-local-control-client.js +0 -826
  5. package/dist/bootstrap-local-control-client.js +0 -2
  6. package/dist/capability-aware-method-proxy.js +0 -42
  7. package/dist/cli-context.js +0 -160
  8. package/dist/commands/arions.js +0 -174
  9. package/dist/commands/auth.js +0 -123
  10. package/dist/commands/daemon.js +0 -367
  11. package/dist/commands/definitions.js +0 -176
  12. package/dist/commands/index.js +0 -80
  13. package/dist/commands/login-handler.js +0 -1108
  14. package/dist/commands/logout-handler.js +0 -92
  15. package/dist/commands/memory-handlers.js +0 -89
  16. package/dist/commands/pairing.js +0 -60
  17. package/dist/commands/runtime-cutover-reset-command.js +0 -12
  18. package/dist/commands/runtime-cutover-reset.js +0 -265
  19. package/dist/commands/terminal-setup.js +0 -84
  20. package/dist/config/aria-config.js +0 -238
  21. package/dist/config/index.js +0 -3
  22. package/dist/config/loader.js +0 -97
  23. package/dist/config.js +0 -142
  24. package/dist/daemon-info.js +0 -10
  25. package/dist/ensure-daemon.js +0 -128
  26. package/dist/entrypoints/command-mode.js +0 -5
  27. package/dist/entrypoints/daemon.js +0 -50
  28. package/dist/entrypoints/headless-stdio.js +0 -25
  29. package/dist/entrypoints/interactive.js +0 -80
  30. package/dist/event-loop-watchdog.js +0 -73
  31. package/dist/headless/auth-orchestrator.js +0 -508
  32. package/dist/headless/auth-service.js +0 -43
  33. package/dist/headless/bootstrap-fast-path.js +0 -112
  34. package/dist/headless/call-command.js +0 -143
  35. package/dist/headless/daemon-service.js +0 -318
  36. package/dist/headless/hook-actions.js +0 -235
  37. package/dist/headless/hook-service.js +0 -42
  38. package/dist/headless/kernel-services.js +0 -216
  39. package/dist/headless/kernel.js +0 -785
  40. package/dist/headless/operations/arion.js +0 -119
  41. package/dist/headless/operations/auth.js +0 -45
  42. package/dist/headless/operations/client.js +0 -31
  43. package/dist/headless/operations/config.js +0 -69
  44. package/dist/headless/operations/daemon.js +0 -47
  45. package/dist/headless/operations/hook.js +0 -56
  46. package/dist/headless/operations/index.js +0 -11
  47. package/dist/headless/operations/memory.js +0 -102
  48. package/dist/headless/operations/message.js +0 -279
  49. package/dist/headless/operations/model.js +0 -100
  50. package/dist/headless/operations/peer.js +0 -56
  51. package/dist/headless/operations/run.js +0 -24
  52. package/dist/headless/operations/session.js +0 -90
  53. package/dist/headless/operations/system.js +0 -19
  54. package/dist/headless/operations/utils.js +0 -35
  55. package/dist/headless/run-orchestrator.js +0 -703
  56. package/dist/headless/stdio-server.js +0 -439
  57. package/dist/history/SessionHistory.js +0 -8
  58. package/dist/history/SessionHistoryClient.js +0 -186
  59. package/dist/history/conversation-message.js +0 -112
  60. package/dist/history/index.js +0 -8
  61. package/dist/history/jsonl-replay.js +0 -154
  62. package/dist/history/repair-tool-pairing.js +0 -84
  63. package/dist/history/stall-phase-bridge.js +0 -11
  64. package/dist/history/turn-accumulator.js +0 -427
  65. package/dist/index.js +0 -7
  66. package/dist/ink-repl.js +0 -4183
  67. package/dist/local-control-bootstrap.js +0 -26
  68. package/dist/local-control-client.js +0 -2
  69. package/dist/local-control-error-reporting.js +0 -34
  70. package/dist/local-control-http-client.js +0 -362
  71. package/dist/local-control-lazy-wrapper.js +0 -363
  72. package/dist/local-control-manager.js +0 -146
  73. package/dist/main.js +0 -62
  74. package/dist/network-security.js +0 -62
  75. package/dist/networking-server.js +0 -38
  76. package/dist/peer-identity.js +0 -23
  77. package/dist/polling-subscription.js +0 -34
  78. package/dist/relaunch.js +0 -617
  79. package/dist/release-notes.js +0 -35
  80. package/dist/repl-cleanup.js +0 -47
  81. package/dist/runtime/configure-bun-sqlite.js +0 -3
  82. package/dist/runtime/crash-handlers.js +0 -111
  83. package/dist/runtime/interactive-invocation.js +0 -39
  84. package/dist/runtime/internal-mode.js +0 -14
  85. package/dist/runtime/launch-spec.js +0 -64
  86. package/dist/runtime/owner-lease.js +0 -44
  87. package/dist/runtime/public-mode.js +0 -20
  88. package/dist/runtime/run-internal-mode.js +0 -18
  89. package/dist/runtime/runtime-kind.js +0 -32
  90. package/dist/runtime/spawn-aria.js +0 -38
  91. package/dist/selectable-client.js +0 -2
  92. package/dist/selectable-peer.js +0 -2
  93. package/dist/session.js +0 -203
  94. package/dist/slash-commands.js +0 -80
  95. package/dist/sounds.js +0 -210
  96. package/dist/ui/App.js +0 -526
  97. package/dist/ui/components/AnthropicMethodPicker.js +0 -6
  98. package/dist/ui/components/ArionPrompt.js +0 -15
  99. package/dist/ui/components/AutocompleteDropdown.js +0 -23
  100. package/dist/ui/components/AutonomySelector.js +0 -55
  101. package/dist/ui/components/Banner.js +0 -98
  102. package/dist/ui/components/ConversationHistory.js +0 -175
  103. package/dist/ui/components/CopilotDeviceLoginFlow.js +0 -88
  104. package/dist/ui/components/CopilotSourcePicker.js +0 -50
  105. package/dist/ui/components/Cost.js +0 -10
  106. package/dist/ui/components/CustomSelect/option-map.js +0 -30
  107. package/dist/ui/components/CustomSelect/select-option.js +0 -13
  108. package/dist/ui/components/CustomSelect/select.js +0 -42
  109. package/dist/ui/components/CustomSelect/use-select-state.js +0 -179
  110. package/dist/ui/components/CustomSelect/use-select.js +0 -15
  111. package/dist/ui/components/ErrorDisplay.js +0 -35
  112. package/dist/ui/components/FallbackToolUseRejectedMessage.js +0 -7
  113. package/dist/ui/components/FileEditToolUpdatedMessage.js +0 -57
  114. package/dist/ui/components/HandoffMarker.js +0 -18
  115. package/dist/ui/components/HighlightedCode.js +0 -21
  116. package/dist/ui/components/InputArea.js +0 -187
  117. package/dist/ui/components/Message.js +0 -25
  118. package/dist/ui/components/OAuthLoginFlow.js +0 -113
  119. package/dist/ui/components/OutputTruncation.js +0 -35
  120. package/dist/ui/components/PermissionPrompt.js +0 -79
  121. package/dist/ui/components/PipelineTimingPanel.js +0 -15
  122. package/dist/ui/components/ProviderMethodPicker.js +0 -61
  123. package/dist/ui/components/ProviderPicker.js +0 -63
  124. package/dist/ui/components/RenderItemView.js +0 -71
  125. package/dist/ui/components/Spinner.js +0 -46
  126. package/dist/ui/components/StatusBar.js +0 -95
  127. package/dist/ui/components/StreamingIndicator.js +0 -55
  128. package/dist/ui/components/StructuredDiff.js +0 -168
  129. package/dist/ui/components/TextInputOverlay.js +0 -43
  130. package/dist/ui/components/ThinkingBlock.js +0 -82
  131. package/dist/ui/components/ToolCost.js +0 -17
  132. package/dist/ui/components/ToolExecution.js +0 -61
  133. package/dist/ui/components/ToolHeader.js +0 -51
  134. package/dist/ui/components/ToolRenderLayoutContext.js +0 -14
  135. package/dist/ui/components/ToolResultWrapper.js +0 -6
  136. package/dist/ui/components/ToolUseLoader.js +0 -35
  137. package/dist/ui/components/TraceWaterfall.js +0 -91
  138. package/dist/ui/components/index.js +0 -33
  139. package/dist/ui/components/messages/AssistantTextMessage.js +0 -25
  140. package/dist/ui/components/messages/UserImageMessage.js +0 -12
  141. package/dist/ui/components/messages/UserTextMessage.js +0 -12
  142. package/dist/ui/components/overlays/ArionSelector.js +0 -68
  143. package/dist/ui/components/overlays/ClientSelector.js +0 -62
  144. package/dist/ui/components/overlays/CommandPalette.js +0 -67
  145. package/dist/ui/components/overlays/DaemonControl.js +0 -87
  146. package/dist/ui/components/overlays/InviteShareOverlay.js +0 -15
  147. package/dist/ui/components/overlays/JoinInviteOverlay.js +0 -32
  148. package/dist/ui/components/overlays/MemoryBrowser.js +0 -100
  149. package/dist/ui/components/overlays/MessageSelector.js +0 -123
  150. package/dist/ui/components/overlays/ModelSelector.js +0 -211
  151. package/dist/ui/components/overlays/PairRequestOverlay.js +0 -42
  152. package/dist/ui/components/overlays/PeerSelector.js +0 -84
  153. package/dist/ui/components/overlays/SessionSelector.js +0 -102
  154. package/dist/ui/components/overlays/SoundSelector.js +0 -86
  155. package/dist/ui/components/overlays/ThemeSelector.js +0 -139
  156. package/dist/ui/components/overlays/index.js +0 -15
  157. package/dist/ui/components/permissions/BashPermissionRequest/BashPermissionRequest.js +0 -53
  158. package/dist/ui/components/permissions/FallbackPermissionRequest.js +0 -56
  159. package/dist/ui/components/permissions/FileEditPermissionRequest/FileEditPermissionRequest.js +0 -76
  160. package/dist/ui/components/permissions/FileEditPermissionRequest/FileEditToolDiff.js +0 -18
  161. package/dist/ui/components/permissions/FileWritePermissionRequest/FileWritePermissionRequest.js +0 -64
  162. package/dist/ui/components/permissions/FileWritePermissionRequest/FileWriteToolDiff.js +0 -26
  163. package/dist/ui/components/permissions/FilesystemPermissionRequest/FilesystemPermissionRequest.js +0 -141
  164. package/dist/ui/components/permissions/PermissionRequest.js +0 -70
  165. package/dist/ui/components/permissions/PermissionRequestTitle.js +0 -41
  166. package/dist/ui/components/permissions/hooks.js +0 -10
  167. package/dist/ui/components/permissions/toolUseOptions.js +0 -68
  168. package/dist/ui/components/permissions/utils.js +0 -10
  169. package/dist/ui/components/text-input/Cursor.js +0 -326
  170. package/dist/ui/components/text-input/TextInput.js +0 -231
  171. package/dist/ui/components/text-input/imagePaste.js +0 -28
  172. package/dist/ui/components/text-input/index.js +0 -6
  173. package/dist/ui/components/text-input/useDoublePress.js +0 -30
  174. package/dist/ui/components/text-input/useTextInput.js +0 -245
  175. package/dist/ui/components/tool-types.js +0 -9
  176. package/dist/ui/constants/figures.js +0 -4
  177. package/dist/ui/constants/index.js +0 -3
  178. package/dist/ui/display-mode.js +0 -93
  179. package/dist/ui/display-policy.js +0 -19
  180. package/dist/ui/hooks/index.js +0 -6
  181. package/dist/ui/hooks/useCommandAutocomplete.js +0 -93
  182. package/dist/ui/hooks/useDoublePress.js +0 -37
  183. package/dist/ui/hooks/useIndicatorState.js +0 -55
  184. package/dist/ui/hooks/useInterval.js +0 -23
  185. package/dist/ui/hooks/useKeyboardShortcuts.js +0 -127
  186. package/dist/ui/hooks/useTerminalSize.js +0 -55
  187. package/dist/ui/hooks/useUnifiedMessages.js +0 -117
  188. package/dist/ui/indicator-state.js +0 -44
  189. package/dist/ui/markdown/highlight.js +0 -44
  190. package/dist/ui/markdown/index.js +0 -1460
  191. package/dist/ui/markdown/tokenizer.js +0 -24
  192. package/dist/ui/render-item.js +0 -5
  193. package/dist/ui/screens/REPL.js +0 -119
  194. package/dist/ui/screens/approval-lifecycle.js +0 -38
  195. package/dist/ui/status-line.js +0 -72
  196. package/dist/ui/theme/index.js +0 -51
  197. package/dist/ui/theme/themes/claude-dark-daltonized.js +0 -51
  198. package/dist/ui/theme/themes/claude-dark.js +0 -50
  199. package/dist/ui/theme/themes/claude-light-daltonized.js +0 -51
  200. package/dist/ui/theme/themes/claude-light.js +0 -50
  201. package/dist/ui/theme/themes/dark-accessible.js +0 -18
  202. package/dist/ui/theme/themes/dark.js +0 -49
  203. package/dist/ui/theme/themes/light-accessible.js +0 -18
  204. package/dist/ui/theme/themes/light.js +0 -49
  205. package/dist/ui/theme/types.js +0 -3
  206. package/dist/ui/theme.js +0 -142
  207. package/dist/ui/to-render-items.js +0 -145
  208. package/dist/ui/tools/AgentTool/index.js +0 -30
  209. package/dist/ui/tools/ArchitectTool/index.js +0 -31
  210. package/dist/ui/tools/AskUserTool/index.js +0 -46
  211. package/dist/ui/tools/BashTool/BashToolResultMessage.js +0 -11
  212. package/dist/ui/tools/BashTool/OutputLine.js +0 -21
  213. package/dist/ui/tools/BashTool/index.js +0 -91
  214. package/dist/ui/tools/BrowseTool/index.js +0 -43
  215. package/dist/ui/tools/BrowserTool/index.js +0 -47
  216. package/dist/ui/tools/CbmTool/index.js +0 -188
  217. package/dist/ui/tools/CheckDelegationTool/index.js +0 -46
  218. package/dist/ui/tools/CheckMessagesTool/index.js +0 -85
  219. package/dist/ui/tools/CreateQuipTool/index.js +0 -30
  220. package/dist/ui/tools/CreateSkillTool/index.js +0 -22
  221. package/dist/ui/tools/CreateToolTool/index.js +0 -31
  222. package/dist/ui/tools/DelegateRemoteTool/index.js +0 -42
  223. package/dist/ui/tools/DeployTool/index.js +0 -47
  224. package/dist/ui/tools/FffTool/index.js +0 -103
  225. package/dist/ui/tools/FileEditTool/index.js +0 -67
  226. package/dist/ui/tools/FileReadTool/index.js +0 -68
  227. package/dist/ui/tools/FileWriteTool/index.js +0 -61
  228. package/dist/ui/tools/ForkTool/index.js +0 -47
  229. package/dist/ui/tools/FrgTool/index.js +0 -96
  230. package/dist/ui/tools/GetThreadTool/index.js +0 -39
  231. package/dist/ui/tools/GlobTool/index.js +0 -50
  232. package/dist/ui/tools/GrepTool/index.js +0 -84
  233. package/dist/ui/tools/HatchArionTool/index.js +0 -36
  234. package/dist/ui/tools/LearnSkillTool/index.js +0 -22
  235. package/dist/ui/tools/LearnTool/index.js +0 -43
  236. package/dist/ui/tools/LearnToolTool/index.js +0 -22
  237. package/dist/ui/tools/ListClientsTool/index.js +0 -39
  238. package/dist/ui/tools/LspTool/index.js +0 -261
  239. package/dist/ui/tools/MCPTool/index.js +0 -33
  240. package/dist/ui/tools/ManageNetworkTool/index.js +0 -53
  241. package/dist/ui/tools/MemoryReadTool/index.js +0 -64
  242. package/dist/ui/tools/MemoryWriteTool/index.js +0 -20
  243. package/dist/ui/tools/NotebookEditTool/index.js +0 -33
  244. package/dist/ui/tools/NotebookReadTool/index.js +0 -25
  245. package/dist/ui/tools/OutlookReadTool/index.js +0 -66
  246. package/dist/ui/tools/OutlookReplyTool/index.js +0 -49
  247. package/dist/ui/tools/OutlookSendTool/index.js +0 -49
  248. package/dist/ui/tools/PauseDelegationTool/index.js +0 -35
  249. package/dist/ui/tools/ProbeTool/index.js +0 -121
  250. package/dist/ui/tools/ProcessTool/index.js +0 -66
  251. package/dist/ui/tools/QuestListTool/index.js +0 -46
  252. package/dist/ui/tools/QuestReportTool/index.js +0 -49
  253. package/dist/ui/tools/QuestUpdateTool/index.js +0 -87
  254. package/dist/ui/tools/QuipCommentTool/index.js +0 -69
  255. package/dist/ui/tools/QuipReadTool/index.js +0 -71
  256. package/dist/ui/tools/RestArionTool/index.js +0 -32
  257. package/dist/ui/tools/RestartTool/index.js +0 -35
  258. package/dist/ui/tools/ResumeDelegationTool/index.js +0 -35
  259. package/dist/ui/tools/RetireArionTool/index.js +0 -32
  260. package/dist/ui/tools/RgTool/index.js +0 -73
  261. package/dist/ui/tools/SearchKnowledgeTool/index.js +0 -43
  262. package/dist/ui/tools/SearchMessagesTool/index.js +0 -43
  263. package/dist/ui/tools/SelfDiagnoseTool/index.js +0 -61
  264. package/dist/ui/tools/SendMessageTool/index.js +0 -45
  265. package/dist/ui/tools/SerenaTool/index.js +0 -124
  266. package/dist/ui/tools/SessionHistoryTool/index.js +0 -52
  267. package/dist/ui/tools/SgTool/index.js +0 -80
  268. package/dist/ui/tools/SlackReactTool/index.js +0 -41
  269. package/dist/ui/tools/SlackReadTool/index.js +0 -48
  270. package/dist/ui/tools/SlackSendTool/index.js +0 -45
  271. package/dist/ui/tools/SpawnWorkerTool/index.js +0 -33
  272. package/dist/ui/tools/StickerRequestTool/index.js +0 -19
  273. package/dist/ui/tools/ThinkTool/index.js +0 -17
  274. package/dist/ui/tools/UgTool/index.js +0 -108
  275. package/dist/ui/tools/UseSkillTool/index.js +0 -22
  276. package/dist/ui/tools/WakeArionTool/index.js +0 -32
  277. package/dist/ui/tools/WebFetchTool/index.js +0 -56
  278. package/dist/ui/tools/WebSearchTool/index.js +0 -44
  279. package/dist/ui/tools/lsTool/index.js +0 -58
  280. package/dist/ui/tools/registry.js +0 -197
  281. package/dist/ui/tools/tool-renderer.js +0 -11
  282. package/dist/ui/tools/truncation.js +0 -35
  283. package/dist/ui/types/anthropic.js +0 -4
  284. package/dist/ui/types/index.js +0 -2
  285. package/dist/ui/types/message.js +0 -3
  286. package/dist/ui/types/tool.js +0 -4
  287. package/dist/ui/utils/array.js +0 -4
  288. package/dist/ui/utils/cursor.js +0 -131
  289. package/dist/ui/utils/diff.js +0 -120
  290. package/dist/ui/utils/format.js +0 -42
  291. package/dist/ui/utils/fuzzy.js +0 -59
  292. package/dist/ui/utils/index.js +0 -11
  293. package/dist/ui/utils/keys.js +0 -8
  294. package/dist/ui/utils/patch.js +0 -17
  295. package/dist/ui/utils/risk.js +0 -114
  296. package/dist/ui/utils/terminal-image.js +0 -70
  297. package/dist/ui/utils/validation.js +0 -48
  298. package/dist/ui/verb-pairs.js +0 -248
  299. package/dist/ui.js +0 -131
  300. package/src/entrypoints/command-mode.ts +0 -5
  301. package/src/entrypoints/daemon.ts +0 -54
  302. package/src/entrypoints/headless-stdio.ts +0 -27
  303. package/src/entrypoints/interactive.ts +0 -112
  304. package/src/main.ts +0 -72
  305. package/src/runtime/configure-bun-sqlite.ts +0 -3
  306. package/src/runtime/crash-handlers.ts +0 -128
  307. package/src/runtime/interactive-invocation.test.ts +0 -42
  308. package/src/runtime/interactive-invocation.ts +0 -51
  309. package/src/runtime/internal-mode.test.ts +0 -19
  310. package/src/runtime/internal-mode.ts +0 -24
  311. package/src/runtime/launch-spec.test.ts +0 -26
  312. package/src/runtime/launch-spec.ts +0 -84
  313. package/src/runtime/owner-lease.ts +0 -52
  314. package/src/runtime/public-mode.test.ts +0 -18
  315. package/src/runtime/public-mode.ts +0 -19
  316. package/src/runtime/run-internal-mode.ts +0 -19
  317. package/src/runtime/runtime-kind.test.ts +0 -23
  318. package/src/runtime/runtime-kind.ts +0 -41
  319. package/src/runtime/spawn-aria.ts +0 -62
@@ -1,12 +0,0 @@
1
- import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
- import { Box, Text } from "ink";
3
- import { getTheme } from "../../theme/index.js";
4
- import { applyMarkdown } from "../../markdown/index.js";
5
- const BLACK_CIRCLE = process.platform === "darwin" ? "\u23FA" : "\u25CF";
6
- export function UserTextMessage({ param: { text }, userName, columns, addMargin = false, showPrefix = true, }) {
7
- const theme = getTheme();
8
- const name = userName || "User";
9
- const contentWidth = Math.max(columns - 4, 20);
10
- return (_jsxs(Box, { flexDirection: "column", marginTop: addMargin ? 1 : 0, width: "100%", children: [showPrefix && (_jsx(Box, { flexDirection: "row", children: _jsxs(Text, { bold: true, color: theme.colors.primary, children: ["\uD83E\uDD84 ", name] }) })), _jsxs(Box, { flexDirection: "row", width: "100%", marginTop: showPrefix ? 1 : 0, children: [_jsx(Box, { minWidth: 2, children: _jsx(Text, { color: theme.colors.primary, children: BLACK_CIRCLE }) }), _jsx(Box, { flexShrink: 1, width: contentWidth, children: _jsx(Text, { wrap: "wrap", children: text ? applyMarkdown(text, { width: contentWidth }) : "" }) })] })] }));
11
- }
12
- //# sourceMappingURL=UserTextMessage.js.map
@@ -1,68 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState, useEffect } from "react";
3
- import { Box, Text, useInput } from "ink";
4
- import { getArionColor } from "../../theme.js";
5
- import { isEscapeInput } from "../../utils/keys.js";
6
- export function ArionSelector({ arions, initialFilter = "", statusFilter = "all", onSelect, onCancel, }) {
7
- const [selectedIndex, setSelectedIndex] = useState(0);
8
- const [filter, setFilter] = useState(initialFilter);
9
- const filtered = arions.filter((arion) => {
10
- // First apply status filter
11
- if (statusFilter === "active" && arion.isResting)
12
- return false;
13
- if (statusFilter === "resting" && !arion.isResting)
14
- return false;
15
- // Then apply text filter
16
- return arion.name.toLowerCase().includes(filter.toLowerCase());
17
- });
18
- // Clamp selectedIndex when filtered results change
19
- useEffect(() => {
20
- setSelectedIndex((i) => Math.min(i, Math.max(0, filtered.length - 1)));
21
- }, [filtered.length]);
22
- // Safe index that's always in bounds
23
- const safeIndex = filtered.length > 0 ? Math.min(selectedIndex, filtered.length - 1) : 0;
24
- // Only use input handling when stdin supports raw mode
25
- const isRawModeSupported = process.stdin.isTTY ?? false;
26
- useInput((input, key) => {
27
- if (isEscapeInput(input, key)) {
28
- onCancel();
29
- return;
30
- }
31
- if (key.return && filtered.length > 0) {
32
- onSelect(filtered[safeIndex]);
33
- return;
34
- }
35
- if (key.upArrow) {
36
- setSelectedIndex((i) => Math.max(0, i - 1));
37
- return;
38
- }
39
- if (key.downArrow) {
40
- setSelectedIndex((i) => Math.min(filtered.length - 1, i + 1));
41
- return;
42
- }
43
- if (key.backspace || key.delete) {
44
- setFilter((f) => f.slice(0, -1));
45
- return;
46
- }
47
- // Printable character input
48
- if (input && !key.ctrl && !key.meta) {
49
- setFilter((f) => f + input);
50
- }
51
- }, { isActive: isRawModeSupported });
52
- return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "gray", paddingX: 1, children: [_jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { bold: true, children: statusFilter === "active"
53
- ? "Active Arions"
54
- : statusFilter === "resting"
55
- ? "Resting Arions"
56
- : "Arions" }), filter && _jsxs(Text, { dimColor: true, children: [" @", filter] })] }), filtered.length === 0 && (_jsx(Text, { dimColor: true, children: arions.length === 0
57
- ? "No arions available. Create one with /hatch"
58
- : statusFilter === "active"
59
- ? "No active arions"
60
- : statusFilter === "resting"
61
- ? "No resting arions"
62
- : "No matching arions" })), filtered.map((arion, i) => {
63
- const colorHex = getArionColor(arion.color);
64
- const suffix = arion.isActive ? " (active)" : arion.isResting ? " (resting)" : "";
65
- return (_jsxs(Box, { children: [_jsxs(Text, { inverse: i === safeIndex, children: [arion.emoji, " ", _jsx(Text, { color: colorHex, children: arion.name })] }), _jsxs(Text, { dimColor: true, children: [" ", arion.description, suffix] })] }, arion.name));
66
- }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "\u2191\u2193 navigate \u23CE select esc cancel" }) })] }));
67
- }
68
- //# sourceMappingURL=ArionSelector.js.map
@@ -1,62 +0,0 @@
1
- import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
- import { useEffect, useMemo, useState } from "react";
3
- import { Box, Text, useInput } from "ink";
4
- import { getTheme } from "../../theme/index.js";
5
- import { isEscapeInput } from "../../utils/keys.js";
6
- function clientMatchesFilter(client, filter) {
7
- const normalizedFilter = filter.trim().toLowerCase();
8
- if (!normalizedFilter) {
9
- return true;
10
- }
11
- return (client.displayLabel.toLowerCase().includes(normalizedFilter) ||
12
- client.clientId.toLowerCase().includes(normalizedFilter) ||
13
- client.clientKind.toLowerCase().includes(normalizedFilter));
14
- }
15
- function clampSelectedIndex(index, length) {
16
- if (length <= 0) {
17
- return 0;
18
- }
19
- return Math.min(index, length - 1);
20
- }
21
- export function ClientSelector({ clients, onSelect, onCancel, }) {
22
- const [selectedIndex, setSelectedIndex] = useState(0);
23
- const [filter, setFilter] = useState("");
24
- const theme = getTheme();
25
- const filteredClients = useMemo(() => clients.filter((client) => clientMatchesFilter(client, filter)), [clients, filter]);
26
- useEffect(() => {
27
- setSelectedIndex((index) => clampSelectedIndex(index, filteredClients.length));
28
- }, [filteredClients.length]);
29
- const safeIndex = clampSelectedIndex(selectedIndex, filteredClients.length);
30
- const isRawModeSupported = process.stdin.isTTY ?? false;
31
- useInput((input, key) => {
32
- if (isEscapeInput(input, key)) {
33
- onCancel();
34
- return;
35
- }
36
- if (key.return) {
37
- if (filteredClients.length > 0 && !filteredClients[safeIndex]?.self) {
38
- onSelect(filteredClients[safeIndex]);
39
- }
40
- return;
41
- }
42
- if (key.upArrow) {
43
- setSelectedIndex((index) => Math.max(0, index - 1));
44
- return;
45
- }
46
- if (key.downArrow) {
47
- setSelectedIndex((index) => clampSelectedIndex(index + 1, filteredClients.length));
48
- return;
49
- }
50
- if (key.backspace || key.delete) {
51
- setFilter((current) => current.slice(0, -1));
52
- setSelectedIndex(0);
53
- return;
54
- }
55
- if (input && !key.ctrl && !key.meta) {
56
- setFilter((current) => current + input);
57
- setSelectedIndex(0);
58
- }
59
- }, { isActive: isRawModeSupported });
60
- return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: theme.colors.secondary, paddingX: 1, children: [_jsxs(Text, { bold: true, color: theme.colors.primary, children: [" ", "Same-Home Clients", " "] }), filter ? _jsxs(Text, { dimColor: true, children: [" (filter: \"", filter, "\")"] }) : null, filteredClients.length === 0 && _jsx(Text, { dimColor: true, children: "No same-home clients found." }), filteredClients.map((client, index) => (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { inverse: index === safeIndex, color: index === safeIndex ? theme.colors.primary : undefined, children: [index === safeIndex ? " ▸ " : " ", client.displayLabel] }), _jsxs(Text, { dimColor: true, children: [" ", client.clientId, client.self ? " self · not sendable" : ""] })] }, `${client.clientId}-${index}`))), _jsx(Box, { marginTop: filteredClients.length > 0 ? 1 : 0, children: _jsx(Text, { dimColor: true, children: "type to search \u2191\u2193 navigate \u23CE select esc cancel" }) })] }));
61
- }
62
- //# sourceMappingURL=ClientSelector.js.map
@@ -1,67 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState, useEffect } from "react";
3
- import { Box, Text, useInput } from "ink";
4
- import { isEscapeInput } from "../../utils/keys.js";
5
- function hasArgumentBoundary(value) {
6
- return /\s/.test(value.trimStart());
7
- }
8
- function extractCommandQuery(value) {
9
- return value.trimStart().split(/\s+/, 1)[0] ?? "";
10
- }
11
- export function CommandPalette({ commands, initialFilter = "", onSelect, onHandOffInput, onCancel, }) {
12
- const [selectedIndex, setSelectedIndex] = useState(0);
13
- const [filter, setFilter] = useState(initialFilter);
14
- const commandQuery = extractCommandQuery(filter).toLowerCase();
15
- const filtered = commands.filter((cmd) => cmd.name.toLowerCase().includes(commandQuery));
16
- // Clamp selectedIndex when filtered results change
17
- useEffect(() => {
18
- setSelectedIndex((i) => Math.min(i, Math.max(0, filtered.length - 1)));
19
- }, [filtered.length]);
20
- useEffect(() => {
21
- if (!onHandOffInput || !hasArgumentBoundary(filter)) {
22
- return;
23
- }
24
- onHandOffInput(`/${filter}`);
25
- }, [filter, onHandOffInput]);
26
- // Safe index that's always in bounds
27
- const safeIndex = filtered.length > 0 ? Math.min(selectedIndex, filtered.length - 1) : 0;
28
- // Only use input handling when stdin supports raw mode
29
- const isRawModeSupported = process.stdin.isTTY ?? false;
30
- useInput((input, key) => {
31
- if (isEscapeInput(input, key)) {
32
- onCancel();
33
- return;
34
- }
35
- if (key.return && hasArgumentBoundary(filter) && onHandOffInput) {
36
- onHandOffInput(`/${filter}`);
37
- return;
38
- }
39
- if (key.return && filtered.length > 0) {
40
- onSelect(filtered[safeIndex]);
41
- return;
42
- }
43
- if (key.upArrow) {
44
- setSelectedIndex((i) => Math.max(0, i - 1));
45
- return;
46
- }
47
- if (key.downArrow) {
48
- setSelectedIndex((i) => Math.min(filtered.length - 1, i + 1));
49
- return;
50
- }
51
- if (key.backspace || key.delete) {
52
- setFilter((f) => f.slice(0, -1));
53
- return;
54
- }
55
- // Printable character input
56
- if (input && !key.ctrl && !key.meta) {
57
- const nextFilter = filter + input;
58
- if (onHandOffInput && hasArgumentBoundary(nextFilter)) {
59
- onHandOffInput(`/${nextFilter}`);
60
- return;
61
- }
62
- setFilter(nextFilter);
63
- }
64
- }, { isActive: isRawModeSupported });
65
- return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "gray", paddingX: 1, children: [_jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { bold: true, children: "Commands" }), filter && _jsxs(Text, { dimColor: true, children: [" /", filter] })] }), filtered.map((cmd, i) => (_jsxs(Box, { children: [_jsxs(Text, { inverse: i === safeIndex, children: ["/", cmd.name] }), _jsxs(Text, { dimColor: true, children: [" ", cmd.description] })] }, cmd.name))), filtered.length === 0 && _jsx(Text, { dimColor: true, children: "No matching commands" }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "\u2191\u2193 navigate \u23CE select esc cancel" }) })] }));
66
- }
67
- //# sourceMappingURL=CommandPalette.js.map
@@ -1,87 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useState } from "react";
3
- import { Box, Text, useInput } from "ink";
4
- import { isEscapeInput } from "../../utils/keys.js";
5
- import { getTheme } from "../../theme/index.js";
6
- const ACTION_OPTIONS = [
7
- {
8
- id: "start",
9
- label: "Start daemon",
10
- description: "Launch the shared background daemon process",
11
- icon: "▶",
12
- showWhenRunning: false,
13
- },
14
- {
15
- id: "stop",
16
- label: "Stop daemon",
17
- description: "Gracefully stop the shared daemon process",
18
- icon: "■",
19
- showWhenRunning: true,
20
- },
21
- {
22
- id: "restart",
23
- label: "Restart daemon",
24
- description: "Restart the shared daemon process cleanly",
25
- icon: "↻",
26
- showWhenRunning: true,
27
- },
28
- ];
29
- function LoopStatusBadge({ loopStatus }) {
30
- const theme = getTheme();
31
- const c = theme.colors;
32
- if (!loopStatus)
33
- return null;
34
- const statusColors = {
35
- running: c.success,
36
- idle: c.info,
37
- starting: c.warning,
38
- stopping: c.warning,
39
- stopped: c.textMuted,
40
- error: c.error,
41
- };
42
- const color = statusColors[loopStatus] ?? c.text;
43
- return _jsx(Text, { color: color, children: loopStatus });
44
- }
45
- export function DaemonControl({ onAction, onClose, status, actionStatus }) {
46
- const theme = getTheme();
47
- const c = theme.colors;
48
- // Filter options based on daemon state
49
- const visibleOptions = ACTION_OPTIONS.filter((opt) => {
50
- if (opt.showWhenRunning === undefined)
51
- return true;
52
- return opt.showWhenRunning === status.running;
53
- });
54
- const [selectedIndex, setSelectedIndex] = useState(0);
55
- const safeIndex = Math.min(selectedIndex, visibleOptions.length - 1);
56
- const isRawModeSupported = process.stdin.isTTY ?? false;
57
- useInput((input, key) => {
58
- if (actionStatus)
59
- return; // Ignore input while action in progress
60
- if (isEscapeInput(input, key)) {
61
- onClose();
62
- return;
63
- }
64
- if (key.upArrow) {
65
- setSelectedIndex((i) => Math.max(0, i - 1));
66
- return;
67
- }
68
- if (key.downArrow) {
69
- setSelectedIndex((i) => Math.min(visibleOptions.length - 1, i + 1));
70
- return;
71
- }
72
- if (key.return && visibleOptions.length > 0) {
73
- const option = visibleOptions[safeIndex];
74
- if (option) {
75
- onAction(option.id);
76
- }
77
- return;
78
- }
79
- }, { isActive: isRawModeSupported });
80
- return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: c.primary, paddingX: 1, children: [_jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { bold: true, color: c.primary, children: "⚙ Daemon" }), _jsxs(Text, { color: c.textMuted, children: [" ", theme.symbols.arrow, " background service control"] })] }), _jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsxs(Box, { children: [_jsx(Text, { color: c.textMuted, children: "Status " }), _jsx(Text, { bold: true, color: status.running ? c.success : c.textMuted, children: status.running ? "● Running" : "○ Stopped" })] }), status.running && (_jsxs(_Fragment, { children: [status.loopStatus && (_jsxs(Box, { children: [_jsx(Text, { color: c.textMuted, children: "Loop " }), _jsx(LoopStatusBadge, { loopStatus: status.loopStatus })] })), status.port && (_jsxs(Box, { children: [_jsx(Text, { color: c.textMuted, children: "Port " }), _jsx(Text, { color: c.text, children: status.port })] })), status.nodeId && (_jsxs(Box, { children: [_jsx(Text, { color: c.textMuted, children: "Node " }), _jsx(Text, { color: c.text, children: status.nodeId.length > 20 ? `${status.nodeId.slice(0, 20)}…` : status.nodeId })] })), status.runtimeId && (_jsxs(Box, { children: [_jsx(Text, { color: c.textMuted, children: "Runtime " }), _jsx(Text, { color: c.text, children: status.runtimeId.length > 20
81
- ? `${status.runtimeId.slice(0, 20)}…`
82
- : status.runtimeId })] })), status.clients !== undefined && (_jsxs(Box, { children: [_jsx(Text, { color: c.textMuted, children: "Clients " }), _jsxs(Text, { color: status.clients > 0 ? c.info : c.textMuted, children: [status.clients, " attached"] })] }))] }))] }), _jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: c.border, children: "─".repeat(44) }) }), actionStatus && (_jsx(Box, { marginBottom: 1, paddingX: 1, children: _jsxs(Text, { color: c.warning, children: ["⟳ ", actionStatus] }) })), _jsx(Box, { flexDirection: "column", children: visibleOptions.map((option, i) => {
83
- const isHighlighted = i === safeIndex;
84
- return (_jsxs(Box, { paddingX: 1, flexDirection: "column", children: [_jsx(Box, { children: _jsxs(Text, { inverse: isHighlighted, color: isHighlighted ? (option.id === "stop" ? c.error : c.primary) : c.text, children: [option.icon, " ", option.label] }) }), isHighlighted && (_jsx(Box, { paddingLeft: 3, children: _jsx(Text, { color: c.textMuted, children: option.description }) }))] }, option.id));
85
- }) }), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: c.textMuted, children: ["↑↓", " navigate ", "⏎", " select ", "esc", " close"] }) })] }));
86
- }
87
- //# sourceMappingURL=DaemonControl.js.map
@@ -1,15 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Box, Text, useInput } from "ink";
3
- import { getTheme } from "../../theme/index.js";
4
- import { isEscapeInput } from "../../utils/keys.js";
5
- export function InviteShareOverlay({ inviteToken, inviteLabel, expiresAt, onClose, }) {
6
- const theme = getTheme();
7
- const isRawModeSupported = process.stdin.isTTY ?? false;
8
- useInput((input, key) => {
9
- if (key.return || isEscapeInput(input, key)) {
10
- onClose();
11
- }
12
- }, { isActive: isRawModeSupported });
13
- return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: theme.colors.secondary, paddingX: 1, paddingY: 1, children: [_jsx(Text, { bold: true, color: theme.colors.primary, children: "Internet Invite" }), inviteLabel ? (_jsxs(Text, { children: ["Label: ", _jsx(Text, { bold: true, children: inviteLabel })] })) : null, expiresAt ? _jsxs(Text, { dimColor: true, children: ["Expires: ", expiresAt] }) : null, _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { children: "Share this token:" }), _jsx(Text, { children: inviteToken })] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { children: "Join with:" }), _jsx(Text, { children: `aria pairing join ${inviteToken}` })] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Press Enter or Esc to close." }) })] }));
14
- }
15
- //# sourceMappingURL=InviteShareOverlay.js.map
@@ -1,32 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState } from "react";
3
- import { Box, Text, useInput } from "ink";
4
- import { getTheme } from "../../theme/index.js";
5
- import { isEscapeInput } from "../../utils/keys.js";
6
- export function JoinInviteOverlay({ onSubmit, onCancel, error, }) {
7
- const [inviteToken, setInviteToken] = useState("");
8
- const theme = getTheme();
9
- const isRawModeSupported = process.stdin.isTTY ?? false;
10
- useInput((input, key) => {
11
- if (isEscapeInput(input, key)) {
12
- onCancel();
13
- return;
14
- }
15
- if (key.return) {
16
- const trimmed = inviteToken.trim();
17
- if (trimmed.length > 0) {
18
- onSubmit(trimmed);
19
- }
20
- return;
21
- }
22
- if (key.backspace || key.delete) {
23
- setInviteToken((current) => current.slice(0, -1));
24
- return;
25
- }
26
- if (input && !key.ctrl && !key.meta) {
27
- setInviteToken((current) => current + input);
28
- }
29
- }, { isActive: isRawModeSupported });
30
- return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: theme.colors.secondary, paddingX: 1, paddingY: 1, children: [_jsx(Text, { bold: true, color: theme.colors.primary, children: "Join Invite" }), _jsx(Text, { children: "Paste the invite token and press Enter." }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { children: inviteToken || " " }) }), error ? (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: theme.colors.error, children: error }) })) : null, _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Type token, Enter to join, Esc to cancel." }) })] }));
31
- }
32
- //# sourceMappingURL=JoinInviteOverlay.js.map
@@ -1,100 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState, useEffect } from "react";
3
- import { Box, Text, useInput } from "ink";
4
- import InkSpinner from "ink-spinner";
5
- import { isEscapeInput } from "../../utils/keys.js";
6
- export function MemoryBrowser({ memories, mode = "browse", isLoading = false, onSelect, onCancel, }) {
7
- const [selectedIndex, setSelectedIndex] = useState(0);
8
- const [filter, setFilter] = useState("");
9
- const [page, setPage] = useState(0);
10
- const pageSize = 8;
11
- // Filter memories by content
12
- const filtered = memories.filter((m) => m.content.toLowerCase().includes(filter.toLowerCase()));
13
- const totalPages = Math.max(1, Math.ceil(filtered.length / pageSize));
14
- const pageItems = filtered.slice(page * pageSize, (page + 1) * pageSize);
15
- // Clamp selectedIndex when filtered results change
16
- useEffect(() => {
17
- setSelectedIndex((i) => Math.min(i, Math.max(0, pageItems.length - 1)));
18
- }, [pageItems.length]);
19
- // Safe index that's always in bounds
20
- const safeIndex = pageItems.length > 0 ? Math.min(selectedIndex, pageItems.length - 1) : 0;
21
- // Only use input handling when stdin supports raw mode
22
- const isRawModeSupported = process.stdin.isTTY ?? false;
23
- useInput((input, key) => {
24
- if (isEscapeInput(input, key)) {
25
- onCancel();
26
- return;
27
- }
28
- if (key.return && pageItems.length > 0 && mode === "forget") {
29
- onSelect?.(pageItems[safeIndex]);
30
- return;
31
- }
32
- if (key.upArrow) {
33
- setSelectedIndex((i) => Math.max(0, i - 1));
34
- return;
35
- }
36
- if (key.downArrow) {
37
- setSelectedIndex((i) => Math.min(pageItems.length - 1, i + 1));
38
- return;
39
- }
40
- if (key.leftArrow && page > 0) {
41
- setPage((p) => p - 1);
42
- setSelectedIndex(0);
43
- return;
44
- }
45
- if (key.rightArrow && page < totalPages - 1) {
46
- setPage((p) => p + 1);
47
- setSelectedIndex(0);
48
- return;
49
- }
50
- if (key.backspace || key.delete) {
51
- setFilter((f) => f.slice(0, -1));
52
- setPage(0);
53
- setSelectedIndex(0);
54
- return;
55
- }
56
- // Printable character input
57
- if (input && !key.ctrl && !key.meta) {
58
- setFilter((f) => f + input);
59
- setPage(0);
60
- setSelectedIndex(0);
61
- }
62
- }, { isActive: isRawModeSupported });
63
- // Format date for display (handles both Date objects and ISO strings)
64
- function formatDate(date) {
65
- const d = date instanceof Date ? date : new Date(date);
66
- if (isNaN(d.getTime()))
67
- return "unknown";
68
- const now = new Date();
69
- const diff = now.getTime() - d.getTime();
70
- const days = Math.floor(diff / (1000 * 60 * 60 * 24));
71
- if (days === 0)
72
- return "today";
73
- if (days === 1)
74
- return "yesterday";
75
- if (days < 7)
76
- return `${days}d ago`;
77
- if (days < 30)
78
- return `${Math.floor(days / 7)}w ago`;
79
- return `${Math.floor(days / 30)}mo ago`;
80
- }
81
- // Truncate content for display
82
- function truncate(str, len) {
83
- if (str.length <= len)
84
- return str;
85
- return str.slice(0, len - 3) + "...";
86
- }
87
- const title = mode === "forget" ? "Select Memory to Delete" : "Memories";
88
- return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: mode === "forget" ? "red" : "cyan", paddingX: 1, children: [_jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { bold: true, color: mode === "forget" ? "red" : "cyan", children: title }), filter && _jsxs(Text, { dimColor: true, children: [" (filter: \"", filter, "\")"] }), _jsxs(Text, { dimColor: true, children: [" - ", filtered.length, " memories"] })] }), isLoading && (_jsxs(Box, { children: [_jsx(Text, { color: "cyan", children: _jsx(InkSpinner, { type: "dots" }) }), _jsx(Text, { dimColor: true, children: " Loading memories..." })] })), !isLoading && filtered.length === 0 && (_jsx(Text, { dimColor: true, children: memories.length === 0
89
- ? "No memories stored yet. Use /remember to add some."
90
- : "No memories match your filter." })), !isLoading &&
91
- pageItems.map((memory, i) => {
92
- const isSelected = i === safeIndex;
93
- const date = formatDate(memory.createdAt);
94
- const content = truncate(memory.content, 60);
95
- return (_jsxs(Box, { flexDirection: "row", children: [_jsxs(Text, { inverse: isSelected, children: [isSelected ? ">" : " ", " ", content] }), _jsxs(Text, { dimColor: true, children: [" [", date, "]"] }), memory.network && _jsxs(Text, { dimColor: true, children: [" (", memory.network, ")"] })] }, memory.id));
96
- }), !isLoading && totalPages > 1 && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { dimColor: true, children: ["Page ", page + 1, "/", totalPages] }) })), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: mode === "forget"
97
- ? "type to filter arrows navigate enter delete esc cancel"
98
- : "type to filter arrows navigate esc close" }) })] }));
99
- }
100
- //# sourceMappingURL=MemoryBrowser.js.map
@@ -1,123 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- // packages/cli/src/ui/components/overlays/MessageSelector.tsx
3
- import { useState, useEffect, useMemo } from "react";
4
- import { Box, Text, useInput } from "ink";
5
- import { isEscapeInput } from "../../utils/keys.js";
6
- import { useTerminalSize } from "../../hooks/useTerminalSize.js";
7
- function truncate(str, len) {
8
- if (str.length <= len)
9
- return str;
10
- return str.slice(0, len - 3) + "…";
11
- }
12
- function roleIcon(role) {
13
- switch (role) {
14
- case "user":
15
- return "👤";
16
- case "assistant":
17
- return "🤖";
18
- case "system":
19
- return "⚙️";
20
- case "tool":
21
- return "🔧";
22
- default:
23
- return " ";
24
- }
25
- }
26
- function roleColor(role) {
27
- switch (role) {
28
- case "user":
29
- return "cyan";
30
- case "assistant":
31
- return "green";
32
- case "system":
33
- return "yellow";
34
- case "tool":
35
- return "gray";
36
- default:
37
- return "white";
38
- }
39
- }
40
- export function MessageSelector({ messages, onSelect, onCancel, }) {
41
- const { columns, rows } = useTerminalSize();
42
- const [selectedIndex, setSelectedIndex] = useState(0);
43
- const [searchQuery, setSearchQuery] = useState("");
44
- // Filter messages by search query (case-insensitive)
45
- const filtered = useMemo(() => {
46
- if (!searchQuery)
47
- return messages;
48
- const q = searchQuery.toLowerCase();
49
- return messages.filter((m) => m.text.toLowerCase().includes(q) ||
50
- m.role.toLowerCase().includes(q) ||
51
- (m.arion && m.arion.toLowerCase().includes(q)));
52
- }, [messages, searchQuery]);
53
- // Clamp selection when filtered list changes
54
- useEffect(() => {
55
- setSelectedIndex((i) => Math.min(i, Math.max(0, filtered.length - 1)));
56
- }, [filtered.length]);
57
- // Start selection on the last user message in filtered list
58
- useEffect(() => {
59
- if (!searchQuery) {
60
- const lastUserIdx = filtered.reduce((acc, m, i) => (m.role === "user" ? i : acc), 0);
61
- setSelectedIndex(lastUserIdx);
62
- }
63
- }, []); // only on mount
64
- // Reserve space for header (3), footer (2), border (2), scroll indicators (2)
65
- const maxVisible = Math.max(4, rows - 10);
66
- // Scrolling window: keep selectedIndex visible
67
- const [scrollOffset, setScrollOffset] = useState(0);
68
- useEffect(() => {
69
- if (selectedIndex < scrollOffset) {
70
- setScrollOffset(selectedIndex);
71
- }
72
- else if (selectedIndex >= scrollOffset + maxVisible) {
73
- setScrollOffset(selectedIndex - maxVisible + 1);
74
- }
75
- }, [selectedIndex, maxVisible, scrollOffset]);
76
- // Reset scroll when search changes
77
- useEffect(() => {
78
- const lastUserIdx = filtered.reduce((acc, m, i) => (m.role === "user" ? i : acc), 0);
79
- setScrollOffset(Math.max(0, lastUserIdx - maxVisible + 2));
80
- }, [searchQuery]);
81
- const visibleMessages = filtered.slice(scrollOffset, scrollOffset + maxVisible);
82
- const safeIndex = filtered.length > 0 ? Math.min(selectedIndex, filtered.length - 1) : 0;
83
- const isRawModeSupported = process.stdin.isTTY ?? false;
84
- useInput((input, key) => {
85
- if (isEscapeInput(input, key)) {
86
- onCancel();
87
- }
88
- else if (key.return && filtered.length > 0) {
89
- const entry = filtered[safeIndex];
90
- if (entry && entry.role === "user") {
91
- onSelect(entry.index, entry.text);
92
- }
93
- }
94
- else if (key.upArrow) {
95
- setSelectedIndex((i) => Math.max(0, i - 1));
96
- }
97
- else if (key.downArrow) {
98
- setSelectedIndex((i) => Math.min(filtered.length - 1, i + 1));
99
- }
100
- else if (key.backspace || key.delete) {
101
- const next = searchQuery.slice(0, -1);
102
- setSearchQuery(next);
103
- setSelectedIndex(0);
104
- }
105
- else if (input && !key.ctrl && !key.meta) {
106
- const next = searchQuery + input;
107
- setSearchQuery(next);
108
- setSelectedIndex(0);
109
- }
110
- }, { isActive: isRawModeSupported });
111
- const textMaxLen = Math.max(30, Math.min(120, columns - 16));
112
- return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [_jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { bold: true, color: "cyan", children: "Edit Message" }), searchQuery ? (_jsxs(Text, { dimColor: true, children: [" ", "(search: \"", searchQuery, "\") \u2014 ", filtered.length, "/", messages.length, " messages"] })) : (_jsxs(Text, { dimColor: true, children: [" \u2014 ", messages.length, " messages \u00B7 select a user message to edit"] }))] }), scrollOffset > 0 && _jsxs(Text, { dimColor: true, children: [" \u2191 ", scrollOffset, " more above"] }), filtered.length === 0 ? (_jsx(Text, { dimColor: true, children: searchQuery ? `No messages match "${searchQuery}".` : "No messages." })) : (visibleMessages.map((entry, vIdx) => {
113
- const globalIdx = scrollOffset + vIdx;
114
- const isSelected = globalIdx === safeIndex;
115
- const isUser = entry.role === "user";
116
- const icon = roleIcon(entry.role);
117
- const color = roleColor(entry.role);
118
- const prefix = isSelected ? "❯" : " ";
119
- const preview = truncate(entry.text.replace(/\n/g, " ").trim() || "(empty)", textMaxLen);
120
- return (_jsx(Box, { flexDirection: "row", children: _jsxs(Text, { inverse: isSelected, color: isSelected ? undefined : color, dimColor: !isUser && !isSelected, bold: isUser, children: [prefix, " ", icon, " ", preview] }) }, `${entry.index}-${vIdx}`));
121
- })), scrollOffset + maxVisible < filtered.length && (_jsxs(Text, { dimColor: true, children: [" \u2193 ", filtered.length - scrollOffset - maxVisible, " more below"] })), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "type to search \u00B7 \u2191\u2193 navigate \u00B7 enter select user message \u00B7 esc cancel" }) })] }));
122
- }
123
- //# sourceMappingURL=MessageSelector.js.map