@heyanon-arp/cli 0.0.16 → 0.0.18

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 (3) hide show
  1. package/dist/cli.js +1043 -847
  2. package/dist/cli.js.map +1 -1
  3. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -345,6 +345,10 @@ var init_api = __esm({
345
345
  async discoverProfile(did) {
346
346
  return this.get(`/v1/discovery/agents/${encodeURIComponent(did)}/profile`);
347
347
  }
348
+ /** Public `GET /v1/discovery/agents/by-name/:name`. Resolves a unique name → composed profile (incl. DID). 404 if unknown. */
349
+ async discoverByName(name) {
350
+ return this.get(`/v1/discovery/agents/by-name/${encodeURIComponent(name)}`);
351
+ }
348
352
  /**
349
353
  * Public `GET /v1/escrow/config`. Returns the live on-chain V2
350
354
  * Config PDA (fees / pause / stakes / windows). No auth.
@@ -722,7 +726,7 @@ var import_simple_update_notifier = __toESM(require("simple-update-notifier"));
722
726
  // package.json
723
727
  var package_default = {
724
728
  name: "@heyanon-arp/cli",
725
- version: "0.0.16",
729
+ version: "0.0.18",
726
730
  description: "Command-line client for the Agent Relationship Protocol \u2014 register agents, sign envelopes, run escrowed work cycles on Solana.",
727
731
  license: "MIT",
728
732
  keywords: ["arp", "agent-relationship-protocol", "did", "solana", "escrow", "ed25519", "agents", "a2a", "cli"],
@@ -767,7 +771,7 @@ var package_default = {
767
771
  };
768
772
 
769
773
  // src/commands/agents.ts
770
- var import_sdk2 = require("@heyanon-arp/sdk");
774
+ var import_sdk3 = require("@heyanon-arp/sdk");
771
775
  var import_chalk3 = __toESM(require("chalk"));
772
776
  init_api();
773
777
 
@@ -804,6 +808,14 @@ function onboardingHelpFooter() {
804
808
  `${import_chalk.default.dim("Then:")} ${import_chalk.default.cyan("heyarp register")} ${import_chalk.default.dim("\u2192 handshake \u2192 delegation \u2192 work \u2192 receipt \u2192 on-chain claim.")}`
805
809
  ].join("\n");
806
810
  }
811
+ function optionPlacementHelpNote() {
812
+ return [
813
+ "",
814
+ `${import_chalk.default.bold("Option placement:")} only ${import_chalk.default.cyan("--trace")}, ${import_chalk.default.cyan("--help")}, ${import_chalk.default.cyan("--version")} are global (before the command).`,
815
+ `Everything else \u2014 ${import_chalk.default.cyan("--json")}, ${import_chalk.default.cyan("--from-did")}, ${import_chalk.default.cyan("--verbose")}, ${import_chalk.default.cyan("--server")}, \u2026 \u2014 is a command option and goes AFTER the command:`,
816
+ ` ${import_chalk.default.cyan("heyarp <command> [options]")} ${import_chalk.default.dim("e.g. heyarp relationships --json --from-did did:arp:\u2026")}`
817
+ ].join("\n");
818
+ }
807
819
  function toCliErrorJson(err, includeStack = false) {
808
820
  const { ApiError: ApiError2 } = (init_api(), __toCommonJS(api_exports));
809
821
  if (err instanceof ApiError2) {
@@ -821,7 +833,9 @@ function toCliErrorJson(err, includeStack = false) {
821
833
  }
822
834
  function emitError(err, opts) {
823
835
  if (opts.json) {
824
- console.error(JSON.stringify(toCliErrorJson(err, opts.verbose)));
836
+ const obj = toCliErrorJson(err, opts.verbose);
837
+ if (opts.hint) obj.hint = opts.hint;
838
+ console.error(JSON.stringify(obj));
825
839
  return;
826
840
  }
827
841
  const { ApiError: ApiError2 } = (init_api(), __toCommonJS(api_exports));
@@ -830,6 +844,7 @@ function emitError(err, opts) {
830
844
  } else {
831
845
  console.error(formatGenericError(err, opts.verbose));
832
846
  }
847
+ if (opts.hint) console.error(`${import_chalk.default.yellow("hint")}: ${opts.hint}`);
833
848
  }
834
849
  function emitActionError(err, command) {
835
850
  let root = command;
@@ -901,6 +916,7 @@ function formatAgentsTable(rows) {
901
916
  // src/state.ts
902
917
  var import_node_fs3 = require("fs");
903
918
  var import_node_path4 = require("path");
919
+ var import_sdk2 = require("@heyanon-arp/sdk");
904
920
  init_api();
905
921
 
906
922
  // src/credentials.ts
@@ -1129,9 +1145,25 @@ function warnIfForeignOwner(agent, serverUrl) {
1129
1145
  function resolveSenderAgent(cmdName, serverOverride, explicitFromDid) {
1130
1146
  const resolvedServerUrl = resolveServerUrl(serverOverride);
1131
1147
  if (explicitFromDid) {
1132
- const agent = loadAgentOrThrow(serverOverride, explicitFromDid);
1133
- warnIfForeignOwner(agent, resolvedServerUrl);
1134
- return agent;
1148
+ if (explicitFromDid.startsWith("did:arp:")) {
1149
+ const agent = loadAgentOrThrow(serverOverride, explicitFromDid);
1150
+ warnIfForeignOwner(agent, resolvedServerUrl);
1151
+ return agent;
1152
+ }
1153
+ const wanted = (0, import_sdk2.normalizeName)(explicitFromDid);
1154
+ const named = listAgents().filter((row) => row.serverUrl === resolvedServerUrl && row.agent.name === wanted);
1155
+ if (named.length === 1) {
1156
+ warnIfForeignOwner(named[0].agent, resolvedServerUrl);
1157
+ return named[0].agent;
1158
+ }
1159
+ if (named.length === 0) {
1160
+ throw new Error(`${cmdName}: no local agent named '${wanted}' for ${resolvedServerUrl}. Pass its did:arp: DID, or register/recover that agent locally first.`);
1161
+ }
1162
+ const dups = named.map((row) => ` ${row.agent.did}`).join("\n");
1163
+ throw new Error(
1164
+ `${cmdName}: ${named.length} local agents share the name '${wanted}' for ${resolvedServerUrl} \u2014 ambiguous. Pass the did:arp: DID instead. Candidates:
1165
+ ${dups}`
1166
+ );
1135
1167
  }
1136
1168
  const onServer = listAgents().filter((row) => row.serverUrl === resolvedServerUrl);
1137
1169
  if (onServer.length === 1) {
@@ -1162,19 +1194,28 @@ function listAgents() {
1162
1194
  var import_chalk2 = __toESM(require("chalk"));
1163
1195
  init_api();
1164
1196
  function registerLifecycleCommands(root) {
1165
- root.command("update").description("Update an agent profile (name / description / tags). At least one flag is required.").argument("<did>").option("--server <url>", "Override ARP server base URL").option("--name <s>", "New display name").option("--description <s>", "New description").option("--tag <s>", "Capability tag \u2014 REPLACES the existing list. Repeatable: --tag translation --tag fr", accumulate, []).option("--clear-tags", "Drop all tags (cannot be combined with --tag)", false).action(
1197
+ root.command("update").description("Update an agent profile (description / tags). At least one flag is required. The agent name is immutable and cannot be changed.").argument("[did]", "Agent DID (did:arp:...) \u2014 optional when --from-did is given OR exactly one agent is registered for the resolved server.").option("--server <url>", "Override ARP server base URL").option("--from-did <did>", "Alias for the positional <did> \u2014 accepted for consistency with other signed commands. Must match the positional if both are given.").option("--description <s>", "New description").option("--tag <s>", "Capability tag \u2014 REPLACES the existing list. Repeatable: --tag translation --tag fr", accumulate, []).option("--clear-tags", "Drop all tags (cannot be combined with --tag)", false).option("--json", "Machine-readable mode \u2014 emit the updated profile as a single JSON object on stdout (AgentPublic). Prelude moves to stderr. ", false).action(
1166
1198
  async (did, opts) => {
1199
+ if (did !== void 0 && opts.fromDid !== void 0 && did !== opts.fromDid) {
1200
+ throw new Error(`update: positional <did> (${did}) and --from-did (${opts.fromDid}) disagree \u2014 pass only one`);
1201
+ }
1202
+ const explicitDid = did ?? opts.fromDid;
1203
+ const targetDid = (explicitDid !== void 0 ? loadAgentOrThrow(opts.server, explicitDid) : resolveSenderAgent("update", opts.server, void 0)).did;
1167
1204
  const body = buildUpdateBody(opts);
1168
1205
  if (Object.keys(body).length === 0) {
1169
- throw new Error("update: pass at least one of --name / --description / --tag / --clear-tags");
1206
+ throw new Error("update: pass at least one of --description / --tag / --clear-tags");
1170
1207
  }
1171
- const agent = await actSigned(did, opts.server, (api, signer) => api.updateAgent(did, body, signer));
1172
- updateAgentLocal(opts.server, did, {
1208
+ const agent = await actSigned(targetDid, opts.server, opts.json, (api, signer) => api.updateAgent(targetDid, body, signer));
1209
+ updateAgentLocal(opts.server, targetDid, {
1173
1210
  name: agent.name,
1174
1211
  description: agent.description,
1175
1212
  tags: agent.tags
1176
1213
  });
1177
- printAgent("Updated", agent);
1214
+ if (opts.json) {
1215
+ jsonOut(agent);
1216
+ } else {
1217
+ printAgent("Updated", agent);
1218
+ }
1178
1219
  }
1179
1220
  );
1180
1221
  }
@@ -1186,7 +1227,6 @@ function buildUpdateBody(opts) {
1186
1227
  throw new Error("update: --clear-tags cannot be combined with --tag");
1187
1228
  }
1188
1229
  const body = {};
1189
- if (opts.name !== void 0) body.name = opts.name;
1190
1230
  if (opts.description !== void 0) body.description = opts.description;
1191
1231
  if (opts.clearTags) {
1192
1232
  body.tags = [];
@@ -1195,11 +1235,11 @@ function buildUpdateBody(opts) {
1195
1235
  }
1196
1236
  return body;
1197
1237
  }
1198
- async function actSigned(did, serverOverride, act) {
1238
+ async function actSigned(did, serverOverride, json, act) {
1199
1239
  const local = loadAgentOrThrow(serverOverride, did);
1200
1240
  const api = new ArpApiClient(serverOverride);
1201
- console.log(import_chalk2.default.dim(`Server: ${api.serverUrl}`));
1202
- console.log(import_chalk2.default.dim(`Signer: ${local.did}`));
1241
+ progress(json, import_chalk2.default.dim(`Server: ${api.serverUrl}`));
1242
+ progress(json, import_chalk2.default.dim(`Signer: ${local.did}`));
1203
1243
  const signer = makeSigner(local);
1204
1244
  return act(api, signer);
1205
1245
  }
@@ -1245,10 +1285,10 @@ function registerAgentsCommand(root) {
1245
1285
  }
1246
1286
  async function runAgents(opts) {
1247
1287
  const limit = parseLimit(opts.limit);
1248
- if (opts.sort && opts.sort !== "reputation" && opts.sort !== "recent" && opts.sort !== "created") {
1288
+ if (opts.sort && opts.sort !== import_sdk3.DiscoverySorts.REPUTATION && opts.sort !== import_sdk3.DiscoverySorts.RECENT && opts.sort !== import_sdk3.DiscoverySorts.CREATED) {
1249
1289
  throw new Error(`agents: --sort must be 'reputation', 'recent', or 'created' (got '${opts.sort}')`);
1250
1290
  }
1251
- const sort = opts.sort === "recent" ? "recent" : opts.sort === "created" ? "created" : "reputation";
1291
+ const sort = opts.sort === import_sdk3.DiscoverySorts.RECENT ? import_sdk3.DiscoverySorts.RECENT : opts.sort === import_sdk3.DiscoverySorts.CREATED ? import_sdk3.DiscoverySorts.CREATED : import_sdk3.DiscoverySorts.REPUTATION;
1252
1292
  const api = new ArpApiClient(opts.server);
1253
1293
  progress(opts.json, import_chalk3.default.dim(`Server: ${api.serverUrl}`));
1254
1294
  const query = { limit, sort };
@@ -1257,7 +1297,7 @@ async function runAgents(opts) {
1257
1297
  if (opts.accountId) query.accountId = opts.accountId;
1258
1298
  if (opts.accepts) query.accepts = resolveAcceptsAsset(opts.accepts);
1259
1299
  if (opts.online) query.online = true;
1260
- if (sort === "created") {
1300
+ if (sort === import_sdk3.DiscoverySorts.CREATED) {
1261
1301
  if (opts.after) query.after = opts.after;
1262
1302
  } else {
1263
1303
  query.page = parsePage(opts.page);
@@ -1296,10 +1336,10 @@ ${rule}`);
1296
1336
  `);
1297
1337
  }
1298
1338
  if (pagination.hasMore) {
1299
- if (sort === "created" && pagination.nextCursor) {
1339
+ if (sort === import_sdk3.DiscoverySorts.CREATED && pagination.nextCursor) {
1300
1340
  console.log(import_chalk3.default.dim(`
1301
1341
  Next page: re-run with --after ${pagination.nextCursor}`));
1302
- } else if (sort !== "created") {
1342
+ } else if (sort !== import_sdk3.DiscoverySorts.CREATED) {
1303
1343
  console.log(import_chalk3.default.dim(`
1304
1344
  Next page: re-run with --page ${parsePage(opts.page) + 1}`));
1305
1345
  }
@@ -1338,7 +1378,7 @@ function parsePage(raw) {
1338
1378
  return n;
1339
1379
  }
1340
1380
  function resolveAcceptsAsset(input) {
1341
- const resolved = (0, import_sdk2.resolveAsset)(input);
1381
+ const resolved = (0, import_sdk3.resolveAsset)(input);
1342
1382
  if (!resolved) {
1343
1383
  throw new Error(`agents: --accepts '${input}' is not a known asset shorthand or a valid CAIP-19 id.`);
1344
1384
  }
@@ -1467,11 +1507,11 @@ function printAcceptPrefs(prefs) {
1467
1507
  }
1468
1508
 
1469
1509
  // src/commands/assets.ts
1470
- var import_sdk3 = require("@heyanon-arp/sdk");
1510
+ var import_sdk4 = require("@heyanon-arp/sdk");
1471
1511
  var import_chalk4 = __toESM(require("chalk"));
1472
1512
  function renderAssetsText() {
1473
1513
  const lines = [];
1474
- for (const [cluster, assets] of Object.entries(import_sdk3.ASSET_WHITELIST)) {
1514
+ for (const [cluster, assets] of Object.entries(import_sdk4.ASSET_WHITELIST)) {
1475
1515
  lines.push(import_chalk4.default.bold(cluster));
1476
1516
  for (const a of assets) {
1477
1517
  const key = `${a.symbol}:${cluster}`;
@@ -1487,7 +1527,7 @@ function renderAssetsText() {
1487
1527
  function registerAssetsCommand(root) {
1488
1528
  root.command("assets").description("List the payment-asset whitelist (per cluster) \u2014 currencies the server accepts for delegations").option("--json", "machine-readable output (the per-cluster whitelist table)").action((opts) => {
1489
1529
  if (opts.json) {
1490
- console.log(formatJson(import_sdk3.ASSET_WHITELIST));
1530
+ console.log(formatJson(import_sdk4.ASSET_WHITELIST));
1491
1531
  return;
1492
1532
  }
1493
1533
  console.log(renderAssetsText());
@@ -1495,13 +1535,14 @@ function registerAssetsCommand(root) {
1495
1535
  }
1496
1536
 
1497
1537
  // src/commands/block.ts
1538
+ var import_sdk5 = require("@heyanon-arp/sdk");
1498
1539
  var import_chalk5 = __toESM(require("chalk"));
1499
1540
  init_api();
1500
1541
  function resolveSigningAgent(opts) {
1501
1542
  return opts.fromDid !== void 0 ? loadAgentOrThrow(opts.server, opts.fromDid) : resolveSenderAgent("block", opts.server, void 0);
1502
1543
  }
1503
1544
  function formatBlockRow(b) {
1504
- const scope = b.scope === "account" ? import_chalk5.default.yellow("account") : import_chalk5.default.cyan("did");
1545
+ const scope = b.scope === import_sdk5.InboxBlockScopes.ACCOUNT ? import_chalk5.default.yellow("account") : import_chalk5.default.cyan("did");
1505
1546
  const reason = b.reason ? import_chalk5.default.dim(` \u2014 ${b.reason}`) : "";
1506
1547
  return `${scope.padEnd(7)} ${b.did}${reason} ${import_chalk5.default.dim(b.blockedAt)}`;
1507
1548
  }
@@ -1526,7 +1567,7 @@ async function runAdd(did, opts) {
1526
1567
  jsonOut(result);
1527
1568
  return;
1528
1569
  }
1529
- const what = result.scope === "account" ? `the owner account of ${did} (all its agents)` : did;
1570
+ const what = result.scope === import_sdk5.InboxBlockScopes.ACCOUNT ? `the owner account of ${did} (all its agents)` : did;
1530
1571
  console.log(import_chalk5.default.green(`\u2713 Blocked ${what}.`));
1531
1572
  }
1532
1573
  async function runRemove(did, opts) {
@@ -1642,14 +1683,15 @@ function unknownKey(key) {
1642
1683
 
1643
1684
  // src/commands/delegation.ts
1644
1685
  var import_node_fs4 = require("fs");
1645
- var import_sdk7 = require("@heyanon-arp/sdk");
1646
- var import_chalk8 = __toESM(require("chalk"));
1686
+ var import_sdk12 = require("@heyanon-arp/sdk");
1687
+ var import_chalk9 = __toESM(require("chalk"));
1647
1688
  init_api();
1648
1689
 
1649
1690
  // src/id-format.ts
1691
+ var import_sdk6 = require("@heyanon-arp/sdk");
1650
1692
  var UUID_RE = /^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$/;
1651
1693
  var OBJECT_ID_24_HEX_RE = /^[0-9a-f]{24}$/;
1652
- var SHA256_PREFIX_RE = /^sha256:[0-9a-f]{64}$/;
1694
+ var SHA256_PREFIX_RE = import_sdk6.SHA256_HEX_RE;
1653
1695
  var UUID_NO_DASHES_RE = /^[a-fA-F0-9]{32}$/;
1654
1696
  function describeNonUuidShape(raw) {
1655
1697
  if (raw === "") return "empty string";
@@ -1680,10 +1722,31 @@ function requireUuid(cmdName, raw, label) {
1680
1722
  throw new Error(hint ? `${base} \u2014 ${hint}` : base);
1681
1723
  }
1682
1724
 
1683
- // src/commands/status.ts
1684
- var import_sdk4 = require("@heyanon-arp/sdk");
1725
+ // src/resolve-recipient.ts
1726
+ var import_sdk7 = require("@heyanon-arp/sdk");
1685
1727
  var import_chalk7 = __toESM(require("chalk"));
1686
1728
  init_api();
1729
+ async function resolveRecipient(serverOverride, cmdName, input, opts = {}) {
1730
+ if (input.startsWith("did:arp:")) {
1731
+ if (!(0, import_sdk7.isValidDid)(input)) {
1732
+ throw new Error(`${cmdName}: '${input}' starts with did:arp: but is not a valid DID (base58btc-encoded 32-byte Ed25519 pubkey).`);
1733
+ }
1734
+ return input;
1735
+ }
1736
+ const name = (0, import_sdk7.normalizeName)(input);
1737
+ if (!(0, import_sdk7.isValidAgentName)(name)) {
1738
+ throw new Error(`${cmdName}: '${input}' is neither a DID (did:arp:...) nor a valid agent name (lowercase a-z0-9_, 3-32 chars).`);
1739
+ }
1740
+ const api = new ArpApiClient(serverOverride);
1741
+ const profile = await api.discoverByName(name);
1742
+ warn(opts.json, import_chalk7.default.dim(`Resolved ${import_chalk7.default.cyan(name)} \u2192 ${profile.did}${profile.description ? ` (${profile.description})` : ""}`));
1743
+ return profile.did;
1744
+ }
1745
+
1746
+ // src/commands/status.ts
1747
+ var import_sdk8 = require("@heyanon-arp/sdk");
1748
+ var import_chalk8 = __toESM(require("chalk"));
1749
+ init_api();
1687
1750
  var UNTIL_PHASES = [
1688
1751
  "delegation.offered",
1689
1752
  "delegation.accepted",
@@ -1731,9 +1794,9 @@ async function runStatus(relationshipId, opts) {
1731
1794
  const api = new ArpApiClient(opts.server);
1732
1795
  const sender = resolveSenderAgent("status", opts.server, opts.fromDid);
1733
1796
  if (!opts.json) {
1734
- console.log(import_chalk7.default.dim(`Server: ${api.serverUrl}`));
1735
- console.log(import_chalk7.default.dim(`Signer: ${sender.did}`));
1736
- console.log(import_chalk7.default.dim(`Relationship: ${relationshipId}`));
1797
+ console.log(import_chalk8.default.dim(`Server: ${api.serverUrl}`));
1798
+ console.log(import_chalk8.default.dim(`Signer: ${sender.did}`));
1799
+ console.log(import_chalk8.default.dim(`Relationship: ${relationshipId}`));
1737
1800
  }
1738
1801
  const signer = makeSigner(sender);
1739
1802
  if (!opts.wait) {
@@ -1765,7 +1828,7 @@ async function runStatus(relationshipId, opts) {
1765
1828
  async function awaitFsmTransitionAfterAction(input) {
1766
1829
  const { api, signerDid, signer, relationshipId, untilPhase, waitIntervalSec, waitTimeoutSec, waitVerbose, json } = input;
1767
1830
  if (!json) {
1768
- console.log(import_chalk7.default.dim(`
1831
+ console.log(import_chalk8.default.dim(`
1769
1832
  [--wait-until ${untilPhase}] polling relationship ${relationshipId} (interval=${waitIntervalSec}s timeout=${waitTimeoutSec}s)`));
1770
1833
  }
1771
1834
  const outcome = await runWaitLoop({
@@ -1782,13 +1845,13 @@ async function awaitFsmTransitionAfterAction(input) {
1782
1845
  }
1783
1846
  }
1784
1847
  async function runWaitLoop(opts) {
1785
- const isTerminal = (s) => s.cycleComplete || s.relationshipState === "closed" || s.relationshipState === "not_found";
1848
+ const isTerminal = (s) => s.cycleComplete || s.relationshipState === import_sdk8.RelationshipStates.CLOSED || s.relationshipState === "not_found";
1786
1849
  const isActionable = (s) => {
1787
1850
  if (s.nextActionOwner === "me") {
1788
1851
  if (s.relationshipState === "unknown") return false;
1789
1852
  return true;
1790
1853
  }
1791
- if (s.nextActionOwner === "either" && s.relationshipState === "active") {
1854
+ if (s.nextActionOwner === "either" && s.relationshipState === import_sdk8.RelationshipStates.ACTIVE) {
1792
1855
  return true;
1793
1856
  }
1794
1857
  return false;
@@ -1804,7 +1867,7 @@ async function runWaitLoop(opts) {
1804
1867
  }
1805
1868
  if (isUntilReached !== null && isUntilReached(initial)) {
1806
1869
  if (opts.json) opts.log(JSON.stringify(initial));
1807
- else opts.log(import_chalk7.default.dim(`
1870
+ else opts.log(import_chalk8.default.dim(`
1808
1871
  [--wait] Phase '${opts.until}' already reached \u2014 exiting without polling.`));
1809
1872
  return { timedOut: false, last: initial };
1810
1873
  }
@@ -1815,13 +1878,13 @@ async function runWaitLoop(opts) {
1815
1878
  else {
1816
1879
  if (opts.until !== void 0) {
1817
1880
  opts.log(
1818
- import_chalk7.default.yellow(
1881
+ import_chalk8.default.yellow(
1819
1882
  `
1820
1883
  [--wait] Terminal state (${initial.relationshipState}, cycleComplete=${initial.cycleComplete}) reached before phase '${opts.until}' \u2014 exiting; phase unreachable.`
1821
1884
  )
1822
1885
  );
1823
1886
  } else {
1824
- opts.log(import_chalk7.default.dim(`
1887
+ opts.log(import_chalk8.default.dim(`
1825
1888
  [--wait] Already terminal \u2014 exiting.`));
1826
1889
  }
1827
1890
  }
@@ -1829,15 +1892,15 @@ async function runWaitLoop(opts) {
1829
1892
  }
1830
1893
  if (opts.until === void 0 && isActionable(initial)) {
1831
1894
  if (opts.json) opts.log(JSON.stringify(initial));
1832
- else opts.log(import_chalk7.default.dim(`
1895
+ else opts.log(import_chalk8.default.dim(`
1833
1896
  [--wait] Your turn already (nextActionOwner=${initial.nextActionOwner}) \u2014 exiting without polling.`));
1834
1897
  return { timedOut: false, last: initial };
1835
1898
  }
1836
1899
  if (!opts.json) {
1837
1900
  const blockerLabel = opts.until !== void 0 ? `Awaiting phase '${opts.until}'` : initial.nextActionOwner === "counterparty" ? "Counterparty owes the next move" : initial.nextActionOwner === "either" ? "Either side may act" : `Awaiting state change (currently ${initial.relationshipState}, nextActionOwner=${initial.nextActionOwner})`;
1838
- opts.log(import_chalk7.default.dim(`
1901
+ opts.log(import_chalk8.default.dim(`
1839
1902
  [--wait] ${blockerLabel}. Polling every ${opts.waitIntervalSec}s, timeout ${opts.waitTimeoutSec}s.`));
1840
- opts.log(import_chalk7.default.dim(`[--wait] Initial hint: ${initial.nextActionHint}`));
1903
+ opts.log(import_chalk8.default.dim(`[--wait] Initial hint: ${initial.nextActionHint}`));
1841
1904
  }
1842
1905
  const startedAt = localNow();
1843
1906
  const deadline = startedAt + opts.waitTimeoutSec * 1e3;
@@ -1857,7 +1920,7 @@ async function runWaitLoop(opts) {
1857
1920
  } else {
1858
1921
  target = `nextActionOwner=${next.nextActionOwner}`;
1859
1922
  }
1860
- opts.log(import_chalk7.default.dim(`[--wait tick ${tickIndex}/${maxTicks}] state=${next.relationshipState}, ${formatPhaseSnapshot(next)} (${target})`));
1923
+ opts.log(import_chalk8.default.dim(`[--wait tick ${tickIndex}/${maxTicks}] state=${next.relationshipState}, ${formatPhaseSnapshot(next)} (${target})`));
1861
1924
  }
1862
1925
  if (exitPredicate(next)) {
1863
1926
  const phaseReached = isUntilReached !== null ? isUntilReached(next) : false;
@@ -1867,16 +1930,16 @@ async function runWaitLoop(opts) {
1867
1930
  opts.log("");
1868
1931
  if (opts.until !== void 0) {
1869
1932
  if (phaseReached) {
1870
- opts.log(import_chalk7.default.green(`[--wait] Phase '${opts.until}' reached.`));
1933
+ opts.log(import_chalk8.default.green(`[--wait] Phase '${opts.until}' reached.`));
1871
1934
  } else {
1872
1935
  opts.log(
1873
- import_chalk7.default.yellow(
1936
+ import_chalk8.default.yellow(
1874
1937
  `[--wait] Terminal state (${next.relationshipState}, cycleComplete=${next.cycleComplete}) reached before phase '${opts.until}' \u2014 phase unreachable.`
1875
1938
  )
1876
1939
  );
1877
1940
  }
1878
1941
  } else {
1879
- opts.log(import_chalk7.default.green(`[--wait] ${isTerminal(next) ? "Cycle terminated" : `Your turn (owner=${next.nextActionOwner})`}.`));
1942
+ opts.log(import_chalk8.default.green(`[--wait] ${isTerminal(next) ? "Cycle terminated" : `Your turn (owner=${next.nextActionOwner})`}.`));
1880
1943
  }
1881
1944
  opts.log(formatStatusReport(next));
1882
1945
  }
@@ -1889,14 +1952,14 @@ async function runWaitLoop(opts) {
1889
1952
  } else {
1890
1953
  if (opts.until !== void 0) {
1891
1954
  opts.log(
1892
- import_chalk7.default.yellow(
1955
+ import_chalk8.default.yellow(
1893
1956
  `
1894
1957
  [--wait] Timed out after ${opts.waitTimeoutSec}s without reaching phase '${opts.until}' (latest state: ${last.relationshipState}, hint: ${last.nextActionHint}).`
1895
1958
  )
1896
1959
  );
1897
1960
  } else {
1898
1961
  opts.log(
1899
- import_chalk7.default.yellow(`
1962
+ import_chalk8.default.yellow(`
1900
1963
  [--wait] Timed out after ${opts.waitTimeoutSec}s without an actionable or terminal transition (your turn never came, cycle still in flight).`)
1901
1964
  );
1902
1965
  }
@@ -1924,41 +1987,41 @@ function parseUntilPhase(raw) {
1924
1987
  function isPhaseTerminallyUnreachable(phase, s) {
1925
1988
  if (untilPhaseMatched(phase, s)) return false;
1926
1989
  if (s.relationshipState === "not_found") return true;
1927
- if (s.relationshipState === "closed" && phase !== "relationship.closed") return true;
1990
+ if (s.relationshipState === import_sdk8.RelationshipStates.CLOSED && phase !== "relationship.closed") return true;
1928
1991
  return false;
1929
1992
  }
1930
1993
  function untilPhaseMatched(phase, s) {
1931
1994
  switch (phase) {
1932
1995
  case "delegation.offered":
1933
- return s.latestDelegation?.state === "offered";
1996
+ return s.latestDelegation?.state === import_sdk8.DelegationStates.OFFERED;
1934
1997
  case "delegation.accepted":
1935
- return s.latestDelegation?.state === "accepted";
1998
+ return s.latestDelegation?.state === import_sdk8.DelegationStates.ACCEPTED;
1936
1999
  case "delegation.locked":
1937
- return s.latestDelegation?.state === "locked";
2000
+ return s.latestDelegation?.state === import_sdk8.DelegationStates.LOCKED;
1938
2001
  case "delegation.disputing":
1939
- return s.latestDelegation?.state === "disputing";
2002
+ return s.latestDelegation?.state === import_sdk8.DelegationStates.DISPUTING;
1940
2003
  case "delegation.canceled":
1941
- return s.latestDelegation?.state === "canceled";
2004
+ return s.latestDelegation?.state === import_sdk8.DelegationStates.CANCELED;
1942
2005
  case "delegation.declined":
1943
- return s.latestDelegation?.state === "declined";
2006
+ return s.latestDelegation?.state === import_sdk8.DelegationStates.DECLINED;
1944
2007
  case "work.requested":
1945
- return s.latestWorkLog?.state === "requested";
2008
+ return s.latestWorkLog?.state === import_sdk8.WorkLogStates.REQUESTED;
1946
2009
  case "work.responded":
1947
- return s.latestWorkLog?.state === "responded";
2010
+ return s.latestWorkLog?.state === import_sdk8.WorkLogStates.RESPONDED;
1948
2011
  case "receipt.proposed":
1949
2012
  return s.latestReceipt != null;
1950
2013
  case "relationship.pending":
1951
- return s.relationshipState === "pending";
2014
+ return s.relationshipState === import_sdk8.RelationshipStates.PENDING;
1952
2015
  case "relationship.active":
1953
- return s.relationshipState === "active";
2016
+ return s.relationshipState === import_sdk8.RelationshipStates.ACTIVE;
1954
2017
  case "relationship.paused":
1955
- return s.relationshipState === "paused";
2018
+ return s.relationshipState === import_sdk8.RelationshipStates.PAUSED;
1956
2019
  case "relationship.closed":
1957
- return s.relationshipState === "closed";
2020
+ return s.relationshipState === import_sdk8.RelationshipStates.CLOSED;
1958
2021
  case "cycle.complete":
1959
2022
  return s.cycleComplete;
1960
2023
  case "cycle.released":
1961
- return s.latestDelegation?.state === "completed";
2024
+ return s.latestDelegation?.state === import_sdk8.DelegationStates.COMPLETED;
1962
2025
  }
1963
2026
  }
1964
2027
  function parseWaitInterval(raw) {
@@ -2009,7 +2072,7 @@ async function composeStatus(api, signerDid, relationshipId, signer) {
2009
2072
  const relationship = relationships.find((r) => r.relationshipId === relationshipId);
2010
2073
  const counterpartyDid = relationship ? relationship.pairDidA === signerDid ? relationship.pairDidB : relationship.pairDidA : inferCounterpartyFromEntities(signerDid, allDelegations);
2011
2074
  const delegations = allDelegations;
2012
- const latestDelegation = pickLatestLive(delegations, ["offered", "accepted", "pending_lock_finalization", "locked"]);
2075
+ const latestDelegation = pickLatestLive(delegations, [...import_sdk8.DELEGATION_ACTIVE_STATES]);
2013
2076
  const [workLogs, receipts] = await Promise.all([
2014
2077
  latestDelegation ? fetchAllPages(
2015
2078
  (after) => api.listWorkLogs(relationshipId, signer, { limit: 100, delegationId: latestDelegation.delegationId, ...after ? { after } : {} })
@@ -2073,8 +2136,8 @@ function findReceiptForWorkLog(receipts, workLog, allWorkLogs = [workLog]) {
2073
2136
  };
2074
2137
  const responseBody = workLog.responseOutput !== void 0 ? { type: "work_response", content: { delegation_id: workLog.delegationId, request_id: workLog.requestId, output: workLog.responseOutput } } : workLog.responseError !== void 0 ? { type: "work_response", content: { delegation_id: workLog.delegationId, request_id: workLog.requestId, error: workLog.responseError } } : null;
2075
2138
  if (!responseBody) return null;
2076
- const expectedRequestHash = (0, import_sdk4.canonicalSha256Hex)(requestBody);
2077
- const expectedResponseHash = (0, import_sdk4.canonicalSha256Hex)(responseBody);
2139
+ const expectedRequestHash = (0, import_sdk8.canonicalSha256Hex)(requestBody);
2140
+ const expectedResponseHash = (0, import_sdk8.canonicalSha256Hex)(responseBody);
2078
2141
  const matches = receipts.filter((r) => r.requestHash === expectedRequestHash && r.responseHash === expectedResponseHash);
2079
2142
  if (matches.length > 0) return pickLatest(matches);
2080
2143
  const respondedSiblings = allWorkLogs.filter((wl) => wl.delegationId === workLog.delegationId && (wl.responseOutput !== void 0 || wl.responseError !== void 0)).length;
@@ -2116,49 +2179,49 @@ function nextAction(input) {
2116
2179
  complete: false
2117
2180
  };
2118
2181
  }
2119
- if (relationship.state === "pending") {
2182
+ if (relationship.state === import_sdk8.RelationshipStates.PENDING) {
2120
2183
  return {
2121
2184
  hint: "Relationship is PENDING \u2014 one side owes `heyarp send-handshake-response <peer> --decision accept | decline`",
2122
2185
  owner: "either",
2123
2186
  complete: false
2124
2187
  };
2125
2188
  }
2126
- if (relationship.state === "paused") {
2189
+ if (relationship.state === import_sdk8.RelationshipStates.PAUSED) {
2127
2190
  return { hint: "Relationship is PAUSED \u2014 owner must `heyarp unpause` before any envelopes flow", owner: "either", complete: false };
2128
2191
  }
2129
- if (relationship.state === "closed") {
2192
+ if (relationship.state === import_sdk8.RelationshipStates.CLOSED) {
2130
2193
  return { hint: "Relationship is CLOSED \u2014 terminal state, no further action possible. Start a fresh handshake to reopen.", owner: "none", complete: false };
2131
2194
  }
2132
- if (!latestDelegation || latestDelegation.state === "declined" || latestDelegation.state === "canceled") {
2195
+ if (!latestDelegation || latestDelegation.state === import_sdk8.DelegationStates.DECLINED || latestDelegation.state === import_sdk8.DelegationStates.CANCELED) {
2133
2196
  return {
2134
2197
  hint: "No live delegation \u2014 buyer offers (terms only, no lock) `heyarp delegation offer <peer> --delegation-id <new-uuid> --title \u2026 --scope \u2026 --amount \u2026 --currency SOL:solana-devnet --deadline \u2026`, then funds the escrow lock AFTER the worker accepts via `heyarp delegation fund <del-id> --escrow-lock-from-file <path>`",
2135
2198
  owner: "either",
2136
2199
  complete: false
2137
2200
  };
2138
2201
  }
2139
- if (latestDelegation.state === "disputing") {
2202
+ if (latestDelegation.state === import_sdk8.DelegationStates.DISPUTING) {
2140
2203
  return {
2141
2204
  hint: `Delegation ${latestDelegation.delegationId} is DISPUTING \u2014 the buyer opened an on-chain dispute (their stake is escrowed too). The operator may rule until the dispute window lapses; after that either party closes with \`heyarp escrow dispute close ${latestDelegation.delegationId}\` (escrow returns to the buyer, both stakes return). Deadline: \`heyarp escrow show ${latestDelegation.delegationId}\`. No envelopes to send meanwhile.`,
2142
2205
  owner: "none",
2143
2206
  complete: false
2144
2207
  };
2145
2208
  }
2146
- if (latestDelegation.state === "completed") {
2209
+ if (latestDelegation.state === import_sdk8.DelegationStates.COMPLETED) {
2147
2210
  return {
2148
2211
  hint: "Cycle COMPLETE \u2014 payment claimed on chain (lock paid; the receipt carries releaseStatus=paid)",
2149
2212
  owner: "none",
2150
2213
  complete: true
2151
2214
  };
2152
2215
  }
2153
- if (latestDelegation.state === "failed" || latestDelegation.state === "refunded" || latestDelegation.state === "dispute_resolved") {
2216
+ if (latestDelegation.state === import_sdk8.DelegationStates.FAILED || latestDelegation.state === import_sdk8.DelegationStates.REFUNDED || latestDelegation.state === import_sdk8.DelegationStates.DISPUTE_RESOLVED) {
2154
2217
  const stateLabel = latestDelegation.state.toUpperCase();
2155
- const reason = latestDelegation.state === "failed" ? "on-chain escrow lock failed to finalise (typical causes: insufficient payer funds, wrong program-id, ProgramState PDA uninitialised \u2014 check `heyarp delegations <rel-id> --json | jq .[].escrowError` for the worker-side reason)" : latestDelegation.state === "refunded" ? (
2218
+ const reason = latestDelegation.state === import_sdk8.DelegationStates.FAILED ? "on-chain escrow lock failed to finalise (typical causes: insufficient payer funds, wrong program-id, ProgramState PDA uninitialised \u2014 check `heyarp delegations <rel-id> --json | jq .[].escrowError` for the worker-side reason)" : latestDelegation.state === import_sdk8.DelegationStates.REFUNDED ? (
2156
2219
  // Keyed on the DELEGATION row's releaseStatus, not the
2157
2220
  // receipt's: in the claim-expired path the worker never
2158
2221
  // submitted anything, so no receipt row exists to carry
2159
2222
  // the outcome — the delegation copy is always present
2160
2223
  // on indexer-driven terminals.
2161
- latestDelegation.releaseStatus === "dispute_closed" ? "the dispute window lapsed without an operator ruling and the dispute was closed \u2014 escrow returned to the buyer, both stakes returned (work was delivered but not paid)" : latestDelegation.releaseStatus === "revoked" ? "the work window lapsed without an on-chain submit \u2014 the buyer reclaimed the escrow AND the worker stake (claim_expired_work)" : "lock was refunded after expiry \u2014 no work was delivered against this delegation"
2224
+ latestDelegation.releaseStatus === import_sdk8.LockStates.DISPUTE_CLOSED ? "the dispute window lapsed without an operator ruling and the dispute was closed \u2014 escrow returned to the buyer, both stakes returned (work was delivered but not paid)" : latestDelegation.releaseStatus === import_sdk8.LockStates.REVOKED ? "the work window lapsed without an on-chain submit \u2014 the buyer reclaimed the escrow AND the worker stake (claim_expired_work)" : "lock was refunded after expiry \u2014 no work was delivered against this delegation"
2162
2225
  ) : "admin closed the delegation via the dispute-resolution path";
2163
2226
  return {
2164
2227
  hint: `Delegation ${latestDelegation.delegationId} is ${stateLabel} (terminal) \u2014 ${reason}. Issue a fresh \`heyarp delegation offer <peer> --delegation-id <new-uuid> \u2026\` to retry (FSM does not auto-retry).`,
@@ -2166,7 +2229,7 @@ function nextAction(input) {
2166
2229
  complete: false
2167
2230
  };
2168
2231
  }
2169
- if (latestDelegation.state === "offered") {
2232
+ if (latestDelegation.state === import_sdk8.DelegationStates.OFFERED) {
2170
2233
  const iAmOfferer = latestDelegation.offererDid === signerDid;
2171
2234
  const stateLabel = "OFFERED";
2172
2235
  return {
@@ -2175,7 +2238,7 @@ function nextAction(input) {
2175
2238
  complete: false
2176
2239
  };
2177
2240
  }
2178
- if (latestDelegation.state === "accepted" && !latestWorkLog) {
2241
+ if (latestDelegation.state === import_sdk8.DelegationStates.ACCEPTED && !latestWorkLog) {
2179
2242
  const iAmOfferer = latestDelegation.offererDid === signerDid;
2180
2243
  return {
2181
2244
  hint: iAmOfferer ? `Delegation ${latestDelegation.delegationId} is ACCEPTED \u2014 you (buyer) owe \`heyarp wallet create-lock --delegation-id ${latestDelegation.delegationId} --condition-hash <hex> ... > lock.json\` then \`heyarp delegation fund ${latestDelegation.delegationId} --escrow-lock-from-file lock.json\` (fund the escrow lock; work begins once it is LOCKED on chain)` : `Delegation ${latestDelegation.delegationId} is ACCEPTED \u2014 counterparty (the buyer) owes \`heyarp delegation fund\` to lock the escrow; wait for the delegation to reach LOCKED before working`,
@@ -2183,7 +2246,7 @@ function nextAction(input) {
2183
2246
  complete: false
2184
2247
  };
2185
2248
  }
2186
- if (latestDelegation.state === "pending_lock_finalization" && !latestWorkLog) {
2249
+ if (latestDelegation.state === import_sdk8.DelegationStates.PENDING_LOCK_FINALIZATION && !latestWorkLog) {
2187
2250
  return {
2188
2251
  hint: `Delegation ${latestDelegation.delegationId} is PENDING_LOCK_FINALIZATION \u2014 the escrow lock was funded and is awaiting on-chain confirmation; both sides wait (auto-advances to LOCKED). Poll with \`heyarp status ${relationship.relationshipId} --wait --until delegation.locked\`.`,
2189
2252
  owner: "none",
@@ -2198,7 +2261,7 @@ function nextAction(input) {
2198
2261
  complete: false
2199
2262
  };
2200
2263
  }
2201
- if (latestWorkLog.state === "requested") {
2264
+ if (latestWorkLog.state === import_sdk8.WorkLogStates.REQUESTED) {
2202
2265
  const iAmPayee = latestWorkLog.payeeDid === signerDid;
2203
2266
  return {
2204
2267
  hint: iAmPayee ? `work_request ${latestWorkLog.requestId} is REQUESTED \u2014 you owe \`heyarp work respond\` (output OR --error)` : `work_request ${latestWorkLog.requestId} is REQUESTED \u2014 counterparty (payee) owes \`heyarp work respond\``,
@@ -2250,106 +2313,106 @@ function formatStatusReport(s) {
2250
2313
  const lines = [];
2251
2314
  lines.push(cycleHeadline(s));
2252
2315
  lines.push("");
2253
- lines.push(import_chalk7.default.bold("Relationship"));
2316
+ lines.push(import_chalk8.default.bold("Relationship"));
2254
2317
  lines.push(` state: ${stateColor(s.relationshipState)}`);
2255
- if (s.counterpartyDid) lines.push(` counterparty: ${import_chalk7.default.cyan(s.counterpartyDid)}`);
2318
+ if (s.counterpartyDid) lines.push(` counterparty: ${import_chalk8.default.cyan(s.counterpartyDid)}`);
2256
2319
  lines.push("");
2257
- lines.push(import_chalk7.default.bold("Latest delegation"));
2320
+ lines.push(import_chalk8.default.bold("Latest delegation"));
2258
2321
  if (s.latestDelegation) {
2259
2322
  lines.push(` ${s.latestDelegation.delegationId} state=${stateColor(s.latestDelegation.state)}`);
2260
- lines.push(` offerer: ${import_chalk7.default.cyan(s.latestDelegation.offererDid)}`);
2323
+ lines.push(` offerer: ${import_chalk8.default.cyan(s.latestDelegation.offererDid)}`);
2261
2324
  if (s.latestDelegation.title) lines.push(` title: ${s.latestDelegation.title}`);
2262
2325
  if (s.latestDelegation.scopeSummary) lines.push(` scope: ${s.latestDelegation.scopeSummary}`);
2263
2326
  } else {
2264
- lines.push(import_chalk7.default.dim(" (none)"));
2327
+ lines.push(import_chalk8.default.dim(" (none)"));
2265
2328
  }
2266
2329
  lines.push("");
2267
- lines.push(import_chalk7.default.bold("Latest work_log"));
2330
+ lines.push(import_chalk8.default.bold("Latest work_log"));
2268
2331
  if (s.latestWorkLog) {
2269
2332
  lines.push(` request_id=${s.latestWorkLog.requestId} state=${stateColor(s.latestWorkLog.state)}`);
2270
2333
  } else {
2271
- lines.push(import_chalk7.default.dim(" (none)"));
2334
+ lines.push(import_chalk8.default.dim(" (none)"));
2272
2335
  }
2273
2336
  lines.push("");
2274
- lines.push(import_chalk7.default.bold("Latest receipt"));
2337
+ lines.push(import_chalk8.default.bold("Latest receipt"));
2275
2338
  if (s.latestReceipt) {
2276
2339
  lines.push(` ${stateColor("proposed")} verdict=${s.latestReceipt.verdictProposed}`);
2277
2340
  } else {
2278
- lines.push(import_chalk7.default.dim(" (none)"));
2341
+ lines.push(import_chalk8.default.dim(" (none)"));
2279
2342
  }
2280
2343
  lines.push("");
2281
- lines.push(import_chalk7.default.bold("Next action"));
2282
- const ownerLabel = s.nextActionOwner === "me" ? import_chalk7.default.green("me") : s.nextActionOwner === "counterparty" ? import_chalk7.default.yellow("counterparty") : s.nextActionOwner === "either" ? import_chalk7.default.cyan("either side") : import_chalk7.default.dim("\u2014");
2344
+ lines.push(import_chalk8.default.bold("Next action"));
2345
+ const ownerLabel = s.nextActionOwner === "me" ? import_chalk8.default.green("me") : s.nextActionOwner === "counterparty" ? import_chalk8.default.yellow("counterparty") : s.nextActionOwner === "either" ? import_chalk8.default.cyan("either side") : import_chalk8.default.dim("\u2014");
2283
2346
  lines.push(` whose turn: ${ownerLabel}`);
2284
2347
  lines.push(` hint: ${s.nextActionHint}`);
2285
- if (s.cycleComplete) lines.push(` ${import_chalk7.default.green("\u2713 Cycle complete.")}`);
2348
+ if (s.cycleComplete) lines.push(` ${import_chalk8.default.green("\u2713 Cycle complete.")}`);
2286
2349
  return lines.join("\n");
2287
2350
  }
2288
2351
  function cycleHeadline(s) {
2289
2352
  if (s.cycleComplete) {
2290
- return `${import_chalk7.default.bold("Cycle:")} ${import_chalk7.default.green.bold("COMPLETE")} ${import_chalk7.default.dim("\u2014 payment proven on chain")}`;
2353
+ return `${import_chalk8.default.bold("Cycle:")} ${import_chalk8.default.green.bold("COMPLETE")} ${import_chalk8.default.dim("\u2014 payment proven on chain")}`;
2291
2354
  }
2292
2355
  switch (s.relationshipState) {
2293
2356
  case "not_found":
2294
- return `${import_chalk7.default.bold("Cycle:")} ${import_chalk7.default.red.bold("NOT FOUND")} ${import_chalk7.default.dim("\u2014 relationship missing or signer is not a member")}`;
2357
+ return `${import_chalk8.default.bold("Cycle:")} ${import_chalk8.default.red.bold("NOT FOUND")} ${import_chalk8.default.dim("\u2014 relationship missing or signer is not a member")}`;
2295
2358
  case "unknown":
2296
- return `${import_chalk7.default.bold("Cycle:")} ${import_chalk7.default.yellow.bold("UNKNOWN")} ${import_chalk7.default.dim("\u2014 state probe inconclusive; hint below is advisory")}`;
2297
- case "closed":
2298
- return `${import_chalk7.default.bold("Cycle:")} ${import_chalk7.default.red.bold("CLOSED")} ${import_chalk7.default.dim("\u2014 relationship terminal, no further protocol action")}`;
2299
- case "paused":
2300
- return `${import_chalk7.default.bold("Cycle:")} ${import_chalk7.default.yellow.bold("PAUSED")} ${import_chalk7.default.dim("\u2014 relationship soft-disabled, resume to continue")}`;
2301
- case "pending":
2302
- return `${import_chalk7.default.bold("Cycle:")} ${import_chalk7.default.yellow.bold("PENDING")} ${import_chalk7.default.dim("\u2014 awaiting handshake_response")}`;
2303
- case "active":
2359
+ return `${import_chalk8.default.bold("Cycle:")} ${import_chalk8.default.yellow.bold("UNKNOWN")} ${import_chalk8.default.dim("\u2014 state probe inconclusive; hint below is advisory")}`;
2360
+ case import_sdk8.RelationshipStates.CLOSED:
2361
+ return `${import_chalk8.default.bold("Cycle:")} ${import_chalk8.default.red.bold("CLOSED")} ${import_chalk8.default.dim("\u2014 relationship terminal, no further protocol action")}`;
2362
+ case import_sdk8.RelationshipStates.PAUSED:
2363
+ return `${import_chalk8.default.bold("Cycle:")} ${import_chalk8.default.yellow.bold("PAUSED")} ${import_chalk8.default.dim("\u2014 relationship soft-disabled, resume to continue")}`;
2364
+ case import_sdk8.RelationshipStates.PENDING:
2365
+ return `${import_chalk8.default.bold("Cycle:")} ${import_chalk8.default.yellow.bold("PENDING")} ${import_chalk8.default.dim("\u2014 awaiting handshake_response")}`;
2366
+ case import_sdk8.RelationshipStates.ACTIVE:
2304
2367
  default:
2305
- return `${import_chalk7.default.bold("Cycle:")} ${import_chalk7.default.cyan.bold("ACTIVE")} ${import_chalk7.default.dim('\u2014 work in progress; see "Next action" below')}`;
2368
+ return `${import_chalk8.default.bold("Cycle:")} ${import_chalk8.default.cyan.bold("ACTIVE")} ${import_chalk8.default.dim('\u2014 work in progress; see "Next action" below')}`;
2306
2369
  }
2307
2370
  }
2308
2371
  function stateColor(state) {
2309
- const c = state === "active" || state === "accepted" || state === "locked" || state === "responded" || state === "completed" ? import_chalk7.default.green : state === "pending" || state === "requested" || state === "offered" || state === "pending_lock_finalization" ? import_chalk7.default.yellow : state === "closed" || state === "declined" || state === "canceled" || state === "replaced" || state === "not_found" || // Terminal failure states deserve the same red
2372
+ const c = state === "active" || state === "accepted" || state === "locked" || state === "responded" || state === "completed" ? import_chalk8.default.green : state === "pending" || state === "requested" || state === "offered" || state === "pending_lock_finalization" ? import_chalk8.default.yellow : state === "closed" || state === "declined" || state === "canceled" || state === "replaced" || state === "not_found" || // Terminal failure states deserve the same red
2310
2373
  // treatment as declined/canceled so an operator
2311
2374
  // scanning `heyarp status` immediately sees
2312
2375
  // "this is dead, don't follow the hint blindly".
2313
- state === "failed" || state === "refunded" || state === "dispute_resolved" ? import_chalk7.default.red : import_chalk7.default.cyan;
2376
+ state === "failed" || state === "refunded" || state === "dispute_resolved" ? import_chalk8.default.red : import_chalk8.default.cyan;
2314
2377
  return c(state);
2315
2378
  }
2316
2379
 
2317
2380
  // src/commands/wallet.ts
2318
- var import_sdk6 = require("@heyanon-arp/sdk");
2381
+ var import_sdk11 = require("@heyanon-arp/sdk");
2319
2382
  var import_utils = require("@noble/hashes/utils");
2320
2383
  var import_web32 = require("@solana/web3.js");
2321
2384
  init_api();
2322
2385
  init_config();
2323
2386
 
2324
2387
  // src/solana/escrow-ix.ts
2325
- var import_sdk5 = require("@heyanon-arp/sdk");
2388
+ var import_sdk9 = require("@heyanon-arp/sdk");
2326
2389
  var import_web3 = require("@solana/web3.js");
2327
- var SPL_TOKEN_PROGRAM_ID = new import_web3.PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");
2328
- var ASSOCIATED_TOKEN_PROGRAM_ID = new import_web3.PublicKey("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL");
2329
- var NATIVE_SOL_MINT = new import_web3.PublicKey(new Uint8Array(32));
2390
+ var SPL_TOKEN_PROGRAM_ID = new import_web3.PublicKey(import_sdk9.SPL_TOKEN_PROGRAM_ID_BASE58);
2391
+ var ASSOCIATED_TOKEN_PROGRAM_ID = new import_web3.PublicKey(import_sdk9.ASSOCIATED_TOKEN_PROGRAM_ID_BASE58);
2392
+ var NATIVE_SOL_MINT = new import_web3.PublicKey(import_sdk9.NATIVE_SOL_MINT_BASE58);
2330
2393
  function deriveLockPda(programId, lockId) {
2331
- return import_web3.PublicKey.findProgramAddressSync([Buffer.from(import_sdk5.ESCROW_PDA_SEEDS.LOCK), Buffer.from(lockId)], programId)[0];
2394
+ return import_web3.PublicKey.findProgramAddressSync([Buffer.from(import_sdk9.ESCROW_PDA_SEEDS.LOCK), Buffer.from(lockId)], programId)[0];
2332
2395
  }
2333
2396
  function deriveEscrowPda(programId, lockId) {
2334
- return import_web3.PublicKey.findProgramAddressSync([Buffer.from(import_sdk5.ESCROW_PDA_SEEDS.ESCROW), Buffer.from(lockId)], programId)[0];
2397
+ return import_web3.PublicKey.findProgramAddressSync([Buffer.from(import_sdk9.ESCROW_PDA_SEEDS.ESCROW), Buffer.from(lockId)], programId)[0];
2335
2398
  }
2336
2399
  function deriveConfigPda(programId) {
2337
- return import_web3.PublicKey.findProgramAddressSync([Buffer.from(import_sdk5.ESCROW_PDA_SEEDS.CONFIG)], programId)[0];
2400
+ return import_web3.PublicKey.findProgramAddressSync([Buffer.from(import_sdk9.ESCROW_PDA_SEEDS.CONFIG)], programId)[0];
2338
2401
  }
2339
2402
  function deriveStakeVaultPda(programId) {
2340
- return import_web3.PublicKey.findProgramAddressSync([Buffer.from(import_sdk5.ESCROW_PDA_SEEDS.STAKE_VAULT)], programId)[0];
2403
+ return import_web3.PublicKey.findProgramAddressSync([Buffer.from(import_sdk9.ESCROW_PDA_SEEDS.STAKE_VAULT)], programId)[0];
2341
2404
  }
2342
2405
  function deriveCollateralConfigPda(programId, mint) {
2343
- return import_web3.PublicKey.findProgramAddressSync([Buffer.from(import_sdk5.ESCROW_PDA_SEEDS.COLLATERAL), mint.toBuffer()], programId)[0];
2406
+ return import_web3.PublicKey.findProgramAddressSync([Buffer.from(import_sdk9.ESCROW_PDA_SEEDS.COLLATERAL), mint.toBuffer()], programId)[0];
2344
2407
  }
2345
2408
  function deriveDisputeResolutionPda(programId, lockId) {
2346
- return import_web3.PublicKey.findProgramAddressSync([Buffer.from(import_sdk5.ESCROW_PDA_SEEDS.DISPUTE_RESOLUTION), Buffer.from(lockId)], programId)[0];
2409
+ return import_web3.PublicKey.findProgramAddressSync([Buffer.from(import_sdk9.ESCROW_PDA_SEEDS.DISPUTE_RESOLUTION), Buffer.from(lockId)], programId)[0];
2347
2410
  }
2348
2411
  function deriveOperatorAuthPda(programId, operator) {
2349
- return import_web3.PublicKey.findProgramAddressSync([Buffer.from(import_sdk5.ESCROW_PDA_SEEDS.OPERATOR_AUTH), operator.toBuffer()], programId)[0];
2412
+ return import_web3.PublicKey.findProgramAddressSync([Buffer.from(import_sdk9.ESCROW_PDA_SEEDS.OPERATOR_AUTH), operator.toBuffer()], programId)[0];
2350
2413
  }
2351
2414
  function deriveEventAuthorityPda(programId) {
2352
- return import_web3.PublicKey.findProgramAddressSync([Buffer.from(import_sdk5.ESCROW_PDA_SEEDS.EVENT_AUTHORITY)], programId)[0];
2415
+ return import_web3.PublicKey.findProgramAddressSync([Buffer.from(import_sdk9.ESCROW_PDA_SEEDS.EVENT_AUTHORITY)], programId)[0];
2353
2416
  }
2354
2417
  function deriveAta(owner, mint) {
2355
2418
  return import_web3.PublicKey.findProgramAddressSync([owner.toBuffer(), SPL_TOKEN_PROGRAM_ID.toBuffer(), mint.toBuffer()], ASSOCIATED_TOKEN_PROGRAM_ID)[0];
@@ -2364,12 +2427,12 @@ function meta(pubkey, opts = {}) {
2364
2427
  return { pubkey, isSigner: opts.signer === true, isWritable: opts.writable === true };
2365
2428
  }
2366
2429
  function noArgIx(programId, name, keys) {
2367
- return new import_web3.TransactionInstruction({ programId, keys, data: Buffer.from((0, import_sdk5.buildLifecycleIxData)(name)) });
2430
+ return new import_web3.TransactionInstruction({ programId, keys, data: Buffer.from((0, import_sdk9.buildLifecycleIxData)(name)) });
2368
2431
  }
2369
2432
  function buildCreateLockIx(input) {
2370
2433
  const { programId, lockId } = input;
2371
2434
  const native = input.mint === null;
2372
- const data = Buffer.from((0, import_sdk5.buildCreateLockIxData)({ lockId, amount: input.amount, conditionHash: input.conditionHash }, { native }));
2435
+ const data = Buffer.from((0, import_sdk9.buildCreateLockIxData)({ lockId, amount: input.amount, conditionHash: input.conditionHash }, { native }));
2373
2436
  const head = [
2374
2437
  meta(input.payer, { signer: true, writable: true }),
2375
2438
  meta(input.payee),
@@ -2505,7 +2568,7 @@ function buildOpenDisputeIx(input) {
2505
2568
  function buildResolveDisputeIx(input) {
2506
2569
  const { programId, lockId } = input;
2507
2570
  const native = input.mint === null;
2508
- const data = Buffer.from((0, import_sdk5.buildResolveDisputeIxData)(input.args, { native }));
2571
+ const data = Buffer.from((0, import_sdk9.buildResolveDisputeIxData)(input.args, { native }));
2509
2572
  if (native) {
2510
2573
  return new import_web3.TransactionInstruction({
2511
2574
  programId,
@@ -2582,16 +2645,17 @@ function buildCloseDisputeIx(input) {
2582
2645
  ]);
2583
2646
  }
2584
2647
  async function fetchLockAccount(conn, programId, delegationId) {
2585
- const lockId = (0, import_sdk5.deriveLockId)(delegationId);
2648
+ const lockId = (0, import_sdk9.deriveLockId)(delegationId);
2586
2649
  const lockPda = deriveLockPda(programId, lockId);
2587
2650
  const info = await conn.getAccountInfo(lockPda);
2588
2651
  if (!info) return null;
2589
- return { lockId, lockPda, lock: (0, import_sdk5.decodeLockAccount)(Uint8Array.from(info.data)) };
2652
+ return { lockId, lockPda, lock: (0, import_sdk9.decodeLockAccount)(Uint8Array.from(info.data)) };
2590
2653
  }
2591
2654
 
2592
2655
  // src/commands/token-amount.ts
2656
+ var import_sdk10 = require("@heyanon-arp/sdk");
2593
2657
  function toBaseUnits(amountDecimal, decimals) {
2594
- if (!/^[0-9]+(\.[0-9]+)?$/.test(amountDecimal)) {
2658
+ if (!(0, import_sdk10.isDecimalAmountString)(amountDecimal)) {
2595
2659
  throw new Error(`amount '${amountDecimal}' is not a non-negative decimal number`);
2596
2660
  }
2597
2661
  if (!Number.isInteger(decimals) || decimals < 0 || decimals > 255) {
@@ -2620,8 +2684,8 @@ function normaliseDelegationId(raw) {
2620
2684
  }
2621
2685
  throw new Error(`wallet: --delegation-id must be either 'del_<uuid>' or a bare canonical-lowercase UUID (got '${raw}')`);
2622
2686
  }
2623
- var SPL_TOKEN_PROGRAM_ID2 = new import_web32.PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");
2624
- var ASSOCIATED_TOKEN_PROGRAM_ID2 = new import_web32.PublicKey("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL");
2687
+ var SPL_TOKEN_PROGRAM_ID2 = new import_web32.PublicKey(import_sdk11.SPL_TOKEN_PROGRAM_ID_BASE58);
2688
+ var ASSOCIATED_TOKEN_PROGRAM_ID2 = new import_web32.PublicKey(import_sdk11.ASSOCIATED_TOKEN_PROGRAM_ID_BASE58);
2625
2689
  var FALLBACK_RPC_URL = "https://api.mainnet-beta.solana.com";
2626
2690
  function resolveRpcUrl(opts) {
2627
2691
  if (opts.rpcUrl !== void 0 && opts.rpcUrl !== "") return opts.rpcUrl;
@@ -2641,7 +2705,7 @@ function redactRpcUrl(url) {
2641
2705
  return "<redacted>";
2642
2706
  }
2643
2707
  }
2644
- var FALLBACK_PROGRAM_ID = "7trAdKybX4kMKARia9nrRPj9rBuUjDTxRzExzwFTvvXg";
2708
+ var FALLBACK_PROGRAM_ID = import_sdk11.ESCROW_PROGRAM_ID_BASE58;
2645
2709
  async function resolveProgramIdWithSource(api, opts) {
2646
2710
  if (opts.programId !== void 0 && opts.programId !== "") {
2647
2711
  return { programId: opts.programId, source: "flag" };
@@ -2725,7 +2789,7 @@ async function derivePdasHandler(opts) {
2725
2789
  const normalisedDelegationId = normaliseDelegationId(opts.delegationId);
2726
2790
  const api = new ArpApiClient(opts.server);
2727
2791
  const programId = new import_web32.PublicKey(await resolveProgramIdStrict(api, opts, "wallet derive-pdas"));
2728
- const lockIdBytes = (0, import_sdk6.deriveLockId)(normalisedDelegationId);
2792
+ const lockIdBytes = (0, import_sdk11.deriveLockId)(normalisedDelegationId);
2729
2793
  const lockIdSeed = Buffer.from(lockIdBytes);
2730
2794
  const lockIdHex = Buffer.from(lockIdBytes).toString("hex");
2731
2795
  const [lockPda] = import_web32.PublicKey.findProgramAddressSync([Buffer.from("lock"), lockIdSeed], programId);
@@ -2744,11 +2808,11 @@ async function derivePdasHandler(opts) {
2744
2808
  };
2745
2809
  }
2746
2810
  var TERMINAL_METHOD = {
2747
- paid: "claim_work_payment",
2748
- canceled: "cancel_lock",
2749
- revoked: "claim_expired_work",
2750
- dispute_resolved: "resolve_dispute",
2751
- dispute_closed: "close_dispute"
2811
+ [import_sdk11.LockStates.PAID]: "claim_work_payment",
2812
+ [import_sdk11.LockStates.CANCELED]: "cancel_lock",
2813
+ [import_sdk11.LockStates.REVOKED]: "claim_expired_work",
2814
+ [import_sdk11.LockStates.DISPUTE_RESOLVED]: "resolve_dispute",
2815
+ [import_sdk11.LockStates.DISPUTE_CLOSED]: "close_dispute"
2752
2816
  };
2753
2817
  function registerVerifyRelease(cmd) {
2754
2818
  cmd.command("verify-release").description(
@@ -2794,7 +2858,7 @@ async function verifyReleaseHandler(opts) {
2794
2858
  const rpcUrl = resolveRpcUrlStrict(opts);
2795
2859
  const conn = new import_web32.Connection(rpcUrl, "confirmed");
2796
2860
  const fetched = await fetchLockAccount(conn, programId, normalisedDelegationId);
2797
- const lockId = (0, import_sdk6.deriveLockId)(normalisedDelegationId);
2861
+ const lockId = (0, import_sdk11.deriveLockId)(normalisedDelegationId);
2798
2862
  const lockPda = deriveLockPda(programId, lockId);
2799
2863
  const escrowPda = deriveEscrowPda(programId, lockId);
2800
2864
  if (!fetched) {
@@ -2815,7 +2879,7 @@ async function verifyReleaseHandler(opts) {
2815
2879
  lock_pda: lockPda.toBase58(),
2816
2880
  escrow_pda: escrowPda.toBase58(),
2817
2881
  lock_account_exists: true,
2818
- released: status === "paid",
2882
+ released: status === import_sdk11.LockStates.PAID,
2819
2883
  status,
2820
2884
  ...TERMINAL_METHOD[status] !== void 0 ? { release_method: TERMINAL_METHOD[status] } : {},
2821
2885
  lock_state: lock.stateByte,
@@ -2825,23 +2889,23 @@ async function verifyReleaseHandler(opts) {
2825
2889
  }
2826
2890
  function renderStatusLine(status) {
2827
2891
  switch (status) {
2828
- case "paid":
2892
+ case import_sdk11.LockStates.PAID:
2829
2893
  return "\u2713 paid \u2014 claim_work_payment landed (buyer approval or post-review self-claim); the payee was paid net of any protocol fee";
2830
- case "created":
2894
+ case import_sdk11.LockStates.CREATED:
2831
2895
  return "\u2717 created \u2014 funded, awaiting the worker accept_lock (stake) \u2014 or a buyer cancel";
2832
- case "in_progress":
2896
+ case import_sdk11.LockStates.IN_PROGRESS:
2833
2897
  return "\u2717 in_progress \u2014 worker accepted + staked; work window running";
2834
- case "submitted":
2898
+ case import_sdk11.LockStates.SUBMITTED:
2835
2899
  return "\u2717 submitted \u2014 work delivered on-chain; review window running (buyer claims to approve, disputes to refuse; worker self-claims after expiry)";
2836
- case "disputing":
2900
+ case import_sdk11.LockStates.DISPUTING:
2837
2901
  return "\u2717 disputing \u2014 buyer disputed; operator has the dispute window to rule, after that either party can close";
2838
- case "canceled":
2902
+ case import_sdk11.LockStates.CANCELED:
2839
2903
  return "\u2717 canceled \u2014 buyer canceled pre-accept; escrow returned";
2840
- case "revoked":
2904
+ case import_sdk11.LockStates.REVOKED:
2841
2905
  return "\u2717 revoked \u2014 work window lapsed unsubmitted; buyer reclaimed the escrow + the worker stake";
2842
- case "dispute_resolved":
2906
+ case import_sdk11.LockStates.DISPUTE_RESOLVED:
2843
2907
  return "\u2717 dispute_resolved \u2014 operator ruled; winner took the escrow per the on-chain split";
2844
- case "dispute_closed":
2908
+ case import_sdk11.LockStates.DISPUTE_CLOSED:
2845
2909
  return "\u2717 dispute_closed \u2014 dispute window lapsed unresolved; escrow returned to the buyer, stakes returned";
2846
2910
  case "lock_never_created":
2847
2911
  return "\u2717 lock_never_created \u2014 no Lock PDA on this cluster/program; create_lock never fired (or wrong --rpc-url/--program-id)";
@@ -3027,7 +3091,7 @@ async function createLockHandler(opts) {
3027
3091
  if (clusterTag !== 0 && clusterTag !== 1) {
3028
3092
  throw new Error(`--cluster-tag must be 0 (devnet) or 1 (mainnet) (got ${clusterTag})`);
3029
3093
  }
3030
- const clusterCaip2 = clusterTag === 1 ? import_sdk6.SOLANA_CLUSTER_IDS["solana-mainnet"] : import_sdk6.SOLANA_CLUSTER_IDS["solana-devnet"];
3094
+ const clusterCaip2 = clusterTag === 1 ? import_sdk11.SOLANA_CLUSTER_IDS["solana-mainnet"] : import_sdk11.SOLANA_CLUSTER_IDS["solana-devnet"];
3031
3095
  const expectedLockAsset = typeof opts.mintPubkey === "string" && opts.mintPubkey !== "" ? { kind: "spl", mint: parsePubkey(opts.mintPubkey, "--mint-pubkey").toBase58(), cluster: clusterCaip2 } : { kind: "native" };
3032
3096
  if (!offlineMode) {
3033
3097
  await preflightLockCurrency(api, agent, normalisedDelegationId, expectedLockAsset);
@@ -3037,7 +3101,7 @@ async function createLockHandler(opts) {
3037
3101
  const conn = new import_web32.Connection(rpcUrl, "confirmed");
3038
3102
  const asset = await resolveCreateLockAsset(conn, opts, payerKp.publicKey, clusterCaip2);
3039
3103
  const amount = asset.amount;
3040
- const lockIdBytes = (0, import_sdk6.deriveLockId)(normalisedDelegationId);
3104
+ const lockIdBytes = (0, import_sdk11.deriveLockId)(normalisedDelegationId);
3041
3105
  const ix = buildCreateLockIx({
3042
3106
  programId,
3043
3107
  lockId: lockIdBytes,
@@ -3121,63 +3185,12 @@ function registerDelegationCommands(root) {
3121
3185
  registerDecline(cmd);
3122
3186
  registerCancel(cmd);
3123
3187
  }
3124
- var POST_COMMIT_ERROR_CODES = /* @__PURE__ */ new Set([
3125
- "DELEGATION_ALREADY_EXISTS",
3126
- "DELEGATION_INVALID_STATE",
3127
- "DELEGATION_NOT_FOUND",
3128
- "DELEGATION_RELATIONSHIP_MISMATCH",
3129
- "DELEGATION_ACCEPTER_IS_OFFERER",
3130
- "DELEGATION_DECLINER_IS_OFFERER",
3131
- "DELEGATION_CANCELER_NOT_OFFERER",
3132
- // PricingPolicy: the offer's terms fell outside the RECIPIENT's
3133
- // published accept-prefs. Fires in `handleOffer` AFTER the event
3134
- // row commit (pre-materialization on the server), so the sequence
3135
- // was consumed — advance it or the corrected re-offer trips
3136
- // ENV_SEQUENCE_BACKWARDS.
3137
- // Asset whitelist gate: the offer currency is not a whitelisted
3138
- // payment asset on this server (or its decimals diverge from the
3139
- // canonical entry). Same lifecycle as the pricing gate — sequence
3140
- // consumed. Fix the --currency and re-offer.
3141
- "DELEGATION_ASSET_NOT_ALLOWED",
3142
- "DELEGATION_PRICING_MISMATCH",
3143
- // Capacity gate: the recipient is at its published
3144
- // maxActiveDelegations cap (or closed with 0). Same lifecycle as
3145
- // the pricing gate — sequence consumed. TRANSIENT: retry later.
3146
- "DELEGATION_CAPACITY_EXCEEDED",
3147
- // `DELEGATION_PENDING_LOCK` fires from the body handler's
3148
- // `requireDelegationInState` AFTER the event row is persisted
3149
- // (same code path as DELEGATION_INVALID_STATE), so an accept
3150
- // against a PENDING_LOCK delegation consumes sender_sequence
3151
- // even though it rejects.
3152
- "DELEGATION_PENDING_LOCK",
3153
- // The `fund` body handler (`handleFund`) emits
3154
- // these AFTER the event row is committed (same lifecycle as
3155
- // DELEGATION_INVALID_STATE). `DELEGATION_FUNDER_NOT_OFFERER` (403)
3156
- // when a non-offerer attempts the fund; `DELEGATION_ALREADY_FUNDED`
3157
- // (409) on a re-fund of a delegation that already moved into the
3158
- // lock lifecycle (pending_lock_finalization / locked, or an
3159
- // in-flight create_lock op). Both consume sender_sequence, so the
3160
- // CLI must advance `lastSenderSequence` or a retry trips
3161
- // `ENV_SEQUENCE_BACKWARDS`.
3162
- "DELEGATION_FUNDER_NOT_OFFERER",
3163
- "DELEGATION_ALREADY_FUNDED",
3164
- // Lock-validator mint.owner pre-flight — kept here for
3165
- // documentation, but the `isPostCommitErrorCode` helper below
3166
- // also matches any `ESC_LOCK_*` prefix. The full lock-validator
3167
- // cross-check set (ID_MISMATCH, CONDITION_HASH_MISMATCH,
3168
- // AMOUNT_DELEGATION_MISMATCH, EXPIRY_TOO_*, PDA_*, etc.) ALSO
3169
- // fires after the delegation event is committed; missing
3170
- // entries here would leave `lastSenderSequence` stale and stall
3171
- // retries on ENV_SEQUENCE_BACKWARDS.
3172
- "ESC_LOCK_MINT_RPC_FAILED",
3173
- "ESC_LOCK_MINT_NOT_FOUND",
3174
- "ESC_LOCK_MINT_OWNER_MISMATCH"
3175
- ]);
3176
- function isPostCommitErrorCode(code) {
3177
- return POST_COMMIT_ERROR_CODES.has(code) || code.startsWith("ESC_LOCK_") || code.startsWith("SDK_");
3178
- }
3179
3188
  function registerOffer(parent) {
3180
- parent.command("offer").description("Open a new delegation addressed to <recipient-did> with the agreed terms INLINE (no escrow lock \u2014 fund AFTER acceptance via `delegation fund`).").argument("<recipient-did>", "Recipient agent DID (did:arp:...)").option("--server <url>", "Override ARP server base URL").option("--from-did <did>", "Sender DID \u2014 required only if multiple agents are registered against this server").option("--delegation-id <uuid>", "Override the auto-generated delegation id (UUID). Reuse the SAME id at `heyarp delegation fund` time. Useful for replay / scripting.").option("--title <s>", "Required: human-readable title for the offer").option("--brief <json>", "Optional structured brief (JSON object)").option("--criterion <s>", "acceptance_criteria \u2014 repeatable; pass --criterion once per bullet", collectRepeated, []).option("--deadline <rfc3339>", 'Optional RFC 3339 deadline (e.g. "2026-12-31T23:59:59Z")').option("--scope <text>", "scope_summary \u2014 short prose describing the agreed work. Required.").option("--amount <s>", 'Optional decimal-as-string amount (e.g. "10.00"). REQUIRES --currency if set.').option("--currency <s>", `Asset identifier: shorthand (${import_sdk7.WELL_KNOWN_ASSET_KEYS.join("|")}) OR raw CAIP-19 string.`).option("--currency-decimals <n>", "Decimal places for base-unit conversion (0-18). Required only when --currency is raw CAIP-19.").option("--currency-symbol <s>", 'Optional UI hint ("USDC", "SOL"). Max 16 chars.').option("--ttl <seconds>", "Envelope TTL in seconds (max 86400 = 24h)", "3600").option("--verbose", "Print the full envelope before sending and the full server response", false).option(
3189
+ parent.command("offer").description("Open a new delegation addressed to <recipient-did> with the agreed terms INLINE (no escrow lock \u2014 fund AFTER acceptance via `delegation fund`).").argument("<recipient>", "Recipient \u2014 agent name (handle) or DID (did:arp:...)").option("--server <url>", "Override ARP server base URL").option("--from-did <did>", "Sender DID \u2014 required only if multiple agents are registered against this server").option("--delegation-id <uuid>", "Override the auto-generated delegation id (UUID). Reuse the SAME id at `heyarp delegation fund` time. Useful for replay / scripting.").option("--title <s>", "Required: human-readable title for the offer").option("--brief <json>", "Optional structured brief (JSON object)").option("--criterion <s>", "acceptance_criteria \u2014 repeatable; pass --criterion once per bullet", collectRepeated, []).option("--deadline <rfc3339>", 'Optional RFC 3339 deadline (e.g. "2026-12-31T23:59:59Z")').option("--scope <text>", "scope_summary \u2014 short prose describing the agreed work. Required.").option("--amount <s>", 'Optional decimal-as-string amount (e.g. "10.00"). REQUIRES --currency if set.').option("--currency <s>", `Asset identifier: shorthand (${import_sdk12.WELL_KNOWN_ASSET_KEYS.join("|")}) OR raw CAIP-19 string.`).option("--currency-decimals <n>", "Decimal places for base-unit conversion (0-18). Required only when --currency is raw CAIP-19.").option("--currency-symbol <s>", 'Optional UI hint ("USDC", "SOL"). Max 16 chars.').option("--ttl <seconds>", `Envelope TTL in seconds (max ${import_sdk12.MAX_ENVELOPE_TTL_SECONDS} = 24h)`, "3600").option("--verbose", "Print the full envelope before sending and the full server response. Mutually exclusive with --json.", false).option(
3190
+ "--json",
3191
+ 'Machine-readable mode \u2014 emit a single JSON object on stdout ({ok, action:"offer", delegationId, eventId, relationshipId, relationshipEventIndex, serverTimestamp, serverEventHash}). Prelude + the "reference this delegation" hints move to stderr; on failure stderr carries `{code, message}`. Mutually exclusive with --verbose.',
3192
+ false
3193
+ ).option(
3181
3194
  "--wait-until <phase>",
3182
3195
  'Block after delivery until the named FSM phase is reached (e.g. delegation.accepted). One of the UNTIL_PHASES from `heyarp status --help`. Exit code 124 on --wait-timeout. Recovers the "sub-agent exits before counterparty accepts" antipattern.'
3183
3196
  ).option("--wait-timeout <seconds>", "When --wait-until is set: max wall-clock wait (default 300). Exit code 124 on timeout.").option("--wait-interval <seconds>", "When --wait-until is set: poll cadence (default 3, bound [1, 60]).").option(
@@ -3283,16 +3296,21 @@ function assembleEscrowLockAttachment(opts) {
3283
3296
  };
3284
3297
  }
3285
3298
  async function runOffer(recipientDid, opts) {
3286
- requireDid("delegation offer", recipientDid, "<recipient-did>");
3299
+ if (opts.verbose && opts.json) {
3300
+ throw new Error(
3301
+ "delegation offer: --verbose and --json are mutually exclusive. --json emits the structured server response; --verbose adds dumps that would break `--json | jq`."
3302
+ );
3303
+ }
3304
+ recipientDid = await resolveRecipient(opts.server, "delegation offer", recipientDid, { json: opts.json });
3287
3305
  const ttlSeconds = parseTtl("delegation offer", opts.ttl);
3288
3306
  if (!opts.title || opts.title.length === 0) {
3289
3307
  throw new Error("delegation offer: --title is required (server-side validator rejects empty offers)");
3290
3308
  }
3291
3309
  const terms = parseOfferTerms("delegation offer", opts);
3292
3310
  const offeredAssetId = terms.currency?.asset_id;
3293
- if (offeredAssetId && !(0, import_sdk7.isWhitelistedAssetId)(offeredAssetId)) {
3311
+ if (offeredAssetId && !(0, import_sdk12.isWhitelistedAssetId)(offeredAssetId)) {
3294
3312
  console.error(
3295
- import_chalk8.default.yellow(
3313
+ import_chalk9.default.yellow(
3296
3314
  `warning: currency '${offeredAssetId}' is not in the static payment whitelist \u2014 the server will reject the offer (DELEGATION_ASSET_NOT_ALLOWED) unless its deploy registers this asset. See 'heyarp assets'.`
3297
3315
  )
3298
3316
  );
@@ -3311,43 +3329,43 @@ async function runOffer(recipientDid, opts) {
3311
3329
  const api = new ArpApiClient(opts.server);
3312
3330
  const sender = resolveSenderAgent("delegation offer", opts.server, opts.fromDid);
3313
3331
  const content = {
3314
- action: "offer",
3332
+ action: import_sdk12.DelegationActions.OFFER,
3315
3333
  delegation_id: delegationId,
3316
3334
  title: opts.title,
3317
3335
  ...terms
3318
3336
  };
3319
3337
  const body = { type: "delegation", content };
3320
- console.log(import_chalk8.default.dim(`Server: ${api.serverUrl}`));
3321
- console.log(import_chalk8.default.dim(`Sender: ${sender.did}`));
3322
- console.log(import_chalk8.default.dim(`Recipient: ${recipientDid}`));
3323
- console.log(import_chalk8.default.dim(`Delegation: ${delegationId}`));
3338
+ progress(opts.json, import_chalk9.default.dim(`Server: ${api.serverUrl}`));
3339
+ progress(opts.json, import_chalk9.default.dim(`Sender: ${sender.did}`));
3340
+ progress(opts.json, import_chalk9.default.dim(`Recipient: ${recipientDid}`));
3341
+ progress(opts.json, import_chalk9.default.dim(`Delegation: ${delegationId}`));
3324
3342
  let result;
3325
3343
  try {
3326
3344
  result = await sendDelegationEnvelope({ api, sender, recipientDid, body, ttlSeconds, verbose: opts.verbose, server: opts.server });
3327
3345
  } catch (err) {
3328
- if (err instanceof ApiError && err.payload.code === "DELEGATION_ASSET_NOT_ALLOWED") {
3346
+ if (err instanceof ApiError && err.payload.code === import_sdk12.DelegationOfferRejectionCodes.ASSET_NOT_ALLOWED) {
3329
3347
  const d = err.payload.details;
3330
- console.error(import_chalk8.default.yellow(`
3348
+ console.error(import_chalk9.default.yellow(`
3331
3349
  The server's payment-asset whitelist rejected this currency.`));
3332
3350
  if (d !== void 0) {
3333
- console.error(import_chalk8.default.dim(` offered: ${JSON.stringify(d.offered)}`));
3334
- console.error(import_chalk8.default.dim(` accepted: ${JSON.stringify(d.accepted)}`));
3351
+ console.error(import_chalk9.default.dim(` offered: ${JSON.stringify(d.offered)}`));
3352
+ console.error(import_chalk9.default.dim(` accepted: ${JSON.stringify(d.accepted)}`));
3335
3353
  }
3336
- console.error(import_chalk8.default.dim(`
3354
+ console.error(import_chalk9.default.dim(`
3337
3355
  See the whitelist (shorthand keys + canonical decimals):
3338
3356
  heyarp assets
3339
3357
  then re-offer with a whitelisted --currency.`));
3340
3358
  }
3341
- if (err instanceof ApiError && err.payload.code === "DELEGATION_PRICING_MISMATCH") {
3359
+ if (err instanceof ApiError && err.payload.code === import_sdk12.DelegationOfferRejectionCodes.PRICING_MISMATCH) {
3342
3360
  const d = err.payload.details;
3343
- console.error(import_chalk8.default.yellow(`
3361
+ console.error(import_chalk9.default.yellow(`
3344
3362
  The recipient's published accept-prefs rejected this offer${d?.reason ? ` (mismatch: ${d.reason})` : ""}.`));
3345
3363
  if (d !== void 0) {
3346
- console.error(import_chalk8.default.dim(` accepted: ${JSON.stringify(d.accepted)}`));
3347
- console.error(import_chalk8.default.dim(` offered: ${JSON.stringify(d.offered)}`));
3364
+ console.error(import_chalk9.default.dim(` accepted: ${JSON.stringify(d.accepted)}`));
3365
+ console.error(import_chalk9.default.dim(` offered: ${JSON.stringify(d.offered)}`));
3348
3366
  }
3349
3367
  console.error(
3350
- import_chalk8.default.dim(
3368
+ import_chalk9.default.dim(
3351
3369
  `
3352
3370
  Check what the recipient accepts BEFORE offering:
3353
3371
  heyarp agents accept-prefs show ${recipientDid}
@@ -3355,26 +3373,40 @@ then re-run with matching --currency / --amount.`
3355
3373
  )
3356
3374
  );
3357
3375
  }
3358
- if (err instanceof ApiError && err.payload.code === "DELEGATION_CAPACITY_EXCEEDED") {
3376
+ if (err instanceof ApiError && err.payload.code === import_sdk12.DelegationOfferRejectionCodes.CAPACITY_EXCEEDED) {
3359
3377
  const d = err.payload.details;
3360
3378
  const cap = d?.maxActive === 0 ? "closed for new offers (busy)" : `at capacity (${d?.currentActive}/${d?.maxActive} active delegations)`;
3361
- console.error(import_chalk8.default.yellow(`
3379
+ console.error(import_chalk9.default.yellow(`
3362
3380
  The recipient is ${cap}.`));
3363
- console.error(import_chalk8.default.dim("\nThis is TRANSIENT \u2014 your terms are fine. Retry the same offer later, or pick another worker (`heyarp agents --tag \u2026`)."));
3381
+ console.error(import_chalk9.default.dim("\nThis is TRANSIENT \u2014 your terms are fine. Retry the same offer later, or pick another worker (`heyarp agents --tag \u2026`)."));
3364
3382
  }
3365
3383
  throw err;
3366
3384
  }
3367
- printIngestResult(result);
3368
- console.log(import_chalk8.default.dim(`
3385
+ if (opts.json) {
3386
+ jsonOut({
3387
+ ok: true,
3388
+ action: "offer",
3389
+ delegationId,
3390
+ eventId: result.eventId,
3391
+ relationshipId: result.relationshipId,
3392
+ relationshipEventIndex: result.relationshipEventIndex,
3393
+ serverTimestamp: result.serverTimestamp,
3394
+ serverEventHash: result.serverEventHash,
3395
+ prevServerEventHash: result.prevServerEventHash ?? null
3396
+ });
3397
+ } else {
3398
+ printIngestResult(result);
3399
+ console.log(import_chalk9.default.dim(`
3369
3400
  Reference this delegation on subsequent calls with:`));
3370
- console.log(import_chalk8.default.dim(` heyarp delegation accept ${result.relationshipId} ${delegationId}`));
3371
- console.log(import_chalk8.default.dim(` heyarp delegation decline ${result.relationshipId} ${delegationId}`));
3372
- console.log(import_chalk8.default.dim(` heyarp delegation cancel ${result.relationshipId} ${delegationId}`));
3373
- console.log(import_chalk8.default.dim(`
3401
+ console.log(import_chalk9.default.dim(` heyarp delegation accept ${result.relationshipId} ${delegationId}`));
3402
+ console.log(import_chalk9.default.dim(` heyarp delegation decline ${result.relationshipId} ${delegationId}`));
3403
+ console.log(import_chalk9.default.dim(` heyarp delegation cancel ${result.relationshipId} ${delegationId}`));
3404
+ console.log(import_chalk9.default.dim(`
3374
3405
  After the worker accepts, fund the escrow lock:`));
3375
- console.log(import_chalk8.default.dim(` heyarp wallet create-lock --delegation-id ${delegationId} --condition-hash <hex> ... > lock.json`));
3376
- console.log(import_chalk8.default.dim(` heyarp delegation fund ${delegationId} --escrow-lock-from-file lock.json`));
3377
- if (opts.waitUntil) {
3406
+ console.log(import_chalk9.default.dim(` heyarp wallet create-lock --delegation-id ${delegationId} --condition-hash <hex> ... > lock.json`));
3407
+ console.log(import_chalk9.default.dim(` heyarp delegation fund ${delegationId} --escrow-lock-from-file lock.json`));
3408
+ }
3409
+ if (opts.waitUntil && !opts.json) {
3378
3410
  const untilPhase = parseUntilPhase(opts.waitUntil);
3379
3411
  if (untilPhase === void 0) {
3380
3412
  throw new Error(`delegation offer: --wait-until requires a phase value (got ${JSON.stringify(opts.waitUntil)})`);
@@ -3394,7 +3426,7 @@ After the worker accepts, fund the escrow lock:`));
3394
3426
  }
3395
3427
  }
3396
3428
  function registerFund(parent) {
3397
- parent.command("fund").description("Fund an ACCEPTED delegation with the escrow lock (buyer-only). Run AFTER the worker accepts the offer.").argument("<delegation-id>", "Delegation UUID (the one you offered + the worker accepted)").option("--server <url>", "Override ARP server base URL").option("--from-did <did>", "Sender DID \u2014 required only if multiple agents are registered against this server").option("--ttl <seconds>", "Envelope TTL in seconds (max 86400 = 24h)", "3600").option("--verbose", "Print the full envelope before sending and the full server response. Mutually exclusive with --json.", false).option(
3429
+ parent.command("fund").description("Fund an ACCEPTED delegation with the escrow lock (buyer-only). Run AFTER the worker accepts the offer.").argument("<delegation-id>", "Delegation UUID (the one you offered + the worker accepted)").option("--server <url>", "Override ARP server base URL").option("--from-did <did>", "Sender DID \u2014 required only if multiple agents are registered against this server").option("--ttl <seconds>", `Envelope TTL in seconds (max ${import_sdk12.MAX_ENVELOPE_TTL_SECONDS} = 24h)`, "3600").option("--verbose", "Print the full envelope before sending and the full server response. Mutually exclusive with --json.", false).option(
3398
3430
  "--json",
3399
3431
  'Machine-readable mode \u2014 emit a single JSON object on stdout ({ok, action:"fund", delegationId, eventId, relationshipId, relationshipEventIndex, serverTimestamp, serverEventHash}). Prelude moves off stdout; on failure stderr carries `{code, message}`. Mutually exclusive with --verbose.',
3400
3432
  false
@@ -3452,23 +3484,23 @@ async function runFund(delegationId, opts) {
3452
3484
  }
3453
3485
  if (result2.kind === "skipped_no_expected_program_id") {
3454
3486
  console.error(
3455
- import_chalk8.default.yellow(
3487
+ import_chalk9.default.yellow(
3456
3488
  "\u26A0 delegation fund: no authoritative expected program-id available (--program-id missing, ARP_ESCROW_PROGRAM_ID env unset, server protocol-fee unreachable). Pre-flight skipped; server-side ESC_LOCK_TX_PROGRAM_ID_MISMATCH check is the only backstop. Set ARP_ESCROW_PROGRAM_ID or pass --program-id to enable pre-flight."
3457
3489
  )
3458
3490
  );
3459
3491
  }
3460
3492
  }
3461
- const content = { action: "fund", delegation_id: delegationId };
3493
+ const content = { action: import_sdk12.DelegationActions.FUND, delegation_id: delegationId };
3462
3494
  const body = { type: "delegation", content };
3463
3495
  const attachments = { escrow_lock: escrowResult.attachment };
3464
- progress(opts.json, import_chalk8.default.dim(`Server: ${api.serverUrl}`));
3465
- progress(opts.json, import_chalk8.default.dim(`Sender: ${sender.did}`));
3466
- progress(opts.json, import_chalk8.default.dim(`Recipient: ${resolved.recipientDid}`));
3467
- progress(opts.json, import_chalk8.default.dim(`Relationship: ${resolved.relationshipId}`));
3468
- progress(opts.json, import_chalk8.default.dim(`Delegation: ${delegationId} (action=fund)`));
3496
+ progress(opts.json, import_chalk9.default.dim(`Server: ${api.serverUrl}`));
3497
+ progress(opts.json, import_chalk9.default.dim(`Sender: ${sender.did}`));
3498
+ progress(opts.json, import_chalk9.default.dim(`Recipient: ${resolved.recipientDid}`));
3499
+ progress(opts.json, import_chalk9.default.dim(`Relationship: ${resolved.relationshipId}`));
3500
+ progress(opts.json, import_chalk9.default.dim(`Delegation: ${delegationId} (action=fund)`));
3469
3501
  {
3470
3502
  const a = escrowResult.attachment;
3471
- progress(opts.json, import_chalk8.default.dim(`Escrow lock attached: lock_id=${a.lock_id} amount=${a.amount} asset_id=${a.asset_id}`));
3503
+ progress(opts.json, import_chalk9.default.dim(`Escrow lock attached: lock_id=${a.lock_id} amount=${a.amount} asset_id=${a.asset_id}`));
3472
3504
  }
3473
3505
  const result = await sendDelegationEnvelope({
3474
3506
  api,
@@ -3494,7 +3526,7 @@ async function runFund(delegationId, opts) {
3494
3526
  });
3495
3527
  } else {
3496
3528
  printIngestResult(result);
3497
- console.log(import_chalk8.default.dim("\nThe worker waits for the on-chain lock to confirm (LOCKED), then begins work."));
3529
+ console.log(import_chalk9.default.dim("\nThe worker waits for the on-chain lock to confirm (LOCKED), then begins work."));
3498
3530
  }
3499
3531
  if (opts.waitUntil && !opts.json) {
3500
3532
  const untilPhase = parseUntilPhase(opts.waitUntil);
@@ -3559,8 +3591,12 @@ function registerDecline(parent) {
3559
3591
  "--reason <code>",
3560
3592
  // surface the closed enum at help time so operators
3561
3593
  // don't have to read source to find acceptable values.
3562
- `Required: decline reason code (one of: ${import_sdk7.DECLINE_REASONS.join(", ")}). Carried in body.content.reason so the counterparty's reactor can branch on it.`
3563
- ).option("--reason-detail <s>", 'Optional free-text elaboration alongside --reason (e.g. "rate floor 0.20 USDC"). Max 512 chars.').option("--verbose", "Print the full envelope before sending and the full server response", false).option(
3594
+ `Required: decline reason code (one of: ${import_sdk12.DECLINE_REASONS.join(", ")}). Carried in body.content.reason so the counterparty's reactor can branch on it.`
3595
+ ).option("--reason-detail <s>", 'Optional free-text elaboration alongside --reason (e.g. "rate floor 0.20 USDC"). Max 512 chars.').option("--verbose", "Print the full envelope before sending and the full server response. Mutually exclusive with --json.", false).option(
3596
+ "--json",
3597
+ 'Machine-readable mode \u2014 emit a single JSON object on stdout ({ok, action:"decline", delegationId, eventId, relationshipId, relationshipEventIndex, serverTimestamp, serverEventHash}). Prelude + pending-lock poll chatter move off stdout; on failure stderr carries `{code, message}`. Mutually exclusive with --verbose.',
3598
+ false
3599
+ ).option(
3564
3600
  "--no-wait-for-lock",
3565
3601
  "Opt-out of the pending-lock pre-flight poll. Default is ON: when the resolved delegation is in `pending_lock_finalization`, the CLI polls until the on-chain lock is confirmed before signing the envelope (avoids the racy DELEGATION_PENDING_LOCK 409 that consumes sender_sequence)."
3566
3602
  ).option("--lock-wait-timeout <seconds>", "Max wall-clock seconds to wait for pending-lock pre-flight (default 300).", "300").option("--lock-wait-interval <seconds>", "Poll cadence for pending-lock pre-flight in seconds. Bound to [1, 60].", "3").action(async (relationshipId, delegationId, opts) => {
@@ -3568,7 +3604,11 @@ function registerDecline(parent) {
3568
3604
  });
3569
3605
  }
3570
3606
  function registerCancel(parent) {
3571
- parent.command("cancel").description("Cancel an OFFERED delegation \u2014 moves to CANCELED. Offerer-only (the OTHER side uses decline).").argument("<relationship-id>", "Relationship UUID").argument("<delegation-id>", "Delegation UUID").option("--server <url>", "Override ARP server base URL").option("--from-did <did>", "Sender DID \u2014 required only if multiple agents are registered against this server").option("--ttl <seconds>", "Envelope TTL in seconds", "3600").option("--verbose", "Print the full envelope before sending and the full server response", false).option(
3607
+ parent.command("cancel").description("Cancel an OFFERED delegation \u2014 moves to CANCELED. Offerer-only (the OTHER side uses decline).").argument("<relationship-id>", "Relationship UUID").argument("<delegation-id>", "Delegation UUID").option("--server <url>", "Override ARP server base URL").option("--from-did <did>", "Sender DID \u2014 required only if multiple agents are registered against this server").option("--ttl <seconds>", "Envelope TTL in seconds", "3600").option("--verbose", "Print the full envelope before sending and the full server response. Mutually exclusive with --json.", false).option(
3608
+ "--json",
3609
+ 'Machine-readable mode \u2014 emit a single JSON object on stdout ({ok, action:"cancel", delegationId, eventId, relationshipId, relationshipEventIndex, serverTimestamp, serverEventHash}). Prelude + pending-lock poll chatter move off stdout; on failure stderr carries `{code, message}`. Mutually exclusive with --verbose.',
3610
+ false
3611
+ ).option(
3572
3612
  "--no-wait-for-lock",
3573
3613
  "Opt-out of the pending-lock pre-flight poll. Default is ON: when the resolved delegation is in `pending_lock_finalization`, the CLI polls until the on-chain lock is confirmed before signing the envelope (avoids the racy DELEGATION_PENDING_LOCK 409 that consumes sender_sequence)."
3574
3614
  ).option("--lock-wait-timeout <seconds>", "Max wall-clock seconds to wait for pending-lock pre-flight (default 300).", "300").option("--lock-wait-interval <seconds>", "Poll cadence for pending-lock pre-flight in seconds. Bound to [1, 60].", "3").action(async (relationshipId, delegationId, opts) => {
@@ -3588,7 +3628,7 @@ async function runFollowupAction(relationshipId, delegationId, action, opts) {
3588
3628
  const lockWaitTimeoutSec = parseLockWaitTimeout(cmdName, opts.lockWaitTimeout);
3589
3629
  const lockWaitIntervalSec = parseLockWaitInterval(cmdName, opts.lockWaitInterval);
3590
3630
  let declinePayload = null;
3591
- if (action === "decline") {
3631
+ if (action === import_sdk12.DelegationActions.DECLINE) {
3592
3632
  const reason = parseDeclineReason(cmdName, opts.reason);
3593
3633
  const validatedDetail = parseReasonDetail(cmdName, opts.reasonDetail);
3594
3634
  declinePayload = validatedDetail ? { reason, reasonDetail: validatedDetail } : { reason };
@@ -3597,7 +3637,7 @@ async function runFollowupAction(relationshipId, delegationId, action, opts) {
3597
3637
  const sender = resolveSenderAgent(cmdName, opts.server, opts.fromDid);
3598
3638
  const signer = makeSigner(sender);
3599
3639
  const resolved = await resolveDelegationRefs(cmdName, api, signer, { relationshipId, delegationId, action, selfDid: sender.did });
3600
- if (resolved.state === "pending_lock_finalization" && opts.waitForLock !== false) {
3640
+ if (resolved.state === import_sdk12.DelegationStates.PENDING_LOCK_FINALIZATION && opts.waitForLock !== false) {
3601
3641
  await awaitDelegationLockFinalized(cmdName, api, signer, {
3602
3642
  relationshipId,
3603
3643
  delegationId,
@@ -3619,10 +3659,10 @@ async function runFollowupAction(relationshipId, delegationId, action, opts) {
3619
3659
  if (declinePayload.reasonDetail) content.reason_detail = declinePayload.reasonDetail;
3620
3660
  }
3621
3661
  const body = { type: "delegation", content };
3622
- progress(opts.json, import_chalk8.default.dim(`Server: ${api.serverUrl}`));
3623
- progress(opts.json, import_chalk8.default.dim(`Sender: ${sender.did}`));
3624
- progress(opts.json, import_chalk8.default.dim(`Relationship: ${relationshipId}`));
3625
- progress(opts.json, import_chalk8.default.dim(`Delegation: ${delegationId} (action=${action}${action === "decline" ? `, reason=${content.reason}` : ""})`));
3662
+ progress(opts.json, import_chalk9.default.dim(`Server: ${api.serverUrl}`));
3663
+ progress(opts.json, import_chalk9.default.dim(`Sender: ${sender.did}`));
3664
+ progress(opts.json, import_chalk9.default.dim(`Relationship: ${relationshipId}`));
3665
+ progress(opts.json, import_chalk9.default.dim(`Delegation: ${delegationId} (action=${action}${action === import_sdk12.DelegationActions.DECLINE ? `, reason=${content.reason}` : ""})`));
3626
3666
  const result = await sendDelegationEnvelope({
3627
3667
  api,
3628
3668
  sender,
@@ -3651,9 +3691,9 @@ async function runFollowupAction(relationshipId, delegationId, action, opts) {
3651
3691
  async function sendDelegationEnvelope(args) {
3652
3692
  const nextSequence = (args.sender.lastSenderSequence ?? 0) + 1;
3653
3693
  const protectedBlock = {
3654
- protocol_version: "arp/0.1",
3655
- purpose: import_sdk7.Purpose.ENVELOPE,
3656
- message_id: (0, import_sdk7.uuidV4)(),
3694
+ protocol_version: import_sdk12.CURRENT_PROTOCOL_VERSION,
3695
+ purpose: import_sdk12.Purpose.ENVELOPE,
3696
+ message_id: (0, import_sdk12.uuidV4)(),
3657
3697
  sender_did: args.sender.did,
3658
3698
  recipient_did: args.recipientDid,
3659
3699
  // `relationship_id: null` matches the handshake
@@ -3662,20 +3702,20 @@ async function sendDelegationEnvelope(args) {
3662
3702
  // existing relationship row.
3663
3703
  relationship_id: null,
3664
3704
  sender_sequence: nextSequence,
3665
- sender_nonce: (0, import_sdk7.senderNonce)(),
3666
- timestamp: (0, import_sdk7.rfc3339)(),
3667
- expires_at: (0, import_sdk7.expiresAt)(args.ttlSeconds),
3705
+ sender_nonce: (0, import_sdk12.senderNonce)(),
3706
+ timestamp: (0, import_sdk12.rfc3339)(),
3707
+ expires_at: (0, import_sdk12.expiresAt)(args.ttlSeconds),
3668
3708
  delivery_id: null
3669
3709
  };
3670
3710
  const signer = makeSigner(args.sender);
3671
- const envelope = (0, import_sdk7.signEnvelope)({
3711
+ const envelope = (0, import_sdk12.signEnvelope)({
3672
3712
  protected: protectedBlock,
3673
3713
  body: args.body,
3674
3714
  identitySecretKey: signer.identitySecretKey,
3675
3715
  attachments: args.attachments
3676
3716
  });
3677
3717
  if (args.verbose) {
3678
- console.log(import_chalk8.default.bold("\nEnvelope (pre-send):"));
3718
+ console.log(import_chalk9.default.bold("\nEnvelope (pre-send):"));
3679
3719
  console.log(formatJson(envelope));
3680
3720
  }
3681
3721
  try {
@@ -3683,7 +3723,7 @@ async function sendDelegationEnvelope(args) {
3683
3723
  updateAgentLocal(args.server, args.sender.did, { lastSenderSequence: nextSequence });
3684
3724
  return result;
3685
3725
  } catch (err) {
3686
- if (err instanceof ApiError && isPostCommitErrorCode(err.payload.code)) {
3726
+ if (err instanceof ApiError && (0, import_sdk12.isPostCommitErrorCode)(err.payload.code)) {
3687
3727
  updateAgentLocal(args.server, args.sender.did, { lastSenderSequence: nextSequence });
3688
3728
  }
3689
3729
  throw err;
@@ -3705,7 +3745,7 @@ async function resolveDelegationRefs(cmdName, api, signer, args) {
3705
3745
  );
3706
3746
  }
3707
3747
  let recipientDid;
3708
- if (args.action === "cancel") {
3748
+ if (args.action === import_sdk12.DelegationActions.CANCEL) {
3709
3749
  const firstEvents = await api.listEvents(args.relationshipId, signer, { since: 0, limit: 1 });
3710
3750
  const handshake = firstEvents[0];
3711
3751
  if (!handshake) {
@@ -3730,7 +3770,7 @@ async function resolveDelegationRefs(cmdName, api, signer, args) {
3730
3770
  async function awaitDelegationLockFinalized(cmdName, api, signer, args) {
3731
3771
  const log = args.log ?? ((line) => console.log(line));
3732
3772
  log(
3733
- import_chalk8.default.dim(
3773
+ import_chalk9.default.dim(
3734
3774
  `
3735
3775
  [--wait-for-lock] delegation ${args.delegationId} is awaiting on-chain lock confirmation; polling until ready (interval=${args.intervalSec}s timeout=${args.timeoutSec}s)`
3736
3776
  )
@@ -3745,7 +3785,7 @@ async function awaitDelegationLockFinalized(cmdName, api, signer, args) {
3745
3785
  after = page[page.length - 1].id;
3746
3786
  }
3747
3787
  };
3748
- const outcome = await (0, import_sdk7.pollUntil)({
3788
+ const outcome = await (0, import_sdk12.pollUntil)({
3749
3789
  fetch: fetchRow,
3750
3790
  // Match on either "row not found at all" OR "state moved
3751
3791
  // past pending_lock_finalization". The post-poll branch
@@ -3755,7 +3795,7 @@ async function awaitDelegationLockFinalized(cmdName, api, signer, args) {
3755
3795
  // rows return cleanly. Polling on null would loop pointlessly
3756
3796
  // until the deadline fires and surface a misleading "timed
3757
3797
  // out" message for what's actually a wrong-id problem.
3758
- predicate: (row2) => row2 === null || row2.state !== "pending_lock_finalization",
3798
+ predicate: (row2) => row2 === null || row2.state !== import_sdk12.DelegationStates.PENDING_LOCK_FINALIZATION,
3759
3799
  intervalMs: args.intervalSec * 1e3,
3760
3800
  timeoutMs: args.timeoutSec * 1e3,
3761
3801
  // Swallow ONLY transient errors. A 4xx during the poll is a
@@ -3769,7 +3809,7 @@ async function awaitDelegationLockFinalized(cmdName, api, signer, args) {
3769
3809
  if (err instanceof ApiError && err.status >= 400 && err.status < 500) {
3770
3810
  throw err;
3771
3811
  }
3772
- log(import_chalk8.default.dim(` poll: transient fetch error (${err instanceof Error ? err.message : String(err)})`));
3812
+ log(import_chalk9.default.dim(` poll: transient fetch error (${err instanceof Error ? err.message : String(err)})`));
3773
3813
  }
3774
3814
  });
3775
3815
  if (outcome.kind === "timeout") {
@@ -3786,12 +3826,12 @@ async function awaitDelegationLockFinalized(cmdName, api, signer, args) {
3786
3826
  `${cmdName}: delegation ${args.delegationId} disappeared from relationship ${args.relationshipId} during --wait-for-lock pre-flight. Re-check the delegation id with \`heyarp delegations ${args.relationshipId}\`.`
3787
3827
  );
3788
3828
  }
3789
- if (row.state !== "offered") {
3829
+ if (row.state !== import_sdk12.DelegationStates.OFFERED) {
3790
3830
  throw new Error(
3791
3831
  `${cmdName}: delegation ${args.delegationId} transitioned to '${row.state}' while waiting for on-chain lock confirmation; cannot ${args.action}. Re-read the delegation timeline with \`heyarp delegations ${args.relationshipId}\` to see the latest state.`
3792
3832
  );
3793
3833
  }
3794
- log(import_chalk8.default.dim(`[--wait-for-lock] delegation ${args.delegationId} ready (state=${row.state}); proceeding with ${args.action}.`));
3834
+ log(import_chalk9.default.dim(`[--wait-for-lock] delegation ${args.delegationId} ready (state=${row.state}); proceeding with ${args.action}.`));
3795
3835
  return row;
3796
3836
  }
3797
3837
  function parseLockWaitTimeout(cmdName, raw) {
@@ -3817,12 +3857,12 @@ function parseLockWaitInterval(cmdName, raw) {
3817
3857
  return n;
3818
3858
  }
3819
3859
  function printIngestResult(result) {
3820
- console.log(import_chalk8.default.green("\nDelivered."));
3821
- console.log(`${import_chalk8.default.bold("Event id")}: ${import_chalk8.default.cyan(result.eventId)}`);
3822
- console.log(`${import_chalk8.default.bold("Relationship id")}: ${import_chalk8.default.cyan(result.relationshipId)}`);
3823
- console.log(`${import_chalk8.default.bold("Chain index")}: ${import_chalk8.default.cyan(String(result.relationshipEventIndex))}`);
3824
- console.log(`${import_chalk8.default.bold("Server timestamp")}: ${import_chalk8.default.cyan(result.serverTimestamp)}`);
3825
- console.log(`${import_chalk8.default.bold("Server event hash")}: ${import_chalk8.default.cyan(result.serverEventHash)}`);
3860
+ console.log(import_chalk9.default.green("\nDelivered."));
3861
+ console.log(`${import_chalk9.default.bold("Event id")}: ${import_chalk9.default.cyan(result.eventId)}`);
3862
+ console.log(`${import_chalk9.default.bold("Relationship id")}: ${import_chalk9.default.cyan(result.relationshipId)}`);
3863
+ console.log(`${import_chalk9.default.bold("Chain index")}: ${import_chalk9.default.cyan(String(result.relationshipEventIndex))}`);
3864
+ console.log(`${import_chalk9.default.bold("Server timestamp")}: ${import_chalk9.default.cyan(result.serverTimestamp)}`);
3865
+ console.log(`${import_chalk9.default.bold("Server event hash")}: ${import_chalk9.default.cyan(result.serverEventHash)}`);
3826
3866
  }
3827
3867
  function parseOfferTerms(cmdName, opts) {
3828
3868
  const out = {};
@@ -3846,7 +3886,7 @@ function parseOfferTerms(cmdName, opts) {
3846
3886
  if (opts.amount) {
3847
3887
  out.amount = opts.amount;
3848
3888
  if (!opts.currency) {
3849
- throw new Error(`${cmdName}: --amount requires --currency. Shorthand: ${import_sdk7.WELL_KNOWN_ASSET_KEYS.join(", ")}, or raw CAIP-19 + --currency-decimals.`);
3889
+ throw new Error(`${cmdName}: --amount requires --currency. Shorthand: ${import_sdk12.WELL_KNOWN_ASSET_KEYS.join(", ")}, or raw CAIP-19 + --currency-decimals.`);
3850
3890
  }
3851
3891
  out.currency = buildAssetIdentifier(cmdName, DELEGATION_CURRENCY_FLAGS, opts.currency, opts.currencyDecimals, opts.currencySymbol);
3852
3892
  } else if (opts.currency) {
@@ -3869,7 +3909,7 @@ function resolveOfferDelegationId(rawCliId, escrow) {
3869
3909
  cliId = rawCliId.toLowerCase();
3870
3910
  }
3871
3911
  if (escrow === void 0) {
3872
- return cliId ?? (0, import_sdk7.uuidV4)();
3912
+ return cliId ?? (0, import_sdk12.uuidV4)();
3873
3913
  }
3874
3914
  if (escrow.delegationIdFromLock !== void 0) {
3875
3915
  const fileId = escrow.delegationIdFromLock;
@@ -3894,20 +3934,15 @@ function requireUuidNormalised(cmdName, raw, label) {
3894
3934
  requireUuid2(cmdName, raw, label);
3895
3935
  return raw.toLowerCase();
3896
3936
  }
3897
- function requireDid(cmdName, did, label) {
3898
- if (typeof did !== "string" || !did.startsWith("did:arp:") || did.length <= "did:arp:".length) {
3899
- throw new Error(`${cmdName}: ${label} must look like 'did:arp:...' (got '${did}')`);
3900
- }
3901
- }
3902
3937
  function collectRepeated(value, previous) {
3903
3938
  return [...previous, value];
3904
3939
  }
3905
3940
  function parseDeclineReason(cmdName, raw) {
3906
3941
  if (raw === void 0 || raw === "") {
3907
- throw new Error(`${cmdName}: --reason is required when declining (one of: ${import_sdk7.DECLINE_REASONS.join(", ")})`);
3942
+ throw new Error(`${cmdName}: --reason is required when declining (one of: ${import_sdk12.DECLINE_REASONS.join(", ")})`);
3908
3943
  }
3909
- if (!(0, import_sdk7.isDeclineReason)(raw)) {
3910
- throw new Error(`${cmdName}: --reason must be one of ${import_sdk7.DECLINE_REASONS.join(", ")} (got '${raw}')`);
3944
+ if (!(0, import_sdk12.isDeclineReason)(raw)) {
3945
+ throw new Error(`${cmdName}: --reason must be one of ${import_sdk12.DECLINE_REASONS.join(", ")} (got '${raw}')`);
3911
3946
  }
3912
3947
  return raw;
3913
3948
  }
@@ -3922,10 +3957,10 @@ function parseReasonDetail(cmdName, raw) {
3922
3957
  return raw;
3923
3958
  }
3924
3959
  function buildAssetIdentifier(cmdName, labels, rawCurrency, rawDecimals, rawSymbol) {
3925
- const resolved = (0, import_sdk7.resolveAsset)(rawCurrency);
3960
+ const resolved = (0, import_sdk12.resolveAsset)(rawCurrency);
3926
3961
  if (!resolved) {
3927
3962
  throw new Error(
3928
- `${cmdName}: ${labels.currencyFlag} '${rawCurrency}' is not a known shorthand or a valid CAIP-19 string. Shorthand: ${import_sdk7.WELL_KNOWN_ASSET_KEYS.join(", ")}. Or pass a raw CAIP-19 id (e.g. "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/spl:EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v") with ${labels.decimalsFlag}.`
3963
+ `${cmdName}: ${labels.currencyFlag} '${rawCurrency}' is not a known shorthand or a valid CAIP-19 string. Shorthand: ${import_sdk12.WELL_KNOWN_ASSET_KEYS.join(", ")}. Or pass a raw CAIP-19 id (e.g. "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/spl:EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v") with ${labels.decimalsFlag}.`
3929
3964
  );
3930
3965
  }
3931
3966
  let decimals = resolved.decimals;
@@ -3934,20 +3969,20 @@ function buildAssetIdentifier(cmdName, labels, rawCurrency, rawDecimals, rawSymb
3934
3969
  throw new Error(`${cmdName}: ${labels.currencyFlag} is a raw CAIP-19 string; ${labels.decimalsFlag} (0-18) is required to convert amounts to base units.`);
3935
3970
  }
3936
3971
  const parsed = Number(rawDecimals);
3937
- if (!Number.isInteger(parsed) || parsed < 0 || parsed > 18) {
3972
+ if (!Number.isInteger(parsed) || parsed < import_sdk12.ASSET_DECIMALS_MIN || parsed > import_sdk12.ASSET_DECIMALS_MAX) {
3938
3973
  throw new Error(`${cmdName}: ${labels.decimalsFlag} must be an integer in [0, 18] (got '${rawDecimals}').`);
3939
3974
  }
3940
3975
  decimals = parsed;
3941
3976
  } else if (rawDecimals !== void 0) {
3942
3977
  const parsed = Number(rawDecimals);
3943
- if (!Number.isInteger(parsed) || parsed < 0 || parsed > 18) {
3978
+ if (!Number.isInteger(parsed) || parsed < import_sdk12.ASSET_DECIMALS_MIN || parsed > import_sdk12.ASSET_DECIMALS_MAX) {
3944
3979
  throw new Error(`${cmdName}: ${labels.decimalsFlag} must be an integer in [0, 18] (got '${rawDecimals}').`);
3945
3980
  }
3946
3981
  decimals = parsed;
3947
3982
  }
3948
3983
  let symbol = resolved.symbol;
3949
3984
  if (rawSymbol !== void 0) {
3950
- if (rawSymbol.length === 0 || rawSymbol.length > 16) {
3985
+ if (rawSymbol.length < import_sdk12.ASSET_SYMBOL_MIN_LEN || rawSymbol.length > import_sdk12.ASSET_SYMBOL_MAX_LEN) {
3951
3986
  throw new Error(`${cmdName}: ${labels.symbolFlag} must be 1-16 chars (got length ${rawSymbol.length}).`);
3952
3987
  }
3953
3988
  symbol = rawSymbol;
@@ -3961,9 +3996,10 @@ var DELEGATION_CURRENCY_FLAGS = {
3961
3996
  };
3962
3997
 
3963
3998
  // src/commands/delegations.ts
3964
- var import_chalk9 = __toESM(require("chalk"));
3999
+ var import_sdk13 = require("@heyanon-arp/sdk");
4000
+ var import_chalk10 = __toESM(require("chalk"));
3965
4001
  init_api();
3966
- var ALLOWED_STATES = /* @__PURE__ */ new Set(["offered", "accepted", "declined", "canceled"]);
4002
+ var ALLOWED_STATES = /* @__PURE__ */ new Set([import_sdk13.DelegationStates.OFFERED, import_sdk13.DelegationStates.ACCEPTED, import_sdk13.DelegationStates.DECLINED, import_sdk13.DelegationStates.CANCELED]);
3967
4003
  function registerDelegationsCommand(root) {
3968
4004
  root.command("delegations").description("List delegations for a relationship (one row per delegationId, oldest-first)").argument("<relationship-id>", "Relationship UUID").option("--server <url>", "Override ARP server base URL").option("--state <s>", "Filter by exact state (offered|accepted|declined|canceled)").option("--after <id>", "Cursor: pass the previous page's last `id` to fetch the next page").option("--limit <n>", "Max rows to return (1..100)", "20").option("--from-did <did>", "Signer DID \u2014 required only if multiple agents are registered against this server").option(
3969
4005
  "--verbose",
@@ -3983,9 +4019,9 @@ async function runDelegations(relationshipId, opts) {
3983
4019
  const state = parseState(opts.state);
3984
4020
  const api = new ArpApiClient(opts.server);
3985
4021
  const sender = resolveSenderAgent("delegations", opts.server, opts.fromDid);
3986
- progress(opts.json, import_chalk9.default.dim(`Server: ${api.serverUrl}`));
3987
- progress(opts.json, import_chalk9.default.dim(`Signer: ${sender.did}`));
3988
- progress(opts.json, import_chalk9.default.dim(`Relationship: ${relationshipId}`));
4022
+ progress(opts.json, import_chalk10.default.dim(`Server: ${api.serverUrl}`));
4023
+ progress(opts.json, import_chalk10.default.dim(`Signer: ${sender.did}`));
4024
+ progress(opts.json, import_chalk10.default.dim(`Relationship: ${relationshipId}`));
3989
4025
  const query = { limit };
3990
4026
  if (state) query.state = state;
3991
4027
  if (opts.after) query.after = opts.after;
@@ -3996,7 +4032,7 @@ async function runDelegations(relationshipId, opts) {
3996
4032
  return;
3997
4033
  }
3998
4034
  if (rows.length === 0) {
3999
- console.log(import_chalk9.default.dim("\n(no delegations for this relationship)"));
4035
+ console.log(import_chalk10.default.dim("\n(no delegations for this relationship)"));
4000
4036
  return;
4001
4037
  }
4002
4038
  console.log("");
@@ -4012,19 +4048,19 @@ async function runDelegations(relationshipId, opts) {
4012
4048
  }));
4013
4049
  }
4014
4050
  const lastId = rows[rows.length - 1].id;
4015
- console.log(import_chalk9.default.dim(`
4051
+ console.log(import_chalk10.default.dim(`
4016
4052
  ${rows.length} delegation row(s). Paginate with --after ${lastId}.`));
4017
4053
  }
4018
4054
  function formatDelegationLine(d, selfDid, opts = {}) {
4019
- const idHead_ = import_chalk9.default.bold(opts.fullIds ? d.delegationId : idHead(d.delegationId));
4055
+ const idHead_ = import_chalk10.default.bold(opts.fullIds ? d.delegationId : idHead(d.delegationId));
4020
4056
  const state = colorState(d.state).padEnd(stateColumnWidth());
4021
- const offerer = d.offererDid === selfDid ? import_chalk9.default.bold("me") : import_chalk9.default.dim(opts.fullIds ? d.offererDid : didHead(d.offererDid));
4057
+ const offerer = d.offererDid === selfDid ? import_chalk10.default.bold("me") : import_chalk10.default.dim(opts.fullIds ? d.offererDid : didHead(d.offererDid));
4022
4058
  const amount = formatAmount(d);
4023
- const title = d.title ? import_chalk9.default.dim(`"${truncate2(d.title, 40)}"`) : import_chalk9.default.dim("(no title)");
4059
+ const title = d.title ? import_chalk10.default.dim(`"${truncate2(d.title, 40)}"`) : import_chalk10.default.dim("(no title)");
4024
4060
  let declineSuffix = "";
4025
- if (d.state === "declined" && d.declineReason) {
4061
+ if (d.state === import_sdk13.DelegationStates.DECLINED && d.declineReason) {
4026
4062
  const detail = d.declineReasonDetail ? `: ${truncate2(d.declineReasonDetail, 40)}` : "";
4027
- declineSuffix = ` ${import_chalk9.default.dim(`(reason: ${d.declineReason}${detail})`)}`;
4063
+ declineSuffix = ` ${import_chalk10.default.dim(`(reason: ${d.declineReason}${detail})`)}`;
4028
4064
  }
4029
4065
  return `${idHead_} ${state} ${offerer} ${amount} ${title}${declineSuffix}`;
4030
4066
  }
@@ -4037,35 +4073,35 @@ function colorState(s) {
4037
4073
  // returns `undefined` and `formatDelegationLine` crashes with
4038
4074
  // `TypeError: Cannot read properties of undefined (reading
4039
4075
  // 'padEnd')` on any listing containing such a row.
4040
- case "offered":
4041
- return import_chalk9.default.yellow("offered");
4042
- case "pending_lock_finalization":
4043
- return import_chalk9.default.yellow("pending_lock");
4044
- case "accepted":
4045
- return import_chalk9.default.green("accepted");
4076
+ case import_sdk13.DelegationStates.OFFERED:
4077
+ return import_chalk10.default.yellow("offered");
4078
+ case import_sdk13.DelegationStates.PENDING_LOCK_FINALIZATION:
4079
+ return import_chalk10.default.yellow("pending_lock");
4080
+ case import_sdk13.DelegationStates.ACCEPTED:
4081
+ return import_chalk10.default.green("accepted");
4046
4082
  // The on-chain escrow lock is confirmed. Distinct branch so a
4047
4083
  // LOCKED row renders without hitting the defensive fallback
4048
4084
  // (which would otherwise echo the raw state).
4049
- case "locked":
4050
- return import_chalk9.default.green("locked");
4051
- case "declined":
4052
- return import_chalk9.default.red("declined");
4053
- case "canceled":
4054
- return import_chalk9.default.dim("canceled");
4085
+ case import_sdk13.DelegationStates.LOCKED:
4086
+ return import_chalk10.default.green("locked");
4087
+ case import_sdk13.DelegationStates.DECLINED:
4088
+ return import_chalk10.default.red("declined");
4089
+ case import_sdk13.DelegationStates.CANCELED:
4090
+ return import_chalk10.default.dim("canceled");
4055
4091
  // Terminal escrow outcomes: completed = payee paid;
4056
4092
  // failed = create_lock never landed; refunded = funds returned
4057
4093
  // to the buyer (work expired / dispute closed);
4058
4094
  // dispute_resolved = operator ruled.
4059
- case "completed":
4060
- return import_chalk9.default.green("completed");
4061
- case "failed":
4062
- return import_chalk9.default.red("failed");
4063
- case "refunded":
4064
- return import_chalk9.default.red("refunded");
4065
- case "disputing":
4066
- return import_chalk9.default.yellow("disputing");
4067
- case "dispute_resolved":
4068
- return import_chalk9.default.red("dispute_resolved");
4095
+ case import_sdk13.DelegationStates.COMPLETED:
4096
+ return import_chalk10.default.green("completed");
4097
+ case import_sdk13.DelegationStates.FAILED:
4098
+ return import_chalk10.default.red("failed");
4099
+ case import_sdk13.DelegationStates.REFUNDED:
4100
+ return import_chalk10.default.red("refunded");
4101
+ case import_sdk13.DelegationStates.DISPUTING:
4102
+ return import_chalk10.default.yellow("disputing");
4103
+ case import_sdk13.DelegationStates.DISPUTE_RESOLVED:
4104
+ return import_chalk10.default.red("dispute_resolved");
4069
4105
  default: {
4070
4106
  const _exhaustive = s;
4071
4107
  void _exhaustive;
@@ -4077,9 +4113,9 @@ function stateColumnWidth() {
4077
4113
  return 12;
4078
4114
  }
4079
4115
  function formatAmount(d) {
4080
- if (!d.amount) return import_chalk9.default.dim("(no amount)");
4116
+ if (!d.amount) return import_chalk10.default.dim("(no amount)");
4081
4117
  const currency = d.currency ? d.currency.symbol ?? d.currency.assetId : "?";
4082
- return import_chalk9.default.cyan(`${d.amount} ${currency}`);
4118
+ return import_chalk10.default.cyan(`${d.amount} ${currency}`);
4083
4119
  }
4084
4120
  function idHead(id) {
4085
4121
  if (id.length <= 12) return id;
@@ -4110,7 +4146,7 @@ function parseLimit2(raw) {
4110
4146
  }
4111
4147
 
4112
4148
  // src/commands/did-doc.ts
4113
- var import_sdk8 = require("@heyanon-arp/sdk");
4149
+ var import_sdk14 = require("@heyanon-arp/sdk");
4114
4150
  init_api();
4115
4151
  function registerDidDocCommand(root) {
4116
4152
  root.command("did-doc").description(
@@ -4119,7 +4155,7 @@ function registerDidDocCommand(root) {
4119
4155
  "--field <path>",
4120
4156
  "Extract a single value via a dotted path. Supports object property access (`id`), numeric array indexes (`verificationMethod.0`), and `#fragment` array selectors that match a verification-method or service entry by its `id` suffix (`verificationMethod.#settlement.publicKeyMultibase`). Two well-known shortcuts skip the path entirely AND strip the multibase prefix: `settlementPublicKey` / `identityPublicKey` emit the raw base58 pubkey ready for flags like `--recipient-pubkey`. Scalar values (string / number / boolean) emit raw to stdout for shell composition (`KEY=$(heyarp did-doc ... --field ...)`); objects / arrays emit as pretty-printed JSON. Mutually exclusive with `--json` since `--field` already controls the shape."
4121
4157
  ).action(async (did, opts) => {
4122
- if (!(0, import_sdk8.isValidDid)(did)) {
4158
+ if (!(0, import_sdk14.isValidDid)(did)) {
4123
4159
  throw new Error(`'${did}' is not a syntactically valid did:arp identifier`);
4124
4160
  }
4125
4161
  if (opts.json && opts.field !== void 0) {
@@ -4231,8 +4267,8 @@ function describeShape(value) {
4231
4267
  }
4232
4268
 
4233
4269
  // src/commands/doctor.ts
4234
- var import_sdk9 = require("@heyanon-arp/sdk");
4235
- var import_chalk10 = __toESM(require("chalk"));
4270
+ var import_sdk15 = require("@heyanon-arp/sdk");
4271
+ var import_chalk11 = __toESM(require("chalk"));
4236
4272
  init_api();
4237
4273
  function registerDoctorCommand(root) {
4238
4274
  root.command("doctor").description("Liveness probe for a counterparty: resolve DID document + read protocol activity. No auth.").argument("<did>", "did:arp:<base58btc> of the agent to probe").option("--server <url>", "Override ARP server base URL").option("--json", "Machine-readable: single JSON object on stdout. Pipe-safe.", false).action(async (did, opts) => {
@@ -4241,7 +4277,7 @@ function registerDoctorCommand(root) {
4241
4277
  }
4242
4278
  var LISTENING_THRESHOLD_SECONDS = 15 * 60;
4243
4279
  async function runDoctor(did, opts) {
4244
- if (!(0, import_sdk9.isValidDid)(did)) {
4280
+ if (!(0, import_sdk15.isValidDid)(did)) {
4245
4281
  throw new Error(`'${did}' is not a syntactically valid did:arp identifier`);
4246
4282
  }
4247
4283
  const api = new ArpApiClient(opts.server);
@@ -4325,39 +4361,39 @@ async function probe(api, did) {
4325
4361
  }
4326
4362
  function formatDoctorReport(r) {
4327
4363
  const lines = [];
4328
- lines.push(`${import_chalk10.default.dim("Server:")} ${r.server}`);
4329
- lines.push(`${import_chalk10.default.dim("Target DID:")} ${r.did}`);
4364
+ lines.push(`${import_chalk11.default.dim("Server:")} ${r.server}`);
4365
+ lines.push(`${import_chalk11.default.dim("Target DID:")} ${r.did}`);
4330
4366
  if (!r.didDocument.found) {
4331
- lines.push(`${import_chalk10.default.dim("DID doc:")} ${import_chalk10.default.red("\u2717")} not found`);
4367
+ lines.push(`${import_chalk11.default.dim("DID doc:")} ${import_chalk11.default.red("\u2717")} not found`);
4332
4368
  } else {
4333
4369
  const registered = r.didDocument.registeredAt ? ` (registered ${r.didDocument.registeredAt})` : "";
4334
- lines.push(`${import_chalk10.default.dim("DID doc:")} ${import_chalk10.default.green("\u2713")} resolved${registered}`);
4370
+ lines.push(`${import_chalk11.default.dim("DID doc:")} ${import_chalk11.default.green("\u2713")} resolved${registered}`);
4335
4371
  }
4336
4372
  if (r.activity) {
4337
4373
  if (r.activity.lastEventAt === null) {
4338
- lines.push(`${import_chalk10.default.dim("Activity:")} ${import_chalk10.default.dim("(no events ever \u2014 fresh agent)")}`);
4374
+ lines.push(`${import_chalk11.default.dim("Activity:")} ${import_chalk11.default.dim("(no events ever \u2014 fresh agent)")}`);
4339
4375
  } else {
4340
4376
  const ageMin = r.activity.ageSeconds !== null ? Math.floor(r.activity.ageSeconds / 60) : null;
4341
4377
  const ageStr = ageMin !== null && ageMin > 0 ? `${ageMin}m ago` : `${r.activity.ageSeconds}s ago`;
4342
- lines.push(`${import_chalk10.default.dim("Activity:")} last event ${ageStr} (${r.activity.lastEventAt})`);
4378
+ lines.push(`${import_chalk11.default.dim("Activity:")} last event ${ageStr} (${r.activity.lastEventAt})`);
4343
4379
  }
4344
4380
  if (r.activity.lastSeenAt !== null && r.activity.lastSeenAt !== void 0) {
4345
4381
  const seenMin = r.activity.seenAgeSeconds !== null && r.activity.seenAgeSeconds !== void 0 ? Math.floor(r.activity.seenAgeSeconds / 60) : null;
4346
4382
  const seenStr = seenMin !== null && seenMin > 0 ? `${seenMin}m ago` : `${r.activity.seenAgeSeconds}s ago`;
4347
- lines.push(`${import_chalk10.default.dim("Last seen:")} signed request ${seenStr} (${r.activity.lastSeenAt})`);
4383
+ lines.push(`${import_chalk11.default.dim("Last seen:")} signed request ${seenStr} (${r.activity.lastSeenAt})`);
4348
4384
  }
4349
4385
  if (r.activity.inboxStreamActive === true) {
4350
- lines.push(`${import_chalk10.default.dim("Inbox SSE:")} ${import_chalk10.default.green("\u2713")} active subscription on the central server`);
4386
+ lines.push(`${import_chalk11.default.dim("Inbox SSE:")} ${import_chalk11.default.green("\u2713")} active subscription on the central server`);
4351
4387
  }
4352
4388
  }
4353
- const verdictColor = r.verdict === "LISTENING" ? import_chalk10.default.green : r.verdict === "DORMANT" ? import_chalk10.default.red : import_chalk10.default.yellow;
4389
+ const verdictColor = r.verdict === "LISTENING" ? import_chalk11.default.green : r.verdict === "DORMANT" ? import_chalk11.default.red : import_chalk11.default.yellow;
4354
4390
  lines.push("");
4355
- lines.push(`${import_chalk10.default.bold("Verdict:")} ${verdictColor(r.verdict)} \u2014 ${r.reason}`);
4391
+ lines.push(`${import_chalk11.default.bold("Verdict:")} ${verdictColor(r.verdict)} \u2014 ${r.reason}`);
4356
4392
  return lines.join("\n");
4357
4393
  }
4358
4394
 
4359
4395
  // src/commands/envelope.ts
4360
- var import_chalk11 = __toESM(require("chalk"));
4396
+ var import_chalk12 = __toESM(require("chalk"));
4361
4397
  init_api();
4362
4398
  function registerEnvelopeCommand(root) {
4363
4399
  root.command("envelope").description("Fetch one canonical envelope by eventId \u2014 full body for inspection (signed read)").argument("<event-id>", "Event UUID \u2014 copy from `heyarp inbox`, `heyarp events`, or a counterparty citation").option("--server <url>", "Override ARP server base URL").option("--from-did <did>", "Signer DID \u2014 required only if multiple agents are registered against this server").option("--json", "Machine-readable: emit only the envelope JSON object on stdout (no prelude, no chalk). Pipe-safe.", false).action(async (eventId, opts) => {
@@ -4368,9 +4404,9 @@ async function runEnvelope(eventId, opts) {
4368
4404
  const api = new ArpApiClient(opts.server);
4369
4405
  const sender = resolveSenderAgent("envelope", opts.server, opts.fromDid);
4370
4406
  if (!opts.json) {
4371
- console.log(import_chalk11.default.dim(`Server: ${api.serverUrl}`));
4372
- console.log(import_chalk11.default.dim(`Signer: ${sender.did}`));
4373
- console.log(import_chalk11.default.dim(`Event: ${eventId}`));
4407
+ console.log(import_chalk12.default.dim(`Server: ${api.serverUrl}`));
4408
+ console.log(import_chalk12.default.dim(`Signer: ${sender.did}`));
4409
+ console.log(import_chalk12.default.dim(`Event: ${eventId}`));
4374
4410
  }
4375
4411
  const signer = makeSigner(sender);
4376
4412
  const event = await api.getEvent(sender.did, eventId, signer);
@@ -4379,29 +4415,29 @@ async function runEnvelope(eventId, opts) {
4379
4415
  return;
4380
4416
  }
4381
4417
  console.log("");
4382
- console.log(import_chalk11.default.bold("Envelope:"));
4418
+ console.log(import_chalk12.default.bold("Envelope:"));
4383
4419
  console.log(formatJson(event));
4384
4420
  console.log("");
4385
4421
  console.log(formatHints(event));
4386
4422
  }
4387
4423
  function formatHints(event) {
4388
4424
  const lines = [];
4389
- lines.push(`${import_chalk11.default.dim("relationshipId:")} ${import_chalk11.default.cyan(event.relationshipId)}`);
4390
- lines.push(`${import_chalk11.default.dim("serverEventHash:")} ${import_chalk11.default.cyan(event.serverEventHash)}`);
4391
- lines.push(`${import_chalk11.default.dim("eventId:")} ${import_chalk11.default.cyan(event.eventId)}`);
4392
- lines.push(`${import_chalk11.default.dim("relationshipEventIndex:")} ${import_chalk11.default.cyan(String(event.relationshipEventIndex))}`);
4425
+ lines.push(`${import_chalk12.default.dim("relationshipId:")} ${import_chalk12.default.cyan(event.relationshipId)}`);
4426
+ lines.push(`${import_chalk12.default.dim("serverEventHash:")} ${import_chalk12.default.cyan(event.serverEventHash)}`);
4427
+ lines.push(`${import_chalk12.default.dim("eventId:")} ${import_chalk12.default.cyan(event.eventId)}`);
4428
+ lines.push(`${import_chalk12.default.dim("relationshipEventIndex:")} ${import_chalk12.default.cyan(String(event.relationshipEventIndex))}`);
4393
4429
  return lines.join("\n");
4394
4430
  }
4395
4431
 
4396
4432
  // src/commands/escrow.ts
4397
- var import_sdk11 = require("@heyanon-arp/sdk");
4433
+ var import_sdk17 = require("@heyanon-arp/sdk");
4398
4434
  var import_utils2 = require("@noble/hashes/utils");
4399
- var import_chalk12 = __toESM(require("chalk"));
4435
+ var import_chalk13 = __toESM(require("chalk"));
4400
4436
  init_api();
4401
4437
 
4402
4438
  // src/commands/escrow-actions.ts
4403
4439
  var import_node_crypto = require("crypto");
4404
- var import_sdk10 = require("@heyanon-arp/sdk");
4440
+ var import_sdk16 = require("@heyanon-arp/sdk");
4405
4441
  var import_web33 = require("@solana/web3.js");
4406
4442
  init_api();
4407
4443
  var FEE_BUFFER_LAMPORTS = 10000000n;
@@ -4415,7 +4451,7 @@ async function setup(cmd, delegationIdArg, opts) {
4415
4451
  const delegationId = normaliseDelegationId(delegationIdArg);
4416
4452
  const fetched = await fetchLockAccount(conn, programId, delegationId);
4417
4453
  if (!fetched) {
4418
- const lockPda = deriveLockPda(programId, (0, import_sdk10.deriveLockId)(delegationId)).toBase58();
4454
+ const lockPda = deriveLockPda(programId, (0, import_sdk16.deriveLockId)(delegationId)).toBase58();
4419
4455
  throw new Error(
4420
4456
  `${cmd}: no on-chain Lock for delegation ${delegationId} (PDA ${lockPda} not found on ${rpcUrl}). Either the buyer hasn't funded yet (delegation fund \u2192 server relays create_lock), or you're pointing at the wrong cluster/program.`
4421
4457
  );
@@ -4440,7 +4476,7 @@ function nowSecs() {
4440
4476
  function deadlinePassed(ctx) {
4441
4477
  return ctx.lock.expiry > 0n && nowSecs() >= ctx.lock.expiry;
4442
4478
  }
4443
- var SYSTEM_PROGRAM_B58 = "11111111111111111111111111111111";
4479
+ var SYSTEM_PROGRAM_B58 = import_sdk16.SYSTEM_PROGRAM_ID_BASE58;
4444
4480
  function effectiveFeeRecipient(lock) {
4445
4481
  if (lock.feeRecipientAtLock !== SYSTEM_PROGRAM_B58) return new import_web33.PublicKey(lock.feeRecipientAtLock);
4446
4482
  if (lock.treasuryAtLock && lock.treasuryAtLock !== SYSTEM_PROGRAM_B58) return new import_web33.PublicKey(lock.treasuryAtLock);
@@ -4502,7 +4538,7 @@ function emit(ctx, action, signature, extra = {}) {
4502
4538
  }
4503
4539
  async function acceptHandler(delegationId, opts) {
4504
4540
  const ctx = await setup("escrow accept", delegationId, opts);
4505
- requireState(ctx, ["created"], "Accept is only possible before any other transition; if it shows in_progress you already accepted.");
4541
+ requireState(ctx, [import_sdk16.LockStates.CREATED], "Accept is only possible before any other transition; if it shows in_progress you already accepted.");
4506
4542
  requireSigner(ctx, "payee", ctx.lock.payee);
4507
4543
  const stake = ctx.lock.workerStakeAtLock;
4508
4544
  await preflightLamports(ctx, stake, `the worker stake (${stake} lamports, returned when the lock settles in your favour)`);
@@ -4512,7 +4548,7 @@ async function acceptHandler(delegationId, opts) {
4512
4548
  }
4513
4549
  async function submitWorkHandler(delegationId, opts) {
4514
4550
  const ctx = await setup("escrow submit-work", delegationId, opts);
4515
- requireState(ctx, ["in_progress"], "Submit needs an accepted lock ('created' \u2192 run `heyarp escrow accept` first; terminal \u2192 the cycle already ended).");
4551
+ requireState(ctx, [import_sdk16.LockStates.IN_PROGRESS], "Submit needs an accepted lock ('created' \u2192 run `heyarp escrow accept` first; terminal \u2192 the cycle already ended).");
4516
4552
  requireSigner(ctx, "payee", ctx.lock.payee);
4517
4553
  if (deadlinePassed(ctx)) {
4518
4554
  throw new Error(
@@ -4523,7 +4559,7 @@ async function submitWorkHandler(delegationId, opts) {
4523
4559
  let reviewDeadline = null;
4524
4560
  try {
4525
4561
  const fresh = await fetchLockAccount(ctx.conn, ctx.programId, ctx.delegationId);
4526
- if (fresh && fresh.lock.state === "submitted" && fresh.lock.expiry > 0n) {
4562
+ if (fresh && fresh.lock.state === import_sdk16.LockStates.SUBMITTED && fresh.lock.expiry > 0n) {
4527
4563
  reviewDeadline = new Date(Number(fresh.lock.expiry) * 1e3).toISOString();
4528
4564
  }
4529
4565
  } catch {
@@ -4536,22 +4572,25 @@ async function submitWorkHandler(delegationId, opts) {
4536
4572
  }
4537
4573
  async function claimHandler(delegationId, opts) {
4538
4574
  const ctx = await setup("escrow claim", delegationId, opts);
4539
- requireState(ctx, ["submitted"], "Claim needs submitted work ('in_progress' \u2192 the worker must `escrow submit-work` first; 'paid' \u2192 already claimed).");
4575
+ requireState(ctx, [import_sdk16.LockStates.SUBMITTED], "Claim needs submitted work ('in_progress' \u2192 the worker must `escrow submit-work` first; 'paid' \u2192 already claimed).");
4540
4576
  const me = ctx.keypair.publicKey.toBase58();
4541
4577
  let role;
4542
4578
  if (me === ctx.lock.payer) {
4543
- role = "buyer_approved";
4579
+ role = import_sdk16.EscrowReleaseMethods.BUYER_APPROVED;
4544
4580
  } else if (me === ctx.lock.payee) {
4545
4581
  if (!deadlinePassed(ctx)) {
4546
4582
  throw new Error(
4547
4583
  `escrow claim: the review window is still open (until ${expiryIso(ctx)}). As the worker you can self-claim only AFTER it lapses; before that the buyer must approve (or dispute).`
4548
4584
  );
4549
4585
  }
4550
- role = "review_timeout";
4586
+ role = import_sdk16.EscrowReleaseMethods.REVIEW_TIMEOUT;
4551
4587
  } else {
4552
4588
  throw new Error(`escrow claim: your settlement key ${me} is neither the payer (${ctx.lock.payer}) nor the payee (${ctx.lock.payee}) of this lock.`);
4553
4589
  }
4554
- progress(ctx.opts.json, role === "buyer_approved" ? "approving payment as the buyer \u2014 this RELEASES the escrow and is irreversible" : "self-claiming after review timeout");
4590
+ progress(
4591
+ ctx.opts.json,
4592
+ role === import_sdk16.EscrowReleaseMethods.BUYER_APPROVED ? "approving payment as the buyer \u2014 this RELEASES the escrow and is irreversible" : "self-claiming after review timeout"
4593
+ );
4555
4594
  const sig = await sendIx(
4556
4595
  ctx,
4557
4596
  buildClaimWorkPaymentIx({
@@ -4568,7 +4607,7 @@ async function claimHandler(delegationId, opts) {
4568
4607
  }
4569
4608
  async function cancelHandler(delegationId, opts) {
4570
4609
  const ctx = await setup("escrow cancel", delegationId, opts);
4571
- requireState(ctx, ["created"], "Cancel is the pre-accept exit only \u2014 once the worker accepted ('in_progress') the windows model governs.");
4610
+ requireState(ctx, [import_sdk16.LockStates.CREATED], "Cancel is the pre-accept exit only \u2014 once the worker accepted ('in_progress') the windows model governs.");
4572
4611
  requireSigner(ctx, "payer", ctx.lock.payer);
4573
4612
  const sig = await sendIx(
4574
4613
  ctx,
@@ -4583,7 +4622,7 @@ async function cancelHandler(delegationId, opts) {
4583
4622
  }
4584
4623
  async function claimExpiredHandler(delegationId, opts) {
4585
4624
  const ctx = await setup("escrow claim-expired", delegationId, opts);
4586
- requireState(ctx, ["in_progress"], "Claim-expired recovers an accepted-but-never-submitted lock; 'submitted' work goes through claim/dispute instead.");
4625
+ requireState(ctx, [import_sdk16.LockStates.IN_PROGRESS], "Claim-expired recovers an accepted-but-never-submitted lock; 'submitted' work goes through claim/dispute instead.");
4587
4626
  requireSigner(ctx, "payer", ctx.lock.payer);
4588
4627
  if (!deadlinePassed(ctx)) {
4589
4628
  throw new Error(`escrow claim-expired: the work window is still open (until ${expiryIso(ctx)}). The worker can still submit; the chain will reject this claim until then.`);
@@ -4601,7 +4640,7 @@ async function claimExpiredHandler(delegationId, opts) {
4601
4640
  }
4602
4641
  async function disputeOpenHandler(delegationId, opts) {
4603
4642
  const ctx = await setup("escrow dispute open", delegationId, opts);
4604
- requireState(ctx, ["submitted"], "Disputes open against SUBMITTED work, inside the review window.");
4643
+ requireState(ctx, [import_sdk16.LockStates.SUBMITTED], "Disputes open against SUBMITTED work, inside the review window.");
4605
4644
  requireSigner(ctx, "payer", ctx.lock.payer);
4606
4645
  if (deadlinePassed(ctx)) {
4607
4646
  throw new Error(
@@ -4616,7 +4655,7 @@ async function disputeOpenHandler(delegationId, opts) {
4616
4655
  }
4617
4656
  async function disputeCloseHandler(delegationId, opts) {
4618
4657
  const ctx = await setup("escrow dispute close", delegationId, opts);
4619
- requireState(ctx, ["disputing"], "Close only applies to an OPEN dispute that the operator never resolved.");
4658
+ requireState(ctx, [import_sdk16.LockStates.DISPUTING], "Close only applies to an OPEN dispute that the operator never resolved.");
4620
4659
  const me = ctx.keypair.publicKey.toBase58();
4621
4660
  if (me !== ctx.lock.payer && me !== ctx.lock.payee) {
4622
4661
  throw new Error(`escrow dispute close: your settlement key ${me} is neither party of this lock.`);
@@ -4641,7 +4680,7 @@ async function disputeCloseHandler(delegationId, opts) {
4641
4680
  }
4642
4681
  async function disputeResolveHandler(delegationId, opts) {
4643
4682
  const ctx = await setup("escrow dispute resolve", delegationId, opts);
4644
- requireState(ctx, ["disputing"], "Resolve only applies to an OPEN dispute, inside the dispute window.");
4683
+ requireState(ctx, [import_sdk16.LockStates.DISPUTING], "Resolve only applies to an OPEN dispute, inside the dispute window.");
4645
4684
  if (deadlinePassed(ctx)) {
4646
4685
  throw new Error(
4647
4686
  `escrow dispute resolve: the dispute window lapsed at ${expiryIso(ctx)} \u2014 the chain rejects late rulings (LockExpired); either party can now \`escrow dispute close\` instead.`
@@ -4685,7 +4724,7 @@ async function showHandler(delegationId, opts) {
4685
4724
  jsonOut({
4686
4725
  delegation_id: normalised.slice("del_".length),
4687
4726
  lock_exists: false,
4688
- lock_pda: deriveLockPda(programId, (0, import_sdk10.deriveLockId)(normalised)).toBase58(),
4727
+ lock_pda: deriveLockPda(programId, (0, import_sdk16.deriveLockId)(normalised)).toBase58(),
4689
4728
  rpc_url: redactRpcUrl(rpcUrl)
4690
4729
  });
4691
4730
  return;
@@ -4762,7 +4801,7 @@ function registerEscrowCommands(root) {
4762
4801
  "Compute canonical condition_hash (32-byte hex) for `heyarp wallet create-lock --condition-hash <hex>` from the DELEGATION terms. Projects the flags to the canonical subset and hashes via SDK deriveDelegationConditionHash \u2014 no server fetch. The SAME terms MUST go into `delegation offer` or the server rejects the lock (ESC_LOCK_CONDITION_HASH_MISMATCH)."
4763
4802
  ).requiredOption("--delegation-id <id>", "Delegation UUID this lock binds (drives the on-chain lock_id + the condition_hash identity binding)").requiredOption("--scope <text>", "scope_summary \u2014 short prose describing the agreed work").option(
4764
4803
  "--currency <s>",
4765
- `Asset identifier bound into the hash: shorthand (${import_sdk11.WELL_KNOWN_ASSET_KEYS.join("|")}) OR raw CAIP-19 string. Optional but must match the offer's --currency.`
4804
+ `Asset identifier bound into the hash: shorthand (${import_sdk17.WELL_KNOWN_ASSET_KEYS.join("|")}) OR raw CAIP-19 string. Optional but must match the offer's --currency.`
4766
4805
  ).option("--currency-decimals <n>", "Decimal places (0-18). Required only when --currency is raw CAIP-19.").option("--currency-symbol <s>", 'Optional UI hint ("USDC", "SOL"). Max 16 chars.').option("--server <url>", "Override ARP server base URL").option("--from-did <did>", "Sender DID \u2014 required only if multiple agents are registered against this server").option("--json", "Machine-readable JSON: {delegation_id, condition_hash_hex, projected_subset}", false).action(async (opts) => {
4767
4806
  await runDeriveConditionHash(opts);
4768
4807
  });
@@ -4776,7 +4815,7 @@ async function runEscrowInfo(opts) {
4776
4815
  const api = new ArpApiClient(opts.server);
4777
4816
  const status = await api.getEscrowConfig();
4778
4817
  if (opts.json) {
4779
- progress(true, import_chalk12.default.dim(`Server: ${api.serverUrl}`));
4818
+ progress(true, import_chalk13.default.dim(`Server: ${api.serverUrl}`));
4780
4819
  jsonOut(status);
4781
4820
  } else {
4782
4821
  console.log(formatEscrowConfigStatus(api.serverUrl, status));
@@ -4785,35 +4824,35 @@ async function runEscrowInfo(opts) {
4785
4824
  function formatEscrowConfigStatus(serverUrl, s) {
4786
4825
  const lines = [];
4787
4826
  const win = (secs) => secs % 3600 === 0 ? `${secs / 3600}h` : secs % 60 === 0 ? `${secs / 60}m` : `${secs}s`;
4788
- lines.push(`${import_chalk12.default.dim("Server:")} ${serverUrl}`);
4789
- lines.push(`${import_chalk12.default.dim("Program ID:")} ${s.programId}`);
4790
- lines.push(`${import_chalk12.default.dim("Admin:")} ${s.admin}`);
4791
- lines.push(`${import_chalk12.default.dim("Treasury:")} ${s.treasury}`);
4792
- lines.push(`${import_chalk12.default.dim("Paused:")} ${s.paused ? import_chalk12.default.yellow("YES (new locks rejected)") : import_chalk12.default.green("no")}`);
4827
+ lines.push(`${import_chalk13.default.dim("Server:")} ${serverUrl}`);
4828
+ lines.push(`${import_chalk13.default.dim("Program ID:")} ${s.programId}`);
4829
+ lines.push(`${import_chalk13.default.dim("Admin:")} ${s.admin}`);
4830
+ lines.push(`${import_chalk13.default.dim("Treasury:")} ${s.treasury}`);
4831
+ lines.push(`${import_chalk13.default.dim("Paused:")} ${s.paused ? import_chalk13.default.yellow("YES (new locks rejected)") : import_chalk13.default.green("no")}`);
4793
4832
  lines.push("");
4794
- lines.push(import_chalk12.default.bold("Windows (rolling deadlines):"));
4795
- lines.push(` ${import_chalk12.default.dim("work:")} ${win(s.workWindowSecs)} ${import_chalk12.default.dim("(accept \u2192 submit_work)")}`);
4796
- lines.push(` ${import_chalk12.default.dim("review:")} ${win(s.reviewWindowSecs)} ${import_chalk12.default.dim("(submit_work \u2192 buyer approve / worker self-claim)")}`);
4797
- lines.push(` ${import_chalk12.default.dim("dispute:")} ${win(s.disputeWindowSecs)} ${import_chalk12.default.dim("(open_dispute \u2192 operator resolve / timeout close)")}`);
4833
+ lines.push(import_chalk13.default.bold("Windows (rolling deadlines):"));
4834
+ lines.push(` ${import_chalk13.default.dim("work:")} ${win(s.workWindowSecs)} ${import_chalk13.default.dim("(accept \u2192 submit_work)")}`);
4835
+ lines.push(` ${import_chalk13.default.dim("review:")} ${win(s.reviewWindowSecs)} ${import_chalk13.default.dim("(submit_work \u2192 buyer approve / worker self-claim)")}`);
4836
+ lines.push(` ${import_chalk13.default.dim("dispute:")} ${win(s.disputeWindowSecs)} ${import_chalk13.default.dim("(open_dispute \u2192 operator resolve / timeout close)")}`);
4798
4837
  lines.push("");
4799
- lines.push(import_chalk12.default.bold("Stakes:"));
4800
- lines.push(` ${import_chalk12.default.dim("worker stake:")} ${s.workerStakeLamports} lamports ${import_chalk12.default.dim("(escrowed at accept_lock, returned on completion)")}`);
4801
- lines.push(` ${import_chalk12.default.dim("operator dispute fee:")} ${s.operatorDisputeFeeLamports} lamports`);
4838
+ lines.push(import_chalk13.default.bold("Stakes:"));
4839
+ lines.push(` ${import_chalk13.default.dim("worker stake:")} ${s.workerStakeLamports} lamports ${import_chalk13.default.dim("(escrowed at accept_lock, returned on completion)")}`);
4840
+ lines.push(` ${import_chalk13.default.dim("operator dispute fee:")} ${s.operatorDisputeFeeLamports} lamports`);
4802
4841
  lines.push("");
4803
- lines.push(import_chalk12.default.bold("Protocol fee:"));
4842
+ lines.push(import_chalk13.default.bold("Protocol fee:"));
4804
4843
  if (!s.feeEnabled || s.feeBps === 0) {
4805
- lines.push(` ${import_chalk12.default.green("DISABLED")}`);
4806
- lines.push(` ${import_chalk12.default.dim("fee_bps:")} ${s.feeBps}`);
4807
- lines.push(` ${import_chalk12.default.dim("fee_recipient:")} ${s.feeRecipient}`);
4844
+ lines.push(` ${import_chalk13.default.green("DISABLED")}`);
4845
+ lines.push(` ${import_chalk13.default.dim("fee_bps:")} ${s.feeBps}`);
4846
+ lines.push(` ${import_chalk13.default.dim("fee_recipient:")} ${s.feeRecipient}`);
4808
4847
  lines.push("");
4809
- lines.push(import_chalk12.default.dim(` New locks will snapshot fee_bps=0 \u2014 payee receives 100% on claim.`));
4848
+ lines.push(import_chalk13.default.dim(` New locks will snapshot fee_bps=0 \u2014 payee receives 100% on claim.`));
4810
4849
  } else {
4811
4850
  const pct = (s.feeBps / 100).toFixed(2);
4812
- lines.push(` ${import_chalk12.default.yellow("ENABLED")} \u2014 ${pct}% of payee slice (${s.feeBps} bps)`);
4813
- lines.push(` ${import_chalk12.default.dim("fee_recipient:")} ${s.feeRecipient}`);
4851
+ lines.push(` ${import_chalk13.default.yellow("ENABLED")} \u2014 ${pct}% of payee slice (${s.feeBps} bps)`);
4852
+ lines.push(` ${import_chalk13.default.dim("fee_recipient:")} ${s.feeRecipient}`);
4814
4853
  lines.push("");
4815
- lines.push(import_chalk12.default.dim(` New locks will snapshot fee_bps=${s.feeBps} onto themselves.`));
4816
- lines.push(import_chalk12.default.dim(` Existing locks keep their lock-time snapshot \u2014 no retroactive change.`));
4854
+ lines.push(import_chalk13.default.dim(` New locks will snapshot fee_bps=${s.feeBps} onto themselves.`));
4855
+ lines.push(import_chalk13.default.dim(` Existing locks keep their lock-time snapshot \u2014 no retroactive change.`));
4817
4856
  }
4818
4857
  return lines.join("\n");
4819
4858
  }
@@ -4838,10 +4877,10 @@ async function runDeriveConditionHash(opts) {
4838
4877
  }
4839
4878
  const api = new ArpApiClient(opts.server);
4840
4879
  const sender = resolveSenderAgent(cmdName, opts.server, opts.fromDid);
4841
- progress(opts.json, import_chalk12.default.dim(`Server: ${api.serverUrl}`));
4842
- progress(opts.json, import_chalk12.default.dim(`Signer: ${sender.did}`));
4880
+ progress(opts.json, import_chalk13.default.dim(`Server: ${api.serverUrl}`));
4881
+ progress(opts.json, import_chalk13.default.dim(`Signer: ${sender.did}`));
4843
4882
  const subset = projectDelegationForHash(cmdName, opts, delegationId);
4844
- const hashBytes = (0, import_sdk11.deriveDelegationConditionHash)(subset);
4883
+ const hashBytes = (0, import_sdk17.deriveDelegationConditionHash)(subset);
4845
4884
  const hex = (0, import_utils2.bytesToHex)(hashBytes);
4846
4885
  if (opts.json) {
4847
4886
  jsonOut({
@@ -4851,14 +4890,14 @@ async function runDeriveConditionHash(opts) {
4851
4890
  });
4852
4891
  return;
4853
4892
  }
4854
- console.log(import_chalk12.default.dim(`Delegation: ${delegationId}`));
4855
- console.log(import_chalk12.default.dim("Subset hashed:"));
4856
- console.log(import_chalk12.default.dim(` scopeSummary: ${subset.scopeSummary ?? "(unset)"}`));
4857
- if (subset.currency !== void 0) console.log(import_chalk12.default.dim(` currency.asset_id: ${subset.currency.asset_id}`));
4893
+ console.log(import_chalk13.default.dim(`Delegation: ${delegationId}`));
4894
+ console.log(import_chalk13.default.dim("Subset hashed:"));
4895
+ console.log(import_chalk13.default.dim(` scopeSummary: ${subset.scopeSummary ?? "(unset)"}`));
4896
+ if (subset.currency !== void 0) console.log(import_chalk13.default.dim(` currency.asset_id: ${subset.currency.asset_id}`));
4858
4897
  console.log("");
4859
- console.log(`${import_chalk12.default.bold("condition_hash:")} ${hex}`);
4898
+ console.log(`${import_chalk13.default.bold("condition_hash:")} ${hex}`);
4860
4899
  console.log("");
4861
- console.log(import_chalk12.default.dim(`Pass to: heyarp wallet create-lock --delegation-id ${delegationId} --condition-hash ${hex} ...`));
4900
+ console.log(import_chalk13.default.dim(`Pass to: heyarp wallet create-lock --delegation-id ${delegationId} --condition-hash ${hex} ...`));
4862
4901
  }
4863
4902
  function classifyRecoverOutcome(local, server) {
4864
4903
  if (local === server) return { kind: "in-sync", value: local };
@@ -4891,39 +4930,40 @@ async function runRecoverSequence(opts) {
4891
4930
  applied: opts.apply === true && outcome.kind === "behind"
4892
4931
  });
4893
4932
  } else {
4894
- console.log(import_chalk12.default.dim(`DID: ${sender.did}`));
4895
- console.log(import_chalk12.default.dim(`Server: ${api.serverUrl}`));
4933
+ console.log(import_chalk13.default.dim(`DID: ${sender.did}`));
4934
+ console.log(import_chalk13.default.dim(`Server: ${api.serverUrl}`));
4896
4935
  console.log("");
4897
- console.log(`${import_chalk12.default.bold("Local lastSenderSequence:")} ${local}`);
4898
- console.log(`${import_chalk12.default.bold("Server lastSenderSequence:")} ${server}`);
4936
+ console.log(`${import_chalk13.default.bold("Local lastSenderSequence:")} ${local}`);
4937
+ console.log(`${import_chalk13.default.bold("Server lastSenderSequence:")} ${server}`);
4899
4938
  console.log("");
4900
4939
  if (outcome.kind === "in-sync") {
4901
- console.log(import_chalk12.default.green("\u2713 In sync \u2014 no recovery needed."));
4940
+ console.log(import_chalk13.default.green("\u2713 In sync \u2014 no recovery needed."));
4902
4941
  } else if (outcome.kind === "behind") {
4903
- console.log(import_chalk12.default.yellow(`\u26A0 Local is BEHIND by ${outcome.drift}. Server has accepted envelopes the CLI didn't classify as post-commit.`));
4942
+ console.log(import_chalk13.default.yellow(`\u26A0 Local is BEHIND by ${outcome.drift}. Server has accepted envelopes the CLI didn't classify as post-commit.`));
4904
4943
  if (opts.apply) {
4905
- console.log(import_chalk12.default.dim("Writing server value to local state..."));
4944
+ console.log(import_chalk13.default.dim("Writing server value to local state..."));
4906
4945
  } else {
4907
- console.log(import_chalk12.default.dim("Dry-run. Pass --apply to update local state to match server."));
4946
+ console.log(import_chalk13.default.dim("Dry-run. Pass --apply to update local state to match server."));
4908
4947
  }
4909
4948
  } else {
4910
- console.log(import_chalk12.default.red(`\u2717 Local is AHEAD of server by ${outcome.drift}. This should not happen under normal protocol flow.`));
4911
- console.log(import_chalk12.default.dim("NOT applying \u2014 manual investigation needed. Possible causes:"));
4912
- console.log(import_chalk12.default.dim(" - Local agents.json edited by hand to a wrong value"));
4913
- console.log(import_chalk12.default.dim(" - Server data lost / rolled back"));
4914
- console.log(import_chalk12.default.dim(" - HEYARP_HOME pointed at a wrong account"));
4949
+ console.log(import_chalk13.default.red(`\u2717 Local is AHEAD of server by ${outcome.drift}. This should not happen under normal protocol flow.`));
4950
+ console.log(import_chalk13.default.dim("NOT applying \u2014 manual investigation needed. Possible causes:"));
4951
+ console.log(import_chalk13.default.dim(" - Local agents.json edited by hand to a wrong value"));
4952
+ console.log(import_chalk13.default.dim(" - Server data lost / rolled back"));
4953
+ console.log(import_chalk13.default.dim(" - HEYARP_HOME pointed at a wrong account"));
4915
4954
  }
4916
4955
  }
4917
4956
  if (outcome.kind === "behind" && opts.apply) {
4918
4957
  updateAgentLocal(opts.server, sender.did, { lastSenderSequence: outcome.server });
4919
- if (!opts.json) console.log(import_chalk12.default.green(`\u2713 Local lastSenderSequence updated: ${local} \u2192 ${outcome.server}`));
4958
+ if (!opts.json) console.log(import_chalk13.default.green(`\u2713 Local lastSenderSequence updated: ${local} \u2192 ${outcome.server}`));
4920
4959
  }
4921
4960
  if (outcome.kind === "behind" && !opts.apply) process.exitCode = 1;
4922
4961
  if (outcome.kind === "ahead") process.exitCode = 2;
4923
4962
  }
4924
4963
 
4925
4964
  // src/commands/events.ts
4926
- var import_chalk13 = __toESM(require("chalk"));
4965
+ var import_sdk18 = require("@heyanon-arp/sdk");
4966
+ var import_chalk14 = __toESM(require("chalk"));
4927
4967
  init_api();
4928
4968
  function registerEventsCommand(root) {
4929
4969
  root.command("events").description("List events for a relationship (chain order, ascending index)").argument("<relationship-id>", "Relationship UUID").option("--server <url>", "Override ARP server base URL").option("--since <n>", "Cursor: only events with relationshipEventIndex >= since").option("--limit <n>", "Max events to return (1..100)", "20").option("--from-did <did>", "Signer DID \u2014 required only if multiple agents are registered against this server").option(
@@ -4967,14 +5007,14 @@ async function runEvents(relationshipId, opts) {
4967
5007
  const api = new ArpApiClient(opts.server);
4968
5008
  const sender = resolveSenderAgent("events", opts.server, opts.fromDid);
4969
5009
  if (!opts.json) {
4970
- console.log(import_chalk13.default.dim(`Server: ${api.serverUrl}`));
4971
- console.log(import_chalk13.default.dim(`Signer: ${sender.did}`));
4972
- console.log(import_chalk13.default.dim(`Relationship: ${relationshipId}`));
5010
+ console.log(import_chalk14.default.dim(`Server: ${api.serverUrl}`));
5011
+ console.log(import_chalk14.default.dim(`Signer: ${sender.did}`));
5012
+ console.log(import_chalk14.default.dim(`Relationship: ${relationshipId}`));
4973
5013
  }
4974
5014
  const query = { limit };
4975
5015
  if (since !== void 0) query.since = since;
4976
- if (opts.successOnly) query.readModelStatus = "materialized";
4977
- else if (opts.rejectedOnly) query.readModelStatus = "rejected";
5016
+ if (opts.successOnly) query.readModelStatus = import_sdk18.ReadModelStatuses.MATERIALIZED;
5017
+ else if (opts.rejectedOnly) query.readModelStatus = import_sdk18.ReadModelStatuses.REJECTED;
4978
5018
  const signer = makeSigner(sender);
4979
5019
  const events = await api.listEvents(relationshipId, signer, query);
4980
5020
  if (opts.json) {
@@ -4982,7 +5022,7 @@ async function runEvents(relationshipId, opts) {
4982
5022
  return;
4983
5023
  }
4984
5024
  if (events.length === 0) {
4985
- console.log(import_chalk13.default.dim("\n(no events for this relationship)"));
5025
+ console.log(import_chalk14.default.dim("\n(no events for this relationship)"));
4986
5026
  return;
4987
5027
  }
4988
5028
  console.log("");
@@ -4998,20 +5038,20 @@ async function runEvents(relationshipId, opts) {
4998
5038
  }));
4999
5039
  }
5000
5040
  const lastIndex = events[events.length - 1].relationshipEventIndex;
5001
- console.log(import_chalk13.default.dim(`
5041
+ console.log(import_chalk14.default.dim(`
5002
5042
  ${events.length} event(s). Paginate with --since ${lastIndex + 1}.`));
5003
5043
  }
5004
5044
  function formatEventLine(ev, selfDid, opts = {}) {
5005
- const idx = import_chalk13.default.bold(`#${ev.relationshipEventIndex}`);
5045
+ const idx = import_chalk14.default.bold(`#${ev.relationshipEventIndex}`);
5006
5046
  const eventId = opts.fullIds ? ev.eventId : eventIdHead(ev.eventId);
5007
5047
  const type = ev.type.padEnd(20);
5008
5048
  const direction = directionLabel(ev, selfDid, opts);
5009
5049
  const hash = opts.fullIds ? ev.serverEventHash : hashHead(ev.serverEventHash);
5010
5050
  const extra = extraDetail(ev);
5011
- const tail = extra ? ` ${import_chalk13.default.dim(`(${extra})`)}` : "";
5012
- const status = ev.readModelStatus ?? "materialized";
5013
- const statusGlyph = status === "rejected" ? `${import_chalk13.default.red("\u2717")} ` : " ";
5014
- return `${statusGlyph}${idx} ${import_chalk13.default.cyan(eventId)} ${type} ${direction} ${import_chalk13.default.cyan(hash)}${tail}`;
5051
+ const tail = extra ? ` ${import_chalk14.default.dim(`(${extra})`)}` : "";
5052
+ const status = ev.readModelStatus ?? import_sdk18.ReadModelStatuses.MATERIALIZED;
5053
+ const statusGlyph = status === import_sdk18.ReadModelStatuses.REJECTED ? `${import_chalk14.default.red("\u2717")} ` : " ";
5054
+ return `${statusGlyph}${idx} ${import_chalk14.default.cyan(eventId)} ${type} ${direction} ${import_chalk14.default.cyan(hash)}${tail}`;
5015
5055
  }
5016
5056
  function eventIdHead(eventId) {
5017
5057
  if (eventId.length <= 20) return eventId;
@@ -5020,9 +5060,9 @@ function eventIdHead(eventId) {
5020
5060
  function directionLabel(ev, selfDid, opts = {}) {
5021
5061
  const senderHead = opts.fullIds ? ev.senderDid : didHead2(ev.senderDid);
5022
5062
  const recipientHead = opts.fullIds ? ev.recipientDid : didHead2(ev.recipientDid);
5023
- if (ev.senderDid === selfDid) return `${import_chalk13.default.bold("me")} \u2192 ${import_chalk13.default.dim(recipientHead)}`;
5024
- if (ev.recipientDid === selfDid) return `${import_chalk13.default.dim(senderHead)} \u2192 ${import_chalk13.default.bold("me")}`;
5025
- return `${import_chalk13.default.dim(senderHead)} \u2192 ${import_chalk13.default.dim(recipientHead)}`;
5063
+ if (ev.senderDid === selfDid) return `${import_chalk14.default.bold("me")} \u2192 ${import_chalk14.default.dim(recipientHead)}`;
5064
+ if (ev.recipientDid === selfDid) return `${import_chalk14.default.dim(senderHead)} \u2192 ${import_chalk14.default.bold("me")}`;
5065
+ return `${import_chalk14.default.dim(senderHead)} \u2192 ${import_chalk14.default.dim(recipientHead)}`;
5026
5066
  }
5027
5067
  function extraDetail(ev) {
5028
5068
  if (ev.type === "handshake_response") {
@@ -5059,7 +5099,7 @@ function parseSince(raw) {
5059
5099
  }
5060
5100
 
5061
5101
  // src/commands/guide.ts
5062
- var import_chalk14 = __toESM(require("chalk"));
5102
+ var import_chalk15 = __toESM(require("chalk"));
5063
5103
 
5064
5104
  // src/guide/source.ts
5065
5105
  var GUIDE_TITLE = "HeyARP CLI \u2014 agent guide";
@@ -5593,7 +5633,7 @@ var GUIDE_SECTIONS = [
5593
5633
  " 1. heyarp login link this CLI to your Solana wallet \u2014 hand the",
5594
5634
  " printed URL to your HUMAN operator (browser",
5595
5635
  " approval; registration REQUIRES it)",
5596
- " 2. heyarp register create your DID + Ed25519 keys",
5636
+ " 2. heyarp register --name <handle> create your DID + Ed25519 keys (handle: unique, lowercase a-z0-9_ 3-32, immutable \u2014 others can address you by it instead of your DID, e.g. `send-handshake <handle>`; `heyarp whois <handle>` resolves it)",
5597
5637
  " 3. heyarp whoami confirm your DID + login account are set",
5598
5638
  " 4. role for THIS deal: you SEND the offer \u2192 buyer; an offer ARRIVES \u2192 worker",
5599
5639
  " 5. BUYER only \u2014 fund your settlement wallet: `whoami --local` \u2192",
@@ -5700,7 +5740,7 @@ function renderCommand(c) {
5700
5740
  ${c.description}`;
5701
5741
  }
5702
5742
  function renderSection(s) {
5703
- const lines = [import_chalk14.default.bold(s.title)];
5743
+ const lines = [import_chalk15.default.bold(s.title)];
5704
5744
  if (s.body && s.body.length > 0) lines.push(...s.body);
5705
5745
  if (s.nextActions && s.nextActions.length > 0) {
5706
5746
  lines.push(" Commands:");
@@ -5727,21 +5767,21 @@ function modeHeader(mode) {
5727
5767
  ""
5728
5768
  ];
5729
5769
  case "role":
5730
- return [import_chalk14.default.dim(`(${mode.role} guide \u2014 your slice only; run \`heyarp guide\` for the overview)`), ""];
5770
+ return [import_chalk15.default.dim(`(${mode.role} guide \u2014 your slice only; run \`heyarp guide\` for the overview)`), ""];
5731
5771
  case "setup":
5732
- return [import_chalk14.default.dim("(setup \u2014 role-agnostic; run `heyarp guide` for the overview)"), ""];
5772
+ return [import_chalk15.default.dim("(setup \u2014 role-agnostic; run `heyarp guide` for the overview)"), ""];
5733
5773
  case "troubleshoot":
5734
- return [import_chalk14.default.dim("(troubleshooting \u2014 role-agnostic)"), ""];
5774
+ return [import_chalk15.default.dim("(troubleshooting \u2014 role-agnostic)"), ""];
5735
5775
  }
5736
5776
  }
5737
5777
  function modeFooter(mode) {
5738
5778
  if (mode.kind === "overview") {
5739
- return ["", import_chalk14.default.dim("Full reference per role: `heyarp guide --role worker|buyer`. Docs: https://www.npmjs.com/package/@heyanon-arp/cli")];
5779
+ return ["", import_chalk15.default.dim("Full reference per role: `heyarp guide --role worker|buyer`. Docs: https://www.npmjs.com/package/@heyanon-arp/cli")];
5740
5780
  }
5741
5781
  return [];
5742
5782
  }
5743
5783
  function renderGuide(mode = { kind: "overview" }) {
5744
- const blocks = [import_chalk14.default.bold(GUIDE_TITLE), "", ...modeHeader(mode)];
5784
+ const blocks = [import_chalk15.default.bold(GUIDE_TITLE), "", ...modeHeader(mode)];
5745
5785
  for (const s of selectSections(mode)) {
5746
5786
  blocks.push(renderSection(s), "");
5747
5787
  }
@@ -5791,7 +5831,7 @@ function renderPrompt(mode, opts = { concise: false }) {
5791
5831
  // src/commands/homes.ts
5792
5832
  var import_node_fs6 = require("fs");
5793
5833
  var import_node_path6 = require("path");
5794
- var import_chalk15 = __toESM(require("chalk"));
5834
+ var import_chalk16 = __toESM(require("chalk"));
5795
5835
  var import_prompts = __toESM(require("prompts"));
5796
5836
 
5797
5837
  // src/homes.ts
@@ -5885,27 +5925,27 @@ function runHomes(opts) {
5885
5925
  return;
5886
5926
  }
5887
5927
  if (rows.length === 0) {
5888
- console.log(import_chalk15.default.dim("(no HEYARP_HOME directories registered yet \u2014 run `heyarp register` once and the registry populates itself)"));
5889
- console.log(import_chalk15.default.dim(` registry path: ${homesRegistryPath()}`));
5928
+ console.log(import_chalk16.default.dim("(no HEYARP_HOME directories registered yet \u2014 run `heyarp register` once and the registry populates itself)"));
5929
+ console.log(import_chalk16.default.dim(` registry path: ${homesRegistryPath()}`));
5890
5930
  return;
5891
5931
  }
5892
5932
  const header = ["Path", "Agents", "Last seen", "Status"];
5893
5933
  const data = rows.map((r) => [
5894
- r.path + (r.isCurrent ? import_chalk15.default.green(" (current)") : ""),
5934
+ r.path + (r.isCurrent ? import_chalk16.default.green(" (current)") : ""),
5895
5935
  String(r.agentCount),
5896
5936
  formatRelativeTime(r.lastSeenAt),
5897
- r.exists ? import_chalk15.default.green("ok") : import_chalk15.default.red("missing")
5937
+ r.exists ? import_chalk16.default.green("ok") : import_chalk16.default.red("missing")
5898
5938
  ]);
5899
5939
  console.log("");
5900
5940
  console.log(formatTable(header, data));
5901
- console.log(import_chalk15.default.dim(`
5941
+ console.log(import_chalk16.default.dim(`
5902
5942
  Registry path: ${homesRegistryPath()}`));
5903
- console.log(import_chalk15.default.dim(`Set HEYARP_HOME=<path> in a shell to switch between homes; run \`heyarp homes forget <path>\` to drop a stale entry.`));
5943
+ console.log(import_chalk16.default.dim(`Set HEYARP_HOME=<path> in a shell to switch between homes; run \`heyarp homes forget <path>\` to drop a stale entry.`));
5904
5944
  }
5905
5945
  async function runForget(path, opts) {
5906
5946
  if (!opts.yes) {
5907
- console.log(import_chalk15.default.yellow(`About to remove '${path}' from the homes registry.`));
5908
- console.log(import_chalk15.default.dim(" Note: this only forgets the registry entry; the directory + its agents.json are NOT touched."));
5947
+ console.log(import_chalk16.default.yellow(`About to remove '${path}' from the homes registry.`));
5948
+ console.log(import_chalk16.default.dim(" Note: this only forgets the registry entry; the directory + its agents.json are NOT touched."));
5909
5949
  const answer = await (0, import_prompts.default)(
5910
5950
  {
5911
5951
  type: "confirm",
@@ -5915,21 +5955,21 @@ async function runForget(path, opts) {
5915
5955
  },
5916
5956
  {
5917
5957
  onCancel: () => {
5918
- console.log(import_chalk15.default.yellow("Aborted."));
5958
+ console.log(import_chalk16.default.yellow("Aborted."));
5919
5959
  process.exit(130);
5920
5960
  }
5921
5961
  }
5922
5962
  );
5923
5963
  if (!answer.confirm) {
5924
- console.log(import_chalk15.default.dim("Aborted (no changes)."));
5964
+ console.log(import_chalk16.default.dim("Aborted (no changes)."));
5925
5965
  return;
5926
5966
  }
5927
5967
  }
5928
5968
  const removed = forgetHome(path);
5929
5969
  if (removed) {
5930
- console.log(import_chalk15.default.green(`\u2713 forgot ${path}`));
5970
+ console.log(import_chalk16.default.green(`\u2713 forgot ${path}`));
5931
5971
  } else {
5932
- console.log(import_chalk15.default.dim(`(no entry for ${path} in the registry \u2014 already absent)`));
5972
+ console.log(import_chalk16.default.dim(`(no entry for ${path} in the registry \u2014 already absent)`));
5933
5973
  }
5934
5974
  }
5935
5975
  function countAgents(homePath) {
@@ -5954,13 +5994,13 @@ function formatTable(header, data) {
5954
5994
  const padding = " ".repeat(Math.max(0, widths[i] - lengths[i]));
5955
5995
  return cell + padding;
5956
5996
  }).join(" ");
5957
- const headerLine = import_chalk15.default.bold(
5997
+ const headerLine = import_chalk16.default.bold(
5958
5998
  pad(
5959
5999
  header,
5960
6000
  header.map((s) => s.length)
5961
6001
  )
5962
6002
  );
5963
- const sepLine = import_chalk15.default.dim(
6003
+ const sepLine = import_chalk16.default.dim(
5964
6004
  pad(
5965
6005
  widths.map((w) => "-".repeat(w)),
5966
6006
  widths
@@ -5987,7 +6027,7 @@ function formatRelativeTime(iso) {
5987
6027
  }
5988
6028
 
5989
6029
  // src/commands/inbox.ts
5990
- var import_chalk16 = __toESM(require("chalk"));
6030
+ var import_chalk17 = __toESM(require("chalk"));
5991
6031
  init_api();
5992
6032
  function formatTailStartedPing(input) {
5993
6033
  const ping = {
@@ -6034,8 +6074,8 @@ async function runInbox(positionalDid, opts) {
6034
6074
  }
6035
6075
  const api = new ArpApiClient(opts.server);
6036
6076
  if (!opts.json) {
6037
- console.log(import_chalk16.default.dim(`Server: ${api.serverUrl}`));
6038
- console.log(import_chalk16.default.dim(`Signer: ${local.did}`));
6077
+ console.log(import_chalk17.default.dim(`Server: ${api.serverUrl}`));
6078
+ console.log(import_chalk17.default.dim(`Signer: ${local.did}`));
6039
6079
  }
6040
6080
  const query = { limit };
6041
6081
  if (opts.before) query.before = opts.before;
@@ -6049,7 +6089,7 @@ async function runInbox(positionalDid, opts) {
6049
6089
  return;
6050
6090
  }
6051
6091
  if (events.length === 0) {
6052
- console.log(import_chalk16.default.dim("\n(no events addressed to me \u2014 `heyarp events <relationship-id>` shows the chain-wide listing)"));
6092
+ console.log(import_chalk17.default.dim("\n(no events addressed to me \u2014 `heyarp events <relationship-id>` shows the chain-wide listing)"));
6053
6093
  return;
6054
6094
  }
6055
6095
  console.log("");
@@ -6064,16 +6104,16 @@ async function runInbox(positionalDid, opts) {
6064
6104
  secondary: `eventId=${ev.eventId} serverEventHash=${ev.serverEventHash}`
6065
6105
  }));
6066
6106
  }
6067
- const addressedToMeHint = import_chalk16.default.dim(" (envelopes addressed to me \u2014 for the full chain see `heyarp events <relationship-id>`)");
6107
+ const addressedToMeHint = import_chalk17.default.dim(" (envelopes addressed to me \u2014 for the full chain see `heyarp events <relationship-id>`)");
6068
6108
  if (opts.since && !opts.before) {
6069
6109
  console.log(
6070
- import_chalk16.default.dim(
6110
+ import_chalk17.default.dim(
6071
6111
  `
6072
6112
  ${events.length} event(s) (oldest-first).${addressedToMeHint} Advance the forward cursor with --since <serverTimestamp> --since-event-id <eventId> using the LAST row above.`
6073
6113
  )
6074
6114
  );
6075
6115
  } else {
6076
- console.log(import_chalk16.default.dim(`
6116
+ console.log(import_chalk17.default.dim(`
6077
6117
  ${events.length} event(s).${addressedToMeHint} Paginate with --before <serverTimestamp> --before-event-id <eventId> using the LAST row above.`));
6078
6118
  }
6079
6119
  }
@@ -6088,7 +6128,7 @@ async function runInboxTail(did, local, opts) {
6088
6128
  } else {
6089
6129
  warn(
6090
6130
  opts.json,
6091
- import_chalk16.default.yellow(
6131
+ import_chalk17.default.yellow(
6092
6132
  "\u26A0 inbox --tail: stdout is piped but `process.stdout._handle.setBlocking` is unavailable in this Node runtime. Buffered writes may delay event delivery. Fall back to polling (`heyarp inbox --json`) if events stop arriving."
6093
6133
  )
6094
6134
  );
@@ -6098,9 +6138,9 @@ async function runInboxTail(did, local, opts) {
6098
6138
  if (opts.json) {
6099
6139
  console.log(formatTailStartedPing({ server: api.serverUrl, signer: local.did, stdoutBlockingApplied }));
6100
6140
  } else {
6101
- console.log(import_chalk16.default.dim(`Server: ${api.serverUrl}`));
6102
- console.log(import_chalk16.default.dim(`Signer: ${local.did}`));
6103
- console.log(import_chalk16.default.dim("Mode: --tail (live SSE, Ctrl-C to stop)"));
6141
+ console.log(import_chalk17.default.dim(`Server: ${api.serverUrl}`));
6142
+ console.log(import_chalk17.default.dim(`Signer: ${local.did}`));
6143
+ console.log(import_chalk17.default.dim("Mode: --tail (live SSE, Ctrl-C to stop)"));
6104
6144
  }
6105
6145
  const controller = new AbortController();
6106
6146
  let userAborted = false;
@@ -6119,7 +6159,7 @@ async function runInboxTail(did, local, opts) {
6119
6159
  }
6120
6160
  if (event.type === "heartbeat") continue;
6121
6161
  if (event.type === "connected") {
6122
- console.log(import_chalk16.default.green("\u25CF stream open \u2014 listening for envelopes..."));
6162
+ console.log(import_chalk17.default.green("\u25CF stream open \u2014 listening for envelopes..."));
6123
6163
  continue;
6124
6164
  }
6125
6165
  if (event.type === "envelope") {
@@ -6133,7 +6173,7 @@ async function runInboxTail(did, local, opts) {
6133
6173
  }
6134
6174
  continue;
6135
6175
  }
6136
- console.log(import_chalk16.default.dim(`(unknown event: ${event.type})`));
6176
+ console.log(import_chalk17.default.dim(`(unknown event: ${event.type})`));
6137
6177
  }
6138
6178
  if (!userAborted) {
6139
6179
  throw new Error("inbox --tail: stream ended unexpectedly (server may have restarted, or change stream errored). Re-run to reconnect.");
@@ -6141,7 +6181,7 @@ async function runInboxTail(did, local, opts) {
6141
6181
  } catch (err) {
6142
6182
  const name = err.name;
6143
6183
  if (name === "AbortError" || userAborted) {
6144
- if (!opts.json) console.log(import_chalk16.default.dim("\nstream closed."));
6184
+ if (!opts.json) console.log(import_chalk17.default.dim("\nstream closed."));
6145
6185
  return;
6146
6186
  }
6147
6187
  throw err;
@@ -6161,15 +6201,15 @@ function formatInboxTable(events, opts = {}) {
6161
6201
  ]);
6162
6202
  const widths = header.map((h, i) => Math.max(h.length, ...data.map((row) => row[i].length)));
6163
6203
  const pad = (cells) => cells.map((c, i) => c.padEnd(widths[i])).join(" ");
6164
- const lines = [import_chalk16.default.bold(pad(header)), import_chalk16.default.dim(pad(widths.map((w) => "-".repeat(w)))), ...data.map((row) => pad(row))];
6165
- const detail = events.map((ev) => ` ${import_chalk16.default.dim("eventId:")} ${import_chalk16.default.cyan(ev.eventId)} ${import_chalk16.default.dim("serverTimestamp:")} ${import_chalk16.default.cyan(ev.serverTimestamp)}`).join("\n");
6204
+ const lines = [import_chalk17.default.bold(pad(header)), import_chalk17.default.dim(pad(widths.map((w) => "-".repeat(w)))), ...data.map((row) => pad(row))];
6205
+ const detail = events.map((ev) => ` ${import_chalk17.default.dim("eventId:")} ${import_chalk17.default.cyan(ev.eventId)} ${import_chalk17.default.dim("serverTimestamp:")} ${import_chalk17.default.cyan(ev.serverTimestamp)}`).join("\n");
6166
6206
  return `${lines.join("\n")}
6167
6207
 
6168
- ${import_chalk16.default.bold("Pagination cursors")} (last \u2192 first):
6208
+ ${import_chalk17.default.bold("Pagination cursors")} (last \u2192 first):
6169
6209
  ${detail}`;
6170
6210
  }
6171
6211
  function hashHead2(hash) {
6172
- if (!hash) return import_chalk16.default.dim("(none)");
6212
+ if (!hash) return import_chalk17.default.dim("(none)");
6173
6213
  if (hash.length <= 14) return hash;
6174
6214
  return `${hash.slice(0, 14)}...`;
6175
6215
  }
@@ -6185,8 +6225,8 @@ function parseLimit4(raw) {
6185
6225
  // src/commands/keys.ts
6186
6226
  var import_node_crypto2 = require("crypto");
6187
6227
  var import_node_fs7 = require("fs");
6188
- var import_sdk12 = require("@heyanon-arp/sdk");
6189
- var import_chalk17 = __toESM(require("chalk"));
6228
+ var import_sdk19 = require("@heyanon-arp/sdk");
6229
+ var import_chalk18 = __toESM(require("chalk"));
6190
6230
  function writeSecretFile(path, body) {
6191
6231
  const tmp = `${path}.tmp.${(0, import_node_crypto2.randomBytes)(8).toString("hex")}`;
6192
6232
  const fd = (0, import_node_fs7.openSync)(tmp, "wx", 384);
@@ -6213,19 +6253,19 @@ function writeSecretFile(path, body) {
6213
6253
  function registerKeysCommand(root) {
6214
6254
  const keys = root.command("keys").description("Local key utilities");
6215
6255
  keys.command("gen").description("Generate a fresh identity + settlement keypair (no save by default)").action(() => {
6216
- const identity = (0, import_sdk12.generateKeyPair)();
6217
- const settlement = (0, import_sdk12.generateKeyPair)();
6256
+ const identity = (0, import_sdk19.generateKeyPair)();
6257
+ const settlement = (0, import_sdk19.generateKeyPair)();
6218
6258
  const out = [
6219
- import_chalk17.default.bold("Identity key (Ed25519)"),
6220
- ` public (base58btc): ${import_chalk17.default.cyan((0, import_sdk12.base58btcEncode)(identity.publicKey))}`,
6221
- ` secret (base64) : ${import_chalk17.default.yellow(Buffer.from(identity.secretKey).toString("base64"))}`,
6259
+ import_chalk18.default.bold("Identity key (Ed25519)"),
6260
+ ` public (base58btc): ${import_chalk18.default.cyan((0, import_sdk19.base58btcEncode)(identity.publicKey))}`,
6261
+ ` secret (base64) : ${import_chalk18.default.yellow(Buffer.from(identity.secretKey).toString("base64"))}`,
6222
6262
  "",
6223
- import_chalk17.default.bold("Settlement key (Ed25519)"),
6224
- ` public (base58btc): ${import_chalk17.default.cyan((0, import_sdk12.base58btcEncode)(settlement.publicKey))}`,
6225
- ` secret (base64) : ${import_chalk17.default.yellow(Buffer.from(settlement.secretKey).toString("base64"))}`,
6263
+ import_chalk18.default.bold("Settlement key (Ed25519)"),
6264
+ ` public (base58btc): ${import_chalk18.default.cyan((0, import_sdk19.base58btcEncode)(settlement.publicKey))}`,
6265
+ ` secret (base64) : ${import_chalk18.default.yellow(Buffer.from(settlement.secretKey).toString("base64"))}`,
6226
6266
  "",
6227
- import_chalk17.default.bold("Resulting DID"),
6228
- ` ${import_chalk17.default.cyan((0, import_sdk12.formatDid)(identity.publicKey))}`
6267
+ import_chalk18.default.bold("Resulting DID"),
6268
+ ` ${import_chalk18.default.cyan((0, import_sdk19.formatDid)(identity.publicKey))}`
6229
6269
  ];
6230
6270
  console.log(out.join("\n"));
6231
6271
  });
@@ -6234,20 +6274,20 @@ function registerKeysCommand(root) {
6234
6274
  const json = JSON.stringify(toKeyBundle(agent, (/* @__PURE__ */ new Date()).toISOString()), null, 2);
6235
6275
  if (opts.out) {
6236
6276
  writeSecretFile(opts.out, json);
6237
- process.stderr.write(import_chalk17.default.yellow(`\u26A0 wrote SECRET key bundle to ${opts.out} (mode 0600) \u2014 keep it offline; anyone with this file can operate ${did}.
6277
+ process.stderr.write(import_chalk18.default.yellow(`\u26A0 wrote SECRET key bundle to ${opts.out} (mode 0600) \u2014 keep it offline; anyone with this file can operate ${did}.
6238
6278
  `));
6239
6279
  console.log(opts.out);
6240
6280
  } else {
6241
- process.stderr.write(import_chalk17.default.yellow("\u26A0 this is a SECRET key bundle \u2014 redirect to a file and keep it offline.\n"));
6281
+ process.stderr.write(import_chalk18.default.yellow("\u26A0 this is a SECRET key bundle \u2014 redirect to a file and keep it offline.\n"));
6242
6282
  console.log(json);
6243
6283
  }
6244
6284
  });
6245
6285
  keys.command("whoami").description("Print the DID derived from a base64-encoded identity secret key").argument("<secret-key-b64>", "32-byte Ed25519 seed, base64").action((secretKeyB64) => {
6246
6286
  const seed = decodeSeed(secretKeyB64);
6247
- const pub = (0, import_sdk12.getPublicKey)(seed);
6248
- const did = (0, import_sdk12.formatDid)(pub);
6249
- console.log(`${import_chalk17.default.bold("DID")}: ${import_chalk17.default.cyan(did)}`);
6250
- console.log(`${import_chalk17.default.bold("Identity public key (base58btc)")}: ${import_chalk17.default.cyan((0, import_sdk12.base58btcEncode)(pub))}`);
6287
+ const pub = (0, import_sdk19.getPublicKey)(seed);
6288
+ const did = (0, import_sdk19.formatDid)(pub);
6289
+ console.log(`${import_chalk18.default.bold("DID")}: ${import_chalk18.default.cyan(did)}`);
6290
+ console.log(`${import_chalk18.default.bold("Identity public key (base58btc)")}: ${import_chalk18.default.cyan((0, import_sdk19.base58btcEncode)(pub))}`);
6251
6291
  });
6252
6292
  }
6253
6293
  function decodeSeed(b64) {
@@ -6264,12 +6304,16 @@ function decodeSeed(b64) {
6264
6304
  }
6265
6305
 
6266
6306
  // src/commands/list.ts
6267
- var import_chalk18 = __toESM(require("chalk"));
6307
+ var import_chalk19 = __toESM(require("chalk"));
6268
6308
  function registerListCommand(root) {
6269
- root.command("list").description("List agents registered locally (~/.heyarp/agents.json)").action(() => {
6309
+ root.command("list").description("List agents registered locally (~/.heyarp/agents.json)").option("--json", "Machine-readable mode \u2014 emit the local agents as a single JSON array on stdout ({serverUrl, did, name, tags, registeredAt}[]).", false).action((opts) => {
6270
6310
  const rows = listAgents();
6311
+ if (opts.json) {
6312
+ jsonOut(rows.map(({ serverUrl, agent }) => ({ serverUrl, did: agent.did, name: agent.name ?? null, tags: agent.tags ?? [], registeredAt: agent.registeredAt })));
6313
+ return;
6314
+ }
6271
6315
  if (rows.length === 0) {
6272
- console.log(import_chalk18.default.dim(`No local agents. State file: ${stateFilePath()}`));
6316
+ console.log(import_chalk19.default.dim(`No local agents. State file: ${stateFilePath()}`));
6273
6317
  return;
6274
6318
  }
6275
6319
  const grouped = /* @__PURE__ */ new Map();
@@ -6281,7 +6325,7 @@ function registerListCommand(root) {
6281
6325
  for (const [serverUrl, group] of grouped) {
6282
6326
  if (!first) console.log("");
6283
6327
  first = false;
6284
- console.log(import_chalk18.default.bold(`Server: ${serverUrl}`));
6328
+ console.log(import_chalk19.default.bold(`Server: ${serverUrl}`));
6285
6329
  console.log(formatAgentsTable(group.map(({ agent }) => ({ did: agent.did, name: agent.name, tags: agent.tags, registeredAt: agent.registeredAt }))));
6286
6330
  }
6287
6331
  });
@@ -6289,7 +6333,7 @@ function registerListCommand(root) {
6289
6333
 
6290
6334
  // src/commands/login.ts
6291
6335
  var import_node_crypto3 = require("crypto");
6292
- var import_chalk19 = __toESM(require("chalk"));
6336
+ var import_chalk20 = __toESM(require("chalk"));
6293
6337
  init_api();
6294
6338
  var POLL_INTERVAL_MS = 2e3;
6295
6339
  var POLL_TIMEOUT_MS = 11 * 6e4;
@@ -6359,9 +6403,9 @@ function registerLoginCommand(root) {
6359
6403
  jsonOut({ serverUrl: result.serverUrl, wallet: result.wallet, credentialsPath: credentialsFilePath() });
6360
6404
  } else {
6361
6405
  console.log("");
6362
- console.log(`${import_chalk19.default.green("Logged in as")} ${import_chalk19.default.cyan(result.wallet)}`);
6363
- console.log(import_chalk19.default.dim(`If that is not the wallet you approved with, run heyarp logout immediately.`));
6364
- console.log(import_chalk19.default.dim(`Credential saved to ${credentialsFilePath()} (mode 0600).`));
6406
+ console.log(`${import_chalk20.default.green("Logged in as")} ${import_chalk20.default.cyan(result.wallet)}`);
6407
+ console.log(import_chalk20.default.dim(`If that is not the wallet you approved with, run heyarp logout immediately.`));
6408
+ console.log(import_chalk20.default.dim(`Credential saved to ${credentialsFilePath()} (mode 0600).`));
6365
6409
  }
6366
6410
  } catch (err) {
6367
6411
  emitActionError(err, cmd);
@@ -6371,7 +6415,7 @@ function registerLoginCommand(root) {
6371
6415
  }
6372
6416
 
6373
6417
  // src/commands/logout.ts
6374
- var import_chalk20 = __toESM(require("chalk"));
6418
+ var import_chalk21 = __toESM(require("chalk"));
6375
6419
  init_api();
6376
6420
  function registerLogoutCommand(root) {
6377
6421
  root.command("logout").description("Log out of the ARP server: revoke the stored CLI auth token (best-effort) and delete the local credential for this server.").option("--server <url>", "Override ARP server base URL").option("--json", "machine-readable output ({ serverUrl, loggedOut, wallet? })", false).action(async (opts, cmd) => {
@@ -6396,7 +6440,7 @@ function registerLogoutCommand(root) {
6396
6440
  if (opts.json) {
6397
6441
  jsonOut({ serverUrl: api.serverUrl, loggedOut: true, wallet: credential.wallet });
6398
6442
  } else {
6399
- console.log(`${import_chalk20.default.green("Logged out of")} ${api.serverUrl} ${import_chalk20.default.dim(`(was ${credential.wallet})`)}`);
6443
+ console.log(`${import_chalk21.default.green("Logged out of")} ${api.serverUrl} ${import_chalk21.default.dim(`(was ${credential.wallet})`)}`);
6400
6444
  }
6401
6445
  } catch (err) {
6402
6446
  emitActionError(err, cmd);
@@ -6405,13 +6449,65 @@ function registerLogoutCommand(root) {
6405
6449
  });
6406
6450
  }
6407
6451
 
6452
+ // src/commands/name.ts
6453
+ var import_sdk20 = require("@heyanon-arp/sdk");
6454
+ var import_chalk22 = __toESM(require("chalk"));
6455
+ init_api();
6456
+ function registerNameCommand(root) {
6457
+ const name = root.command("name").description("Agent name (handle) utilities.");
6458
+ name.command("check").description("Check whether an agent name (handle) can be registered \u2014 reports invalid / reserved / taken / available without registering.").argument("<name>", "Candidate handle (lowercase a-z0-9_, 3-32 chars)").option("--server <url>", "Override ARP server base URL").option("--json", "Emit {name, available, reason, did?} as a single JSON object on stdout.", false).action(async (input, opts) => {
6459
+ const result = await runNameCheck(input, opts);
6460
+ if (opts.json) {
6461
+ jsonOut(result);
6462
+ } else {
6463
+ printNameCheck(input, result);
6464
+ }
6465
+ if (!result.available) process.exitCode = 1;
6466
+ });
6467
+ }
6468
+ async function runNameCheck(input, opts) {
6469
+ const name = (0, import_sdk20.normalizeName)(input);
6470
+ if (!(0, import_sdk20.isValidAgentName)(name)) {
6471
+ return { name, available: false, reason: "invalid" };
6472
+ }
6473
+ if ((0, import_sdk20.isReservedName)(name)) {
6474
+ return { name, available: false, reason: "reserved" };
6475
+ }
6476
+ const api = new ArpApiClient(opts.server);
6477
+ progress(opts.json, import_chalk22.default.dim(`Server: ${api.serverUrl}`));
6478
+ try {
6479
+ const profile = await api.discoverByName(name);
6480
+ return { name, available: false, reason: "taken", did: profile.did };
6481
+ } catch (err) {
6482
+ if (err instanceof ApiError && err.payload.code === "AGENT_NOT_FOUND") {
6483
+ return { name, available: true, reason: null };
6484
+ }
6485
+ throw err;
6486
+ }
6487
+ }
6488
+ function printNameCheck(input, r) {
6489
+ switch (r.reason) {
6490
+ case "invalid":
6491
+ console.log(`${import_chalk22.default.red("\u2717")} '${input}' is not a valid handle \u2014 must be lowercase a-z0-9_, 3-32 chars.`);
6492
+ break;
6493
+ case "reserved":
6494
+ console.log(`${import_chalk22.default.red("\u2717")} '${r.name}' is reserved and cannot be registered.`);
6495
+ break;
6496
+ case "taken":
6497
+ console.log(`${import_chalk22.default.yellow("\u2717")} '${r.name}' is taken \u2192 ${import_chalk22.default.cyan(r.did ?? "(unknown DID)")}`);
6498
+ break;
6499
+ default:
6500
+ console.log(`${import_chalk22.default.green("\u2713")} '${r.name}' is available.`);
6501
+ }
6502
+ }
6503
+
6408
6504
  // src/commands/profile.ts
6409
- var import_sdk13 = require("@heyanon-arp/sdk");
6410
- var import_chalk21 = __toESM(require("chalk"));
6505
+ var import_sdk21 = require("@heyanon-arp/sdk");
6506
+ var import_chalk23 = __toESM(require("chalk"));
6411
6507
  init_api();
6412
6508
  function registerProfileCommand(root) {
6413
6509
  root.command("profile").description("Composed agent profile: public fields + reputation + liveness, in one read.").argument("<did>", "did:arp:<base58btc> identifier").option("--server <url>", "Override ARP server base URL").option("--json", "Emit the profile as JSON on stdout.", false).action(async (did, opts) => {
6414
- if (!(0, import_sdk13.isValidDid)(did)) {
6510
+ if (!(0, import_sdk21.isValidDid)(did)) {
6415
6511
  throw new Error(`'${did}' is not a syntactically valid did:arp identifier`);
6416
6512
  }
6417
6513
  const api = new ArpApiClient(opts.server);
@@ -6422,62 +6518,33 @@ function registerProfileCommand(root) {
6422
6518
  }
6423
6519
  const j = false;
6424
6520
  const s = p.reputation.scores;
6425
- const live = p.liveness.online ? import_chalk21.default.green("\u25CF online") : import_chalk21.default.dim("\u25CB offline");
6521
+ const live = p.liveness.online ? import_chalk23.default.green("\u25CF online") : import_chalk23.default.dim("\u25CB offline");
6426
6522
  const tags = p.tags.map(sanitizeForTerminal).filter((t) => t.length > 0);
6427
- progress(j, import_chalk21.default.bold(`${p.name ? sanitizeForTerminal(p.name) : "(unnamed)"} ${import_chalk21.default.dim(p.did)}`));
6428
- if (p.description) progress(j, import_chalk21.default.dim(` ${sanitizeForTerminal(p.description)}`));
6429
- progress(j, ` ${live}${p.liveness.inboxStreamActive ? import_chalk21.default.green(" \xB7 stream attached") : ""} \xB7 last seen ${p.liveness.lastSeenAt ?? "\u2014"}`);
6430
- progress(j, ` tags: ${tags.length ? tags.join(", ") : import_chalk21.default.dim("none")}`);
6523
+ progress(j, import_chalk23.default.bold(`${p.name ? sanitizeForTerminal(p.name) : "(unnamed)"} ${import_chalk23.default.dim(p.did)}`));
6524
+ if (p.description) progress(j, import_chalk23.default.dim(` ${sanitizeForTerminal(p.description)}`));
6525
+ progress(j, ` ${live}${p.liveness.inboxStreamActive ? import_chalk23.default.green(" \xB7 stream attached") : ""} \xB7 last seen ${p.liveness.lastSeenAt ?? "\u2014"}`);
6526
+ progress(j, ` tags: ${tags.length ? tags.join(", ") : import_chalk23.default.dim("none")}`);
6431
6527
  progress(j, "");
6432
- progress(j, import_chalk21.default.bold(" Reputation") + import_chalk21.default.dim(" (informational)"));
6528
+ progress(j, import_chalk23.default.bold(" Reputation") + import_chalk23.default.dim(" (informational)"));
6433
6529
  progress(
6434
6530
  j,
6435
6531
  ` composite ${s.composite.toFixed(2)} \xB7 reliability ${s.reliability.toFixed(2)} \xB7 settlement ${s.settlement.toFixed(2)} \xB7 dispute-health ${s.disputeHealth.toFixed(2)}`
6436
6532
  );
6437
- progress(j, import_chalk21.default.dim(` ${p.reputation.computed ? `computed ${p.reputation.lastComputedAt}` : "never computed (neutral cold-start)"}`));
6533
+ progress(j, import_chalk23.default.dim(` ${p.reputation.computed ? `computed ${p.reputation.lastComputedAt}` : "never computed (neutral cold-start)"}`));
6438
6534
  });
6439
6535
  }
6440
6536
 
6441
6537
  // src/commands/receipt.ts
6442
- var import_sdk14 = require("@heyanon-arp/sdk");
6538
+ var import_sdk22 = require("@heyanon-arp/sdk");
6443
6539
  var import_shield2 = require("@heyanon-arp/shield");
6444
- var import_chalk22 = __toESM(require("chalk"));
6540
+ var import_chalk24 = __toESM(require("chalk"));
6445
6541
  init_api();
6446
6542
  function registerReceiptCommands(root) {
6447
6543
  const cmd = root.command("receipt").description("Receipt envelopes \u2014 the payee proposes a delivery record (payment consent is on-chain via claim_work_payment)");
6448
6544
  registerPropose(cmd);
6449
6545
  }
6450
- var POST_COMMIT_ERROR_CODES2 = /* @__PURE__ */ new Set([
6451
- "RECEIPT_ALREADY_EXISTS",
6452
- "RECEIPT_DELEGATION_NOT_FOUND",
6453
- "RECEIPT_DELEGATION_NOT_ACTIVE",
6454
- "RECEIPT_RELATIONSHIP_MISMATCH",
6455
- "RECEIPT_ISSUER_IS_CALLER",
6456
- "RECEIPT_NOT_FOUND",
6457
- "RECEIPT_INVALID_STATE",
6458
- // The receipt-propose handler's LOCKED gate emits
6459
- // `DELEGATION_PENDING_LOCK` (409) when the delegation is funded but
6460
- // the on-chain lock isn't confirmed yet (state
6461
- // `pending_lock_finalization`). It fires from the body handler AFTER
6462
- // the event row is committed — same lifecycle as
6463
- // `RECEIPT_DELEGATION_NOT_ACTIVE` — so the CLI must advance
6464
- // `lastSenderSequence`, otherwise a retry once the lock confirms
6465
- // reuses the consumed sequence and trips `ENV_SEQUENCE_BACKWARDS`.
6466
- "DELEGATION_PENDING_LOCK",
6467
- // response_hash / request_hash / deliverable_hash content
6468
- // verification. Server commits the receipt envelope row BEFORE
6469
- // running the canonical-hash lookup, so a rejection here still
6470
- // consumes the sender sequence — must be in the allowlist or
6471
- // a retry after fixing the hashes would trip
6472
- // `ENV_SEQUENCE_BACKWARDS`.
6473
- "RECEIPT_RESPONSE_HASH_NOT_FOUND",
6474
- "RECEIPT_REQUEST_HASH_NOT_FOUND",
6475
- "RECEIPT_DELIVERABLE_HASH_MISMATCH"
6476
- ]);
6477
- var VERDICT_VALUES = ["accepted", "accepted_with_notes", "rejected"];
6478
- var SHA256_RE = /^sha256:[0-9a-f]{64}$/;
6479
6546
  function registerPropose(parent) {
6480
- parent.command("propose").description("Send a receipt envelope as the PAYEE. Row lands PROPOSED; the buyer approves payment on-chain via claim_work_payment.").argument("<recipient-did>", "Recipient agent DID (= caller / offerer of the parent delegation)").argument("<delegation-id>", "Parent delegation id (UUID, must be ACCEPTED)").argument("[request-hash]", "sha256:<64 hex> \u2014 SHA-256 of the work_request payload being settled. Omit when --auto-hashes is set.").argument("[response-hash]", "sha256:<64 hex> \u2014 SHA-256 of the work_response payload being settled. Omit when --auto-hashes is set.").option("--server <url>", "Override ARP server base URL").option("--from-did <did>", "Sender DID \u2014 required only if multiple agents are registered against this server").option("--verdict <s>", "verdict_proposed (accepted | accepted_with_notes | rejected)", "accepted").option("--notes-hash <sha256>", "Optional sha256:<64 hex> notes hash").option("--deliverable-hash <sha256>", "Optional sha256:<64 hex> deliverable hash").option("--input-tokens <n>", "Optional usage.input_tokens").option("--output-tokens <n>", "Optional usage.output_tokens").option("--latency-ms <n>", "Optional usage.latency_ms").option("--model <name>", "Optional usage.model").option("--computed-amount <s>", "Optional usage.computed_amount").option("--ttl <seconds>", "Envelope TTL in seconds", "3600").option(
6547
+ parent.command("propose").description("Send a receipt envelope as the PAYEE. Row lands PROPOSED; the buyer approves payment on-chain via claim_work_payment.").argument("<recipient>", "Recipient \u2014 agent name (handle) or DID (= caller / offerer of the parent delegation)").argument("<delegation-id>", "Parent delegation id (UUID, must be ACCEPTED)").argument("[request-hash]", "sha256:<64 hex> \u2014 SHA-256 of the work_request payload being settled. Omit when --auto-hashes is set.").argument("[response-hash]", "sha256:<64 hex> \u2014 SHA-256 of the work_response payload being settled. Omit when --auto-hashes is set.").option("--server <url>", "Override ARP server base URL").option("--from-did <did>", "Sender DID \u2014 required only if multiple agents are registered against this server").option("--verdict <s>", "verdict_proposed (accepted | accepted_with_notes | rejected)", "accepted").option("--notes-hash <sha256>", "Optional sha256:<64 hex> notes hash").option("--deliverable-hash <sha256>", "Optional sha256:<64 hex> deliverable hash").option("--input-tokens <n>", "Optional usage.input_tokens").option("--output-tokens <n>", "Optional usage.output_tokens").option("--latency-ms <n>", "Optional usage.latency_ms").option("--model <name>", "Optional usage.model").option("--computed-amount <s>", "Optional usage.computed_amount").option("--ttl <seconds>", "Envelope TTL in seconds", "3600").option(
6481
6548
  "--auto-hashes",
6482
6549
  "Compute request_hash + response_hash automatically from the work-log row at (--rel-id, <delegation-id>, --request-id). Positional <request-hash>/<response-hash> become optional; if supplied they must match the computed values (consistency check). --rel-id and --request-id auto-resolve from local state when unambiguous \u2014 pass them explicitly only if the lookup finds multiple candidates.",
6483
6550
  false
@@ -6497,7 +6564,7 @@ function registerPropose(parent) {
6497
6564
  } catch (err) {
6498
6565
  emitActionError(err, cmd);
6499
6566
  if (!opts.json && err instanceof ApiError && err.payload.code === "RECEIPT_ALREADY_EXISTS") {
6500
- console.error(import_chalk22.default.dim(" This receipt already exists (a prior propose committed it). Do NOT re-propose \u2014 payment consent is on-chain (claim_work_payment)."));
6567
+ console.error(import_chalk24.default.dim(" This receipt already exists (a prior propose committed it). Do NOT re-propose \u2014 payment consent is on-chain (claim_work_payment)."));
6501
6568
  }
6502
6569
  process.exitCode = 1;
6503
6570
  }
@@ -6509,7 +6576,7 @@ async function runPropose(recipientDid, delegationId, requestHashArg, responseHa
6509
6576
  "receipt propose: --verbose and --json are mutually exclusive. --json already emits the full server response as a structured payload; --verbose adds an envelope + response dump on top that would break `--json | jq`."
6510
6577
  );
6511
6578
  }
6512
- requireDid2("receipt propose", recipientDid, "<recipient-did>");
6579
+ recipientDid = await resolveRecipient(opts.server, "receipt propose", recipientDid, { json: opts.json });
6513
6580
  delegationId = requireUuidNormalised2("receipt propose", delegationId, "<delegation-id>");
6514
6581
  if (opts.relId) opts.relId = requireUuidNormalised2("receipt propose", opts.relId, "--rel-id");
6515
6582
  const verdict = parseVerdict("receipt propose", opts.verdict);
@@ -6523,7 +6590,7 @@ async function runPropose(recipientDid, delegationId, requestHashArg, responseHa
6523
6590
  opts.relId = await resolveAutoRelId(api, sender, delegationId);
6524
6591
  progress(
6525
6592
  opts.json,
6526
- import_chalk22.default.dim(`[auto-rel-id] resolved --rel-id=${opts.relId} (delegation found in exactly one of your relationships; pass --rel-id explicitly to override)`)
6593
+ import_chalk24.default.dim(`[auto-rel-id] resolved --rel-id=${opts.relId} (delegation found in exactly one of your relationships; pass --rel-id explicitly to override)`)
6527
6594
  );
6528
6595
  }
6529
6596
  if (opts.relId) {
@@ -6539,7 +6606,7 @@ async function runPropose(recipientDid, delegationId, requestHashArg, responseHa
6539
6606
  opts.requestId = await resolveAutoRequestId(api, sender, opts.relId, delegationId);
6540
6607
  progress(
6541
6608
  opts.json,
6542
- import_chalk22.default.dim(
6609
+ import_chalk24.default.dim(
6543
6610
  `[auto-request-id] resolved --request-id=${opts.requestId} (unique 'responded' work_log under this delegation; pass --request-id explicitly to override)`
6544
6611
  )
6545
6612
  );
@@ -6558,8 +6625,8 @@ async function runPropose(recipientDid, delegationId, requestHashArg, responseHa
6558
6625
  }
6559
6626
  requestHash = computed.requestHash;
6560
6627
  responseHash = computed.responseHash;
6561
- progress(opts.json, import_chalk22.default.dim(`[auto-hashes] request_hash: ${requestHash} (from work-log ${opts.relId}/${delegationId}/${opts.requestId})`));
6562
- progress(opts.json, import_chalk22.default.dim(`[auto-hashes] response_hash: ${responseHash}`));
6628
+ progress(opts.json, import_chalk24.default.dim(`[auto-hashes] request_hash: ${requestHash} (from work-log ${opts.relId}/${delegationId}/${opts.requestId})`));
6629
+ progress(opts.json, import_chalk24.default.dim(`[auto-hashes] response_hash: ${responseHash}`));
6563
6630
  } else {
6564
6631
  if (requestHashArg === void 0 || responseHashArg === void 0) {
6565
6632
  throw new Error("receipt propose: <request-hash> and <response-hash> are required (or pass --auto-hashes + --rel-id + --request-id to derive them from the work-log)");
@@ -6579,11 +6646,11 @@ async function runPropose(recipientDid, delegationId, requestHashArg, responseHa
6579
6646
  if (opts.deliverableHash) content.deliverable_hash = opts.deliverableHash;
6580
6647
  if (usage) content.usage = usage;
6581
6648
  const body = { type: "receipt", content };
6582
- progress(opts.json, import_chalk22.default.dim(`Server: ${api.serverUrl}`));
6583
- progress(opts.json, import_chalk22.default.dim(`Sender (payee): ${sender.did}`));
6584
- progress(opts.json, import_chalk22.default.dim(`Recipient (caller): ${recipientDid}`));
6585
- progress(opts.json, import_chalk22.default.dim(`Delegation: ${delegationId}`));
6586
- progress(opts.json, import_chalk22.default.dim(`Verdict (proposed): ${verdict}`));
6649
+ progress(opts.json, import_chalk24.default.dim(`Server: ${api.serverUrl}`));
6650
+ progress(opts.json, import_chalk24.default.dim(`Sender (payee): ${sender.did}`));
6651
+ progress(opts.json, import_chalk24.default.dim(`Recipient (caller): ${recipientDid}`));
6652
+ progress(opts.json, import_chalk24.default.dim(`Delegation: ${delegationId}`));
6653
+ progress(opts.json, import_chalk24.default.dim(`Verdict (proposed): ${verdict}`));
6587
6654
  const result = await sendReceiptEnvelope({ api, sender, recipientDid, body, attachments: void 0, ttlSeconds, verbose: opts.verbose, server: opts.server });
6588
6655
  if (opts.json) {
6589
6656
  const json = {
@@ -6604,10 +6671,10 @@ async function runPropose(recipientDid, delegationId, requestHashArg, responseHa
6604
6671
  return;
6605
6672
  }
6606
6673
  printIngestResult2(result);
6607
- console.log(import_chalk22.default.dim(`
6608
- Receipt event hash: ${import_chalk22.default.cyan(result.serverEventHash)}`));
6609
- console.log(import_chalk22.default.dim("Receipt recorded. Payment consent is ON-CHAIN now: the buyer approves by"));
6610
- console.log(import_chalk22.default.dim("sending claim_work_payment (or you self-claim after the review window)."));
6674
+ console.log(import_chalk24.default.dim(`
6675
+ Receipt event hash: ${import_chalk24.default.cyan(result.serverEventHash)}`));
6676
+ console.log(import_chalk24.default.dim("Receipt recorded. Payment consent is ON-CHAIN now: the buyer approves by"));
6677
+ console.log(import_chalk24.default.dim("sending claim_work_payment (or you self-claim after the review window)."));
6611
6678
  }
6612
6679
  async function assertSenderIsReceiptPayee(api, sender, relationshipId, delegationId) {
6613
6680
  const signer = makeSigner(sender);
@@ -6675,7 +6742,7 @@ async function computeWorkLogHashes(api, sender, relationshipId, delegationId, r
6675
6742
  `receipt propose --auto-hashes: no work-log row found for (relationshipId=${relationshipId}, delegationId=${delegationId}, requestId=${requestId}). Did the work_request envelope land yet?`
6676
6743
  );
6677
6744
  }
6678
- if (workLog.state !== "responded") {
6745
+ if (workLog.state !== import_sdk22.WorkLogStates.RESPONDED) {
6679
6746
  throw new Error(
6680
6747
  `receipt propose --auto-hashes: work-log row ${requestId} is in state '${workLog.state}', not 'responded'. The payee must \`work respond\` before a receipt can be proposed.`
6681
6748
  );
@@ -6691,34 +6758,34 @@ async function computeWorkLogHashes(api, sender, relationshipId, delegationId, r
6691
6758
  };
6692
6759
  const responseBody = workLog.responseOutput !== void 0 ? { type: "work_response", content: { delegation_id: workLog.delegationId, request_id: workLog.requestId, output: workLog.responseOutput } } : { type: "work_response", content: { delegation_id: workLog.delegationId, request_id: workLog.requestId, error: workLog.responseError } };
6693
6760
  return {
6694
- requestHash: (0, import_sdk14.canonicalSha256Hex)(requestBody),
6695
- responseHash: (0, import_sdk14.canonicalSha256Hex)(responseBody)
6761
+ requestHash: (0, import_sdk22.canonicalSha256Hex)(requestBody),
6762
+ responseHash: (0, import_sdk22.canonicalSha256Hex)(responseBody)
6696
6763
  };
6697
6764
  }
6698
6765
  async function sendReceiptEnvelope(args) {
6699
6766
  const nextSequence = (args.sender.lastSenderSequence ?? 0) + 1;
6700
6767
  const protectedBlock = {
6701
- protocol_version: "arp/0.1",
6702
- purpose: import_sdk14.Purpose.ENVELOPE,
6703
- message_id: (0, import_sdk14.uuidV4)(),
6768
+ protocol_version: import_sdk22.CURRENT_PROTOCOL_VERSION,
6769
+ purpose: import_sdk22.Purpose.ENVELOPE,
6770
+ message_id: (0, import_sdk22.uuidV4)(),
6704
6771
  sender_did: args.sender.did,
6705
6772
  recipient_did: args.recipientDid,
6706
6773
  relationship_id: null,
6707
6774
  sender_sequence: nextSequence,
6708
- sender_nonce: (0, import_sdk14.senderNonce)(),
6709
- timestamp: (0, import_sdk14.rfc3339)(),
6710
- expires_at: (0, import_sdk14.expiresAt)(args.ttlSeconds),
6775
+ sender_nonce: (0, import_sdk22.senderNonce)(),
6776
+ timestamp: (0, import_sdk22.rfc3339)(),
6777
+ expires_at: (0, import_sdk22.expiresAt)(args.ttlSeconds),
6711
6778
  delivery_id: null
6712
6779
  };
6713
6780
  const signer = makeSigner(args.sender);
6714
- const envelope = (0, import_sdk14.signEnvelope)({
6781
+ const envelope = (0, import_sdk22.signEnvelope)({
6715
6782
  protected: protectedBlock,
6716
6783
  body: args.body,
6717
6784
  identitySecretKey: signer.identitySecretKey,
6718
6785
  attachments: args.attachments
6719
6786
  });
6720
6787
  if (args.verbose) {
6721
- console.log(import_chalk22.default.bold("\nEnvelope (pre-send):"));
6788
+ console.log(import_chalk24.default.bold("\nEnvelope (pre-send):"));
6722
6789
  console.log(formatJson(envelope));
6723
6790
  }
6724
6791
  try {
@@ -6726,24 +6793,24 @@ async function sendReceiptEnvelope(args) {
6726
6793
  updateAgentLocal(args.server, args.sender.did, { lastSenderSequence: nextSequence });
6727
6794
  return result;
6728
6795
  } catch (err) {
6729
- if (err instanceof ApiError && POST_COMMIT_ERROR_CODES2.has(err.payload.code)) {
6796
+ if (err instanceof ApiError && (0, import_sdk22.isPostCommitErrorCode)(err.payload.code)) {
6730
6797
  updateAgentLocal(args.server, args.sender.did, { lastSenderSequence: nextSequence });
6731
6798
  }
6732
6799
  throw err;
6733
6800
  }
6734
6801
  }
6735
6802
  function printIngestResult2(result) {
6736
- console.log(import_chalk22.default.green("\nDelivered."));
6737
- console.log(`${import_chalk22.default.bold("Event id")}: ${import_chalk22.default.cyan(result.eventId)}`);
6738
- console.log(`${import_chalk22.default.bold("Relationship id")}: ${import_chalk22.default.cyan(result.relationshipId)}`);
6739
- console.log(`${import_chalk22.default.bold("Chain index")}: ${import_chalk22.default.cyan(String(result.relationshipEventIndex))}`);
6740
- console.log(`${import_chalk22.default.bold("Server timestamp")}: ${import_chalk22.default.cyan(result.serverTimestamp)}`);
6741
- console.log(`${import_chalk22.default.bold("Server event hash")}: ${import_chalk22.default.cyan(result.serverEventHash)}`);
6803
+ console.log(import_chalk24.default.green("\nDelivered."));
6804
+ console.log(`${import_chalk24.default.bold("Event id")}: ${import_chalk24.default.cyan(result.eventId)}`);
6805
+ console.log(`${import_chalk24.default.bold("Relationship id")}: ${import_chalk24.default.cyan(result.relationshipId)}`);
6806
+ console.log(`${import_chalk24.default.bold("Chain index")}: ${import_chalk24.default.cyan(String(result.relationshipEventIndex))}`);
6807
+ console.log(`${import_chalk24.default.bold("Server timestamp")}: ${import_chalk24.default.cyan(result.serverTimestamp)}`);
6808
+ console.log(`${import_chalk24.default.bold("Server event hash")}: ${import_chalk24.default.cyan(result.serverEventHash)}`);
6742
6809
  }
6743
6810
  function parseVerdict(cmdName, raw) {
6744
- if (raw === void 0 || raw === "") return "accepted";
6745
- if (!VERDICT_VALUES.includes(raw)) {
6746
- throw new Error(`${cmdName}: --verdict must be one of ${VERDICT_VALUES.join(" | ")} (got '${raw}')`);
6811
+ if (raw === void 0 || raw === "") return import_sdk22.ReceiptVerdicts.ACCEPTED;
6812
+ if (!import_sdk22.RECEIPT_VERDICTS.includes(raw)) {
6813
+ throw new Error(`${cmdName}: --verdict must be one of ${import_sdk22.RECEIPT_VERDICTS.join(" | ")} (got '${raw}')`);
6747
6814
  }
6748
6815
  return raw;
6749
6816
  }
@@ -6780,18 +6847,14 @@ function requireUuid3(cmdName, raw, label) {
6780
6847
  requireUuid(cmdName, raw, label);
6781
6848
  }
6782
6849
  function requireSha256(cmdName, raw, label) {
6783
- if (!SHA256_RE.test(raw)) {
6850
+ if (!(0, import_sdk22.isSha256Hex)(raw)) {
6784
6851
  throw new Error(`${cmdName}: ${label} must match 'sha256:<64 lowercase hex>' (got '${raw}')`);
6785
6852
  }
6786
6853
  }
6787
- function requireDid2(cmdName, did, label) {
6788
- if (typeof did !== "string" || !did.startsWith("did:arp:") || did.length <= "did:arp:".length) {
6789
- throw new Error(`${cmdName}: ${label} must look like 'did:arp:...' (got '${did}')`);
6790
- }
6791
- }
6792
6854
 
6793
6855
  // src/commands/receipts.ts
6794
- var import_chalk23 = __toESM(require("chalk"));
6856
+ var import_sdk23 = require("@heyanon-arp/sdk");
6857
+ var import_chalk25 = __toESM(require("chalk"));
6795
6858
  init_api();
6796
6859
  function registerReceiptsCommand(root) {
6797
6860
  root.command("receipts").description(
@@ -6814,9 +6877,9 @@ async function runReceipts(relationshipId, opts) {
6814
6877
  const api = new ArpApiClient(opts.server);
6815
6878
  const sender = resolveSenderAgent("receipts", opts.server, opts.fromDid);
6816
6879
  if (!opts.json) {
6817
- console.log(import_chalk23.default.dim(`Server: ${api.serverUrl}`));
6818
- console.log(import_chalk23.default.dim(`Signer: ${sender.did}`));
6819
- console.log(import_chalk23.default.dim(`Relationship: ${relationshipId}`));
6880
+ console.log(import_chalk25.default.dim(`Server: ${api.serverUrl}`));
6881
+ console.log(import_chalk25.default.dim(`Signer: ${sender.did}`));
6882
+ console.log(import_chalk25.default.dim(`Relationship: ${relationshipId}`));
6820
6883
  }
6821
6884
  const query = { limit };
6822
6885
  if (opts.delegationId) query.delegationId = opts.delegationId;
@@ -6828,7 +6891,7 @@ async function runReceipts(relationshipId, opts) {
6828
6891
  return;
6829
6892
  }
6830
6893
  if (rows.length === 0) {
6831
- console.log(import_chalk23.default.dim("\n(no receipts for this relationship)"));
6894
+ console.log(import_chalk25.default.dim("\n(no receipts for this relationship)"));
6832
6895
  return;
6833
6896
  }
6834
6897
  console.log("");
@@ -6845,29 +6908,29 @@ async function runReceipts(relationshipId, opts) {
6845
6908
  }));
6846
6909
  }
6847
6910
  const lastId = rows[rows.length - 1].id;
6848
- console.log(import_chalk23.default.dim(`
6911
+ console.log(import_chalk25.default.dim(`
6849
6912
  ${rows.length} receipt row(s). Paginate with --after ${lastId}.`));
6850
6913
  }
6851
6914
  function formatReceiptLine(r, selfDid, opts = {}) {
6852
6915
  const delegationPart = opts.fullIds ? r.delegationId : idHead2(r.delegationId);
6853
6916
  const requestHashPart = opts.fullIds ? r.requestHash : hashHead3(r.requestHash);
6854
- const id = import_chalk23.default.bold(`${delegationPart}/${requestHashPart}`);
6917
+ const id = import_chalk25.default.bold(`${delegationPart}/${requestHashPart}`);
6855
6918
  const callerHead = opts.fullIds ? r.callerDid : didHead3(r.callerDid);
6856
6919
  const payeeHead = opts.fullIds ? r.payeeDid : didHead3(r.payeeDid);
6857
- const direction = r.payeeDid === selfDid ? `${import_chalk23.default.bold("me")}(payee) \u2192 ${import_chalk23.default.dim(callerHead)}` : `${import_chalk23.default.dim(payeeHead)}(payee) \u2192 ${import_chalk23.default.bold("me")}`;
6920
+ const direction = r.payeeDid === selfDid ? `${import_chalk25.default.bold("me")}(payee) \u2192 ${import_chalk25.default.dim(callerHead)}` : `${import_chalk25.default.dim(payeeHead)}(payee) \u2192 ${import_chalk25.default.bold("me")}`;
6858
6921
  const verdict = formatVerdict(r);
6859
6922
  const responseTail = opts.fullIds ? `
6860
- ${import_chalk23.default.dim("responseHash:")} ${import_chalk23.default.cyan(r.responseHash)}` : "";
6923
+ ${import_chalk25.default.dim("responseHash:")} ${import_chalk25.default.cyan(r.responseHash)}` : "";
6861
6924
  return `${id} ${direction} ${verdict}${responseTail}`;
6862
6925
  }
6863
6926
  function formatVerdict(r) {
6864
6927
  switch (r.verdictProposed) {
6865
- case "accepted":
6866
- return import_chalk23.default.green("accepted");
6867
- case "accepted_with_notes":
6868
- return import_chalk23.default.yellow("accepted_with_notes");
6869
- case "rejected":
6870
- return import_chalk23.default.red("rejected");
6928
+ case import_sdk23.ReceiptVerdicts.ACCEPTED:
6929
+ return import_chalk25.default.green("accepted");
6930
+ case import_sdk23.ReceiptVerdicts.ACCEPTED_WITH_NOTES:
6931
+ return import_chalk25.default.yellow("accepted_with_notes");
6932
+ case import_sdk23.ReceiptVerdicts.REJECTED:
6933
+ return import_chalk25.default.red("rejected");
6871
6934
  }
6872
6935
  }
6873
6936
  function idHead2(id) {
@@ -6893,8 +6956,8 @@ function parseLimit5(raw) {
6893
6956
 
6894
6957
  // src/commands/recover.ts
6895
6958
  var import_node_fs8 = require("fs");
6896
- var import_sdk15 = require("@heyanon-arp/sdk");
6897
- var import_chalk24 = __toESM(require("chalk"));
6959
+ var import_sdk24 = require("@heyanon-arp/sdk");
6960
+ var import_chalk26 = __toESM(require("chalk"));
6898
6961
  init_api();
6899
6962
  function registerRecoverCommand(root) {
6900
6963
  root.command("recover").description(
@@ -6914,23 +6977,23 @@ async function runRecover(opts) {
6914
6977
  }
6915
6978
  const bundle = validateKeyBundle(raw);
6916
6979
  const identitySecret = new Uint8Array(Buffer.from(bundle.identitySecretKeyB64, "base64"));
6917
- const identityPub = (0, import_sdk15.base58btcDecode)(bundle.identityPublicKeyB58);
6918
- const derivedDid = (0, import_sdk15.formatDid)(identityPub);
6980
+ const identityPub = (0, import_sdk24.base58btcDecode)(bundle.identityPublicKeyB58);
6981
+ const derivedDid = (0, import_sdk24.formatDid)(identityPub);
6919
6982
  if (derivedDid !== bundle.did) {
6920
6983
  throw new Error(`recover: key file is inconsistent \u2014 its DID (${bundle.did}) does not match its identity public key (${derivedDid})`);
6921
6984
  }
6922
6985
  const probe2 = new TextEncoder().encode("heyarp-recover-keycheck");
6923
- if (!(0, import_sdk15.verify)((0, import_sdk15.sign)(probe2, identitySecret), probe2, identityPub)) {
6986
+ if (!(0, import_sdk24.verify)((0, import_sdk24.sign)(probe2, identitySecret), probe2, identityPub)) {
6924
6987
  throw new Error("recover: the identity secret key does not match the public key in this bundle");
6925
6988
  }
6926
6989
  const settlementSecret = new Uint8Array(Buffer.from(bundle.settlementSecretKeyB64, "base64"));
6927
- const settlementPub = (0, import_sdk15.base58btcDecode)(bundle.settlementPublicKeyB58);
6928
- if (!(0, import_sdk15.verify)((0, import_sdk15.sign)(probe2, settlementSecret), probe2, settlementPub)) {
6990
+ const settlementPub = (0, import_sdk24.base58btcDecode)(bundle.settlementPublicKeyB58);
6991
+ if (!(0, import_sdk24.verify)((0, import_sdk24.sign)(probe2, settlementSecret), probe2, settlementPub)) {
6929
6992
  throw new Error("recover: the settlement secret key does not match the settlement public key in this bundle");
6930
6993
  }
6931
6994
  if (bundle.ownerWallet && bundle.ownerWallet !== credential.wallet) {
6932
6995
  process.stderr.write(
6933
- import_chalk24.default.yellow(
6996
+ import_chalk26.default.yellow(
6934
6997
  `\u26A0 this bundle was exported under wallet ${bundle.ownerWallet}, but you are logged in as ${credential.wallet}. The server will reject the recover unless the agent is yours.
6935
6998
  `
6936
6999
  )
@@ -6947,7 +7010,7 @@ async function runRecover(opts) {
6947
7010
  lastSenderSequence = seq.lastSenderSequence;
6948
7011
  } catch (err) {
6949
7012
  process.stderr.write(
6950
- import_chalk24.default.yellow(
7013
+ import_chalk26.default.yellow(
6951
7014
  `\u26A0 could not read the sender sequence from the server (${err.message}). If sends are rejected as backwards, run \`heyarp escrow recover-sequence --apply\`.
6952
7015
  `
6953
7016
  )
@@ -6975,14 +7038,14 @@ async function runRecover(opts) {
6975
7038
  jsonOut({ recovered: true, did: derivedDid, name: row.name });
6976
7039
  return;
6977
7040
  }
6978
- console.log(import_chalk24.default.green(`\u2713 Recovered ${row.name ? `${row.name} ` : ""}${derivedDid} into local state \u2014 you can operate it now.`));
7041
+ console.log(import_chalk26.default.green(`\u2713 Recovered ${row.name ? `${row.name} ` : ""}${derivedDid} into local state \u2014 you can operate it now.`));
6979
7042
  }
6980
7043
 
6981
7044
  // src/commands/register.ts
6982
7045
  var import_node_crypto4 = require("crypto");
6983
7046
  var import_node_fs9 = require("fs");
6984
- var import_sdk16 = require("@heyanon-arp/sdk");
6985
- var import_chalk25 = __toESM(require("chalk"));
7047
+ var import_sdk25 = require("@heyanon-arp/sdk");
7048
+ var import_chalk27 = __toESM(require("chalk"));
6986
7049
  var import_prompts2 = __toESM(require("prompts"));
6987
7050
  init_api();
6988
7051
  init_paths();
@@ -6994,7 +7057,7 @@ function registerRegisterCommand(root) {
6994
7057
  "`--password` is REQUIRED \u2014 must be at least 8 characters. In interactive mode (--yes omitted) the CLI prompts for it; with --yes it must be passed explicitly.",
6995
7058
  "`--yes` is the non-interactive switch \u2014 every required field must arrive via flags (no prompts). Use this for scripted setups."
6996
7059
  ].join("\n")
6997
- ).option("--server <url>", "Override ARP server base URL").option("--from-keys <file>", "Load identity + settlement keys from a JSON file instead of generating").option("--name <s>", "Display name (skips the name prompt)").option("--description <s>", "Description (skips the description prompt)").option("--tag <s>", "Capability tag \u2014 repeatable, e.g. --tag translation --tag fr", accumulate3, []).option(
7060
+ ).option("--server <url>", "Override ARP server base URL").option("--from-keys <file>", "Load identity + settlement keys from a JSON file instead of generating").option("--name <s>", "Unique handle \u2014 lowercase a-z0-9_, 3-32 chars, immutable (skips the name prompt)").option("--description <s>", "Description (skips the description prompt)").option("--tag <s>", "Capability tag \u2014 repeatable, e.g. --tag translation --tag fr", accumulate3, []).option(
6998
7061
  "--password <s>",
6999
7062
  // `--password` puts the secret in `argv` — visible via
7000
7063
  // `ps aux` / kernel process table on shared hosts,
@@ -7036,44 +7099,44 @@ var defaultRegisterDeps = {
7036
7099
  async function runRegister(opts, deps = defaultRegisterDeps) {
7037
7100
  assertJsonRequiresYes(opts);
7038
7101
  const api = deps.makeApi(opts.server);
7039
- if (!opts.json) console.log(import_chalk25.default.dim(`Server: ${api.serverUrl}`));
7102
+ if (!opts.json) console.log(import_chalk27.default.dim(`Server: ${api.serverUrl}`));
7040
7103
  const credential = requireCredential("register", api.serverUrl);
7041
7104
  if (!opts.json) {
7042
7105
  warnIfAgentsAlreadyRegistered(opts.server);
7043
7106
  warnIfOrphanHomesPresent();
7044
7107
  }
7045
7108
  const keys = opts.fromKeys ? loadKeysFromFile(opts.fromKeys) : freshKeys();
7046
- const did = (0, import_sdk16.formatDid)(keys.identityPublicKey);
7047
- if (!opts.json) console.log(import_chalk25.default.dim(`DID will be: ${did}`));
7109
+ const did = (0, import_sdk25.formatDid)(keys.identityPublicKey);
7110
+ if (!opts.json) console.log(import_chalk27.default.dim(`DID will be: ${did}`));
7048
7111
  const answers = await mergeAnswers(opts);
7049
7112
  const scryptSalt = (0, import_node_crypto4.randomBytes)(16);
7050
- if (!opts.json) console.log(import_chalk25.default.dim("Deriving scrypt key, this may take a moment..."));
7051
- const scryptKey = (0, import_sdk16.deriveScryptKey)(answers.password, new Uint8Array(scryptSalt));
7113
+ if (!opts.json) console.log(import_chalk27.default.dim("Deriving scrypt key, this may take a moment..."));
7114
+ const scryptKey = (0, import_sdk25.deriveScryptKey)(answers.password, new Uint8Array(scryptSalt));
7052
7115
  const challenge = await api.issueChallenge("register");
7053
7116
  const challengeBytes = base64UrlNoPadDecode(challenge.challengeB64);
7054
7117
  if (challengeBytes.length !== 32) {
7055
7118
  throw new Error(`Server returned a ${challengeBytes.length}-byte challenge; expected 32`);
7056
7119
  }
7057
- const challengeSig = (0, import_sdk16.signChallenge)(challengeBytes, keys.identitySecretKey);
7058
- const identityPublicKeyB58 = (0, import_sdk16.base58btcEncode)(keys.identityPublicKey);
7120
+ const challengeSig = (0, import_sdk25.signChallenge)(challengeBytes, keys.identitySecretKey);
7121
+ const identityPublicKeyB58 = (0, import_sdk25.base58btcEncode)(keys.identityPublicKey);
7059
7122
  await api.submitChallengeResponse({
7060
7123
  challengeId: challenge.challengeId,
7061
7124
  identityPublicKey: identityPublicKeyB58,
7062
7125
  signature: Buffer.from(challengeSig).toString("base64")
7063
7126
  });
7064
- const settlementPublicKeyB58 = (0, import_sdk16.base58btcEncode)(keys.settlementPublicKey);
7065
- const scryptSaltId = (0, import_sdk16.uuidV4)();
7127
+ const settlementPublicKeyB58 = (0, import_sdk25.base58btcEncode)(keys.settlementPublicKey);
7128
+ const scryptSaltId = (0, import_sdk25.uuidV4)();
7066
7129
  const payload = {
7067
- purpose: "ARP-KEY-LINK-v1",
7130
+ purpose: import_sdk25.Purpose.KEY_LINK,
7068
7131
  agent_did: did,
7069
7132
  identity_public_key: identityPublicKeyB58,
7070
7133
  settlement_public_key: settlementPublicKeyB58,
7071
- owner_signing_method: "scrypt_password_proof",
7134
+ owner_signing_method: import_sdk25.OWNER_SIGNING_METHODS[0],
7072
7135
  link_method: "manual",
7073
- created_at: (0, import_sdk16.rfc3339)(),
7074
- nonce: (0, import_sdk16.senderNonce)()
7136
+ created_at: (0, import_sdk25.rfc3339)(),
7137
+ nonce: (0, import_sdk25.senderNonce)()
7075
7138
  };
7076
- const attestation = (0, import_sdk16.signKeyLinkAttestation)({ payload, scryptKey, scryptSaltId });
7139
+ const attestation = (0, import_sdk25.signKeyLinkAttestation)({ payload, scryptKey, scryptSaltId });
7077
7140
  const body = {
7078
7141
  challengeId: challenge.challengeId,
7079
7142
  identityPublicKey: identityPublicKeyB58,
@@ -7116,7 +7179,7 @@ async function runRegister(opts, deps = defaultRegisterDeps) {
7116
7179
  try {
7117
7180
  result = await api.register(body, credential.token);
7118
7181
  } catch (err) {
7119
- if (err instanceof ApiError && (err.payload.code === "AUTH_TOKEN_INVALID" || err.payload.code === "AUTH_TOKEN_REQUIRED")) {
7182
+ if (err instanceof ApiError && (err.payload.code === import_sdk25.CliAuthTokenErrorCodes.INVALID || err.payload.code === import_sdk25.CliAuthTokenErrorCodes.REQUIRED)) {
7120
7183
  throw new Error(
7121
7184
  `register: the stored login token for ${api.serverUrl} was rejected (${err.payload.message}) \u2014 run 'heyarp login' again. Your keys are saved locally; re-running register with --from-keys is safe.`
7122
7185
  );
@@ -7135,19 +7198,19 @@ async function runRegister(opts, deps = defaultRegisterDeps) {
7135
7198
  try {
7136
7199
  recordHome(arpHomeDir());
7137
7200
  } catch (registryErr) {
7138
- if (!opts.json) console.log(import_chalk25.default.dim(`(homes registry write failed: ${registryErr.message})`));
7201
+ if (!opts.json) console.log(import_chalk27.default.dim(`(homes registry write failed: ${registryErr.message})`));
7139
7202
  }
7140
7203
  if (!opts.json) {
7141
- console.log(import_chalk25.default.green("\nRegistered."));
7142
- console.log(`${import_chalk25.default.bold("DID")}: ${import_chalk25.default.cyan(result.did)}`);
7143
- console.log(`${import_chalk25.default.bold("Settlement pubkey")} ${import_chalk25.default.dim("(fund with SOL)")}: ${import_chalk25.default.cyan(settlementPublicKeyB58)}`);
7144
- console.log(`${import_chalk25.default.bold("Owner account")}: ${import_chalk25.default.cyan(credential.wallet)}`);
7145
- console.log(import_chalk25.default.bold("DID document:"));
7204
+ console.log(import_chalk27.default.green("\nRegistered."));
7205
+ console.log(`${import_chalk27.default.bold("DID")}: ${import_chalk27.default.cyan(result.did)}`);
7206
+ console.log(`${import_chalk27.default.bold("Settlement pubkey")} ${import_chalk27.default.dim("(fund with SOL)")}: ${import_chalk27.default.cyan(settlementPublicKeyB58)}`);
7207
+ console.log(`${import_chalk27.default.bold("Owner account")}: ${import_chalk27.default.cyan(credential.wallet)}`);
7208
+ console.log(import_chalk27.default.bold("DID document:"));
7146
7209
  console.log(formatJson(result.didDocument));
7147
7210
  }
7148
- if (!opts.json) console.log(import_chalk25.default.green(`
7211
+ if (!opts.json) console.log(import_chalk27.default.green(`
7149
7212
  \u2713 Discoverable now via \`heyarp agents\`.`));
7150
- if (!opts.json) console.log(import_chalk25.default.dim(`
7213
+ if (!opts.json) console.log(import_chalk27.default.dim(`
7151
7214
  Local state saved to ${arpHomeDir()}/agents.json (mode 0600).`));
7152
7215
  if (opts.json) {
7153
7216
  console.log(
@@ -7198,8 +7261,13 @@ async function mergeAnswers(opts) {
7198
7261
  promptDefs.push({
7199
7262
  type: "text",
7200
7263
  name: "name",
7201
- message: "Agent name (display only)",
7202
- validate: (v) => v.length > 0 ? true : "required"
7264
+ message: "Agent name \u2014 unique handle (lowercase a-z0-9_, 3-32 chars, immutable; addressable instead of the DID)",
7265
+ validate: (v) => {
7266
+ const n = (0, import_sdk25.normalizeName)(v);
7267
+ if (!(0, import_sdk25.isValidAgentName)(n)) return "must be lowercase a-z0-9_, 3-32 chars";
7268
+ if ((0, import_sdk25.isReservedName)(n)) return `'${n}' is reserved`;
7269
+ return true;
7270
+ }
7203
7271
  });
7204
7272
  }
7205
7273
  if (need.description) {
@@ -7215,18 +7283,29 @@ async function mergeAnswers(opts) {
7215
7283
  }
7216
7284
  const prompted = promptDefs.length > 0 ? await (0, import_prompts2.default)(promptDefs, {
7217
7285
  onCancel: () => {
7218
- console.log(import_chalk25.default.yellow("\nAborted."));
7286
+ console.log(import_chalk27.default.yellow("\nAborted."));
7219
7287
  process.exit(130);
7220
7288
  }
7221
7289
  }) : {};
7222
7290
  const tags = (opts.tag && opts.tag.length > 0 ? opts.tag : parseTagsCsv(typeof prompted.tagsCsv === "string" ? prompted.tagsCsv : "")).map((t) => t.trim().toLowerCase()).filter((t) => t.length > 0);
7291
+ const name = normalizeAndValidateName(opts.name ?? prompted.name);
7223
7292
  return {
7224
7293
  password: opts.password ?? prompted.password,
7225
- name: opts.name ?? prompted.name,
7294
+ name,
7226
7295
  description: opts.description ?? prompted.description ?? "",
7227
7296
  tags
7228
7297
  };
7229
7298
  }
7299
+ function normalizeAndValidateName(raw) {
7300
+ const name = (0, import_sdk25.normalizeName)(raw);
7301
+ if (!(0, import_sdk25.isValidAgentName)(name)) {
7302
+ throw new Error(`register: name '${raw}' must be a lowercase handle \u2014 a-z0-9_, 3-32 chars`);
7303
+ }
7304
+ if ((0, import_sdk25.isReservedName)(name)) {
7305
+ throw new Error(`register: name '${name}' is reserved and cannot be registered`);
7306
+ }
7307
+ return name;
7308
+ }
7230
7309
  function warnIfOrphanHomesPresent() {
7231
7310
  if (process.env.HEYARP_HOME && process.env.HEYARP_HOME.length > 0) {
7232
7311
  return;
@@ -7236,16 +7315,16 @@ function warnIfOrphanHomesPresent() {
7236
7315
  try {
7237
7316
  others = listHomes().filter((h) => h.path !== current);
7238
7317
  } catch (registryErr) {
7239
- console.log(import_chalk25.default.dim(`(homes registry unreadable, skipping orphan-home check: ${registryErr.message})`));
7318
+ console.log(import_chalk27.default.dim(`(homes registry unreadable, skipping orphan-home check: ${registryErr.message})`));
7240
7319
  return;
7241
7320
  }
7242
7321
  if (others.length === 0) return;
7243
- const list = others.map((h) => ` \u2022 ${import_chalk25.default.cyan(h.path)} ${import_chalk25.default.dim(`(last seen ${h.lastSeenAt})`)}`).join("\n");
7244
- console.log(import_chalk25.default.yellow(`
7322
+ const list = others.map((h) => ` \u2022 ${import_chalk27.default.cyan(h.path)} ${import_chalk27.default.dim(`(last seen ${h.lastSeenAt})`)}`).join("\n");
7323
+ console.log(import_chalk27.default.yellow(`
7245
7324
  \u26A0 HEYARP_HOME is unset, but other agent homes are registered on this machine:`));
7246
7325
  console.log(list);
7247
7326
  console.log(
7248
- import_chalk25.default.dim(
7327
+ import_chalk27.default.dim(
7249
7328
  ` Registering will create a NEW agent under ${current}.
7250
7329
  If you meant to add to an existing home, abort (Ctrl-C) and re-run with:
7251
7330
  HEYARP_HOME=<path> heyarp register \u2026
@@ -7258,11 +7337,11 @@ function warnIfAgentsAlreadyRegistered(serverOverride) {
7258
7337
  const targetServer = resolveServerUrl(serverOverride);
7259
7338
  const existing = listAgents().filter((row) => row.serverUrl === targetServer);
7260
7339
  if (existing.length === 0) return;
7261
- const list = existing.map((row) => ` \u2022 ${import_chalk25.default.cyan(row.agent.did)}${row.agent.name ? import_chalk25.default.dim(` (${row.agent.name})`) : ""}`).join("\n");
7262
- console.log(import_chalk25.default.yellow("\n\u26A0 ~/.heyarp/agents.json already has agent(s) for this server:"));
7340
+ const list = existing.map((row) => ` \u2022 ${import_chalk27.default.cyan(row.agent.did)}${row.agent.name ? import_chalk27.default.dim(` (${row.agent.name})`) : ""}`).join("\n");
7341
+ console.log(import_chalk27.default.yellow("\n\u26A0 ~/.heyarp/agents.json already has agent(s) for this server:"));
7263
7342
  console.log(list);
7264
7343
  console.log(
7265
- import_chalk25.default.dim(
7344
+ import_chalk27.default.dim(
7266
7345
  " After this register completes, you will have multiple local DIDs sharing one state file.\n To keep their state isolated, run with HEYARP_HOME pointing at a per-agent dir, e.g.\n HEYARP_HOME=/tmp/agent-alice heyarp register \u2026\n Otherwise, pass --from-did <did> explicitly on every signed command.\n"
7267
7346
  )
7268
7347
  );
@@ -7272,8 +7351,8 @@ function parseTagsCsv(raw) {
7272
7351
  return raw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
7273
7352
  }
7274
7353
  function freshKeys() {
7275
- const identity = (0, import_sdk16.generateKeyPair)();
7276
- const settlement = (0, import_sdk16.generateKeyPair)();
7354
+ const identity = (0, import_sdk25.generateKeyPair)();
7355
+ const settlement = (0, import_sdk25.generateKeyPair)();
7277
7356
  return {
7278
7357
  identityPublicKey: identity.publicKey,
7279
7358
  identitySecretKey: identity.secretKey,
@@ -7299,9 +7378,9 @@ function loadKeysFromFile(path) {
7299
7378
  if (identitySecret.length !== 32) throw new Error("--from-keys: identitySecretKeyB64 is not a 32-byte Ed25519 seed");
7300
7379
  if (settlementSecret.length !== 32) throw new Error("--from-keys: settlementSecretKeyB64 is not a 32-byte Ed25519 seed");
7301
7380
  return {
7302
- identityPublicKey: (0, import_sdk16.getPublicKey)(identitySecret),
7381
+ identityPublicKey: (0, import_sdk25.getPublicKey)(identitySecret),
7303
7382
  identitySecretKey: identitySecret,
7304
- settlementPublicKey: (0, import_sdk16.getPublicKey)(settlementSecret),
7383
+ settlementPublicKey: (0, import_sdk25.getPublicKey)(settlementSecret),
7305
7384
  settlementSecretKey: settlementSecret
7306
7385
  };
7307
7386
  }
@@ -7317,17 +7396,27 @@ function assertJsonRequiresYes(opts) {
7317
7396
  }
7318
7397
 
7319
7398
  // src/commands/relationships.ts
7320
- var import_chalk26 = __toESM(require("chalk"));
7399
+ var import_sdk26 = require("@heyanon-arp/sdk");
7400
+ var import_chalk28 = __toESM(require("chalk"));
7321
7401
  init_api();
7322
- var ALLOWED_STATES2 = /* @__PURE__ */ new Set(["pending", "active", "paused", "closed"]);
7402
+ var ALLOWED_STATES2 = new Set(import_sdk26.RELATIONSHIP_STATE_NAMES);
7323
7403
  function registerRelationshipsCommand(root) {
7324
7404
  root.command("relationships").description(
7325
7405
  "List relationships <did> belongs to (live + closed pairs, ordered by lastEventAt desc). DID can be passed positionally OR via --from-did; if both are omitted the resolver picks the sole local agent for the server (see `heyarp config set server` + multi-DID disambiguation rules)."
7326
- ).argument("[did]", "Agent DID (did:arp:...) \u2014 must have local state. Optional when --from-did is given OR exactly one agent is registered for the resolved server.").option("--server <url>", "Override ARP server base URL").option("--state <s>", "Filter by relationship state (pending|active|paused|closed)").option("--limit <n>", "Max relationships to return (1..100)", "20").option("--verbose", "Print the full JSON for each relationship in addition to the table", false).option("--from-did <did>", "Alias for the positional <did> argument \u2014 accepted for consistency with other signed commands. Must match the positional if both are given.").action(async (did, opts) => {
7406
+ ).argument("[did]", "Agent DID (did:arp:...) \u2014 must have local state. Optional when --from-did is given OR exactly one agent is registered for the resolved server.").option("--server <url>", "Override ARP server base URL").option("--state <s>", "Filter by relationship state (pending|active|paused|closed)").option("--limit <n>", "Max relationships to return (1..100)", "20").option("--verbose", "Print the full JSON for each relationship in addition to the table. Mutually exclusive with --json.", false).option(
7407
+ "--json",
7408
+ "Machine-readable mode \u2014 emit the relationships as a single JSON array on stdout (RelationshipPublic[]). Prelude + table move to stderr. Mutually exclusive with --verbose.",
7409
+ false
7410
+ ).option("--from-did <did>", "Alias for the positional <did> argument \u2014 accepted for consistency with other signed commands. Must match the positional if both are given.").action(async (did, opts) => {
7327
7411
  await runRelationships(did, opts);
7328
7412
  });
7329
7413
  }
7330
7414
  async function runRelationships(positionalDid, opts) {
7415
+ if (opts.verbose && opts.json) {
7416
+ throw new Error(
7417
+ "relationships: --verbose and --json are mutually exclusive. --json emits the rows as a clean array; --verbose adds per-row dumps that would break `--json | jq`."
7418
+ );
7419
+ }
7331
7420
  const limit = parseLimit6(opts.limit);
7332
7421
  const state = parseState2(opts.state);
7333
7422
  if (positionalDid !== void 0 && opts.fromDid !== void 0 && positionalDid !== opts.fromDid) {
@@ -7337,25 +7426,29 @@ async function runRelationships(positionalDid, opts) {
7337
7426
  const local = explicitDid !== void 0 ? loadAgentOrThrow(opts.server, explicitDid) : resolveSenderAgent("relationships", opts.server, void 0);
7338
7427
  const did = local.did;
7339
7428
  const api = new ArpApiClient(opts.server);
7340
- console.log(import_chalk26.default.dim(`Server: ${api.serverUrl}`));
7341
- console.log(import_chalk26.default.dim(`Signer: ${local.did}`));
7429
+ progress(opts.json, import_chalk28.default.dim(`Server: ${api.serverUrl}`));
7430
+ progress(opts.json, import_chalk28.default.dim(`Signer: ${local.did}`));
7342
7431
  const query = { limit };
7343
7432
  if (state) query.state = state;
7344
7433
  const signer = makeSigner(local);
7345
7434
  const rows = await api.listRelationships(did, signer, query);
7435
+ if (opts.json) {
7436
+ jsonOut(rows);
7437
+ return;
7438
+ }
7346
7439
  if (rows.length === 0) {
7347
- console.log(import_chalk26.default.dim("\n(no relationships)"));
7440
+ console.log(import_chalk28.default.dim("\n(no relationships)"));
7348
7441
  return;
7349
7442
  }
7350
7443
  console.log("");
7351
7444
  console.log(formatRelationshipsTable(rows, did));
7352
7445
  if (opts.verbose) {
7353
- console.log(import_chalk26.default.bold("\nFull relationships:"));
7446
+ console.log(import_chalk28.default.bold("\nFull relationships:"));
7354
7447
  for (const r of rows) {
7355
7448
  console.log(formatJson(r));
7356
7449
  }
7357
7450
  }
7358
- console.log(import_chalk26.default.dim(`
7451
+ console.log(import_chalk28.default.dim(`
7359
7452
  ${rows.length} relationship(s).`));
7360
7453
  }
7361
7454
  function formatRelationshipsTable(rows, selfDid) {
@@ -7363,7 +7456,7 @@ function formatRelationshipsTable(rows, selfDid) {
7363
7456
  const data = rows.map((r) => [r.relationshipId, otherPair(r, selfDid), r.state, r.lastEventAt ?? "(none)", String(r.lastEventIndex)]);
7364
7457
  const widths = header.map((h, i) => Math.max(h.length, ...data.map((row) => row[i].length)));
7365
7458
  const pad = (cells) => cells.map((c, i) => c.padEnd(widths[i])).join(" ");
7366
- return [import_chalk26.default.bold(pad(header)), import_chalk26.default.dim(pad(widths.map((w) => "-".repeat(w)))), ...data.map((row) => pad(row))].join("\n");
7459
+ return [import_chalk28.default.bold(pad(header)), import_chalk28.default.dim(pad(widths.map((w) => "-".repeat(w)))), ...data.map((row) => pad(row))].join("\n");
7367
7460
  }
7368
7461
  function otherPair(r, selfDid) {
7369
7462
  if (r.pairDidA === selfDid) return r.pairDidB;
@@ -7387,12 +7480,12 @@ function parseLimit6(raw) {
7387
7480
  }
7388
7481
 
7389
7482
  // src/commands/reputation.ts
7390
- var import_sdk17 = require("@heyanon-arp/sdk");
7391
- var import_chalk27 = __toESM(require("chalk"));
7483
+ var import_sdk27 = require("@heyanon-arp/sdk");
7484
+ var import_chalk29 = __toESM(require("chalk"));
7392
7485
  init_api();
7393
7486
  function registerReputationCommand(root) {
7394
7487
  root.command("reputation").description("Show an agent's informational reputation (composite + component scores + raw counters). Public, no auth. NOT a money/eligibility gate.").argument("<did>", "did:arp:<base58btc> identifier").option("--server <url>", "Override ARP server base URL").option("--json", "Emit the reputation as JSON on stdout.", false).action(async (did, opts) => {
7395
- if (!(0, import_sdk17.isValidDid)(did)) {
7488
+ if (!(0, import_sdk27.isValidDid)(did)) {
7396
7489
  throw new Error(`'${did}' is not a syntactically valid did:arp identifier`);
7397
7490
  }
7398
7491
  const api = new ArpApiClient(opts.server);
@@ -7404,10 +7497,10 @@ function registerReputationCommand(root) {
7404
7497
  const s = rep.scores;
7405
7498
  const c = rep.counters;
7406
7499
  const j = false;
7407
- progress(j, import_chalk27.default.bold(`Reputation \u2014 ${did}`));
7500
+ progress(j, import_chalk29.default.bold(`Reputation \u2014 ${did}`));
7408
7501
  progress(
7409
7502
  j,
7410
- import_chalk27.default.dim(` ${rep.informational ? "INFORMATIONAL" : "GATING"} \xB7 ${rep.computed ? `computed ${rep.lastComputedAt}` : "never computed (neutral cold-start)"}`)
7503
+ import_chalk29.default.dim(` ${rep.informational ? "INFORMATIONAL" : "GATING"} \xB7 ${rep.computed ? `computed ${rep.lastComputedAt}` : "never computed (neutral cold-start)"}`)
7411
7504
  );
7412
7505
  progress(j, "");
7413
7506
  progress(j, ` composite ${bar(s.composite)} ${s.composite.toFixed(2)}`);
@@ -7415,17 +7508,17 @@ function registerReputationCommand(root) {
7415
7508
  progress(j, ` settlement ${bar(s.settlement)} ${s.settlement.toFixed(2)}`);
7416
7509
  progress(j, ` dispute health ${bar(s.disputeHealth)} ${s.disputeHealth.toFixed(2)}`);
7417
7510
  progress(j, "");
7418
- progress(j, import_chalk27.default.dim(" evidence:"));
7511
+ progress(j, import_chalk29.default.dim(" evidence:"));
7419
7512
  progress(
7420
7513
  j,
7421
- import_chalk27.default.dim(
7514
+ import_chalk29.default.dim(
7422
7515
  ` on-chain cycles ${c.onchainCycles} \xB7 completed ${c.completedDelegations} (payer ${c.completedAsPayer} / payee ${c.completedAsPayee}) \xB7 failed ${c.failedDelegations}`
7423
7516
  )
7424
7517
  );
7425
- progress(j, import_chalk27.default.dim(` escrows settled ${c.settledEscrows} / refunded ${c.refundedEscrows} \xB7 disputed ${c.disputedEscrows} (adverse ${c.disputesAdverse})`));
7426
- progress(j, import_chalk27.default.dim(` distinct counterparts ${c.distinctCounterparts} \xB7 active relationships ${c.activeRelationships}`));
7518
+ progress(j, import_chalk29.default.dim(` escrows settled ${c.settledEscrows} / refunded ${c.refundedEscrows} \xB7 disputed ${c.disputedEscrows} (adverse ${c.disputesAdverse})`));
7519
+ progress(j, import_chalk29.default.dim(` distinct counterparts ${c.distinctCounterparts} \xB7 active relationships ${c.activeRelationships}`));
7427
7520
  progress(j, "");
7428
- progress(j, import_chalk27.default.dim(" Informational only \u2014 a discovery-sort signal, not a money or eligibility gate."));
7521
+ progress(j, import_chalk29.default.dim(" Informational only \u2014 a discovery-sort signal, not a money or eligibility gate."));
7429
7522
  });
7430
7523
  }
7431
7524
  function bar(score) {
@@ -7434,11 +7527,11 @@ function bar(score) {
7434
7527
  }
7435
7528
 
7436
7529
  // src/commands/send-handshake.ts
7437
- var import_sdk18 = require("@heyanon-arp/sdk");
7438
- var import_chalk28 = __toESM(require("chalk"));
7530
+ var import_sdk28 = require("@heyanon-arp/sdk");
7531
+ var import_chalk30 = __toESM(require("chalk"));
7439
7532
  init_api();
7440
7533
  function registerSendHandshakeCommand(root) {
7441
- root.command("send-handshake").description("Send a handshake envelope to <recipient-did>. Server creates the relationship row on first contact.").argument("<recipient-did>", "Recipient agent DID (did:arp:...)").option("--server <url>", "Override ARP server base URL").option("--from-did <did>", "Sender DID \u2014 required only if multiple agents are registered against this server").option("--greeting <s>", "Optional greeting text included in body.content").option("--intent <s>", "Optional intent text included in body.content").option("--ttl <seconds>", "Envelope TTL in seconds (max 86400 = 24h)", "3600").option("--verbose", "Print the full envelope before sending and the full server response. Mutually exclusive with --json.", false).option(
7534
+ root.command("send-handshake").description("Send a handshake envelope to a recipient (agent name or DID). Server creates the relationship row on first contact.").argument("<recipient>", "Recipient \u2014 agent name (handle) or DID (did:arp:...)").option("--server <url>", "Override ARP server base URL").option("--from-did <did>", "Sender DID \u2014 required only if multiple agents are registered against this server").option("--greeting <s>", "Optional greeting text included in body.content").option("--intent <s>", "Optional intent text included in body.content").option("--ttl <seconds>", `Envelope TTL in seconds (max ${import_sdk28.MAX_ENVELOPE_TTL_SECONDS} = 24h)`, "3600").option("--verbose", "Print the full envelope before sending and the full server response. Mutually exclusive with --json.", false).option(
7442
7535
  "--json",
7443
7536
  "Machine-readable mode \u2014 emit a single JSON object on stdout ({ok, eventId, relationshipId, relationshipEventIndex, serverTimestamp, signedMessageHash, serverEventHash, prevServerEventHash, senderSequence}). The Server/Sender/Recipient prelude moves to stderr so `--json | jq` stays byte-pure. Mutually exclusive with --verbose.",
7444
7537
  false
@@ -7447,46 +7540,44 @@ function registerSendHandshakeCommand(root) {
7447
7540
  });
7448
7541
  }
7449
7542
  async function runSendHandshake(recipientDid, opts) {
7450
- if (!isDid(recipientDid)) {
7451
- throw new Error(`send-handshake: <recipient-did> must look like 'did:arp:...' (got '${recipientDid}')`);
7452
- }
7453
7543
  if (opts.verbose && opts.json) {
7454
7544
  throw new Error(
7455
7545
  "send-handshake: --verbose and --json are mutually exclusive. --json emits the structured server response; --verbose adds envelope + response dumps that would break `--json | jq`."
7456
7546
  );
7457
7547
  }
7548
+ recipientDid = await resolveRecipient(opts.server, "send-handshake", recipientDid, { json: opts.json });
7458
7549
  const ttlSeconds = parseTtl3(opts.ttl);
7459
7550
  const api = new ArpApiClient(opts.server);
7460
- progress(opts.json, import_chalk28.default.dim(`Server: ${api.serverUrl}`));
7551
+ progress(opts.json, import_chalk30.default.dim(`Server: ${api.serverUrl}`));
7461
7552
  const sender = resolveSenderAgent("send-handshake", opts.server, opts.fromDid);
7462
- progress(opts.json, import_chalk28.default.dim(`Sender: ${sender.did}`));
7463
- progress(opts.json, import_chalk28.default.dim(`Recipient: ${recipientDid}`));
7553
+ progress(opts.json, import_chalk30.default.dim(`Sender: ${sender.did}`));
7554
+ progress(opts.json, import_chalk30.default.dim(`Recipient: ${recipientDid}`));
7464
7555
  const content = {};
7465
7556
  if (opts.greeting) content.greeting = opts.greeting;
7466
7557
  if (opts.intent) content.intent = opts.intent;
7467
7558
  const body = { type: "handshake", content };
7468
7559
  const nextSequence = (sender.lastSenderSequence ?? 0) + 1;
7469
7560
  const protectedBlock = {
7470
- protocol_version: "arp/0.1",
7471
- purpose: import_sdk18.Purpose.ENVELOPE,
7472
- message_id: (0, import_sdk18.uuidV4)(),
7561
+ protocol_version: import_sdk28.CURRENT_PROTOCOL_VERSION,
7562
+ purpose: import_sdk28.Purpose.ENVELOPE,
7563
+ message_id: (0, import_sdk28.uuidV4)(),
7473
7564
  sender_did: sender.did,
7474
7565
  recipient_did: recipientDid,
7475
7566
  relationship_id: null,
7476
7567
  sender_sequence: nextSequence,
7477
- sender_nonce: (0, import_sdk18.senderNonce)(),
7478
- timestamp: (0, import_sdk18.rfc3339)(),
7479
- expires_at: (0, import_sdk18.expiresAt)(ttlSeconds),
7568
+ sender_nonce: (0, import_sdk28.senderNonce)(),
7569
+ timestamp: (0, import_sdk28.rfc3339)(),
7570
+ expires_at: (0, import_sdk28.expiresAt)(ttlSeconds),
7480
7571
  delivery_id: null
7481
7572
  };
7482
7573
  const signer = makeSigner(sender);
7483
- const envelope = (0, import_sdk18.signEnvelope)({
7574
+ const envelope = (0, import_sdk28.signEnvelope)({
7484
7575
  protected: protectedBlock,
7485
7576
  body,
7486
7577
  identitySecretKey: signer.identitySecretKey
7487
7578
  });
7488
7579
  if (opts.verbose) {
7489
- console.log(import_chalk28.default.bold("\nEnvelope (pre-send):"));
7580
+ console.log(import_chalk30.default.bold("\nEnvelope (pre-send):"));
7490
7581
  console.log(formatJson(envelope));
7491
7582
  }
7492
7583
  const result = await api.ingest(envelope);
@@ -7494,6 +7585,7 @@ async function runSendHandshake(recipientDid, opts) {
7494
7585
  if (opts.json) {
7495
7586
  jsonOut({
7496
7587
  ok: true,
7588
+ action: "handshake",
7497
7589
  eventId: result.eventId,
7498
7590
  relationshipId: result.relationshipId,
7499
7591
  relationshipEventIndex: result.relationshipEventIndex,
@@ -7505,23 +7597,23 @@ async function runSendHandshake(recipientDid, opts) {
7505
7597
  });
7506
7598
  return;
7507
7599
  }
7508
- console.log(import_chalk28.default.green("\nDelivered."));
7509
- console.log(`${import_chalk28.default.bold("Event id")}: ${import_chalk28.default.cyan(result.eventId)}`);
7510
- console.log(`${import_chalk28.default.bold("Relationship id")}: ${import_chalk28.default.cyan(result.relationshipId)}`);
7511
- console.log(`${import_chalk28.default.bold("Chain index")}: ${import_chalk28.default.cyan(String(result.relationshipEventIndex))}`);
7512
- console.log(`${import_chalk28.default.bold("Server timestamp")}: ${import_chalk28.default.cyan(result.serverTimestamp)}`);
7513
- console.log(`${import_chalk28.default.bold("Signed message hash")}: ${import_chalk28.default.cyan(result.signedMessageHash)}`);
7514
- console.log(`${import_chalk28.default.bold("Server event hash")}: ${import_chalk28.default.cyan(result.serverEventHash)}`);
7600
+ console.log(import_chalk30.default.green("\nDelivered."));
7601
+ console.log(`${import_chalk30.default.bold("Event id")}: ${import_chalk30.default.cyan(result.eventId)}`);
7602
+ console.log(`${import_chalk30.default.bold("Relationship id")}: ${import_chalk30.default.cyan(result.relationshipId)}`);
7603
+ console.log(`${import_chalk30.default.bold("Chain index")}: ${import_chalk30.default.cyan(String(result.relationshipEventIndex))}`);
7604
+ console.log(`${import_chalk30.default.bold("Server timestamp")}: ${import_chalk30.default.cyan(result.serverTimestamp)}`);
7605
+ console.log(`${import_chalk30.default.bold("Signed message hash")}: ${import_chalk30.default.cyan(result.signedMessageHash)}`);
7606
+ console.log(`${import_chalk30.default.bold("Server event hash")}: ${import_chalk30.default.cyan(result.serverEventHash)}`);
7515
7607
  if (result.prevServerEventHash) {
7516
- console.log(`${import_chalk28.default.bold("Prev server event hash")}: ${import_chalk28.default.cyan(result.prevServerEventHash)}`);
7608
+ console.log(`${import_chalk30.default.bold("Prev server event hash")}: ${import_chalk30.default.cyan(result.prevServerEventHash)}`);
7517
7609
  } else {
7518
- console.log(`${import_chalk28.default.bold("Prev server event hash")}: ${import_chalk28.default.dim("(null \u2014 first event of this relationship)")}`);
7610
+ console.log(`${import_chalk30.default.bold("Prev server event hash")}: ${import_chalk30.default.dim("(null \u2014 first event of this relationship)")}`);
7519
7611
  }
7520
7612
  if (opts.verbose) {
7521
- console.log(import_chalk28.default.bold("\nFull server response:"));
7613
+ console.log(import_chalk30.default.bold("\nFull server response:"));
7522
7614
  console.log(formatJson(result));
7523
7615
  }
7524
- console.log(import_chalk28.default.dim(`
7616
+ console.log(import_chalk30.default.dim(`
7525
7617
  Local sender_sequence advanced to ${nextSequence}.`));
7526
7618
  }
7527
7619
  function parseTtl3(raw) {
@@ -7532,15 +7624,12 @@ function parseTtl3(raw) {
7532
7624
  }
7533
7625
  return n;
7534
7626
  }
7535
- function isDid(s) {
7536
- return typeof s === "string" && s.startsWith("did:arp:") && s.length > "did:arp:".length;
7537
- }
7538
7627
 
7539
7628
  // src/commands/send-handshake-response.ts
7540
- var import_sdk19 = require("@heyanon-arp/sdk");
7541
- var import_chalk29 = __toESM(require("chalk"));
7629
+ var import_sdk29 = require("@heyanon-arp/sdk");
7630
+ var import_chalk31 = __toESM(require("chalk"));
7542
7631
  init_api();
7543
- var ALLOWED_DECISIONS = /* @__PURE__ */ new Set(["accept", "decline"]);
7632
+ var ALLOWED_DECISIONS = new Set(import_sdk29.HANDSHAKE_DECISIONS);
7544
7633
  function registerSendHandshakeResponseCommand(root) {
7545
7634
  root.command("send-handshake-response").description("Accept or decline an inbound handshake from <recipient-did>. Server reuses the existing relationship row.").argument("<recipient-did>", "Recipient agent DID (did:arp:...) \u2014 the original handshake sender").option("--server <url>", "Override ARP server base URL").option("--from-did <did>", "Sender DID \u2014 required only if multiple agents are registered against this server").option("--decision <s>", "REQUIRED: accept or decline").option("--notes <s>", "Optional notes included in body.content").option(
7546
7635
  "--reason <code>",
@@ -7548,8 +7637,8 @@ function registerSendHandshakeResponseCommand(root) {
7548
7637
  // We don't use commander's requiredOption because it
7549
7638
  // would fire for the accept path too; validate manually
7550
7639
  // after decision is parsed.
7551
- `When --decision=decline: required reason code (one of: ${import_sdk19.DECLINE_REASONS.join(", ")}). Carried in body.content.reason.`
7552
- ).option("--reason-detail <s>", "Optional free-text elaboration alongside --reason (max 512 chars).").option("--ttl <seconds>", "Envelope TTL in seconds (max 86400 = 24h)", "3600").option("--verbose", "Print the full envelope before sending and the full server response. Mutually exclusive with --json.", false).option(
7640
+ `When --decision=decline: required reason code (one of: ${import_sdk29.DECLINE_REASONS.join(", ")}). Carried in body.content.reason.`
7641
+ ).option("--reason-detail <s>", "Optional free-text elaboration alongside --reason (max 512 chars).").option("--ttl <seconds>", `Envelope TTL in seconds (max ${import_sdk29.MAX_ENVELOPE_TTL_SECONDS} = 24h)`, "3600").option("--verbose", "Print the full envelope before sending and the full server response. Mutually exclusive with --json.", false).option(
7553
7642
  "--json",
7554
7643
  "Machine-readable mode \u2014 emit a single JSON object on stdout ({ok, decision, eventId, relationshipId, relationshipEventIndex, serverTimestamp, serverEventHash, prevServerEventHash}; idempotent short-circuit adds {idempotent:true}). Prelude + banners move off stdout; on failure stderr carries `{code, message}`. Mutually exclusive with --verbose.",
7555
7644
  false
@@ -7567,23 +7656,23 @@ async function runSendHandshakeResponse(recipientDid, opts) {
7567
7656
  "send-handshake-response: --verbose and --json are mutually exclusive. --json emits the structured server response; --verbose adds envelope + response dumps that would break `--json | jq`."
7568
7657
  );
7569
7658
  }
7570
- if (!isDid2(recipientDid)) {
7571
- throw new Error(`send-handshake-response: <recipient-did> must look like 'did:arp:...' (got '${recipientDid}')`);
7659
+ if (!(0, import_sdk29.isValidDid)(recipientDid)) {
7660
+ throw new Error(`send-handshake-response: <recipient-did> must be a valid did:arp identifier (base58btc-encoded 32-byte Ed25519 pubkey) (got '${recipientDid}')`);
7572
7661
  }
7573
7662
  const decision = parseDecision(opts.decision);
7574
7663
  const ttlSeconds = parseTtl4(opts.ttl);
7575
7664
  let declinePayload = null;
7576
- if (decision === "decline") {
7665
+ if (decision === import_sdk29.HandshakeDecisions.DECLINE) {
7577
7666
  const reason = parseDeclineReason("send-handshake-response", opts.reason);
7578
7667
  const detail = parseReasonDetail("send-handshake-response", opts.reasonDetail);
7579
7668
  declinePayload = detail ? { reason, reasonDetail: detail } : { reason };
7580
7669
  }
7581
7670
  const api = new ArpApiClient(opts.server);
7582
- progress(opts.json, import_chalk29.default.dim(`Server: ${api.serverUrl}`));
7671
+ progress(opts.json, import_chalk31.default.dim(`Server: ${api.serverUrl}`));
7583
7672
  const sender = resolveSenderAgent("send-handshake-response", opts.server, opts.fromDid);
7584
- progress(opts.json, import_chalk29.default.dim(`Sender: ${sender.did}`));
7585
- progress(opts.json, import_chalk29.default.dim(`Recipient: ${recipientDid}`));
7586
- progress(opts.json, import_chalk29.default.dim(`Decision: ${decision}`));
7673
+ progress(opts.json, import_chalk31.default.dim(`Sender: ${sender.did}`));
7674
+ progress(opts.json, import_chalk31.default.dim(`Recipient: ${recipientDid}`));
7675
+ progress(opts.json, import_chalk31.default.dim(`Decision: ${decision}`));
7587
7676
  const signer = makeSigner(sender);
7588
7677
  if (!opts.force) {
7589
7678
  try {
@@ -7599,6 +7688,7 @@ async function runSendHandshakeResponse(recipientDid, opts) {
7599
7688
  if (opts.json) {
7600
7689
  jsonOut({
7601
7690
  ok: true,
7691
+ action: "handshake_response",
7602
7692
  idempotent: true,
7603
7693
  decision,
7604
7694
  eventId: previousResponseFromMe.eventId,
@@ -7612,13 +7702,13 @@ async function runSendHandshakeResponse(recipientDid, opts) {
7612
7702
  });
7613
7703
  return;
7614
7704
  }
7615
- progress(opts.json, import_chalk29.default.yellow(`
7705
+ progress(opts.json, import_chalk31.default.yellow(`
7616
7706
  [--idempotency] Relationship ${existing.relationshipId} with ${recipientDid} is already 'active'.`));
7617
7707
  progress(
7618
7708
  opts.json,
7619
- import_chalk29.default.dim(`A previous accept from this signer (event ${previousResponseFromMe.eventId}) landed successfully. Skipping re-send (use --force to override).`)
7709
+ import_chalk31.default.dim(`A previous accept from this signer (event ${previousResponseFromMe.eventId}) landed successfully. Skipping re-send (use --force to override).`)
7620
7710
  );
7621
- progress(opts.json, import_chalk29.default.dim(`Last event index: ${existing.lastEventIndex}, last server event hash: ${existing.lastServerEventHash ?? "(none)"}`));
7711
+ progress(opts.json, import_chalk31.default.dim(`Last event index: ${existing.lastEventIndex}, last server event hash: ${existing.lastServerEventHash ?? "(none)"}`));
7622
7712
  return;
7623
7713
  }
7624
7714
  throw new Error(
@@ -7629,7 +7719,7 @@ async function runSendHandshakeResponse(recipientDid, opts) {
7629
7719
  if (probeErr instanceof Error && /CLOSED|terminated|already 'active' from a previous ACCEPT|original initiator/i.test(probeErr.message)) {
7630
7720
  throw probeErr;
7631
7721
  }
7632
- progress(opts.json, import_chalk29.default.dim(`(idempotency probe failed; proceeding anyway: ${probeErr.message})`));
7722
+ progress(opts.json, import_chalk31.default.dim(`(idempotency probe failed; proceeding anyway: ${probeErr.message})`));
7633
7723
  }
7634
7724
  }
7635
7725
  const content = { decision };
@@ -7641,25 +7731,25 @@ async function runSendHandshakeResponse(recipientDid, opts) {
7641
7731
  const body = { type: "handshake_response", content };
7642
7732
  const nextSequence = (sender.lastSenderSequence ?? 0) + 1;
7643
7733
  const protectedBlock = {
7644
- protocol_version: "arp/0.1",
7645
- purpose: import_sdk19.Purpose.ENVELOPE,
7646
- message_id: (0, import_sdk19.uuidV4)(),
7734
+ protocol_version: import_sdk29.CURRENT_PROTOCOL_VERSION,
7735
+ purpose: import_sdk29.Purpose.ENVELOPE,
7736
+ message_id: (0, import_sdk29.uuidV4)(),
7647
7737
  sender_did: sender.did,
7648
7738
  recipient_did: recipientDid,
7649
7739
  relationship_id: null,
7650
7740
  sender_sequence: nextSequence,
7651
- sender_nonce: (0, import_sdk19.senderNonce)(),
7652
- timestamp: (0, import_sdk19.rfc3339)(),
7653
- expires_at: (0, import_sdk19.expiresAt)(ttlSeconds),
7741
+ sender_nonce: (0, import_sdk29.senderNonce)(),
7742
+ timestamp: (0, import_sdk29.rfc3339)(),
7743
+ expires_at: (0, import_sdk29.expiresAt)(ttlSeconds),
7654
7744
  delivery_id: null
7655
7745
  };
7656
- const envelope = (0, import_sdk19.signEnvelope)({
7746
+ const envelope = (0, import_sdk29.signEnvelope)({
7657
7747
  protected: protectedBlock,
7658
7748
  body,
7659
7749
  identitySecretKey: signer.identitySecretKey
7660
7750
  });
7661
7751
  if (opts.verbose) {
7662
- console.log(import_chalk29.default.bold("\nEnvelope (pre-send):"));
7752
+ console.log(import_chalk31.default.bold("\nEnvelope (pre-send):"));
7663
7753
  console.log(formatJson(envelope));
7664
7754
  }
7665
7755
  const result = await api.ingest(envelope);
@@ -7667,6 +7757,7 @@ async function runSendHandshakeResponse(recipientDid, opts) {
7667
7757
  if (opts.json) {
7668
7758
  jsonOut({
7669
7759
  ok: true,
7760
+ action: "handshake_response",
7670
7761
  decision,
7671
7762
  eventId: result.eventId,
7672
7763
  relationshipId: result.relationshipId,
@@ -7679,23 +7770,23 @@ async function runSendHandshakeResponse(recipientDid, opts) {
7679
7770
  });
7680
7771
  return;
7681
7772
  }
7682
- console.log(import_chalk29.default.green("\nDelivered."));
7683
- console.log(`${import_chalk29.default.bold("Event id")}: ${import_chalk29.default.cyan(result.eventId)}`);
7684
- console.log(`${import_chalk29.default.bold("Relationship id")}: ${import_chalk29.default.cyan(result.relationshipId)}`);
7685
- console.log(`${import_chalk29.default.bold("Chain index")}: ${import_chalk29.default.cyan(String(result.relationshipEventIndex))}`);
7686
- console.log(`${import_chalk29.default.bold("Server timestamp")}: ${import_chalk29.default.cyan(result.serverTimestamp)}`);
7687
- console.log(`${import_chalk29.default.bold("Signed message hash")}: ${import_chalk29.default.cyan(result.signedMessageHash)}`);
7688
- console.log(`${import_chalk29.default.bold("Server event hash")}: ${import_chalk29.default.cyan(result.serverEventHash)}`);
7773
+ console.log(import_chalk31.default.green("\nDelivered."));
7774
+ console.log(`${import_chalk31.default.bold("Event id")}: ${import_chalk31.default.cyan(result.eventId)}`);
7775
+ console.log(`${import_chalk31.default.bold("Relationship id")}: ${import_chalk31.default.cyan(result.relationshipId)}`);
7776
+ console.log(`${import_chalk31.default.bold("Chain index")}: ${import_chalk31.default.cyan(String(result.relationshipEventIndex))}`);
7777
+ console.log(`${import_chalk31.default.bold("Server timestamp")}: ${import_chalk31.default.cyan(result.serverTimestamp)}`);
7778
+ console.log(`${import_chalk31.default.bold("Signed message hash")}: ${import_chalk31.default.cyan(result.signedMessageHash)}`);
7779
+ console.log(`${import_chalk31.default.bold("Server event hash")}: ${import_chalk31.default.cyan(result.serverEventHash)}`);
7689
7780
  if (result.prevServerEventHash) {
7690
- console.log(`${import_chalk29.default.bold("Prev server event hash")}: ${import_chalk29.default.cyan(result.prevServerEventHash)}`);
7781
+ console.log(`${import_chalk31.default.bold("Prev server event hash")}: ${import_chalk31.default.cyan(result.prevServerEventHash)}`);
7691
7782
  } else {
7692
- console.log(`${import_chalk29.default.bold("Prev server event hash")}: ${import_chalk29.default.dim("(null \u2014 first event of this relationship)")}`);
7783
+ console.log(`${import_chalk31.default.bold("Prev server event hash")}: ${import_chalk31.default.dim("(null \u2014 first event of this relationship)")}`);
7693
7784
  }
7694
7785
  if (opts.verbose) {
7695
- console.log(import_chalk29.default.bold("\nFull server response:"));
7786
+ console.log(import_chalk31.default.bold("\nFull server response:"));
7696
7787
  console.log(formatJson(result));
7697
7788
  }
7698
- console.log(import_chalk29.default.dim(`
7789
+ console.log(import_chalk31.default.dim(`
7699
7790
  Local sender_sequence advanced to ${nextSequence}.`));
7700
7791
  }
7701
7792
  function parseDecision(raw) {
@@ -7715,13 +7806,10 @@ function parseTtl4(raw) {
7715
7806
  }
7716
7807
  return n;
7717
7808
  }
7718
- function isDid2(s) {
7719
- return typeof s === "string" && s.startsWith("did:arp:") && s.length > "did:arp:".length;
7720
- }
7721
7809
  function classifyIdempotencyOutcome(decision, existing) {
7722
7810
  if (!existing) return { kind: "proceed" };
7723
- if (existing.state === "active") {
7724
- if (decision === "decline") {
7811
+ if (existing.state === import_sdk29.RelationshipStates.ACTIVE) {
7812
+ if (decision === import_sdk29.HandshakeDecisions.DECLINE) {
7725
7813
  return {
7726
7814
  kind: "error",
7727
7815
  message: `send-handshake-response: relationship ${existing.relationshipId} is already 'active' from a previous ACCEPT. A decline cannot reverse that \u2014 the active relationship is now under FSM control. If you want to terminate, close the relationship explicitly; pass --force to ignore this check and send the decline (which the server will reject with DOM_INVALID_TRANSITION).`
@@ -7729,7 +7817,7 @@ function classifyIdempotencyOutcome(decision, existing) {
7729
7817
  }
7730
7818
  return { kind: "short-circuit" };
7731
7819
  }
7732
- if (existing.state === "closed") {
7820
+ if (existing.state === import_sdk29.RelationshipStates.CLOSED) {
7733
7821
  return {
7734
7822
  kind: "error",
7735
7823
  message: `send-handshake-response: relationship ${existing.relationshipId} is CLOSED. Cannot respond to handshake on a terminated relationship \u2014 start a fresh handshake instead.`
@@ -7749,7 +7837,7 @@ async function findExistingRelationship(api, signer, senderDid, recipientDid) {
7749
7837
  }
7750
7838
 
7751
7839
  // src/commands/watch.ts
7752
- var import_chalk30 = __toESM(require("chalk"));
7840
+ var import_chalk32 = __toESM(require("chalk"));
7753
7841
  init_api();
7754
7842
  function registerWatchCommand(root) {
7755
7843
  root.command("watch").description("Live tail filtered to a single relationship (SSE). Server-side $match; only envelopes belonging to <rel-id> are streamed.").argument("<relationship-id>", "Relationship UUID to watch").option("--server <url>", "Override ARP server base URL").option("--from-did <did>", "Signer DID \u2014 required only if multiple agents are registered against this server").option("--verbose", "After each envelope, print the full JSON with a per-row label including eventId + serverEventHash", false).option("--json", "Machine-readable: one NDJSON object per line. Pipe-safe into `jq -c`.", false).option("--full-ids", "Print DIDs + serverEventHash in full (no truncation).", false).action(async (relationshipId, opts) => {
@@ -7760,9 +7848,9 @@ async function runWatch(relationshipId, opts) {
7760
7848
  const local = resolveSenderAgent("watch", opts.server, opts.fromDid);
7761
7849
  const api = new ArpApiClient(opts.server);
7762
7850
  if (!opts.json) {
7763
- console.log(import_chalk30.default.dim(`Server: ${api.serverUrl}`));
7764
- console.log(import_chalk30.default.dim(`Signer: ${local.did}`));
7765
- console.log(import_chalk30.default.dim(`Watching: ${relationshipId}`));
7851
+ console.log(import_chalk32.default.dim(`Server: ${api.serverUrl}`));
7852
+ console.log(import_chalk32.default.dim(`Signer: ${local.did}`));
7853
+ console.log(import_chalk32.default.dim(`Watching: ${relationshipId}`));
7766
7854
  }
7767
7855
  const controller = new AbortController();
7768
7856
  let userAborted = false;
@@ -7781,7 +7869,7 @@ async function runWatch(relationshipId, opts) {
7781
7869
  }
7782
7870
  if (event.type === "heartbeat") continue;
7783
7871
  if (event.type === "connected") {
7784
- console.log(import_chalk30.default.green(`\u25CF stream open \u2014 watching ${relationshipId}`));
7872
+ console.log(import_chalk32.default.green(`\u25CF stream open \u2014 watching ${relationshipId}`));
7785
7873
  continue;
7786
7874
  }
7787
7875
  if (event.type === "envelope") {
@@ -7795,7 +7883,7 @@ async function runWatch(relationshipId, opts) {
7795
7883
  }
7796
7884
  continue;
7797
7885
  }
7798
- console.log(import_chalk30.default.dim(`(unknown event: ${event.type})`));
7886
+ console.log(import_chalk32.default.dim(`(unknown event: ${event.type})`));
7799
7887
  }
7800
7888
  if (!userAborted) {
7801
7889
  throw new Error(`watch ${relationshipId}: stream ended unexpectedly (server may have restarted, or the change stream errored). Re-run to reconnect.`);
@@ -7803,7 +7891,7 @@ async function runWatch(relationshipId, opts) {
7803
7891
  } catch (err) {
7804
7892
  const name = err.name;
7805
7893
  if (name === "AbortError" || userAborted) {
7806
- if (!opts.json) console.log(import_chalk30.default.dim("\nstream closed."));
7894
+ if (!opts.json) console.log(import_chalk32.default.dim("\nstream closed."));
7807
7895
  return;
7808
7896
  }
7809
7897
  throw err;
@@ -7817,21 +7905,21 @@ function formatWatchLine(ev, selfDid, opts = {}) {
7817
7905
  const type = ev.type.padEnd(20);
7818
7906
  const direction = directionLabel2(ev, selfDid, opts);
7819
7907
  const hash = opts.fullIds ? ev.serverEventHash : hashHead4(ev.serverEventHash);
7820
- return `${import_chalk30.default.dim(`[${ts}]`)} ${type} ${direction} ${import_chalk30.default.cyan(hash)}`;
7908
+ return `${import_chalk32.default.dim(`[${ts}]`)} ${type} ${direction} ${import_chalk32.default.cyan(hash)}`;
7821
7909
  }
7822
7910
  function directionLabel2(ev, selfDid, opts = {}) {
7823
7911
  const senderHead = opts.fullIds ? ev.senderDid : didHead4(ev.senderDid);
7824
7912
  const recipientHead = opts.fullIds ? ev.recipientDid : didHead4(ev.recipientDid);
7825
- if (ev.senderDid === selfDid) return `${import_chalk30.default.bold("me")} \u2192 ${import_chalk30.default.dim(recipientHead)}`;
7826
- if (ev.recipientDid === selfDid) return `${import_chalk30.default.dim(senderHead)} \u2192 ${import_chalk30.default.bold("me")}`;
7827
- return `${import_chalk30.default.dim(senderHead)} \u2192 ${import_chalk30.default.dim(recipientHead)}`;
7913
+ if (ev.senderDid === selfDid) return `${import_chalk32.default.bold("me")} \u2192 ${import_chalk32.default.dim(recipientHead)}`;
7914
+ if (ev.recipientDid === selfDid) return `${import_chalk32.default.dim(senderHead)} \u2192 ${import_chalk32.default.bold("me")}`;
7915
+ return `${import_chalk32.default.dim(senderHead)} \u2192 ${import_chalk32.default.dim(recipientHead)}`;
7828
7916
  }
7829
7917
  function didHead4(did) {
7830
7918
  if (did.length <= 20) return did;
7831
7919
  return `${did.slice(0, 20)}...`;
7832
7920
  }
7833
7921
  function hashHead4(hash) {
7834
- if (!hash) return import_chalk30.default.dim("(none)");
7922
+ if (!hash) return import_chalk32.default.dim("(none)");
7835
7923
  if (hash.length <= 14) return hash;
7836
7924
  return `${hash.slice(0, 14)}...`;
7837
7925
  }
@@ -7843,7 +7931,7 @@ function formatClock(iso) {
7843
7931
  }
7844
7932
 
7845
7933
  // src/commands/whoami.ts
7846
- var import_chalk31 = __toESM(require("chalk"));
7934
+ var import_chalk33 = __toESM(require("chalk"));
7847
7935
  init_api();
7848
7936
  function registerWhoamiCommand(root) {
7849
7937
  root.command("whoami").description(
@@ -7873,12 +7961,12 @@ function registerWhoamiCommand(root) {
7873
7961
  if (opts.json) {
7874
7962
  console.log(formatJson({ ...localJson, account: credential ? { wallet: credential.wallet } : null }));
7875
7963
  } else {
7876
- console.log(import_chalk31.default.bold("Local agent:"));
7877
- console.log(` DID: ${import_chalk31.default.cyan(local.did)}`);
7878
- console.log(` Settlement pubkey: ${import_chalk31.default.cyan(local.settlementPublicKeyB58)}`);
7879
- console.log(` Identity pubkey: ${import_chalk31.default.cyan(local.identityPublicKeyB58)}`);
7964
+ console.log(import_chalk33.default.bold("Local agent:"));
7965
+ console.log(` DID: ${import_chalk33.default.cyan(local.did)}`);
7966
+ console.log(` Settlement pubkey: ${import_chalk33.default.cyan(local.settlementPublicKeyB58)}`);
7967
+ console.log(` Identity pubkey: ${import_chalk33.default.cyan(local.identityPublicKeyB58)}`);
7880
7968
  if (local.name) console.log(` Name: ${local.name}`);
7881
- console.log(` Account: ${credential ? import_chalk31.default.cyan(credential.wallet) : import_chalk31.default.dim("not logged in (heyarp login)")}`);
7969
+ console.log(` Account: ${credential ? import_chalk33.default.cyan(credential.wallet) : import_chalk33.default.dim("not logged in (heyarp login)")}`);
7882
7970
  }
7883
7971
  return;
7884
7972
  }
@@ -7896,19 +7984,19 @@ function registerWhoamiCommand(root) {
7896
7984
  if (opts.json) {
7897
7985
  console.log(formatJson({ local: localJson, account, server: agent }));
7898
7986
  } else {
7899
- console.log(import_chalk31.default.dim(`Server: ${api.serverUrl}`));
7900
- console.log(import_chalk31.default.bold("\nLocal agent:"));
7901
- console.log(` DID: ${import_chalk31.default.cyan(local.did)}`);
7902
- console.log(` Settlement pubkey: ${import_chalk31.default.cyan(local.settlementPublicKeyB58)}`);
7903
- console.log(` Identity pubkey: ${import_chalk31.default.cyan(local.identityPublicKeyB58)}`);
7904
- console.log(import_chalk31.default.bold("\nAccount:"));
7987
+ console.log(import_chalk33.default.dim(`Server: ${api.serverUrl}`));
7988
+ console.log(import_chalk33.default.bold("\nLocal agent:"));
7989
+ console.log(` DID: ${import_chalk33.default.cyan(local.did)}`);
7990
+ console.log(` Settlement pubkey: ${import_chalk33.default.cyan(local.settlementPublicKeyB58)}`);
7991
+ console.log(` Identity pubkey: ${import_chalk33.default.cyan(local.identityPublicKeyB58)}`);
7992
+ console.log(import_chalk33.default.bold("\nAccount:"));
7905
7993
  if (account) {
7906
- console.log(` Wallet: ${import_chalk31.default.cyan(account.wallet)}`);
7994
+ console.log(` Wallet: ${import_chalk33.default.cyan(account.wallet)}`);
7907
7995
  console.log(` Agents registered: ${account.agentCount}`);
7908
7996
  } else {
7909
- console.log(` ${import_chalk31.default.dim("not logged in (heyarp login)")}`);
7997
+ console.log(` ${import_chalk33.default.dim("not logged in (heyarp login)")}`);
7910
7998
  }
7911
- console.log(import_chalk31.default.bold("\nServer profile:"));
7999
+ console.log(import_chalk33.default.bold("\nServer profile:"));
7912
8000
  console.log(formatJson(agent));
7913
8001
  }
7914
8002
  } catch (err) {
@@ -7918,47 +8006,77 @@ function registerWhoamiCommand(root) {
7918
8006
  });
7919
8007
  }
7920
8008
 
8009
+ // src/commands/whois.ts
8010
+ var import_sdk30 = require("@heyanon-arp/sdk");
8011
+ var import_chalk34 = __toESM(require("chalk"));
8012
+ init_api();
8013
+ function registerWhoisCommand(root) {
8014
+ root.command("whois").description("Resolve an agent name (handle) or DID to its public profile \u2014 DID, description, reputation, liveness.").argument("<name-or-did>", "Agent name (handle) or DID (did:arp:...)").option("--server <url>", "Override ARP server base URL").option("--json", "Emit the full composed profile (DiscoveryProfile) as a single JSON object on stdout.", false).action(async (input, opts) => {
8015
+ const api = new ArpApiClient(opts.server);
8016
+ progress(opts.json, import_chalk34.default.dim(`Server: ${api.serverUrl}`));
8017
+ const profile = await resolveProfile(api, input);
8018
+ if (opts.json) {
8019
+ jsonOut(profile);
8020
+ return;
8021
+ }
8022
+ printProfile(profile);
8023
+ });
8024
+ }
8025
+ async function resolveProfile(api, input) {
8026
+ if (input.startsWith("did:arp:")) {
8027
+ if (!(0, import_sdk30.isValidDid)(input)) {
8028
+ throw new Error(`whois: '${input}' starts with did:arp: but is not a valid DID (base58btc-encoded 32-byte Ed25519 pubkey).`);
8029
+ }
8030
+ return api.discoverProfile(input);
8031
+ }
8032
+ const name = (0, import_sdk30.normalizeName)(input);
8033
+ if (!(0, import_sdk30.isValidAgentName)(name)) {
8034
+ throw new Error(`whois: '${input}' is neither a DID (did:arp:...) nor a valid agent name (lowercase a-z0-9_, 3-32 chars).`);
8035
+ }
8036
+ return api.discoverByName(name);
8037
+ }
8038
+ function printProfile(p) {
8039
+ console.log(`${import_chalk34.default.bold("Name")}: ${import_chalk34.default.cyan(p.name ?? "(unnamed)")}`);
8040
+ console.log(`${import_chalk34.default.bold("DID")}: ${import_chalk34.default.cyan(p.did)}`);
8041
+ if (p.description) console.log(`${import_chalk34.default.bold("Description")}: ${p.description}`);
8042
+ if (p.tags.length > 0) console.log(`${import_chalk34.default.bold("Tags")}: ${p.tags.join(", ")}`);
8043
+ console.log(`${import_chalk34.default.bold("Registered")}: ${p.registeredAt}`);
8044
+ const rep = p.reputation;
8045
+ console.log(`${import_chalk34.default.bold("Reputation")}: composite ${rep.scores.composite}/100${rep.computed ? "" : import_chalk34.default.dim(" (cold-start \u2014 no settled cycles yet)")}`);
8046
+ console.log(`${import_chalk34.default.bold("Online")}: ${p.liveness.online ? import_chalk34.default.green("yes") : import_chalk34.default.dim("no")}`);
8047
+ }
8048
+
7921
8049
  // src/commands/work.ts
7922
- var import_sdk20 = require("@heyanon-arp/sdk");
7923
- var import_chalk32 = __toESM(require("chalk"));
8050
+ var import_sdk31 = require("@heyanon-arp/sdk");
8051
+ var import_chalk35 = __toESM(require("chalk"));
7924
8052
  init_api();
7925
8053
  function registerWorkCommands(root) {
7926
8054
  const cmd = root.command("work").description("Work envelopes inside an ACCEPTED delegation: request / respond");
7927
8055
  registerRequest(cmd);
7928
8056
  registerRespond(cmd);
7929
8057
  }
7930
- var POST_COMMIT_ERROR_CODES3 = /* @__PURE__ */ new Set([
7931
- "WORK_DELEGATION_NOT_FOUND",
7932
- "WORK_DELEGATION_NOT_ACTIVE",
7933
- "WORK_RELATIONSHIP_MISMATCH",
7934
- "WORK_REQUESTER_NOT_OFFERER",
7935
- "WORK_REQUEST_ALREADY_EXISTS",
7936
- "WORK_REQUEST_NOT_FOUND",
7937
- "WORK_RESPONDER_IS_CALLER",
7938
- "WORK_INVALID_STATE",
7939
- // The work handler's LOCKED gate emits
7940
- // `DELEGATION_PENDING_LOCK` (409) when the delegation is funded but
7941
- // the on-chain lock isn't confirmed yet (state
7942
- // `pending_lock_finalization`). It fires from the body handler AFTER
7943
- // the event row is committed — same lifecycle as
7944
- // `WORK_DELEGATION_NOT_ACTIVE` — so the CLI must advance
7945
- // `lastSenderSequence`, otherwise a retry once the lock confirms
7946
- // reuses the consumed sequence and trips `ENV_SEQUENCE_BACKWARDS`.
7947
- "DELEGATION_PENDING_LOCK"
7948
- ]);
7949
8058
  function registerRequest(parent) {
7950
- parent.command("request").description("Send a work_request to <recipient-did> under <delegation-id> (must be ACCEPTED).").argument("<recipient-did>", "Recipient agent DID (the payee \u2014 the OTHER side of the delegation pair)").argument("<delegation-id>", "Parent delegation id (UUID, must be ACCEPTED)").option("--server <url>", "Override ARP server base URL").option("--from-did <did>", "Sender DID \u2014 required only if multiple agents are registered against this server").option("--request-id <id>", "Override the auto-generated request id (must be unique within the delegation)").option(
8059
+ parent.command("request").description("Send a work_request to <recipient-did> under <delegation-id> (must be ACCEPTED).").argument("<recipient>", "Recipient \u2014 agent name (handle) or DID (the payee \u2014 the OTHER side of the delegation pair)").argument("<delegation-id>", "Parent delegation id (UUID, must be ACCEPTED)").option("--server <url>", "Override ARP server base URL").option("--from-did <did>", "Sender DID \u2014 required only if multiple agents are registered against this server").option("--request-id <id>", "Override the auto-generated request id (must be unique within the delegation)").option(
7951
8060
  "--params <json>",
7952
8061
  "JSON object payload as a literal string. Defaults to {}. Mutually exclusive with --params-file. Brittle against shell quoting \u2014 prefer --params-file for non-trivial bodies."
7953
8062
  ).option(
7954
8063
  "--params-file <path>",
7955
8064
  "Read the JSON payload from a file. Mutually exclusive with --params. Use this for any payload large or quote-heavy enough that `--params '{...}'` would fight your shell."
7956
- ).option("--ttl <seconds>", "Envelope TTL in seconds (max 86400 = 24h)", "3600").option("--verbose", "Print the full envelope before sending and the full server response", false).action(async (recipientDid, delegationId, opts) => {
8065
+ ).option("--ttl <seconds>", `Envelope TTL in seconds (max ${import_sdk31.MAX_ENVELOPE_TTL_SECONDS} = 24h)`, "3600").option("--verbose", "Print the full envelope before sending and the full server response. Mutually exclusive with --json.", false).option(
8066
+ "--json",
8067
+ 'Machine-readable mode \u2014 emit a single JSON object on stdout ({ok, action:"work_request", requestId, delegationId, eventId, relationshipId, relationshipEventIndex, serverTimestamp, serverEventHash}). Prelude + reply hints move to stderr; on failure stderr carries `{code, message}`. Mutually exclusive with --verbose.',
8068
+ false
8069
+ ).action(async (recipientDid, delegationId, opts) => {
7957
8070
  await runRequest(recipientDid, delegationId, opts);
7958
8071
  });
7959
8072
  }
7960
8073
  async function runRequest(recipientDid, delegationId, opts) {
7961
- requireDid3("work request", recipientDid, "<recipient-did>");
8074
+ if (opts.verbose && opts.json) {
8075
+ throw new Error(
8076
+ "work request: --verbose and --json are mutually exclusive. --json emits the structured server response; --verbose adds dumps that would break `--json | jq`."
8077
+ );
8078
+ }
8079
+ recipientDid = await resolveRecipient(opts.server, "work request", recipientDid, { json: opts.json });
7962
8080
  delegationId = requireUuidNormalised3("work request", delegationId, "<delegation-id>");
7963
8081
  const ttlSeconds = parseTtl5("work request", opts.ttl);
7964
8082
  const params = parseParamsInput("work request", opts);
@@ -7971,27 +8089,51 @@ async function runRequest(recipientDid, delegationId, opts) {
7971
8089
  params
7972
8090
  };
7973
8091
  const body = { type: "work_request", content };
7974
- console.log(import_chalk32.default.dim(`Server: ${api.serverUrl}`));
7975
- console.log(import_chalk32.default.dim(`Sender: ${sender.did}`));
7976
- console.log(import_chalk32.default.dim(`Recipient: ${recipientDid}`));
7977
- console.log(import_chalk32.default.dim(`Delegation: ${delegationId}`));
7978
- console.log(import_chalk32.default.dim(`Request id: ${requestId}`));
8092
+ progress(opts.json, import_chalk35.default.dim(`Server: ${api.serverUrl}`));
8093
+ progress(opts.json, import_chalk35.default.dim(`Sender: ${sender.did}`));
8094
+ progress(opts.json, import_chalk35.default.dim(`Recipient: ${recipientDid}`));
8095
+ progress(opts.json, import_chalk35.default.dim(`Delegation: ${delegationId}`));
8096
+ progress(opts.json, import_chalk35.default.dim(`Request id: ${requestId}`));
7979
8097
  const result = await sendWorkEnvelope({ api, sender, recipientDid, body, ttlSeconds, verbose: opts.verbose, server: opts.server });
7980
- printIngestResult3(result);
7981
- console.log(import_chalk32.default.dim(`
8098
+ if (opts.json) {
8099
+ jsonOut({
8100
+ ok: true,
8101
+ action: "work_request",
8102
+ requestId,
8103
+ delegationId,
8104
+ eventId: result.eventId,
8105
+ relationshipId: result.relationshipId,
8106
+ relationshipEventIndex: result.relationshipEventIndex,
8107
+ serverTimestamp: result.serverTimestamp,
8108
+ serverEventHash: result.serverEventHash,
8109
+ prevServerEventHash: result.prevServerEventHash ?? null
8110
+ });
8111
+ } else {
8112
+ printIngestResult3(result);
8113
+ console.log(import_chalk35.default.dim(`
7982
8114
  The payee can reply with:`));
7983
- console.log(import_chalk32.default.dim(` heyarp work respond ${result.relationshipId} ${delegationId} ${requestId} --output '<json>'`));
7984
- console.log(import_chalk32.default.dim(` heyarp work respond ${result.relationshipId} ${delegationId} ${requestId} --error CODE:message`));
8115
+ console.log(import_chalk35.default.dim(` heyarp work respond ${result.relationshipId} ${delegationId} ${requestId} --output '<json>'`));
8116
+ console.log(import_chalk35.default.dim(` heyarp work respond ${result.relationshipId} ${delegationId} ${requestId} --error CODE:message`));
8117
+ }
7985
8118
  }
7986
8119
  function registerRespond(parent) {
7987
8120
  parent.command("respond").description("Send a work_response under <relationship-id> for <delegation-id> / <request-id>. Payee-only.").argument("<relationship-id>", "Relationship UUID").argument("<delegation-id>", "Parent delegation id (UUID)").argument("<request-id>", "Request id supplied on the work_request").option("--server <url>", "Override ARP server base URL").option("--from-did <did>", "Sender DID \u2014 required only if multiple agents are registered against this server").option("--output <json>", "Success payload as a JSON object literal. Mutually exclusive with --error and --output-file.").option(
7988
8121
  "--output-file <path>",
7989
8122
  "Read the success payload from a file. Mutually exclusive with --output and --error. Use this for any payload large or quote-heavy enough to fight your shell."
7990
- ).option("--error <code:message>", "Failure payload as `CODE:message`. Mutually exclusive with --output / --output-file.").option("--ttl <seconds>", "Envelope TTL in seconds", "3600").option("--verbose", "Print the full envelope before sending and the full server response", false).action(async (relationshipId, delegationId, requestId, opts) => {
8123
+ ).option("--error <code:message>", "Failure payload as `CODE:message`. Mutually exclusive with --output / --output-file.").option("--ttl <seconds>", "Envelope TTL in seconds", "3600").option("--verbose", "Print the full envelope before sending and the full server response. Mutually exclusive with --json.", false).option(
8124
+ "--json",
8125
+ 'Machine-readable mode \u2014 emit a single JSON object on stdout ({ok, action:"work_response", requestId, delegationId, eventId, relationshipId, relationshipEventIndex, serverTimestamp, serverEventHash}). Prelude moves to stderr; on failure stderr carries `{code, message}`. Mutually exclusive with --verbose.',
8126
+ false
8127
+ ).action(async (relationshipId, delegationId, requestId, opts) => {
7991
8128
  await runRespond(relationshipId, delegationId, requestId, opts);
7992
8129
  });
7993
8130
  }
7994
8131
  async function runRespond(relationshipId, delegationId, requestId, opts) {
8132
+ if (opts.verbose && opts.json) {
8133
+ throw new Error(
8134
+ "work respond: --verbose and --json are mutually exclusive. --json emits the structured server response; --verbose adds dumps that would break `--json | jq`."
8135
+ );
8136
+ }
7995
8137
  relationshipId = requireUuidNormalised3("work respond", relationshipId, "<relationship-id>");
7996
8138
  delegationId = requireUuidNormalised3("work respond", delegationId, "<delegation-id>");
7997
8139
  const ttlSeconds = parseTtl5("work respond", opts.ttl);
@@ -8006,39 +8148,54 @@ async function runRespond(relationshipId, delegationId, requestId, opts) {
8006
8148
  ...responsePayload
8007
8149
  };
8008
8150
  const body = { type: "work_response", content };
8009
- console.log(import_chalk32.default.dim(`Server: ${api.serverUrl}`));
8010
- console.log(import_chalk32.default.dim(`Sender: ${sender.did}`));
8011
- console.log(import_chalk32.default.dim(`Recipient: ${recipientDid}`));
8012
- console.log(import_chalk32.default.dim(`Relationship: ${relationshipId}`));
8013
- console.log(import_chalk32.default.dim(`Delegation: ${delegationId}`));
8014
- console.log(import_chalk32.default.dim(`Request id: ${requestId}`));
8015
- console.log(import_chalk32.default.dim(`Outcome: ${responsePayload.output ? "success" : "error"}`));
8151
+ progress(opts.json, import_chalk35.default.dim(`Server: ${api.serverUrl}`));
8152
+ progress(opts.json, import_chalk35.default.dim(`Sender: ${sender.did}`));
8153
+ progress(opts.json, import_chalk35.default.dim(`Recipient: ${recipientDid}`));
8154
+ progress(opts.json, import_chalk35.default.dim(`Relationship: ${relationshipId}`));
8155
+ progress(opts.json, import_chalk35.default.dim(`Delegation: ${delegationId}`));
8156
+ progress(opts.json, import_chalk35.default.dim(`Request id: ${requestId}`));
8157
+ progress(opts.json, import_chalk35.default.dim(`Outcome: ${responsePayload.output ? "success" : "error"}`));
8016
8158
  const result = await sendWorkEnvelope({ api, sender, recipientDid, body, ttlSeconds, verbose: opts.verbose, server: opts.server });
8017
- printIngestResult3(result);
8159
+ if (opts.json) {
8160
+ jsonOut({
8161
+ ok: true,
8162
+ action: "work_response",
8163
+ requestId,
8164
+ delegationId,
8165
+ eventId: result.eventId,
8166
+ relationshipId: result.relationshipId,
8167
+ relationshipEventIndex: result.relationshipEventIndex,
8168
+ serverTimestamp: result.serverTimestamp,
8169
+ serverEventHash: result.serverEventHash,
8170
+ prevServerEventHash: result.prevServerEventHash ?? null
8171
+ });
8172
+ } else {
8173
+ printIngestResult3(result);
8174
+ }
8018
8175
  }
8019
8176
  async function sendWorkEnvelope(args) {
8020
8177
  const nextSequence = (args.sender.lastSenderSequence ?? 0) + 1;
8021
8178
  const protectedBlock = {
8022
- protocol_version: "arp/0.1",
8023
- purpose: import_sdk20.Purpose.ENVELOPE,
8024
- message_id: (0, import_sdk20.uuidV4)(),
8179
+ protocol_version: import_sdk31.CURRENT_PROTOCOL_VERSION,
8180
+ purpose: import_sdk31.Purpose.ENVELOPE,
8181
+ message_id: (0, import_sdk31.uuidV4)(),
8025
8182
  sender_did: args.sender.did,
8026
8183
  recipient_did: args.recipientDid,
8027
8184
  relationship_id: null,
8028
8185
  sender_sequence: nextSequence,
8029
- sender_nonce: (0, import_sdk20.senderNonce)(),
8030
- timestamp: (0, import_sdk20.rfc3339)(),
8031
- expires_at: (0, import_sdk20.expiresAt)(args.ttlSeconds),
8186
+ sender_nonce: (0, import_sdk31.senderNonce)(),
8187
+ timestamp: (0, import_sdk31.rfc3339)(),
8188
+ expires_at: (0, import_sdk31.expiresAt)(args.ttlSeconds),
8032
8189
  delivery_id: null
8033
8190
  };
8034
8191
  const signer = makeSigner(args.sender);
8035
- const envelope = (0, import_sdk20.signEnvelope)({
8192
+ const envelope = (0, import_sdk31.signEnvelope)({
8036
8193
  protected: protectedBlock,
8037
8194
  body: args.body,
8038
8195
  identitySecretKey: signer.identitySecretKey
8039
8196
  });
8040
8197
  if (args.verbose) {
8041
- console.log(import_chalk32.default.bold("\nEnvelope (pre-send):"));
8198
+ console.log(import_chalk35.default.bold("\nEnvelope (pre-send):"));
8042
8199
  console.log(formatJson(envelope));
8043
8200
  }
8044
8201
  try {
@@ -8046,7 +8203,7 @@ async function sendWorkEnvelope(args) {
8046
8203
  updateAgentLocal(args.server, args.sender.did, { lastSenderSequence: nextSequence });
8047
8204
  return result;
8048
8205
  } catch (err) {
8049
- if (err instanceof ApiError && POST_COMMIT_ERROR_CODES3.has(err.payload.code)) {
8206
+ if (err instanceof ApiError && (0, import_sdk31.isPostCommitErrorCode)(err.payload.code)) {
8050
8207
  updateAgentLocal(args.server, args.sender.did, { lastSenderSequence: nextSequence });
8051
8208
  }
8052
8209
  throw err;
@@ -8058,7 +8215,7 @@ async function resolveResponseRecipient(cmdName, api, signer, args) {
8058
8215
  const page = await api.listWorkLogs(args.relationshipId, signer, { delegationId: args.delegationId, limit: 100, after });
8059
8216
  const row = page.find((w) => w.requestId === args.requestId);
8060
8217
  if (row) {
8061
- if (row.state !== "requested") {
8218
+ if (row.state !== import_sdk31.WorkLogStates.REQUESTED) {
8062
8219
  throw new Error(
8063
8220
  `${cmdName}: work_request ${args.requestId} for delegation ${args.delegationId} is already in state '${row.state}' \u2014 only requests in state 'requested' can be responded to.`
8064
8221
  );
@@ -8078,12 +8235,12 @@ async function resolveResponseRecipient(cmdName, api, signer, args) {
8078
8235
  );
8079
8236
  }
8080
8237
  function printIngestResult3(result) {
8081
- console.log(import_chalk32.default.green("\nDelivered."));
8082
- console.log(`${import_chalk32.default.bold("Event id")}: ${import_chalk32.default.cyan(result.eventId)}`);
8083
- console.log(`${import_chalk32.default.bold("Relationship id")}: ${import_chalk32.default.cyan(result.relationshipId)}`);
8084
- console.log(`${import_chalk32.default.bold("Chain index")}: ${import_chalk32.default.cyan(String(result.relationshipEventIndex))}`);
8085
- console.log(`${import_chalk32.default.bold("Server timestamp")}: ${import_chalk32.default.cyan(result.serverTimestamp)}`);
8086
- console.log(`${import_chalk32.default.bold("Server event hash")}: ${import_chalk32.default.cyan(result.serverEventHash)}`);
8238
+ console.log(import_chalk35.default.green("\nDelivered."));
8239
+ console.log(`${import_chalk35.default.bold("Event id")}: ${import_chalk35.default.cyan(result.eventId)}`);
8240
+ console.log(`${import_chalk35.default.bold("Relationship id")}: ${import_chalk35.default.cyan(result.relationshipId)}`);
8241
+ console.log(`${import_chalk35.default.bold("Chain index")}: ${import_chalk35.default.cyan(String(result.relationshipEventIndex))}`);
8242
+ console.log(`${import_chalk35.default.bold("Server timestamp")}: ${import_chalk35.default.cyan(result.serverTimestamp)}`);
8243
+ console.log(`${import_chalk35.default.bold("Server event hash")}: ${import_chalk35.default.cyan(result.serverEventHash)}`);
8087
8244
  }
8088
8245
  function parseJsonObject(cmdName, flagName, raw) {
8089
8246
  let parsed;
@@ -8175,7 +8332,7 @@ function parseTtl5(cmdName, raw) {
8175
8332
  }
8176
8333
  function parseRequestId(cmdName, raw) {
8177
8334
  if (raw === void 0 || raw === "") {
8178
- return (0, import_sdk20.uuidV4)();
8335
+ return (0, import_sdk31.uuidV4)();
8179
8336
  }
8180
8337
  if (raw.length === 0) {
8181
8338
  throw new Error(`${cmdName}: --request-id must be a non-empty string`);
@@ -8189,16 +8346,12 @@ function requireUuidNormalised3(cmdName, raw, label) {
8189
8346
  function requireUuid4(cmdName, raw, label) {
8190
8347
  requireUuid(cmdName, raw, label);
8191
8348
  }
8192
- function requireDid3(cmdName, did, label) {
8193
- if (typeof did !== "string" || !did.startsWith("did:arp:") || did.length <= "did:arp:".length) {
8194
- throw new Error(`${cmdName}: ${label} must look like 'did:arp:...' (got '${did}')`);
8195
- }
8196
- }
8197
8349
 
8198
8350
  // src/commands/work-list.ts
8199
- var import_chalk33 = __toESM(require("chalk"));
8351
+ var import_sdk32 = require("@heyanon-arp/sdk");
8352
+ var import_chalk36 = __toESM(require("chalk"));
8200
8353
  init_api();
8201
- var ALLOWED_STATES3 = /* @__PURE__ */ new Set(["requested", "responded"]);
8354
+ var ALLOWED_STATES3 = new Set(import_sdk32.WORK_LOG_STATES);
8202
8355
  function registerWorkListCommand(root) {
8203
8356
  root.command("work-list").description("List work-log rows for a relationship (one row per (delegationId, requestId), oldest-first)").argument("<relationship-id>", "Relationship UUID").option("--server <url>", "Override ARP server base URL").option("--state <s>", "Filter by exact state (requested|responded)").option("--delegation-id <uuid>", "Narrow to work-logs operating under a specific delegation id").option("--after <id>", "Cursor: pass the previous page's last `id` to fetch the next page").option("--limit <n>", "Max rows to return (1..100)", "20").option("--from-did <did>", "Signer DID \u2014 required only if multiple agents are registered against this server").option(
8204
8357
  "--verbose",
@@ -8223,9 +8376,9 @@ async function runWorkList(relationshipId, opts) {
8223
8376
  const api = new ArpApiClient(opts.server);
8224
8377
  const sender = resolveSenderAgent("work-list", opts.server, opts.fromDid);
8225
8378
  if (!opts.json) {
8226
- console.log(import_chalk33.default.dim(`Server: ${api.serverUrl}`));
8227
- console.log(import_chalk33.default.dim(`Signer: ${sender.did}`));
8228
- console.log(import_chalk33.default.dim(`Relationship: ${relationshipId}`));
8379
+ console.log(import_chalk36.default.dim(`Server: ${api.serverUrl}`));
8380
+ console.log(import_chalk36.default.dim(`Signer: ${sender.did}`));
8381
+ console.log(import_chalk36.default.dim(`Relationship: ${relationshipId}`));
8229
8382
  }
8230
8383
  const query = { limit };
8231
8384
  if (state) query.state = state;
@@ -8238,7 +8391,7 @@ async function runWorkList(relationshipId, opts) {
8238
8391
  return;
8239
8392
  }
8240
8393
  if (rows.length === 0) {
8241
- console.log(import_chalk33.default.dim("\n(no work-logs for this relationship)"));
8394
+ console.log(import_chalk36.default.dim("\n(no work-logs for this relationship)"));
8242
8395
  return;
8243
8396
  }
8244
8397
  console.log("");
@@ -8255,36 +8408,36 @@ async function runWorkList(relationshipId, opts) {
8255
8408
  }));
8256
8409
  }
8257
8410
  const lastId = rows[rows.length - 1].id;
8258
- console.log(import_chalk33.default.dim(`
8411
+ console.log(import_chalk36.default.dim(`
8259
8412
  ${rows.length} work-log row(s). Paginate with --after ${lastId}.`));
8260
8413
  }
8261
8414
  function formatWorkLogLine(w, selfDid, opts = {}) {
8262
8415
  const delegationPart = opts.fullIds ? w.delegationId : idHead3(w.delegationId);
8263
8416
  const requestPart = opts.fullIds ? w.requestId : truncate3(w.requestId, 16);
8264
- const id = import_chalk33.default.bold(`${delegationPart}/${requestPart}`);
8417
+ const id = import_chalk36.default.bold(`${delegationPart}/${requestPart}`);
8265
8418
  const state = colorState2(w.state).padEnd(stateColumnWidth2());
8266
8419
  const peerCallerHead = opts.fullIds ? w.callerDid : didHead5(w.callerDid);
8267
8420
  const peerPayeeHead = opts.fullIds ? w.payeeDid : didHead5(w.payeeDid);
8268
- const direction = w.callerDid === selfDid ? `${import_chalk33.default.bold("me")} \u2192 ${import_chalk33.default.dim(peerPayeeHead)}` : `${import_chalk33.default.dim(peerCallerHead)} \u2192 ${import_chalk33.default.bold("me")}`;
8421
+ const direction = w.callerDid === selfDid ? `${import_chalk36.default.bold("me")} \u2192 ${import_chalk36.default.dim(peerPayeeHead)}` : `${import_chalk36.default.dim(peerCallerHead)} \u2192 ${import_chalk36.default.bold("me")}`;
8269
8422
  const outcome = formatOutcome(w);
8270
8423
  return `${id} ${state} ${direction} ${outcome}`;
8271
8424
  }
8272
8425
  function colorState2(s) {
8273
8426
  switch (s) {
8274
- case "requested":
8275
- return import_chalk33.default.yellow("requested");
8276
- case "responded":
8277
- return import_chalk33.default.green("responded");
8427
+ case import_sdk32.WorkLogStates.REQUESTED:
8428
+ return import_chalk36.default.yellow("requested");
8429
+ case import_sdk32.WorkLogStates.RESPONDED:
8430
+ return import_chalk36.default.green("responded");
8278
8431
  }
8279
8432
  }
8280
8433
  function stateColumnWidth2() {
8281
8434
  return 9;
8282
8435
  }
8283
8436
  function formatOutcome(w) {
8284
- if (w.state === "requested") return import_chalk33.default.dim("(in flight)");
8285
- if (w.responseError) return import_chalk33.default.red(`error ${w.responseError.code}: ${truncate3(w.responseError.message, 32)}`);
8286
- if (w.responseOutput) return import_chalk33.default.cyan("ok");
8287
- return import_chalk33.default.dim("(empty response)");
8437
+ if (w.state === import_sdk32.WorkLogStates.REQUESTED) return import_chalk36.default.dim("(in flight)");
8438
+ if (w.responseError) return import_chalk36.default.red(`error ${w.responseError.code}: ${truncate3(w.responseError.message, 32)}`);
8439
+ if (w.responseOutput) return import_chalk36.default.cyan("ok");
8440
+ return import_chalk36.default.dim("(empty response)");
8288
8441
  }
8289
8442
  function idHead3(id) {
8290
8443
  if (id.length <= 12) return id;
@@ -8314,6 +8467,43 @@ function parseLimit7(raw) {
8314
8467
  return n;
8315
8468
  }
8316
8469
 
8470
+ // src/option-hint.ts
8471
+ function unknownOptionHint(program, err) {
8472
+ try {
8473
+ if (err.code !== "commander.unknownOption" || !err.message) return null;
8474
+ const m = /unknown option '([^']+)'/.exec(err.message);
8475
+ if (!m) return null;
8476
+ const raw = m[1];
8477
+ const flag = raw.split("=")[0];
8478
+ const owners = [];
8479
+ const walk = (cmd, path) => {
8480
+ for (const opt of cmd.options) {
8481
+ if (opt.long === flag || opt.short === flag) owners.push(path.join(" "));
8482
+ }
8483
+ for (const sub of cmd.commands) walk(sub, [...path, sub.name()]);
8484
+ };
8485
+ for (const sub of program.commands) walk(sub, [sub.name()]);
8486
+ if (owners.length === 0) return null;
8487
+ owners.sort((a, b) => a.split(" ").length - b.split(" ").length);
8488
+ const argv = process.argv.slice(2);
8489
+ const commandNames = /* @__PURE__ */ new Set();
8490
+ for (const c of program.commands) {
8491
+ commandNames.add(c.name());
8492
+ for (const a of c.aliases()) commandNames.add(a);
8493
+ }
8494
+ const flagIdx = argv.findIndex((t) => t === raw || t.split("=")[0] === flag);
8495
+ const cmdIdx = argv.findIndex((t) => commandNames.has(t));
8496
+ const placedBeforeCommand = cmdIdx === -1 || flagIdx !== -1 && flagIdx < cmdIdx;
8497
+ if (placedBeforeCommand) {
8498
+ return `'${flag}' is a command option, not a global one \u2014 put it AFTER the command (e.g. \`heyarp ${owners[0]} ${flag} \u2026\`), not before it.`;
8499
+ }
8500
+ const list = owners.slice(0, 4).join(", ") + (owners.length > 4 ? ", \u2026" : "");
8501
+ return `'${flag}' isn't valid for that command \u2014 it's an option of: ${list}.`;
8502
+ } catch {
8503
+ return null;
8504
+ }
8505
+ }
8506
+
8317
8507
  // src/cli.ts
8318
8508
  async function checkForUpdates() {
8319
8509
  if (package_default.private === true) return;
@@ -8328,7 +8518,7 @@ async function checkForUpdates() {
8328
8518
  async function main() {
8329
8519
  void checkForUpdates();
8330
8520
  const program = new import_commander.Command();
8331
- program.name("heyarp").description("ARP \u2014 Agent Relationship Protocol CLI (talks to apps/arp-server)").version(package_default.version).option("--trace", "Surface stack traces and error details on failure.", false);
8521
+ program.name("heyarp").description("ARP \u2014 Agent Relationship Protocol CLI (talks to apps/arp-server)").version(package_default.version).usage("[global-options] <command> [options]").option("--trace", "Surface stack traces and error details on failure.", false);
8332
8522
  program.exitOverride();
8333
8523
  program.configureOutput({
8334
8524
  writeErr: (str) => {
@@ -8336,6 +8526,7 @@ async function main() {
8336
8526
  process.stderr.write(str);
8337
8527
  }
8338
8528
  });
8529
+ program.addHelpText("after", () => optionPlacementHelpNote());
8339
8530
  program.addHelpText("after", () => onboardingHelpFooter());
8340
8531
  registerConfigCommand(program);
8341
8532
  registerGuideCommand(program);
@@ -8353,6 +8544,8 @@ async function main() {
8353
8544
  registerAssetsCommand(program);
8354
8545
  registerEscrowCommands(program);
8355
8546
  registerWhoamiCommand(program);
8547
+ registerWhoisCommand(program);
8548
+ registerNameCommand(program);
8356
8549
  registerLifecycleCommands(program);
8357
8550
  registerSendHandshakeCommand(program);
8358
8551
  registerSendHandshakeResponseCommand(program);
@@ -8383,10 +8576,13 @@ async function main() {
8383
8576
  const json = process.argv.includes("--json");
8384
8577
  const verbose = process.argv.includes("--trace");
8385
8578
  const exitCode = typeof cerr.exitCode === "number" && cerr.exitCode !== 0 ? cerr.exitCode : 1;
8579
+ const hint = unknownOptionHint(program, cerr);
8386
8580
  if (isCommanderError && !json) {
8581
+ if (hint) process.stderr.write(`hint: ${hint}
8582
+ `);
8387
8583
  process.exit(exitCode);
8388
8584
  }
8389
- emitError(err, { json, verbose });
8585
+ emitError(err, { json, verbose, hint: hint ?? void 0 });
8390
8586
  process.exit(exitCode);
8391
8587
  }
8392
8588
  }