arc402-cli 1.0.0-rc.1 → 1.1.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 (257) hide show
  1. package/README.md +43 -2
  2. package/dist/abis.d.ts +1 -0
  3. package/dist/abis.d.ts.map +1 -1
  4. package/dist/abis.js +29 -1
  5. package/dist/abis.js.map +1 -1
  6. package/dist/commands/backup.d.ts +3 -0
  7. package/dist/commands/backup.d.ts.map +1 -0
  8. package/dist/commands/backup.js +106 -0
  9. package/dist/commands/backup.js.map +1 -0
  10. package/dist/commands/compute.d.ts +14 -0
  11. package/dist/commands/compute.d.ts.map +1 -0
  12. package/dist/commands/compute.js +466 -0
  13. package/dist/commands/compute.js.map +1 -0
  14. package/dist/commands/config.d.ts.map +1 -1
  15. package/dist/commands/config.js +11 -1
  16. package/dist/commands/config.js.map +1 -1
  17. package/dist/commands/daemon.d.ts.map +1 -1
  18. package/dist/commands/daemon.js +67 -0
  19. package/dist/commands/daemon.js.map +1 -1
  20. package/dist/commands/discover.d.ts.map +1 -1
  21. package/dist/commands/discover.js +60 -15
  22. package/dist/commands/discover.js.map +1 -1
  23. package/dist/commands/doctor.d.ts +3 -0
  24. package/dist/commands/doctor.d.ts.map +1 -0
  25. package/dist/commands/doctor.js +205 -0
  26. package/dist/commands/doctor.js.map +1 -0
  27. package/dist/commands/tunnel.d.ts +3 -0
  28. package/dist/commands/tunnel.d.ts.map +1 -0
  29. package/dist/commands/tunnel.js +281 -0
  30. package/dist/commands/tunnel.js.map +1 -0
  31. package/dist/commands/wallet.d.ts.map +1 -1
  32. package/dist/commands/wallet.js +299 -65
  33. package/dist/commands/wallet.js.map +1 -1
  34. package/dist/commands/watch.d.ts.map +1 -1
  35. package/dist/commands/watch.js +146 -9
  36. package/dist/commands/watch.js.map +1 -1
  37. package/dist/commands/workroom.d.ts.map +1 -1
  38. package/dist/commands/workroom.js +112 -6
  39. package/dist/commands/workroom.js.map +1 -1
  40. package/dist/config.d.ts +13 -0
  41. package/dist/config.d.ts.map +1 -1
  42. package/dist/config.js +41 -4
  43. package/dist/config.js.map +1 -1
  44. package/dist/daemon/compute-metering.d.ts +61 -0
  45. package/dist/daemon/compute-metering.d.ts.map +1 -0
  46. package/dist/daemon/compute-metering.js +299 -0
  47. package/dist/daemon/compute-metering.js.map +1 -0
  48. package/dist/daemon/compute-session.d.ts +100 -0
  49. package/dist/daemon/compute-session.d.ts.map +1 -0
  50. package/dist/daemon/compute-session.js +231 -0
  51. package/dist/daemon/compute-session.js.map +1 -0
  52. package/dist/daemon/config.d.ts +33 -1
  53. package/dist/daemon/config.d.ts.map +1 -1
  54. package/dist/daemon/config.js +69 -0
  55. package/dist/daemon/config.js.map +1 -1
  56. package/dist/daemon/credentials.d.ts +24 -0
  57. package/dist/daemon/credentials.d.ts.map +1 -0
  58. package/dist/daemon/credentials.js +80 -0
  59. package/dist/daemon/credentials.js.map +1 -0
  60. package/dist/daemon/delivery-client.d.ts +35 -0
  61. package/dist/daemon/delivery-client.d.ts.map +1 -0
  62. package/dist/daemon/delivery-client.js +231 -0
  63. package/dist/daemon/delivery-client.js.map +1 -0
  64. package/dist/daemon/file-delivery.d.ts +98 -0
  65. package/dist/daemon/file-delivery.d.ts.map +1 -0
  66. package/dist/daemon/file-delivery.js +461 -0
  67. package/dist/daemon/file-delivery.js.map +1 -0
  68. package/dist/daemon/index.d.ts +1 -0
  69. package/dist/daemon/index.d.ts.map +1 -1
  70. package/dist/daemon/index.js +793 -227
  71. package/dist/daemon/index.js.map +1 -1
  72. package/dist/daemon/notify.d.ts +35 -6
  73. package/dist/daemon/notify.d.ts.map +1 -1
  74. package/dist/daemon/notify.js +176 -48
  75. package/dist/daemon/notify.js.map +1 -1
  76. package/dist/daemon/worker-executor.d.ts +71 -0
  77. package/dist/daemon/worker-executor.d.ts.map +1 -0
  78. package/dist/daemon/worker-executor.js +382 -0
  79. package/dist/daemon/worker-executor.js.map +1 -0
  80. package/dist/drain-v4.js +2 -2
  81. package/dist/drain-v4.js.map +1 -1
  82. package/dist/endpoint-notify.d.ts +9 -1
  83. package/dist/endpoint-notify.d.ts.map +1 -1
  84. package/dist/endpoint-notify.js +116 -3
  85. package/dist/endpoint-notify.js.map +1 -1
  86. package/dist/index.js +81 -1
  87. package/dist/index.js.map +1 -1
  88. package/dist/program.d.ts.map +1 -1
  89. package/dist/program.js +8 -0
  90. package/dist/program.js.map +1 -1
  91. package/dist/repl.d.ts.map +1 -1
  92. package/dist/repl.js +69 -486
  93. package/dist/repl.js.map +1 -1
  94. package/dist/tui/App.d.ts +12 -0
  95. package/dist/tui/App.d.ts.map +1 -0
  96. package/dist/tui/App.js +154 -0
  97. package/dist/tui/App.js.map +1 -0
  98. package/dist/tui/Footer.d.ts +11 -0
  99. package/dist/tui/Footer.d.ts.map +1 -0
  100. package/dist/tui/Footer.js +13 -0
  101. package/dist/tui/Footer.js.map +1 -0
  102. package/dist/tui/Header.d.ts +14 -0
  103. package/dist/tui/Header.d.ts.map +1 -0
  104. package/dist/tui/Header.js +19 -0
  105. package/dist/tui/Header.js.map +1 -0
  106. package/dist/tui/InputLine.d.ts +11 -0
  107. package/dist/tui/InputLine.d.ts.map +1 -0
  108. package/dist/tui/InputLine.js +145 -0
  109. package/dist/tui/InputLine.js.map +1 -0
  110. package/dist/tui/Viewport.d.ts +14 -0
  111. package/dist/tui/Viewport.d.ts.map +1 -0
  112. package/dist/tui/Viewport.js +48 -0
  113. package/dist/tui/Viewport.js.map +1 -0
  114. package/dist/tui/WalletConnectPairing.d.ts +23 -0
  115. package/dist/tui/WalletConnectPairing.d.ts.map +1 -0
  116. package/dist/tui/WalletConnectPairing.js +61 -0
  117. package/dist/tui/WalletConnectPairing.js.map +1 -0
  118. package/dist/tui/components/Button.d.ts +7 -0
  119. package/dist/tui/components/Button.d.ts.map +1 -0
  120. package/dist/tui/components/Button.js +21 -0
  121. package/dist/tui/components/Button.js.map +1 -0
  122. package/dist/tui/components/CeremonyView.d.ts +13 -0
  123. package/dist/tui/components/CeremonyView.d.ts.map +1 -0
  124. package/dist/tui/components/CeremonyView.js +10 -0
  125. package/dist/tui/components/CeremonyView.js.map +1 -0
  126. package/dist/tui/components/CompletionDropdown.d.ts +7 -0
  127. package/dist/tui/components/CompletionDropdown.d.ts.map +1 -0
  128. package/dist/tui/components/CompletionDropdown.js +23 -0
  129. package/dist/tui/components/CompletionDropdown.js.map +1 -0
  130. package/dist/tui/components/ConfirmPrompt.d.ts +9 -0
  131. package/dist/tui/components/ConfirmPrompt.d.ts.map +1 -0
  132. package/dist/tui/components/ConfirmPrompt.js +10 -0
  133. package/dist/tui/components/ConfirmPrompt.js.map +1 -0
  134. package/dist/tui/components/CustomTextInput.d.ts +15 -0
  135. package/dist/tui/components/CustomTextInput.d.ts.map +1 -0
  136. package/dist/tui/components/CustomTextInput.js +99 -0
  137. package/dist/tui/components/CustomTextInput.js.map +1 -0
  138. package/dist/tui/components/InteractiveTable.d.ts +14 -0
  139. package/dist/tui/components/InteractiveTable.d.ts.map +1 -0
  140. package/dist/tui/components/InteractiveTable.js +61 -0
  141. package/dist/tui/components/InteractiveTable.js.map +1 -0
  142. package/dist/tui/components/StepSpinner.d.ts +11 -0
  143. package/dist/tui/components/StepSpinner.d.ts.map +1 -0
  144. package/dist/tui/components/StepSpinner.js +32 -0
  145. package/dist/tui/components/StepSpinner.js.map +1 -0
  146. package/dist/tui/components/Toast.d.ts +18 -0
  147. package/dist/tui/components/Toast.d.ts.map +1 -0
  148. package/dist/tui/components/Toast.js +29 -0
  149. package/dist/tui/components/Toast.js.map +1 -0
  150. package/dist/tui/index.d.ts +2 -0
  151. package/dist/tui/index.d.ts.map +1 -0
  152. package/dist/tui/index.js +55 -0
  153. package/dist/tui/index.js.map +1 -0
  154. package/dist/tui/useChat.d.ts +11 -0
  155. package/dist/tui/useChat.d.ts.map +1 -0
  156. package/dist/tui/useChat.js +91 -0
  157. package/dist/tui/useChat.js.map +1 -0
  158. package/dist/tui/useCommand.d.ts +12 -0
  159. package/dist/tui/useCommand.d.ts.map +1 -0
  160. package/dist/tui/useCommand.js +137 -0
  161. package/dist/tui/useCommand.js.map +1 -0
  162. package/dist/tui/useNotifications.d.ts +9 -0
  163. package/dist/tui/useNotifications.d.ts.map +1 -0
  164. package/dist/tui/useNotifications.js +17 -0
  165. package/dist/tui/useNotifications.js.map +1 -0
  166. package/dist/tui/useScroll.d.ts +17 -0
  167. package/dist/tui/useScroll.d.ts.map +1 -0
  168. package/dist/tui/useScroll.js +46 -0
  169. package/dist/tui/useScroll.js.map +1 -0
  170. package/dist/ui/format.d.ts.map +1 -1
  171. package/dist/ui/format.js +2 -0
  172. package/dist/ui/format.js.map +1 -1
  173. package/dist/ui/qr-render.d.ts +25 -0
  174. package/dist/ui/qr-render.d.ts.map +1 -0
  175. package/dist/ui/qr-render.js +90 -0
  176. package/dist/ui/qr-render.js.map +1 -0
  177. package/dist/ui/rpc-fallback.d.ts +11 -0
  178. package/dist/ui/rpc-fallback.d.ts.map +1 -0
  179. package/dist/ui/rpc-fallback.js +58 -0
  180. package/dist/ui/rpc-fallback.js.map +1 -0
  181. package/dist/walletconnect.d.ts +4 -0
  182. package/dist/walletconnect.d.ts.map +1 -1
  183. package/dist/walletconnect.js.map +1 -1
  184. package/package.json +11 -3
  185. package/scripts/authorize-machine-key.ts +0 -43
  186. package/scripts/drain-wallet.ts +0 -149
  187. package/scripts/execute-spend-only.ts +0 -81
  188. package/scripts/register-agent-userop.ts +0 -186
  189. package/src/abis.ts +0 -187
  190. package/src/bundler.ts +0 -235
  191. package/src/client.ts +0 -36
  192. package/src/coinbase-smart-wallet.ts +0 -51
  193. package/src/commands/accept.ts +0 -64
  194. package/src/commands/agent-handshake.ts +0 -72
  195. package/src/commands/agent.ts +0 -691
  196. package/src/commands/agreements.ts +0 -350
  197. package/src/commands/arbitrator.ts +0 -180
  198. package/src/commands/arena-handshake.ts +0 -257
  199. package/src/commands/arena.ts +0 -122
  200. package/src/commands/cancel.ts +0 -35
  201. package/src/commands/channel.ts +0 -218
  202. package/src/commands/coldstart.ts +0 -165
  203. package/src/commands/config.ts +0 -58
  204. package/src/commands/contract-interaction.ts +0 -166
  205. package/src/commands/daemon.ts +0 -978
  206. package/src/commands/deliver.ts +0 -148
  207. package/src/commands/discover.ts +0 -297
  208. package/src/commands/dispute.ts +0 -375
  209. package/src/commands/endpoint.ts +0 -620
  210. package/src/commands/feed.ts +0 -229
  211. package/src/commands/hire.ts +0 -245
  212. package/src/commands/migrate.ts +0 -177
  213. package/src/commands/negotiate.ts +0 -271
  214. package/src/commands/openshell.ts +0 -1055
  215. package/src/commands/owner.ts +0 -35
  216. package/src/commands/policy.ts +0 -263
  217. package/src/commands/relay.ts +0 -273
  218. package/src/commands/remediate.ts +0 -24
  219. package/src/commands/reputation.ts +0 -79
  220. package/src/commands/setup.ts +0 -343
  221. package/src/commands/trust.ts +0 -27
  222. package/src/commands/verify.ts +0 -91
  223. package/src/commands/wallet.ts +0 -3280
  224. package/src/commands/watch.ts +0 -23
  225. package/src/commands/watchtower.ts +0 -248
  226. package/src/commands/workroom.ts +0 -959
  227. package/src/config.ts +0 -174
  228. package/src/daemon/config.ts +0 -308
  229. package/src/daemon/hire-listener.ts +0 -226
  230. package/src/daemon/index.ts +0 -955
  231. package/src/daemon/job-lifecycle.ts +0 -215
  232. package/src/daemon/notify.ts +0 -157
  233. package/src/daemon/token-metering.ts +0 -183
  234. package/src/daemon/userops.ts +0 -119
  235. package/src/daemon/wallet-monitor.ts +0 -90
  236. package/src/drain-v4.ts +0 -159
  237. package/src/endpoint-config.ts +0 -83
  238. package/src/endpoint-notify.ts +0 -46
  239. package/src/index.ts +0 -26
  240. package/src/openshell-runtime.ts +0 -277
  241. package/src/program.ts +0 -83
  242. package/src/repl.ts +0 -680
  243. package/src/signing.ts +0 -28
  244. package/src/telegram-notify.ts +0 -88
  245. package/src/ui/banner.ts +0 -51
  246. package/src/ui/colors.ts +0 -30
  247. package/src/ui/format.ts +0 -77
  248. package/src/ui/spinner.ts +0 -56
  249. package/src/ui/tree.ts +0 -16
  250. package/src/utils/format.ts +0 -48
  251. package/src/utils/hash.ts +0 -5
  252. package/src/utils/time.ts +0 -15
  253. package/src/wallet-router.ts +0 -178
  254. package/src/walletconnect-session.ts +0 -27
  255. package/src/walletconnect.ts +0 -294
  256. package/test/time.test.js +0 -11
  257. package/tsconfig.json +0 -19
