arc402-cli 0.4.0 → 0.4.1

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
@@ -2,6 +2,10 @@ import { Command } from "commander";
2
2
  import { ethers } from "ethers";
3
3
  import { loadConfig } from "../config";
4
4
  import { getClient, requireSigner } from "../client";
5
+ import { c } from '../ui/colors';
6
+ import { startSpinner } from '../ui/spinner';
7
+ import { renderTree } from '../ui/tree';
8
+ import { formatAddress } from '../ui/format';
5
9
 
6
10
  const MIGRATION_REGISTRY_ABI = [
7
11
  "function registerMigration(address oldWallet, address newWallet) external",
@@ -35,8 +39,10 @@ export function registerMigrateCommands(program: Command): void {
35
39
  const { signer } = await requireSigner(config);
36
40
  const contract = new ethers.Contract(config.migrationRegistryAddress, MIGRATION_REGISTRY_ABI, signer);
37
41
 
42
+ const migrateSpinner = startSpinner('Registering migration...');
38
43
  const tx = await contract.registerMigration(oldWallet, newWallet);
39
44
  const receipt = await tx.wait();
45
+ migrateSpinner.succeed('Migration registered');
40
46
 
41
47
  const payload = {
42
48
  oldWallet,
@@ -44,11 +50,11 @@ export function registerMigrateCommands(program: Command): void {
44
50
  txHash: receipt.hash,
45
51
  };
46
52
  if (opts.json) return console.log(JSON.stringify(payload, null, 2));
47
- console.log(`migration registered`);
48
- console.log(` old: ${oldWallet}`);
49
- console.log(` new: ${newWallet}`);
50
- console.log(` note: 10% trust score decay applied on migration`);
51
- console.log(` tx: ${receipt.hash}`);
53
+ renderTree([
54
+ { label: 'Old', value: formatAddress(oldWallet) },
55
+ { label: 'New', value: formatAddress(newWallet) },
56
+ { label: 'Note', value: '10% trust score decay applied', last: true },
57
+ ]);
52
58
  });
53
59
 
54
60
  // ─── migrate status <address> ──────────────────────────────────────────────
@@ -85,15 +91,15 @@ export function registerMigrateCommands(program: Command): void {
85
91
  migratedFrom: wasSource ? migratedFrom : null,
86
92
  };
87
93
  if (opts.json) return console.log(JSON.stringify(payload, null, 2));
88
- console.log(`address=${address}`);
89
- console.log(` active wallet: ${activeWallet}`);
90
- if (isCurrent) {
91
- console.log(` status: current (no further migration)`);
92
- } else {
93
- console.log(` status: migrated score queries resolve to ${activeWallet}`);
94
- }
95
- if (hasMigrated) console.log(` migrated to: ${migratedTo}`);
96
- if (wasSource) console.log(` migrated from: ${migratedFrom}`);
94
+ const statusItems: import('../ui/tree').TreeItem[] = [
95
+ { label: 'Address', value: formatAddress(address) },
96
+ { label: 'Active', value: formatAddress(activeWallet) },
97
+ { label: 'Status', value: isCurrent ? 'current (no further migration)' : `migrated — resolves to ${formatAddress(activeWallet)}` },
98
+ ];
99
+ if (hasMigrated) statusItems.push({ label: 'Migrated to', value: formatAddress(migratedTo) });
100
+ if (wasSource) statusItems.push({ label: 'Migrated from', value: formatAddress(migratedFrom) });
101
+ statusItems[statusItems.length - 1].last = true;
102
+ renderTree(statusItems);
97
103
  });
98
104
 
99
105
  // ─── migrate lineage <address> ────────────────────────────────────────────
@@ -158,18 +164,14 @@ export function registerMigrateCommands(program: Command): void {
158
164
  };
159
165
  if (opts.json) return console.log(JSON.stringify(payload, null, 2));
160
166
 
