arc402-cli 0.9.18 → 0.10.0

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 (358) hide show
  1. package/README.md +41 -2
  2. package/dist/abis.d.ts +1 -0
  3. package/dist/abis.d.ts.map +1 -1
  4. package/dist/abis.js +45 -14
  5. package/dist/abis.js.map +1 -1
  6. package/dist/bundler.d.ts +1 -1
  7. package/dist/bundler.d.ts.map +1 -1
  8. package/dist/bundler.js +61 -27
  9. package/dist/bundler.js.map +1 -1
  10. package/dist/client.d.ts +1 -1
  11. package/dist/client.d.ts.map +1 -1
  12. package/dist/client.js +9 -5
  13. package/dist/client.js.map +1 -1
  14. package/dist/coinbase-smart-wallet.js +4 -1
  15. package/dist/coinbase-smart-wallet.js.map +1 -1
  16. package/dist/commands/accept.js +28 -25
  17. package/dist/commands/accept.js.map +1 -1
  18. package/dist/commands/agent-handshake.js +18 -15
  19. package/dist/commands/agent-handshake.js.map +1 -1
  20. package/dist/commands/agent.js +104 -98
  21. package/dist/commands/agent.js.map +1 -1
  22. package/dist/commands/agreements.js +98 -62
  23. package/dist/commands/agreements.js.map +1 -1
  24. package/dist/commands/arbitrator.js +81 -45
  25. package/dist/commands/arbitrator.js.map +1 -1
  26. package/dist/commands/arena-handshake.d.ts.map +1 -1
  27. package/dist/commands/arena-handshake.js +35 -53
  28. package/dist/commands/arena-handshake.js.map +1 -1
  29. package/dist/commands/arena.js +18 -12
  30. package/dist/commands/arena.js.map +1 -1
  31. package/dist/commands/backup.js +36 -30
  32. package/dist/commands/backup.js.map +1 -1
  33. package/dist/commands/cancel.js +18 -15
  34. package/dist/commands/cancel.js.map +1 -1
  35. package/dist/commands/channel.js +81 -45
  36. package/dist/commands/channel.js.map +1 -1
  37. package/dist/commands/coldstart.js +34 -31
  38. package/dist/commands/coldstart.js.map +1 -1
  39. package/dist/commands/compute.d.ts +14 -0
  40. package/dist/commands/compute.d.ts.map +1 -0
  41. package/dist/commands/compute.js +466 -0
  42. package/dist/commands/compute.js.map +1 -0
  43. package/dist/commands/config.js +30 -24
  44. package/dist/commands/config.js.map +1 -1
  45. package/dist/commands/contract-interaction.js +15 -12
  46. package/dist/commands/contract-interaction.js.map +1 -1
  47. package/dist/commands/daemon.d.ts.map +1 -1
  48. package/dist/commands/daemon.js +135 -98
  49. package/dist/commands/daemon.js.map +1 -1
  50. package/dist/commands/deliver.js +76 -37
  51. package/dist/commands/deliver.js.map +1 -1
  52. package/dist/commands/discover.js +27 -24
  53. package/dist/commands/discover.js.map +1 -1
  54. package/dist/commands/dispute.js +110 -104
  55. package/dist/commands/dispute.js.map +1 -1
  56. package/dist/commands/doctor.js +55 -16
  57. package/dist/commands/doctor.js.map +1 -1
  58. package/dist/commands/endpoint.js +95 -56
  59. package/dist/commands/endpoint.js.map +1 -1
  60. package/dist/commands/feed.js +18 -11
  61. package/dist/commands/feed.js.map +1 -1
  62. package/dist/commands/hire.js +40 -37
  63. package/dist/commands/hire.js.map +1 -1
  64. package/dist/commands/migrate.js +33 -30
  65. package/dist/commands/migrate.js.map +1 -1
  66. package/dist/commands/negotiate.d.ts.map +1 -1
  67. package/dist/commands/negotiate.js +36 -34
  68. package/dist/commands/negotiate.js.map +1 -1
  69. package/dist/commands/openshell.js +104 -68
  70. package/dist/commands/openshell.js.map +1 -1
  71. package/dist/commands/owner.js +20 -17
  72. package/dist/commands/owner.js.map +1 -1
  73. package/dist/commands/policy.js +43 -41
  74. package/dist/commands/policy.js.map +1 -1
  75. package/dist/commands/relay.d.ts.map +1 -1
  76. package/dist/commands/relay.js +51 -18
  77. package/dist/commands/relay.js.map +1 -1
  78. package/dist/commands/remediate.js +23 -20
  79. package/dist/commands/remediate.js.map +1 -1
  80. package/dist/commands/reputation.js +27 -25
  81. package/dist/commands/reputation.js.map +1 -1
  82. package/dist/commands/setup.js +104 -65
  83. package/dist/commands/setup.js.map +1 -1
  84. package/dist/commands/trust.js +20 -17
  85. package/dist/commands/trust.js.map +1 -1
  86. package/dist/commands/verify.js +21 -18
  87. package/dist/commands/verify.js.map +1 -1
  88. package/dist/commands/wallet.d.ts.map +1 -1
  89. package/dist/commands/wallet.js +645 -679
  90. package/dist/commands/wallet.js.map +1 -1
  91. package/dist/commands/watch.js +36 -33
  92. package/dist/commands/watch.js.map +1 -1
  93. package/dist/commands/watchtower.js +73 -37
  94. package/dist/commands/watchtower.js.map +1 -1
  95. package/dist/commands/workroom.d.ts.map +1 -1
  96. package/dist/commands/workroom.js +282 -143
  97. package/dist/commands/workroom.js.map +1 -1
  98. package/dist/config.d.ts +3 -0
  99. package/dist/config.d.ts.map +1 -1
  100. package/dist/config.js +71 -22
  101. package/dist/config.js.map +1 -1
  102. package/dist/daemon/compute-metering.d.ts +61 -0
  103. package/dist/daemon/compute-metering.d.ts.map +1 -0
  104. package/dist/daemon/compute-metering.js +299 -0
  105. package/dist/daemon/compute-metering.js.map +1 -0
  106. package/dist/daemon/compute-session.d.ts +100 -0
  107. package/dist/daemon/compute-session.d.ts.map +1 -0
  108. package/dist/daemon/compute-session.js +231 -0
  109. package/dist/daemon/compute-session.js.map +1 -0
  110. package/dist/daemon/config.d.ts +19 -1
  111. package/dist/daemon/config.d.ts.map +1 -1
  112. package/dist/daemon/config.js +90 -16
  113. package/dist/daemon/config.js.map +1 -1
  114. package/dist/daemon/credentials.d.ts +24 -0
  115. package/dist/daemon/credentials.d.ts.map +1 -0
  116. package/dist/daemon/credentials.js +80 -0
  117. package/dist/daemon/credentials.js.map +1 -0
  118. package/dist/daemon/delivery-client.d.ts +35 -0
  119. package/dist/daemon/delivery-client.d.ts.map +1 -0
  120. package/dist/daemon/delivery-client.js +231 -0
  121. package/dist/daemon/delivery-client.js.map +1 -0
  122. package/dist/daemon/file-delivery.d.ts +98 -0
  123. package/dist/daemon/file-delivery.d.ts.map +1 -0
  124. package/dist/daemon/file-delivery.js +461 -0
  125. package/dist/daemon/file-delivery.js.map +1 -0
  126. package/dist/daemon/hire-listener.d.ts +3 -3
  127. package/dist/daemon/hire-listener.d.ts.map +1 -1
  128. package/dist/daemon/hire-listener.js +47 -13
  129. package/dist/daemon/hire-listener.js.map +1 -1
  130. package/dist/daemon/index.d.ts +2 -1
  131. package/dist/daemon/index.d.ts.map +1 -1
  132. package/dist/daemon/index.js +526 -53
  133. package/dist/daemon/index.js.map +1 -1
  134. package/dist/daemon/job-lifecycle.d.ts +1 -1
  135. package/dist/daemon/job-lifecycle.d.ts.map +1 -1
  136. package/dist/daemon/job-lifecycle.js +51 -11
  137. package/dist/daemon/job-lifecycle.js.map +1 -1
  138. package/dist/daemon/notify.d.ts +1 -1
  139. package/dist/daemon/notify.d.ts.map +1 -1
  140. package/dist/daemon/notify.js +53 -19
  141. package/dist/daemon/notify.js.map +1 -1
  142. package/dist/daemon/token-metering.js +47 -8
  143. package/dist/daemon/token-metering.js.map +1 -1
  144. package/dist/daemon/userops.d.ts +2 -2
  145. package/dist/daemon/userops.d.ts.map +1 -1
  146. package/dist/daemon/userops.js +27 -23
  147. package/dist/daemon/userops.js.map +1 -1
  148. package/dist/daemon/wallet-monitor.d.ts +1 -1
  149. package/dist/daemon/wallet-monitor.d.ts.map +1 -1
  150. package/dist/daemon/wallet-monitor.js +12 -8
  151. package/dist/daemon/wallet-monitor.js.map +1 -1
  152. package/dist/daemon/worker-executor.d.ts +71 -0
  153. package/dist/daemon/worker-executor.d.ts.map +1 -0
  154. package/dist/daemon/worker-executor.js +382 -0
  155. package/dist/daemon/worker-executor.js.map +1 -0
  156. package/dist/drain-v4.js +64 -26
  157. package/dist/drain-v4.js.map +1 -1
  158. package/dist/endpoint-config.js +63 -20
  159. package/dist/endpoint-config.js.map +1 -1
  160. package/dist/endpoint-notify.js +48 -9
  161. package/dist/endpoint-notify.js.map +1 -1
  162. package/dist/index.js +50 -18
  163. package/dist/index.js.map +1 -1
  164. package/dist/openshell-runtime.d.ts.map +1 -1
  165. package/dist/openshell-runtime.js +82 -38
  166. package/dist/openshell-runtime.js.map +1 -1
  167. package/dist/program.d.ts.map +1 -1
  168. package/dist/program.js +85 -78
  169. package/dist/program.js.map +1 -1
  170. package/dist/repl.js +31 -25
  171. package/dist/repl.js.map +1 -1
  172. package/dist/signing.js +6 -3
  173. package/dist/signing.js.map +1 -1
  174. package/dist/telegram-notify.js +40 -3
  175. package/dist/telegram-notify.js.map +1 -1
  176. package/dist/tui/App.d.ts.map +1 -1
  177. package/dist/tui/App.js +56 -89
  178. package/dist/tui/App.js.map +1 -1
  179. package/dist/tui/Footer.js +7 -4
  180. package/dist/tui/Footer.js.map +1 -1
  181. package/dist/tui/Header.d.ts +1 -1
  182. package/dist/tui/Header.d.ts.map +1 -1
  183. package/dist/tui/Header.js +14 -9
  184. package/dist/tui/Header.js.map +1 -1
  185. package/dist/tui/InputLine.d.ts +2 -1
  186. package/dist/tui/InputLine.d.ts.map +1 -1
  187. package/dist/tui/InputLine.js +47 -97
  188. package/dist/tui/InputLine.js.map +1 -1
  189. package/dist/tui/Viewport.d.ts +1 -2
  190. package/dist/tui/Viewport.d.ts.map +1 -1
  191. package/dist/tui/Viewport.js +26 -6
  192. package/dist/tui/Viewport.js.map +1 -1
  193. package/dist/tui/WalletConnectPairing.js +19 -16
  194. package/dist/tui/WalletConnectPairing.js.map +1 -1
  195. package/dist/tui/components/Button.js +9 -6
  196. package/dist/tui/components/Button.js.map +1 -1
  197. package/dist/tui/components/CeremonyView.js +8 -5
  198. package/dist/tui/components/CeremonyView.js.map +1 -1
  199. package/dist/tui/components/CompletionDropdown.js +9 -6
  200. package/dist/tui/components/CompletionDropdown.js.map +1 -1
  201. package/dist/tui/components/ConfirmPrompt.js +8 -5
  202. package/dist/tui/components/ConfirmPrompt.js.map +1 -1
  203. package/dist/tui/components/CustomTextInput.js +14 -11
  204. package/dist/tui/components/CustomTextInput.js.map +1 -1
  205. package/dist/tui/components/InteractiveTable.js +12 -9
  206. package/dist/tui/components/InteractiveTable.js.map +1 -1
  207. package/dist/tui/components/StepSpinner.js +13 -10
  208. package/dist/tui/components/StepSpinner.js.map +1 -1
  209. package/dist/tui/components/Toast.js +12 -8
  210. package/dist/tui/components/Toast.js.map +1 -1
  211. package/dist/tui/index.d.ts.map +1 -1
  212. package/dist/tui/index.js +21 -28
  213. package/dist/tui/index.js.map +1 -1
  214. package/dist/tui/useChat.js +19 -13
  215. package/dist/tui/useChat.js.map +1 -1
  216. package/dist/tui/useCommand.d.ts +2 -3
  217. package/dist/tui/useCommand.d.ts.map +1 -1
  218. package/dist/tui/useCommand.js +24 -100
  219. package/dist/tui/useCommand.js.map +1 -1
  220. package/dist/tui/useNotifications.js +8 -5
  221. package/dist/tui/useNotifications.js.map +1 -1
  222. package/dist/tui/useScroll.d.ts.map +1 -1
  223. package/dist/tui/useScroll.js +12 -15
  224. package/dist/tui/useScroll.js.map +1 -1
  225. package/dist/ui/banner.d.ts +0 -12
  226. package/dist/ui/banner.d.ts.map +1 -1
  227. package/dist/ui/banner.js +19 -35
  228. package/dist/ui/banner.js.map +1 -1
  229. package/dist/ui/colors.js +19 -13
  230. package/dist/ui/colors.js.map +1 -1
  231. package/dist/ui/format.js +14 -6
  232. package/dist/ui/format.js.map +1 -1
  233. package/dist/ui/qr-render.js +11 -4
  234. package/dist/ui/qr-render.js.map +1 -1
  235. package/dist/ui/rpc-fallback.js +11 -6
  236. package/dist/ui/rpc-fallback.js.map +1 -1
  237. package/dist/ui/spinner.js +12 -6
  238. package/dist/ui/spinner.js.map +1 -1
  239. package/dist/ui/tree.js +6 -3
  240. package/dist/ui/tree.js.map +1 -1
  241. package/dist/utils/format.js +41 -27
  242. package/dist/utils/format.js.map +1 -1
  243. package/dist/utils/hash.js +42 -4
  244. package/dist/utils/hash.js.map +1 -1
  245. package/dist/utils/time.js +6 -2
  246. package/dist/utils/time.js.map +1 -1
  247. package/dist/wallet-router.d.ts +1 -1
  248. package/dist/wallet-router.d.ts.map +1 -1
  249. package/dist/wallet-router.js +19 -12
  250. package/dist/wallet-router.js.map +1 -1
  251. package/dist/walletconnect-session.d.ts +1 -1
  252. package/dist/walletconnect-session.d.ts.map +1 -1
  253. package/dist/walletconnect-session.js +11 -6
  254. package/dist/walletconnect-session.js.map +1 -1
  255. package/dist/walletconnect.d.ts +5 -6
  256. package/dist/walletconnect.d.ts.map +1 -1
  257. package/dist/walletconnect.js +35 -32
  258. package/dist/walletconnect.js.map +1 -1
  259. package/package.json +11 -10
  260. package/INK6-UX-SPEC.md +0 -446
  261. package/MIGRATION-SPEC.md +0 -108
  262. package/TUI-SPEC.md +0 -214
  263. package/scripts/authorize-machine-key.ts +0 -43
  264. package/scripts/drain-wallet.ts +0 -149
  265. package/scripts/execute-spend-only.ts +0 -81
  266. package/scripts/register-agent-userop.ts +0 -186
  267. package/src/abis.ts +0 -187
  268. package/src/bundler.ts +0 -235
  269. package/src/client.ts +0 -36
  270. package/src/coinbase-smart-wallet.ts +0 -51
  271. package/src/commands/accept.ts +0 -64
  272. package/src/commands/agent-handshake.ts +0 -72
  273. package/src/commands/agent.ts +0 -691
  274. package/src/commands/agreements.ts +0 -350
  275. package/src/commands/arbitrator.ts +0 -180
  276. package/src/commands/arena-handshake.ts +0 -274
  277. package/src/commands/arena.ts +0 -122
  278. package/src/commands/backup.ts +0 -117
  279. package/src/commands/cancel.ts +0 -35
  280. package/src/commands/channel.ts +0 -218
  281. package/src/commands/coldstart.ts +0 -165
  282. package/src/commands/config.ts +0 -68
  283. package/src/commands/contract-interaction.ts +0 -166
  284. package/src/commands/daemon.ts +0 -1054
  285. package/src/commands/deliver.ts +0 -148
  286. package/src/commands/discover.ts +0 -350
  287. package/src/commands/dispute.ts +0 -375
  288. package/src/commands/doctor.ts +0 -172
  289. package/src/commands/endpoint.ts +0 -620
  290. package/src/commands/feed.ts +0 -229
  291. package/src/commands/hire.ts +0 -245
  292. package/src/commands/migrate.ts +0 -177
  293. package/src/commands/negotiate.ts +0 -272
  294. package/src/commands/openshell.ts +0 -1055
  295. package/src/commands/owner.ts +0 -35
  296. package/src/commands/policy.ts +0 -263
  297. package/src/commands/relay.ts +0 -277
  298. package/src/commands/remediate.ts +0 -24
  299. package/src/commands/reputation.ts +0 -79
  300. package/src/commands/setup.ts +0 -343
  301. package/src/commands/trust.ts +0 -27
  302. package/src/commands/verify.ts +0 -91
  303. package/src/commands/wallet.ts +0 -3548
  304. package/src/commands/watch.ts +0 -220
  305. package/src/commands/watchtower.ts +0 -248
  306. package/src/commands/workroom.ts +0 -963
  307. package/src/config.ts +0 -220
  308. package/src/daemon/config.ts +0 -344
  309. package/src/daemon/hire-listener.ts +0 -226
  310. package/src/daemon/index.ts +0 -1089
  311. package/src/daemon/job-lifecycle.ts +0 -215
  312. package/src/daemon/notify.ts +0 -297
  313. package/src/daemon/token-metering.ts +0 -183
  314. package/src/daemon/userops.ts +0 -119
  315. package/src/daemon/wallet-monitor.ts +0 -90
  316. package/src/drain-v4.ts +0 -159
  317. package/src/endpoint-config.ts +0 -83
  318. package/src/endpoint-notify.ts +0 -129
  319. package/src/index.ts +0 -74
  320. package/src/openshell-runtime.ts +0 -281
  321. package/src/program.ts +0 -88
  322. package/src/repl.ts +0 -178
  323. package/src/signing.ts +0 -28
  324. package/src/telegram-notify.ts +0 -88
  325. package/src/tui/App.tsx +0 -263
  326. package/src/tui/Footer.tsx +0 -18
  327. package/src/tui/Header.tsx +0 -45
  328. package/src/tui/InputLine.tsx +0 -243
  329. package/src/tui/Viewport.tsx +0 -51
  330. package/src/tui/WalletConnectPairing.tsx +0 -114
  331. package/src/tui/components/Button.tsx +0 -38
  332. package/src/tui/components/CeremonyView.tsx +0 -39
  333. package/src/tui/components/CompletionDropdown.tsx +0 -56
  334. package/src/tui/components/ConfirmPrompt.tsx +0 -36
  335. package/src/tui/components/CustomTextInput.tsx +0 -132
  336. package/src/tui/components/InteractiveTable.tsx +0 -106
  337. package/src/tui/components/StepSpinner.tsx +0 -84
  338. package/src/tui/components/Toast.tsx +0 -59
  339. package/src/tui/index.tsx +0 -90
  340. package/src/tui/useChat.ts +0 -103
  341. package/src/tui/useCommand.ts +0 -238
  342. package/src/tui/useNotifications.ts +0 -28
  343. package/src/tui/useScroll.ts +0 -69
  344. package/src/ui/banner.ts +0 -78
  345. package/src/ui/colors.ts +0 -30
  346. package/src/ui/format.ts +0 -78
  347. package/src/ui/qr-render.ts +0 -92
  348. package/src/ui/rpc-fallback.ts +0 -59
  349. package/src/ui/spinner.ts +0 -56
  350. package/src/ui/tree.ts +0 -16
  351. package/src/utils/format.ts +0 -48
  352. package/src/utils/hash.ts +0 -5
  353. package/src/utils/time.ts +0 -15
  354. package/src/wallet-router.ts +0 -178
  355. package/src/walletconnect-session.ts +0 -27
  356. package/src/walletconnect.ts +0 -309
  357. package/test/time.test.js +0 -11
  358. package/tsconfig.json +0 -33