package/dist/repl.js CHANGED
@@ -8,17 +8,11 @@ const chalk_1 = __importDefault(require("chalk"));
8
8
  const fs_1 = __importDefault(require("fs"));
9
9
  const path_1 = __importDefault(require("path"));
10
10
  const os_1 = __importDefault(require("os"));
11
+ const readline_1 = __importDefault(require("readline"));
11
12
  const program_1 = require("./program");
12
13
  const banner_1 = require("./ui/banner");
13
14
  const colors_1 = require("./ui/colors");
14
- // ─── Sentinel to intercept process.exit() from commands ──────────────────────
15
- class REPLExitSignal extends Error {
16
- constructor(code = 0) {
17
- super("repl-exit-signal");
18
- this.code = code;
19
- }
20
- }
21
- // ─── Config / banner helpers ──────────────────────────────────────────────────
15
+ // ─── Config helpers ────────────────────────────────────────────────────────────
22
16
  const CONFIG_PATH = path_1.default.join(os_1.default.homedir(), ".arc402", "config.json");
23
17
  async function loadBannerConfig() {
24
18
  if (!fs_1.default.existsSync(CONFIG_PATH))
@@ -30,66 +24,42 @@ async function loadBannerConfig() {
30
24
  const w = raw.walletContractAddress;
31
25
  cfg.wallet = `${w.slice(0, 6)}...${w.slice(-4)}`;
32
26
  }
33
- if (raw.rpcUrl && raw.walletContractAddress) {
34
- try {
35
- // eslint-disable-next-line @typescript-eslint/no-var-requires
36
- const ethersLib = require("ethers");
37
- const provider = new ethersLib.ethers.JsonRpcProvider(raw.rpcUrl);
38
- const bal = await Promise.race([
39
- provider.getBalance(raw.walletContractAddress),
40
- new Promise((_, r) => setTimeout(() => r(new Error("timeout")), 2000)),
41
- ]);
42
- cfg.balance = `${parseFloat(ethersLib.ethers.formatEther(bal)).toFixed(4)} ETH`;
43
- }
44
- catch {
45
- /* skip balance on timeout */
46
- }
47
- }
48
27
  return cfg;
49
28
  }