161
- console.log(`address=${address}`);
162
- console.log(` lineage depth: ${lineage.length} wallet${lineage.length !== 1 ? "s" : ""}`);
163
- console.log(` migrations: ${entries.length}`);
164
- console.log();
165
- lineage.forEach((addr, i) => {
166
- const label = i === 0 ? " (origin)" : i === lineage.length - 1 ? " (current)" : "";
167
- console.log(` [${i}] ${addr}${label}`);
168
- if (i < entries.length) {
169
- const e = entries[i];
170
- if (e.timestamp) console.log(` migrated: ${e.timestamp}`);
171
- if (e.scoreAtMigration) console.log(` score at migration: ${e.scoreAtMigration} (decay: ${Number(e.decayBps) / 100}%)`);
172
- }
167
+ const lineageItems = lineage.map((addr, i) => {
168
+ const roleLabel = i === 0 ? ' (origin)' : i === lineage.length - 1 ? ' (current)' : '';
169
+ const e = i < entries.length ? entries[i] : null;
170
+ let value = formatAddress(addr) + roleLabel;
171
+ if (e?.timestamp) value += ` · ${e.timestamp}`;
172
+ if (e?.scoreAtMigration) value += ` · score: ${e.scoreAtMigration} (decay: ${Number(e.decayBps) / 100}%)`;
173
+ return { label: `[${i}]`, value, last: i === lineage.length - 1 };
173
174
  });
175
+ renderTree(lineageItems);
174
176
  });
175
177
  }
@@ -11,6 +11,7 @@ import {
11
11
  import { loadConfig } from "../config";
12
12
  import { requireSigner, getClient } from "../client";
13
13
  import { hashFile, hashString } from "../utils/hash";
14
+ import { c } from '../ui/colors';
14
15
 
15
16
  const sessionManager = new SessionManager();
16
17
 
@@ -102,7 +103,7 @@ export function registerNegotiateCommands(program: Command): void {
102
103
  if (opts.json) {
103
104
  console.log(JSON.stringify({ sessionId: session.sessionId, message: proposal }));
104
105
  } else {
105
- console.log(`Session started: ${session.sessionId}`);
106
+ console.log(' ' + c.success + c.white(' Session started: ' + session.sessionId.slice(0, 12) + '...'));
106
107
  console.log(`Signed PROPOSE:`);
107
108
  console.log(JSON.stringify(proposal, null, 2));
108
109
  }
@@ -138,7 +139,7 @@ export function registerNegotiateCommands(program: Command): void {
138
139
  if (opts.json) {
139
140
  console.log(JSON.stringify(counter));
140
141
  } else {
141
- console.log(`Signed COUNTER added to session ${sessionId.slice(0, 10)}...`);
142
+ console.log(' ' + c.success + c.white(' Counter added to session'));
142
143
  console.log(JSON.stringify(counter, null, 2));
143
144
  }
144
145
  });
@@ -177,8 +178,8 @@ export function registerNegotiateCommands(program: Command): void {
177
178
  message: accept,
178
179
  }));
179
180
  } else {
180
- console.log(`✓ Session ${sessionId.slice(0, 10)}... ACCEPTED`);
181
- console.log(`✓ Transcript hash: ${updatedSession.transcriptHash}`);
181
+ console.log(' ' + c.success + c.white(' Session ACCEPTED — transcript locked'));
182
+ console.log(' ' + c.dim(' Transcript:') + ' ' + c.white(updatedSession.transcriptHash ?? ''));
182
183
  if (opts.record) {
183
184
  console.log(`\nTranscript hash is ready to commit on-chain.`);
184
185
  console.log(`Run: arc402 hire --session ${sessionId} to propose() and record the transcript hash.`);
@@ -212,7 +213,7 @@ export function registerNegotiateCommands(program: Command): void {
212
213
  if (opts.json) {
213
214
  console.log(JSON.stringify(reject));
214
215
  } else {
215
- console.log(`✗ Session ${sessionId.slice(0, 10)}... REJECTED`);
216
+ console.log(' ' + c.failure + c.white(' Session REJECTED'));
216
217
  console.log(`Reason: ${opts.reason}`);
217
218
  }
218
219
  });
@@ -239,9 +240,9 @@ export function registerNegotiateCommands(program: Command): void {
239
240
  if (opts.json) {
240
241
  console.log(JSON.stringify(result));
241
242
  } else if (result.valid) {
242
- console.log(`✓ Valid — signer: ${result.recoveredSigner}`);
243
+ console.log(' ' + c.success + c.white(' Valid — signer: ' + result.recoveredSigner));
243
244
  } else {
244
- console.error(`✗ Invalid — ${result.error}`);
245
+ console.error(' ' + c.failure + c.white(' Invalid — ' + result.error));
245
246
  process.exit(1);
246
247
  }
247
248
  });