package/src/tui/App.tsx DELETED
@@ -1,263 +0,0 @@
1
- import React, { useState, useCallback, useEffect, useRef } from "react";
2
- import { createRequire } from "node:module";
3
- import { Box, Text, useApp, useInput, useStdout } from "ink";
4
- import { Header } from "./Header.js";
5
- import { Viewport } from "./Viewport.js";
6
- import { Footer } from "./Footer.js";
7
- import { InputLine } from "./InputLine.js";
8
- import { useCommand } from "./useCommand.js";
9
- import { useChat } from "./useChat.js";
10
- import { useScroll } from "./useScroll.js";
11
- import { useNotifications } from "./useNotifications.js";
12
- import { ToastContainer } from "./components/Toast.js";
13
- import { createProgram } from "../program.js";
14
- import chalk from "chalk";
15
-
16
- const pkg = createRequire(import.meta.url)("../../package.json") as { version: string };
17
-
18
- const BUILTIN_CMDS = ["help", "exit", "quit", "clear", "status"];
19
-
20
- interface AppProps {
21
- version: string;
22
- network?: string;
23
- wallet?: string;
24
- balance?: string;
25
- }
26
-
27
- /**
28
- * Root TUI component — fixed header/footer with scrollable viewport.
29
- */
30
- export function App({ version, network, wallet, balance }: AppProps) {
31
- const { exit } = useApp();
32
-
33
- const { stdout } = useStdout();
34
-
35
- const [outputBuffer, setOutputBuffer] = useState<string[]>([
36
- chalk.dim(" Type 'help' to see available commands"),
37
- "",
38
- ]);
39
- const [isProcessing, setIsProcessing] = useState(false);
40
-
41
- const { execute, isRunning } = useCommand();
42
- const { send, isSending } = useChat();
43
-
44
- // Compute viewport height from actual fixed rows:
45
- // Header: 6 (art) + 1 (blank) + 1 (subtitle) + 1 (separator) = 9
46
- // + 1 status line if any status items present
47
- // App chrome: 1 (top separator) + 1 (bottom separator) + 1 (input line) = 3
48
- const rows = stdout?.rows ?? process.stdout.rows ?? 24;
49
- const hasStatus = !!(network || wallet || balance);
50
- const headerRows = 9 + (hasStatus ? 1 : 0);
51
- const chromeRows = 3; // top separator + bottom separator + input line
52
- const viewportHeight = Math.max(1, rows - headerRows - chromeRows);
53
-
54
- const { scrollOffset, isAutoScroll, scrollUp, scrollDown, snapToBottom } =
55
- useScroll(viewportHeight);
56
-
57
- const { toasts, dismiss: dismissToast } = useNotifications();
58
-
59
- // Get top-level command names for dispatch detection
60
- const [topCmds] = useState<string[]>(() => {
61
- try {
62
- const prog = createProgram();
63
- return prog.commands.map((cmd) => cmd.name());
64
- } catch {
65
- return [];
66
- }
67
- });
68
-
69
- // ── Enhanced keyboard shortcuts ────────────────────────────────────────
70
- useInput((input, key) => {
71
- // Ctrl+L — clear viewport
72
- if (key.ctrl && input === "l") {
73
- setOutputBuffer([]);
74
- return;
75
- }
76
- // Escape — cancel / clear (snap to bottom if scrolled)
77
- if (key.escape) {
78
- snapToBottom();
79
- return;
80
- }
81
- });
82
-
83
- // ── Batched line appender ─────────────────────────────────────────────────
84
- // Accumulate lines in a ref and flush once per microtask so that rapid
85
- // onLine() calls (stdout monkey-patch, child-process pipe) produce a
86
- // single React state update instead of one re-render per line.
87
- const pendingLines = useRef<string[]>([]);
88
- const flushScheduled = useRef(false);
89
-
90
- const appendLine = useCallback((line: string) => {
91
- pendingLines.current.push(line);
92
- if (!flushScheduled.current) {
93
- flushScheduled.current = true;
94
- queueMicrotask(() => {
95
- const batch = pendingLines.current;
96
- pendingLines.current = [];
97
- flushScheduled.current = false;
98
- if (batch.length > 0) {
99
- setOutputBuffer((prev) => [...prev, ...batch]);
100
- }
101
- });
102
- }
103
- }, []);
104
-
105
- const handleCommand = useCallback(
106
- async (input: string): Promise<void> => {
107
- // Echo command to viewport
108
- appendLine(
109
- chalk.cyanBright("◈") +
110
- " " +
111
- chalk.dim("arc402") +
112
- " " +
113
- chalk.white(">") +
114
- " " +
115
- chalk.white(input)
116
- );
117
-
118
- // Snap to bottom on new command
119
- snapToBottom();
120
- setIsProcessing(true);
121
-
122
- const firstWord = input.split(/\s+/)[0];
123
- const allKnown = [...BUILTIN_CMDS, ...topCmds];
124
-
125
- // ── Built-in: exit/quit ────────────────────────────────────────────────
126
- if (input === "exit" || input === "quit") {
127
- appendLine(
128
- " " + chalk.cyanBright("◈") + chalk.dim(" goodbye")
129
- );
130
- setIsProcessing(false);
131
- setTimeout(() => exit(), 100);
132
- return;
133
- }
134
-
135
- // ── Built-in: clear ────────────────────────────────────────────────────
136
- if (input === "clear") {
137
- setOutputBuffer([]);
138
- setIsProcessing(false);
139
- return;
140
- }
141
-
142
- // ── Built-in: help ─────────────────────────────────────────────────────
143
- if (input === "help" || input === "/help") {
144
- const lines: string[] = [];
145
- try {
146
- const prog = createProgram();
147
- prog.exitOverride();
148
- const helpText: string[] = [];
149
- prog.configureOutput({
150
- writeOut: (str) => helpText.push(str),
151
- writeErr: (str) => helpText.push(str),
152
- });
153
- try {
154
- await prog.parseAsync(["node", "arc402", "--help"]);
155
- } catch {
156
- /* commander throws after printing help */
157
- }
158
- for (const chunk of helpText) {
159
- for (const l of chunk.split("\n")) lines.push(l);
160
- }
161
- } catch {
162
- lines.push(chalk.red("Failed to load help"));
163
- }
164
- lines.push("");
165
- lines.push(chalk.cyanBright("Chat"));
166
- lines.push(
167
- " " +
168
- chalk.white("<message>") +
169
- chalk.dim(" Send message to OpenClaw gateway")
170
- );
171
- lines.push(
172
- " " +
173
- chalk.white("/chat <message>") +
174
- chalk.dim(" Explicitly route to chat")
175
- );
176
- lines.push(
177
- chalk.dim(
178
- " Gateway: http://localhost:19000 (openclaw gateway start)"
179
- )
180
- );
181
- lines.push("");
182
- for (const l of lines) appendLine(l);
183
- setIsProcessing(false);
184
- return;
185
- }
186
-
187
- // ── Built-in: status ───────────────────────────────────────────────────
188
- if (input === "status") {
189
- if (network)
190
- appendLine(
191
- ` ${chalk.dim("Network")} ${chalk.white(network)}`
192
- );
193
- if (wallet)
194
- appendLine(` ${chalk.dim("Wallet")} ${chalk.white(wallet)}`);
195
- if (balance)
196
- appendLine(` ${chalk.dim("Balance")} ${chalk.white(balance)}`);
197
- if (!network && !wallet && !balance)
198
- appendLine(chalk.dim(" No config found. Run 'config init' to get started."));
199
- appendLine("");
200
- setIsProcessing(false);
201
- return;
202
- }
203
-
204
- // ── /chat prefix or unknown command → chat ─────────────────────────────
205
- const isExplicitChat = input.startsWith("/chat ");
206
- const isChatInput =
207
- isExplicitChat || (!allKnown.includes(firstWord) && firstWord !== "");
208
-
209
- if (isChatInput) {
210
- const msg = isExplicitChat ? input.slice(6).trim() : input;
211
- if (msg) {
212
- await send(msg, appendLine);
213
- }
214
- appendLine("");
215
- setIsProcessing(false);
216
- return;
217
- }
218
-
219
- // ── Dispatch to commander ──────────────────────────────────────────────
220
- await execute(input, appendLine);
221
- appendLine("");
222
- setIsProcessing(false);
223
- },
224
- [appendLine, execute, send, snapToBottom, topCmds, network, wallet, balance, exit]
225
- );
226
-
227
- const isDisabled = isProcessing || isRunning || isSending;
228
-
229
- const cols = Math.min(stdout?.columns ?? process.stdout.columns ?? 80, 120);
230
-
231
- return (
232
- <Box flexDirection="column" height="100%">
233
- {/* BANNER — memoized, participates in flex layout */}
234
- <Header version={version} network={network} wallet={wallet} balance={balance} />
235
-
236
- {/* Separator */}
237
- <Box flexShrink={0}>
238
- <Text dimColor>{"─".repeat(cols)}</Text>
239
- </Box>
240
-
241
- {/* VIEWPORT — fills remaining space */}
242
- <Viewport
243
- lines={outputBuffer}
244
- scrollOffset={scrollOffset}
245
- isAutoScroll={isAutoScroll}
246
- height={viewportHeight}
247
- />
248
-
249
- {/* Notification toasts — above footer */}
250
- <ToastContainer toasts={toasts} onDismiss={dismissToast} />
251
-
252
- {/* Bottom separator */}
253
- <Box flexShrink={0}>
254
- <Text dimColor>{"─".repeat(cols)}</Text>
255
- </Box>
256
-
257
- {/* FOOTER — fixed, input pinned */}
258
- <Footer>
259
- <InputLine onSubmit={handleCommand} isDisabled={isDisabled} />
260
- </Footer>
261
- </Box>
262
- );
263
- }
@@ -1,18 +0,0 @@
1
- import React from "react";
2
- import { Box } from "ink";
3
-
4
- interface FooterProps {
5
- children: React.ReactNode;
6
- }
7
-
8
- /**
9
- * Fixed footer containing the input line.
10
- * Pinned at the bottom of the screen.
11
- */
12
- export function Footer({ children }: FooterProps) {
13
- return (
14
- <Box flexShrink={0}>
15
- {children}
16
- </Box>
17
- );
18
- }
@@ -1,45 +0,0 @@
1
- import React from "react";
2
- import { Box, Text } from "ink";
3
- import { getBannerArt, getStatusItems } from "../ui/banner.js";
4
- import type { BannerConfig } from "../ui/banner.js";
5
-
6
- interface HeaderProps {
7
- version: string;
8
- network?: string;
9
- wallet?: string;
10
- balance?: string;
11
- }
12
-
13
- /**
14
- * Fixed header showing the ASCII art banner + status info.
15
- * Status items use flexWrap to adapt to narrow terminals.
16
- */
17
- export const Header = React.memo(function Header({
18
- network,
19
- wallet,
20
- balance,
21
- }: HeaderProps) {
22
- const { artLines, subtitle, separator } = getBannerArt();
23
- const statusItems = getStatusItems({ network, wallet, balance });
24
-
25
- return (
26
- <Box flexDirection="column" flexShrink={0}>
27
- {artLines.map((line, i) => (
28
- <Text key={i}>{line}</Text>
29
- ))}
30
- <Text> </Text>
31
- <Text>{subtitle}</Text>
32
- <Text>{separator}</Text>
33
- {statusItems.length > 0 && (
34
- <Box flexWrap="wrap" columnGap={2}>
35
- {statusItems.map((item) => (
36
- <Box key={item.label}>
37
- <Text dimColor>{item.label}</Text>
38
- <Text>{" "}{item.value}</Text>
39
- </Box>
40
- ))}
41
- </Box>
42
- )}
43
- </Box>
44
- );
45
- });
@@ -1,243 +0,0 @@
1
- import React, { useState, useCallback, useMemo } from "react";
2
- import { Box, Text, useInput } from "ink";
3
- import { CustomTextInput } from "./components/CustomTextInput.js";
4
- import { createProgram } from "../program.js";
5
- import { CompletionDropdown } from "./components/CompletionDropdown.js";
6
-
7
- const BUILTIN_CMDS = ["help", "exit", "quit", "clear", "status"];
8
-
9
- interface InputLineProps {
10
- onSubmit: (value: string) => void;
11
- isDisabled?: boolean;
12
- }
13
-
14
- /**
15
- * Input line with command history navigation, tab completion, and dropdown.
16
- */
17
- export function InputLine({ onSubmit, isDisabled = false }: InputLineProps) {
18
- const [value, setValue] = useState("");
19
- const [history, setHistory] = useState<string[]>([]);
20
- const [historyIdx, setHistoryIdx] = useState(-1);
21
- const [historyTemp, setHistoryTemp] = useState("");
22
-
23
- // Dropdown state
24
- const [showDropdown, setShowDropdown] = useState(false);
25
- const [dropdownIdx, setDropdownIdx] = useState(0);
26
- const [dropdownCandidates, setDropdownCandidates] = useState<string[]>([]);
27
-
28
- // Lazily build command list for tab completion
29
- const [topCmds] = useState<string[]>(() => {
30
- try {
31
- const prog = createProgram();
32
- return prog.commands.map((cmd) => cmd.name());
33
- } catch {
34
- return [];
35
- }
36
- });
37
- const [subCmds] = useState<Map<string, string[]>>(() => {
38
- try {
39
- const prog = createProgram();
40
- const map = new Map<string, string[]>();
41
- for (const cmd of prog.commands) {
42
- if (cmd.commands.length > 0) {
43
- map.set(cmd.name(), cmd.commands.map((s) => s.name()));
44
- }
45
- }
46
- return map;
47
- } catch {
48
- return new Map();
49
- }
50
- });
51
-
52
- const getCompletions = useCallback(
53
- (input: string): string[] => {
54
- const allTop = [...BUILTIN_CMDS, ...topCmds];
55
- const trimmed = input.trimStart();
56
- const spaceIdx = trimmed.indexOf(" ");
57
-
58
- if (spaceIdx === -1) {
59
- return allTop.filter((cmd) => cmd.startsWith(trimmed));
60
- }
61
- const parent = trimmed.slice(0, spaceIdx);
62
- const rest = trimmed.slice(spaceIdx + 1);
63
- const subs = subCmds.get(parent) ?? [];
64
- return subs
65
- .filter((s) => s.startsWith(rest))
66
- .map((s) => `${parent} ${s}`);
67
- },
68
- [topCmds, subCmds]
69
- );
70
-
71
- const handleSubmit = useCallback(
72
- (val: string) => {
73
- const trimmed = val.trim();
74
- if (!trimmed) return;
75
-
76
- setHistory((prev) => {
77
- if (prev[prev.length - 1] === trimmed) return prev;
78
- return [...prev, trimmed];
79
- });
80
- setHistoryIdx(-1);
81
- setHistoryTemp("");
82
- setValue("");
83
- setShowDropdown(false);
84
-
85
- onSubmit(trimmed);
86
- },
87
- [onSubmit]
88
- );
89
-
90
- useInput(
91
- (_input, key) => {
92
- if (isDisabled) return;
93
-
94
- // ── Dropdown navigation ───────────────────────────────────────────
95
- if (showDropdown) {
96
- if (key.upArrow) {
97
- setDropdownIdx((i) => Math.max(0, i - 1));
98
- return;
99
- }
100
- if (key.downArrow) {
101
- setDropdownIdx((i) =>
102
- Math.min(dropdownCandidates.length - 1, i + 1)
103
- );
104
- return;
105
- }
106
- if (key.return) {
107
- // Select the highlighted candidate
108
- if (dropdownCandidates[dropdownIdx]) {
109
- setValue(dropdownCandidates[dropdownIdx] + " ");
110
- }
111
- setShowDropdown(false);
112
- return;
113
- }
114
- if (key.escape) {
115
- setShowDropdown(false);
116
- return;
117
- }
118
- }
119
-
120
- // ── History navigation ────────────────────────────────────────────
121
- if (key.upArrow) {
122
- setHistory((hist) => {
123
- setHistoryIdx((idx) => {
124
- if (idx === -1) {
125
- setHistoryTemp(value);
126
- const newIdx = hist.length - 1;
127
- if (newIdx >= 0) setValue(hist[newIdx]);
128
- return newIdx;
129
- } else if (idx > 0) {
130
- const newIdx = idx - 1;
131
- setValue(hist[newIdx]);
132
- return newIdx;
133
- }
134
- return idx;
135
- });
136
- return hist;
137
- });
138
- return;
139
- }
140
-
141
- if (key.downArrow) {
142
- setHistory((hist) => {
143
- setHistoryIdx((idx) => {
144
- if (idx >= 0) {
145
- const newIdx = idx + 1;
146
- if (newIdx >= hist.length) {
147
- setValue(historyTemp);
148
- return -1;
149
- } else {
150
- setValue(hist[newIdx]);
151
- return newIdx;
152
- }
153
- }
154
- return idx;
155
- });
156
- return hist;
157
- });
158
- return;
159
- }
160
-
161
- // ── Tab — completion / dropdown ───────────────────────────────────
162
- if (key.tab) {
163
- const completions = getCompletions(value);
164
-
165
- if (completions.length === 0) {
166
- setShowDropdown(false);
167
- return;
168
- }
169
-
170
- if (completions.length === 1) {
171
- setValue(completions[0] + " ");
172
- setShowDropdown(false);
173
- return;
174
- }
175
-
176
- // Show dropdown with multiple candidates
177
- setDropdownCandidates(completions);
178
- setDropdownIdx(0);
179
- setShowDropdown(true);
180
-
181
- // Also advance to common prefix
182
- const common = completions.reduce((a, b) => {
183
- let i = 0;
184
- while (i < a.length && i < b.length && a[i] === b[i]) i++;
185
- return a.slice(0, i);
186
- });
187
- if (common.length > value.trimStart().length) {
188
- setValue(common);
189
- }
190
- }
191
-
192
- // ── Escape — dismiss dropdown ─────────────────────────────────────
193
- if (key.escape) {
194
- setShowDropdown(false);
195
- }
196
- },
197
- { isActive: !isDisabled }
198
- );
199
-
200
- // Auto-show completions as user types (no Tab needed)
201
- const handleChange = useCallback(
202
- (newVal: string) => {
203
- setValue(newVal);
204
- const trimmed = newVal.trimStart();
205
- if (trimmed.length >= 2) {
206
- const completions = getCompletions(newVal);
207
- if (completions.length > 1) {
208
- setDropdownCandidates(completions);
209
- setDropdownIdx(0);
210
- setShowDropdown(true);
211
- } else {
212
- setShowDropdown(false);
213
- }
214
- } else {
215
- setShowDropdown(false);
216
- }
217
- },
218
- [getCompletions]
219
- );
220
-
221
- return (
222
- <Box flexDirection="column">
223
- {/* Completion dropdown renders above the input */}
224
- <CompletionDropdown
225
- candidates={dropdownCandidates}
226
- selectedIndex={dropdownIdx}
227
- visible={showDropdown}
228
- />
229
- <Box>
230
- <Text color="cyan">◈</Text>
231
- <Text dimColor> arc402 </Text>
232
- <Text color="white">{">"} </Text>
233
- <CustomTextInput
234
- value={value}
235
- onChange={handleChange}
236
- onSubmit={handleSubmit}
237
- focus={!isDisabled}
238
- suppressEnter={showDropdown}
239
- />
240
- </Box>
241
- </Box>
242
- );
243
- }
@@ -1,51 +0,0 @@
1
- import React from "react";
2
- import { Box, Text } from "ink";
3
-
4
- interface ViewportProps {
5
- lines: string[];
6
- scrollOffset: number;
7
- isAutoScroll: boolean;
8
- height: number;
9
- }
10
-
11
- /**
12
- * Scrollable output area that fills remaining terminal space.
13
- * Renders a window slice of the buffer, not terminal scroll.
14
- * scrollOffset=0 means pinned to bottom (auto-scroll).
15
- * Positive scrollOffset means scrolled up by that many lines.
16
- */
17
- export function Viewport({ lines, scrollOffset, isAutoScroll, height }: ViewportProps) {
18
- const viewportHeight = Math.max(1, height);
19
-
20
- // Compute the window slice
21
- const totalLines = lines.length;
22
- let endIdx: number;
23
- let startIdx: number;
24
-
25
- if (scrollOffset === 0) {
26
- endIdx = totalLines;
27
- startIdx = Math.max(0, endIdx - viewportHeight);
28
- } else {
29
- endIdx = Math.max(0, totalLines - scrollOffset);
30
- startIdx = Math.max(0, endIdx - viewportHeight);
31
- }
32
-
33
- const visibleLines = lines.slice(startIdx, endIdx);
34
-
35
- const canScrollUp = startIdx > 0;
36
- const canScrollDown = scrollOffset > 0;
37
-
38
- return (
39
- <Box flexDirection="column" flexGrow={1}>
40
- {canScrollUp && (
41
- <Text dimColor>{" \u2191 more (Shift+Up)"}</Text>
42
- )}
43
- {visibleLines.map((line, i) => (
44
- <Text key={startIdx + i}>{line}</Text>
45
- ))}
46
- {canScrollDown && !isAutoScroll && (
47
- <Text dimColor>{" \u2193 more (Shift+Down / Esc)"}</Text>
48
- )}
49
- </Box>
50
- );
51
- }