50
29
  catch {
51
30
  return undefined;
52
31
  }
53
32
  }
54
- // ─── ANSI helpers ─────────────────────────────────────────────────────────────
55
- const ESC = "\x1b";
56
- const ansi = {
57
- clearScreen: `${ESC}[2J`,
58
- home: `${ESC}[H`,
59
- clearLine: `${ESC}[2K`,
60
- clearToEol: `${ESC}[K`,
61
- hideCursor: `${ESC}[?25l`,
62
- showCursor: `${ESC}[?25h`,
63
- move: (r, col) => `${ESC}[${r};${col}H`,
64
- scrollRegion: (top, bot) => `${ESC}[${top};${bot}r`,
65
- resetScroll: `${ESC}[r`,
66
- };
67
- function write(s) {
68
- process.stdout.write(s);
69
- }
70
- // ─── Prompt constants ─────────────────────────────────────────────────────────
71
- const PROMPT_TEXT = chalk_1.default.cyanBright("◈") +
33
+ // ─── Prompt ────────────────────────────────────────────────────────────────────
34
+ const PROMPT = chalk_1.default.cyanBright("") +
72
35
  " " +
73
36
  chalk_1.default.dim("arc402") +
74
37
  " " +
75
38
  chalk_1.default.white(">") +
76
39
  " ";