@@ -3,6 +3,8 @@ import * as fs from "fs";
3
3
  import * as path from "path";
4
4
  import * as os from "os";
5
5
  import * as YAML from "yaml";
6
+ import { c } from '../ui/colors';
7
+ import { startSpinner } from '../ui/spinner';
6
8
  import {
7
9
  ARC402_DIR,
8
10
  DEFAULT_RUNTIME_REMOTE_ROOT,
@@ -757,7 +759,7 @@ If you update the local CLI build and want the sandbox to pick it up immediately
757
759
  synced_at: new Date().toISOString(),
758
760
  },
759
761
  });
760
- console.log(`✓ Runtime synced to ${provisioned.remoteRoot}`);
762
+ console.log(' ' + c.success + c.white(` Runtime synced to ${provisioned.remoteRoot}`));
761
763
  } catch (err) {
762
764
  console.error(`Runtime sync failed: ${err instanceof Error ? err.message : String(err)}`);
763
765
  process.exit(1);
@@ -972,7 +974,7 @@ If you update the local CLI build and want the sandbox to pick it up immediately
972
974
  const key = peerPolicyKey(cleanedHost);
973
975
  const result = ensurePolicyEntry(policy, key, buildPolicyEntry(`peer-agent:${cleanedHost}`, cleanedHost));
974
976
  applyAndPersistPolicy(policy);
975
- console.log(`✓ Peer agent host ${cleanedHost} ${result} under ${key}`);
977
+ console.log(' ' + c.success + c.white(` Peer agent host ${cleanedHost} ${result} under ${key}`));
976
978
  console.log(" This only affects sandbox outbound access. It does not claim or expose a public endpoint.");
977
979
  });
978
980
 
@@ -989,7 +991,7 @@ If you update the local CLI build and want the sandbox to pick it up immediately
989
991
  process.exit(1);
990
992
  }
991
993
  applyAndPersistPolicy(policy);
992
- console.log(`✓ Peer agent host ${cleanedHost} removed (${key})`);
994
+ console.log(' ' + c.success + c.white(` Peer agent host ${cleanedHost} removed (${key})`));
993
995
  });
994
996
 
995
997
  peerCmd
@@ -1018,7 +1020,7 @@ If you update the local CLI build and want the sandbox to pick it up immediately
1018
1020
  const key = customPolicyKey(name);
1019
1021
  const result = ensurePolicyEntry(policy, key, buildPolicyEntry(name, host, [...NODE_BINARIES, ...PYTHON_BINARIES]));
1020
1022
  applyAndPersistPolicy(policy);
1021
- console.log(`✓ ${host} ${result} as ${key}`);
1023
+ console.log(' ' + c.success + c.white(` ${host} ${result} as ${key}`));
1022
1024
  console.log(" Prefer `arc402 openshell policy peer add <host>` for peer agents or `preset <name>` for launch-safe expansion packs.");
1023
1025
  });
1024
1026
 
@@ -1048,6 +1050,6 @@ If you update the local CLI build and want the sandbox to pick it up immediately
1048
1050
  delete policy.network_policies[key];
1049
1051
 
1050
1052
  applyAndPersistPolicy(policy);
1051
- console.log(`✓ ${removedHost} removed from daemon sandbox policy (hot-reloaded)`);
1053
+ console.log(' ' + c.success + c.white(` ${removedHost} removed from daemon sandbox policy (hot-reloaded)`));
1052
1054
  });
1053
1055
  }
@@ -28,7 +28,8 @@ export function registerOwnerCommands(program: Command): void {
28
28
  if (!config.disputeArbitrationAddress) throw new Error("disputeArbitrationAddress missing in config");
29
29
  const { signer } = await requireSigner(config);
30
30
  const client = new DisputeArbitrationClient(config.disputeArbitrationAddress, signer);
31
+ const spinner = startSpinner('Accepting ownership…');
31
32
  await client.acceptOwnership();
32
- console.log("ownership transfer accepted you are now the owner of DisputeArbitration");
33
+ spinner.succeed(c.success + c.white(' Ownership accepted'));
33
34
  });
34
35
  }
@@ -45,11 +45,11 @@ blocklist
45
45
  const already = await contract.isBlocked(wallet, address);
