arc402-cli 0.4.0 → 0.4.2

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 (87) hide show
  1. package/dist/commands/arbitrator.d.ts.map +1 -1
  2. package/dist/commands/arbitrator.js +62 -13
  3. package/dist/commands/arbitrator.js.map +1 -1
  4. package/dist/commands/arena.d.ts.map +1 -1
  5. package/dist/commands/arena.js +4 -3
  6. package/dist/commands/arena.js.map +1 -1
  7. package/dist/commands/cancel.d.ts.map +1 -1
  8. package/dist/commands/cancel.js +20 -10
  9. package/dist/commands/cancel.js.map +1 -1
  10. package/dist/commands/config.d.ts.map +1 -1
  11. package/dist/commands/config.js +1 -0
  12. package/dist/commands/config.js.map +1 -1
  13. package/dist/commands/deliver.d.ts.map +1 -1
  14. package/dist/commands/deliver.js +16 -3
  15. package/dist/commands/deliver.js.map +1 -1
  16. package/dist/commands/discover.d.ts.map +1 -1
  17. package/dist/commands/discover.js +2 -0
  18. package/dist/commands/discover.js.map +1 -1
  19. package/dist/commands/dispute.d.ts.map +1 -1
  20. package/dist/commands/dispute.js +11 -10
  21. package/dist/commands/dispute.js.map +1 -1
  22. package/dist/commands/hire.d.ts.map +1 -1
  23. package/dist/commands/hire.js +12 -2
  24. package/dist/commands/hire.js.map +1 -1
  25. package/dist/commands/migrate.d.ts.map +1 -1
  26. package/dist/commands/migrate.js +29 -29
  27. package/dist/commands/migrate.js.map +1 -1
  28. package/dist/commands/negotiate.d.ts.map +1 -1
  29. package/dist/commands/negotiate.js +8 -7
  30. package/dist/commands/negotiate.js.map +1 -1
  31. package/dist/commands/openshell.d.ts.map +1 -1
  32. package/dist/commands/openshell.js +6 -5
  33. package/dist/commands/openshell.js.map +1 -1
  34. package/dist/commands/owner.d.ts.map +1 -1
  35. package/dist/commands/owner.js +2 -1
  36. package/dist/commands/owner.js.map +1 -1
  37. package/dist/commands/policy.d.ts.map +1 -1
  38. package/dist/commands/policy.js +22 -10
  39. package/dist/commands/policy.js.map +1 -1
  40. package/dist/commands/relay.js +6 -5
  41. package/dist/commands/relay.js.map +1 -1
  42. package/dist/commands/remediate.js +3 -2
  43. package/dist/commands/remediate.js.map +1 -1
  44. package/dist/commands/reputation.d.ts.map +1 -1
  45. package/dist/commands/reputation.js +12 -5
  46. package/dist/commands/reputation.js.map +1 -1
  47. package/dist/commands/trust.d.ts.map +1 -1
  48. package/dist/commands/trust.js +16 -1
  49. package/dist/commands/trust.js.map +1 -1
  50. package/dist/commands/verify.d.ts.map +1 -1
  51. package/dist/commands/verify.js +6 -4
  52. package/dist/commands/verify.js.map +1 -1
  53. package/dist/commands/wallet.d.ts.map +1 -1
  54. package/dist/commands/wallet.js +202 -165
  55. package/dist/commands/wallet.js.map +1 -1
  56. package/dist/commands/watchtower.d.ts.map +1 -1
  57. package/dist/commands/watchtower.js +30 -13
  58. package/dist/commands/watchtower.js.map +1 -1
  59. package/dist/commands/workroom.d.ts.map +1 -1
  60. package/dist/commands/workroom.js +123 -95
  61. package/dist/commands/workroom.js.map +1 -1
  62. package/dist/config.d.ts.map +1 -1
  63. package/dist/config.js +1 -0
  64. package/dist/config.js.map +1 -1
  65. package/package.json +1 -1
  66. package/src/commands/arbitrator.ts +45 -10
  67. package/src/commands/arena.ts +4 -3
  68. package/src/commands/cancel.ts +19 -10
  69. package/src/commands/config.ts +1 -0
  70. package/src/commands/deliver.ts +16 -3
  71. package/src/commands/discover.ts +2 -0
  72. package/src/commands/dispute.ts +12 -10
  73. package/src/commands/hire.ts +9 -2
  74. package/src/commands/migrate.ts +28 -26
  75. package/src/commands/negotiate.ts +8 -7
  76. package/src/commands/openshell.ts +7 -5
  77. package/src/commands/owner.ts +2 -1
  78. package/src/commands/policy.ts +18 -10
  79. package/src/commands/relay.ts +5 -5
  80. package/src/commands/remediate.ts +2 -2
  81. package/src/commands/reputation.ts +9 -5
  82. package/src/commands/trust.ts +10 -1
  83. package/src/commands/verify.ts +5 -4
  84. package/src/commands/wallet.ts +203 -165
  85. package/src/commands/watchtower.ts +25 -13
  86. package/src/commands/workroom.ts +121 -95
  87. package/src/config.ts +2 -1