77
- // Visible character count of "◈ arc402 > "
78
- const PROMPT_VIS = 11;
79
- // ─── Known command detection ──────────────────────────────────────────────────
80
- const BUILTIN_CMDS = ["help", "exit", "quit", "clear", "status"];
81
40
  // ─── Shell-style tokenizer ────────────────────────────────────────────────────
82
41
  function parseTokens(input) {
83
42
  const tokens = [];
84
43
  let current = "";
85
44
  let inQuote = false;
86
45
  let quoteChar = "";
46
+ let escape = false;
87
47
  for (const ch of input) {
48
+ if (escape) {
49
+ current += ch;
50
+ escape = false;
51
+ continue;
52
+ }
88
53
  if (inQuote) {
89
- if (ch === quoteChar)
54
+ if (quoteChar === '"' && ch === "\\") {
55
+ escape = true;
56
+ }
57
+ else if (ch === quoteChar) {
90
58
  inQuote = false;
91
- else
59
+ }
60
+ else {
92
61
  current += ch;
62
+ }
93
63
  }
94
64
  else if (ch === '"' || ch === "'") {
95
65
  inQuote = true;
@@ -109,468 +79,81 @@ function parseTokens(input) {
109
79
  tokens.push(current);
110
80
  return tokens;
111
81
  }
112
- // ─── Tab completion logic ─────────────────────────────────────────────────────
113
- function getCompletions(line, topCmds, subCmds) {
114
- const allTop = [...BUILTIN_CMDS, ...topCmds];
115
- const trimmed = line.trimStart();
116
- const spaceIdx = trimmed.indexOf(" ");
117
- if (spaceIdx === -1) {
118
- return allTop.filter((cmd) => cmd.startsWith(trimmed));
119
- }
120
- const parent = trimmed.slice(0, spaceIdx);
121
- const rest = trimmed.slice(spaceIdx + 1);
122
- const subs = subCmds.get(parent) ?? [];
123
- return subs.filter((s) => s.startsWith(rest)).map((s) => `${parent} ${s}`);
124
- }
125
- // ─── TUI class ────────────────────────────────────────────────────────────────
126
- class TUI {
127
- constructor() {
128
- this.inputBuffer = "";
129
- this.cursorPos = 0;
130
- this.history = [];
131
- this.historyIdx = -1;
132
- this.historyTemp = "";
133
- this.bannerLines = [];
134
- this.topCmds = [];
135
- this.subCmds = new Map();
136
- this.commandRunning = false;
137
- // ── Key handler ──────────────────────────────────────────────────────────────
138
- this.boundKeyHandler = (key) => {
139
- if (this.commandRunning)
140
- return;
141
- this.handleKey(key);
142
- };
143
- }
144
- get termRows() {
145
- return process.stdout.rows || 24;
146
- }
147
- get termCols() {
148
- return process.stdout.columns || 80;
149
- }
150
- get scrollTop() {
151
- // +1 for separator row after banner
152
- return this.bannerLines.length + 2;
153
- }
154
- get scrollBot() {
155
- return this.termRows - 1;
156
- }
157
- get inputRow() {
158
- return this.termRows;
159
- }
160
- // ── Lifecycle ───────────────────────────────────────────────────────────────
161
- async start() {
162
- this.bannerCfg = await loadBannerConfig();
163
- // Build command metadata for completion
164
- const template = (0, program_1.createProgram)();
165
- this.topCmds = template.commands.map((cmd) => cmd.name());
166
- for (const cmd of template.commands) {
167
- if (cmd.commands.length > 0) {
168
- this.subCmds.set(cmd.name(), cmd.commands.map((s) => s.name()));
169
- }
170
- }
171
- // Draw initial screen
172
- this.setupScreen();
173
- this.drawInputLine();
174
- // Enter raw mode
175
- if (process.stdin.isTTY) {
176
- process.stdin.setRawMode(true);
177
- }
178
- process.stdin.resume();
179
- process.stdin.setEncoding("utf8");
180
- process.stdin.on("data", this.boundKeyHandler);
181
- // Resize handler
182
- process.stdout.on("resize", () => {
183
- this.setupScreen();
184
- this.drawInputLine();
185
- });
186
- // SIGINT (shouldn't fire in raw mode, but just in case)
187
- process.on("SIGINT", () => this.exitGracefully());
188
- // Keep alive — process.stdin listener keeps the event loop running
189
- await new Promise(() => {
190
- /* never resolves; process.exit() is called on quit */
191
- });
192
- }
193
- // ── Screen setup ────────────────────────────────────────────────────────────
194
- setupScreen() {
195
- this.bannerLines = (0, banner_1.getBannerLines)(this.bannerCfg);
196
- write(ansi.hideCursor);
197
- write(ansi.clearScreen + ansi.home);
198
- // Banner
199
- for (const line of this.bannerLines) {
200
- write(line + "\n");
201
- }
202
- // Separator between banner and output area
203
- write(chalk_1.default.dim("─".repeat(this.termCols)) + "\n");
204
- // Set scroll region (output area, leaves last row free for input)
205
- if (this.scrollTop <= this.scrollBot) {
206
- write(ansi.scrollRegion(this.scrollTop, this.scrollBot));
207
- }
208
- // Position cursor at top of output area
209
- write(ansi.move(this.scrollTop, 1));
210
- write(ansi.showCursor);
211
- }
212
- // ── Banner repaint (in-place, preserves output area) ────────────────────────
213
- repaintBanner() {
214
- write(ansi.hideCursor);
215
- for (let i = 0; i < this.bannerLines.length; i++) {
216
- write(ansi.move(i + 1, 1) + ansi.clearToEol + this.bannerLines[i]);
82
+ // ─── REPL entry point (basic readline fallback) ────────────────────────────────
83
+ async function startREPL() {
84
+ if (!process.stdout.isTTY) {
85
+ const bannerCfg = await loadBannerConfig();
86
+ for (const line of (0, banner_1.getBannerLines)(bannerCfg)) {
87
+ process.stdout.write(line + "\n");
217
88
  }
218
- // Separator
219
- const sepRow = this.bannerLines.length + 1;
220
- write(ansi.move(sepRow, 1) +
221
- ansi.clearToEol +
222
- chalk_1.default.dim("─".repeat(this.termCols)));
223
- write(ansi.showCursor);
89
+ process.stdout.write("Interactive TUI requires a TTY. Use arc402 <command> directly.\n");
90
+ return;
224
91
  }
225
- // ── Input line ───────────────────────────────────────────────────────────────
226
- drawInputLine() {
227
- write(ansi.move(this.inputRow, 1) + ansi.clearLine);
228
- write(PROMPT_TEXT + this.inputBuffer);
229
- // Place cursor at correct position within the input
230
- write(ansi.move(this.inputRow, PROMPT_VIS + 1 + this.cursorPos));
92
+ const bannerCfg = await loadBannerConfig();
93
+ for (const line of (0, banner_1.getBannerLines)(bannerCfg)) {
94
+ process.stdout.write(line + "\n");
231
95
  }
232
- handleKey(key) {
233
- // Ctrl+C
234
- if (key === "\u0003") {
235
- this.exitGracefully();
236
- return;
237
- }
238
- // Ctrl+L — refresh
239
- if (key === "\u000C") {
240
- this.setupScreen();
241
- this.drawInputLine();
242
- return;
243
- }
244
- // Enter
245
- if (key === "\r" || key === "\n") {
246
- void this.submit();
247
- return;
248
- }
249
- // Backspace
250
- if (key === "\u007F" || key === "\b") {
251
- if (this.cursorPos > 0) {
252
- this.inputBuffer =
253
- this.inputBuffer.slice(0, this.cursorPos - 1) +
254
- this.inputBuffer.slice(this.cursorPos);
255
- this.cursorPos--;
256
- this.drawInputLine();
257
- }
96
+ const rl = readline_1.default.createInterface({
97
+ input: process.stdin,
98
+ output: process.stdout,
99
+ prompt: PROMPT,
100
+ terminal: true,
101
+ });
102
+ rl.prompt();
103
+ rl.on("line", async (input) => {
104
+ const trimmed = input.trim();
105
+ if (!trimmed) {
106
+ rl.prompt();
258
107
  return;
259
108
  }
260
- // Delete (forward)
261
- if (key === "\x1b[3~") {
262
- if (this.cursorPos < this.inputBuffer.length) {
263
- this.inputBuffer =
264
- this.inputBuffer.slice(0, this.cursorPos) +
265
- this.inputBuffer.slice(this.cursorPos + 1);
266
- this.drawInputLine();
267
- }
268
- return;
109
+ if (trimmed === "exit" || trimmed === "quit") {
110
+ process.stdout.write(" " + chalk_1.default.cyanBright("◈") + chalk_1.default.dim(" goodbye") + "\n");
111
+ process.exit(0);
269
112
  }
270
- // Up arrow history prev
271
- if (key === "\x1b[A") {
272
- if (this.historyIdx === -1) {
273
- this.historyTemp = this.inputBuffer;
274
- this.historyIdx = this.history.length - 1;
275
- }
276
- else if (this.historyIdx > 0) {
277
- this.historyIdx--;
278
- }
279
- if (this.historyIdx >= 0) {
280
- this.inputBuffer = this.history[this.historyIdx];
281
- this.cursorPos = this.inputBuffer.length;
282
- this.drawInputLine();
113
+ if (trimmed === "clear") {
114
+ process.stdout.write("\x1b[2J\x1b[H");
115
+ for (const line of (0, banner_1.getBannerLines)(bannerCfg)) {
116
+ process.stdout.write(line + "\n");
283
117
  }
118
+ rl.prompt();
284
119
  return;
285
120
  }
286
- // Down arrow — history next
287
- if (key === "\x1b[B") {
288
- if (this.historyIdx >= 0) {
289
- this.historyIdx++;
290
- if (this.historyIdx >= this.history.length) {
291
- this.historyIdx = -1;
292
- this.inputBuffer = this.historyTemp;
293
- }
294
- else {
295
- this.inputBuffer = this.history[this.historyIdx];
296
- }
297
- this.cursorPos = this.inputBuffer.length;
298
- this.drawInputLine();
299
- }
300
- return;
301
- }
302
- // Right arrow
303
- if (key === "\x1b[C") {
304
- if (this.cursorPos < this.inputBuffer.length) {
305
- this.cursorPos++;
306
- this.drawInputLine();
307
- }
308
- return;
309
- }
310
- // Left arrow
311
- if (key === "\x1b[D") {
312
- if (this.cursorPos > 0) {
313
- this.cursorPos--;
314
- this.drawInputLine();
315
- }
316
- return;
317
- }
318
- // Home / Ctrl+A
319
- if (key === "\x1b[H" || key === "\u0001") {
320
- this.cursorPos = 0;
321
- this.drawInputLine();
322
- return;
323
- }
324
- // End / Ctrl+E
325
- if (key === "\x1b[F" || key === "\u0005") {
326
- this.cursorPos = this.inputBuffer.length;
327
- this.drawInputLine();
328
- return;
329
- }
330
- // Ctrl+U — clear line
331
- if (key === "\u0015") {
332
- this.inputBuffer = "";
333
- this.cursorPos = 0;
334
- this.drawInputLine();
335
- return;
336
- }
337
- // Ctrl+K — kill to end
338
- if (key === "\u000B") {
339
- this.inputBuffer = this.inputBuffer.slice(0, this.cursorPos);
340
- this.drawInputLine();
341
- return;
342
- }
343
- // Tab — completion
344
- if (key === "\t") {
345
- this.handleTab();
346
- return;
347
- }
348
- // Printable characters
349
- if (key >= " " && !key.startsWith("\x1b")) {
350
- this.inputBuffer =
351
- this.inputBuffer.slice(0, this.cursorPos) +
352
- key +
353
- this.inputBuffer.slice(this.cursorPos);
354
- this.cursorPos += key.length;
355
- this.drawInputLine();
356
- }
357
- }
358
- // ── Tab completion ───────────────────────────────────────────────────────────
359
- handleTab() {
360
- const completions = getCompletions(this.inputBuffer, this.topCmds, this.subCmds);
361
- if (completions.length === 0)
362
- return;
363
- if (completions.length === 1) {
364
- this.inputBuffer = completions[0] + " ";
365
- this.cursorPos = this.inputBuffer.length;
366
- this.drawInputLine();
367
- return;
368
- }
369
- // Find common prefix
370
- const common = completions.reduce((a, b) => {
371
- let i = 0;
372
- while (i < a.length && i < b.length && a[i] === b[i])
373
- i++;
374
- return a.slice(0, i);
375
- });
376
- if (common.length > this.inputBuffer.trimStart().length) {
377
- this.inputBuffer = common;
378
- this.cursorPos = common.length;
379
- }
380
- // Show options in output area
381
- this.writeOutput("\n" + chalk_1.default.dim(completions.join(" ")) + "\n");
382
- this.drawInputLine();
383
- }
384
- // ── Write to output area ─────────────────────────────────────────────────────
385
- writeOutput(text) {
386
- // Move cursor to bottom of scroll region to ensure scroll-down works
387
- write(ansi.move(this.scrollBot, 1));
388
- write(text);
389
- }
390
- // ── Submit line ──────────────────────────────────────────────────────────────
391
- async submit() {
392
- const input = this.inputBuffer.trim();
393
- this.inputBuffer = "";
394
- this.cursorPos = 0;
395
- this.historyIdx = -1;
396
- if (!input) {
397
- this.drawInputLine();
398
- return;
399
- }
400
- // Add to history
401
- if (input !== this.history[this.history.length - 1]) {
402
- this.history.push(input);
403
- }
404
- // Echo the input into the output area
405
- this.writeOutput("\n" + chalk_1.default.dim("◈ ") + chalk_1.default.white(input) + "\n");
406
- // ── Built-in commands ──────────────────────────────────────────────────────
407
- if (input === "exit" || input === "quit") {
408
- this.exitGracefully();
409
- return;
410
- }
411
- if (input === "clear") {
412
- this.bannerCfg = await loadBannerConfig();
413
- this.setupScreen();
414
- this.drawInputLine();
415
- return;
416
- }
417
- if (input === "status") {
418
- await this.runStatus();
419
- this.afterCommand();
420
- return;
421
- }
422
- if (input === "help") {
423
- await this.runHelp();
424
- this.afterCommand();
425
- return;
426
- }
427
- // ── Chat mode detection ────────────────────────────────────────────────────
428
- const firstWord = input.split(/\s+/)[0];
429
- const allKnown = [...BUILTIN_CMDS, ...this.topCmds];
430
- if (!allKnown.includes(firstWord)) {
431
- this.writeOutput(chalk_1.default.dim("\n ◈ Chat coming soon — type a command or help\n"));
432
- this.afterCommand();
433
- return;
434
- }
435
- // ── Dispatch to commander ──────────────────────────────────────────────────
436
- this.commandRunning = true;
437
- // Move output cursor to bottom of scroll region
438
- write(ansi.move(this.scrollBot, 1));
439
- // Suspend TUI stdin so interactive commands (prompts, readline) work cleanly
440
- process.stdin.removeListener("data", this.boundKeyHandler);
441
- const tokens = parseTokens(input);
121
+ // Dispatch to commander
122
+ const tokens = parseTokens(trimmed);
442
123
  const prog = (0, program_1.createProgram)();
443
124
  prog.exitOverride();
444
125
  prog.configureOutput({
445
126
  writeOut: (str) => process.stdout.write(str),
446
127
  writeErr: (str) => process.stderr.write(str),
447
128
  });
448
- const origExit = process.exit;
449
- process.exit = ((code) => {
450
- throw new REPLExitSignal(code ?? 0);
451
- });
452
129
  try {
453
130
  await prog.parseAsync(["node", "arc402", ...tokens]);
454
131
  }
455
132
  catch (err) {
456
- if (err instanceof REPLExitSignal) {
457
- // Command called process.exit() — normal
133
+ const e = err;
134
+ if (e.code === "commander.helpDisplayed" ||
135
+ e.code === "commander.version" ||
136
+ e.code === "commander.executeSubCommandAsync") {
137
+ // already written
458
138
  }
459
- else {
460
- const e = err;
461
- if (e.code === "commander.helpDisplayed" ||
462
- e.code === "commander.version") {
463
- // already written
464
- }
465
- else if (e.code === "commander.unknownCommand") {
466
- process.stdout.write(`\n ${colors_1.c.failure} ${chalk_1.default.red(`Unknown command: ${chalk_1.default.white(tokens[0])}`)} \n`);
467
- process.stdout.write(chalk_1.default.dim(" Type 'help' for available commands\n"));
468
- }
469
- else if (e.code?.startsWith("commander.")) {
470
- process.stdout.write(`\n ${colors_1.c.failure} ${chalk_1.default.red(e.message ?? String(err))}\n`);
471
- }
472
- else {
473
- process.stdout.write(`\n ${colors_1.c.failure} ${chalk_1.default.red(e.message ?? String(err))}\n`);
474
- }
475
- }
476
- }
477
- finally {
478
- process.exit = origExit;
479
- }
480
- // Restore raw mode + our listener (interactive commands may have toggled it)
481
- if (process.stdin.isTTY) {
482
- process.stdin.setRawMode(true);
483
- }
484
- process.stdin.on("data", this.boundKeyHandler);
485
- this.commandRunning = false;
486
- this.afterCommand();
487
- }
488
- // ── After each command: repaint banner + input ───────────────────────────────
489
- afterCommand() {
490
- this.repaintBanner();
491
- this.drawInputLine();
492
- }
493
- // ── Built-in: status ─────────────────────────────────────────────────────────
494
- async runStatus() {
495
- write(ansi.move(this.scrollBot, 1));
496
- if (!fs_1.default.existsSync(CONFIG_PATH)) {
497
- process.stdout.write(chalk_1.default.dim("\n No config found. Run 'config init' to get started.\n"));
498
- return;
499
- }
500
- try {
501
- const raw = JSON.parse(fs_1.default.readFileSync(CONFIG_PATH, "utf-8"));
502
- process.stdout.write("\n");
503
- if (raw.network)
504
- process.stdout.write(` ${chalk_1.default.dim("Network")} ${chalk_1.default.white(raw.network)}\n`);
505
- if (raw.walletContractAddress) {
506
- const w = raw.walletContractAddress;
507
- process.stdout.write(` ${chalk_1.default.dim("Wallet")} ${chalk_1.default.white(`${w.slice(0, 6)}...${w.slice(-4)}`)}\n`);
139
+ else if (e.code === "commander.unknownCommand") {
140
+ process.stdout.write(`\n ${colors_1.c.failure} ${chalk_1.default.red(`Unknown command: ${chalk_1.default.white(tokens[0])}`)} \n`);
141
+ process.stdout.write(chalk_1.default.dim(" Type 'help' for available commands\n"));
508
142
  }
509
- if (raw.rpcUrl && raw.walletContractAddress) {
510
- try {
511
- // eslint-disable-next-line @typescript-eslint/no-var-requires
512
- const ethersLib = require("ethers");
513
- const provider = new ethersLib.ethers.JsonRpcProvider(raw.rpcUrl);
514
- const bal = await Promise.race([
515
- provider.getBalance(raw.walletContractAddress),
516
- new Promise((_, r) => setTimeout(() => r(new Error("timeout")), 2000)),
517
- ]);
518
- process.stdout.write(` ${chalk_1.default.dim("Balance")} ${chalk_1.default.white(`${parseFloat(ethersLib.ethers.formatEther(bal)).toFixed(4)} ETH`)}\n`);
519
- }
520
- catch {
521
- /* skip */
522
- }
143
+ else {
144
+ process.stdout.write(`\n ${colors_1.c.failure} ${chalk_1.default.red(e.message ?? String(err))}\n`);
523
145
  }
524
- process.stdout.write("\n");
525
- }
526
- catch {
527
- /* skip */
528
- }
529
- }
530
- // ── Built-in: help ────────────────────────────────────────────────────────────
531
- async runHelp() {
532
- write(ansi.move(this.scrollBot, 1));
533
- process.stdin.removeListener("data", this.boundKeyHandler);
534
- const prog = (0, program_1.createProgram)();
535
- prog.exitOverride();
536
- prog.configureOutput({
537
- writeOut: (str) => process.stdout.write(str),
538
- writeErr: (str) => process.stderr.write(str),
539
- });
540
- try {
541
- await prog.parseAsync(["node", "arc402", "--help"]);
542
- }
543
- catch {
544
- /* commander throws after printing help */
545
- }
546
- if (process.stdin.isTTY)
547
- process.stdin.setRawMode(true);
548
- process.stdin.on("data", this.boundKeyHandler);
549
- }
550
- // ── Exit ──────────────────────────────────────────────────────────────────────
551
- exitGracefully() {
552
- write(ansi.move(this.inputRow, 1) + ansi.clearLine);
553
- write(" " + chalk_1.default.cyanBright("◈") + chalk_1.default.dim(" goodbye") + "\n");
554
- write(ansi.resetScroll);
555
- write(ansi.showCursor);
556
- if (process.stdin.isTTY) {
557
- process.stdin.setRawMode(false);
558
146
  }
147
+ process.stdout.write("\n");
148
+ rl.prompt();
149
+ });
150
+ rl.on("close", () => {
151
+ process.stdout.write("\n " + chalk_1.default.cyanBright("◈") + chalk_1.default.dim(" goodbye") + "\n");
559
152
  process.exit(0);
560
- }
561
- }
562
- // ─── REPL entry point ─────────────────────────────────────────────────────────
563
- async function startREPL() {
564
- if (!process.stdout.isTTY) {
565
- // Non-TTY (piped): fall back to minimal line-mode output
566
- const bannerCfg = await loadBannerConfig();
567
- for (const line of (0, banner_1.getBannerLines)(bannerCfg)) {
568
- process.stdout.write(line + "\n");
569
- }
570
- process.stdout.write("Interactive TUI requires a TTY. Use arc402 <command> directly.\n");
571
- return;
572
- }
573
- const tui = new TUI();
574
- await tui.start();
153
+ });
154
+ // Keep alive
155
+ await new Promise(() => {
156
+ /* readline keeps event loop alive */
157
+ });
575
158
  }
576
159
  //# sourceMappingURL=repl.js.map