46
46
  if (already) {
47
47
  if (opts.json) return console.log(JSON.stringify({ address, blocked: true, alreadyBlocked: true }));
48
- return console.log(`${address} is already blocked`);
48
+ return console.log(' ' + c.dim('Already blocked: ' + formatAddress(address)));
49
49
  }
50
50
  await (await contract.addToBlocklist(wallet, address)).wait();
51
51
  if (opts.json) return console.log(JSON.stringify({ address, blocked: true }));
52
- console.log(`Added ${address} to blocklist`);
52
+ console.log(' ' + c.success + c.white(' Blocked: ' + formatAddress(address)));
53
53
  });
54
54
 
55
55
  blocklist
@@ -67,11 +67,11 @@ blocklist
67
67
  const isBlockedNow = await contract.isBlocked(wallet, address);
68
68
  if (!isBlockedNow) {
69
69
  if (opts.json) return console.log(JSON.stringify({ address, blocked: false, notBlocked: true }));
70
- return console.log(`${address} is not on your blocklist`);
70
+ return console.log(' ' + c.dim('Not on blocklist: ' + formatAddress(address)));
71
71
  }
72
72
  await (await contract.removeFromBlocklist(wallet, address)).wait();
73
73
  if (opts.json) return console.log(JSON.stringify({ address, blocked: false }));
74
- console.log(`Removed ${address} from blocklist`);
74
+ console.log(' ' + c.success + c.white(' Unblocked: ' + formatAddress(address)));
75
75
  });
76
76
 
77
77
  blocklist
@@ -89,7 +89,11 @@ blocklist
89
89
  const contract = getPolicyEngine(config.policyEngineAddress, provider);
90
90
  const blocked = await contract.isBlocked(wallet, address);
91
91
  if (opts.json) return console.log(JSON.stringify({ address, blocked }));
92
- console.log(blocked ? `${address} is BLOCKED` : `${address} is not blocked`);
92
+ if (blocked) {
93
+ console.log(' ' + c.warning + c.white(' ' + formatAddress(address) + ' is BLOCKED'));
94
+ } else {
95
+ console.log(' ' + c.success + c.white(' ' + formatAddress(address) + ' is not blocked'));
96
+ }
93
97
  });
94
98
 
95
99
  blocklist
@@ -147,11 +151,11 @@ shortlist
147
151
  const alreadyPreferred = await contract.isPreferred(wallet, opts.capability, address);
148
152
  if (alreadyPreferred) {
149
153
  if (opts.json) return console.log(JSON.stringify({ address, capability: opts.capability, preferred: true, alreadyPreferred: true }));
150
- return console.log(`${address} is already shortlisted for ${opts.capability}`);
154
+ return console.log(' ' + c.dim('Already shortlisted: ' + formatAddress(address) + ' for ' + opts.capability));
151
155
  }
152
156
  await (await contract.addPreferred(wallet, opts.capability, address)).wait();
153
157
  if (opts.json) return console.log(JSON.stringify({ address, capability: opts.capability, preferred: true }));
154
- console.log(`Added ${address} to shortlist for ${opts.capability}`);
158
+ console.log(' ' + c.success + c.white(' Shortlisted: ' + formatAddress(address) + ' for ' + opts.capability));
155
159
  });
156
160
 
157
161
  shortlist
@@ -170,11 +174,11 @@ shortlist
170
174
  const isPreferredNow = await contract.isPreferred(wallet, opts.capability, address);
171
175
  if (!isPreferredNow) {
172
176
  if (opts.json) return console.log(JSON.stringify({ address, capability: opts.capability, preferred: false, notPreferred: true }));
173
- return console.log(`${address} is not shortlisted for ${opts.capability}`);
177
+ return console.log(' ' + c.dim('Not shortlisted: ' + formatAddress(address) + ' for ' + opts.capability));
174
178
  }
175
179
  await (await contract.removePreferred(wallet, opts.capability, address)).wait();
176
180
  if (opts.json) return console.log(JSON.stringify({ address, capability: opts.capability, preferred: false }));
177
- console.log(`Removed ${address} from shortlist for ${opts.capability}`);
181
+ console.log(' ' + c.success + c.white(' Removed from shortlist: ' + formatAddress(address) + ' for ' + opts.capability));
178
182
  });
179
183
 
180
184
  shortlist
@@ -193,7 +197,11 @@ shortlist
193
197
  const contract = getPolicyEngine(config.policyEngineAddress, provider);
194
198
  const preferred = await contract.isPreferred(wallet, opts.capability, address);
