arc402-cli 0.7.5 → 0.9.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 (309) hide show
  1. package/INK6-UX-SPEC.md +446 -0
  2. package/MIGRATION-SPEC.md +108 -0
  3. package/dist/abis.js +14 -17
  4. package/dist/abis.js.map +1 -1
  5. package/dist/bundler.d.ts +1 -1
  6. package/dist/bundler.d.ts.map +1 -1
  7. package/dist/bundler.js +27 -61
  8. package/dist/bundler.js.map +1 -1
  9. package/dist/client.d.ts +1 -1
  10. package/dist/client.d.ts.map +1 -1
  11. package/dist/client.js +5 -9
  12. package/dist/client.js.map +1 -1
  13. package/dist/coinbase-smart-wallet.js +1 -4
  14. package/dist/coinbase-smart-wallet.js.map +1 -1
  15. package/dist/commands/accept.js +25 -28
  16. package/dist/commands/accept.js.map +1 -1
  17. package/dist/commands/agent-handshake.js +15 -18
  18. package/dist/commands/agent-handshake.js.map +1 -1
  19. package/dist/commands/agent.js +98 -104
  20. package/dist/commands/agent.js.map +1 -1
  21. package/dist/commands/agreements.js +62 -98
  22. package/dist/commands/agreements.js.map +1 -1
  23. package/dist/commands/arbitrator.js +45 -81
  24. package/dist/commands/arbitrator.js.map +1 -1
  25. package/dist/commands/arena-handshake.js +27 -30
  26. package/dist/commands/arena-handshake.js.map +1 -1
  27. package/dist/commands/arena.js +12 -18
  28. package/dist/commands/arena.js.map +1 -1
  29. package/dist/commands/backup.js +30 -36
  30. package/dist/commands/backup.js.map +1 -1
  31. package/dist/commands/cancel.js +15 -18
  32. package/dist/commands/cancel.js.map +1 -1
  33. package/dist/commands/channel.js +45 -81
  34. package/dist/commands/channel.js.map +1 -1
  35. package/dist/commands/coldstart.js +31 -34
  36. package/dist/commands/coldstart.js.map +1 -1
  37. package/dist/commands/config.js +23 -29
  38. package/dist/commands/config.js.map +1 -1
  39. package/dist/commands/contract-interaction.js +12 -15
  40. package/dist/commands/contract-interaction.js.map +1 -1
  41. package/dist/commands/daemon.d.ts.map +1 -1
  42. package/dist/commands/daemon.js +98 -135
  43. package/dist/commands/daemon.js.map +1 -1
  44. package/dist/commands/deliver.js +37 -76
  45. package/dist/commands/deliver.js.map +1 -1
  46. package/dist/commands/discover.js +24 -27
  47. package/dist/commands/discover.js.map +1 -1
  48. package/dist/commands/dispute.js +104 -110
  49. package/dist/commands/dispute.js.map +1 -1
  50. package/dist/commands/doctor.js +16 -55
  51. package/dist/commands/doctor.js.map +1 -1
  52. package/dist/commands/endpoint.js +56 -95
  53. package/dist/commands/endpoint.js.map +1 -1
  54. package/dist/commands/feed.js +11 -18
  55. package/dist/commands/feed.js.map +1 -1
  56. package/dist/commands/hire.js +37 -40
  57. package/dist/commands/hire.js.map +1 -1
  58. package/dist/commands/migrate.js +30 -33
  59. package/dist/commands/migrate.js.map +1 -1
  60. package/dist/commands/negotiate.d.ts.map +1 -1
  61. package/dist/commands/negotiate.js +34 -36
  62. package/dist/commands/negotiate.js.map +1 -1
  63. package/dist/commands/openshell.js +68 -104
  64. package/dist/commands/openshell.js.map +1 -1
  65. package/dist/commands/owner.js +17 -20
  66. package/dist/commands/owner.js.map +1 -1
  67. package/dist/commands/policy.js +41 -43
  68. package/dist/commands/policy.js.map +1 -1
  69. package/dist/commands/relay.d.ts.map +1 -1
  70. package/dist/commands/relay.js +18 -51
  71. package/dist/commands/relay.js.map +1 -1
  72. package/dist/commands/remediate.js +20 -23
  73. package/dist/commands/remediate.js.map +1 -1
  74. package/dist/commands/reputation.js +25 -27
  75. package/dist/commands/reputation.js.map +1 -1
  76. package/dist/commands/setup.js +65 -104
  77. package/dist/commands/setup.js.map +1 -1
  78. package/dist/commands/trust.js +17 -20
  79. package/dist/commands/trust.js.map +1 -1
  80. package/dist/commands/verify.js +18 -21
  81. package/dist/commands/verify.js.map +1 -1
  82. package/dist/commands/wallet.js +619 -625
  83. package/dist/commands/wallet.js.map +1 -1
  84. package/dist/commands/watch.js +33 -36
  85. package/dist/commands/watch.js.map +1 -1
  86. package/dist/commands/watchtower.js +37 -73
  87. package/dist/commands/watchtower.js.map +1 -1
  88. package/dist/commands/workroom.d.ts.map +1 -1
  89. package/dist/commands/workroom.js +138 -171
  90. package/dist/commands/workroom.js.map +1 -1
  91. package/dist/config.js +21 -65
  92. package/dist/config.js.map +1 -1
  93. package/dist/daemon/config.d.ts.map +1 -1
  94. package/dist/daemon/config.js +16 -53
  95. package/dist/daemon/config.js.map +1 -1
  96. package/dist/daemon/hire-listener.d.ts +3 -3
  97. package/dist/daemon/hire-listener.d.ts.map +1 -1
  98. package/dist/daemon/hire-listener.js +13 -47
  99. package/dist/daemon/hire-listener.js.map +1 -1
  100. package/dist/daemon/index.d.ts +1 -1
  101. package/dist/daemon/index.d.ts.map +1 -1
  102. package/dist/daemon/index.js +50 -88
  103. package/dist/daemon/index.js.map +1 -1
  104. package/dist/daemon/job-lifecycle.d.ts +1 -1
  105. package/dist/daemon/job-lifecycle.d.ts.map +1 -1
  106. package/dist/daemon/job-lifecycle.js +11 -51
  107. package/dist/daemon/job-lifecycle.js.map +1 -1
  108. package/dist/daemon/notify.d.ts +1 -1
  109. package/dist/daemon/notify.d.ts.map +1 -1
  110. package/dist/daemon/notify.js +19 -53
  111. package/dist/daemon/notify.js.map +1 -1
  112. package/dist/daemon/token-metering.js +8 -47
  113. package/dist/daemon/token-metering.js.map +1 -1
  114. package/dist/daemon/userops.d.ts +2 -2
  115. package/dist/daemon/userops.d.ts.map +1 -1
  116. package/dist/daemon/userops.js +23 -27
  117. package/dist/daemon/userops.js.map +1 -1
  118. package/dist/daemon/wallet-monitor.d.ts +1 -1
  119. package/dist/daemon/wallet-monitor.d.ts.map +1 -1
  120. package/dist/daemon/wallet-monitor.js +8 -12
  121. package/dist/daemon/wallet-monitor.js.map +1 -1
  122. package/dist/drain-v4.js +26 -64
  123. package/dist/drain-v4.js.map +1 -1
  124. package/dist/endpoint-config.js +20 -63
  125. package/dist/endpoint-config.js.map +1 -1
  126. package/dist/endpoint-notify.js +9 -48
  127. package/dist/endpoint-notify.js.map +1 -1
  128. package/dist/index.js +16 -50
  129. package/dist/index.js.map +1 -1
  130. package/dist/openshell-runtime.d.ts.map +1 -1
  131. package/dist/openshell-runtime.js +38 -82
  132. package/dist/openshell-runtime.js.map +1 -1
  133. package/dist/program.d.ts.map +1 -1
  134. package/dist/program.js +77 -83
  135. package/dist/program.js.map +1 -1
  136. package/dist/repl.js +25 -31
  137. package/dist/repl.js.map +1 -1
  138. package/dist/signing.js +3 -6
  139. package/dist/signing.js.map +1 -1
  140. package/dist/telegram-notify.js +3 -40
  141. package/dist/telegram-notify.js.map +1 -1
  142. package/dist/tui/App.d.ts +1 -9
  143. package/dist/tui/App.d.ts.map +1 -1
  144. package/dist/tui/App.js +87 -65
  145. package/dist/tui/App.js.map +1 -1
  146. package/dist/tui/Footer.js +4 -7
  147. package/dist/tui/Footer.js.map +1 -1
  148. package/dist/tui/Header.d.ts +1 -2
  149. package/dist/tui/Header.d.ts.map +1 -1
  150. package/dist/tui/Header.js +9 -14
  151. package/dist/tui/Header.js.map +1 -1
  152. package/dist/tui/InputLine.d.ts +1 -2
  153. package/dist/tui/InputLine.d.ts.map +1 -1
  154. package/dist/tui/InputLine.js +92 -46
  155. package/dist/tui/InputLine.js.map +1 -1
  156. package/dist/tui/Viewport.d.ts +5 -4
  157. package/dist/tui/Viewport.d.ts.map +1 -1
  158. package/dist/tui/Viewport.js +20 -13
  159. package/dist/tui/Viewport.js.map +1 -1
  160. package/dist/tui/WalletConnectPairing.d.ts +23 -0
  161. package/dist/tui/WalletConnectPairing.d.ts.map +1 -0
  162. package/dist/tui/WalletConnectPairing.js +75 -0
  163. package/dist/tui/WalletConnectPairing.js.map +1 -0
  164. package/dist/tui/components/Button.d.ts +7 -0
  165. package/dist/tui/components/Button.d.ts.map +1 -0
  166. package/dist/tui/components/Button.js +18 -0
  167. package/dist/tui/components/Button.js.map +1 -0
  168. package/dist/tui/components/CeremonyView.d.ts +13 -0
  169. package/dist/tui/components/CeremonyView.d.ts.map +1 -0
  170. package/dist/tui/components/CeremonyView.js +7 -0
  171. package/dist/tui/components/CeremonyView.js.map +1 -0
  172. package/dist/tui/components/CompletionDropdown.d.ts +7 -0
  173. package/dist/tui/components/CompletionDropdown.d.ts.map +1 -0
  174. package/dist/tui/components/CompletionDropdown.js +20 -0
  175. package/dist/tui/components/CompletionDropdown.js.map +1 -0
  176. package/dist/tui/components/ConfirmPrompt.d.ts +9 -0
  177. package/dist/tui/components/ConfirmPrompt.d.ts.map +1 -0
  178. package/dist/tui/components/ConfirmPrompt.js +7 -0
  179. package/dist/tui/components/ConfirmPrompt.js.map +1 -0
  180. package/dist/tui/components/InteractiveTable.d.ts +14 -0
  181. package/dist/tui/components/InteractiveTable.d.ts.map +1 -0
  182. package/dist/tui/components/InteractiveTable.js +58 -0
  183. package/dist/tui/components/InteractiveTable.js.map +1 -0
  184. package/dist/tui/components/StepSpinner.d.ts +11 -0
  185. package/dist/tui/components/StepSpinner.d.ts.map +1 -0
  186. package/dist/tui/components/StepSpinner.js +29 -0
  187. package/dist/tui/components/StepSpinner.js.map +1 -0
  188. package/dist/tui/components/Toast.d.ts +18 -0
  189. package/dist/tui/components/Toast.d.ts.map +1 -0
  190. package/dist/tui/components/Toast.js +25 -0
  191. package/dist/tui/components/Toast.js.map +1 -0
  192. package/dist/tui/index.d.ts.map +1 -1
  193. package/dist/tui/index.js +28 -21
  194. package/dist/tui/index.js.map +1 -1
  195. package/dist/tui/useChat.js +13 -19
  196. package/dist/tui/useChat.js.map +1 -1
  197. package/dist/tui/useCommand.d.ts +2 -7
  198. package/dist/tui/useCommand.d.ts.map +1 -1
  199. package/dist/tui/useCommand.js +77 -165
  200. package/dist/tui/useCommand.js.map +1 -1
  201. package/dist/tui/useNotifications.d.ts +9 -0
  202. package/dist/tui/useNotifications.d.ts.map +1 -0
  203. package/dist/tui/useNotifications.js +14 -0
  204. package/dist/tui/useNotifications.js.map +1 -0
  205. package/dist/tui/useScroll.js +9 -12
  206. package/dist/tui/useScroll.js.map +1 -1
  207. package/dist/ui/banner.d.ts +12 -0
  208. package/dist/ui/banner.d.ts.map +1 -1
  209. package/dist/ui/banner.js +35 -19
  210. package/dist/ui/banner.js.map +1 -1
  211. package/dist/ui/colors.js +13 -19
  212. package/dist/ui/colors.js.map +1 -1
  213. package/dist/ui/format.js +6 -14
  214. package/dist/ui/format.js.map +1 -1
  215. package/dist/ui/spinner.js +6 -12
  216. package/dist/ui/spinner.js.map +1 -1
  217. package/dist/ui/tree.js +3 -6
  218. package/dist/ui/tree.js.map +1 -1
  219. package/dist/utils/format.js +27 -41
  220. package/dist/utils/format.js.map +1 -1
  221. package/dist/utils/hash.js +4 -42
  222. package/dist/utils/hash.js.map +1 -1
  223. package/dist/utils/time.js +2 -6
  224. package/dist/utils/time.js.map +1 -1
  225. package/dist/wallet-router.d.ts +1 -1
  226. package/dist/wallet-router.d.ts.map +1 -1
  227. package/dist/wallet-router.js +12 -19
  228. package/dist/wallet-router.js.map +1 -1
  229. package/dist/walletconnect-session.d.ts +1 -1
  230. package/dist/walletconnect-session.d.ts.map +1 -1
  231. package/dist/walletconnect-session.js +6 -11
  232. package/dist/walletconnect-session.js.map +1 -1
  233. package/dist/walletconnect.d.ts +6 -1
  234. package/dist/walletconnect.d.ts.map +1 -1
  235. package/dist/walletconnect.js +32 -35
  236. package/dist/walletconnect.js.map +1 -1
  237. package/package.json +7 -6
  238. package/src/bundler.ts +1 -1
  239. package/src/client.ts +1 -1
  240. package/src/commands/accept.ts +7 -7
  241. package/src/commands/agent-handshake.ts +4 -4
  242. package/src/commands/agent.ts +9 -9
  243. package/src/commands/agreements.ts +8 -8
  244. package/src/commands/arbitrator.ts +5 -5
  245. package/src/commands/arena-handshake.ts +6 -6
  246. package/src/commands/arena.ts +2 -2
  247. package/src/commands/backup.ts +1 -1
  248. package/src/commands/cancel.ts +6 -6
  249. package/src/commands/channel.ts +6 -6
  250. package/src/commands/coldstart.ts +5 -5
  251. package/src/commands/config.ts +2 -2
  252. package/src/commands/contract-interaction.ts +2 -2
  253. package/src/commands/daemon.ts +14 -11
  254. package/src/commands/deliver.ts +9 -9
  255. package/src/commands/discover.ts +5 -5
  256. package/src/commands/dispute.ts +7 -7
  257. package/src/commands/doctor.ts +2 -2
  258. package/src/commands/endpoint.ts +6 -6
  259. package/src/commands/feed.ts +1 -1
  260. package/src/commands/hire.ts +10 -10
  261. package/src/commands/migrate.ts +7 -7
  262. package/src/commands/negotiate.ts +6 -5
  263. package/src/commands/openshell.ts +4 -4
  264. package/src/commands/owner.ts +5 -5
  265. package/src/commands/policy.ts +5 -5
  266. package/src/commands/relay.ts +5 -1
  267. package/src/commands/remediate.ts +5 -5
  268. package/src/commands/reputation.ts +6 -6
  269. package/src/commands/setup.ts +1 -1
  270. package/src/commands/trust.ts +6 -6
  271. package/src/commands/verify.ts +6 -6
  272. package/src/commands/wallet.ts +15 -15
  273. package/src/commands/watch.ts +3 -3
  274. package/src/commands/watchtower.ts +6 -6
  275. package/src/commands/workroom.ts +14 -10
  276. package/src/daemon/config.ts +2 -1
  277. package/src/daemon/hire-listener.ts +3 -3
  278. package/src/daemon/index.ts +10 -9
  279. package/src/daemon/job-lifecycle.ts +1 -1
  280. package/src/daemon/notify.ts +4 -4
  281. package/src/daemon/userops.ts +4 -4
  282. package/src/daemon/wallet-monitor.ts +2 -2
  283. package/src/endpoint-notify.ts +1 -1
  284. package/src/index.ts +8 -7
  285. package/src/openshell-runtime.ts +5 -1
  286. package/src/program.ts +36 -36
  287. package/src/repl.ts +3 -3
  288. package/src/tui/App.tsx +75 -52
  289. package/src/tui/Header.tsx +26 -12
  290. package/src/tui/InputLine.tsx +108 -33
  291. package/src/tui/Viewport.tsx +22 -18
  292. package/src/tui/WalletConnectPairing.tsx +131 -0
  293. package/src/tui/components/Button.tsx +38 -0
  294. package/src/tui/components/CeremonyView.tsx +39 -0
  295. package/src/tui/components/CompletionDropdown.tsx +59 -0
  296. package/src/tui/components/ConfirmPrompt.tsx +36 -0
  297. package/src/tui/components/InteractiveTable.tsx +112 -0
  298. package/src/tui/components/StepSpinner.tsx +84 -0
  299. package/src/tui/components/Toast.tsx +59 -0
  300. package/src/tui/index.tsx +27 -9
  301. package/src/tui/useChat.ts +1 -1
  302. package/src/tui/useCommand.ts +86 -183
  303. package/src/tui/useNotifications.ts +28 -0
  304. package/src/ui/banner.ts +29 -2
  305. package/src/ui/tree.ts +1 -1
  306. package/src/wallet-router.ts +2 -2
  307. package/src/walletconnect-session.ts +1 -1
  308. package/src/walletconnect.ts +20 -5
  309. package/tsconfig.json +16 -7
