arc402-cli 0.9.19 → 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 (359) 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.d.ts.map +1 -1
  161. package/dist/endpoint-notify.js +49 -15
  162. package/dist/endpoint-notify.js.map +1 -1
  163. package/dist/index.js +50 -18
  164. package/dist/index.js.map +1 -1
  165. package/dist/openshell-runtime.d.ts.map +1 -1
  166. package/dist/openshell-runtime.js +82 -38
  167. package/dist/openshell-runtime.js.map +1 -1
  168. package/dist/program.d.ts.map +1 -1
  169. package/dist/program.js +85 -78
  170. package/dist/program.js.map +1 -1
  171. package/dist/repl.js +31 -25
  172. package/dist/repl.js.map +1 -1
  173. package/dist/signing.js +6 -3
  174. package/dist/signing.js.map +1 -1
  175. package/dist/telegram-notify.js +40 -3
  176. package/dist/telegram-notify.js.map +1 -1
  177. package/dist/tui/App.d.ts.map +1 -1
  178. package/dist/tui/App.js +56 -89
  179. package/dist/tui/App.js.map +1 -1
  180. package/dist/tui/Footer.js +7 -4
  181. package/dist/tui/Footer.js.map +1 -1
  182. package/dist/tui/Header.d.ts +1 -1
  183. package/dist/tui/Header.d.ts.map +1 -1
  184. package/dist/tui/Header.js +14 -9
  185. package/dist/tui/Header.js.map +1 -1
  186. package/dist/tui/InputLine.d.ts +2 -1
  187. package/dist/tui/InputLine.d.ts.map +1 -1
  188. package/dist/tui/InputLine.js +47 -97
  189. package/dist/tui/InputLine.js.map +1 -1
  190. package/dist/tui/Viewport.d.ts +1 -2
  191. package/dist/tui/Viewport.d.ts.map +1 -1
  192. package/dist/tui/Viewport.js +26 -6
  193. package/dist/tui/Viewport.js.map +1 -1
  194. package/dist/tui/WalletConnectPairing.js +19 -16
  195. package/dist/tui/WalletConnectPairing.js.map +1 -1
  196. package/dist/tui/components/Button.js +9 -6
  197. package/dist/tui/components/Button.js.map +1 -1
  198. package/dist/tui/components/CeremonyView.js +8 -5
  199. package/dist/tui/components/CeremonyView.js.map +1 -1
  200. package/dist/tui/components/CompletionDropdown.js +9 -6
  201. package/dist/tui/components/CompletionDropdown.js.map +1 -1
  202. package/dist/tui/components/ConfirmPrompt.js +8 -5
  203. package/dist/tui/components/ConfirmPrompt.js.map +1 -1
  204. package/dist/tui/components/CustomTextInput.js +14 -11
  205. package/dist/tui/components/CustomTextInput.js.map +1 -1
  206. package/dist/tui/components/InteractiveTable.js +12 -9
  207. package/dist/tui/components/InteractiveTable.js.map +1 -1
  208. package/dist/tui/components/StepSpinner.js +13 -10
  209. package/dist/tui/components/StepSpinner.js.map +1 -1
  210. package/dist/tui/components/Toast.js +12 -8
  211. package/dist/tui/components/Toast.js.map +1 -1
  212. package/dist/tui/index.d.ts.map +1 -1
  213. package/dist/tui/index.js +21 -28
  214. package/dist/tui/index.js.map +1 -1
  215. package/dist/tui/useChat.js +19 -13
  216. package/dist/tui/useChat.js.map +1 -1
  217. package/dist/tui/useCommand.d.ts +2 -3
  218. package/dist/tui/useCommand.d.ts.map +1 -1
  219. package/dist/tui/useCommand.js +24 -100
  220. package/dist/tui/useCommand.js.map +1 -1
  221. package/dist/tui/useNotifications.js +8 -5
  222. package/dist/tui/useNotifications.js.map +1 -1
  223. package/dist/tui/useScroll.d.ts.map +1 -1
  224. package/dist/tui/useScroll.js +12 -15
  225. package/dist/tui/useScroll.js.map +1 -1
  226. package/dist/ui/banner.d.ts +0 -12
  227. package/dist/ui/banner.d.ts.map +1 -1
  228. package/dist/ui/banner.js +19 -35
  229. package/dist/ui/banner.js.map +1 -1
  230. package/dist/ui/colors.js +19 -13
  231. package/dist/ui/colors.js.map +1 -1
  232. package/dist/ui/format.js +14 -6
  233. package/dist/ui/format.js.map +1 -1
  234. package/dist/ui/qr-render.js +11 -4
  235. package/dist/ui/qr-render.js.map +1 -1
  236. package/dist/ui/rpc-fallback.js +11 -6
  237. package/dist/ui/rpc-fallback.js.map +1 -1
  238. package/dist/ui/spinner.js +12 -6
  239. package/dist/ui/spinner.js.map +1 -1
  240. package/dist/ui/tree.js +6 -3
  241. package/dist/ui/tree.js.map +1 -1
  242. package/dist/utils/format.js +41 -27
  243. package/dist/utils/format.js.map +1 -1
  244. package/dist/utils/hash.js +42 -4
  245. package/dist/utils/hash.js.map +1 -1
  246. package/dist/utils/time.js +6 -2
  247. package/dist/utils/time.js.map +1 -1
  248. package/dist/wallet-router.d.ts +1 -1
  249. package/dist/wallet-router.d.ts.map +1 -1
  250. package/dist/wallet-router.js +19 -12
  251. package/dist/wallet-router.js.map +1 -1
  252. package/dist/walletconnect-session.d.ts +1 -1
  253. package/dist/walletconnect-session.d.ts.map +1 -1
  254. package/dist/walletconnect-session.js +11 -6
  255. package/dist/walletconnect-session.js.map +1 -1
  256. package/dist/walletconnect.d.ts +5 -6
  257. package/dist/walletconnect.d.ts.map +1 -1
  258. package/dist/walletconnect.js +35 -32
  259. package/dist/walletconnect.js.map +1 -1
  260. package/package.json +11 -10
  261. package/INK6-UX-SPEC.md +0 -446
  262. package/MIGRATION-SPEC.md +0 -108
  263. package/TUI-SPEC.md +0 -214
  264. package/scripts/authorize-machine-key.ts +0 -43
  265. package/scripts/drain-wallet.ts +0 -149
  266. package/scripts/execute-spend-only.ts +0 -81
  267. package/scripts/register-agent-userop.ts +0 -186
  268. package/src/abis.ts +0 -187
  269. package/src/bundler.ts +0 -235
  270. package/src/client.ts +0 -36
  271. package/src/coinbase-smart-wallet.ts +0 -51
  272. package/src/commands/accept.ts +0 -64
  273. package/src/commands/agent-handshake.ts +0 -72
  274. package/src/commands/agent.ts +0 -691
  275. package/src/commands/agreements.ts +0 -350
  276. package/src/commands/arbitrator.ts +0 -180
  277. package/src/commands/arena-handshake.ts +0 -274
  278. package/src/commands/arena.ts +0 -122
  279. package/src/commands/backup.ts +0 -117
  280. package/src/commands/cancel.ts +0 -35
  281. package/src/commands/channel.ts +0 -218
  282. package/src/commands/coldstart.ts +0 -165
  283. package/src/commands/config.ts +0 -68
  284. package/src/commands/contract-interaction.ts +0 -166
  285. package/src/commands/daemon.ts +0 -1054
  286. package/src/commands/deliver.ts +0 -148
  287. package/src/commands/discover.ts +0 -350
  288. package/src/commands/dispute.ts +0 -375
  289. package/src/commands/doctor.ts +0 -172
  290. package/src/commands/endpoint.ts +0 -620
  291. package/src/commands/feed.ts +0 -229
  292. package/src/commands/hire.ts +0 -245
  293. package/src/commands/migrate.ts +0 -177
  294. package/src/commands/negotiate.ts +0 -272
  295. package/src/commands/openshell.ts +0 -1055
  296. package/src/commands/owner.ts +0 -35
  297. package/src/commands/policy.ts +0 -263
  298. package/src/commands/relay.ts +0 -277
  299. package/src/commands/remediate.ts +0 -24
  300. package/src/commands/reputation.ts +0 -79
  301. package/src/commands/setup.ts +0 -343
  302. package/src/commands/trust.ts +0 -27
  303. package/src/commands/verify.ts +0 -91
  304. package/src/commands/wallet.ts +0 -3548
  305. package/src/commands/watch.ts +0 -220
  306. package/src/commands/watchtower.ts +0 -248
  307. package/src/commands/workroom.ts +0 -963
  308. package/src/config.ts +0 -220
  309. package/src/daemon/config.ts +0 -344
  310. package/src/daemon/hire-listener.ts +0 -226
  311. package/src/daemon/index.ts +0 -1089
  312. package/src/daemon/job-lifecycle.ts +0 -215
  313. package/src/daemon/notify.ts +0 -297
  314. package/src/daemon/token-metering.ts +0 -183
  315. package/src/daemon/userops.ts +0 -119
  316. package/src/daemon/wallet-monitor.ts +0 -90
  317. package/src/drain-v4.ts +0 -159
  318. package/src/endpoint-config.ts +0 -83
  319. package/src/endpoint-notify.ts +0 -134
  320. package/src/index.ts +0 -74
  321. package/src/openshell-runtime.ts +0 -281
  322. package/src/program.ts +0 -88
  323. package/src/repl.ts +0 -178
  324. package/src/signing.ts +0 -28
  325. package/src/telegram-notify.ts +0 -88
  326. package/src/tui/App.tsx +0 -263
  327. package/src/tui/Footer.tsx +0 -18
  328. package/src/tui/Header.tsx +0 -45
  329. package/src/tui/InputLine.tsx +0 -243
  330. package/src/tui/Viewport.tsx +0 -51
  331. package/src/tui/WalletConnectPairing.tsx +0 -114
  332. package/src/tui/components/Button.tsx +0 -38
  333. package/src/tui/components/CeremonyView.tsx +0 -39
  334. package/src/tui/components/CompletionDropdown.tsx +0 -56
  335. package/src/tui/components/ConfirmPrompt.tsx +0 -36
  336. package/src/tui/components/CustomTextInput.tsx +0 -132
  337. package/src/tui/components/InteractiveTable.tsx +0 -106
  338. package/src/tui/components/StepSpinner.tsx +0 -84
  339. package/src/tui/components/Toast.tsx +0 -59
  340. package/src/tui/index.tsx +0 -90
  341. package/src/tui/useChat.ts +0 -103
  342. package/src/tui/useCommand.ts +0 -238
  343. package/src/tui/useNotifications.ts +0 -28
  344. package/src/tui/useScroll.ts +0 -69
  345. package/src/ui/banner.ts +0 -78
  346. package/src/ui/colors.ts +0 -30
  347. package/src/ui/format.ts +0 -78
  348. package/src/ui/qr-render.ts +0 -92
  349. package/src/ui/rpc-fallback.ts +0 -59
  350. package/src/ui/spinner.ts +0 -56
  351. package/src/ui/tree.ts +0 -16
  352. package/src/utils/format.ts +0 -48
  353. package/src/utils/hash.ts +0 -5
  354. package/src/utils/time.ts +0 -15
  355. package/src/wallet-router.ts +0 -178
  356. package/src/walletconnect-session.ts +0 -27
  357. package/src/walletconnect.ts +0 -309
  358. package/test/time.test.js +0 -11
  359. 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
- }