195
199
  if (opts.json) return console.log(JSON.stringify({ address, capability: opts.capability, preferred }));
196
- console.log(preferred ? `${address} is shortlisted for ${opts.capability}` : `${address} is NOT shortlisted for ${opts.capability}`);
200
+ if (preferred) {
201
+ console.log(' ' + c.success + c.white(' ' + formatAddress(address) + ' is shortlisted for ' + opts.capability));
202
+ } else {
203
+ console.log(' ' + c.warning + c.white(' ' + formatAddress(address) + ' is NOT shortlisted for ' + opts.capability));
204
+ }
197
205
  });
198
206
 
199
207
  shortlist
@@ -127,7 +127,7 @@ export function registerRelayCommands(program: Command): void {
127
127
  console.log(JSON.stringify(result.data));
128
128
  } else {
129
129
  const d = result.data as { messageId?: string };
130
- console.log(`Sent. messageId: ${d.messageId}`);
130
+ console.log(' ' + c.success + c.white(' Sent — messageId: ' + d.messageId));
131
131
  }
132
132
  });
133
133
 
@@ -159,7 +159,7 @@ export function registerRelayCommands(program: Command): void {
159
159
  }
160
160
 
161
161
  if (messages.length === 0) {
162
- console.log("No messages.");
162
+ console.log(' ' + c.dim('No messages.'));
163
163
  return;
164
164
  }
165
165
 
@@ -217,7 +217,7 @@ export function registerRelayCommands(program: Command): void {
217
217
  if (opts.json) {
218
218
  console.log(JSON.stringify({ started: true, pid: child.pid, pidFile: PID_FILE }));
219
219
  } else {
220
- console.log(`Daemon started (PID ${child.pid}). PID file: ${PID_FILE}`);
220
+ console.log(' ' + c.success + c.white(' Daemon started (PID ' + child.pid + ')'));
221
221
  }
222
222
  });
223
223
 
@@ -230,7 +230,7 @@ export function registerRelayCommands(program: Command): void {
230
230
  if (opts.json) {
231
231
  console.log(JSON.stringify({ stopped: false, reason: "no pid file" }));
232
232
  } else {
233
- console.log("No running daemon found (no PID file).");
233
+ console.log(' ' + c.dim('No running daemon found.'));
234
234
  }
235
235
  return;
236
236
  }