@@ -1,4 +1,5 @@
1
1
  import { Command } from "commander";
2
+ import * as crypto from "node:crypto";
2
3
  import * as fs from "fs";
3
4
  import * as path from "path";
4
5
  import * as os from "os";
@@ -7,12 +8,16 @@ import { spawnSync, execSync } from "child_process";
7
8
  import {
8
9
  ARC402_DIR,
9
10
  runCmd,
10
- } from "../openshell-runtime";
11
- import { DAEMON_LOG, DAEMON_TOML } from "../daemon/config";
12
- import { c } from "../ui/colors";
13
- import { startSpinner } from "../ui/spinner";
14
- import { renderTree } from "../ui/tree";
15
- import { formatAddress } from "../ui/format";
11
+ } from "../openshell-runtime.js";
12
+ import { DAEMON_LOG, DAEMON_TOML, loadDaemonConfig } from "../daemon/config.js";
13
+ import { c } from "../ui/colors.js";
14
+ import { startSpinner } from "../ui/spinner.js";
15
+ import { renderTree } from "../ui/tree.js";
16
+ import { formatAddress } from "../ui/format.js";
17
+
18
+ import { fileURLToPath } from "node:url";
19
+ const __filename = fileURLToPath(import.meta.url);
20
+ const __dirname = path.dirname(__filename);
16
21
 