@@ -49,16 +49,21 @@ export function registerWatchtowerCommands(program: Command): void {
49
49
  .split(",")
50
50
  .map((s: string) => s.trim())
51
51
  .filter(Boolean);
52
+ const regSpinner = startSpinner('Registering watchtower…');
52
53
  const result = await client.registerWatchtower({
53
54
  name: opts.name,
54
55
  description: opts.description,
55
56
  capabilities,
56
57
  });
57
58
  if (opts.json || program.opts().json) {
59
+ regSpinner.stop();
58
60
  console.log(JSON.stringify(result));
59
61
  } else {
60
- console.log(`registered as watchtower: ${opts.name}`);
61
- console.log(`tx: ${result.txHash}`);
62
+ regSpinner.succeed(c.success + c.white(' Registered as watchtower'));
63
+ renderTree([
64
+ { label: 'Name', value: opts.name },
65
+ { label: 'Tx', value: result.txHash, last: true },
66
+ ]);
62
67
  }
63
68
  });
64
69
 
@@ -86,14 +91,19 @@ export function registerWatchtowerCommands(program: Command): void {
86
91
  if (opts.json || program.opts().json) {
87
92
  console.log(JSON.stringify(status, null, 2));
88
93
  } else {
89
- console.log(`watchtower: ${status.addr}`);
90
- console.log(` name: ${status.name}`);
91
- console.log(` description: ${status.description}`);
92
- console.log(` capabilities: ${status.capabilities.join(", ") || "(none)"}`);
93
- console.log(` active: ${status.active}`);
94
+ console.log('\n ' + c.mark + c.white(' Watchtower — ' + formatAddress(status.addr)));
95
+ const statusItems: { label: string; value: string; last?: boolean }[] = [
96
+ { label: 'Name', value: status.name },
97
+ { label: 'Description', value: status.description },
98
+ { label: 'Capabilities', value: status.capabilities.join(', ') || '(none)' },
99
+ { label: 'Active', value: String(status.active) },
100
+ ];
94
101
  if (status.registeredAt) {
95
- console.log(` registered: ${new Date(status.registeredAt * 1000).toISOString()}`);
102
+ statusItems.push({ label: 'Registered', value: new Date(status.registeredAt * 1000).toISOString(), last: true });
103
+ } else {
104
+ statusItems[statusItems.length - 1].last = true;
96
105
  }
106
+ renderTree(statusItems);
97
107
  }
98
108
  });
99
109
 
@@ -164,7 +174,7 @@ export function registerWatchtowerCommands(program: Command): void {
164
174
  if (opts.json) {
165
175
  console.log(JSON.stringify({ event: "challenge_submitted", channelId, txHash: result.txHash }));
166
176
  } else {
167
- console.log(`challenge submitted: ${result.txHash}`);
177
+ console.log(' ' + c.success + c.white(' Challenge submitted — tx ' + result.txHash.slice(0, 12) + '...'));
168
178
  }
169
179
  return;
170
180
  } else {
@@ -201,12 +211,13 @@ export function registerWatchtowerCommands(program: Command): void {
201
211
  config.serviceAgreementAddress,
202
212
  signer
203
213
  );
214
+ const authSpinner = startSpinner('Authorizing watchtower…');
204
215
  const result = await client.authorizeWatchtower(channelId, watchtower);
205
216
  if (opts.json || program.opts().json) {
217
+ authSpinner.stop();
206
218
  console.log(JSON.stringify(result));
207
219
  } else {
208
- console.log(`watchtower authorized: ${watchtower}`);
209
- console.log(`tx: ${result.txHash}`);
220
+ authSpinner.succeed(c.success + c.white(' Authorized: ' + formatAddress(watchtower)));
210
221
  }
211
222
  });
212
223
 
@@ -225,12 +236,13 @@ export function registerWatchtowerCommands(program: Command): void {
225
236
  config.serviceAgreementAddress,
226
237
  signer
227
238
  );
239
+ const revokeSpinner = startSpinner('Revoking watchtower…');
228
240
  const result = await client.revokeWatchtower(channelId, watchtower);