@@ -242,7 +242,7 @@ export function registerRelayCommands(program: Command): void {
242
242
  if (opts.json) {
243
243
  console.log(JSON.stringify({ stopped: true, pid }));
244
244
  } else {
245
- console.log(`Daemon stopped (PID ${pid}).`);
245
+ console.log(' ' + c.success + c.white(' Daemon stopped (PID ' + pid + ')'));
246
246
  }
247
247
  } catch (err: unknown) {
248
248
  const msg = err instanceof Error ? err.message : String(err);
@@ -10,12 +10,12 @@ export function registerRemediateCommands(program: Command): void {
10
10
  const remediate = program.command("remediate").description("Negotiated remediation before formal dispute");
11
11
  remediate.command("request <id>").requiredOption("--text <feedback>").option("--uri <uri>", "Structured feedback URI", "").option("--file <path>").option("--previous <hash>", "Previous transcript hash", "0x0000000000000000000000000000000000000000000000000000000000000000").action(async (id, opts) => {
12
12
  const config = loadConfig(); if (!config.serviceAgreementAddress) throw new Error("serviceAgreementAddress missing in config"); const { signer } = await requireSigner(config); const client = new ServiceAgreementClient(config.serviceAgreementAddress, signer);
13
- const hash = opts.file ? hashFile(opts.file) : hashString(opts.text); await client.requestRevision(BigInt(id), hash, opts.uri, opts.previous); console.log(`revision requested for ${id} transcriptSeed=${hash}`);
13
+ const hash = opts.file ? hashFile(opts.file) : hashString(opts.text); await client.requestRevision(BigInt(id), hash, opts.uri, opts.previous); console.log(' ' + c.success + c.white(' Revision requested agreement #' + id));
14
14
  });
15
15
  remediate.command("respond <id>").requiredOption("--type <type>", "revise|defend|counter|partial-settlement|human-review|escalate").requiredOption("--text <response>").option("--uri <uri>", "Structured response URI", "").option("--file <path>").option("--previous <hash>", "Previous transcript hash", "0x0000000000000000000000000000000000000000000000000000000000000000").option("--provider-payout <amount>", "Wei/token units for partial settlement", "0").action(async (id, opts) => {
16
16
  const config = loadConfig(); if (!config.serviceAgreementAddress) throw new Error("serviceAgreementAddress missing in config"); const { signer } = await requireSigner(config); const client = new ServiceAgreementClient(config.serviceAgreementAddress, signer);
17
17
  const map: Record<string, ProviderResponseType> = { revise: ProviderResponseType.REVISE, defend: ProviderResponseType.DEFEND, counter: ProviderResponseType.COUNTER, 'partial-settlement': ProviderResponseType.PARTIAL_SETTLEMENT, 'human-review': ProviderResponseType.REQUEST_HUMAN_REVIEW, escalate: ProviderResponseType.ESCALATE };
18
- const hash = opts.file ? hashFile(opts.file) : hashString(opts.text); await client.respondToRevision(BigInt(id), map[String(opts.type)], hash, opts.uri, opts.previous, BigInt(opts.providerPayout)); console.log(`revision response recorded for ${id}`);
18
+ const hash = opts.file ? hashFile(opts.file) : hashString(opts.text); await client.respondToRevision(BigInt(id), map[String(opts.type)], hash, opts.uri, opts.previous, BigInt(opts.providerPayout)); console.log(' ' + c.success + c.white(' Response recorded agreement #' + id));
19
19
  });
20
20
  remediate.command("status <id>").option("--json").action(async (id, opts) => {
21
21
  const config = loadConfig(); if (!config.serviceAgreementAddress) throw new Error("serviceAgreementAddress missing in config"); const { provider } = await getClient(config); const client = new ServiceAgreementClient(config.serviceAgreementAddress, provider);
@@ -25,7 +25,7 @@ reputation
25
25
  const oracle = new ReputationOracleClient(config.reputationOracleAddress, signer);
26
26
  await oracle.publishSignal(address, ReputationSignalType.WARN, ethers.ZeroHash, opts.reason);
27
27
  if (opts.json) return console.log(JSON.stringify({ address, signal: "WARN", reason: opts.reason }, null, 2));
28
- console.log(`WARN signal published against ${address}: "${opts.reason}"`);
28
+ console.log(' ' + c.warning + c.white(' WARN published against ' + formatAddress(address)));
29
29
  });
30
30
 
31
31
  reputation
@@ -43,7 +43,7 @@ reputation
43
43
  const oracle = new ReputationOracleClient(config.reputationOracleAddress, signer);
44
44
  await oracle.publishSignal(address, ReputationSignalType.BLOCK, ethers.ZeroHash, opts.reason);
45
45
  if (opts.json) return console.log(JSON.stringify({ address, signal: "BLOCK", reason: opts.reason }, null, 2));
46
- console.log(`BLOCK signal published against ${address}: "${opts.reason}"`);
46
+ console.log(' ' + c.failure + c.white(' BLOCK published against ' + formatAddress(address)));
47
47
  });
48
48
 
49
49
  reputation
@@ -67,9 +67,13 @@ reputation
67
67
  weightedScore: rep.weightedScore.toString(),
68
68
  };
69
69
  if (opts.json) return console.log(JSON.stringify(payload, null, 2));
70
- console.log(`address=${address}`);
71
- console.log(`endorsements=${rep.endorsements} warnings=${rep.warnings} blocks=${rep.blocks}`);
72
- console.log(`weightedScore=${rep.weightedScore}`);
70
+ console.log('\n ' + c.mark + c.white(' Reputation — ' + formatAddress(address)));
71
+ renderTree([
72
+ { label: 'Endorsements', value: rep.endorsements.toString() },
73
+ { label: 'Warnings', value: rep.warnings.toString() },
74
+ { label: 'Blocks', value: rep.blocks.toString() },
75
+ { label: 'Score', value: rep.weightedScore.toString(), last: true },
76
+ ]);
73
77
  });
74
78
 
75
79
  export default reputation;