17
22
  // ─── Daemon lifecycle notify ──────────────────────────────────────────────────
18
23
 
@@ -27,7 +32,6 @@ function notifyDaemonWorkroomStatus(
27
32
  let daemonPort = port;
28
33
  if (fs.existsSync(DAEMON_TOML)) {
29
34
  try {
30
- const { loadDaemonConfig } = require("../daemon/config") as typeof import("../daemon/config");
31
35
  const cfg = loadDaemonConfig();
32
36
  daemonPort = cfg.relay?.listen_port ?? port;
33
37
  } catch { /* use default */ }
@@ -101,7 +105,7 @@ function buildImage(): boolean {
101
105
  function getPolicyHash(): string {
102
106
  if (!fs.existsSync(POLICY_FILE)) return "(no policy file)";
103
107
  const content = fs.readFileSync(POLICY_FILE, "utf-8");
104
- const crypto = require("crypto");
108
+ // crypto imported at top level
105
109
  return "0x" + crypto.createHash("sha256").update(content).digest("hex").slice(0, 16);
106
110
  }
107
111
 
@@ -131,7 +135,7 @@ export function registerWorkroomCommands(program: Command): void {
131
135
  if (!fs.existsSync(POLICY_FILE)) {
132
136
  console.log(c.dim("No policy file found. Generating default..."));
133
137
  // Import and call the existing policy generator
134
- const { registerOpenShellCommands } = require("./openshell");
138
+ const { registerOpenShellCommands } = await import("./openshell.js");
135
139
  console.log(c.dim(`Policy file will be generated at: ${POLICY_FILE}`));
136
140
  console.log(c.dim("Run 'arc402 workroom policy preset core-launch' after init to apply defaults."));
137
141
  } else {
@@ -797,7 +801,7 @@ No learnings yet. Complete your first hired task to start accumulating expertise
797
801
  .command("token-usage [agreementId]")
798
802
  .description("Show token usage for a specific agreement or across all jobs.")
799
803
  .action(async (agreementId) => {
800
- const { readUsageReport, formatUsageReport } = require("../daemon/token-metering");
804
+ const { readUsageReport, formatUsageReport } = await import("../daemon/token-metering.js");
801
805
 
802
806
  if (agreementId) {
803
807
  const usage = readUsageReport(agreementId);
@@ -6,6 +6,7 @@
6
6
  import * as fs from "fs";
7
7
  import * as path from "path";
8
8
  import * as os from "os";
9
+ import { ethers } from "ethers";
9
10
  import { parse as parseToml } from "smol-toml";
10
11
 
11
12
  export const DAEMON_DIR = path.join(os.homedir(), ".arc402");
@@ -249,7 +250,7 @@ export function loadMachineKey(config: DaemonConfig): { privateKey: string; addr
249
250
  throw new Error(`Machine key not found. Set environment variable: ${envVarName}`);
250
251
  }
251
252
 
252
- const { ethers } = require("ethers") as typeof import("ethers");
253
+ // ethers imported at top level
253
254
  let address: string;
254
255
  try {
255
256
  const w = new ethers.Wallet(privateKey);
@@ -5,9 +5,9 @@
5
5
  import * as http from "http";
6
6
  import * as https from "https";
7
7
  import { ethers } from "ethers";
8
- import type { DaemonConfig } from "./config";
9
- import type { DaemonDB } from "./index";
10
- import type { Notifier } from "./notify";
8
+ import type { DaemonConfig } from "./config.js";
9
+ import type { DaemonDB } from "./index.js";
10
+ import type { Notifier } from "./notify.js";
11
11
 
12
12
  export interface HireProposal {
13
13
  messageId: string;
@@ -8,6 +8,7 @@
8
8
  * Signals: SIGTERM → graceful shutdown.
9
9
  */
10
10
  import * as fs from "fs";
11
+ import * as os from "os";
11
12
  import * as path from "path";
12
13
  import * as net from "net";
13
14
  import * as http from "http";
@@ -25,12 +26,12 @@ import {
25
26
  DAEMON_DB,
26
27
  DAEMON_SOCK,
27
28
  type DaemonConfig,
28
- } from "./config";
29
- import { verifyWallet, getWalletBalance } from "./wallet-monitor";
30
- import { buildNotifier } from "./notify";
31
- import { HireListener } from "./hire-listener";
32
- import { UserOpsManager, buildAcceptCalldata } from "./userops";
33
- import { generateReceipt, extractLearnings, createJobDirectory, cleanJobDirectory } from "./job-lifecycle";
29
+ } from "./config.js";
30
+ import { verifyWallet, getWalletBalance } from "./wallet-monitor.js";
31
+ import { buildNotifier } from "./notify.js";
32
+ import { HireListener } from "./hire-listener.js";
33
+ import { UserOpsManager, buildAcceptCalldata } from "./userops.js";
34
+ import { generateReceipt, extractLearnings, createJobDirectory, cleanJobDirectory } from "./job-lifecycle.js";
34
35
 
35
36
  // ─── State DB ─────────────────────────────────────────────────────────────────
36
37
 
@@ -432,7 +433,7 @@ function formatUptime(seconds: number): string {
432
433
  // ─── Daemon main ──────────────────────────────────────────────────────────────
433
434
 
434
435
  // Extend config with serviceAgreementAddress (loaded from CLI config if available)
435
- declare module "./config" {
436
+ declare module "./config.js" {
436
437
  interface DaemonConfig {
437
438
  serviceAgreementAddress?: string;
438
439
  }
@@ -448,7 +449,7 @@ export async function runDaemon(foreground = false): Promise<void> {
448
449
  let config: DaemonConfig;
449
450
  try {
450
451
  config = loadDaemonConfig();
451
- log({ event: "config_loaded", path: require("path").join(require("os").homedir(), ".arc402", "daemon.toml") });
452
+ log({ event: "config_loaded", path: path.join(os.homedir(), ".arc402", "daemon.toml") });
452
453
  } catch (err) {
453
454
  process.stderr.write(`Config error: ${err}\n`);
454
455
  process.exit(1);
@@ -763,7 +764,7 @@ export async function runDaemon(foreground = false): Promise<void> {
763
764
  }
764
765
 
765
766
  // Policy check
766
- const { evaluatePolicy } = await import("./hire-listener");
767
+ const { evaluatePolicy } = await import("./hire-listener.js");
767
768
  const activeCount = db.countActiveHireRequests();
768
769
  const policyResult = evaluatePolicy(proposal, config, activeCount);
769
770
 
@@ -13,7 +13,7 @@ import * as fs from "fs";
13
13
  import * as path from "path";
14
14
  import * as os from "os";
15
15
  import * as crypto from "crypto";
16
- import { readUsageReport, type AggregatedTokenUsage } from "./token-metering";
16
+ import { readUsageReport, type AggregatedTokenUsage } from "./token-metering.js";
17
17
 
18
18
  const ARC402_DIR = path.join(os.homedir(), ".arc402");
19
19
  const RECEIPTS_DIR = path.join(ARC402_DIR, "receipts");
@@ -4,7 +4,7 @@
4
4
  */
5
5
  import * as https from "https";
6
6
  import * as http from "http";
7
- import type { DaemonConfig } from "./config";
7
+ import type { DaemonConfig } from "./config.js";
8
8
 
9
9
  export type NotifyEvent =
10
10
  | "hire_request"
@@ -133,11 +133,11 @@ export class EmailChannel implements NotificationChannel {
133
133
  async send(title: string, body: string): Promise<void> {
134
134
  // nodemailer is an optional runtime dependency — load via require to skip
135
135
  // compile-time module resolution. Throws a clear message if not installed.
136
- // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-explicit-any
136
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
137
137
  let nodemailer: any;
138
138
  try {
139
- // Using Function constructor avoids TypeScript static import analysis.
140
- nodemailer = (new Function("require", "return require('nodemailer')"))(require);
139
+ // @ts-expect-error nodemailer is an optional dependency
140
+ nodemailer = await import("nodemailer");
141
141
  } catch {
142
142
  throw new Error("nodemailer is not installed. Run: npm install nodemailer");
143
143
  }
@@ -3,10 +3,10 @@
3
3
  * Wraps protocol calls (accept, fulfill) into ERC-4337 UserOperations.
4
4
  */
5
5
  import { ethers } from "ethers";
6
- import { BundlerClient } from "../bundler";
7
- import type { UserOperation } from "../bundler";
8
- import type { DaemonConfig } from "./config";
9
- import { ARC402_WALLET_EXECUTE_ABI } from "../abis";
6
+ import { BundlerClient } from "../bundler.js";
7
+ import type { UserOperation } from "../bundler.js";
8
+ import type { DaemonConfig } from "./config.js";
9
+ import { ARC402_WALLET_EXECUTE_ABI } from "../abis.js";
10
10
 
11
11
  // ServiceAgreement calldata encoders
12
12
  const SA_IFACE = new ethers.Interface([
@@ -3,11 +3,11 @@
3
3
  * Steps 4 and 5 of the daemon startup sequence (Spec 32 §3).
4
4
  */
5
5
  import { ethers } from "ethers";
6
- import type { DaemonConfig } from "./config";
6
+ import type { DaemonConfig } from "./config.js";
7
7
  import {
8
8
  ARC402_WALLET_GUARDIAN_ABI,
9
9
  ARC402_WALLET_MACHINE_KEY_ABI,
10
- } from "../abis";
10
+ } from "../abis.js";
11
11
 
12
12
  export interface WalletStatus {
13
13
  contractAddress: string;
@@ -4,7 +4,7 @@
4
4
  * and POSTs lifecycle events after onchain transactions.
5
5
  */
6
6
  import { ethers } from "ethers";
7
- import { AGENT_REGISTRY_ABI } from "./abis";
7
+ import { AGENT_REGISTRY_ABI } from "./abis.js";
8
8
  import * as dns from "dns/promises";
9
9
 
10
10
  export const DEFAULT_REGISTRY_ADDRESS = "0xD5c2851B00090c92Ba7F4723FB548bb30C9B6865";
package/src/index.ts CHANGED
@@ -1,11 +1,12 @@
1
1
  #!/usr/bin/env node
2
- import { createProgram } from "./program";
3
- import { startREPL } from "./repl";
4
- import { configExists, loadConfig, saveConfig } from "./config";
2
+ import { createRequire } from "node:module";
3
+ import { createProgram } from "./program.js";
4
+ import { startREPL } from "./repl.js";
5
+ import { configExists, loadConfig, saveConfig } from "./config.js";
5
6
 
6
7
  // ── Upgrade safety check ────────────────────────────────────────────────────
7
- // eslint-disable-next-line @typescript-eslint/no-var-requires
8
- const currentVersion: string = (require("../package.json") as { version: string }).version;
8
+ const _require = createRequire(import.meta.url);
9
+ const currentVersion: string = (_require("../package.json") as { version: string }).version;
9
10
 
10
11
  function checkUpgrade(): void {
11
12
  if (!configExists()) return;
@@ -53,9 +54,9 @@ if (printMode) {
53
54
  process.exit(1);
54
55
  });
55
56
  } else if (process.stdout.isTTY && !hasSubcommand && process.argv.length <= 2 && !process.env.ARC402_NO_TUI) {
56
- // TTY with no subcommand — launch Ink TUI (unless spawned by TUI as a child process)
57
+ // TTY with no subcommand — launch Ink TUI
57
58
  checkUpgrade();
58
- void import("./tui/index").then(({ launchTUI }) => launchTUI()).catch((e: unknown) => {
59
+ void import("./tui/index.js").then(({ launchTUI }) => launchTUI()).catch((e: unknown) => {
59
60
  console.error("TUI failed to start:", e instanceof Error ? e.message : String(e));
60
61
  // Fallback to REPL
61
62
  void startREPL();
@@ -3,7 +3,11 @@ import * as os from "os";
3
3
  import * as path from "path";
4
4
  import { spawnSync } from "child_process";
5
5
  import { parse as parseToml } from "smol-toml";
6
- import { loadConfig } from "./config";
6
+ import { loadConfig } from "./config.js";
7
+
8
+ import { fileURLToPath } from "node:url";
9
+ const __filename = fileURLToPath(import.meta.url);
10
+ const __dirname = path.dirname(__filename);
7
11
 
8
12
  export const ARC402_DIR = path.join(os.homedir(), ".arc402");
9
13
  export const OPENSHELL_TOML = path.join(ARC402_DIR, "openshell.toml");
package/src/program.ts CHANGED
@@ -1,38 +1,39 @@
1
+ import { createRequire } from "node:module";
1
2
  import { Command } from "commander";
2
- import { registerAcceptCommand } from "./commands/accept";
3
- import { registerAgentCommands } from "./commands/agent";
4
- import { registerAgreementsCommands } from "./commands/agreements";
5
- import { registerArbitratorCommand } from "./commands/arbitrator";
6
- import { registerCancelCommand } from "./commands/cancel";
7
- import { registerChannelCommands } from "./commands/channel";
8
- import { registerConfigCommands } from "./commands/config";
9
- import { registerDeliverCommand } from "./commands/deliver";
10
- import { registerDiscoverCommand } from "./commands/discover";
11
- import { registerEndpointCommands } from "./commands/endpoint";
12
- import { registerDisputeCommand } from "./commands/dispute";
13
- import { registerHireCommand } from "./commands/hire";
14
- import { registerHandshakeCommand } from "./commands/agent-handshake";
15
- import { registerNegotiateCommands } from "./commands/negotiate";
16
- import { registerRelayCommands } from "./commands/relay";
17
- import { registerRemediateCommands } from "./commands/remediate";
18
- import { registerDaemonCommands } from "./commands/daemon";
19
- import { registerOpenShellCommands } from "./commands/openshell";
20
- import { registerWorkroomCommands } from "./commands/workroom";
21
- import { registerArenaHandshakeCommands } from "./commands/arena-handshake";
22
- import { registerTrustCommand } from "./commands/trust";
23
- import { registerWalletCommands } from "./commands/wallet";
24
- import { registerOwnerCommands } from "./commands/owner";
25
- import { registerSetupCommands } from "./commands/setup";
26
- import { registerVerifyCommand } from "./commands/verify";
27
- import { registerContractInteractionCommands } from "./commands/contract-interaction";
28
- import { registerWatchtowerCommands } from "./commands/watchtower";
29
- import { registerColdStartCommands } from "./commands/coldstart";
30
- import { registerDoctorCommand } from "./commands/doctor";
31
- import { registerMigrateCommands } from "./commands/migrate";
32
- import { registerFeedCommand } from "./commands/feed";
33
- import { registerArenaCommands } from "./commands/arena";
34
- import { registerWatchCommand } from "./commands/watch";
35
- import { registerBackupCommand } from "./commands/backup";
3
+ import { registerAcceptCommand } from "./commands/accept.js";
4
+ import { registerAgentCommands } from "./commands/agent.js";
5
+ import { registerAgreementsCommands } from "./commands/agreements.js";
6
+ import { registerArbitratorCommand } from "./commands/arbitrator.js";
7
+ import { registerCancelCommand } from "./commands/cancel.js";
8
+ import { registerChannelCommands } from "./commands/channel.js";
9
+ import { registerConfigCommands } from "./commands/config.js";
10
+ import { registerDeliverCommand } from "./commands/deliver.js";
11
+ import { registerDiscoverCommand } from "./commands/discover.js";
12
+ import { registerEndpointCommands } from "./commands/endpoint.js";
13
+ import { registerDisputeCommand } from "./commands/dispute.js";
14
+ import { registerHireCommand } from "./commands/hire.js";
15
+ import { registerHandshakeCommand } from "./commands/agent-handshake.js";
16
+ import { registerNegotiateCommands } from "./commands/negotiate.js";
17
+ import { registerRelayCommands } from "./commands/relay.js";
18
+ import { registerRemediateCommands } from "./commands/remediate.js";
19
+ import { registerDaemonCommands } from "./commands/daemon.js";
20
+ import { registerOpenShellCommands } from "./commands/openshell.js";
21
+ import { registerWorkroomCommands } from "./commands/workroom.js";
22
+ import { registerArenaHandshakeCommands } from "./commands/arena-handshake.js";
23
+ import { registerTrustCommand } from "./commands/trust.js";
24
+ import { registerWalletCommands } from "./commands/wallet.js";
25
+ import { registerOwnerCommands } from "./commands/owner.js";
26
+ import { registerSetupCommands } from "./commands/setup.js";
27
+ import { registerVerifyCommand } from "./commands/verify.js";
28
+ import { registerContractInteractionCommands } from "./commands/contract-interaction.js";
29
+ import { registerWatchtowerCommands } from "./commands/watchtower.js";
30
+ import { registerColdStartCommands } from "./commands/coldstart.js";
31
+ import { registerDoctorCommand } from "./commands/doctor.js";
32
+ import { registerMigrateCommands } from "./commands/migrate.js";
33
+ import { registerFeedCommand } from "./commands/feed.js";
34
+ import { registerArenaCommands } from "./commands/arena.js";
35
+ import { registerWatchCommand } from "./commands/watch.js";
36
+ import { registerBackupCommand } from "./commands/backup.js";
36
37
  import reputation from "./commands/reputation.js";
37
38
  import policy from "./commands/policy.js";
38
39
 
@@ -43,8 +44,7 @@ export function createProgram(): Command {
43
44
  .description(
44
45
  "ARC-402 CLI aligned to canonical-capability discovery → negotiate → hire → remediate → dispute workflow"
45
46
  )
46
- // eslint-disable-next-line @typescript-eslint/no-var-requires
47
- .version((require("../package.json") as { version: string }).version);
47
+ .version((createRequire(import.meta.url)("../package.json") as { version: string }).version);
48
48
 
49
49
  registerConfigCommands(program);
50
50
  registerHandshakeCommand(program);
package/src/repl.ts CHANGED
@@ -3,9 +3,9 @@ import fs from "fs";
3
3
  import path from "path";
4
4
  import os from "os";
5
5
  import readline from "readline";
6
- import { createProgram } from "./program";
7
- import { getBannerLines, BannerConfig } from "./ui/banner";
8
- import { c } from "./ui/colors";
6
+ import { createProgram } from "./program.js";
7
+ import { getBannerLines, BannerConfig } from "./ui/banner.js";
8
+ import { c } from "./ui/colors.js";
9
9
 
10
10
  // ─── Config helpers ────────────────────────────────────────────────────────────
11
11
 
package/src/tui/App.tsx CHANGED
@@ -1,14 +1,20 @@
1
- import React, { useState, useCallback } from "react";
2
- import { Box, Text, useApp, useStdout } from "ink";
3
- import { Header } from "./Header";
4
- import { Viewport } from "./Viewport";
5
- import { InputLine } from "./InputLine";
6
- import { useCommand } from "./useCommand";
7
- import { useChat } from "./useChat";
8
- import { useScroll } from "./useScroll";
9
- import { createProgram } from "../program";
1
+ import React, { useState, useCallback, useEffect } from "react";
2
+ import { createRequire } from "node:module";
3
+ import { Box, Text, Static, useApp, useInput } from "ink";
4
+ import { Viewport } from "./Viewport.js";
5
+ import { Footer } from "./Footer.js";
6
+ import { InputLine } from "./InputLine.js";
7
+ import { useCommand } from "./useCommand.js";
8
+ import { useChat } from "./useChat.js";
9
+ import { useScroll } from "./useScroll.js";
10
+ import { useNotifications } from "./useNotifications.js";
11
+ import { ToastContainer } from "./components/Toast.js";
12
+ import { createProgram } from "../program.js";
13
+ import { getBannerArt, getStatusItems } from "../ui/banner.js";
10
14
  import chalk from "chalk";
11
15
 
16
+ const pkg = createRequire(import.meta.url)("../../package.json") as { version: string };
17
+
12
18
  const BUILTIN_CMDS = ["help", "exit", "quit", "clear", "status"];
13
19
 
14
20
  interface AppProps {
@@ -19,22 +25,35 @@ interface AppProps {
19
25
  }
20
26
 
21
27
  /**
22
- * Root TUI component — box-drawn frame with fixed header/footer, scrollable viewport.
23
- *
24
- * ┌─────────────────────────────────────────────┐
25
- * │ ASCII banner + status info │ ← FIXED header
26
- * ├─────────────────────────────────────────────┤
27
- * │ scrollable output │ ← VIEWPORT
28
- * ├─────────────────────────────────────────────┤
29
- * │ ◈ arc402 > _ │ ← FIXED footer
30
- * └─────────────────────────────────────────────┘
28
+ * Root TUI component — fixed header/footer with scrollable viewport.
31
29
  */
32
30
  export function App({ version, network, wallet, balance }: AppProps) {
33
31
  const { exit } = useApp();
34
- const { stdout } = useStdout();
35
- const cols = stdout?.columns ?? 60;
36
- const W = Math.min(cols, 80); // inner width between │ chars
37
- const inner = W - 2; // space between the two │ border chars
32
+
33
+ // Banner computed once rendered via <Static> so it never re-renders
34
+ const [bannerData] = useState(() => {
35
+ const { artLines, subtitle, separator } = getBannerArt();
36
+ const statusItems = getStatusItems({ network, wallet, balance });
37
+ // Build static items: art lines + subtitle + separator + status + help hint
38
+ const items: { id: string; text: string }[] = [];
39
+ artLines.forEach((line, i) => items.push({ id: `art-${i}`, text: line }));
40
+ items.push({ id: "blank-1", text: "" });
41
+ items.push({ id: "subtitle", text: subtitle });
42
+ items.push({ id: "separator", text: separator });
43
+ if (statusItems.length > 0) {
44
+ items.push({ id: "blank-2", text: "" });
45
+ // Status items as a single formatted line for <Static>
46
+ // (FlexWrap rendering happens in the Header component for non-Static contexts)
47
+ const statusLine = statusItems
48
+ .map((s) => `\x1b[2m${s.label}\x1b[22m ${s.value}`)
49
+ .join(" ");
50
+ items.push({ id: "status", text: ` ${statusLine}` });
51
+ }
52
+ items.push({ id: "blank-3", text: "" });
53
+ items.push({ id: "hint", text: " \x1b[2mType 'help' to get started\x1b[22m" });
54
+ items.push({ id: "blank-4", text: "" });
55
+ return items;
56
+ });
38
57
 
39
58
  const [outputBuffer, setOutputBuffer] = useState<string[]>([
40
59
  chalk.dim(" Type 'help' to see available commands"),
@@ -46,14 +65,16 @@ export function App({ version, network, wallet, balance }: AppProps) {
46
65
  const { send, isSending } = useChat();
47
66
 
48
67
  // Approximate viewport height for scroll management
49
- const HEADER_ROWS = 17;
50
- const FOOTER_ROWS = 3;
68
+ const HEADER_ROWS = 15;
69
+ const FOOTER_ROWS = 1;
51
70
  const rows = process.stdout.rows ?? 24;
52
71
  const viewportHeight = Math.max(1, rows - HEADER_ROWS - FOOTER_ROWS);
53
72
 
54
73
  const { scrollOffset, isAutoScroll, scrollUp, scrollDown, snapToBottom } =
55
74
  useScroll(viewportHeight);
56
75
 
76
+ const { toasts, dismiss: dismissToast } = useNotifications();
77
+
57
78
  // Get top-level command names for dispatch detection
58
79
  const [topCmds] = useState<string[]>(() => {
59
80
  try {
@@ -64,6 +85,20 @@ export function App({ version, network, wallet, balance }: AppProps) {
64
85
  }
65
86
  });
66
87
 
88
+ // ── Enhanced keyboard shortcuts ────────────────────────────────────────
89
+ useInput((input, key) => {
90
+ // Ctrl+L — clear viewport
91
+ if (key.ctrl && input === "l") {
92
+ setOutputBuffer([]);
93
+ return;
94
+ }
95
+ // Escape — cancel / clear (snap to bottom if scrolled)
96
+ if (key.escape) {
97
+ snapToBottom();
98
+ return;
99
+ }
100
+ });
101
+
67
102
  const appendLine = useCallback((line: string) => {
68
103
  setOutputBuffer((prev) => [...prev, line]);
69
104
  }, []);
@@ -192,49 +227,37 @@ export function App({ version, network, wallet, balance }: AppProps) {
192
227
 
193
228
  const isDisabled = isProcessing || isRunning || isSending;
194
229
 
195
- const topBorder = "┌" + "─".repeat(inner) + "┐";
196
- const midBorder = "├" + "─".repeat(inner) + "┤";
197
- const botBorder = "└" + "─".repeat(inner) + "┘";
198
-
199
230
  return (
200
231
  <Box flexDirection="column" height="100%">
201
- {/* Top border */}
202
- <Text dimColor>{topBorder}</Text>
203
-
204
- {/* HEADER — fixed, never scrolls */}
205
- <Header
206
- version={version}
207
- network={network}
208
- wallet={wallet}
209
- balance={balance}
210
- innerWidth={inner}
211
- />
232
+ {/* BANNER rendered once via <Static>, never re-renders */}
233
+ <Static items={bannerData}>
234
+ {(item) => <Text key={item.id}>{item.text}</Text>}
235
+ </Static>
212
236
 
213
- {/* Mid separator */}
214
- <Text dimColor>{midBorder}</Text>
237
+ {/* Separator */}
238
+ <Box>
239
+ <Text dimColor>{"─".repeat(60)}</Text>
240
+ </Box>
215
241
 
216
242
  {/* VIEWPORT — fills remaining space */}
217
243
  <Viewport
218
244
  lines={outputBuffer}
219
245
  scrollOffset={scrollOffset}
220
246
  isAutoScroll={isAutoScroll}
221
- innerWidth={inner}
222
247
  />
223
248
 
224
- {/* Footer separator */}
225
- <Text dimColor>{midBorder}</Text>
249
+ {/* Notification toasts — above footer */}
250
+ <ToastContainer toasts={toasts} onDismiss={dismissToast} />
226
251
 
227
- {/* FOOTER input pinned */}
252
+ {/* Bottom separator */}
228
253
  <Box>
229
- <Text dimColor>│</Text>
230
- <Box flexGrow={1}>
231
- <InputLine onSubmit={handleCommand} isDisabled={isDisabled} />
232
- </Box>
233
- <Text dimColor>│</Text>
254
+ <Text dimColor>{"─".repeat(60)}</Text>
234
255
  </Box>
235
256
 
236
- {/* Bottom border */}
237
- <Text dimColor>{botBorder}</Text>
257
+ {/* FOOTER fixed, input pinned */}
258
+ <Footer>
259
+ <InputLine onSubmit={handleCommand} isDisabled={isDisabled} />
260
+ </Footer>
238
261
  </Box>
239
262
  );
240
263
  }
@@ -1,37 +1,51 @@
1
1
  import React from "react";
2
2
  import { Box, Text } from "ink";
3
- import { getBannerLines } from "../ui/banner";
3
+ import { getBannerArt, getStatusItems } from "../ui/banner.js";
4
+ import type { BannerConfig } from "../ui/banner.js";
4
5
 
5
6
  interface HeaderProps {
6
7
  version: string;
7
8
  network?: string;
8
9
  wallet?: string;
9
10
  balance?: string;
10
- innerWidth?: number;
11
11
  }
12
12
 
13
13
  /**
14
14
  * Fixed header showing the ASCII art banner + status info.
15
- * Each line is framed with box-drawing borders.
15
+ * Status items use flexWrap to adapt to narrow terminals.
16
16
  */
17
17
  export const Header = React.memo(function Header({
18
18
  network,
19
19
  wallet,
20
20
  balance,
21
- innerWidth = 58,
22
21
  }: HeaderProps) {
23
- const bannerLines = getBannerLines({ network, wallet, balance });
22
+ const { artLines, subtitle, separator } = getBannerArt();
23
+ const statusItems = getStatusItems({ network, wallet, balance });
24
24
 
25
25
  return (
26
26
  <Box flexDirection="column">
27
- {bannerLines.map((line, i) => (
28
- <Box key={i}>
29
- <Text dimColor>│</Text>
30
- <Text>{" " + line}</Text>
31
- <Box flexGrow={1} />
32
- <Text dimColor>│</Text>
33
- </Box>
27
+ {artLines.map((line, i) => (
28
+ <Text key={i}>{line}</Text>
34
29
  ))}
30
+ <Text>{""}</Text>
31
+ <Text>{subtitle}</Text>
32
+ <Text>{separator}</Text>
33
+ {statusItems.length > 0 && (
34
+ <>
35
+ <Text>{""}</Text>
36
+ <Box flexWrap="wrap" columnGap={2}>
37
+ {statusItems.map((item) => (
38
+ <Box key={item.label}>
39
+ <Text dimColor>{item.label}</Text>
40
+ <Text> {item.value}</Text>
41
+ </Box>
42
+ ))}
43
+ </Box>
44
+ </>
45
+ )}
46
+ <Text>{""}</Text>
47
+ <Text dimColor>{" Type 'help' to get started"}</Text>
48
+ <Text>{""}</Text>
35
49
  </Box>
36
50
  );
37
51
  });