229
241
  if (opts.json || program.opts().json) {
242
+ revokeSpinner.stop();
230
243
  console.log(JSON.stringify(result));
231
244
  } else {
232
- console.log(`watchtower revoked: ${watchtower}`);
233
- console.log(`tx: ${result.txHash}`);
245
+ revokeSpinner.succeed(c.success + c.white(' Revoked: ' + formatAddress(watchtower)));
234
246
  }
235
247
  });
236
248
  }
@@ -9,6 +9,10 @@ import {
9
9
  runCmd,
10
10
  } from "../openshell-runtime";
11
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";
12
16
 
13
17
  // ─── Daemon lifecycle notify ──────────────────────────────────────────────────
14
18
 
@@ -113,33 +117,33 @@ export function registerWorkroomCommands(program: Command): void {
113
117
  .command("init")
114
118
  .description("Create the ARC-402 Workroom: build Docker image, validate policy, prepare runtime bundle.")
115
119
  .action(async () => {
116
- console.log("ARC-402 Workroom Init");
117
- console.log("─────────────────────");
120
+ console.log(c.brightCyan("ARC-402 Workroom Init"));
121
+ console.log(c.dim("─────────────────────"));
118
122
 
119
123
  // Check Docker
120
124
  if (!dockerAvailable()) {
121
- console.error("Docker is not available. Install Docker Desktop and try again.");
125
+ console.error(c.failure + " " + c.red("Docker is not available. Install Docker Desktop and try again."));
122
126
  process.exit(1);
123
127
  }
124
- console.log(" Docker available");
128
+ console.log(" " + c.success + c.white(" Docker available"));
125
129
 
126
130
  // Check policy file
127
131
  if (!fs.existsSync(POLICY_FILE)) {
128
- console.log("No policy file found. Generating default...");
132
+ console.log(c.dim("No policy file found. Generating default..."));
129
133
  // Import and call the existing policy generator
130
134
  const { registerOpenShellCommands } = require("./openshell");
131
- console.log(`Policy file will be generated at: ${POLICY_FILE}`);
132
- console.log("Run 'arc402 workroom policy preset core-launch' after init to apply defaults.");
135
+ console.log(c.dim(`Policy file will be generated at: ${POLICY_FILE}`));
136
+ console.log(c.dim("Run 'arc402 workroom policy preset core-launch' after init to apply defaults."));
133
137
  } else {
134
- console.log(`✓ Policy file: ${POLICY_FILE}`);
138
+ console.log(" " + c.success + c.dim(" Policy file: ") + c.white(POLICY_FILE));
135
139
  }
136
140
 
137
141
  // Check daemon.toml
138
142
  if (!fs.existsSync(DAEMON_TOML)) {
139
- console.error("daemon.toml not found. Run 'arc402 daemon init' first.");
143
+ console.error(c.failure + " " + c.red("daemon.toml not found. Run 'arc402 daemon init' first."));
140
144
  process.exit(1);
141
145
  }
142
- console.log(" daemon.toml found");
146
+ console.log(" " + c.success + c.white(" daemon.toml found"));
143
147
 
144
148
  // Set up Arena directories and default policy
145
149
  if (!fs.existsSync(ARENA_DATA_DIR)) {
@@ -147,9 +151,9 @@ export function registerWorkroomCommands(program: Command): void {
147
151
  for (const sub of ["feed", "profile", "state", "queue"]) {
148
152
  fs.mkdirSync(path.join(ARENA_DATA_DIR, sub), { recursive: true });
149
153
  }
150
- console.log(" Arena directories created");
154
+ console.log(" " + c.success + c.white(" Arena directories created"));
151
155
  } else {
152
- console.log(" Arena directories exist");
156
+ console.log(" " + c.success + c.white(" Arena directories exist"));
153
157
  }
154
158
 
155
159
  // Copy default arena policy if not present
@@ -157,34 +161,34 @@ export function registerWorkroomCommands(program: Command): void {
157
161
  const defaultArenaPolicy = path.join(WORKROOM_DIR, "arena-policy.yaml");
158
162
  if (fs.existsSync(defaultArenaPolicy)) {
159
163
  fs.copyFileSync(defaultArenaPolicy, ARENA_POLICY_FILE);
160
- console.log(" Arena policy: default installed");
164
+ console.log(" " + c.success + c.white(" Arena policy: default installed"));
161
165
  } else {
162
- console.log(" Arena policy template not found — create manually at " + ARENA_POLICY_FILE);
166
+ console.log(" " + c.warning + " " + c.yellow("Arena policy template not found — create manually at " + ARENA_POLICY_FILE));
163
167
  }
164
168
  } else {
165
- console.log(" Arena policy exists");
169
+ console.log(" " + c.success + c.white(" Arena policy exists"));
166
170
  }
167
171
 
168
172
  // Build image
169
173
  if (!imageExists()) {
170
174
  if (!buildImage()) {
171
- console.error("Failed to build workroom image.");
175
+ console.error(c.failure + " " + c.red("Failed to build workroom image."));
172
176
  process.exit(1);
173
177
  }
174
178
  }
175
- console.log(`✓ Image: ${WORKROOM_IMAGE}`);
179
+ console.log(" " + c.success + c.dim(" Image: ") + c.white(WORKROOM_IMAGE));
176
180
 
177
181
  // Package CLI runtime for the workroom
178
182
  const cliDist = path.resolve(__dirname, "..", "..");
179
183
  const cliPackage = path.resolve(__dirname, "..", "..", "..", "package.json");
180
184
  if (fs.existsSync(cliDist) && fs.existsSync(cliPackage)) {
181
- console.log(" CLI runtime available for workroom mount");
185
+ console.log(" " + c.success + c.white(" CLI runtime available for workroom mount"));
182
186
  } else {
183
- console.warn(" CLI dist not found — workroom will need runtime bundle");
187
+ console.warn(" " + c.warning + " " + c.yellow("CLI dist not found — workroom will need runtime bundle"));
184
188
  }
185
189
 
186
- console.log("\nWorkroom initialized. Start with: arc402 workroom start");
187
- console.log(`Policy hash: ${getPolicyHash()}`);
190
+ console.log("\n" + c.success + c.white(" Workroom initialized. Start with: arc402 workroom start"));
191
+ console.log(c.dim("Policy hash: ") + c.white(getPolicyHash()));
188
192
  });
189
193
 
190
194
  // ── start ─────────────────────────────────────────────────────────────────
@@ -229,7 +233,7 @@ export function registerWorkroomCommands(program: Command): void {
229
233
  // CLI runtime path
230
234
  const cliRoot = path.resolve(__dirname, "..", "..", "..");
231
235
 
232
- console.log("Starting ARC-402 Workroom...");
236
+ console.log(c.dim("Starting ARC-402 Workroom..."));
233
237
 
234
238
  const args = [
235
239
  "run", "-d",
@@ -267,16 +271,18 @@ export function registerWorkroomCommands(program: Command): void {
267
271
  spawnSync("sleep", ["2"]);
268
272
 
269
273
  if (containerRunning()) {
270
- console.log("\n ARC-402 Workroom is running");
271
- console.log(` Container: ${WORKROOM_CONTAINER}`);
272
- console.log(` Policy hash: ${getPolicyHash()}`);
273
- console.log(` Relay port: 4402`);
274
- console.log(` Logs: arc402 workroom logs`);
274
+ console.log("\n" + c.success + c.white(" ARC-402 Workroom is running"));
275
+ renderTree([
276
+ { label: "Container", value: WORKROOM_CONTAINER },
277
+ { label: "Policy hash", value: getPolicyHash() },
278
+ { label: "Relay port", value: "4402" },
279
+ { label: "Logs", value: "arc402 workroom logs", last: true },
280
+ ]);
275
281
  // Notify local daemon of workroom entry
276
282
  notifyDaemonWorkroomStatus("entered");
277
283
  } else {
278
- console.error("Workroom started but exited immediately. Check logs:");
279
- console.error(" docker logs arc402-workroom");
284
+ console.error(c.failure + " " + c.red("Workroom started but exited immediately. Check logs:"));
285
+ console.error(c.dim(" docker logs arc402-workroom"));
280
286
  process.exit(1);
281
287
  }
282
288
  });
@@ -290,11 +296,11 @@ export function registerWorkroomCommands(program: Command): void {
290
296
  console.log("Workroom is not running.");
291
297
  return;
292
298
  }
293
- console.log("Stopping ARC-402 Workroom...");
299
+ console.log(c.dim("Stopping ARC-402 Workroom..."));
294
300
  // Notify daemon before stopping (daemon may be inside container)
295
301
  notifyDaemonWorkroomStatus("exited");
296
302
  runCmd("docker", ["stop", WORKROOM_CONTAINER]);
297
- console.log(" Workroom stopped");
303
+ console.log(" " + c.success + c.white(" Workroom stopped"));
298
304
  });
299
305
 
300
306
  // ── status ────────────────────────────────────────────────────────────────
@@ -302,22 +308,26 @@ export function registerWorkroomCommands(program: Command): void {
302
308
  .command("status")
303
309
  .description("Show ARC-402 Workroom health, policy, and active state.")
304
310
  .action(async () => {
305
- console.log("ARC-402 Workroom Status");
306
- console.log("───────────────────────");
311
+ console.log(c.brightCyan("ARC-402 Workroom Status"));
312
+ console.log(c.dim("───────────────────────"));
307
313
 
308
314
  // Docker
309
315
  if (!dockerAvailable()) {
310
- console.log("Docker: not available");
316
+ console.log(c.dim("Docker: ") + c.failure + " " + c.red("not available"));
311
317
  return;
312
318
  }
313
- console.log("Docker: available");
319
+ console.log(c.dim("Docker: ") + c.success + c.white(" available"));
314
320
 
315
321
  // Image
316
- console.log(`Image: ${imageExists() ? "✓ " + WORKROOM_IMAGE : "❌ not built (run: arc402 workroom init)"}`);
322
+ if (imageExists()) {
323
+ console.log(c.dim("Image: ") + c.success + " " + c.white(WORKROOM_IMAGE));
324
+ } else {
325
+ console.log(c.dim("Image: ") + c.failure + " " + c.red("not built (run: arc402 workroom init)"));
326
+ }
317
327
 
318
328
  // Container
319
329
  if (containerRunning()) {
320
- console.log(`Container: running (${WORKROOM_CONTAINER})`);
330
+ console.log(c.dim("Container: ") + c.success + c.white(` running (${WORKROOM_CONTAINER})`));
321
331
 
322
332
  // Get container uptime
323
333
  const inspect = runCmd("docker", ["inspect", WORKROOM_CONTAINER, "--format", "{{.State.StartedAt}}"]);
@@ -326,30 +336,38 @@ export function registerWorkroomCommands(program: Command): void {
326
336
  const uptime = Math.floor((Date.now() - started.getTime()) / 1000);
327
337
  const h = Math.floor(uptime / 3600);
328
338
  const m = Math.floor((uptime % 3600) / 60);
329
- console.log(`Uptime: ${h}h ${m}m`);
339
+ console.log(c.dim("Uptime: ") + c.white(`${h}h ${m}m`));
330
340
  }
331
341
 
332
342
  // Get iptables rule count from inside container
333
343
  const rules = runCmd("docker", ["exec", WORKROOM_CONTAINER, "iptables", "-L", "OUTPUT", "-n", "--line-numbers"]);
334
344
  if (rules.ok) {
335
345
  const ruleCount = rules.stdout.split("\n").filter(l => l.match(/^\d+/)).length;
336
- console.log(`Network rules: ${ruleCount} iptables rules enforced`);
346
+ console.log(c.dim("Network rules: ") + c.white(`${ruleCount} iptables rules enforced`));
337
347
  }
338
348
  } else if (containerExists()) {
339
- console.log(`Container: stopped (run: arc402 workroom start)`);
349
+ console.log(c.dim("Container: ") + c.warning + " " + c.yellow("stopped (run: arc402 workroom start)"));
340
350
  } else {
341
- console.log(`Container: not created (run: arc402 workroom init)`);
351
+ console.log(c.dim("Container: ") + c.failure + " " + c.red("not created (run: arc402 workroom init)"));
342
352
  }
343
353
 
344
354
  // Policy
345
- console.log(`Policy file: ${fs.existsSync(POLICY_FILE) ? "✓ " + POLICY_FILE : "❌ missing"}`);
346
- console.log(`Policy hash: ${getPolicyHash()}`);
355
+ if (fs.existsSync(POLICY_FILE)) {
356
+ console.log(c.dim("Policy file: ") + c.success + " " + c.white(POLICY_FILE));
357
+ } else {
358
+ console.log(c.dim("Policy file: ") + c.failure + " " + c.red("missing"));
359
+ }
360
+ console.log(c.dim("Policy hash: ") + c.white(getPolicyHash()));
347
361
 
348
362
  // Arena
349
363
  const arenaExists = fs.existsSync(ARENA_DATA_DIR);
350
364
  const arenaPolicy = fs.existsSync(ARENA_POLICY_FILE);
351
- console.log(`Arena data: ${arenaExists ? "✓ " + ARENA_DATA_DIR : "❌ missing (run: arc402 workroom init)"}`);
352
- console.log(`Arena policy: ${arenaPolicy ? " loaded" : "❌ missing"}`);
365
+ if (arenaExists) {
366
+ console.log(c.dim("Arena data: ") + c.success + " " + c.white(ARENA_DATA_DIR));
367
+ } else {
368
+ console.log(c.dim("Arena data: ") + c.failure + " " + c.red("missing (run: arc402 workroom init)"));
369
+ }
370
+ console.log(c.dim("Arena policy: ") + (arenaPolicy ? c.success + c.white(" loaded") : c.failure + " " + c.red("missing")));
353
371
 
354
372
  // Arena queue (pending approvals)
355
373
  if (arenaExists) {
@@ -357,9 +375,9 @@ export function registerWorkroomCommands(program: Command): void {
357
375
  if (fs.existsSync(queueDir)) {
358
376
  const pending = fs.readdirSync(queueDir).filter(f => f.endsWith(".json")).length;
359
377
  if (pending > 0) {
360
- console.log(`Arena queue: ${pending} action(s) awaiting approval`);
378
+ console.log(c.dim("Arena queue: ") + c.warning + " " + c.yellow(`${pending} action(s) awaiting approval`));
361
379
  } else {
362
- console.log(`Arena queue: empty`);
380
+ console.log(c.dim("Arena queue: ") + c.success + c.white(" empty"));
363
381
  }
364
382
  }
365
383
  }
@@ -399,8 +417,8 @@ export function registerWorkroomCommands(program: Command): void {
399
417
  .command("doctor")
400
418
  .description("Diagnose workroom health: Docker, image, container, network, policy, daemon.")
401
419
  .action(async () => {
402
- console.log("ARC-402 Workroom Doctor");
403
- console.log("───────────────────────");
420
+ console.log(c.brightCyan("ARC-402 Workroom Doctor"));
421
+ console.log(c.dim("───────────────────────"));
404
422
 
405
423
  const checks: Array<{ label: string; pass: boolean; detail: string }> = [];
406
424
 
@@ -436,17 +454,19 @@ export function registerWorkroomCommands(program: Command): void {
436
454
  }
437
455
 
438
456
  // Print results
439
- for (const c of checks) {
440
- const icon = c.pass ? "✓" : "✗";
441
- const color = c.pass ? "" : " FIX";
442
- console.log(` ${icon} ${c.label}: ${c.detail}${color}`);
457
+ for (const chk of checks) {
458
+ if (chk.pass) {
459
+ console.log(" " + c.success + " " + c.dim(chk.label + ":") + " " + c.white(chk.detail));
460
+ } else {
461
+ console.log(" " + c.failure + " " + c.dim(chk.label + ":") + " " + c.red(chk.detail) + c.yellow(" ← FIX"));
462
+ }
443
463
  }
444
464
 
445
- const failures = checks.filter(c => !c.pass);
465
+ const failures = checks.filter(chk => !chk.pass);
446
466
  if (failures.length === 0) {
447
- console.log("\n All checks passed. Workroom is healthy.");
467
+ console.log("\n" + c.success + c.white(" All checks passed. Workroom is healthy."));
448
468
  } else {
449
- console.log(`\n ${failures.length} issue(s) found.`);
469
+ console.log("\n" + c.failure + " " + c.red(`${failures.length} issue(s) found.`));
450
470
  }
451
471
  });
452
472
 
@@ -482,18 +502,18 @@ export function registerWorkroomCommands(program: Command): void {
482
502
  console.error("Workroom is not running. Start it first: arc402 workroom start");
483
503
  process.exit(1);
484
504
  }
485
- console.log(`Testing connectivity to ${host} from inside workroom...`);
505
+ console.log(c.dim(`Testing connectivity to ${host} from inside workroom...`));
486
506
  const result = runCmd("docker", [
487
507
  "exec", WORKROOM_CONTAINER,
488
508
  "curl", "-s", "-o", "/dev/null", "-w", "%{http_code}", "--max-time", "5",
489
509
  `https://${host}`,
490
510
  ]);
491
511
  if (result.ok && result.stdout.trim() !== "000") {
492
- console.log(`✓ ${host} is reachable (HTTP ${result.stdout.trim()})`);
512
+ console.log(" " + c.success + " " + c.white(host) + c.dim(` is reachable (HTTP ${result.stdout.trim()})`));
493
513
  } else {
494
- console.log(`✗ ${host} is NOT reachable from the workroom`);
495
- console.log(" This host may not be in the workroom policy.");
496
- console.log(" Add it with: arc402 openshell policy add <name> <host>");
514
+ console.log(" " + c.failure + " " + c.red(`${host} is NOT reachable from the workroom`));
515
+ console.log(c.dim(" This host may not be in the workroom policy."));
516
+ console.log(c.dim(" Add it with: arc402 openshell policy add <name> <host>"));
497
517
  }
498
518
  });
499
519
 
@@ -553,9 +573,9 @@ Write these learnings concisely. They will be available on your next job.
553
573
  - If the task is unclear, produce the best interpretation and document assumptions
554
574
  - Every deliverable must be verifiable against the task spec
555
575
  `);
556
- console.log(`✓ Worker SOUL.md created: ${soulPath}`);
576
+ console.log(" " + c.success + c.dim(` Worker SOUL.md created: ${soulPath}`));
557
577
  } else {
558
- console.log(`✓ Worker SOUL.md already exists: ${soulPath}`);
578
+ console.log(" " + c.success + c.dim(` Worker SOUL.md already exists: ${soulPath}`));
559
579
  }
560
580
 
561
581
  // Generate default MEMORY.md
@@ -572,7 +592,7 @@ Write these learnings concisely. They will be available on your next job.
572
592
 
573
593
  No jobs completed yet. Learnings will accumulate here as the worker completes hired tasks.
574
594
  `);
575
- console.log(`✓ Worker MEMORY.md created: ${memoryPath}`);
595
+ console.log(" " + c.success + c.dim(` Worker MEMORY.md created: ${memoryPath}`));
576
596
  }
577
597
 
578
598
  // Generate learnings.md
@@ -586,7 +606,7 @@ No jobs completed yet. Learnings will accumulate here as the worker completes hi
586
606
 
587
607
  No learnings yet. Complete your first hired task to start accumulating expertise.
588
608
  `);
589
- console.log(`✓ Learnings file created: ${learningsPath}`);
609
+ console.log(" " + c.success + c.dim(` Learnings file created: ${learningsPath}`));
590
610
  }
591
611
 
592
612
  // Worker config
@@ -601,13 +621,13 @@ No learnings yet. Complete your first hired task to start accumulating expertise
601
621
  total_earned_eth: "0",
602
622
  };
603
623
  fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
604
- console.log(`✓ Worker config created: ${configPath}`);
624
+ console.log(" " + c.success + c.dim(` Worker config created: ${configPath}`));
605
625
  }
606
626
 
607
- console.log(`\nWorker initialized at: ${workerDir}`);
608
- console.log("Next: customize the worker SOUL.md and add skills.");
609
- console.log(" arc402 workroom worker set-soul <file>");
610
- console.log(" arc402 workroom worker set-skills <dir>");
627
+ console.log("\n" + c.success + c.white(` Worker initialized at: ${workerDir}`));
628
+ console.log(c.dim("Next: customize the worker SOUL.md and add skills."));
629
+ console.log(c.dim(" arc402 workroom worker set-soul <file>"));
630
+ console.log(c.dim(" arc402 workroom worker set-skills <dir>"));
611
631
  });
612
632
 
613
633
  worker
@@ -636,16 +656,18 @@ No learnings yet. Complete your first hired task to start accumulating expertise
636
656
  ? fs.readdirSync(skillsDir).length
637
657
  : 0;
638
658
 
639
- console.log("ARC-402 Workroom Worker");
640
- console.log("───────────────────────");
641
- console.log(`Name: ${config.name}`);
642
- console.log(`Model: ${config.model}`);
643
- console.log(`Created: ${config.created}`);
644
- console.log(`Jobs done: ${config.job_count}`);
645
- console.log(`Job memories: ${jobFiles}`);
646
- console.log(`Learnings: ${learningsSize > 200 ? Math.round(learningsSize / 1024) + " KB" : "empty"}`);
647
- console.log(`Skills: ${skillCount}`);
648
- console.log(`Total earned: ${config.total_earned_eth} ETH`);
659
+ console.log(c.brightCyan("ARC-402 Workroom Worker"));
660
+ console.log(c.dim("───────────────────────"));
661
+ renderTree([
662
+ { label: "Name", value: config.name },
663
+ { label: "Model", value: config.model },
664
+ { label: "Created", value: config.created },
665
+ { label: "Jobs done", value: String(config.job_count) },
666
+ { label: "Job memories", value: String(jobFiles) },
667
+ { label: "Learnings", value: learningsSize > 200 ? Math.round(learningsSize / 1024) + " KB" : "empty" },
668
+ { label: "Skills", value: String(skillCount) },
669
+ { label: "Total earned", value: config.total_earned_eth + " ETH", last: true },
670
+ ]);
649
671
  });
650
672
 
651
673
  worker
@@ -659,7 +681,7 @@ No learnings yet. Complete your first hired task to start accumulating expertise
659
681
  const dest = path.join(ARC402_DIR, "worker", "SOUL.md");
660
682
  fs.mkdirSync(path.dirname(dest), { recursive: true });
661
683
  fs.copyFileSync(file, dest);
662
- console.log(`✓ Worker SOUL.md updated from: ${file}`);
684
+ console.log(" " + c.success + c.white(` Worker SOUL.md updated from: ${file}`));
663
685
  });
664
686
 
665
687
  worker
@@ -684,7 +706,7 @@ No learnings yet. Complete your first hired task to start accumulating expertise
684
706
  fs.cpSync(src, dst, { recursive: true });
685
707
  }
686
708
  }
687
- console.log(`✓ ${files.length} items copied to worker skills`);
709
+ console.log(" " + c.success + c.white(` ${files.length} items copied to worker skills`));
688
710
  });
689
711
 
690
712
  worker
@@ -710,10 +732,10 @@ No learnings yet. Complete your first hired task to start accumulating expertise
710
732
  count++;
711
733
  }
712
734
  }
713
- console.log(`✓ ${count} items copied to worker knowledge`);
714
- console.log(` Path: ${dest}`);
715
- console.log(` The worker can reference these files during hired tasks.`);
716
- console.log(` To update: run this command again with the updated directory.`);
735
+ console.log(" " + c.success + c.white(` ${count} items copied to worker knowledge`));
736
+ console.log(" " + c.dim("Path:") + " " + c.white(dest));
737
+ console.log(c.dim(" The worker can reference these files during hired tasks."));
738
+ console.log(c.dim(" To update: run this command again with the updated directory."));
717
739
  });
718
740
 
719
741
  worker
@@ -767,7 +789,7 @@ No learnings yet. Complete your first hired task to start accumulating expertise
767
789
  config.job_count = 0;
768
790
  fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
769
791
  }
770
- console.log(" Worker memory cleared. Starting fresh.");
792
+ console.log(" " + c.success + c.white(" Worker memory cleared. Starting fresh."));
771
793
  });
772
794
 
773
795
  // ── token usage ──────────────────────────────────────────────────────────
@@ -877,14 +899,18 @@ No learnings yet. Complete your first hired task to start accumulating expertise
877
899
  return;
878
900
  }
879
901
  const config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
880
- console.log("ARC-402 Earnings");
881
- console.log("────────────────");
882
- console.log(`Total earned: ${config.total_earned_eth} ETH`);
883
- console.log(`Jobs completed: ${config.job_count}`);
902
+ console.log(c.brightCyan("ARC-402 Earnings"));
903
+ console.log(c.dim("────────────────"));
904
+ const earningsItems: { label: string; value: string; last?: boolean }[] = [
905
+ { label: "Total earned", value: config.total_earned_eth + " ETH" },
906
+ { label: "Jobs completed", value: String(config.job_count) },
907
+ ];
884
908
  if (config.job_count > 0) {
885
909
  const avg = (parseFloat(config.total_earned_eth) / config.job_count).toFixed(6);
886
- console.log(`Average/job: ${avg} ETH`);
910
+ earningsItems.push({ label: "Average/job", value: avg + " ETH" });
887
911
  }
912
+ earningsItems[earningsItems.length - 1].last = true;
913
+ renderTree(earningsItems);
888
914
  });
889
915
 
890
916
  workroom
@@ -918,16 +944,16 @@ No learnings yet. Complete your first hired task to start accumulating expertise
918
944
  console.error("Workroom is not running.");
919
945
  process.exit(1);
920
946
  }
921
- console.log("Reloading workroom policy...");
947
+ console.log(c.dim("Reloading workroom policy..."));
922
948
  // Trigger DNS refresh manually (which re-reads policy and updates iptables)
923
949
  const result = runCmd("docker", [
924
950
  "exec", WORKROOM_CONTAINER,
925
951
  "bash", "-c", "/dns-refresh.sh /workroom/.arc402/openshell-policy.yaml &",
926
952
  ]);
927
953
  if (result.ok) {
928
- console.log(" Policy reload triggered");
954
+ console.log(" " + c.success + c.white(" Policy reload triggered"));
929
955
  } else {
930
- console.error("Failed to reload policy");
956
+ console.error(c.failure + " " + c.red("Failed to reload policy"));
931
957
  }
932
958
  });
933
959
  }
package/src/config.ts CHANGED
@@ -61,7 +61,8 @@ export function loadConfig(): Arc402Config {
61
61
  network: "base-mainnet",
62
62
  rpcUrl: defaults.rpcUrl ?? "https://mainnet.base.org",
63
63
  trustRegistryAddress: defaults.trustRegistryAddress ?? "",
64
- agentRegistryAddress: (defaults as Record<string,string>).agentRegistryV2Address ?? defaults.agentRegistryAddress,
64
+ walletConnectProjectId: "455e9425343b9156fce1428250c9a54a",
65
+ agentRegistryAddress: (defaults as unknown as Record<string,string>).agentRegistryV2Address ?? defaults.agentRegistryAddress,
65
66
  serviceAgreementAddress: defaults.serviceAgreementAddress,
66
67
  reputationOracleAddress: defaults.reputationOracleAddress,
67
68
  capabilityRegistryAddress: defaults.capabilityRegistryAddress,