@@ -13,6 +13,15 @@ export function registerTrustCommand(program: Command): void {
13
13
  const score = await trust.getScore(address); const sponsorship = config.sponsorshipAttestationAddress ? new SponsorshipAttestationClient(config.sponsorshipAttestationAddress, provider) : null; const reputation = config.reputationOracleAddress ? new ReputationOracleClient(config.reputationOracleAddress, provider) : null;
14
14
  const highestTier = sponsorship ? await sponsorship.getHighestTier(address) : undefined; const rep = reputation ? await reputation.getReputation(address) : undefined;
15
15
  if (opts.json) return console.log(JSON.stringify({ address, score, highestTier, reputation: rep }, (_k, value) => typeof value === 'bigint' ? value.toString() : value, 2));
16
- console.log(`score=${score.score} tier=${getTrustTier(score.score)} next=${score.nextLevelAt}${highestTier !== undefined ? ` sponsorship=${identityTierLabel(highestTier)}` : ''}${rep ? ` reputation=${rep.weightedScore}` : ''}`);
16
+ console.log('\n ' + c.mark + c.white(' Trust ' + formatAddress(address)));
17
+ const trustTreeItems: { label: string; value: string; last?: boolean }[] = [
18
+ { label: 'Score', value: String(score.score) },
19
+ { label: 'Tier', value: getTrustTier(score.score) },
20
+ { label: 'Next level', value: String(score.nextLevelAt) },
21
+ ];
22
+ if (highestTier !== undefined) trustTreeItems.push({ label: 'Sponsorship', value: identityTierLabel(highestTier) });
23
+ if (rep) trustTreeItems.push({ label: 'Reputation', value: String(rep.weightedScore), last: true });
24
+ else trustTreeItems[trustTreeItems.length - 1].last = true;
25
+ renderTree(trustTreeItems);
17
26
  });
18
27
  }
@@ -31,6 +31,7 @@ export function registerVerifyCommand(program: Command): void {
31
31
  if (!config.serviceAgreementAddress) throw new Error("serviceAgreementAddress missing in config");
32
32
  const { signer } = await requireSigner(config);
33
33
  printSenderInfo(config);
34
+ const spinner = startSpinner('Submitting…');
34
35
 
35
36
  // Pre-flight: check agreement is in PENDING_VERIFICATION status (J2-04)
36
37
  if (!opts.auto) {
@@ -64,12 +65,12 @@ export function registerVerifyCommand(program: Command): void {
64
65
  SERVICE_AGREEMENT_ABI, "autoRelease", [BigInt(id)],
65
66
  );
66
67
  if (opts.json) return console.log(JSON.stringify({ agreementId: id, action: "autoRelease", txHash: tx.hash }));
67
- console.log(`autoRelease submitted for agreement #${id}. tx=${tx.hash}`);
68
+ spinner.succeed('Auto-released agreement #' + id + ' — tx ' + tx.hash.slice(0, 10) + '...');
68
69
  } else {
69
70
  const client = new ServiceAgreementClient(config.serviceAgreementAddress, signer);
70
71
  const tx = await client.autoRelease(BigInt(id));
71
72
  if (opts.json) return console.log(JSON.stringify({ agreementId: id, action: "autoRelease", txHash: tx.hash }));
72
- console.log(`autoRelease submitted for agreement #${id}. tx=${tx.hash}`);
73
+ spinner.succeed('Auto-released agreement #' + id + ' — tx ' + tx.hash.slice(0, 10) + '...');
73
74
  }
74
75
  } else {
75
76
  if (config.walletContractAddress) {
@@ -78,12 +79,12 @@ export function registerVerifyCommand(program: Command): void {
78
79
  SERVICE_AGREEMENT_ABI, "verifyDeliverable", [BigInt(id)],
79
80
  );
80
81
  if (opts.json) return console.log(JSON.stringify({ agreementId: id, action: "verifyDeliverable", txHash: tx.hash }));
81
- console.log(`Agreement #${id} verified — escrow released. tx=${tx.hash}`);
82
+ spinner.succeed('Verified — agreement #' + id + ' — escrow released');
82
83
  } else {
83
84
  const client = new ServiceAgreementClient(config.serviceAgreementAddress, signer);
84
85
  const tx = await client.verifyDeliverable(BigInt(id));
85
86
  if (opts.json) return console.log(JSON.stringify({ agreementId: id, action: "verifyDeliverable", txHash: tx.hash }));
86
- console.log(`Agreement #${id} verified — escrow released. tx=${tx.hash}`);
87
+ spinner.succeed('Verified — agreement #' + id + ' — escrow released');
87
88
  }
88
89
  }
89
90
  });