@heyanon-arp/cli 0.0.7 → 0.0.8

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.
package/dist/cli.js CHANGED
@@ -289,8 +289,7 @@ var init_api = __esm({
289
289
  }
290
290
  /**
291
291
  * Public `GET /v1/agents` — discovery / marketplace catalog.
292
- * Unauthenticated. Server pins `publicationStatus = active` so
293
- * drafts / paused agents never appear here.
292
+ * Unauthenticated. Returns registered agents.
294
293
  *
295
294
  * Filters AND-compose: pass multiple tags to require all of them,
296
295
  * combine with `q` for free-text. `after` is the `id` of the
@@ -321,18 +320,6 @@ var init_api = __esm({
321
320
  async updateAgent(did, body, signer) {
322
321
  return this.signedRequest("PATCH", `/v1/agents/${encodeURIComponent(did)}`, body, signer);
323
322
  }
324
- async publishAgent(did, signer) {
325
- return this.signedRequest("POST", `/v1/agents/${encodeURIComponent(did)}/publish`, {}, signer);
326
- }
327
- async pauseAgent(did, signer) {
328
- return this.signedRequest("POST", `/v1/agents/${encodeURIComponent(did)}/pause`, {}, signer);
329
- }
330
- async unpauseAgent(did, signer) {
331
- return this.signedRequest("POST", `/v1/agents/${encodeURIComponent(did)}/unpause`, {}, signer);
332
- }
333
- async rotateIdentityKey(did, body, signer) {
334
- return this.signedRequest("POST", `/v1/agents/${encodeURIComponent(did)}/rotate-identity-key`, body, signer);
335
- }
336
323
  /**
337
324
  * Ingest a signed envelope. Endpoint is public (no
338
325
  * `X-ARP-Signer-DID` headers) — authentication is the envelope's
@@ -933,18 +920,6 @@ var init_state = __esm({
933
920
 
934
921
  // src/commands/lifecycle.ts
935
922
  function registerLifecycleCommands(root) {
936
- root.command("publish").description("Publish a draft agent (draft \u2192 active), making it discoverable in the catalog.").argument("<did>", "Agent DID (did:arp:...) \u2014 must have local state").option("--server <url>", "Override ARP server base URL").action(async (did, opts) => {
937
- const agent = await actSigned(did, opts.server, (api, signer) => api.publishAgent(did, signer));
938
- printAgent("Published", agent);
939
- });
940
- root.command("pause").description("Pause an active agent (active \u2192 paused).").argument("<did>").option("--server <url>", "Override ARP server base URL").action(async (did, opts) => {
941
- const agent = await actSigned(did, opts.server, (api, signer) => api.pauseAgent(did, signer));
942
- printAgent("Paused", agent);
943
- });
944
- root.command("unpause").description("Unpause a paused agent (paused \u2192 active).").argument("<did>").option("--server <url>", "Override ARP server base URL").action(async (did, opts) => {
945
- const agent = await actSigned(did, opts.server, (api, signer) => api.unpauseAgent(did, signer));
946
- printAgent("Unpaused", agent);
947
- });
948
923
  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", accumulate2, []).option("--clear-tags", "Drop all tags (cannot be combined with --tag)", false).action(
949
924
  async (did, opts) => {
950
925
  const body = buildUpdateBody(opts);
@@ -996,7 +971,6 @@ function printAgent(verb, agent) {
996
971
  console.log(import_chalk4.default.green(`
997
972
  ${verb}.`));
998
973
  console.log(`${import_chalk4.default.bold("DID")}: ${import_chalk4.default.cyan(agent.did)}`);
999
- console.log(`${import_chalk4.default.bold("Status")}: ${import_chalk4.default.cyan(agent.publicationStatus)}`);
1000
974
  console.log(import_chalk4.default.bold("\nAgent profile:"));
1001
975
  console.log(formatJson(agent));
1002
976
  }
@@ -1238,9 +1212,11 @@ function isPhaseTerminallyUnreachable(phase, s) {
1238
1212
  function untilPhaseMatched(phase, s) {
1239
1213
  switch (phase) {
1240
1214
  case "delegation.proposed":
1241
- return s.latestDelegation?.state === "proposed" || s.latestDelegation?.state === "offered" || s.latestDelegation?.state === "pending_lock_finalization";
1215
+ return s.latestDelegation?.state === "proposed" || s.latestDelegation?.state === "offered";
1242
1216
  case "delegation.accepted":
1243
1217
  return s.latestDelegation?.state === "accepted";
1218
+ case "delegation.locked":
1219
+ return s.latestDelegation?.state === "locked";
1244
1220
  case "delegation.canceled":
1245
1221
  return s.latestDelegation?.state === "canceled";
1246
1222
  case "delegation.declined":
@@ -1279,7 +1255,7 @@ function parseWaitInterval(raw) {
1279
1255
  return n;
1280
1256
  }
1281
1257
  function sleep(ms) {
1282
- return new Promise((resolve2) => setTimeout(resolve2, ms));
1258
+ return new Promise((resolve) => setTimeout(resolve, ms));
1283
1259
  }
1284
1260
  async function composeStatus(api, signerDid, relationshipId, signer) {
1285
1261
  const [relationshipsOrNull, delegationsOrError] = await Promise.all([
@@ -1315,7 +1291,7 @@ async function composeStatus(api, signerDid, relationshipId, signer) {
1315
1291
  const relationship = relationships.find((r) => r.relationshipId === relationshipId);
1316
1292
  const counterpartyDid = relationship ? relationship.pairDidA === signerDid ? relationship.pairDidB : relationship.pairDidA : inferCounterpartyFromEntities(signerDid, allDelegations);
1317
1293
  const delegations = allDelegations;
1318
- const latestDelegation = pickLatestLive(delegations, ["proposed", "offered", "pending_lock_finalization", "accepted", "awaiting_release_finalization"]);
1294
+ const latestDelegation = pickLatestLive(delegations, ["proposed", "offered", "accepted", "pending_lock_finalization", "locked", "awaiting_release_finalization"]);
1319
1295
  const [workLogs, receipts] = await Promise.all([
1320
1296
  latestDelegation ? fetchAllPages(
1321
1297
  (after) => api.listWorkLogs(relationshipId, signer, { limit: 100, delegationId: latestDelegation.delegationId, ...after ? { after } : {} })
@@ -1437,7 +1413,7 @@ function nextAction(input) {
1437
1413
  }
1438
1414
  if (!latestDelegation || latestDelegation.state === "declined" || latestDelegation.state === "canceled") {
1439
1415
  return {
1440
- hint: "No live delegation \u2014 buyer funds escrow `heyarp wallet create-lock \u2026` then offers `heyarp delegation offer <peer> --delegation-id <new-uuid> --title \u2026 --scope \u2026 --pricing-model flat --settlement-model escrow --amount \u2026 --currency USDC:solana-devnet --deadline \u2026 --escrow-lock-from-file <path>`",
1416
+ hint: "No live delegation \u2014 buyer offers (terms only, no lock) `heyarp delegation offer <peer> --delegation-id <new-uuid> --title \u2026 --scope \u2026 --pricing-model flat --amount \u2026 --currency USDC:solana-devnet --deadline \u2026`, then funds the escrow lock AFTER the worker accepts via `heyarp delegation fund <del-id> --escrow-lock-from-file <path>`",
1441
1417
  owner: "either",
1442
1418
  complete: false
1443
1419
  };
@@ -1451,7 +1427,7 @@ function nextAction(input) {
1451
1427
  complete: false
1452
1428
  };
1453
1429
  }
1454
- if (latestDelegation.state === "proposed" || latestDelegation.state === "offered" || latestDelegation.state === "pending_lock_finalization") {
1430
+ if (latestDelegation.state === "proposed" || latestDelegation.state === "offered") {
1455
1431
  const iAmOfferer = latestDelegation.offererDid === signerDid;
1456
1432
  const stateLabel = latestDelegation.state === "proposed" ? "PROPOSED" : `${latestDelegation.state.toUpperCase()} (\u2261 proposed)`;
1457
1433
  return {
@@ -1460,10 +1436,25 @@ function nextAction(input) {
1460
1436
  complete: false
1461
1437
  };
1462
1438
  }
1439
+ if (latestDelegation.state === "accepted" && !latestWorkLog) {
1440
+ const iAmOfferer = latestDelegation.offererDid === signerDid;
1441
+ return {
1442
+ 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`,
1443
+ owner: iAmOfferer ? "me" : "counterparty",
1444
+ complete: false
1445
+ };
1446
+ }
1447
+ if (latestDelegation.state === "pending_lock_finalization" && !latestWorkLog) {
1448
+ return {
1449
+ 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\`.`,
1450
+ owner: "none",
1451
+ complete: false
1452
+ };
1453
+ }
1463
1454
  if (!latestWorkLog) {
1464
1455
  const iAmOfferer = latestDelegation.offererDid === signerDid;
1465
1456
  return {
1466
- hint: iAmOfferer ? `Delegation ${latestDelegation.delegationId} is ACCEPTED \u2014 you owe \`heyarp work request <peer> ${latestDelegation.delegationId} --request-id <new-uuid> --params '{\u2026}'\`` : `Delegation ${latestDelegation.delegationId} is ACCEPTED \u2014 counterparty (the caller) owes \`heyarp work request\``,
1457
+ hint: iAmOfferer ? `Delegation ${latestDelegation.delegationId} is LOCKED \u2014 you owe \`heyarp work request <peer> ${latestDelegation.delegationId} --request-id <new-uuid> --params '{\u2026}'\`` : `Delegation ${latestDelegation.delegationId} is LOCKED \u2014 counterparty (the caller) owes \`heyarp work request\``,
1467
1458
  owner: iAmOfferer ? "me" : "counterparty",
1468
1459
  complete: false
1469
1460
  };
@@ -1576,7 +1567,7 @@ function cycleHeadline(s) {
1576
1567
  }
1577
1568
  }
1578
1569
  function stateColor(state) {
1579
- const c = state === "active" || state === "accepted" || state === "cosigned" || state === "responded" || state === "completed" ? import_chalk5.default.green : state === "pending" || state === "proposed" || state === "requested" || state === "offered" || state === "pending_lock_finalization" || state === "awaiting_release_finalization" ? import_chalk5.default.yellow : state === "closed" || state === "declined" || state === "canceled" || state === "replaced" || state === "not_found" || // Terminal failure states deserve the same red
1570
+ const c = state === "active" || state === "accepted" || state === "locked" || state === "cosigned" || state === "responded" || state === "completed" ? import_chalk5.default.green : state === "pending" || state === "proposed" || state === "requested" || state === "offered" || state === "pending_lock_finalization" || state === "awaiting_release_finalization" ? import_chalk5.default.yellow : state === "closed" || state === "declined" || state === "canceled" || state === "replaced" || state === "not_found" || // Terminal failure states deserve the same red
1580
1571
  // treatment as declined/canceled so an operator
1581
1572
  // scanning `heyarp status` immediately sees
1582
1573
  // "this is dead, don't follow the hint blindly".
@@ -1594,6 +1585,7 @@ var init_status = __esm({
1594
1585
  UNTIL_PHASES = [
1595
1586
  "delegation.proposed",
1596
1587
  "delegation.accepted",
1588
+ "delegation.locked",
1597
1589
  "delegation.canceled",
1598
1590
  "delegation.declined",
1599
1591
  "work.requested",
@@ -1839,7 +1831,7 @@ async function verifyReleaseHandler(opts) {
1839
1831
  if (shouldRetrySigCheck) {
1840
1832
  const retryDelaysMs = [3e3, 3e3];
1841
1833
  for (const delay of retryDelaysMs) {
1842
- await new Promise((resolve2) => setTimeout(resolve2, delay));
1834
+ await new Promise((resolve) => setTimeout(resolve, delay));
1843
1835
  const retriedSigs = await conn.getSignaturesForAddress(lockPda, { limit: 5 });
1844
1836
  if (retriedSigs.length > 0) {
1845
1837
  lockSeenInSignatures = true;
@@ -1953,7 +1945,7 @@ function mapReleaseMethodToStatus(method) {
1953
1945
  }
1954
1946
  function registerCreateLock(cmd) {
1955
1947
  cmd.command("create-lock").description(
1956
- "Build + sign a create_lock Solana tx (native SOL or an SPL token); output JSON ready for attachments.escrow_lock. This command does NOT submit the tx to chain \u2014 it only signs the blob locally. The actual on-chain submission happens inside `heyarp delegation offer --escrow-lock-from-file <path>` (the server's escrow worker picks up the signed blob from the offer envelope's attachments and posts it). Watch for the `lock_id` appearing on-chain only AFTER `delegation offer` runs, not after this command."
1948
+ "Build + sign a create_lock Solana tx (native SOL or an SPL token); output JSON ready for attachments.escrow_lock. This command does NOT submit the tx to chain \u2014 it only signs the blob locally. M6 lock-at-accept: run this AFTER the worker accepts your offer; the actual on-chain submission happens inside `heyarp delegation fund <delegation-id> --escrow-lock-from-file <path>` (the server's escrow worker picks up the signed blob from the fund envelope's attachments and posts it). Watch for the `lock_id` appearing on-chain only AFTER `delegation fund` runs, not after this command."
1957
1949
  ).option("--server <url>", "Override server URL for sender-key resolution").option("--from-did <did>", "Sender DID (= payer of the lock). Required when more than one agent on the host.").requiredOption("--delegation-id <id>", "Delegation UUID (drives the lock_id derivation)").requiredOption("--recipient-pubkey <base58>", "Payee Solana pubkey (recipient agent's settlement_pubkey)").option("--amount-lamports <int>", "NATIVE SOL: lock amount in lamports (1 SOL = 1_000_000_000). Required when --mint-pubkey is omitted; not allowed with it.").option("--mint-pubkey <base58>", "SPL token mint to lock. Omit for native SOL. Must be a legacy SPL Token mint (Token-2022 is not supported).").option("--amount-base-units <int>", "SPL: lock amount in the mint's base units (e.g. 1000000 = 1 USDC at 6 decimals). Canonical SPL amount input.").option(
1958
1950
  "--amount <decimal>",
1959
1951
  "SPL: lock amount as a human decimal (e.g. 1.5); converted using the mint's on-chain decimals. Convenience alternative to --amount-base-units."
@@ -2199,7 +2191,7 @@ async function createLockHandler(opts) {
2199
2191
  asset_id: asset.assetId,
2200
2192
  expiry: Number(expiry),
2201
2193
  // Persist the BARE UUID form. The consumer is
2202
- // `delegation offer --escrow-lock-from-file`, which validates
2194
+ // `delegation fund --escrow-lock-from-file`, which validates
2203
2195
  // this field with a bare-UUID regex (the wire form for
2204
2196
  // `body.content.delegation_id`). The `del_<uuid>` prefix is an
2205
2197
  // SDK-internal byte-encoding marker — not the wire-form. Keeping
@@ -2385,6 +2377,7 @@ var init_wallet = __esm({
2385
2377
  function registerDelegationCommands(root) {
2386
2378
  const cmd = root.command("delegation").description("Delegation FSM actions: offer / accept / decline / cancel");
2387
2379
  registerOffer(cmd);
2380
+ registerFund(cmd);
2388
2381
  registerAccept(cmd);
2389
2382
  registerDecline(cmd);
2390
2383
  registerCancel(cmd);
@@ -2393,19 +2386,7 @@ function isPostCommitErrorCode(code) {
2393
2386
  return POST_COMMIT_ERROR_CODES.has(code) || code.startsWith("ESC_LOCK_") || code.startsWith("SDK_");
2394
2387
  }
2395
2388
  function registerOffer(parent) {
2396
- parent.command("offer").description("Open a new delegation addressed to <recipient-did> with the agreed terms INLINE.").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). 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 for escrow offers.").option("--pricing-model <flat|usage_based>", "pricing_model (flat|usage_based). Required for escrow offers.").option("--settlement-model <prepaid|escrow>", "settlement_model (prepaid|escrow). Required for escrow offers.").option("--rate-amount <decimal>", 'rate_amount \u2014 decimal as string (e.g. "10.00"). Optional per-unit rate bound into the condition_hash.').option("--rate-unit <task|thread|handoff>", "rate_unit (task|thread|handoff). Optional.").option("--amount <s>", 'Optional decimal-as-string amount (e.g. "10.00"). REQUIRES --currency if set.').option("--currency <s>", `Asset identifier: shorthand (${import_sdk4.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(
2397
- "--escrow-lock-from-file <path>",
2398
- "Path to JSON output of `heyarp wallet create-lock` (recommended). Contains all 5 escrow_lock fields: signed_tx_blob, lock_id, amount, asset_id, expiry. Mutually exclusive with the inline --escrow-lock-* flags below."
2399
- ).option(
2400
- "--escrow-lock-blob <base64>",
2401
- "INLINE alternative: the signed Solana tx blob (base64). Requires --escrow-lock-id, --escrow-lock-amount, --escrow-lock-asset-id, --escrow-lock-expiry together."
2402
- ).option("--escrow-lock-id <hex32>", "INLINE lock_id (32-byte hex). Used with --escrow-lock-blob.").option("--escrow-lock-amount <int>", "INLINE lock amount in base units (e.g. lamports for native SOL). Used with --escrow-lock-blob.").option("--escrow-lock-asset-id <caip19>", "INLINE currency CAIP-19 asset_id (e.g. solana:<cluster_id>/slip44:501). Used with --escrow-lock-blob.").option("--escrow-lock-expiry <unix>", "INLINE expiry as unix seconds. Used with --escrow-lock-blob.").option(
2403
- "--program-id <pubkey>",
2404
- "Expected ARP escrow program id for pre-flight against the lock file's embedded `program_id`. Precedence: this flag > ARP_ESCROW_PROGRAM_ID env > server protocol-fee endpoint. Mismatch throws BEFORE the envelope ships, so a wrong-program lock never silently fails on chain after the offer was already delivered. Pre-flight is skipped only for old lock files lacking `program_id`, or when no expected value can be resolved."
2405
- ).option(
2406
- "--no-escrow",
2407
- "Opt-out for test_mode servers. Default REQUIRES the escrow_lock attachment; without --no-escrow, missing flags throw BEFORE the envelope is sent (avoids ESC_LOCK_MISSING POST_COMMIT consuming sender_sequence)."
2408
- ).option(
2389
+ 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("--pricing-model <flat|usage_based>", "pricing_model (flat|usage_based). Required.").option("--amount <s>", 'Optional decimal-as-string amount (e.g. "10.00"). REQUIRES --currency if set.').option("--currency <s>", `Asset identifier: shorthand (${import_sdk4.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(
2409
2390
  "--wait-until <phase>",
2410
2391
  '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.'
2411
2392
  ).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(
@@ -2435,39 +2416,35 @@ function assembleEscrowLockAttachment(opts) {
2435
2416
  const someInlineSet = inlineFlags.some((f) => f !== void 0 && f !== "");
2436
2417
  const allInlineSet = inlineFlags.every((f) => f !== void 0 && f !== "");
2437
2418
  if (fromFile && someInlineSet) {
2438
- throw new Error("delegation offer: --escrow-lock-from-file and --escrow-lock-blob/--escrow-lock-* are mutually exclusive. Pick one path.");
2419
+ throw new Error("delegation fund: --escrow-lock-from-file and --escrow-lock-blob/--escrow-lock-* are mutually exclusive. Pick one path.");
2439
2420
  }
2440
2421
  if (!fromFile && !someInlineSet) {
2441
- if (opts.escrow === false) return void 0;
2442
2422
  throw new Error(
2443
- "delegation offer: escrow_lock is required. Pass --escrow-lock-from-file <path> (JSON output of `heyarp wallet create-lock`), OR all of --escrow-lock-blob/--escrow-lock-id/--escrow-lock-amount/--escrow-lock-asset-id/--escrow-lock-expiry, OR --no-escrow if the server is in test_mode."
2423
+ "delegation fund: escrow_lock is required. Pass --escrow-lock-from-file <path> (JSON output of `heyarp wallet create-lock`), OR all of --escrow-lock-blob/--escrow-lock-id/--escrow-lock-amount/--escrow-lock-asset-id/--escrow-lock-expiry."
2444
2424
  );
2445
2425
  }
2446
- if (opts.escrow === false) {
2447
- throw new Error("delegation offer: --no-escrow is mutually exclusive with explicit escrow_lock flags. Pick one path.");
2448
- }
2449
2426
  if (fromFile) {
2450
2427
  let raw;
2451
2428
  try {
2452
2429
  raw = (0, import_node_fs4.readFileSync)(fromFile, "utf8");
2453
2430
  } catch (err) {
2454
- throw new Error(`delegation offer: failed to read --escrow-lock-from-file '${fromFile}': ${err.message}`);
2431
+ throw new Error(`delegation fund: failed to read --escrow-lock-from-file '${fromFile}': ${err.message}`);
2455
2432
  }
2456
2433
  let parsed;
2457
2434
  try {
2458
2435
  parsed = JSON.parse(raw);
2459
2436
  } catch (err) {
2460
- throw new Error(`delegation offer: --escrow-lock-from-file '${fromFile}' is not valid JSON: ${err.message}`);
2437
+ throw new Error(`delegation fund: --escrow-lock-from-file '${fromFile}' is not valid JSON: ${err.message}`);
2461
2438
  }
2462
2439
  if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
2463
- throw new Error(`delegation offer: --escrow-lock-from-file '${fromFile}' must be a JSON object, got ${Array.isArray(parsed) ? "array" : typeof parsed}.`);
2440
+ throw new Error(`delegation fund: --escrow-lock-from-file '${fromFile}' must be a JSON object, got ${Array.isArray(parsed) ? "array" : typeof parsed}.`);
2464
2441
  }
2465
2442
  const p = parsed;
2466
2443
  const required = ["signed_tx_blob", "lock_id", "amount", "asset_id", "expiry"];
2467
2444
  const missing = required.filter((k) => p[k] === void 0);
2468
2445
  if (missing.length > 0) {
2469
2446
  throw new Error(
2470
- `delegation offer: --escrow-lock-from-file '${fromFile}' is missing required fields: ${missing.join(", ")}. Expected JSON output of \`heyarp wallet create-lock\`.`
2447
+ `delegation fund: --escrow-lock-from-file '${fromFile}' is missing required fields: ${missing.join(", ")}. Expected JSON output of \`heyarp wallet create-lock\`.`
2471
2448
  );
2472
2449
  }
2473
2450
  const expiryRaw = p.expiry;
@@ -2478,19 +2455,19 @@ function assembleEscrowLockAttachment(opts) {
2478
2455
  expiryNum2 = Number(expiryRaw);
2479
2456
  if (String(expiryNum2) !== expiryRaw.trim()) {
2480
2457
  throw new Error(
2481
- `delegation offer: --escrow-lock-from-file '${fromFile}' has invalid 'expiry' (must be positive integer unix seconds): ${JSON.stringify(expiryRaw)}.`
2458
+ `delegation fund: --escrow-lock-from-file '${fromFile}' has invalid 'expiry' (must be positive integer unix seconds): ${JSON.stringify(expiryRaw)}.`
2482
2459
  );
2483
2460
  }
2484
2461
  } else {
2485
- throw new Error(`delegation offer: --escrow-lock-from-file '${fromFile}' has invalid 'expiry' (must be positive integer unix seconds): ${JSON.stringify(expiryRaw)}.`);
2462
+ throw new Error(`delegation fund: --escrow-lock-from-file '${fromFile}' has invalid 'expiry' (must be positive integer unix seconds): ${JSON.stringify(expiryRaw)}.`);
2486
2463
  }
2487
2464
  if (!Number.isFinite(expiryNum2) || !Number.isInteger(expiryNum2) || expiryNum2 <= 0) {
2488
- throw new Error(`delegation offer: --escrow-lock-from-file '${fromFile}' has invalid 'expiry' (must be positive integer unix seconds): ${JSON.stringify(expiryRaw)}.`);
2465
+ throw new Error(`delegation fund: --escrow-lock-from-file '${fromFile}' has invalid 'expiry' (must be positive integer unix seconds): ${JSON.stringify(expiryRaw)}.`);
2489
2466
  }
2490
2467
  let delegationIdFromLock;
2491
2468
  if (p.delegation_id !== void 0) {
2492
2469
  if (typeof p.delegation_id !== "string" || !UUID_RE.test(p.delegation_id)) {
2493
- throw new Error(`delegation offer: --escrow-lock-from-file '${fromFile}' has invalid 'delegation_id' (must be a UUID): ${JSON.stringify(p.delegation_id)}.`);
2470
+ throw new Error(`delegation fund: --escrow-lock-from-file '${fromFile}' has invalid 'delegation_id' (must be a UUID): ${JSON.stringify(p.delegation_id)}.`);
2494
2471
  }
2495
2472
  delegationIdFromLock = p.delegation_id.toLowerCase();
2496
2473
  }
@@ -2498,7 +2475,7 @@ function assembleEscrowLockAttachment(opts) {
2498
2475
  if (p.program_id !== void 0) {
2499
2476
  if (typeof p.program_id !== "string" || p.program_id.length < 32 || p.program_id.length > 44) {
2500
2477
  throw new Error(
2501
- `delegation offer: --escrow-lock-from-file '${fromFile}' has invalid 'program_id' (must be a base58 Solana pubkey, 32-44 chars): ${JSON.stringify(p.program_id)}.`
2478
+ `delegation fund: --escrow-lock-from-file '${fromFile}' has invalid 'program_id' (must be a base58 Solana pubkey, 32-44 chars): ${JSON.stringify(p.program_id)}.`
2502
2479
  );
2503
2480
  }
2504
2481
  lockProgramId = p.program_id;
@@ -2517,13 +2494,13 @@ function assembleEscrowLockAttachment(opts) {
2517
2494
  }
2518
2495
  if (!allInlineSet) {
2519
2496
  throw new Error(
2520
- "delegation offer: when using inline escrow flags, --escrow-lock-blob requires all of --escrow-lock-id, --escrow-lock-amount, --escrow-lock-asset-id, --escrow-lock-expiry to be set together."
2497
+ "delegation fund: when using inline escrow flags, --escrow-lock-blob requires all of --escrow-lock-id, --escrow-lock-amount, --escrow-lock-asset-id, --escrow-lock-expiry to be set together."
2521
2498
  );
2522
2499
  }
2523
2500
  const expiryStr = opts.escrowLockExpiry ?? "";
2524
2501
  const expiryNum = Number.parseInt(expiryStr, 10);
2525
2502
  if (!Number.isFinite(expiryNum) || !Number.isInteger(expiryNum) || expiryNum <= 0 || String(expiryNum) !== expiryStr) {
2526
- throw new Error(`delegation offer: --escrow-lock-expiry must be a positive integer (unix seconds), got '${expiryStr}'.`);
2503
+ throw new Error(`delegation fund: --escrow-lock-expiry must be a positive integer (unix seconds), got '${expiryStr}'.`);
2527
2504
  }
2528
2505
  return {
2529
2506
  attachment: {
@@ -2545,47 +2522,22 @@ async function runOffer(recipientDid, opts) {
2545
2522
  throw new Error("delegation offer: --title is required (server-side validator rejects empty offers)");
2546
2523
  }
2547
2524
  const terms = parseOfferTerms("delegation offer", opts);
2548
- const escrowResult = assembleEscrowLockAttachment(opts);
2549
- const delegationId = resolveOfferDelegationId(opts.delegationId, escrowResult);
2550
- if (escrowResult !== void 0) {
2551
- if (terms.amount === void 0 || terms.currency === void 0) {
2552
- throw new Error(
2553
- "delegation offer: escrow-backed offers require both --amount and --currency (server cross-checks body.content.amount/currency against attachments.escrow_lock.amount/asset_id)."
2554
- );
2555
- }
2556
- const missingTerms = [
2557
- terms.scope_summary === void 0 ? "--scope" : null,
2558
- terms.pricing_model === void 0 ? "--pricing-model" : null,
2559
- terms.settlement_model === void 0 ? "--settlement-model" : null
2560
- ].filter((x) => x !== null);
2561
- if (missingTerms.length > 0) {
2562
- throw new Error(
2563
- `delegation offer: escrow-backed offers require the inline terms ${missingTerms.join(", ")} (the on-chain condition_hash binds scope_summary/pricing_model/settlement_model/rate_amount/rate_unit/currency; a missing or divergent term is rejected by the server with ESC_LOCK_CONDITION_HASH_MISMATCH). Pass the SAME values you fed to \`heyarp escrow derive-condition-hash\`.`
2564
- );
2565
- }
2525
+ const delegationId = resolveOfferDelegationId(opts.delegationId, void 0);
2526
+ if (terms.amount === void 0 || terms.currency === void 0) {
2527
+ throw new Error(
2528
+ "delegation offer: escrow-backed offers require both --amount and --currency (these are the agreed terms; the buyer funds the matching escrow_lock later via `heyarp delegation fund`)."
2529
+ );
2530
+ }
2531
+ const missingTerms = [terms.scope_summary === void 0 ? "--scope" : null, terms.pricing_model === void 0 ? "--pricing-model" : null].filter(
2532
+ (x) => x !== null
2533
+ );
2534
+ if (missingTerms.length > 0) {
2535
+ throw new Error(
2536
+ `delegation offer: escrow-backed offers require the inline terms ${missingTerms.join(", ")} (the on-chain condition_hash binds scope_summary/pricing_model/currency at fund time; a missing or divergent term is rejected with ESC_LOCK_CONDITION_HASH_MISMATCH when you run \`heyarp delegation fund\`). Pass the SAME values you will feed to \`heyarp escrow derive-condition-hash\`.`
2537
+ );
2566
2538
  }
2567
2539
  const api = new ArpApiClient(opts.server);
2568
2540
  const sender = resolveSenderAgent("delegation offer", opts.server, opts.fromDid);
2569
- if (escrowResult?.lockProgramId !== void 0) {
2570
- const expected = await resolveProgramIdWithSource(api, { programId: opts.programId });
2571
- const result2 = preflightLockProgramId({
2572
- lockProgramId: escrowResult.lockProgramId,
2573
- expectedProgramId: expected.programId,
2574
- expectedSource: expected.source
2575
- });
2576
- if (result2.kind === "mismatch") {
2577
- throw new Error(
2578
- `delegation offer: lock file program_id ${result2.lockProgramId} does not match the expected escrow program ${result2.expectedProgramId} (resolved from --program-id flag > ARP_ESCROW_PROGRAM_ID env > server protocol-fee). The lock tx would be rejected on chain (ESC_LOCK_TX_PROGRAM_ID_MISMATCH) and the delegation would silently fail ~26s after offer. Regenerate the lock with the correct program id via \`heyarp wallet create-lock --program-id ${result2.expectedProgramId} ...\`.`
2579
- );
2580
- }
2581
- if (result2.kind === "skipped_no_expected_program_id") {
2582
- console.error(
2583
- import_chalk6.default.yellow(
2584
- `\u26A0 delegation offer: 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.`
2585
- )
2586
- );
2587
- }
2588
- }
2589
2541
  const content = {
2590
2542
  action: "offer",
2591
2543
  delegation_id: delegationId,
@@ -2593,22 +2545,21 @@ async function runOffer(recipientDid, opts) {
2593
2545
  ...terms
2594
2546
  };
2595
2547
  const body = { type: "delegation", content };
2596
- const attachments = escrowResult ? { escrow_lock: escrowResult.attachment } : void 0;
2597
2548
  console.log(import_chalk6.default.dim(`Server: ${api.serverUrl}`));
2598
2549
  console.log(import_chalk6.default.dim(`Sender: ${sender.did}`));
2599
2550
  console.log(import_chalk6.default.dim(`Recipient: ${recipientDid}`));
2600
2551
  console.log(import_chalk6.default.dim(`Delegation: ${delegationId}`));
2601
- if (escrowResult) {
2602
- const a = escrowResult.attachment;
2603
- console.log(import_chalk6.default.dim(`Escrow lock attached: lock_id=${a.lock_id} amount=${a.amount} asset_id=${a.asset_id}`));
2604
- }
2605
- const result = await sendDelegationEnvelope({ api, sender, recipientDid, body, attachments, ttlSeconds, verbose: opts.verbose, server: opts.server });
2552
+ const result = await sendDelegationEnvelope({ api, sender, recipientDid, body, ttlSeconds, verbose: opts.verbose, server: opts.server });
2606
2553
  printIngestResult(result);
2607
2554
  console.log(import_chalk6.default.dim(`
2608
2555
  Reference this delegation on subsequent calls with:`));
2609
2556
  console.log(import_chalk6.default.dim(` heyarp delegation accept ${result.relationshipId} ${delegationId}`));
2610
2557
  console.log(import_chalk6.default.dim(` heyarp delegation decline ${result.relationshipId} ${delegationId}`));
2611
2558
  console.log(import_chalk6.default.dim(` heyarp delegation cancel ${result.relationshipId} ${delegationId}`));
2559
+ console.log(import_chalk6.default.dim(`
2560
+ After the worker accepts, fund the escrow lock:`));
2561
+ console.log(import_chalk6.default.dim(` heyarp wallet create-lock --delegation-id ${delegationId} --condition-hash <hex> ... > lock.json`));
2562
+ console.log(import_chalk6.default.dim(` heyarp delegation fund ${delegationId} --escrow-lock-from-file lock.json`));
2612
2563
  if (opts.waitUntil) {
2613
2564
  const untilPhase = parseUntilPhase(opts.waitUntil);
2614
2565
  if (untilPhase === void 0) {
@@ -2628,6 +2579,152 @@ Reference this delegation on subsequent calls with:`));
2628
2579
  });
2629
2580
  }
2630
2581
  }
2582
+ function registerFund(parent) {
2583
+ 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(
2584
+ "--json",
2585
+ '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.',
2586
+ false
2587
+ ).option(
2588
+ "--escrow-lock-from-file <path>",
2589
+ "Path to JSON output of `heyarp wallet create-lock` (recommended). Contains all 5 escrow_lock fields: signed_tx_blob, lock_id, amount, asset_id, expiry (+ delegation_id / program_id for pre-flight). Mutually exclusive with the inline --escrow-lock-* flags below."
2590
+ ).option(
2591
+ "--escrow-lock-blob <base64>",
2592
+ "INLINE alternative: the signed Solana tx blob (base64). Requires --escrow-lock-id, --escrow-lock-amount, --escrow-lock-asset-id, --escrow-lock-expiry together."
2593
+ ).option("--escrow-lock-id <hex32>", "INLINE lock_id (32-byte hex). Used with --escrow-lock-blob.").option("--escrow-lock-amount <int>", "INLINE lock amount in base units (e.g. lamports for native SOL). Used with --escrow-lock-blob.").option("--escrow-lock-asset-id <caip19>", "INLINE currency CAIP-19 asset_id (e.g. solana:<cluster_id>/slip44:501). Used with --escrow-lock-blob.").option("--escrow-lock-expiry <unix>", "INLINE expiry as unix seconds. Used with --escrow-lock-blob.").option(
2594
+ "--program-id <pubkey>",
2595
+ "Expected ARP escrow program id for pre-flight against the lock file's embedded `program_id`. Precedence: this flag > ARP_ESCROW_PROGRAM_ID env > server protocol-fee endpoint. Mismatch throws BEFORE the envelope ships, so a wrong-program lock never silently fails on chain after fund was already delivered. Pre-flight is skipped only for old lock files lacking `program_id`, or when no expected value can be resolved."
2596
+ ).option(
2597
+ "--wait-until <phase>",
2598
+ "Block after delivery until the named FSM phase is reached (typically delegation.locked \u2014 resolves once the escrow lock confirms on chain). One of the UNTIL_PHASES from `heyarp status --help`. Exit code 124 on --wait-timeout."
2599
+ ).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("--wait-verbose", "When --wait-until is set: emit one dim line per poll tick showing the current FSM state.", false).action(async (delegationId, opts) => {
2600
+ await runFund(delegationId, opts);
2601
+ });
2602
+ }
2603
+ async function runFund(delegationId, opts) {
2604
+ if (opts.verbose && opts.json) {
2605
+ throw new Error(
2606
+ "delegation fund: --verbose and --json are mutually exclusive. --json emits the structured server response; --verbose adds dumps that would break `--json | jq`."
2607
+ );
2608
+ }
2609
+ delegationId = requireUuidNormalised("delegation fund", delegationId, "<delegation-id>");
2610
+ const ttlSeconds = parseTtl("delegation fund", opts.ttl);
2611
+ const escrowResult = assembleEscrowLockAttachment({
2612
+ escrowLockFromFile: opts.escrowLockFromFile,
2613
+ escrowLockBlob: opts.escrowLockBlob,
2614
+ escrowLockId: opts.escrowLockId,
2615
+ escrowLockAmount: opts.escrowLockAmount,
2616
+ escrowLockAssetId: opts.escrowLockAssetId,
2617
+ escrowLockExpiry: opts.escrowLockExpiry
2618
+ });
2619
+ if (escrowResult.delegationIdFromLock !== void 0 && escrowResult.delegationIdFromLock !== delegationId) {
2620
+ throw new Error(
2621
+ `delegation fund: <delegation-id> (${delegationId}) disagrees with the lock file's delegation_id (${escrowResult.delegationIdFromLock}). The on-chain lock_id is derived from the lock-side id; funding a different delegation would guarantee ESC_LOCK_ID_MISMATCH. Fund the delegation the lock was built for, or regenerate the lock with --delegation-id ${delegationId}.`
2622
+ );
2623
+ }
2624
+ const api = new ArpApiClient(opts.server);
2625
+ const sender = resolveSenderAgent("delegation fund", opts.server, opts.fromDid);
2626
+ const signer = makeSigner(sender);
2627
+ const resolved = await resolveFundRefs("delegation fund", api, signer, { delegationId, selfDid: sender.did });
2628
+ if (escrowResult.lockProgramId !== void 0) {
2629
+ const expected = await resolveProgramIdWithSource(api, { programId: opts.programId });
2630
+ const result2 = preflightLockProgramId({
2631
+ lockProgramId: escrowResult.lockProgramId,
2632
+ expectedProgramId: expected.programId,
2633
+ expectedSource: expected.source
2634
+ });
2635
+ if (result2.kind === "mismatch") {
2636
+ throw new Error(
2637
+ `delegation fund: lock file program_id ${result2.lockProgramId} does not match the expected escrow program ${result2.expectedProgramId} (resolved from --program-id flag > ARP_ESCROW_PROGRAM_ID env > server protocol-fee). The lock tx would be rejected on chain (ESC_LOCK_TX_PROGRAM_ID_MISMATCH) and the delegation would silently fail ~26s after fund. Regenerate the lock with the correct program id via \`heyarp wallet create-lock --program-id ${result2.expectedProgramId} ...\`.`
2638
+ );
2639
+ }
2640
+ if (result2.kind === "skipped_no_expected_program_id") {
2641
+ console.error(
2642
+ import_chalk6.default.yellow(
2643
+ "\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."
2644
+ )
2645
+ );
2646
+ }
2647
+ }
2648
+ const content = { action: "fund", delegation_id: delegationId };
2649
+ const body = { type: "delegation", content };
2650
+ const attachments = { escrow_lock: escrowResult.attachment };
2651
+ progress(opts.json, import_chalk6.default.dim(`Server: ${api.serverUrl}`));
2652
+ progress(opts.json, import_chalk6.default.dim(`Sender: ${sender.did}`));
2653
+ progress(opts.json, import_chalk6.default.dim(`Recipient: ${resolved.recipientDid}`));
2654
+ progress(opts.json, import_chalk6.default.dim(`Relationship: ${resolved.relationshipId}`));
2655
+ progress(opts.json, import_chalk6.default.dim(`Delegation: ${delegationId} (action=fund)`));
2656
+ {
2657
+ const a = escrowResult.attachment;
2658
+ progress(opts.json, import_chalk6.default.dim(`Escrow lock attached: lock_id=${a.lock_id} amount=${a.amount} asset_id=${a.asset_id}`));
2659
+ }
2660
+ const result = await sendDelegationEnvelope({
2661
+ api,
2662
+ sender,
2663
+ recipientDid: resolved.recipientDid,
2664
+ body,
2665
+ attachments,
2666
+ ttlSeconds,
2667
+ verbose: opts.verbose,
2668
+ server: opts.server
2669
+ });
2670
+ if (opts.json) {
2671
+ jsonOut({
2672
+ ok: true,
2673
+ action: "fund",
2674
+ delegationId,
2675
+ eventId: result.eventId,
2676
+ relationshipId: result.relationshipId,
2677
+ relationshipEventIndex: result.relationshipEventIndex,
2678
+ serverTimestamp: result.serverTimestamp,
2679
+ serverEventHash: result.serverEventHash,
2680
+ prevServerEventHash: result.prevServerEventHash ?? null
2681
+ });
2682
+ } else {
2683
+ printIngestResult(result);
2684
+ console.log(import_chalk6.default.dim("\nThe worker waits for the on-chain lock to confirm (LOCKED), then begins work."));
2685
+ }
2686
+ if (opts.waitUntil && !opts.json) {
2687
+ const untilPhase = parseUntilPhase(opts.waitUntil);
2688
+ if (untilPhase === void 0) {
2689
+ throw new Error(`delegation fund: --wait-until requires a phase value (got ${JSON.stringify(opts.waitUntil)})`);
2690
+ }
2691
+ await awaitFsmTransitionAfterAction({
2692
+ api,
2693
+ signerDid: sender.did,
2694
+ signer,
2695
+ relationshipId: result.relationshipId,
2696
+ untilPhase,
2697
+ waitIntervalSec: parseWaitInterval(opts.waitInterval),
2698
+ waitTimeoutSec: parseWaitTimeout(opts.waitTimeout),
2699
+ waitVerbose: !!opts.waitVerbose,
2700
+ json: false
2701
+ });
2702
+ }
2703
+ }
2704
+ async function resolveFundRefs(cmdName, api, signer, args) {
2705
+ const relationships = await api.listRelationships(args.selfDid, signer, { limit: 100 });
2706
+ for (const rel of relationships) {
2707
+ let after;
2708
+ for (; ; ) {
2709
+ const page = await api.listDelegations(rel.relationshipId, signer, { limit: 100, after });
2710
+ const row = page.find((d) => d.delegationId === args.delegationId);
2711
+ if (row) {
2712
+ if (row.offererDid !== args.selfDid) {
2713
+ throw new Error(
2714
+ `${cmdName}: delegation ${args.delegationId} was offered by ${row.offererDid}, not you (${args.selfDid}). Funding the escrow lock is the BUYER's (offerer's) action.`
2715
+ );
2716
+ }
2717
+ const recipientDid = rel.pairDidA === args.selfDid ? rel.pairDidB : rel.pairDidA;
2718
+ return { relationshipId: rel.relationshipId, recipientDid, state: row.state };
2719
+ }
2720
+ if (page.length < 100) break;
2721
+ after = page[page.length - 1].id;
2722
+ }
2723
+ }
2724
+ throw new Error(
2725
+ `${cmdName}: delegation ${args.delegationId} not found in any of your relationships (checked the first 100 by recent activity). Confirm the worker accepted your offer and that you are the offerer; inspect with \`heyarp delegations <relationship-id> --from-did ${args.selfDid}\`.`
2726
+ );
2727
+ }
2631
2728
  function registerAccept(parent) {
2632
2729
  parent.command("accept").description("Accept a PROPOSED delegation \u2014 promotes to ACCEPTED. Counterparty-only.").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(
2633
2730
  "--json",
@@ -2654,7 +2751,7 @@ function registerDecline(parent) {
2654
2751
  });
2655
2752
  }
2656
2753
  function registerCancel(parent) {
2657
- parent.command("cancel").description("Cancel a PROPOSED 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(
2754
+ 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(
2658
2755
  "--no-wait-for-lock",
2659
2756
  "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)."
2660
2757
  ).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) => {
@@ -2931,11 +3028,6 @@ function parseOfferTerms(cmdName, opts) {
2931
3028
  if (opts.scope) out.scope_summary = opts.scope;
2932
3029
  const pricingModel = parsePricingModel(cmdName, opts.pricingModel);
2933
3030
  if (pricingModel !== void 0) out.pricing_model = pricingModel;
2934
- const settlementModel = parseSettlementModel(cmdName, opts.settlementModel);
2935
- if (settlementModel !== void 0) out.settlement_model = settlementModel;
2936
- if (opts.rateAmount) out.rate_amount = opts.rateAmount;
2937
- const rateUnit = parseRateUnit(cmdName, opts.rateUnit);
2938
- if (rateUnit !== void 0) out.rate_unit = rateUnit;
2939
3031
  if (opts.amount) {
2940
3032
  out.amount = opts.amount;
2941
3033
  if (!opts.currency) {
@@ -2954,20 +3046,6 @@ function parsePricingModel(cmdName, raw) {
2954
3046
  }
2955
3047
  return raw;
2956
3048
  }
2957
- function parseSettlementModel(cmdName, raw) {
2958
- if (raw === void 0 || raw === "") return void 0;
2959
- if (raw !== "prepaid" && raw !== "escrow") {
2960
- throw new Error(`${cmdName}: --settlement-model must be one of prepaid|escrow (got '${raw}')`);
2961
- }
2962
- return raw;
2963
- }
2964
- function parseRateUnit(cmdName, raw) {
2965
- if (raw === void 0 || raw === "") return void 0;
2966
- if (raw !== "task" && raw !== "thread" && raw !== "handoff") {
2967
- throw new Error(`${cmdName}: --rate-unit must be one of task|thread|handoff (got '${raw}')`);
2968
- }
2969
- return raw;
2970
- }
2971
3049
  function parseTtl(cmdName, raw) {
2972
3050
  if (raw === void 0) return 3600;
2973
3051
  const n = Number(raw);
@@ -3095,6 +3173,17 @@ var init_delegation = __esm({
3095
3173
  // against a PENDING_LOCK delegation consumes sender_sequence
3096
3174
  // even though it rejects.
3097
3175
  "DELEGATION_PENDING_LOCK",
3176
+ // M6 lock-at-accept: the `fund` body handler (`handleFund`) emits
3177
+ // these AFTER the event row is committed (same lifecycle as
3178
+ // DELEGATION_INVALID_STATE). `DELEGATION_FUNDER_NOT_OFFERER` (403)
3179
+ // when a non-offerer attempts the fund; `DELEGATION_ALREADY_FUNDED`
3180
+ // (409) on a re-fund of a delegation that already moved into the
3181
+ // lock lifecycle (pending_lock_finalization / locked, or an
3182
+ // in-flight create_lock op). Both consume sender_sequence, so the
3183
+ // CLI must advance `lastSenderSequence` or a retry trips
3184
+ // `ENV_SEQUENCE_BACKWARDS`.
3185
+ "DELEGATION_FUNDER_NOT_OFFERER",
3186
+ "DELEGATION_ALREADY_FUNDED",
3098
3187
  // V1.5 lock-validator mint.owner pre-flight — kept here for
3099
3188
  // documentation, but the `isPostCommitErrorCode` helper below
3100
3189
  // also matches any `ESC_LOCK_*` prefix. The full lock-validator
@@ -3346,11 +3435,8 @@ function projectDelegationRowForHash(d) {
3346
3435
  const out = {
3347
3436
  delegationId: d.delegationId,
3348
3437
  scopeSummary: d.scopeSummary,
3349
- pricingModel: d.pricingModel,
3350
- settlementModel: d.settlementModel
3438
+ pricingModel: d.pricingModel
3351
3439
  };
3352
- if (d.rateAmount !== void 0) out.rateAmount = d.rateAmount;
3353
- if (d.rateUnit !== void 0) out.rateUnit = d.rateUnit;
3354
3440
  if (d.currency !== void 0) {
3355
3441
  out.currency = {
3356
3442
  asset_id: d.currency.assetId,
@@ -3492,10 +3578,10 @@ async function autoSignAndDeliverPayeeSig(opts, cmdName = "receipt propose") {
3492
3578
  const api = new ArpApiClient(opts.server);
3493
3579
  const sender = resolveSenderAgent(cmdName, opts.server, opts.fromDid);
3494
3580
  const signer = makeSigner(sender);
3495
- say(import_chalk18.default.dim(`Server: ${api.serverUrl}`));
3496
- say(import_chalk18.default.dim(`Signer (payee): ${sender.did}`));
3581
+ say(import_chalk17.default.dim(`Server: ${api.serverUrl}`));
3582
+ say(import_chalk17.default.dim(`Signer (payee): ${sender.did}`));
3497
3583
  const relId = opts.relId ?? await resolveAutoRelId(api, sender, delegationId);
3498
- say(import_chalk18.default.dim(`Relationship: ${relId}`));
3584
+ say(import_chalk17.default.dim(`Relationship: ${relId}`));
3499
3585
  const receiptMatches = await collectReceiptRows(api, signer, relId, delegationId);
3500
3586
  const receipt = selectReceipt(receiptMatches, opts.receiptEventHash, cmdName);
3501
3587
  if (!receipt) {
@@ -3516,7 +3602,7 @@ async function autoSignAndDeliverPayeeSig(opts, cmdName = "receipt propose") {
3516
3602
  if (opts.json) {
3517
3603
  jsonOut({ ok: true, idempotent: true, alreadyCosigned: true, delegationId, relationshipId: relId, buyerDid: receipt.callerDid });
3518
3604
  } else {
3519
- progress(opts.json, import_chalk18.default.yellow("\n[idempotent] Receipt already cosigned \u2014 escrow release is settled. Nothing to send."));
3605
+ progress(opts.json, import_chalk17.default.yellow("\n[idempotent] Receipt already cosigned \u2014 escrow release is settled. Nothing to send."));
3520
3606
  }
3521
3607
  }
3522
3608
  return { delivered: false, idempotent: true, alreadyCosigned: true, relationshipId: relId, buyerDid: receipt.callerDid };
@@ -3539,8 +3625,8 @@ async function autoSignAndDeliverPayeeSig(opts, cmdName = "receipt propose") {
3539
3625
  expiresAt: ps.expires_at
3540
3626
  });
3541
3627
  } else {
3542
- progress(opts.json, import_chalk18.default.yellow("\n[idempotent] Payee settlement signature already delivered + still valid for this receipt \u2014 skipping re-send."));
3543
- progress(opts.json, import_chalk18.default.dim(` purpose=${ps.purpose} settlement_pubkey=${ps.settlement_pubkey} expires_at=${ps.expires_at}`));
3628
+ progress(opts.json, import_chalk17.default.yellow("\n[idempotent] Payee settlement signature already delivered + still valid for this receipt \u2014 skipping re-send."));
3629
+ progress(opts.json, import_chalk17.default.dim(` purpose=${ps.purpose} settlement_pubkey=${ps.settlement_pubkey} expires_at=${ps.expires_at}`));
3544
3630
  }
3545
3631
  }
3546
3632
  return {
@@ -3554,14 +3640,14 @@ async function autoSignAndDeliverPayeeSig(opts, cmdName = "receipt propose") {
3554
3640
  expiresAt: ps.expires_at
3555
3641
  };
3556
3642
  }
3557
- say(import_chalk18.default.yellow(`
3643
+ say(import_chalk17.default.yellow(`
3558
3644
  [refresh] Existing payee settlement sig expires at ${ps.expires_at} (\u2264 now+${SETTLEMENT_REFRESH_HEADROOM_SECS}s) \u2014 re-signing with a fresh expiry.`));
3559
3645
  }
3560
3646
  const buyerDid = receipt.callerDid;
3561
3647
  const receiptEventHash = receipt.receiptEventHash;
3562
3648
  const deliverableHash = receipt.deliverableHash ?? receipt.responseHash;
3563
- say(import_chalk18.default.dim(`Buyer (payer): ${buyerDid}`));
3564
- say(import_chalk18.default.dim(`Receipt event hash: ${receiptEventHash}`));
3649
+ say(import_chalk17.default.dim(`Buyer (payer): ${buyerDid}`));
3650
+ say(import_chalk17.default.dim(`Receipt event hash: ${receiptEventHash}`));
3565
3651
  const delegation = await findDelegationRow(api, signer, relId, delegationId);
3566
3652
  if (!delegation) {
3567
3653
  throw new Error(`${cmdName}: delegation ${delegationId} not found under relationship ${relId} (paginated 5000 rows).`);
@@ -3601,11 +3687,6 @@ async function autoSignAndDeliverPayeeSig(opts, cmdName = "receipt propose") {
3601
3687
  `${cmdName}: settlement expires_at (${Number.isFinite(expiresAt6) ? expiresAt6 : "NaN"}) is not far enough in the future \u2014 it must be > now+${SETTLEMENT_MIN_EXPIRY_HEADROOM_SECS}s (${minSafeExpiry}) or the server rejects it post-commit (SETTLEMENT_SIG_EXPIRES_AT_*), burning a sender_sequence. ${fromExplicit ? "Pass a later --expires-at <unix-seconds> (still \u2264 the lock's on-chain expiry)." : `Derived from deadline ${JSON.stringify(delegation.deadline)} + buffer ${bufferSecs}s \u2014 the deadline is too close or in the past. Increase --settlement-buffer-secs or pass --expires-at <unix-seconds> \u2264 the lock's expiry.`}`
3602
3688
  );
3603
3689
  }
3604
- if (delegation.settlementModel === "prepaid") {
3605
- throw new Error(
3606
- `${cmdName}: delegation ${delegationId} settlementModel is 'prepaid' (non-escrow). This command delivers an on-chain escrow-release signature; a prepaid delegation has no lock to settle and the server would reject post-commit (SETTLEMENT_SIG_LOCK_NOT_FOUND). Nothing to settle on-chain.`
3607
- );
3608
- }
3609
3690
  const subset = projectDelegationRowForHash(delegation);
3610
3691
  const conditionHash = (0, import_utils3.bytesToHex)((0, import_sdk10.deriveDelegationConditionHash)(subset));
3611
3692
  const buyerDidDoc = await api.getDidDocument(buyerDid);
@@ -3667,9 +3748,9 @@ async function autoSignAndDeliverPayeeSig(opts, cmdName = "receipt propose") {
3667
3748
  });
3668
3749
  effectiveFeeBpsAtLock = resolvedFee.feeBpsAtLock;
3669
3750
  effectiveFeeRecipientAtLock = resolvedFee.feeRecipientAtLock;
3670
- say(import_chalk18.default.dim(`On-chain lock pre-flight OK \u2014 payee/amount/expiry/mint match; fee_bps_at_lock=${resolvedFee.feeBpsAtLock}.`));
3751
+ say(import_chalk17.default.dim(`On-chain lock pre-flight OK \u2014 payee/amount/expiry/mint match; fee_bps_at_lock=${resolvedFee.feeBpsAtLock}.`));
3671
3752
  } else {
3672
- say(import_chalk18.default.yellow(`On-chain lock pre-flight skipped: ${lockCheck.skipReason}. The server remains the validation boundary.`));
3753
+ say(import_chalk17.default.yellow(`On-chain lock pre-flight skipped: ${lockCheck.skipReason}. The server remains the validation boundary.`));
3673
3754
  }
3674
3755
  const signOpts = {
3675
3756
  server: opts.server,
@@ -3692,7 +3773,7 @@ async function autoSignAndDeliverPayeeSig(opts, cmdName = "receipt propose") {
3692
3773
  ...effectiveFeeRecipientAtLock !== void 0 ? { feeRecipientAtLock: effectiveFeeRecipientAtLock } : {},
3693
3774
  ...partialPayeeAmount !== void 0 ? { partialPayeeAmount } : {}
3694
3775
  };
3695
- say(import_chalk18.default.dim(`Signing ${partialPayeeAmount !== void 0 ? "PARTIAL" : "full"} release: lock_amount=${lockAmount}, expires_at=${expiresAt6}, cluster_tag=${clusterTag}`));
3776
+ say(import_chalk17.default.dim(`Signing ${partialPayeeAmount !== void 0 ? "PARTIAL" : "full"} release: lock_amount=${lockAmount}, expires_at=${expiresAt6}, cluster_tag=${clusterTag}`));
3696
3777
  const signed = await signSettlementHandler(signOpts);
3697
3778
  const content = {
3698
3779
  delegation_id: delegationId,
@@ -3723,16 +3804,16 @@ async function autoSignAndDeliverPayeeSig(opts, cmdName = "receipt propose") {
3723
3804
  serverTimestamp: result.serverTimestamp
3724
3805
  });
3725
3806
  } else {
3726
- console.log(import_chalk18.default.green("\nSettlement signature signed + delivered."));
3727
- console.log(`${import_chalk18.default.bold("Delegation")}: ${import_chalk18.default.cyan(delegationId)}`);
3728
- console.log(`${import_chalk18.default.bold("Buyer")}: ${import_chalk18.default.cyan(buyerDid)}`);
3729
- console.log(`${import_chalk18.default.bold("Purpose")}: ${import_chalk18.default.cyan(signed.purpose)}`);
3807
+ console.log(import_chalk17.default.green("\nSettlement signature signed + delivered."));
3808
+ console.log(`${import_chalk17.default.bold("Delegation")}: ${import_chalk17.default.cyan(delegationId)}`);
3809
+ console.log(`${import_chalk17.default.bold("Buyer")}: ${import_chalk17.default.cyan(buyerDid)}`);
3810
+ console.log(`${import_chalk17.default.bold("Purpose")}: ${import_chalk17.default.cyan(signed.purpose)}`);
3730
3811
  if (partialPayeeAmount !== void 0) {
3731
- console.log(`${import_chalk18.default.bold("Payee amount")}: ${import_chalk18.default.cyan(partialPayeeAmount)} (partial release)`);
3812
+ console.log(`${import_chalk17.default.bold("Payee amount")}: ${import_chalk17.default.cyan(partialPayeeAmount)} (partial release)`);
3732
3813
  }
3733
- console.log(`${import_chalk18.default.bold("Expires at")}: ${import_chalk18.default.cyan(String(expiresAt6))}`);
3734
- console.log(`${import_chalk18.default.bold("Delivered event")}: ${import_chalk18.default.cyan(result.serverEventHash)}`);
3735
- console.log(import_chalk18.default.dim("\nThe buyer cosigns with: heyarp receipt cosign <rel-id> <del-id> --auto-hashes --auto-resolve-payee-sig --payer-sig-from-file <path>"));
3814
+ console.log(`${import_chalk17.default.bold("Expires at")}: ${import_chalk17.default.cyan(String(expiresAt6))}`);
3815
+ console.log(`${import_chalk17.default.bold("Delivered event")}: ${import_chalk17.default.cyan(result.serverEventHash)}`);
3816
+ console.log(import_chalk17.default.dim("\nThe buyer cosigns with: heyarp receipt cosign <rel-id> <del-id> --auto-hashes --auto-resolve-payee-sig --payer-sig-from-file <path>"));
3736
3817
  }
3737
3818
  }
3738
3819
  return {
@@ -3751,13 +3832,13 @@ async function autoSignAndDeliverPayeeSig(opts, cmdName = "receipt propose") {
3751
3832
  serverTimestamp: result.serverTimestamp
3752
3833
  };
3753
3834
  }
3754
- var import_sdk10, import_utils3, import_web33, import_chalk18, NATIVE_SOL_MINT2, SETTLEMENT_MIN_EXPIRY_HEADROOM_SECS, SETTLEMENT_REFRESH_HEADROOM_SECS;
3835
+ var import_sdk10, import_utils3, import_web33, import_chalk17, NATIVE_SOL_MINT2, SETTLEMENT_MIN_EXPIRY_HEADROOM_SECS, SETTLEMENT_REFRESH_HEADROOM_SECS;
3755
3836
  var init_settlement = __esm({
3756
3837
  "src/commands/settlement.ts"() {
3757
3838
  import_sdk10 = require("@heyanon-arp/sdk");
3758
3839
  import_utils3 = require("@noble/hashes/utils");
3759
3840
  import_web33 = require("@solana/web3.js");
3760
- import_chalk18 = __toESM(require("chalk"));
3841
+ import_chalk17 = __toESM(require("chalk"));
3761
3842
  init_api();
3762
3843
  init_format();
3763
3844
  init_state();
@@ -3798,10 +3879,10 @@ function registerPropose(parent) {
3798
3879
  false
3799
3880
  ).option(
3800
3881
  "--cluster-tag <int>",
3801
- "Solana cluster the escrow lock lives on: 0 = devnet, 1 = mainnet-beta. MUST match the create_lock cluster or the server-reconstructed release digest will not verify. REQUIRED for an escrow delegation \u2014 there is no default (a defaulted/wrong cluster silently signs an invalid settlement digest that fails at cosign). Ignored for prepaid."
3882
+ "Solana cluster the escrow lock lives on: 0 = devnet, 1 = mainnet-beta. MUST match the create_lock cluster or the server-reconstructed release digest will not verify. REQUIRED (every delegation is escrow-backed) \u2014 there is no default (a defaulted/wrong cluster silently signs an invalid settlement digest that fails at cosign)."
3802
3883
  ).option(
3803
3884
  "--settlement-buffer-secs <int>",
3804
- "Seconds added to the delegation deadline for the settlement digest expires_at (dispute buffer). Default 86400 (1 day). Ignored when --expires-at is given, and for prepaid delegations.",
3885
+ "Seconds added to the delegation deadline for the settlement digest expires_at (dispute buffer). Default 86400 (1 day). Ignored when --expires-at is given.",
3805
3886
  "86400"
3806
3887
  ).option(
3807
3888
  "--expires-at <unix>",
@@ -3850,15 +3931,13 @@ async function runPropose(recipientDid, delegationId, requestHashArg, responseHa
3850
3931
  opts.relId = await resolveAutoRelId(api, sender, delegationId);
3851
3932
  progress(
3852
3933
  opts.json,
3853
- import_chalk19.default.dim(`[auto-rel-id] resolved --rel-id=${opts.relId} (delegation found in exactly one of your relationships; pass --rel-id explicitly to override)`)
3934
+ import_chalk18.default.dim(`[auto-rel-id] resolved --rel-id=${opts.relId} (delegation found in exactly one of your relationships; pass --rel-id explicitly to override)`)
3854
3935
  );
3855
3936
  }
3856
- let delegationRow;
3857
3937
  if (opts.relId) {
3858
- delegationRow = await assertSenderIsReceiptPayee(api, sender, opts.relId, delegationId);
3938
+ await assertSenderIsReceiptPayee(api, sender, opts.relId, delegationId);
3859
3939
  }
3860
- const isEscrow = delegationRow?.settlementModel === "escrow";
3861
- if (isEscrow) {
3940
+ {
3862
3941
  const ct = opts.clusterTag;
3863
3942
  if (ct === void 0 || ct === "") {
3864
3943
  throw new Error(
@@ -3879,7 +3958,7 @@ async function runPropose(recipientDid, delegationId, requestHashArg, responseHa
3879
3958
  opts.requestId = await resolveAutoRequestId(api, sender, opts.relId, delegationId);
3880
3959
  progress(
3881
3960
  opts.json,
3882
- import_chalk19.default.dim(
3961
+ import_chalk18.default.dim(
3883
3962
  `[auto-request-id] resolved --request-id=${opts.requestId} (unique 'responded' work_log under this delegation; pass --request-id explicitly to override)`
3884
3963
  )
3885
3964
  );
@@ -3898,8 +3977,8 @@ async function runPropose(recipientDid, delegationId, requestHashArg, responseHa
3898
3977
  }
3899
3978
  requestHash = computed.requestHash;
3900
3979
  responseHash = computed.responseHash;
3901
- progress(opts.json, import_chalk19.default.dim(`[auto-hashes] request_hash: ${requestHash} (from work-log ${opts.relId}/${delegationId}/${opts.requestId})`));
3902
- progress(opts.json, import_chalk19.default.dim(`[auto-hashes] response_hash: ${responseHash}`));
3980
+ progress(opts.json, import_chalk18.default.dim(`[auto-hashes] request_hash: ${requestHash} (from work-log ${opts.relId}/${delegationId}/${opts.requestId})`));
3981
+ progress(opts.json, import_chalk18.default.dim(`[auto-hashes] response_hash: ${responseHash}`));
3903
3982
  } else {
3904
3983
  if (requestHashArg === void 0 || responseHashArg === void 0) {
3905
3984
  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)");
@@ -3919,15 +3998,15 @@ async function runPropose(recipientDid, delegationId, requestHashArg, responseHa
3919
3998
  if (opts.deliverableHash) content.deliverable_hash = opts.deliverableHash;
3920
3999
  if (usage) content.usage = usage;
3921
4000
  const body = { type: "receipt", content };
3922
- progress(opts.json, import_chalk19.default.dim(`Server: ${api.serverUrl}`));
3923
- progress(opts.json, import_chalk19.default.dim(`Sender (payee): ${sender.did}`));
3924
- progress(opts.json, import_chalk19.default.dim(`Recipient (caller): ${recipientDid}`));
3925
- progress(opts.json, import_chalk19.default.dim(`Delegation: ${delegationId}`));
3926
- progress(opts.json, import_chalk19.default.dim(`Verdict (proposed): ${verdict}`));
4001
+ progress(opts.json, import_chalk18.default.dim(`Server: ${api.serverUrl}`));
4002
+ progress(opts.json, import_chalk18.default.dim(`Sender (payee): ${sender.did}`));
4003
+ progress(opts.json, import_chalk18.default.dim(`Recipient (caller): ${recipientDid}`));
4004
+ progress(opts.json, import_chalk18.default.dim(`Delegation: ${delegationId}`));
4005
+ progress(opts.json, import_chalk18.default.dim(`Verdict (proposed): ${verdict}`));
3927
4006
  const result = await sendReceiptEnvelope({ api, sender, recipientDid, body, attachments: void 0, ttlSeconds, verbose: opts.verbose, server: opts.server });
3928
4007
  let settlementResult;
3929
4008
  let settlementError;
3930
- if (isEscrow && opts.relId) {
4009
+ if (opts.relId) {
3931
4010
  const { autoSignAndDeliverPayeeSig: autoSignAndDeliverPayeeSig2 } = await Promise.resolve().then(() => (init_settlement(), settlement_exports));
3932
4011
  try {
3933
4012
  settlementResult = await autoSignAndDeliverPayeeSig2({
@@ -3995,32 +4074,36 @@ async function runPropose(recipientDid, delegationId, requestHashArg, responseHa
3995
4074
  return;
3996
4075
  }
3997
4076
  printIngestResult2(result);
3998
- console.log(import_chalk19.default.dim(`
3999
- Receipt event hash: ${import_chalk19.default.cyan(result.serverEventHash)}`));
4077
+ console.log(import_chalk18.default.dim(`
4078
+ Receipt event hash: ${import_chalk18.default.cyan(result.serverEventHash)}`));
4000
4079
  if (settlementError) {
4001
- console.error(import_chalk19.default.yellow("\nWARNING: receipt proposed, but the payee settlement signature was NOT delivered."));
4002
- console.error(import_chalk19.default.yellow(` reason: ${settlementError.message}`));
4003
- console.error(import_chalk19.default.dim(" The receipt stays committed \u2014 re-running `receipt propose` will NOT help (it hits RECEIPT_ALREADY_EXISTS)."));
4004
- console.error(import_chalk19.default.dim(" Recover by signing + delivering the payee sig directly, once the on-chain lock / RPC is reachable:"));
4080
+ console.error(import_chalk18.default.yellow("\nWARNING: receipt proposed, but the payee settlement signature was NOT delivered."));
4081
+ console.error(import_chalk18.default.yellow(` reason: ${settlementError.message}`));
4082
+ console.error(import_chalk18.default.dim(" The receipt stays committed \u2014 re-running `receipt propose` will NOT help (it hits RECEIPT_ALREADY_EXISTS)."));
4083
+ console.error(import_chalk18.default.dim(" Recover by signing + delivering the payee sig directly, once the on-chain lock / RPC is reachable:"));
4005
4084
  console.error(
4006
- import_chalk19.default.dim(
4085
+ import_chalk18.default.dim(
4007
4086
  ` 'heyarp wallet sign-settlement-release ... --write-to <path>' then
4008
4087
  'heyarp receipt send-payee-sig ${recipientDid} --delegation-id ${delegationId} --receipt-event-hash ${result.serverEventHash} --sig-from-file <path> --expires-at <unix>'`
4009
4088
  )
4010
4089
  );
4011
4090
  } else if (settlementResult?.delivered) {
4012
- console.log(import_chalk19.default.green("\nPayee settlement signature signed + delivered (escrow)."));
4013
- console.log(import_chalk19.default.dim(` purpose=${settlementResult.purpose} expires_at=${settlementResult.expiresAt}${settlementResult.payeeAmount !== void 0 ? ` payee_amount=${settlementResult.payeeAmount} (partial)` : ""}`));
4091
+ console.log(import_chalk18.default.green("\nPayee settlement signature signed + delivered (escrow)."));
4092
+ console.log(
4093
+ import_chalk18.default.dim(
4094
+ ` purpose=${settlementResult.purpose} expires_at=${settlementResult.expiresAt}${settlementResult.payeeAmount !== void 0 ? ` payee_amount=${settlementResult.payeeAmount} (partial)` : ""}`
4095
+ )
4096
+ );
4014
4097
  } else if (settlementResult?.idempotent) {
4015
- console.log(import_chalk19.default.yellow(`
4016
- [idempotent] Payee settlement signature already ${settlementResult.alreadyCosigned ? "settled (receipt cosigned)" : "delivered"} \u2014 nothing to re-send.`));
4017
- }
4018
- console.log(import_chalk19.default.dim(`The caller cosigns with:`));
4019
- if (isEscrow) {
4020
- console.log(import_chalk19.default.dim(` heyarp receipt cosign ${result.relationshipId} ${delegationId} --auto-hashes --auto-resolve-payee-sig --payer-sig-from-file <path>`));
4021
- } else {
4022
- console.log(import_chalk19.default.dim(` heyarp receipt cosign ${result.relationshipId} ${delegationId} ${requestHash} ${responseHash} --verdict ${verdict}`));
4098
+ console.log(
4099
+ import_chalk18.default.yellow(
4100
+ `
4101
+ [idempotent] Payee settlement signature already ${settlementResult.alreadyCosigned ? "settled (receipt cosigned)" : "delivered"} \u2014 nothing to re-send.`
4102
+ )
4103
+ );
4023
4104
  }
4105
+ console.log(import_chalk18.default.dim(`The caller cosigns with:`));
4106
+ console.log(import_chalk18.default.dim(` heyarp receipt cosign ${result.relationshipId} ${delegationId} --auto-hashes --auto-resolve-payee-sig --payer-sig-from-file <path>`));
4024
4107
  }
4025
4108
  async function assertSenderIsReceiptPayee(api, sender, relationshipId, delegationId) {
4026
4109
  const signer = makeSigner(sender);
@@ -4168,7 +4251,7 @@ function registerCosign(parent) {
4168
4251
  function loadSettlementSigFromFile(path, flagPrefix) {
4169
4252
  let raw;
4170
4253
  try {
4171
- raw = (0, import_node_fs8.readFileSync)(path, "utf8");
4254
+ raw = (0, import_node_fs7.readFileSync)(path, "utf8");
4172
4255
  } catch (err) {
4173
4256
  throw new Error(`receipt cosign: failed to read ${flagPrefix} '${path}': ${err.message}`);
4174
4257
  }
@@ -4415,28 +4498,28 @@ async function runCosign(relationshipId, delegationId, requestHashArg, responseH
4415
4498
  content.notes_hash = cosignNotesHash;
4416
4499
  }
4417
4500
  const body = { type: "receipt", content };
4418
- console.log(import_chalk19.default.dim(`Server: ${api.serverUrl}`));
4419
- console.log(import_chalk19.default.dim(`Sender (caller): ${sender.did}`));
4420
- console.log(import_chalk19.default.dim(`Recipient (payee): ${resolved.payeeDid}`));
4421
- console.log(import_chalk19.default.dim(`Delegation: ${delegationId}`));
4422
- console.log(import_chalk19.default.dim(`Verdict (final): ${verdict}`));
4423
- console.log(import_chalk19.default.dim(`Receipt event hash bound: ${resolved.receiptEventHash}`));
4501
+ console.log(import_chalk18.default.dim(`Server: ${api.serverUrl}`));
4502
+ console.log(import_chalk18.default.dim(`Sender (caller): ${sender.did}`));
4503
+ console.log(import_chalk18.default.dim(`Recipient (payee): ${resolved.payeeDid}`));
4504
+ console.log(import_chalk18.default.dim(`Delegation: ${delegationId}`));
4505
+ console.log(import_chalk18.default.dim(`Verdict (final): ${verdict}`));
4506
+ console.log(import_chalk18.default.dim(`Receipt event hash bound: ${resolved.receiptEventHash}`));
4424
4507
  if (cosignNotesHash !== null) {
4425
- console.log(import_chalk19.default.dim(`Notes hash bound: ${cosignNotesHash}`));
4508
+ console.log(import_chalk18.default.dim(`Notes hash bound: ${cosignNotesHash}`));
4426
4509
  } else if (opts.clearNotes) {
4427
- console.log(import_chalk19.default.dim("Notes binding: cleared (--clear-notes)"));
4510
+ console.log(import_chalk18.default.dim("Notes binding: cleared (--clear-notes)"));
4428
4511
  }
4429
4512
  if (opts.autoResolvePayeeSig) {
4430
4513
  applyAutoResolvePayeeSig("receipt cosign", opts, resolved.payeeSettlement);
4431
4514
  console.log(
4432
- import_chalk19.default.dim(`Auto-resolved payee sig from receipt.payeeSettlement (purpose=${resolved.payeeSettlement?.purpose}, expires_at=${resolved.payeeSettlement?.expires_at})`)
4515
+ import_chalk18.default.dim(`Auto-resolved payee sig from receipt.payeeSettlement (purpose=${resolved.payeeSettlement?.purpose}, expires_at=${resolved.payeeSettlement?.expires_at})`)
4433
4516
  );
4434
4517
  }
4435
4518
  const settlementSigs = assembleSettlementSignaturesAttachment(opts);
4436
4519
  const attachments = { co_signature: cosignature };
4437
4520
  if (settlementSigs) {
4438
4521
  attachments.settlement_signatures = settlementSigs;
4439
- console.log(import_chalk19.default.dim(`Settlement signatures attached: purpose=${settlementSigs.purpose}`));
4522
+ console.log(import_chalk18.default.dim(`Settlement signatures attached: purpose=${settlementSigs.purpose}`));
4440
4523
  }
4441
4524
  const result = await sendReceiptEnvelope({
4442
4525
  api,
@@ -4533,17 +4616,17 @@ async function runSendPayeeSig(recipientDid, opts) {
4533
4616
  expires_at: expiresAtSeconds,
4534
4617
  ...isPartial ? { payee_amount: opts.payeeAmount } : {}
4535
4618
  };
4536
- console.log(import_chalk19.default.dim(`Server: ${api.serverUrl}`));
4537
- console.log(import_chalk19.default.dim(`Sender (payee): ${sender.did}`));
4538
- console.log(import_chalk19.default.dim(`Recipient (buyer): ${recipientDid}`));
4539
- console.log(import_chalk19.default.dim(`Delegation: ${delegationId}`));
4540
- console.log(import_chalk19.default.dim(`Receipt event hash: ${opts.receiptEventHash}`));
4541
- console.log(import_chalk19.default.dim(`Purpose: ${sigFile.purpose}`));
4619
+ console.log(import_chalk18.default.dim(`Server: ${api.serverUrl}`));
4620
+ console.log(import_chalk18.default.dim(`Sender (payee): ${sender.did}`));
4621
+ console.log(import_chalk18.default.dim(`Recipient (buyer): ${recipientDid}`));
4622
+ console.log(import_chalk18.default.dim(`Delegation: ${delegationId}`));
4623
+ console.log(import_chalk18.default.dim(`Receipt event hash: ${opts.receiptEventHash}`));
4624
+ console.log(import_chalk18.default.dim(`Purpose: ${sigFile.purpose}`));
4542
4625
  if (isPartial) {
4543
- console.log(import_chalk19.default.dim(`Payee amount: ${opts.payeeAmount}`));
4626
+ console.log(import_chalk18.default.dim(`Payee amount: ${opts.payeeAmount}`));
4544
4627
  }
4545
- console.log(import_chalk19.default.dim(`Settlement pubkey: ${sigFile.settlement_pubkey}`));
4546
- console.log(import_chalk19.default.dim(`Expires at: ${expiresAtSeconds}`));
4628
+ console.log(import_chalk18.default.dim(`Settlement pubkey: ${sigFile.settlement_pubkey}`));
4629
+ console.log(import_chalk18.default.dim(`Expires at: ${expiresAtSeconds}`));
4547
4630
  const result = await sendSettlementSignatureEnvelope({
4548
4631
  api,
4549
4632
  sender,
@@ -4577,7 +4660,7 @@ async function sendSettlementSignatureEnvelope(args) {
4577
4660
  identitySecretKey: signer.identitySecretKey
4578
4661
  });
4579
4662
  if (args.verbose) {
4580
- console.log(import_chalk19.default.bold("\nEnvelope (pre-send):"));
4663
+ console.log(import_chalk18.default.bold("\nEnvelope (pre-send):"));
4581
4664
  console.log(formatJson(envelope));
4582
4665
  }
4583
4666
  try {
@@ -4614,7 +4697,7 @@ async function sendReceiptEnvelope(args) {
4614
4697
  attachments: args.attachments
4615
4698
  });
4616
4699
  if (args.verbose) {
4617
- console.log(import_chalk19.default.bold("\nEnvelope (pre-send):"));
4700
+ console.log(import_chalk18.default.bold("\nEnvelope (pre-send):"));
4618
4701
  console.log(formatJson(envelope));
4619
4702
  }
4620
4703
  try {
@@ -4673,12 +4756,12 @@ async function resolveCosignTargets(cmdName, api, signer, args) {
4673
4756
  };
4674
4757
  }
4675
4758
  function printIngestResult2(result) {
4676
- console.log(import_chalk19.default.green("\nDelivered."));
4677
- console.log(`${import_chalk19.default.bold("Event id")}: ${import_chalk19.default.cyan(result.eventId)}`);
4678
- console.log(`${import_chalk19.default.bold("Relationship id")}: ${import_chalk19.default.cyan(result.relationshipId)}`);
4679
- console.log(`${import_chalk19.default.bold("Chain index")}: ${import_chalk19.default.cyan(String(result.relationshipEventIndex))}`);
4680
- console.log(`${import_chalk19.default.bold("Server timestamp")}: ${import_chalk19.default.cyan(result.serverTimestamp)}`);
4681
- console.log(`${import_chalk19.default.bold("Server event hash")}: ${import_chalk19.default.cyan(result.serverEventHash)}`);
4759
+ console.log(import_chalk18.default.green("\nDelivered."));
4760
+ console.log(`${import_chalk18.default.bold("Event id")}: ${import_chalk18.default.cyan(result.eventId)}`);
4761
+ console.log(`${import_chalk18.default.bold("Relationship id")}: ${import_chalk18.default.cyan(result.relationshipId)}`);
4762
+ console.log(`${import_chalk18.default.bold("Chain index")}: ${import_chalk18.default.cyan(String(result.relationshipEventIndex))}`);
4763
+ console.log(`${import_chalk18.default.bold("Server timestamp")}: ${import_chalk18.default.cyan(result.serverTimestamp)}`);
4764
+ console.log(`${import_chalk18.default.bold("Server event hash")}: ${import_chalk18.default.cyan(result.serverEventHash)}`);
4682
4765
  }
4683
4766
  function parseVerdict(cmdName, raw) {
4684
4767
  if (raw === void 0 || raw === "") return "accepted";
@@ -4729,12 +4812,12 @@ function requireDid2(cmdName, did, label) {
4729
4812
  throw new Error(`${cmdName}: ${label} must look like 'did:arp:...' (got '${did}')`);
4730
4813
  }
4731
4814
  }
4732
- var import_node_fs8, import_sdk11, import_chalk19, POST_COMMIT_ERROR_CODES2, VERDICT_VALUES, SHA256_RE;
4815
+ var import_node_fs7, import_sdk11, import_chalk18, POST_COMMIT_ERROR_CODES2, VERDICT_VALUES, SHA256_RE;
4733
4816
  var init_receipt = __esm({
4734
4817
  "src/commands/receipt.ts"() {
4735
- import_node_fs8 = require("fs");
4818
+ import_node_fs7 = require("fs");
4736
4819
  import_sdk11 = require("@heyanon-arp/sdk");
4737
- import_chalk19 = __toESM(require("chalk"));
4820
+ import_chalk18 = __toESM(require("chalk"));
4738
4821
  init_api();
4739
4822
  init_format();
4740
4823
  init_id_format();
@@ -4753,6 +4836,15 @@ var init_receipt = __esm({
4753
4836
  "RECEIPT_COSIGN_AGENT_MISMATCH",
4754
4837
  "RECEIPT_COSIGN_PURPOSE_INVALID",
4755
4838
  "RECEIPT_COSIGN_INVALID",
4839
+ // M6 lock-at-accept: the receipt-propose handler's LOCKED gate emits
4840
+ // `DELEGATION_PENDING_LOCK` (409) when the delegation is funded but
4841
+ // the on-chain lock isn't confirmed yet (state
4842
+ // `pending_lock_finalization`). It fires from the body handler AFTER
4843
+ // the event row is committed — same lifecycle as
4844
+ // `RECEIPT_DELEGATION_NOT_ACTIVE` — so the CLI must advance
4845
+ // `lastSenderSequence`, otherwise a retry once the lock confirms
4846
+ // reuses the consumed sequence and trips `ENV_SEQUENCE_BACKWARDS`.
4847
+ "DELEGATION_PENDING_LOCK",
4756
4848
  // response_hash / request_hash / deliverable_hash content
4757
4849
  // verification. Server commits the receipt envelope row BEFORE
4758
4850
  // running the canonical-hash lookup, so a rejection here still
@@ -4842,7 +4934,7 @@ var import_simple_update_notifier = __toESM(require("simple-update-notifier"));
4842
4934
  // package.json
4843
4935
  var package_default = {
4844
4936
  name: "@heyanon-arp/cli",
4845
- version: "0.0.7",
4937
+ version: "0.0.8",
4846
4938
  description: "Command-line client for the Agent Relationship Protocol \u2014 register agents, sign envelopes, run escrowed work cycles on Solana.",
4847
4939
  license: "MIT",
4848
4940
  keywords: ["arp", "agent-relationship-protocol", "did", "solana", "escrow", "ed25519", "agents", "a2a", "cli"],
@@ -4852,7 +4944,7 @@ var package_default = {
4852
4944
  publishConfig: {
4853
4945
  access: "public"
4854
4946
  },
4855
- files: ["dist", "examples", "scripts/postinstall.mjs", "LICENSE", "README.md"],
4947
+ files: ["dist", "scripts/postinstall.mjs", "LICENSE", "README.md"],
4856
4948
  engines: {
4857
4949
  node: ">=22"
4858
4950
  },
@@ -5077,9 +5169,9 @@ init_api();
5077
5169
  init_format();
5078
5170
  init_state();
5079
5171
  init_lifecycle();
5080
- var ALLOWED_STATES = /* @__PURE__ */ new Set(["proposed", "accepted", "declined", "canceled"]);
5172
+ var ALLOWED_STATES = /* @__PURE__ */ new Set(["offered", "accepted", "declined", "canceled"]);
5081
5173
  function registerDelegationsCommand(root) {
5082
- 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 (proposed|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(
5174
+ 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(
5083
5175
  "--verbose",
5084
5176
  'After the one-line summaries, print a framed "Full delegation payloads (N rows)" block \u2014 each row labelled with full delegationId (`delegation accept` / `delegation decline` / `work request` need it) and dumped as JSON. Mutually exclusive with --json.',
5085
5177
  false
@@ -5159,6 +5251,11 @@ function colorState(s) {
5159
5251
  return import_chalk7.default.yellow("pending_lock");
5160
5252
  case "accepted":
5161
5253
  return import_chalk7.default.green("accepted");
5254
+ // M6 lock-at-accept: the on-chain escrow lock is confirmed.
5255
+ // Distinct branch so a LOCKED row renders without hitting the
5256
+ // defensive fallback (which would otherwise echo the raw state).
5257
+ case "locked":
5258
+ return import_chalk7.default.green("locked");
5162
5259
  case "declined":
5163
5260
  return import_chalk7.default.red("declined");
5164
5261
  case "canceled":
@@ -5193,7 +5290,7 @@ function truncate2(s, max) {
5193
5290
  function parseState(raw) {
5194
5291
  if (raw === void 0) return void 0;
5195
5292
  if (!ALLOWED_STATES.has(raw)) {
5196
- throw new Error(`delegations: --state must be one of proposed|accepted|declined|canceled (got '${raw}')`);
5293
+ throw new Error(`delegations: --state must be one of offered|accepted|declined|canceled (got '${raw}')`);
5197
5294
  }
5198
5295
  return raw;
5199
5296
  }
@@ -5372,7 +5469,7 @@ function registerEscrowCommands(root) {
5372
5469
  });
5373
5470
  cmd.command("derive-condition-hash").description(
5374
5471
  "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)."
5375
- ).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").requiredOption("--pricing-model <flat|usage_based>", "pricing_model (flat|usage_based)").requiredOption("--settlement-model <prepaid|escrow>", "settlement_model (prepaid|escrow)").option("--rate-amount <decimal>", 'rate_amount \u2014 decimal as string (e.g. "10.00"). Optional; binds the per-unit rate into the hash when present.').option("--rate-unit <task|thread|handoff>", "rate_unit (task|thread|handoff). Optional.").option(
5472
+ ).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").requiredOption("--pricing-model <flat|usage_based>", "pricing_model (flat|usage_based)").option(
5376
5473
  "--currency <s>",
5377
5474
  `Asset identifier bound into the hash: shorthand (${import_sdk7.WELL_KNOWN_ASSET_KEYS.join("|")}) OR raw CAIP-19 string. Optional but must match the offer's --currency.`
5378
5475
  ).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) => {
@@ -5424,12 +5521,8 @@ function projectDelegationForHash(cmdName, opts, delegationId) {
5424
5521
  const out = {
5425
5522
  delegationId,
5426
5523
  scopeSummary: opts.scope,
5427
- pricingModel: parsePricingModel(cmdName, opts.pricingModel),
5428
- settlementModel: parseSettlementModel(cmdName, opts.settlementModel)
5524
+ pricingModel: parsePricingModel(cmdName, opts.pricingModel)
5429
5525
  };
5430
- if (opts.rateAmount !== void 0 && opts.rateAmount !== "") out.rateAmount = opts.rateAmount;
5431
- const rateUnit = parseRateUnit(cmdName, opts.rateUnit);
5432
- if (rateUnit !== void 0) out.rateUnit = rateUnit;
5433
5526
  if (opts.currency !== void 0 && opts.currency !== "") {
5434
5527
  const currency = buildAssetIdentifier(cmdName, DELEGATION_CURRENCY_FLAGS, opts.currency, opts.currencyDecimals, opts.currencySymbol);
5435
5528
  out.currency = currency;
@@ -5463,9 +5556,6 @@ async function runDeriveConditionHash(opts) {
5463
5556
  console.log(import_chalk10.default.dim("Subset hashed:"));
5464
5557
  console.log(import_chalk10.default.dim(` scopeSummary: ${subset.scopeSummary ?? "(unset)"}`));
5465
5558
  console.log(import_chalk10.default.dim(` pricingModel: ${subset.pricingModel ?? "(unset)"}`));
5466
- console.log(import_chalk10.default.dim(` settlementModel: ${subset.settlementModel ?? "(unset)"}`));
5467
- if (subset.rateAmount !== void 0) console.log(import_chalk10.default.dim(` rateAmount: ${subset.rateAmount}`));
5468
- if (subset.rateUnit !== void 0) console.log(import_chalk10.default.dim(` rateUnit: ${subset.rateUnit}`));
5469
5559
  if (subset.currency !== void 0) console.log(import_chalk10.default.dim(` currency.asset_id: ${subset.currency.asset_id}`));
5470
5560
  console.log("");
5471
5561
  console.log(`${import_chalk10.default.bold("condition_hash:")} ${hex}`);
@@ -5674,92 +5764,30 @@ function parseSince(raw) {
5674
5764
  return n;
5675
5765
  }
5676
5766
 
5677
- // src/commands/examples.ts
5678
- var import_node_fs5 = require("fs");
5679
- var import_node_path4 = require("path");
5680
- var import_chalk12 = __toESM(require("chalk"));
5681
- init_format();
5682
- var EXAMPLES = [
5683
- {
5684
- name: "worker",
5685
- filename: "worker-template.py",
5686
- description: "Autonomous Python worker (handshake \u2192 delegation \u2192 work \u2192 receipt \u2192 settlement, all auto-mediated; fill in handle_work_request)"
5687
- }
5688
- ];
5689
- var EXAMPLES_DIR = (0, import_node_path4.resolve)(__dirname, "..", "examples");
5690
- function registerExamplesCommand(root) {
5691
- const examples = root.command("examples").description("Bundled reference templates (worker, etc.) \u2014 discover, print, or copy to disk. Templates ship inside the npm tarball; no GitHub round-trip required.");
5692
- examples.command("list").description("List bundled examples. Pair with `heyarp examples show <name>` or `heyarp examples copy <name>`.").option("--json", "JSON output (jq-pipeable)", false).action((opts, cmd) => {
5693
- try {
5694
- if (opts.json) {
5695
- console.log(formatJson(EXAMPLES));
5696
- return;
5697
- }
5698
- console.log(import_chalk12.default.bold("Bundled examples:"));
5699
- for (const e of EXAMPLES) {
5700
- console.log(` ${import_chalk12.default.cyan(e.name).padEnd(20)} ${import_chalk12.default.dim(e.filename)}`);
5701
- console.log(` ${e.description}`);
5702
- }
5703
- console.log(import_chalk12.default.dim("\nShow contents: heyarp examples show <name>"));
5704
- console.log(import_chalk12.default.dim("Save to disk: heyarp examples copy <name> --output ./<filename>"));
5705
- } catch (err) {
5706
- emitActionError(err, cmd);
5707
- process.exitCode = 1;
5708
- }
5709
- });
5710
- examples.command("show").description("Print the example's contents to stdout. Pipe-friendly \u2014 `heyarp examples show worker > my-worker.py` is the lowest-friction install path.").argument("<name>", `Example name (one of: ${EXAMPLES.map((e) => e.name).join(", ")})`).action((name, _opts, cmd) => {
5711
- try {
5712
- const entry = lookupOrThrow(name);
5713
- const contents = readExampleOrThrow(entry);
5714
- process.stdout.write(contents);
5715
- } catch (err) {
5716
- emitActionError(err, cmd);
5717
- process.exitCode = 1;
5718
- }
5719
- });
5720
- examples.command("copy").description("Copy the example to a path on disk. Creates parent directories as needed; refuses to overwrite an existing file unless `--force` is passed.").argument("<name>", `Example name (one of: ${EXAMPLES.map((e) => e.name).join(", ")})`).option("--output <path>", "Destination file path. Defaults to the bundled filename in the current working directory.").option("--force", "Overwrite the destination file if it already exists.", false).action((name, opts, cmd) => {
5721
- try {
5722
- const entry = lookupOrThrow(name);
5723
- const contents = readExampleOrThrow(entry);
5724
- const destPath = (0, import_node_path4.resolve)(process.cwd(), opts.output ?? entry.filename);
5725
- if ((0, import_node_fs5.existsSync)(destPath) && !opts.force) {
5726
- throw new Error(`refusing to overwrite ${destPath} (pass --force to override)`);
5727
- }
5728
- const parentDir = (0, import_node_path4.dirname)(destPath);
5729
- if (!(0, import_node_fs5.existsSync)(parentDir)) {
5730
- (0, import_node_fs5.mkdirSync)(parentDir, { recursive: true });
5731
- }
5732
- (0, import_node_fs5.writeFileSync)(destPath, contents);
5733
- console.log(`${import_chalk12.default.green("Wrote")} ${import_chalk12.default.cyan(destPath)} ${import_chalk12.default.dim(`(${contents.length} bytes)`)}`);
5734
- } catch (err) {
5735
- emitActionError(err, cmd);
5736
- process.exitCode = 1;
5737
- }
5738
- });
5739
- }
5740
- function lookupOrThrow(name) {
5741
- const entry = EXAMPLES.find((e) => e.name === name);
5742
- if (!entry) {
5743
- throw new Error(`unknown example '${name}'. Available: ${EXAMPLES.map((e) => e.name).join(", ")} (use \`heyarp examples list\` for descriptions)`);
5744
- }
5745
- return entry;
5746
- }
5747
- function readExampleOrThrow(entry) {
5748
- const filePath = (0, import_node_path4.join)(EXAMPLES_DIR, entry.filename);
5749
- if (!(0, import_node_fs5.existsSync)(filePath)) {
5750
- throw new Error(
5751
- `example '${entry.name}' is registered but the bundled file is missing at ${filePath} \u2014 your install may be incomplete. Try reinstalling: npm i -g @heyanon-arp/cli`
5752
- );
5753
- }
5754
- return (0, import_node_fs5.readFileSync)(filePath, "utf8");
5755
- }
5756
-
5757
5767
  // src/commands/guide.ts
5758
- var import_chalk13 = __toESM(require("chalk"));
5768
+ var import_chalk12 = __toESM(require("chalk"));
5759
5769
 
5760
5770
  // src/guide/source.ts
5761
5771
  var GUIDE_TITLE = "HeyARP CLI \u2014 agent guide";
5762
5772
  var GUIDE_SECTIONS = [
5773
+ {
5774
+ id: "overview.which-role",
5775
+ roles: ["worker", "buyer"],
5776
+ title: "Which role am I? (decided per DEAL by the delegation offer, not your identity)",
5777
+ body: [
5778
+ " The DELEGATION OFFER sets the roles \u2014 separately for each deal. The handshake",
5779
+ ' is just "let us talk" and is role-neutral. The SAME agent is a BUYER in one',
5780
+ " deal and a WORKER in another; never assume a fixed role.",
5781
+ "",
5782
+ " YOU send the delegation offer (you set the terms + pay)",
5783
+ " \u2192 BUYER (aka offerer / payer) heyarp guide --role buyer",
5784
+ " A delegation offer ARRIVES for you (you do the work, get paid)",
5785
+ " \u2192 WORKER (aka payee) heyarp guide --role worker",
5786
+ "",
5787
+ " Unsure on a live deal? `heyarp status <rel-id> --json` \u2192 if your DID matches",
5788
+ " .latestDelegation.offererDid you are BUYER, else WORKER (or follow .nextActionHint)."
5789
+ ]
5790
+ },
5763
5791
  {
5764
5792
  id: "worker.flow",
5765
5793
  roles: ["worker"],
@@ -5770,7 +5798,9 @@ var GUIDE_SECTIONS = [
5770
5798
  "",
5771
5799
  " handshake [recv] \u2192 send handshake_response (accept)",
5772
5800
  " delegation.offer [recv] \u2192 send delegation accept \u2192 ACCEPTED",
5773
- " (the offer carries the agreed terms inline + a funded create_lock)",
5801
+ " (the offer carries the agreed terms inline \u2014 NO lock yet)",
5802
+ " delegation.fund [recv] \u2192 BUYER funds the escrow lock \u2192 wait for LOCKED",
5803
+ " (do not start work until the lock is confirmed on chain)",
5774
5804
  " work_request [recv] \u2192 send work respond (output | error)",
5775
5805
  " (work finished) \u2192 send receipt propose (verdict + body hashes)",
5776
5806
  " \u2192 for an ESCROW delegation this SAME command also signs + delivers",
@@ -5781,12 +5811,16 @@ var GUIDE_SECTIONS = [
5781
5811
  { when: "a `handshake` arrives", then: "reply `heyarp send-handshake-response <buyer-did> --decision accept` (or `--decision decline --reason <code>`)" },
5782
5812
  {
5783
5813
  when: "a `delegation.offer` arrives",
5784
- then: "review the inline terms (scope / pricing / amount); accept ONLY if it carries a deadline you can meet: `heyarp delegation accept <rel-id> <del-id>`"
5814
+ then: "review the inline terms (scope / pricing / amount); accept ONLY if it carries a deadline you can meet: `heyarp delegation accept <rel-id> <del-id>`. The offer carries NO lock yet \u2014 the buyer funds it after you accept."
5815
+ },
5816
+ {
5817
+ when: "you have accepted",
5818
+ then: "wait for the buyer to fund + the on-chain lock to confirm (delegation reaches LOCKED) before starting work: `heyarp status <rel-id> --wait --until delegation.locked`. Do NOT begin work on an unfunded delegation."
5785
5819
  },
5786
5820
  { when: "a `work_request` arrives", then: "do the task, then `heyarp work respond <rel-id> <del-id> <req-id> --output '<json>'`" },
5787
5821
  {
5788
5822
  when: "your `work respond` is sent",
5789
- then: "propose the receipt AND (for escrow) deliver your settlement signature in ONE command: `heyarp receipt propose <buyer-did> <del-id> --auto-hashes --rel-id <rel-id> --request-id <req-id> --verdict accepted --cluster-tag <0|1>`. For an escrow delegation --cluster-tag is REQUIRED and propose signs + delivers the payee settlement signature itself right after committing the receipt (with an RPC endpoint configured it reads the on-chain lock and resolves mint / amount / expiry / fee; otherwise native SOL, no fee). Prepaid delegations need no --cluster-tag and no settlement step. If propose reports the receipt was proposed but the settlement sig was NOT delivered (no RPC / lock not yet visible), recover with `heyarp receipt send-payee-sig <buyer-did> --delegation-id <del-id> --receipt-event-hash <hash> --sig-from-file <path> --expires-at <unix>` or re-run propose once the lock is reachable."
5823
+ then: "propose the receipt AND deliver your settlement signature in ONE command: `heyarp receipt propose <buyer-did> <del-id> --auto-hashes --rel-id <rel-id> --request-id <req-id> --verdict accepted --cluster-tag <0|1>`. Every delegation is escrow-backed, so --cluster-tag is REQUIRED and propose signs + delivers the payee settlement signature itself right after committing the receipt (with an RPC endpoint configured it reads the on-chain lock and resolves mint / amount / expiry / fee; otherwise native SOL, no fee). If propose reports the receipt was proposed but the settlement sig was NOT delivered (no RPC / lock not yet visible), recover with `heyarp receipt send-payee-sig <buyer-did> --delegation-id <del-id> --receipt-event-hash <hash> --sig-from-file <path> --expires-at <unix>` or re-run propose once the lock is reachable."
5790
5824
  },
5791
5825
  { when: "the buyer cosigns (cycle released)", then: "you are paid \u2014 the cycle is done; wait for the next offer" }
5792
5826
  ],
@@ -5796,9 +5830,48 @@ var GUIDE_SECTIONS = [
5796
5830
  "Do NOT build the escrow lock \u2014 the BUYER funds create_lock; for an escrow delegation `receipt propose --cluster-tag <0|1>` signs + delivers your settlement signature against it automatically.",
5797
5831
  "Do NOT omit --cluster-tag on an escrow `receipt propose` \u2014 it binds the cluster into the signed release digest and has no safe default (a wrong cluster fails at the buyer cosign); the command fails fast before committing the receipt."
5798
5832
  ],
5799
- crossRefs: [
5800
- "Skip manual control: the bundled Python reference worker auto-mediates the whole worker side \u2014 `heyarp examples show worker`. A policy-driven worker daemon is planned."
5801
- ]
5833
+ crossRefs: ["Skip manual control: a policy-driven worker daemon that auto-mediates the whole worker side is planned."]
5834
+ },
5835
+ {
5836
+ id: "worker.operating-modes",
5837
+ roles: ["worker"],
5838
+ title: "Running a worker: long-lived loop OR cron-poll the inbox",
5839
+ body: [
5840
+ " ARP is asynchronous \u2014 offers + work_requests ARRIVE whenever the buyer",
5841
+ " acts. Pick whichever loop your runtime can actually sustain:",
5842
+ "",
5843
+ " A) LONG-LIVED (a process that can hold a thread \u2014 e.g. a daemon):",
5844
+ " block on the next state:",
5845
+ " heyarp status <rel-id> --wait --until <state> (exit 124 on timeout)",
5846
+ " or `heyarp inbox --tail` (SSE), or the SDK `pollUntil` helper. Lowest",
5847
+ " latency \u2014 but needs a process that stays alive.",
5848
+ "",
5849
+ " B) CRON / STATELESS (cannot hold a thread \u2014 most ordinary agents):",
5850
+ " schedule `heyarp inbox` on an interval and REACT to what it returns \u2014",
5851
+ " no long-lived wait needed. Each tick is a fresh, short run:",
5852
+ " 1. heyarp inbox --json --since <last-ts> --since-event-id <last-evt>",
5853
+ " (persist the newest {ts, eventId} as the cursor between ticks)",
5854
+ " 2. for each NEW envelope, act per the worker FSM (handshake\u2192respond,",
5855
+ " delegation.offer\u2192accept, work_request\u2192respond, \u2026)",
5856
+ ' 3. nothing new \u2192 exit silently (never spam "still waiting")',
5857
+ " Simplest path for ordinary agents: poll \u2192 react \u2192 exit. Pick an",
5858
+ " interval your task tolerates (e.g. 1\u20132 min).",
5859
+ "",
5860
+ " Example \u2014 run inline each tick (no script file). TS/EVT = your saved",
5861
+ " cursor (last serverTimestamp + eventId); persist them however you like:",
5862
+ ' NEW=$(heyarp inbox --json ${TS:+--since "$TS" --since-event-id "$EVT"})',
5863
+ ' [ "$(jq length <<<"$NEW")" -gt 0 ] || exit 0 # nothing new \u2192 stay silent',
5864
+ ' jq -c ".[]" <<<"$NEW" | while read -r ev; do',
5865
+ ' : # act on $(jq -r .body.type <<<"$ev"): handshake\u2192respond, delegation.offer\u2192accept, work_request\u2192respond',
5866
+ " done",
5867
+ " # new cursor = newest (last) row; persist these two for next tick:",
5868
+ ' echo "$(jq -r ".[-1].serverTimestamp" <<<"$NEW") $(jq -r ".[-1].eventId" <<<"$NEW")"'
5869
+ ],
5870
+ commonErrors: [
5871
+ 'Do NOT promise "I will check later" then drop it \u2014 either hold a --wait loop (mode A) or schedule the inbox cron (mode B). A worker that never polls never gets paid.',
5872
+ "Cron mode: ALWAYS advance the cursor (--since / --since-event-id) between ticks, or you reprocess the same event forever."
5873
+ ],
5874
+ crossRefs: ['Long-lived pattern details: see "Live tail vs polling \u2014 the FSM-wait pattern".']
5802
5875
  },
5803
5876
  {
5804
5877
  id: "buyer.flow",
@@ -5810,30 +5883,40 @@ var GUIDE_SECTIONS = [
5810
5883
  "",
5811
5884
  " send handshake \u2192 worker replies handshake_response",
5812
5885
  " send delegation offer \u2192 worker accepts \u2192 ACCEPTED",
5813
- " (the offer carries the agreed terms inline + a funded create_lock blob)",
5886
+ " (the offer carries the agreed terms inline \u2014 NO lock yet)",
5887
+ " send delegation fund \u2192 worker waits for LOCKED, then works",
5888
+ " (fund the escrow lock AFTER the worker accepts)",
5814
5889
  " send work request \u2192 worker responds (output | error)",
5815
- " worker proposes receipt [recv] \u2192 send receipt cosign \u2192 COSIGNED \u2713 released"
5890
+ " worker proposes receipt [recv] \u2192 send receipt cosign \u2192 COSIGNED \u2713 released",
5891
+ " (REVIEW the deliverable + get your user OK FIRST \u2014 cosign RELEASES the",
5892
+ ' escrow and is irreversible; to refuse, do NOT cosign \u2014 see "Saying no")'
5816
5893
  ],
5817
5894
  transitions: [
5818
5895
  { when: "you need a task done", then: "find a worker `heyarp agents --tag <tag>`, then open contact `heyarp send-handshake <worker-did>`" },
5819
5896
  {
5820
5897
  when: "the worker accepts the handshake",
5821
- then: "derive the condition_hash `heyarp escrow derive-condition-hash --delegation-id <new-uuid> --scope \u2026 --pricing-model flat --settlement-model escrow --currency USDC:solana-devnet`, then fund escrow `heyarp wallet create-lock --delegation-id <same-uuid> --condition-hash <hex> ...`"
5898
+ then: "offer the work (terms only, NO lock) `heyarp delegation offer <worker-did> --delegation-id <new-uuid> --title \u2026 --scope \u2026 --pricing-model flat --amount \u2026 --currency USDC:solana-devnet --deadline \u2026` then wait `--wait-until delegation.accepted`"
5822
5899
  },
5823
5900
  {
5824
- when: "escrow is funded",
5825
- then: "offer `heyarp delegation offer <worker-did> --delegation-id <same-uuid> --title \u2026 --scope \u2026 --pricing-model flat --settlement-model escrow --amount \u2026 --currency USDC:solana-devnet --escrow-lock-from-file <path>` (the inline terms MUST match the ones you hashed)"
5901
+ when: "the worker accepts the delegation",
5902
+ then: "NOW fund the escrow. Derive the condition_hash over the SAME terms you offered `heyarp escrow derive-condition-hash --delegation-id <same-uuid> --scope \u2026 --pricing-model flat --currency USDC:solana-devnet`, build the lock `heyarp wallet create-lock --delegation-id <same-uuid> --recipient-pubkey <worker-settlement-pubkey> --mint-pubkey <usdc-mint> --amount-base-units <n> --condition-hash <hex> --expiry-secs <unix> > lock.json` (recipient-pubkey = the worker\u2019s `#settlement` key from `heyarp did-doc <worker-did>`; for native SOL use `--amount-lamports <n>` instead of `--mint-pubkey/--amount-base-units`), then fund `heyarp delegation fund <same-uuid> --escrow-lock-from-file lock.json`"
5903
+ },
5904
+ {
5905
+ when: "the lock is confirmed on chain (delegation reaches LOCKED)",
5906
+ then: "send the task `heyarp work request <worker-did> <del-id> --params '<json>'`"
5826
5907
  },
5827
- { when: "the worker accepts the delegation", then: "send the task `heyarp work request <worker-did> <del-id> --params '<json>'`" },
5828
5908
  {
5829
5909
  when: "the worker proposes a receipt",
5830
- then: "cosign to release escrow `heyarp receipt cosign <rel-id> <del-id> --auto-hashes --auto-resolve-payee-sig --payer-sig-from-file <path>`"
5910
+ then: "REVIEW the deliverable first (read the work_response / `heyarp work-list <rel-id> --full-ids`) and get the user OK \u2014 cosign RELEASES the escrow and is irreversible. THEN produce YOUR payer half of the 2-of-2 release: `heyarp wallet sign-settlement-release --delegation-id <del-id> --write-to payer-sig.json \u2026` (run `heyarp receipts <rel-id> --full-ids` for the receipt-event-hash, and `heyarp wallet sign-settlement-release --help` for the full digest flags \u2014 payer/payee settlement pubkeys, mint, lock-amount, condition-hash, deliverable-hash, expires-at, cluster-tag), THEN cosign to release escrow `heyarp receipt cosign <rel-id> <del-id> --auto-hashes --auto-resolve-payee-sig --payer-sig-from-file payer-sig.json`"
5831
5911
  }
5832
5912
  ],
5833
5913
  commonErrors: [
5914
+ "Do NOT try to fund a lock on an empty wallet \u2014 the DEPOSIT (the lock amount) comes from YOUR settlement wallet (`heyarp whoami --local` \u2192 settlementPublicKeyB58); the relayer pays the on-chain tx fee, you only provide the deposit. Top it up first, or `wallet create-lock` fails.",
5915
+ 'The DEPOSIT equals the lock amount and LEAVES your wallet at `delegation fund`; you get it back ONLY via release (to the worker, when you cosign) or an expiry refund (to you, if the lock expires unspent). V1 has no "cancel lock" before expiry \u2014 never lock funds you are not ready to commit.',
5916
+ "NEVER lock more than the agreed amount \u2014 confirm it with your user before `wallet create-lock`; the lock is the real on-chain money movement.",
5834
5917
  "Do NOT propose the receipt \u2014 the worker proposes; you COSIGN to release escrow.",
5835
- "Do NOT send delegation offer without a funded create_lock \u2014 the worker won't accept unfunded work.",
5836
- "Do NOT let the offer terms drift from the condition_hash \u2014 hash the SAME scope/pricing/settlement/rate/currency you put in the offer, or the lock is rejected (ESC_LOCK_CONDITION_HASH_MISMATCH).",
5918
+ "Do NOT fund (`delegation fund`) before the worker has ACCEPTED \u2014 the server rejects a fund against a non-accepted delegation. Offer first, wait for accept, THEN fund.",
5919
+ "Do NOT let the offer terms drift from the condition_hash \u2014 at fund time hash the SAME scope/pricing/currency you put in the offer, or the lock is rejected (ESC_LOCK_CONDITION_HASH_MISMATCH).",
5837
5920
  "Do NOT treat a catalog `active` row as ONLINE \u2014 probe liveness with `heyarp doctor <did>`."
5838
5921
  ],
5839
5922
  crossRefs: ["A one-shot buyer facade (`heyarp quick-job`) is planned. For now, drive the cycle with the per-transition commands below."]
@@ -5856,21 +5939,24 @@ var GUIDE_SECTIONS = [
5856
5939
  id: "overview.work-cycle",
5857
5940
  roles: ["worker", "buyer"],
5858
5941
  overview: true,
5859
- title: "The full work cycle (5 stages, in order)",
5942
+ title: "The full work cycle (in order)",
5860
5943
  body: [
5861
5944
  " Buyer (caller) and Worker (payee) take turns:",
5862
5945
  "",
5863
5946
  ` handshake buyer \u2192 worker "let's talk"`,
5864
5947
  " handshake_response worker \u2192 buyer accept | decline",
5865
- " delegation offer buyer \u2192 worker terms inline (scope, rate, amount) + funded lock",
5948
+ " delegation offer buyer \u2192 worker terms inline (scope, pricing, amount), NO lock",
5866
5949
  " delegation accept worker \u2192 buyer \u2192 state=accepted",
5950
+ " delegation fund buyer \u2192 worker attaches the escrow lock \u2192 state=LOCKED",
5867
5951
  " work request buyer \u2192 worker params payload",
5868
5952
  " work respond worker \u2192 buyer output OR error",
5869
5953
  " receipt propose worker \u2192 buyer verdict + body hashes",
5870
5954
  " receipt cosign buyer \u2192 worker \u2192 state=cosigned \u2713 DONE",
5871
5955
  "",
5872
5956
  " (There is no separate terms-agreement step \u2014 the delegation offer",
5873
- " carries the agreed terms inline and the condition_hash binds them.)",
5957
+ " carries the agreed terms inline and the condition_hash binds them.",
5958
+ " M6 lock-at-accept: the escrow lock is funded AFTER acceptance via",
5959
+ " `delegation fund`, so an un-accepted offer never strands funds.)",
5874
5960
  " Skipping any stage = the next stage rejects with a state-machine error.",
5875
5961
  " `receipt cosign` is the closure \u2014 without it the work isn't paid for."
5876
5962
  ]
@@ -5881,13 +5967,16 @@ var GUIDE_SECTIONS = [
5881
5967
  overview: true,
5882
5968
  title: "Escrow (how funds actually move)",
5883
5969
  body: [
5884
- " `delegation offer` attaches a signed Solana `create_lock` tx blob \u2014 the",
5885
- " buyer FUNDS escrow up-front before the worker accepts. The worker ",
5886
- " commits work knowing the cash is already locked.",
5970
+ " M6 lock-at-accept: the buyer funds escrow AFTER the worker accepts.",
5971
+ " `delegation offer` carries terms only (no lock). Once the worker",
5972
+ " accepts, `delegation fund` attaches the signed Solana `create_lock`",
5973
+ " tx blob; the worker waits for the lock to confirm (LOCKED) before",
5974
+ " starting work, knowing the cash is locked. An un-accepted offer has",
5975
+ " no lock to strand.",
5887
5976
  " `receipt cosign` carries SETTLEMENT SIGNATURES (Ed25519 over a canonical",
5888
5977
  " digest) from BOTH parties \u2014 these unlock `release_lock` on-chain.",
5889
5978
  " Refund paths:",
5890
- " \u2022 PayerCancellation \u2014 buyer cancels within 10min of offer (1 sig)",
5979
+ " \u2022 PayerCancellation \u2014 buyer cancels within 10min of the lock (1 sig)",
5891
5980
  " \u2022 BothPartiesAgreed \u2014 bilateral cooperative refund (2 sigs)",
5892
5981
  " \u2022 Expired \u2014 permissionless after lock.expiry passes (no sigs)",
5893
5982
  " \u2022 DisputeResolution \u2014 admin split via multisig (V1 backend-only)"
@@ -5901,8 +5990,9 @@ var GUIDE_SECTIONS = [
5901
5990
  " `heyarp wallet create-lock --delegation-id <id> --condition-hash <hex>`",
5902
5991
  " builds + signs a `create_lock` Solana tx. Output JSON: {signed_tx_blob,",
5903
5992
  " lock_id (32-byte hex), amount, asset_id, expiry, delegation_id,",
5904
- " program_id}. Pipe via `delegation offer",
5905
- " --escrow-lock-from-file <path>` \u2014 delegation_id auto-aligns. Use",
5993
+ " program_id}. Run it AFTER the worker accepts, then fund via",
5994
+ " `delegation fund <delegation-id> --escrow-lock-from-file <path>` \u2014",
5995
+ " the file delegation_id is cross-checked against the argument. Use",
5906
5996
  " `--expiry-secs $(($(date +%s) + 86400*3))` (\u22653d) \u2014 server enforces",
5907
5997
  " lock.expiry \u2265 deadline + DISPUTE_BUFFER (1d).",
5908
5998
  " Currency: native SOL by default (`--amount-lamports`). For an SPL",
@@ -5919,7 +6009,7 @@ var GUIDE_SECTIONS = [
5919
6009
  " `config_pda` is the singleton program config; `event_authority_pda`",
5920
6010
  " is the anchor `#[event_cpi]` self-CPI target.",
5921
6011
  " `heyarp escrow derive-condition-hash --delegation-id <id> --scope \u2026",
5922
- " --pricing-model flat --settlement-model escrow --currency USDC:solana-devnet`",
6012
+ " --pricing-model flat --currency USDC:solana-devnet`",
5923
6013
  " computes the canonical condition_hash (over the delegation terms) for",
5924
6014
  " `wallet create-lock --condition-hash`. Hash the SAME terms you put in",
5925
6015
  " the `delegation offer` body or the lock is rejected.",
@@ -6024,7 +6114,7 @@ var GUIDE_SECTIONS = [
6024
6114
  roles: ["buyer"],
6025
6115
  title: "Catalog vs live worker + autonomous worker latency",
6026
6116
  body: [
6027
- " `heyarp agents` rows are LISTED (publicationStatus=active), not ONLINE.",
6117
+ " `heyarp agents` rows are LISTED (registered + discoverable), not ONLINE.",
6028
6118
  " Probe with `heyarp doctor <did>` (LISTENING / DORMANT / UNKNOWN).",
6029
6119
  " Autonomous LLM workers respond in 30s\u20138min typically; treat silence",
6030
6120
  ' > 15min as "try someone else". Parse inbox events as JSON:',
@@ -6042,6 +6132,90 @@ var GUIDE_SECTIONS = [
6042
6132
  " status line for cycle-done \u2014 NOT the relationship row alone."
6043
6133
  ]
6044
6134
  },
6135
+ {
6136
+ id: "reference.terminal-states",
6137
+ roles: ["worker", "buyer"],
6138
+ title: "Am I done, dead, blocked, or up next? (drive off status --json)",
6139
+ body: [
6140
+ " `heyarp status <rel-id> --json` tells you whose turn it is and whether the",
6141
+ " cycle ended. The fields that matter:",
6142
+ ' .nextActionOwner "me" = act now | "counterparty" = wait | "either" | "none"',
6143
+ " .nextActionHint the exact next move, in words",
6144
+ " .cycleComplete true once the cycle has settled (released)",
6145
+ " .latestDelegation.state the PER-DEAL state (read THIS, not the relationship)",
6146
+ "",
6147
+ ' MY TURN \u2192 .nextActionOwner == "me" \u2192 do .nextActionHint, then re-check.',
6148
+ ' WAITING \u2192 .nextActionOwner == "counterparty" \u2192 status --wait --until <phase>;',
6149
+ " silence past your timeout = counterparty unresponsive, move on.",
6150
+ ' DONE \u2192 .cycleComplete == true OR latestDelegation.state == "completed".',
6151
+ ' The relationship STAYS "active" for the next deal \u2014 do not loop on it.',
6152
+ " DEAD \u2192 latestDelegation.state in {declined, canceled, failed, refunded,",
6153
+ " dispute_resolved}: deal off / funds settled. Do NOT retry \u2014 make a",
6154
+ " fresh offer if you still want the work."
6155
+ ]
6156
+ },
6157
+ {
6158
+ id: "reference.json-reads",
6159
+ roles: ["worker", "buyer"],
6160
+ title: "Reading state as JSON (never scrape the human table)",
6161
+ body: [
6162
+ " Always add `--json` and read the DOCUMENTED field \u2014 the pretty table is for",
6163
+ " humans and its columns will shift. Wire keys \u2260 table labels:",
6164
+ " turn / next move : status <rel> --json \u2192 .nextActionOwner, .nextActionHint",
6165
+ " relationship : status <rel> --json \u2192 .relationshipState (NOT .state)",
6166
+ " delegation : status <rel> --json \u2192 .latestDelegation.state",
6167
+ " (or delegations <rel> --json \u2192 .[].state)",
6168
+ " receipt : receipts <rel> --json \u2192 .[].state / .verdictFinal / .receiptEventHash",
6169
+ " incoming events : inbox --json \u2192 .[].body.type / .eventId / .serverTimestamp /",
6170
+ " .senderDid (NOT .signer)",
6171
+ " worker pay key : did-doc <worker-did> --json \u2192 the #settlement",
6172
+ " verificationMethod (NOT agents --json)"
6173
+ ]
6174
+ },
6175
+ {
6176
+ id: "reference.operating-rules",
6177
+ roles: ["worker", "buyer"],
6178
+ title: "Operating rules for autonomous agents",
6179
+ body: [" Four habits that prevent almost every mechanical failure:"],
6180
+ commonErrors: [
6181
+ "NEVER invent a flag, state, or value \u2014 run `<command> --help`; flag and state names are exact and the CLI rejects guesses.",
6182
+ "NEVER scrape the human table \u2014 pass `--json` and read the documented fields (see the JSON read-map above).",
6183
+ "NEVER truncate, edit, or re-case an ID or hash \u2014 copy it verbatim (use `--full-ids` for untruncated values); IDs are opaque tokens.",
6184
+ "NEVER fire the next envelope optimistically \u2014 do ONE action, then WAIT for the state to advance (`status --wait --until <phase>`) before sending the next.",
6185
+ "On a retry that returns a *_INVALID_STATE error, do NOT blindly resend \u2014 it usually means the action ALREADY landed; re-read `status --json` first to confirm the new state."
6186
+ ]
6187
+ },
6188
+ {
6189
+ id: "reference.saying-no",
6190
+ roles: ["worker", "buyer"],
6191
+ title: "Saying no (decline an offer / refuse to pay)",
6192
+ body: [
6193
+ " WORKER \u2014 refuse an OFFER before doing any work:",
6194
+ " heyarp delegation decline <rel-id> <del-id> --reason <code> (--help lists codes)",
6195
+ " You are not obligated to accept; declining ends that delegation cleanly.",
6196
+ " BUYER \u2014 unhappy with the DELIVERABLE:",
6197
+ " Do NOT cosign. Cosign = release/pay \u2014 it is NOT conditional on a verdict, and",
6198
+ ' V1 has no "cosign-to-reject" and no --verdict flag. If you never cosign, the lock',
6199
+ " stays and AUTO-REFUNDS to you when it expires. (Disputes / partial settlement",
6200
+ " are post-V1.)",
6201
+ " BUYER \u2014 withdraw your OWN offer before the worker accepts:",
6202
+ " heyarp delegation cancel <rel-id> <del-id> (offerer-only; OFFERED state only)"
6203
+ ]
6204
+ },
6205
+ {
6206
+ id: "setup.quickstart",
6207
+ roles: ["setup"],
6208
+ title: "Quickstart \u2014 install to first action",
6209
+ body: [
6210
+ " 1. heyarp register create your DID + Ed25519 keys",
6211
+ " 2. heyarp whoami confirm your DID is set",
6212
+ " 3. role for THIS deal: you SEND the offer \u2192 buyer; an offer ARRIVES \u2192 worker",
6213
+ " 4. BUYER only \u2014 fund your settlement wallet: `whoami --local` \u2192",
6214
+ " settlementPublicKeyB58, send SOL/USDC there (the deposit comes from it)",
6215
+ " 5. feed your role into your agent: heyarp guide --role <worker|buyer> --format prompt",
6216
+ " 6. then act on ONE event at a time; after each: status --wait --until <phase>"
6217
+ ]
6218
+ },
6045
6219
  {
6046
6220
  id: "troubleshoot.stuck",
6047
6221
  roles: ["troubleshoot"],
@@ -6050,6 +6224,15 @@ var GUIDE_SECTIONS = [
6050
6224
  " Every command supports `--help` \u2014 read structured `code` + `message`",
6051
6225
  " error fields, they name the exact state-machine constraint violated.",
6052
6226
  " `heyarp doctor <did>` probes a peer agent's endpoint (LISTED vs LIVE).",
6227
+ " Common blockers \u2192 fix:",
6228
+ " \u2022 `wallet create-lock` fails / insufficient balance \u2192 fund your settlement",
6229
+ " wallet (buyer side); `heyarp whoami --local` shows settlementPublicKeyB58.",
6230
+ " \u2022 `ATA does not exist` \u2192 use native SOL, or make sure the recipient token",
6231
+ " account for that mint exists.",
6232
+ " \u2022 handshake stuck `pending` / delegation stuck `offered` \u2192 the COUNTERPARTY",
6233
+ " has not acted; block on it with `heyarp status <rel-id> --wait --until <state>`.",
6234
+ ' \u2022 "wrong move for my role" \u2192 you mixed up buyer vs worker; role is',
6235
+ ' PER-RELATIONSHIP \u2014 re-check with `heyarp guide` ("Which role am I?").',
6053
6236
  " More: README at https://www.npmjs.com/package/@heyanon-arp/cli"
6054
6237
  ]
6055
6238
  }
@@ -6103,7 +6286,7 @@ function renderCommand(c) {
6103
6286
  ${c.description}`;
6104
6287
  }
6105
6288
  function renderSection(s) {
6106
- const lines = [import_chalk13.default.bold(s.title)];
6289
+ const lines = [import_chalk12.default.bold(s.title)];
6107
6290
  if (s.body && s.body.length > 0) lines.push(...s.body);
6108
6291
  if (s.nextActions && s.nextActions.length > 0) {
6109
6292
  lines.push(" Commands:");
@@ -6122,29 +6305,29 @@ function modeHeader(mode) {
6122
6305
  switch (mode.kind) {
6123
6306
  case "overview":
6124
6307
  return [
6125
- "Pick your path:",
6126
- " \u2022 Worker (you do tasks, get paid): heyarp guide --role worker",
6127
- " \u2022 Buyer (you delegate tasks, pay): heyarp guide --role buyer",
6308
+ "Pick your path (role is PER-DEAL \u2014 the same agent can be both):",
6309
+ " \u2022 WORKER \u2014 an OFFER comes to you; you do tasks, get paid: heyarp guide --role worker",
6310
+ " \u2022 BUYER \u2014 YOU send the OFFER; you set terms + pay: heyarp guide --role buyer",
6128
6311
  " \u2022 Setup / keys / multi-agent: heyarp guide --setup",
6129
6312
  " \u2022 Common errors \u2192 fixes: heyarp guide --troubleshoot",
6130
6313
  ""
6131
6314
  ];
6132
6315
  case "role":
6133
- return [import_chalk13.default.dim(`(${mode.role} guide \u2014 your slice only; run \`heyarp guide\` for the overview)`), ""];
6316
+ return [import_chalk12.default.dim(`(${mode.role} guide \u2014 your slice only; run \`heyarp guide\` for the overview)`), ""];
6134
6317
  case "setup":
6135
- return [import_chalk13.default.dim("(setup \u2014 role-agnostic; run `heyarp guide` for the overview)"), ""];
6318
+ return [import_chalk12.default.dim("(setup \u2014 role-agnostic; run `heyarp guide` for the overview)"), ""];
6136
6319
  case "troubleshoot":
6137
- return [import_chalk13.default.dim("(troubleshooting \u2014 role-agnostic)"), ""];
6320
+ return [import_chalk12.default.dim("(troubleshooting \u2014 role-agnostic)"), ""];
6138
6321
  }
6139
6322
  }
6140
6323
  function modeFooter(mode) {
6141
6324
  if (mode.kind === "overview") {
6142
- return ["", import_chalk13.default.dim("Full reference per role: `heyarp guide --role worker|buyer`. Docs: https://www.npmjs.com/package/@heyanon-arp/cli")];
6325
+ return ["", import_chalk12.default.dim("Full reference per role: `heyarp guide --role worker|buyer`. Docs: https://www.npmjs.com/package/@heyanon-arp/cli")];
6143
6326
  }
6144
6327
  return [];
6145
6328
  }
6146
6329
  function renderGuide(mode = { kind: "overview" }) {
6147
- const blocks = [import_chalk13.default.bold(GUIDE_TITLE), "", ...modeHeader(mode)];
6330
+ const blocks = [import_chalk12.default.bold(GUIDE_TITLE), "", ...modeHeader(mode)];
6148
6331
  for (const s of selectSections(mode)) {
6149
6332
  blocks.push(renderSection(s), "");
6150
6333
  }
@@ -6192,22 +6375,22 @@ function renderPrompt(mode, opts = { concise: false }) {
6192
6375
  }
6193
6376
 
6194
6377
  // src/commands/homes.ts
6195
- var import_node_fs7 = require("fs");
6196
- var import_node_path6 = require("path");
6197
- var import_chalk14 = __toESM(require("chalk"));
6378
+ var import_node_fs6 = require("fs");
6379
+ var import_node_path5 = require("path");
6380
+ var import_chalk13 = __toESM(require("chalk"));
6198
6381
  var import_prompts = __toESM(require("prompts"));
6199
6382
 
6200
6383
  // src/homes.ts
6201
- var import_node_fs6 = require("fs");
6202
- var import_node_path5 = require("path");
6384
+ var import_node_fs5 = require("fs");
6385
+ var import_node_path4 = require("path");
6203
6386
  init_paths();
6204
6387
  var REGISTRY_WARNING = "DO NOT COMMIT \u2014 paths to home dirs may be sensitive (e.g. encrypted-volume mounts).";
6205
6388
  function readRegistry() {
6206
6389
  const path = homesRegistryPath();
6207
- if (!(0, import_node_fs6.existsSync)(path)) return { homes: [] };
6390
+ if (!(0, import_node_fs5.existsSync)(path)) return { homes: [] };
6208
6391
  let raw;
6209
6392
  try {
6210
- raw = (0, import_node_fs6.readFileSync)(path, "utf8");
6393
+ raw = (0, import_node_fs5.readFileSync)(path, "utf8");
6211
6394
  } catch (err) {
6212
6395
  throw new Error(`Failed to read homes registry at ${path}: ${err.message}`);
6213
6396
  }
@@ -6228,12 +6411,12 @@ function readRegistry() {
6228
6411
  }
6229
6412
  function writeRegistry(file) {
6230
6413
  const path = homesRegistryPath();
6231
- const dir = (0, import_node_path5.dirname)(path);
6232
- if (!(0, import_node_fs6.existsSync)(dir)) (0, import_node_fs6.mkdirSync)(dir, { recursive: true, mode: 448 });
6414
+ const dir = (0, import_node_path4.dirname)(path);
6415
+ if (!(0, import_node_fs5.existsSync)(dir)) (0, import_node_fs5.mkdirSync)(dir, { recursive: true, mode: 448 });
6233
6416
  const body = JSON.stringify({ _warning: REGISTRY_WARNING, homes: file.homes }, null, 2);
6234
- (0, import_node_fs6.writeFileSync)(path, body, { encoding: "utf8", mode: 384 });
6417
+ (0, import_node_fs5.writeFileSync)(path, body, { encoding: "utf8", mode: 384 });
6235
6418
  try {
6236
- (0, import_node_fs6.chmodSync)(path, 384);
6419
+ (0, import_node_fs5.chmodSync)(path, 384);
6237
6420
  } catch {
6238
6421
  }
6239
6422
  }
@@ -6261,7 +6444,7 @@ function forgetHome(homePath) {
6261
6444
  return true;
6262
6445
  }
6263
6446
  function homeStillExists(homePath) {
6264
- return (0, import_node_fs6.existsSync)(`${homePath}/agents.json`);
6447
+ return (0, import_node_fs5.existsSync)(`${homePath}/agents.json`);
6265
6448
  }
6266
6449
 
6267
6450
  // src/commands/homes.ts
@@ -6288,27 +6471,27 @@ function runHomes(opts) {
6288
6471
  return;
6289
6472
  }
6290
6473
  if (rows.length === 0) {
6291
- console.log(import_chalk14.default.dim("(no HEYARP_HOME directories registered yet \u2014 run `heyarp register` once and the registry populates itself)"));
6292
- console.log(import_chalk14.default.dim(` registry path: ${homesRegistryPath()}`));
6474
+ console.log(import_chalk13.default.dim("(no HEYARP_HOME directories registered yet \u2014 run `heyarp register` once and the registry populates itself)"));
6475
+ console.log(import_chalk13.default.dim(` registry path: ${homesRegistryPath()}`));
6293
6476
  return;
6294
6477
  }
6295
6478
  const header = ["Path", "Agents", "Last seen", "Status"];
6296
6479
  const data = rows.map((r) => [
6297
- r.path + (r.isCurrent ? import_chalk14.default.green(" (current)") : ""),
6480
+ r.path + (r.isCurrent ? import_chalk13.default.green(" (current)") : ""),
6298
6481
  String(r.agentCount),
6299
6482
  formatRelativeTime(r.lastSeenAt),
6300
- r.exists ? import_chalk14.default.green("ok") : import_chalk14.default.red("missing")
6483
+ r.exists ? import_chalk13.default.green("ok") : import_chalk13.default.red("missing")
6301
6484
  ]);
6302
6485
  console.log("");
6303
6486
  console.log(formatTable(header, data));
6304
- console.log(import_chalk14.default.dim(`
6487
+ console.log(import_chalk13.default.dim(`
6305
6488
  Registry path: ${homesRegistryPath()}`));
6306
- console.log(import_chalk14.default.dim(`Set HEYARP_HOME=<path> in a shell to switch between homes; run \`heyarp homes forget <path>\` to drop a stale entry.`));
6489
+ console.log(import_chalk13.default.dim(`Set HEYARP_HOME=<path> in a shell to switch between homes; run \`heyarp homes forget <path>\` to drop a stale entry.`));
6307
6490
  }
6308
6491
  async function runForget(path, opts) {
6309
6492
  if (!opts.yes) {
6310
- console.log(import_chalk14.default.yellow(`About to remove '${path}' from the homes registry.`));
6311
- console.log(import_chalk14.default.dim(" Note: this only forgets the registry entry; the directory + its agents.json are NOT touched."));
6493
+ console.log(import_chalk13.default.yellow(`About to remove '${path}' from the homes registry.`));
6494
+ console.log(import_chalk13.default.dim(" Note: this only forgets the registry entry; the directory + its agents.json are NOT touched."));
6312
6495
  const answer = await (0, import_prompts.default)(
6313
6496
  {
6314
6497
  type: "confirm",
@@ -6318,28 +6501,28 @@ async function runForget(path, opts) {
6318
6501
  },
6319
6502
  {
6320
6503
  onCancel: () => {
6321
- console.log(import_chalk14.default.yellow("Aborted."));
6504
+ console.log(import_chalk13.default.yellow("Aborted."));
6322
6505
  process.exit(130);
6323
6506
  }
6324
6507
  }
6325
6508
  );
6326
6509
  if (!answer.confirm) {
6327
- console.log(import_chalk14.default.dim("Aborted (no changes)."));
6510
+ console.log(import_chalk13.default.dim("Aborted (no changes)."));
6328
6511
  return;
6329
6512
  }
6330
6513
  }
6331
6514
  const removed = forgetHome(path);
6332
6515
  if (removed) {
6333
- console.log(import_chalk14.default.green(`\u2713 forgot ${path}`));
6516
+ console.log(import_chalk13.default.green(`\u2713 forgot ${path}`));
6334
6517
  } else {
6335
- console.log(import_chalk14.default.dim(`(no entry for ${path} in the registry \u2014 already absent)`));
6518
+ console.log(import_chalk13.default.dim(`(no entry for ${path} in the registry \u2014 already absent)`));
6336
6519
  }
6337
6520
  }
6338
6521
  function countAgents(homePath) {
6339
- const file = (0, import_node_path6.join)(homePath, "agents.json");
6340
- if (!(0, import_node_fs7.existsSync)(file)) return 0;
6522
+ const file = (0, import_node_path5.join)(homePath, "agents.json");
6523
+ if (!(0, import_node_fs6.existsSync)(file)) return 0;
6341
6524
  try {
6342
- const parsed = JSON.parse((0, import_node_fs7.readFileSync)(file, "utf8"));
6525
+ const parsed = JSON.parse((0, import_node_fs6.readFileSync)(file, "utf8"));
6343
6526
  if (!parsed || typeof parsed !== "object" || !parsed.servers) return 0;
6344
6527
  let total = 0;
6345
6528
  for (const server of Object.values(parsed.servers)) {
@@ -6357,13 +6540,13 @@ function formatTable(header, data) {
6357
6540
  const padding = " ".repeat(Math.max(0, widths[i] - lengths[i]));
6358
6541
  return cell + padding;
6359
6542
  }).join(" ");
6360
- const headerLine = import_chalk14.default.bold(
6543
+ const headerLine = import_chalk13.default.bold(
6361
6544
  pad(
6362
6545
  header,
6363
6546
  header.map((s) => s.length)
6364
6547
  )
6365
6548
  );
6366
- const sepLine = import_chalk14.default.dim(
6549
+ const sepLine = import_chalk13.default.dim(
6367
6550
  pad(
6368
6551
  widths.map((w) => "-".repeat(w)),
6369
6552
  widths
@@ -6390,7 +6573,7 @@ function formatRelativeTime(iso) {
6390
6573
  }
6391
6574
 
6392
6575
  // src/commands/inbox.ts
6393
- var import_chalk15 = __toESM(require("chalk"));
6576
+ var import_chalk14 = __toESM(require("chalk"));
6394
6577
  init_api();
6395
6578
  init_format();
6396
6579
  init_state();
@@ -6440,8 +6623,8 @@ async function runInbox(positionalDid, opts) {
6440
6623
  }
6441
6624
  const api = new ArpApiClient(opts.server);
6442
6625
  if (!opts.json) {
6443
- console.log(import_chalk15.default.dim(`Server: ${api.serverUrl}`));
6444
- console.log(import_chalk15.default.dim(`Signer: ${local.did}`));
6626
+ console.log(import_chalk14.default.dim(`Server: ${api.serverUrl}`));
6627
+ console.log(import_chalk14.default.dim(`Signer: ${local.did}`));
6445
6628
  }
6446
6629
  const query = { limit };
6447
6630
  if (opts.before) query.before = opts.before;
@@ -6455,7 +6638,7 @@ async function runInbox(positionalDid, opts) {
6455
6638
  return;
6456
6639
  }
6457
6640
  if (events.length === 0) {
6458
- console.log(import_chalk15.default.dim("\n(no events addressed to me \u2014 `heyarp events <relationship-id>` shows the chain-wide listing)"));
6641
+ console.log(import_chalk14.default.dim("\n(no events addressed to me \u2014 `heyarp events <relationship-id>` shows the chain-wide listing)"));
6459
6642
  return;
6460
6643
  }
6461
6644
  console.log("");
@@ -6470,16 +6653,16 @@ async function runInbox(positionalDid, opts) {
6470
6653
  secondary: `eventId=${ev.eventId} serverEventHash=${ev.serverEventHash}`
6471
6654
  }));
6472
6655
  }
6473
- const addressedToMeHint = import_chalk15.default.dim(" (envelopes addressed to me \u2014 for the full chain see `heyarp events <relationship-id>`)");
6656
+ const addressedToMeHint = import_chalk14.default.dim(" (envelopes addressed to me \u2014 for the full chain see `heyarp events <relationship-id>`)");
6474
6657
  if (opts.since && !opts.before) {
6475
6658
  console.log(
6476
- import_chalk15.default.dim(
6659
+ import_chalk14.default.dim(
6477
6660
  `
6478
6661
  ${events.length} event(s) (oldest-first).${addressedToMeHint} Advance the forward cursor with --since <serverTimestamp> --since-event-id <eventId> using the LAST row above.`
6479
6662
  )
6480
6663
  );
6481
6664
  } else {
6482
- console.log(import_chalk15.default.dim(`
6665
+ console.log(import_chalk14.default.dim(`
6483
6666
  ${events.length} event(s).${addressedToMeHint} Paginate with --before <serverTimestamp> --before-event-id <eventId> using the LAST row above.`));
6484
6667
  }
6485
6668
  }
@@ -6494,7 +6677,7 @@ async function runInboxTail(did, local, opts) {
6494
6677
  } else {
6495
6678
  warn(
6496
6679
  opts.json,
6497
- import_chalk15.default.yellow(
6680
+ import_chalk14.default.yellow(
6498
6681
  "\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."
6499
6682
  )
6500
6683
  );
@@ -6504,9 +6687,9 @@ async function runInboxTail(did, local, opts) {
6504
6687
  if (opts.json) {
6505
6688
  console.log(formatTailStartedPing({ server: api.serverUrl, signer: local.did, stdoutBlockingApplied }));
6506
6689
  } else {
6507
- console.log(import_chalk15.default.dim(`Server: ${api.serverUrl}`));
6508
- console.log(import_chalk15.default.dim(`Signer: ${local.did}`));
6509
- console.log(import_chalk15.default.dim("Mode: --tail (live SSE, Ctrl-C to stop)"));
6690
+ console.log(import_chalk14.default.dim(`Server: ${api.serverUrl}`));
6691
+ console.log(import_chalk14.default.dim(`Signer: ${local.did}`));
6692
+ console.log(import_chalk14.default.dim("Mode: --tail (live SSE, Ctrl-C to stop)"));
6510
6693
  }
6511
6694
  const controller = new AbortController();
6512
6695
  let userAborted = false;
@@ -6525,7 +6708,7 @@ async function runInboxTail(did, local, opts) {
6525
6708
  }
6526
6709
  if (event.type === "heartbeat") continue;
6527
6710
  if (event.type === "connected") {
6528
- console.log(import_chalk15.default.green("\u25CF stream open \u2014 listening for envelopes..."));
6711
+ console.log(import_chalk14.default.green("\u25CF stream open \u2014 listening for envelopes..."));
6529
6712
  continue;
6530
6713
  }
6531
6714
  if (event.type === "envelope") {
@@ -6539,7 +6722,7 @@ async function runInboxTail(did, local, opts) {
6539
6722
  }
6540
6723
  continue;
6541
6724
  }
6542
- console.log(import_chalk15.default.dim(`(unknown event: ${event.type})`));
6725
+ console.log(import_chalk14.default.dim(`(unknown event: ${event.type})`));
6543
6726
  }
6544
6727
  if (!userAborted) {
6545
6728
  throw new Error("inbox --tail: stream ended unexpectedly (server may have restarted, or change stream errored). Re-run to reconnect.");
@@ -6547,7 +6730,7 @@ async function runInboxTail(did, local, opts) {
6547
6730
  } catch (err) {
6548
6731
  const name = err.name;
6549
6732
  if (name === "AbortError" || userAborted) {
6550
- if (!opts.json) console.log(import_chalk15.default.dim("\nstream closed."));
6733
+ if (!opts.json) console.log(import_chalk14.default.dim("\nstream closed."));
6551
6734
  return;
6552
6735
  }
6553
6736
  throw err;
@@ -6567,15 +6750,15 @@ function formatInboxTable(events, opts = {}) {
6567
6750
  ]);
6568
6751
  const widths = header.map((h, i) => Math.max(h.length, ...data.map((row) => row[i].length)));
6569
6752
  const pad = (cells) => cells.map((c, i) => c.padEnd(widths[i])).join(" ");
6570
- const lines = [import_chalk15.default.bold(pad(header)), import_chalk15.default.dim(pad(widths.map((w) => "-".repeat(w)))), ...data.map((row) => pad(row))];
6571
- const detail = events.map((ev) => ` ${import_chalk15.default.dim("eventId:")} ${import_chalk15.default.cyan(ev.eventId)} ${import_chalk15.default.dim("serverTimestamp:")} ${import_chalk15.default.cyan(ev.serverTimestamp)}`).join("\n");
6753
+ const lines = [import_chalk14.default.bold(pad(header)), import_chalk14.default.dim(pad(widths.map((w) => "-".repeat(w)))), ...data.map((row) => pad(row))];
6754
+ const detail = events.map((ev) => ` ${import_chalk14.default.dim("eventId:")} ${import_chalk14.default.cyan(ev.eventId)} ${import_chalk14.default.dim("serverTimestamp:")} ${import_chalk14.default.cyan(ev.serverTimestamp)}`).join("\n");
6572
6755
  return `${lines.join("\n")}
6573
6756
 
6574
- ${import_chalk15.default.bold("Pagination cursors")} (last \u2192 first):
6757
+ ${import_chalk14.default.bold("Pagination cursors")} (last \u2192 first):
6575
6758
  ${detail}`;
6576
6759
  }
6577
6760
  function hashHead2(hash) {
6578
- if (!hash) return import_chalk15.default.dim("(none)");
6761
+ if (!hash) return import_chalk14.default.dim("(none)");
6579
6762
  if (hash.length <= 14) return hash;
6580
6763
  return `${hash.slice(0, 14)}...`;
6581
6764
  }
@@ -6590,35 +6773,35 @@ function parseLimit4(raw) {
6590
6773
 
6591
6774
  // src/commands/keys.ts
6592
6775
  var import_sdk8 = require("@heyanon-arp/sdk");
6593
- var import_chalk16 = __toESM(require("chalk"));
6776
+ var import_chalk15 = __toESM(require("chalk"));
6594
6777
  function registerKeysCommand(root) {
6595
6778
  const keys = root.command("keys").description("Local key utilities");
6596
6779
  keys.command("gen").description("Generate a fresh identity + settlement keypair (no save by default)").option("--save", "Reserved for future scratch-key storage; currently a no-op with a notice", false).action((opts) => {
6597
6780
  const identity = (0, import_sdk8.generateKeyPair)();
6598
6781
  const settlement = (0, import_sdk8.generateKeyPair)();
6599
6782
  const out = [
6600
- import_chalk16.default.bold("Identity key (Ed25519)"),
6601
- ` public (base58btc): ${import_chalk16.default.cyan((0, import_sdk8.base58btcEncode)(identity.publicKey))}`,
6602
- ` secret (base64) : ${import_chalk16.default.yellow(Buffer.from(identity.secretKey).toString("base64"))}`,
6783
+ import_chalk15.default.bold("Identity key (Ed25519)"),
6784
+ ` public (base58btc): ${import_chalk15.default.cyan((0, import_sdk8.base58btcEncode)(identity.publicKey))}`,
6785
+ ` secret (base64) : ${import_chalk15.default.yellow(Buffer.from(identity.secretKey).toString("base64"))}`,
6603
6786
  "",
6604
- import_chalk16.default.bold("Settlement key (Ed25519)"),
6605
- ` public (base58btc): ${import_chalk16.default.cyan((0, import_sdk8.base58btcEncode)(settlement.publicKey))}`,
6606
- ` secret (base64) : ${import_chalk16.default.yellow(Buffer.from(settlement.secretKey).toString("base64"))}`,
6787
+ import_chalk15.default.bold("Settlement key (Ed25519)"),
6788
+ ` public (base58btc): ${import_chalk15.default.cyan((0, import_sdk8.base58btcEncode)(settlement.publicKey))}`,
6789
+ ` secret (base64) : ${import_chalk15.default.yellow(Buffer.from(settlement.secretKey).toString("base64"))}`,
6607
6790
  "",
6608
- import_chalk16.default.bold("Resulting DID"),
6609
- ` ${import_chalk16.default.cyan((0, import_sdk8.formatDid)(identity.publicKey))}`
6791
+ import_chalk15.default.bold("Resulting DID"),
6792
+ ` ${import_chalk15.default.cyan((0, import_sdk8.formatDid)(identity.publicKey))}`
6610
6793
  ];
6611
6794
  console.log(out.join("\n"));
6612
6795
  if (opts.save) {
6613
- console.log(import_chalk16.default.yellow("\nNote: --save is not yet implemented. Capture the secret keys above before they scroll off-screen."));
6796
+ console.log(import_chalk15.default.yellow("\nNote: --save is not yet implemented. Capture the secret keys above before they scroll off-screen."));
6614
6797
  }
6615
6798
  });
6616
6799
  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) => {
6617
6800
  const seed = decodeSeed(secretKeyB64);
6618
6801
  const pub = (0, import_sdk8.getPublicKey)(seed);
6619
6802
  const did = (0, import_sdk8.formatDid)(pub);
6620
- console.log(`${import_chalk16.default.bold("DID")}: ${import_chalk16.default.cyan(did)}`);
6621
- console.log(`${import_chalk16.default.bold("Identity public key (base58btc)")}: ${import_chalk16.default.cyan((0, import_sdk8.base58btcEncode)(pub))}`);
6803
+ console.log(`${import_chalk15.default.bold("DID")}: ${import_chalk15.default.cyan(did)}`);
6804
+ console.log(`${import_chalk15.default.bold("Identity public key (base58btc)")}: ${import_chalk15.default.cyan((0, import_sdk8.base58btcEncode)(pub))}`);
6622
6805
  });
6623
6806
  }
6624
6807
  function decodeSeed(b64) {
@@ -6638,14 +6821,14 @@ function decodeSeed(b64) {
6638
6821
  init_lifecycle();
6639
6822
 
6640
6823
  // src/commands/list.ts
6641
- var import_chalk17 = __toESM(require("chalk"));
6824
+ var import_chalk16 = __toESM(require("chalk"));
6642
6825
  init_format();
6643
6826
  init_state();
6644
6827
  function registerListCommand(root) {
6645
6828
  root.command("list").description("List agents registered locally (~/.arp/agents.json)").action(() => {
6646
6829
  const rows = listAgents();
6647
6830
  if (rows.length === 0) {
6648
- console.log(import_chalk17.default.dim(`No local agents. State file: ${stateFilePath()}`));
6831
+ console.log(import_chalk16.default.dim(`No local agents. State file: ${stateFilePath()}`));
6649
6832
  return;
6650
6833
  }
6651
6834
  const grouped = /* @__PURE__ */ new Map();
@@ -6657,7 +6840,7 @@ function registerListCommand(root) {
6657
6840
  for (const [serverUrl, group] of grouped) {
6658
6841
  if (!first) console.log("");
6659
6842
  first = false;
6660
- console.log(import_chalk17.default.bold(`Server: ${serverUrl}`));
6843
+ console.log(import_chalk16.default.bold(`Server: ${serverUrl}`));
6661
6844
  console.log(formatAgentsTable(group.map(({ agent }) => ({ did: agent.did, name: agent.name, tags: agent.tags, registeredAt: agent.registeredAt }))));
6662
6845
  }
6663
6846
  });
@@ -6667,7 +6850,7 @@ function registerListCommand(root) {
6667
6850
  init_receipt();
6668
6851
 
6669
6852
  // src/commands/receipts.ts
6670
- var import_chalk20 = __toESM(require("chalk"));
6853
+ var import_chalk19 = __toESM(require("chalk"));
6671
6854
  init_api();
6672
6855
  init_format();
6673
6856
  init_state();
@@ -6699,9 +6882,9 @@ async function runReceipts(relationshipId, opts) {
6699
6882
  const api = new ArpApiClient(opts.server);
6700
6883
  const sender = resolveSenderAgent("receipts", opts.server, opts.fromDid);
6701
6884
  if (!opts.json) {
6702
- console.log(import_chalk20.default.dim(`Server: ${api.serverUrl}`));
6703
- console.log(import_chalk20.default.dim(`Signer: ${sender.did}`));
6704
- console.log(import_chalk20.default.dim(`Relationship: ${relationshipId}`));
6885
+ console.log(import_chalk19.default.dim(`Server: ${api.serverUrl}`));
6886
+ console.log(import_chalk19.default.dim(`Signer: ${sender.did}`));
6887
+ console.log(import_chalk19.default.dim(`Relationship: ${relationshipId}`));
6705
6888
  }
6706
6889
  const query = { limit };
6707
6890
  if (state) query.state = state;
@@ -6714,7 +6897,7 @@ async function runReceipts(relationshipId, opts) {
6714
6897
  return;
6715
6898
  }
6716
6899
  if (rows.length === 0) {
6717
- console.log(import_chalk20.default.dim("\n(no receipts for this relationship)"));
6900
+ console.log(import_chalk19.default.dim("\n(no receipts for this relationship)"));
6718
6901
  return;
6719
6902
  }
6720
6903
  console.log("");
@@ -6732,28 +6915,28 @@ async function runReceipts(relationshipId, opts) {
6732
6915
  }));
6733
6916
  }
6734
6917
  const lastId = rows[rows.length - 1].id;
6735
- console.log(import_chalk20.default.dim(`
6918
+ console.log(import_chalk19.default.dim(`
6736
6919
  ${rows.length} receipt row(s). Paginate with --after ${lastId}.`));
6737
6920
  }
6738
6921
  function formatReceiptLine(r, selfDid, opts = {}) {
6739
6922
  const delegationPart = opts.fullIds ? r.delegationId : idHead2(r.delegationId);
6740
6923
  const requestHashPart = opts.fullIds ? r.requestHash : hashHead3(r.requestHash);
6741
- const id = import_chalk20.default.bold(`${delegationPart}/${requestHashPart}`);
6924
+ const id = import_chalk19.default.bold(`${delegationPart}/${requestHashPart}`);
6742
6925
  const state = colorState2(r.state).padEnd(stateColumnWidth2());
6743
6926
  const callerHead = opts.fullIds ? r.callerDid : didHead3(r.callerDid);
6744
6927
  const payeeHead = opts.fullIds ? r.payeeDid : didHead3(r.payeeDid);
6745
- const direction = r.payeeDid === selfDid ? `${import_chalk20.default.bold("me")}(payee) \u2192 ${import_chalk20.default.dim(callerHead)}` : `${import_chalk20.default.dim(payeeHead)}(payee) \u2192 ${import_chalk20.default.bold("me")}`;
6928
+ const direction = r.payeeDid === selfDid ? `${import_chalk19.default.bold("me")}(payee) \u2192 ${import_chalk19.default.dim(callerHead)}` : `${import_chalk19.default.dim(payeeHead)}(payee) \u2192 ${import_chalk19.default.bold("me")}`;
6746
6929
  const verdict = formatVerdict(r);
6747
6930
  const responseTail = opts.fullIds ? `
6748
- ${import_chalk20.default.dim("responseHash:")} ${import_chalk20.default.cyan(r.responseHash)}` : "";
6931
+ ${import_chalk19.default.dim("responseHash:")} ${import_chalk19.default.cyan(r.responseHash)}` : "";
6749
6932
  return `${id} ${state} ${direction} ${verdict}${responseTail}`;
6750
6933
  }
6751
6934
  function colorState2(s) {
6752
6935
  switch (s) {
6753
6936
  case "proposed":
6754
- return import_chalk20.default.yellow("proposed");
6937
+ return import_chalk19.default.yellow("proposed");
6755
6938
  case "cosigned":
6756
- return import_chalk20.default.green("cosigned");
6939
+ return import_chalk19.default.green("cosigned");
6757
6940
  }
6758
6941
  }
6759
6942
  function stateColumnWidth2() {
@@ -6763,11 +6946,11 @@ function formatVerdict(r) {
6763
6946
  const final = r.verdictFinal ?? r.verdictProposed;
6764
6947
  switch (final) {
6765
6948
  case "accepted":
6766
- return import_chalk20.default.green("accepted");
6949
+ return import_chalk19.default.green("accepted");
6767
6950
  case "accepted_with_notes":
6768
- return import_chalk20.default.yellow("accepted_with_notes");
6951
+ return import_chalk19.default.yellow("accepted_with_notes");
6769
6952
  case "rejected":
6770
- return import_chalk20.default.red("rejected");
6953
+ return import_chalk19.default.red("rejected");
6771
6954
  }
6772
6955
  }
6773
6956
  function idHead2(id) {
@@ -6800,9 +6983,9 @@ function parseLimit5(raw) {
6800
6983
 
6801
6984
  // src/commands/register.ts
6802
6985
  var import_node_crypto = require("crypto");
6803
- var import_node_fs9 = require("fs");
6986
+ var import_node_fs8 = require("fs");
6804
6987
  var import_sdk12 = require("@heyanon-arp/sdk");
6805
- var import_chalk21 = __toESM(require("chalk"));
6988
+ var import_chalk20 = __toESM(require("chalk"));
6806
6989
  var import_prompts2 = __toESM(require("prompts"));
6807
6990
  init_api();
6808
6991
  init_format();
@@ -6835,22 +7018,15 @@ function registerRegisterCommand(root) {
6835
7018
  "--yes",
6836
7019
  "Strict non-interactive: fail if any required field is still missing after merging flags. With --yes, --password must be supplied explicitly (>= 8 chars).",
6837
7020
  false
6838
- ).option(
6839
- "--publication <state>",
6840
- "Post-register publication mode. 'active' (default) auto-publishes the agent into the discovery catalog so other agents can find it immediately via `heyarp agents`. 'draft' keeps it out of the catalog \u2014 curate the profile first, then run `heyarp publish <did>` manually.",
6841
- "active"
6842
7021
  ).option(
6843
7022
  "--json",
6844
7023
  // Emit a single JSON object instead of human-friendly
6845
7024
  // success prints. Output shape:
6846
7025
  // {did, settlementPublicKeyB58, identityPublicKeyB58,
6847
- // keyMode, publication, didDocument}
7026
+ // localStatePath, didDocument}
6848
7027
  // (V1-alpha: `accountId` parked from the output.)
6849
7028
  // REQUIRES --yes (interactive prompts would corrupt the
6850
- // single-doc contract). The auto-publish branch reports
6851
- // its outcome under `.publication` ('published', 'draft',
6852
- // or 'failed:<reason>') instead of emitting human-readable
6853
- // lines.
7029
+ // single-doc contract).
6854
7030
  "Machine-readable mode \u2014 emit `{did, settlementPublicKeyB58, \u2026, didDocument}` JSON instead of human prints. REQUIRES --yes (interactive prompts would corrupt the single-doc JSON output).",
6855
7031
  false
6856
7032
  ).action(async (opts) => {
@@ -6860,21 +7036,24 @@ function registerRegisterCommand(root) {
6860
7036
  function accumulate3(value, previous) {
6861
7037
  return [...previous, value];
6862
7038
  }
6863
- async function runRegister(opts) {
6864
- const publication = parsePublicationMode(opts.publication ?? "active");
7039
+ var defaultRegisterDeps = {
7040
+ makeApi: (serverOverride) => new ArpApiClient(serverOverride),
7041
+ save: saveAgent
7042
+ };
7043
+ async function runRegister(opts, deps = defaultRegisterDeps) {
6865
7044
  assertJsonRequiresYes(opts);
6866
- const api = new ArpApiClient(opts.server);
6867
- if (!opts.json) console.log(import_chalk21.default.dim(`Server: ${api.serverUrl}`));
7045
+ const api = deps.makeApi(opts.server);
7046
+ if (!opts.json) console.log(import_chalk20.default.dim(`Server: ${api.serverUrl}`));
6868
7047
  if (!opts.json) {
6869
7048
  warnIfAgentsAlreadyRegistered(opts.server);
6870
7049
  warnIfOrphanHomesPresent();
6871
7050
  }
6872
7051
  const keys = opts.fromKeys ? loadKeysFromFile(opts.fromKeys) : freshKeys();
6873
7052
  const did = (0, import_sdk12.formatDid)(keys.identityPublicKey);
6874
- if (!opts.json) console.log(import_chalk21.default.dim(`DID will be: ${did}`));
7053
+ if (!opts.json) console.log(import_chalk20.default.dim(`DID will be: ${did}`));
6875
7054
  const answers = await mergeAnswers(opts);
6876
7055
  const scryptSalt = (0, import_node_crypto.randomBytes)(16);
6877
- if (!opts.json) console.log(import_chalk21.default.dim("Deriving scrypt key, this may take a moment..."));
7056
+ if (!opts.json) console.log(import_chalk20.default.dim("Deriving scrypt key, this may take a moment..."));
6878
7057
  const scryptKey = (0, import_sdk12.deriveScryptKey)(answers.password, new Uint8Array(scryptSalt));
6879
7058
  const challenge = await api.issueChallenge("register");
6880
7059
  const challengeBytes = base64UrlNoPadDecode(challenge.challengeB64);
@@ -6896,7 +7075,6 @@ async function runRegister(opts) {
6896
7075
  agent_did: did,
6897
7076
  identity_public_key: identityPublicKeyB58,
6898
7077
  settlement_public_key: settlementPublicKeyB58,
6899
- key_mode: "separated_soft",
6900
7078
  owner_id: ownerId,
6901
7079
  owner_signing_method: "scrypt_password_proof",
6902
7080
  link_method: "manual",
@@ -6910,7 +7088,6 @@ async function runRegister(opts) {
6910
7088
  // accountId: answers.accountId,
6911
7089
  identityPublicKey: identityPublicKeyB58,
6912
7090
  settlementPublicKey: settlementPublicKeyB58,
6913
- keyMode: "separated_soft",
6914
7091
  ownerAttestation: {
6915
7092
  payload: attestation.payload,
6916
7093
  sig: attestation.sig,
@@ -6922,9 +7099,8 @@ async function runRegister(opts) {
6922
7099
  description: answers.description ? answers.description : void 0,
6923
7100
  tags: answers.tags.length > 0 ? answers.tags : void 0
6924
7101
  };
6925
- const result = await api.register(body);
6926
- saveAgent(opts.server, {
6927
- did: result.did,
7102
+ const durableState = {
7103
+ did,
6928
7104
  identityPublicKeyB58,
6929
7105
  identitySecretKeyB64: Buffer.from(keys.identitySecretKey).toString("base64"),
6930
7106
  settlementPublicKeyB58,
@@ -6933,59 +7109,45 @@ async function runRegister(opts) {
6933
7109
  scryptSaltB64: Buffer.from(scryptSalt).toString("base64"),
6934
7110
  scryptSaltId,
6935
7111
  ownerId,
6936
- // `metadata.owner_attestation_id` is the canonical name in the
6937
- // DID document same value as server's `currentAttestationId`
6938
- // at the moment of registration.
6939
- currentAttestationId: result.didDocument.metadata.owner_attestation_id,
7112
+ // Placeholder until the server confirms registration and returns
7113
+ // the canonical attestation id (finalized in Step 8 below).
7114
+ currentAttestationId: "",
6940
7115
  // V1-alpha: accountId parked — local state file no longer
6941
7116
  // records the field. Existing state files written when the
6942
7117
  // field was required will still carry the value; readers
6943
7118
  // tolerate either shape.
6944
7119
  // accountId: answers.accountId,
6945
- keyMode: "separated_soft",
6946
7120
  name: answers.name,
6947
7121
  description: answers.description || void 0,
6948
7122
  tags: answers.tags.length > 0 ? answers.tags : void 0,
6949
7123
  registeredAt: (/* @__PURE__ */ new Date()).toISOString()
7124
+ };
7125
+ deps.save(opts.server, durableState);
7126
+ const result = await api.register(body);
7127
+ if (result.did !== did) {
7128
+ throw new Error(
7129
+ `register: server returned DID ${result.did} but the locally-derived DID is ${did}. These must be identical (both base58btc of the identity public key). Refusing to finalize \u2014 the secret keys are already saved locally under ${did}.`
7130
+ );
7131
+ }
7132
+ deps.save(opts.server, {
7133
+ ...durableState,
7134
+ currentAttestationId: result.didDocument.metadata.owner_attestation_id
6950
7135
  });
6951
7136
  try {
6952
7137
  recordHome(arpHomeDir());
6953
7138
  } catch (registryErr) {
6954
- if (!opts.json) console.log(import_chalk21.default.dim(`(homes registry write failed: ${registryErr.message})`));
7139
+ if (!opts.json) console.log(import_chalk20.default.dim(`(homes registry write failed: ${registryErr.message})`));
6955
7140
  }
6956
7141
  if (!opts.json) {
6957
- console.log(import_chalk21.default.green("\nRegistered."));
6958
- console.log(`${import_chalk21.default.bold("DID")}: ${import_chalk21.default.cyan(result.did)}`);
6959
- console.log(`${import_chalk21.default.bold("Settlement pubkey")} ${import_chalk21.default.dim("(fund with SOL)")}: ${import_chalk21.default.cyan(settlementPublicKeyB58)}`);
6960
- console.log(import_chalk21.default.bold("DID document:"));
7142
+ console.log(import_chalk20.default.green("\nRegistered."));
7143
+ console.log(`${import_chalk20.default.bold("DID")}: ${import_chalk20.default.cyan(result.did)}`);
7144
+ console.log(`${import_chalk20.default.bold("Settlement pubkey")} ${import_chalk20.default.dim("(fund with SOL)")}: ${import_chalk20.default.cyan(settlementPublicKeyB58)}`);
7145
+ console.log(import_chalk20.default.bold("DID document:"));
6961
7146
  console.log(formatJson(result.didDocument));
6962
7147
  }
6963
- const decision = decideAutoPublish({ publication });
6964
- let publicationOutcome;
6965
- if (decision === "try") {
6966
- try {
6967
- const signer = makeSignerFromSecret(keys.identitySecretKey, result.did);
6968
- await api.publishAgent(result.did, signer);
6969
- publicationOutcome = "published";
6970
- if (!opts.json) console.log(import_chalk21.default.green(`
6971
- \u2713 Published \u2014 discoverable now via \`heyarp agents\`.`));
6972
- } catch (err) {
6973
- publicationOutcome = `failed: ${err.message}`;
6974
- if (!opts.json)
6975
- console.log(
6976
- import_chalk21.default.yellow(`
6977
- \u26A0 Auto-publish failed (${err.message}). Agent saved as DRAFT \u2014 run \`heyarp publish ${result.did}\` to make it discoverable.`)
6978
- );
6979
- }
6980
- } else {
6981
- publicationOutcome = "draft";
6982
- if (!opts.json) {
6983
- console.log(import_chalk21.default.dim(`
6984
- Publication mode: DRAFT. Agent is registered but NOT discoverable via \`heyarp agents\`.`));
6985
- console.log(import_chalk21.default.dim(`Run \`heyarp publish ${result.did}\` when ready to appear in the catalog.`));
6986
- }
6987
- }
6988
- if (!opts.json) console.log(import_chalk21.default.dim(`
7148
+ if (!opts.json) console.log(import_chalk20.default.green(`
7149
+ \u2713 Discoverable now via \`heyarp agents\`.`));
7150
+ if (!opts.json) console.log(import_chalk20.default.dim(`
6989
7151
  Local state saved to ${arpHomeDir()}/agents.json (mode 0600).`));
6990
7152
  if (opts.json) {
6991
7153
  console.log(
@@ -6997,8 +7159,6 @@ Local state saved to ${arpHomeDir()}/agents.json (mode 0600).`));
6997
7159
  // V1-alpha: accountId parked — `--json` output no longer
6998
7160
  // includes it. Uncomment when launchpad↔ARP join lands.
6999
7161
  // accountId: answers.accountId,
7000
- keyMode: "separated_soft",
7001
- publication: publicationOutcome,
7002
7162
  localStatePath: `${arpHomeDir()}/agents.json`,
7003
7163
  didDocument: result.didDocument
7004
7164
  },
@@ -7065,7 +7225,7 @@ async function mergeAnswers(opts) {
7065
7225
  }
7066
7226
  const prompted = promptDefs.length > 0 ? await (0, import_prompts2.default)(promptDefs, {
7067
7227
  onCancel: () => {
7068
- console.log(import_chalk21.default.yellow("\nAborted."));
7228
+ console.log(import_chalk20.default.yellow("\nAborted."));
7069
7229
  process.exit(130);
7070
7230
  }
7071
7231
  }) : {};
@@ -7087,16 +7247,16 @@ function warnIfOrphanHomesPresent() {
7087
7247
  try {
7088
7248
  others = listHomes().filter((h) => h.path !== current);
7089
7249
  } catch (registryErr) {
7090
- console.log(import_chalk21.default.dim(`(homes registry unreadable, skipping orphan-home check: ${registryErr.message})`));
7250
+ console.log(import_chalk20.default.dim(`(homes registry unreadable, skipping orphan-home check: ${registryErr.message})`));
7091
7251
  return;
7092
7252
  }
7093
7253
  if (others.length === 0) return;
7094
- const list = others.map((h) => ` \u2022 ${import_chalk21.default.cyan(h.path)} ${import_chalk21.default.dim(`(last seen ${h.lastSeenAt})`)}`).join("\n");
7095
- console.log(import_chalk21.default.yellow(`
7254
+ const list = others.map((h) => ` \u2022 ${import_chalk20.default.cyan(h.path)} ${import_chalk20.default.dim(`(last seen ${h.lastSeenAt})`)}`).join("\n");
7255
+ console.log(import_chalk20.default.yellow(`
7096
7256
  \u26A0 HEYARP_HOME is unset, but other agent homes are registered on this machine:`));
7097
7257
  console.log(list);
7098
7258
  console.log(
7099
- import_chalk21.default.dim(
7259
+ import_chalk20.default.dim(
7100
7260
  ` Registering will create a NEW agent under ${current}.
7101
7261
  If you meant to add to an existing home, abort (Ctrl-C) and re-run with:
7102
7262
  HEYARP_HOME=<path> heyarp register \u2026
@@ -7109,11 +7269,11 @@ function warnIfAgentsAlreadyRegistered(serverOverride) {
7109
7269
  const targetServer = resolveServerUrl(serverOverride);
7110
7270
  const existing = listAgents().filter((row) => row.serverUrl === targetServer);
7111
7271
  if (existing.length === 0) return;
7112
- const list = existing.map((row) => ` \u2022 ${import_chalk21.default.cyan(row.agent.did)}${row.agent.name ? import_chalk21.default.dim(` (${row.agent.name})`) : ""}`).join("\n");
7113
- console.log(import_chalk21.default.yellow("\n\u26A0 ~/.arp/agents.json already has agent(s) for this server:"));
7272
+ const list = existing.map((row) => ` \u2022 ${import_chalk20.default.cyan(row.agent.did)}${row.agent.name ? import_chalk20.default.dim(` (${row.agent.name})`) : ""}`).join("\n");
7273
+ console.log(import_chalk20.default.yellow("\n\u26A0 ~/.arp/agents.json already has agent(s) for this server:"));
7114
7274
  console.log(list);
7115
7275
  console.log(
7116
- import_chalk21.default.dim(
7276
+ import_chalk20.default.dim(
7117
7277
  " 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"
7118
7278
  )
7119
7279
  );
@@ -7133,12 +7293,12 @@ function freshKeys() {
7133
7293
  };
7134
7294
  }
7135
7295
  function loadKeysFromFile(path) {
7136
- if (!(0, import_node_fs9.existsSync)(path)) {
7296
+ if (!(0, import_node_fs8.existsSync)(path)) {
7137
7297
  throw new Error(`--from-keys: file not found at ${path}`);
7138
7298
  }
7139
7299
  let parsed;
7140
7300
  try {
7141
- parsed = JSON.parse((0, import_node_fs9.readFileSync)(path, "utf8"));
7301
+ parsed = JSON.parse((0, import_node_fs8.readFileSync)(path, "utf8"));
7142
7302
  } catch (err) {
7143
7303
  throw new Error(`--from-keys: ${path} is not valid JSON: ${err.message}`);
7144
7304
  }
@@ -7166,20 +7326,9 @@ function assertJsonRequiresYes(opts) {
7166
7326
  throw new Error("register --json REQUIRES --yes (interactive prompts would corrupt the single-doc JSON output)");
7167
7327
  }
7168
7328
  }
7169
- function parsePublicationMode(raw) {
7170
- if (raw === "active" || raw === "draft") return raw;
7171
- throw new Error(`register: --publication must be 'active' or 'draft' (got '${raw}')`);
7172
- }
7173
- function decideAutoPublish(input) {
7174
- if (input.publication !== "active") return "skip-draft";
7175
- return "try";
7176
- }
7177
- function makeSignerFromSecret(identitySecretKey, did) {
7178
- return { did, identitySecretKey };
7179
- }
7180
7329
 
7181
7330
  // src/commands/relationships.ts
7182
- var import_chalk22 = __toESM(require("chalk"));
7331
+ var import_chalk21 = __toESM(require("chalk"));
7183
7332
  init_api();
7184
7333
  init_format();
7185
7334
  init_state();
@@ -7202,25 +7351,25 @@ async function runRelationships(positionalDid, opts) {
7202
7351
  const local = explicitDid !== void 0 ? loadAgentOrThrow(opts.server, explicitDid) : resolveSenderAgent("relationships", opts.server, void 0);
7203
7352
  const did = local.did;
7204
7353
  const api = new ArpApiClient(opts.server);
7205
- console.log(import_chalk22.default.dim(`Server: ${api.serverUrl}`));
7206
- console.log(import_chalk22.default.dim(`Signer: ${local.did}`));
7354
+ console.log(import_chalk21.default.dim(`Server: ${api.serverUrl}`));
7355
+ console.log(import_chalk21.default.dim(`Signer: ${local.did}`));
7207
7356
  const query = { limit };
7208
7357
  if (state) query.state = state;
7209
7358
  const signer = makeSigner(local);
7210
7359
  const rows = await api.listRelationships(did, signer, query);
7211
7360
  if (rows.length === 0) {
7212
- console.log(import_chalk22.default.dim("\n(no relationships)"));
7361
+ console.log(import_chalk21.default.dim("\n(no relationships)"));
7213
7362
  return;
7214
7363
  }
7215
7364
  console.log("");
7216
7365
  console.log(formatRelationshipsTable(rows, did));
7217
7366
  if (opts.verbose) {
7218
- console.log(import_chalk22.default.bold("\nFull relationships:"));
7367
+ console.log(import_chalk21.default.bold("\nFull relationships:"));
7219
7368
  for (const r of rows) {
7220
7369
  console.log(formatJson(r));
7221
7370
  }
7222
7371
  }
7223
- console.log(import_chalk22.default.dim(`
7372
+ console.log(import_chalk21.default.dim(`
7224
7373
  ${rows.length} relationship(s).`));
7225
7374
  }
7226
7375
  function formatRelationshipsTable(rows, selfDid) {
@@ -7228,7 +7377,7 @@ function formatRelationshipsTable(rows, selfDid) {
7228
7377
  const data = rows.map((r) => [r.relationshipId, otherPair(r, selfDid), r.state, r.lastEventAt ?? "(none)", String(r.lastEventIndex)]);
7229
7378
  const widths = header.map((h, i) => Math.max(h.length, ...data.map((row) => row[i].length)));
7230
7379
  const pad = (cells) => cells.map((c, i) => c.padEnd(widths[i])).join(" ");
7231
- return [import_chalk22.default.bold(pad(header)), import_chalk22.default.dim(pad(widths.map((w) => "-".repeat(w)))), ...data.map((row) => pad(row))].join("\n");
7380
+ return [import_chalk21.default.bold(pad(header)), import_chalk21.default.dim(pad(widths.map((w) => "-".repeat(w)))), ...data.map((row) => pad(row))].join("\n");
7232
7381
  }
7233
7382
  function otherPair(r, selfDid) {
7234
7383
  if (r.pairDidA === selfDid) return r.pairDidB;
@@ -7251,141 +7400,9 @@ function parseLimit6(raw) {
7251
7400
  return n;
7252
7401
  }
7253
7402
 
7254
- // src/commands/rotate.ts
7255
- var import_sdk13 = require("@heyanon-arp/sdk");
7256
- var import_chalk23 = __toESM(require("chalk"));
7257
- var import_prompts3 = __toESM(require("prompts"));
7258
- init_api();
7259
- init_format();
7260
- init_state();
7261
- init_lifecycle();
7262
- var ROTATION_REASONS = ["scheduled", "compromise", "lost_device", "other"];
7263
- function registerRotateCommand(root) {
7264
- root.command("rotate").description("Rotate the agent identity key (DID stays frozen). Requires local state with ownerId + currentAttestationId.").argument("<did>").option("--server <url>", "Override ARP server base URL").option("--yes", "Skip the destructive-action confirmation prompt", false).option("--reason <s>", `Rotation reason \u2014 one of ${ROTATION_REASONS.join(" | ")}`, "scheduled").action(async (did, opts) => {
7265
- if (opts.reason && !ROTATION_REASONS.includes(opts.reason)) {
7266
- throw new Error(`rotate: --reason must be one of ${ROTATION_REASONS.join(", ")} (got '${opts.reason}')`);
7267
- }
7268
- await runRotate(did, opts);
7269
- });
7270
- }
7271
- async function runRotate(did, opts) {
7272
- const local = loadAgentOrThrow(opts.server, did);
7273
- if (!local.ownerId || !local.currentAttestationId) {
7274
- throw new Error("rotate: local state is missing ownerId / currentAttestationId. State predates the rotation flow \u2014 please re-register.");
7275
- }
7276
- const api = new ArpApiClient(opts.server);
7277
- console.log(import_chalk23.default.dim(`Server: ${api.serverUrl}`));
7278
- console.log(import_chalk23.default.dim(`Rotating: ${local.did}`));
7279
- if (!opts.yes) {
7280
- const confirm = await (0, import_prompts3.default)({
7281
- type: "confirm",
7282
- name: "go",
7283
- message: "Rotation invalidates the CURRENT private key the moment the server commits. Continue?",
7284
- initial: false
7285
- });
7286
- if (!confirm.go) {
7287
- console.log(import_chalk23.default.yellow("Aborted."));
7288
- return;
7289
- }
7290
- }
7291
- const next = (0, import_sdk13.generateKeyPair)();
7292
- const newIdentityPublicKeyB58 = (0, import_sdk13.base58btcEncode)(next.publicKey);
7293
- const challenge = await api.issueChallenge("rotate");
7294
- const challengeBytes = base64UrlNoPadDecode2(challenge.challengeB64);
7295
- if (challengeBytes.length !== 32) {
7296
- throw new Error(`Server returned a ${challengeBytes.length}-byte challenge; expected 32`);
7297
- }
7298
- const challengeSig = (0, import_sdk13.signChallenge)(challengeBytes, next.secretKey);
7299
- await api.submitChallengeResponse({
7300
- challengeId: challenge.challengeId,
7301
- identityPublicKey: newIdentityPublicKeyB58,
7302
- signature: Buffer.from(challengeSig).toString("base64")
7303
- });
7304
- const scryptKey = new Uint8Array(Buffer.from(local.scryptKeyB64, "base64"));
7305
- if (scryptKey.length !== 32) {
7306
- throw new Error("rotate: stored scryptKeyB64 is not 32 bytes \u2014 local state is corrupted, re-register.");
7307
- }
7308
- const reason = opts.reason ?? "scheduled";
7309
- const payload = {
7310
- purpose: "ARP-KEY-ROTATION-v1",
7311
- agent_did: did,
7312
- current_identity_public_key: local.identityPublicKeyB58,
7313
- new_identity_public_key: newIdentityPublicKeyB58,
7314
- settlement_public_key: local.settlementPublicKeyB58,
7315
- supersedes_attestation_id: local.currentAttestationId,
7316
- owner_id: local.ownerId,
7317
- owner_signing_method: "scrypt_password_proof",
7318
- rotation_reason: reason,
7319
- created_at: (0, import_sdk13.rfc3339)(),
7320
- nonce: (0, import_sdk13.senderNonce)()
7321
- };
7322
- const attestation = (0, import_sdk13.signKeyRotationAttestation)({
7323
- payload,
7324
- scryptKey,
7325
- scryptSaltId: local.scryptSaltId
7326
- });
7327
- const newIdentitySecretKeyB64 = Buffer.from(next.secretKey).toString("base64");
7328
- updateAgentLocal(opts.server, did, {
7329
- pendingRotation: {
7330
- newIdentityPublicKeyB58,
7331
- newIdentitySecretKeyB64,
7332
- issuedAt: (/* @__PURE__ */ new Date()).toISOString()
7333
- }
7334
- });
7335
- const body = {
7336
- challengeId: challenge.challengeId,
7337
- newIdentityPublicKey: newIdentityPublicKeyB58,
7338
- newKeyAttestation: {
7339
- payload: attestation.payload,
7340
- sig: attestation.sig,
7341
- scrypt_salt_id: attestation.scrypt_salt_id
7342
- }
7343
- };
7344
- const signer = makeSigner(local);
7345
- let updated;
7346
- try {
7347
- updated = await api.rotateIdentityKey(did, body, signer);
7348
- } catch (err) {
7349
- try {
7350
- updateAgentLocal(opts.server, did, { pendingRotation: void 0 });
7351
- } catch {
7352
- }
7353
- throw err;
7354
- }
7355
- try {
7356
- updateAgentLocal(opts.server, did, {
7357
- identityPublicKeyB58: newIdentityPublicKeyB58,
7358
- identitySecretKeyB64: newIdentitySecretKeyB64,
7359
- currentAttestationId: updated.currentAttestationId,
7360
- pendingRotation: void 0
7361
- });
7362
- } catch (err) {
7363
- console.error(import_chalk23.default.red("\nServer rotation succeeded but local state write failed."));
7364
- console.error(import_chalk23.default.red("Capture these values now \u2014 the new key is already live server-side:"));
7365
- console.error(` ${import_chalk23.default.bold("identityPublicKeyB58")} : ${newIdentityPublicKeyB58}`);
7366
- console.error(` ${import_chalk23.default.bold("identitySecretKeyB64")} : ${newIdentitySecretKeyB64}`);
7367
- console.error(` ${import_chalk23.default.bold("currentAttestationId")} : ${updated.currentAttestationId}`);
7368
- console.error(import_chalk23.default.dim(`(Also persisted in pendingRotation at ~/.arp/agents.json before the server call.)`));
7369
- console.error(import_chalk23.default.dim(`Underlying error: ${err.message}`));
7370
- throw err;
7371
- }
7372
- console.log(import_chalk23.default.green("\nRotated."));
7373
- console.log(`${import_chalk23.default.bold("DID")}: ${import_chalk23.default.cyan(updated.did)} ${import_chalk23.default.dim("(unchanged)")}`);
7374
- console.log(`${import_chalk23.default.bold("New identity public key")}: ${import_chalk23.default.cyan(newIdentityPublicKeyB58)}`);
7375
- console.log(`${import_chalk23.default.bold("New attestation id")}: ${import_chalk23.default.cyan(updated.currentAttestationId)}`);
7376
- console.log(import_chalk23.default.bold("\nAgent profile:"));
7377
- console.log(formatJson(updated));
7378
- console.log(import_chalk23.default.dim("\nLocal state updated; old private key is no longer valid."));
7379
- }
7380
- function base64UrlNoPadDecode2(s) {
7381
- const replaced = s.replace(/-/g, "+").replace(/_/g, "/");
7382
- const padded = replaced + "==".slice(0, (4 - replaced.length % 4) % 4);
7383
- return new Uint8Array(Buffer.from(padded, "base64"));
7384
- }
7385
-
7386
7403
  // src/commands/send-handshake.ts
7387
- var import_sdk14 = require("@heyanon-arp/sdk");
7388
- var import_chalk24 = __toESM(require("chalk"));
7404
+ var import_sdk13 = require("@heyanon-arp/sdk");
7405
+ var import_chalk22 = __toESM(require("chalk"));
7389
7406
  init_api();
7390
7407
  init_format();
7391
7408
  init_state();
@@ -7401,10 +7418,10 @@ async function runSendHandshake(recipientDid, opts) {
7401
7418
  }
7402
7419
  const ttlSeconds = parseTtl3(opts.ttl);
7403
7420
  const api = new ArpApiClient(opts.server);
7404
- console.log(import_chalk24.default.dim(`Server: ${api.serverUrl}`));
7421
+ console.log(import_chalk22.default.dim(`Server: ${api.serverUrl}`));
7405
7422
  const sender = resolveSenderAgent("send-handshake", opts.server, opts.fromDid);
7406
- console.log(import_chalk24.default.dim(`Sender: ${sender.did}`));
7407
- console.log(import_chalk24.default.dim(`Recipient: ${recipientDid}`));
7423
+ console.log(import_chalk22.default.dim(`Sender: ${sender.did}`));
7424
+ console.log(import_chalk22.default.dim(`Recipient: ${recipientDid}`));
7408
7425
  const content = {};
7409
7426
  if (opts.greeting) content.greeting = opts.greeting;
7410
7427
  if (opts.intent) content.intent = opts.intent;
@@ -7412,46 +7429,46 @@ async function runSendHandshake(recipientDid, opts) {
7412
7429
  const nextSequence = (sender.lastSenderSequence ?? 0) + 1;
7413
7430
  const protectedBlock = {
7414
7431
  protocol_version: "arp/0.1",
7415
- purpose: import_sdk14.Purpose.ENVELOPE,
7416
- message_id: (0, import_sdk14.uuidV4)(),
7432
+ purpose: import_sdk13.Purpose.ENVELOPE,
7433
+ message_id: (0, import_sdk13.uuidV4)(),
7417
7434
  sender_did: sender.did,
7418
7435
  recipient_did: recipientDid,
7419
7436
  relationship_id: null,
7420
7437
  sender_sequence: nextSequence,
7421
- sender_nonce: (0, import_sdk14.senderNonce)(),
7422
- timestamp: (0, import_sdk14.rfc3339)(),
7423
- expires_at: (0, import_sdk14.expiresAt)(ttlSeconds),
7438
+ sender_nonce: (0, import_sdk13.senderNonce)(),
7439
+ timestamp: (0, import_sdk13.rfc3339)(),
7440
+ expires_at: (0, import_sdk13.expiresAt)(ttlSeconds),
7424
7441
  delivery_id: null
7425
7442
  };
7426
7443
  const signer = makeSigner(sender);
7427
- const envelope = (0, import_sdk14.signEnvelope)({
7444
+ const envelope = (0, import_sdk13.signEnvelope)({
7428
7445
  protected: protectedBlock,
7429
7446
  body,
7430
7447
  identitySecretKey: signer.identitySecretKey
7431
7448
  });
7432
7449
  if (opts.verbose) {
7433
- console.log(import_chalk24.default.bold("\nEnvelope (pre-send):"));
7450
+ console.log(import_chalk22.default.bold("\nEnvelope (pre-send):"));
7434
7451
  console.log(formatJson(envelope));
7435
7452
  }
7436
7453
  const result = await api.ingest(envelope);
7437
7454
  updateAgentLocal(opts.server, sender.did, { lastSenderSequence: nextSequence });
7438
- console.log(import_chalk24.default.green("\nDelivered."));
7439
- console.log(`${import_chalk24.default.bold("Event id")}: ${import_chalk24.default.cyan(result.eventId)}`);
7440
- console.log(`${import_chalk24.default.bold("Relationship id")}: ${import_chalk24.default.cyan(result.relationshipId)}`);
7441
- console.log(`${import_chalk24.default.bold("Chain index")}: ${import_chalk24.default.cyan(String(result.relationshipEventIndex))}`);
7442
- console.log(`${import_chalk24.default.bold("Server timestamp")}: ${import_chalk24.default.cyan(result.serverTimestamp)}`);
7443
- console.log(`${import_chalk24.default.bold("Signed message hash")}: ${import_chalk24.default.cyan(result.signedMessageHash)}`);
7444
- console.log(`${import_chalk24.default.bold("Server event hash")}: ${import_chalk24.default.cyan(result.serverEventHash)}`);
7455
+ console.log(import_chalk22.default.green("\nDelivered."));
7456
+ console.log(`${import_chalk22.default.bold("Event id")}: ${import_chalk22.default.cyan(result.eventId)}`);
7457
+ console.log(`${import_chalk22.default.bold("Relationship id")}: ${import_chalk22.default.cyan(result.relationshipId)}`);
7458
+ console.log(`${import_chalk22.default.bold("Chain index")}: ${import_chalk22.default.cyan(String(result.relationshipEventIndex))}`);
7459
+ console.log(`${import_chalk22.default.bold("Server timestamp")}: ${import_chalk22.default.cyan(result.serverTimestamp)}`);
7460
+ console.log(`${import_chalk22.default.bold("Signed message hash")}: ${import_chalk22.default.cyan(result.signedMessageHash)}`);
7461
+ console.log(`${import_chalk22.default.bold("Server event hash")}: ${import_chalk22.default.cyan(result.serverEventHash)}`);
7445
7462
  if (result.prevServerEventHash) {
7446
- console.log(`${import_chalk24.default.bold("Prev server event hash")}: ${import_chalk24.default.cyan(result.prevServerEventHash)}`);
7463
+ console.log(`${import_chalk22.default.bold("Prev server event hash")}: ${import_chalk22.default.cyan(result.prevServerEventHash)}`);
7447
7464
  } else {
7448
- console.log(`${import_chalk24.default.bold("Prev server event hash")}: ${import_chalk24.default.dim("(null \u2014 first event of this relationship)")}`);
7465
+ console.log(`${import_chalk22.default.bold("Prev server event hash")}: ${import_chalk22.default.dim("(null \u2014 first event of this relationship)")}`);
7449
7466
  }
7450
7467
  if (opts.verbose) {
7451
- console.log(import_chalk24.default.bold("\nFull server response:"));
7468
+ console.log(import_chalk22.default.bold("\nFull server response:"));
7452
7469
  console.log(formatJson(result));
7453
7470
  }
7454
- console.log(import_chalk24.default.dim(`
7471
+ console.log(import_chalk22.default.dim(`
7455
7472
  Local sender_sequence advanced to ${nextSequence}.`));
7456
7473
  }
7457
7474
  function parseTtl3(raw) {
@@ -7467,8 +7484,8 @@ function isDid(s) {
7467
7484
  }
7468
7485
 
7469
7486
  // src/commands/send-handshake-response.ts
7470
- var import_sdk15 = require("@heyanon-arp/sdk");
7471
- var import_chalk25 = __toESM(require("chalk"));
7487
+ var import_sdk14 = require("@heyanon-arp/sdk");
7488
+ var import_chalk23 = __toESM(require("chalk"));
7472
7489
  init_api();
7473
7490
  init_format();
7474
7491
  init_state();
@@ -7482,7 +7499,7 @@ function registerSendHandshakeResponseCommand(root) {
7482
7499
  // We don't use commander's requiredOption because it
7483
7500
  // would fire for the accept path too; validate manually
7484
7501
  // after decision is parsed.
7485
- `When --decision=decline: required reason code (one of: ${import_sdk15.DECLINE_REASONS.join(", ")}). Carried in body.content.reason.`
7502
+ `When --decision=decline: required reason code (one of: ${import_sdk14.DECLINE_REASONS.join(", ")}). Carried in body.content.reason.`
7486
7503
  ).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(
7487
7504
  "--json",
7488
7505
  "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.",
@@ -7513,11 +7530,11 @@ async function runSendHandshakeResponse(recipientDid, opts) {
7513
7530
  declinePayload = detail ? { reason, reasonDetail: detail } : { reason };
7514
7531
  }
7515
7532
  const api = new ArpApiClient(opts.server);
7516
- progress(opts.json, import_chalk25.default.dim(`Server: ${api.serverUrl}`));
7533
+ progress(opts.json, import_chalk23.default.dim(`Server: ${api.serverUrl}`));
7517
7534
  const sender = resolveSenderAgent("send-handshake-response", opts.server, opts.fromDid);
7518
- progress(opts.json, import_chalk25.default.dim(`Sender: ${sender.did}`));
7519
- progress(opts.json, import_chalk25.default.dim(`Recipient: ${recipientDid}`));
7520
- progress(opts.json, import_chalk25.default.dim(`Decision: ${decision}`));
7535
+ progress(opts.json, import_chalk23.default.dim(`Sender: ${sender.did}`));
7536
+ progress(opts.json, import_chalk23.default.dim(`Recipient: ${recipientDid}`));
7537
+ progress(opts.json, import_chalk23.default.dim(`Decision: ${decision}`));
7521
7538
  const signer = makeSigner(sender);
7522
7539
  if (!opts.force) {
7523
7540
  try {
@@ -7546,13 +7563,13 @@ async function runSendHandshakeResponse(recipientDid, opts) {
7546
7563
  });
7547
7564
  return;
7548
7565
  }
7549
- progress(opts.json, import_chalk25.default.yellow(`
7566
+ progress(opts.json, import_chalk23.default.yellow(`
7550
7567
  [--idempotency] Relationship ${existing.relationshipId} with ${recipientDid} is already 'active'.`));
7551
7568
  progress(
7552
7569
  opts.json,
7553
- import_chalk25.default.dim(`A previous accept from this signer (event ${previousResponseFromMe.eventId}) landed successfully. Skipping re-send (use --force to override).`)
7570
+ import_chalk23.default.dim(`A previous accept from this signer (event ${previousResponseFromMe.eventId}) landed successfully. Skipping re-send (use --force to override).`)
7554
7571
  );
7555
- progress(opts.json, import_chalk25.default.dim(`Last event index: ${existing.lastEventIndex}, last server event hash: ${existing.lastServerEventHash ?? "(none)"}`));
7572
+ progress(opts.json, import_chalk23.default.dim(`Last event index: ${existing.lastEventIndex}, last server event hash: ${existing.lastServerEventHash ?? "(none)"}`));
7556
7573
  return;
7557
7574
  }
7558
7575
  throw new Error(
@@ -7563,7 +7580,7 @@ async function runSendHandshakeResponse(recipientDid, opts) {
7563
7580
  if (probeErr instanceof Error && /CLOSED|terminated|already 'active' from a previous ACCEPT|original initiator/i.test(probeErr.message)) {
7564
7581
  throw probeErr;
7565
7582
  }
7566
- progress(opts.json, import_chalk25.default.dim(`(idempotency probe failed; proceeding anyway: ${probeErr.message})`));
7583
+ progress(opts.json, import_chalk23.default.dim(`(idempotency probe failed; proceeding anyway: ${probeErr.message})`));
7567
7584
  }
7568
7585
  }
7569
7586
  const content = { decision };
@@ -7576,24 +7593,24 @@ async function runSendHandshakeResponse(recipientDid, opts) {
7576
7593
  const nextSequence = (sender.lastSenderSequence ?? 0) + 1;
7577
7594
  const protectedBlock = {
7578
7595
  protocol_version: "arp/0.1",
7579
- purpose: import_sdk15.Purpose.ENVELOPE,
7580
- message_id: (0, import_sdk15.uuidV4)(),
7596
+ purpose: import_sdk14.Purpose.ENVELOPE,
7597
+ message_id: (0, import_sdk14.uuidV4)(),
7581
7598
  sender_did: sender.did,
7582
7599
  recipient_did: recipientDid,
7583
7600
  relationship_id: null,
7584
7601
  sender_sequence: nextSequence,
7585
- sender_nonce: (0, import_sdk15.senderNonce)(),
7586
- timestamp: (0, import_sdk15.rfc3339)(),
7587
- expires_at: (0, import_sdk15.expiresAt)(ttlSeconds),
7602
+ sender_nonce: (0, import_sdk14.senderNonce)(),
7603
+ timestamp: (0, import_sdk14.rfc3339)(),
7604
+ expires_at: (0, import_sdk14.expiresAt)(ttlSeconds),
7588
7605
  delivery_id: null
7589
7606
  };
7590
- const envelope = (0, import_sdk15.signEnvelope)({
7607
+ const envelope = (0, import_sdk14.signEnvelope)({
7591
7608
  protected: protectedBlock,
7592
7609
  body,
7593
7610
  identitySecretKey: signer.identitySecretKey
7594
7611
  });
7595
7612
  if (opts.verbose) {
7596
- console.log(import_chalk25.default.bold("\nEnvelope (pre-send):"));
7613
+ console.log(import_chalk23.default.bold("\nEnvelope (pre-send):"));
7597
7614
  console.log(formatJson(envelope));
7598
7615
  }
7599
7616
  const result = await api.ingest(envelope);
@@ -7613,23 +7630,23 @@ async function runSendHandshakeResponse(recipientDid, opts) {
7613
7630
  });
7614
7631
  return;
7615
7632
  }
7616
- console.log(import_chalk25.default.green("\nDelivered."));
7617
- console.log(`${import_chalk25.default.bold("Event id")}: ${import_chalk25.default.cyan(result.eventId)}`);
7618
- console.log(`${import_chalk25.default.bold("Relationship id")}: ${import_chalk25.default.cyan(result.relationshipId)}`);
7619
- console.log(`${import_chalk25.default.bold("Chain index")}: ${import_chalk25.default.cyan(String(result.relationshipEventIndex))}`);
7620
- console.log(`${import_chalk25.default.bold("Server timestamp")}: ${import_chalk25.default.cyan(result.serverTimestamp)}`);
7621
- console.log(`${import_chalk25.default.bold("Signed message hash")}: ${import_chalk25.default.cyan(result.signedMessageHash)}`);
7622
- console.log(`${import_chalk25.default.bold("Server event hash")}: ${import_chalk25.default.cyan(result.serverEventHash)}`);
7633
+ console.log(import_chalk23.default.green("\nDelivered."));
7634
+ console.log(`${import_chalk23.default.bold("Event id")}: ${import_chalk23.default.cyan(result.eventId)}`);
7635
+ console.log(`${import_chalk23.default.bold("Relationship id")}: ${import_chalk23.default.cyan(result.relationshipId)}`);
7636
+ console.log(`${import_chalk23.default.bold("Chain index")}: ${import_chalk23.default.cyan(String(result.relationshipEventIndex))}`);
7637
+ console.log(`${import_chalk23.default.bold("Server timestamp")}: ${import_chalk23.default.cyan(result.serverTimestamp)}`);
7638
+ console.log(`${import_chalk23.default.bold("Signed message hash")}: ${import_chalk23.default.cyan(result.signedMessageHash)}`);
7639
+ console.log(`${import_chalk23.default.bold("Server event hash")}: ${import_chalk23.default.cyan(result.serverEventHash)}`);
7623
7640
  if (result.prevServerEventHash) {
7624
- console.log(`${import_chalk25.default.bold("Prev server event hash")}: ${import_chalk25.default.cyan(result.prevServerEventHash)}`);
7641
+ console.log(`${import_chalk23.default.bold("Prev server event hash")}: ${import_chalk23.default.cyan(result.prevServerEventHash)}`);
7625
7642
  } else {
7626
- console.log(`${import_chalk25.default.bold("Prev server event hash")}: ${import_chalk25.default.dim("(null \u2014 first event of this relationship)")}`);
7643
+ console.log(`${import_chalk23.default.bold("Prev server event hash")}: ${import_chalk23.default.dim("(null \u2014 first event of this relationship)")}`);
7627
7644
  }
7628
7645
  if (opts.verbose) {
7629
- console.log(import_chalk25.default.bold("\nFull server response:"));
7646
+ console.log(import_chalk23.default.bold("\nFull server response:"));
7630
7647
  console.log(formatJson(result));
7631
7648
  }
7632
- console.log(import_chalk25.default.dim(`
7649
+ console.log(import_chalk23.default.dim(`
7633
7650
  Local sender_sequence advanced to ${nextSequence}.`));
7634
7651
  }
7635
7652
  function parseDecision(raw) {
@@ -7688,7 +7705,7 @@ init_status();
7688
7705
  init_wallet();
7689
7706
 
7690
7707
  // src/commands/watch.ts
7691
- var import_chalk26 = __toESM(require("chalk"));
7708
+ var import_chalk24 = __toESM(require("chalk"));
7692
7709
  init_api();
7693
7710
  init_format();
7694
7711
  init_state();
@@ -7702,9 +7719,9 @@ async function runWatch(relationshipId, opts) {
7702
7719
  const local = resolveSenderAgent("watch", opts.server, opts.fromDid);
7703
7720
  const api = new ArpApiClient(opts.server);
7704
7721
  if (!opts.json) {
7705
- console.log(import_chalk26.default.dim(`Server: ${api.serverUrl}`));
7706
- console.log(import_chalk26.default.dim(`Signer: ${local.did}`));
7707
- console.log(import_chalk26.default.dim(`Watching: ${relationshipId}`));
7722
+ console.log(import_chalk24.default.dim(`Server: ${api.serverUrl}`));
7723
+ console.log(import_chalk24.default.dim(`Signer: ${local.did}`));
7724
+ console.log(import_chalk24.default.dim(`Watching: ${relationshipId}`));
7708
7725
  }
7709
7726
  const controller = new AbortController();
7710
7727
  let userAborted = false;
@@ -7723,7 +7740,7 @@ async function runWatch(relationshipId, opts) {
7723
7740
  }
7724
7741
  if (event.type === "heartbeat") continue;
7725
7742
  if (event.type === "connected") {
7726
- console.log(import_chalk26.default.green(`\u25CF stream open \u2014 watching ${relationshipId}`));
7743
+ console.log(import_chalk24.default.green(`\u25CF stream open \u2014 watching ${relationshipId}`));
7727
7744
  continue;
7728
7745
  }
7729
7746
  if (event.type === "envelope") {
@@ -7737,7 +7754,7 @@ async function runWatch(relationshipId, opts) {
7737
7754
  }
7738
7755
  continue;
7739
7756
  }
7740
- console.log(import_chalk26.default.dim(`(unknown event: ${event.type})`));
7757
+ console.log(import_chalk24.default.dim(`(unknown event: ${event.type})`));
7741
7758
  }
7742
7759
  if (!userAborted) {
7743
7760
  throw new Error(`watch ${relationshipId}: stream ended unexpectedly (server may have restarted, or the change stream errored). Re-run to reconnect.`);
@@ -7745,7 +7762,7 @@ async function runWatch(relationshipId, opts) {
7745
7762
  } catch (err) {
7746
7763
  const name = err.name;
7747
7764
  if (name === "AbortError" || userAborted) {
7748
- if (!opts.json) console.log(import_chalk26.default.dim("\nstream closed."));
7765
+ if (!opts.json) console.log(import_chalk24.default.dim("\nstream closed."));
7749
7766
  return;
7750
7767
  }
7751
7768
  throw err;
@@ -7759,21 +7776,21 @@ function formatWatchLine(ev, selfDid, opts = {}) {
7759
7776
  const type = ev.type.padEnd(20);
7760
7777
  const direction = directionLabel2(ev, selfDid, opts);
7761
7778
  const hash = opts.fullIds ? ev.serverEventHash : hashHead4(ev.serverEventHash);
7762
- return `${import_chalk26.default.dim(`[${ts}]`)} ${type} ${direction} ${import_chalk26.default.cyan(hash)}`;
7779
+ return `${import_chalk24.default.dim(`[${ts}]`)} ${type} ${direction} ${import_chalk24.default.cyan(hash)}`;
7763
7780
  }
7764
7781
  function directionLabel2(ev, selfDid, opts = {}) {
7765
7782
  const senderHead = opts.fullIds ? ev.senderDid : didHead4(ev.senderDid);
7766
7783
  const recipientHead = opts.fullIds ? ev.recipientDid : didHead4(ev.recipientDid);
7767
- if (ev.senderDid === selfDid) return `${import_chalk26.default.bold("me")} \u2192 ${import_chalk26.default.dim(recipientHead)}`;
7768
- if (ev.recipientDid === selfDid) return `${import_chalk26.default.dim(senderHead)} \u2192 ${import_chalk26.default.bold("me")}`;
7769
- return `${import_chalk26.default.dim(senderHead)} \u2192 ${import_chalk26.default.dim(recipientHead)}`;
7784
+ if (ev.senderDid === selfDid) return `${import_chalk24.default.bold("me")} \u2192 ${import_chalk24.default.dim(recipientHead)}`;
7785
+ if (ev.recipientDid === selfDid) return `${import_chalk24.default.dim(senderHead)} \u2192 ${import_chalk24.default.bold("me")}`;
7786
+ return `${import_chalk24.default.dim(senderHead)} \u2192 ${import_chalk24.default.dim(recipientHead)}`;
7770
7787
  }
7771
7788
  function didHead4(did) {
7772
7789
  if (did.length <= 20) return did;
7773
7790
  return `${did.slice(0, 20)}...`;
7774
7791
  }
7775
7792
  function hashHead4(hash) {
7776
- if (!hash) return import_chalk26.default.dim("(none)");
7793
+ if (!hash) return import_chalk24.default.dim("(none)");
7777
7794
  if (hash.length <= 14) return hash;
7778
7795
  return `${hash.slice(0, 14)}...`;
7779
7796
  }
@@ -7785,7 +7802,7 @@ function formatClock(iso) {
7785
7802
  }
7786
7803
 
7787
7804
  // src/commands/whoami.ts
7788
- var import_chalk27 = __toESM(require("chalk"));
7805
+ var import_chalk25 = __toESM(require("chalk"));
7789
7806
  init_api();
7790
7807
  init_format();
7791
7808
  init_state();
@@ -7798,10 +7815,10 @@ function registerWhoamiCommand(root) {
7798
7815
  // Persona scripts want the local settlement pubkey for
7799
7816
  // `--payer-settlement-pubkey` / on-chain ops without a
7800
7817
  // server round-trip. `--local` short-circuits the signed
7801
- // GET, prints just the resolved DID + pubkeys + keyMode
7802
- // from local state. (V1-alpha: accountId parked, no longer
7803
- // in --local output.)
7804
- "Print local-state info only (DID + settlement + identity pubkeys + keyMode). Skips the signed server fetch \u2014 useful for scripts that need the local pubkey before the server is up, or to grep from a shell without burning a network round-trip.",
7818
+ // GET, prints just the resolved DID + pubkeys from local
7819
+ // state. (V1-alpha: accountId parked, no longer in --local
7820
+ // output.)
7821
+ "Print local-state info only (DID + settlement + identity pubkeys). Skips the signed server fetch \u2014 useful for scripts that need the local pubkey before the server is up, or to grep from a shell without burning a network round-trip.",
7805
7822
  false
7806
7823
  ).option("--json", "JSON output (jq-pipeable). Combines local + server data when --local is unset, or just local when --local is set.", false).action(async (didArg, opts, cmd) => {
7807
7824
  try {
@@ -7815,18 +7832,16 @@ function registerWhoamiCommand(root) {
7815
7832
  // longer carries the field. Uncomment when launchpad↔ARP
7816
7833
  // join lands.
7817
7834
  // accountId: local.accountId,
7818
- keyMode: local.keyMode,
7819
7835
  name: local.name
7820
7836
  };
7821
7837
  if (opts.local) {
7822
7838
  if (opts.json) {
7823
7839
  console.log(formatJson(localJson));
7824
7840
  } else {
7825
- console.log(import_chalk27.default.bold("Local agent:"));
7826
- console.log(` DID: ${import_chalk27.default.cyan(local.did)}`);
7827
- console.log(` Settlement pubkey: ${import_chalk27.default.cyan(local.settlementPublicKeyB58)}`);
7828
- console.log(` Identity pubkey: ${import_chalk27.default.cyan(local.identityPublicKeyB58)}`);
7829
- console.log(` Key mode: ${local.keyMode}`);
7841
+ console.log(import_chalk25.default.bold("Local agent:"));
7842
+ console.log(` DID: ${import_chalk25.default.cyan(local.did)}`);
7843
+ console.log(` Settlement pubkey: ${import_chalk25.default.cyan(local.settlementPublicKeyB58)}`);
7844
+ console.log(` Identity pubkey: ${import_chalk25.default.cyan(local.identityPublicKeyB58)}`);
7830
7845
  if (local.name) console.log(` Name: ${local.name}`);
7831
7846
  }
7832
7847
  return;
@@ -7837,12 +7852,12 @@ function registerWhoamiCommand(root) {
7837
7852
  if (opts.json) {
7838
7853
  console.log(formatJson({ local: localJson, server: agent }));
7839
7854
  } else {
7840
- console.log(import_chalk27.default.dim(`Server: ${api.serverUrl}`));
7841
- console.log(import_chalk27.default.bold("\nLocal agent:"));
7842
- console.log(` DID: ${import_chalk27.default.cyan(local.did)}`);
7843
- console.log(` Settlement pubkey: ${import_chalk27.default.cyan(local.settlementPublicKeyB58)}`);
7844
- console.log(` Identity pubkey: ${import_chalk27.default.cyan(local.identityPublicKeyB58)}`);
7845
- console.log(import_chalk27.default.bold("\nServer profile:"));
7855
+ console.log(import_chalk25.default.dim(`Server: ${api.serverUrl}`));
7856
+ console.log(import_chalk25.default.bold("\nLocal agent:"));
7857
+ console.log(` DID: ${import_chalk25.default.cyan(local.did)}`);
7858
+ console.log(` Settlement pubkey: ${import_chalk25.default.cyan(local.settlementPublicKeyB58)}`);
7859
+ console.log(` Identity pubkey: ${import_chalk25.default.cyan(local.identityPublicKeyB58)}`);
7860
+ console.log(import_chalk25.default.bold("\nServer profile:"));
7846
7861
  console.log(formatJson(agent));
7847
7862
  }
7848
7863
  } catch (err) {
@@ -7853,8 +7868,8 @@ function registerWhoamiCommand(root) {
7853
7868
  }
7854
7869
 
7855
7870
  // src/commands/work.ts
7856
- var import_sdk16 = require("@heyanon-arp/sdk");
7857
- var import_chalk28 = __toESM(require("chalk"));
7871
+ var import_sdk15 = require("@heyanon-arp/sdk");
7872
+ var import_chalk26 = __toESM(require("chalk"));
7858
7873
  init_api();
7859
7874
  init_format();
7860
7875
  init_id_format();
@@ -7873,7 +7888,16 @@ var POST_COMMIT_ERROR_CODES3 = /* @__PURE__ */ new Set([
7873
7888
  "WORK_REQUEST_ALREADY_EXISTS",
7874
7889
  "WORK_REQUEST_NOT_FOUND",
7875
7890
  "WORK_RESPONDER_IS_CALLER",
7876
- "WORK_INVALID_STATE"
7891
+ "WORK_INVALID_STATE",
7892
+ // M6 lock-at-accept: the work handler's LOCKED gate emits
7893
+ // `DELEGATION_PENDING_LOCK` (409) when the delegation is funded but
7894
+ // the on-chain lock isn't confirmed yet (state
7895
+ // `pending_lock_finalization`). It fires from the body handler AFTER
7896
+ // the event row is committed — same lifecycle as
7897
+ // `WORK_DELEGATION_NOT_ACTIVE` — so the CLI must advance
7898
+ // `lastSenderSequence`, otherwise a retry once the lock confirms
7899
+ // reuses the consumed sequence and trips `ENV_SEQUENCE_BACKWARDS`.
7900
+ "DELEGATION_PENDING_LOCK"
7877
7901
  ]);
7878
7902
  function registerRequest(parent) {
7879
7903
  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(
@@ -7900,17 +7924,17 @@ async function runRequest(recipientDid, delegationId, opts) {
7900
7924
  params
7901
7925
  };
7902
7926
  const body = { type: "work_request", content };
7903
- console.log(import_chalk28.default.dim(`Server: ${api.serverUrl}`));
7904
- console.log(import_chalk28.default.dim(`Sender: ${sender.did}`));
7905
- console.log(import_chalk28.default.dim(`Recipient: ${recipientDid}`));
7906
- console.log(import_chalk28.default.dim(`Delegation: ${delegationId}`));
7907
- console.log(import_chalk28.default.dim(`Request id: ${requestId}`));
7927
+ console.log(import_chalk26.default.dim(`Server: ${api.serverUrl}`));
7928
+ console.log(import_chalk26.default.dim(`Sender: ${sender.did}`));
7929
+ console.log(import_chalk26.default.dim(`Recipient: ${recipientDid}`));
7930
+ console.log(import_chalk26.default.dim(`Delegation: ${delegationId}`));
7931
+ console.log(import_chalk26.default.dim(`Request id: ${requestId}`));
7908
7932
  const result = await sendWorkEnvelope({ api, sender, recipientDid, body, ttlSeconds, verbose: opts.verbose, server: opts.server });
7909
7933
  printIngestResult3(result);
7910
- console.log(import_chalk28.default.dim(`
7934
+ console.log(import_chalk26.default.dim(`
7911
7935
  The payee can reply with:`));
7912
- console.log(import_chalk28.default.dim(` heyarp work respond ${result.relationshipId} ${delegationId} ${requestId} --output '<json>'`));
7913
- console.log(import_chalk28.default.dim(` heyarp work respond ${result.relationshipId} ${delegationId} ${requestId} --error CODE:message`));
7936
+ console.log(import_chalk26.default.dim(` heyarp work respond ${result.relationshipId} ${delegationId} ${requestId} --output '<json>'`));
7937
+ console.log(import_chalk26.default.dim(` heyarp work respond ${result.relationshipId} ${delegationId} ${requestId} --error CODE:message`));
7914
7938
  }
7915
7939
  function registerRespond(parent) {
7916
7940
  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(
@@ -7935,13 +7959,13 @@ async function runRespond(relationshipId, delegationId, requestId, opts) {
7935
7959
  ...responsePayload
7936
7960
  };
7937
7961
  const body = { type: "work_response", content };
7938
- console.log(import_chalk28.default.dim(`Server: ${api.serverUrl}`));
7939
- console.log(import_chalk28.default.dim(`Sender: ${sender.did}`));
7940
- console.log(import_chalk28.default.dim(`Recipient: ${recipientDid}`));
7941
- console.log(import_chalk28.default.dim(`Relationship: ${relationshipId}`));
7942
- console.log(import_chalk28.default.dim(`Delegation: ${delegationId}`));
7943
- console.log(import_chalk28.default.dim(`Request id: ${requestId}`));
7944
- console.log(import_chalk28.default.dim(`Outcome: ${responsePayload.output ? "success" : "error"}`));
7962
+ console.log(import_chalk26.default.dim(`Server: ${api.serverUrl}`));
7963
+ console.log(import_chalk26.default.dim(`Sender: ${sender.did}`));
7964
+ console.log(import_chalk26.default.dim(`Recipient: ${recipientDid}`));
7965
+ console.log(import_chalk26.default.dim(`Relationship: ${relationshipId}`));
7966
+ console.log(import_chalk26.default.dim(`Delegation: ${delegationId}`));
7967
+ console.log(import_chalk26.default.dim(`Request id: ${requestId}`));
7968
+ console.log(import_chalk26.default.dim(`Outcome: ${responsePayload.output ? "success" : "error"}`));
7945
7969
  const result = await sendWorkEnvelope({ api, sender, recipientDid, body, ttlSeconds, verbose: opts.verbose, server: opts.server });
7946
7970
  printIngestResult3(result);
7947
7971
  }
@@ -7949,25 +7973,25 @@ async function sendWorkEnvelope(args) {
7949
7973
  const nextSequence = (args.sender.lastSenderSequence ?? 0) + 1;
7950
7974
  const protectedBlock = {
7951
7975
  protocol_version: "arp/0.1",
7952
- purpose: import_sdk16.Purpose.ENVELOPE,
7953
- message_id: (0, import_sdk16.uuidV4)(),
7976
+ purpose: import_sdk15.Purpose.ENVELOPE,
7977
+ message_id: (0, import_sdk15.uuidV4)(),
7954
7978
  sender_did: args.sender.did,
7955
7979
  recipient_did: args.recipientDid,
7956
7980
  relationship_id: null,
7957
7981
  sender_sequence: nextSequence,
7958
- sender_nonce: (0, import_sdk16.senderNonce)(),
7959
- timestamp: (0, import_sdk16.rfc3339)(),
7960
- expires_at: (0, import_sdk16.expiresAt)(args.ttlSeconds),
7982
+ sender_nonce: (0, import_sdk15.senderNonce)(),
7983
+ timestamp: (0, import_sdk15.rfc3339)(),
7984
+ expires_at: (0, import_sdk15.expiresAt)(args.ttlSeconds),
7961
7985
  delivery_id: null
7962
7986
  };
7963
7987
  const signer = makeSigner(args.sender);
7964
- const envelope = (0, import_sdk16.signEnvelope)({
7988
+ const envelope = (0, import_sdk15.signEnvelope)({
7965
7989
  protected: protectedBlock,
7966
7990
  body: args.body,
7967
7991
  identitySecretKey: signer.identitySecretKey
7968
7992
  });
7969
7993
  if (args.verbose) {
7970
- console.log(import_chalk28.default.bold("\nEnvelope (pre-send):"));
7994
+ console.log(import_chalk26.default.bold("\nEnvelope (pre-send):"));
7971
7995
  console.log(formatJson(envelope));
7972
7996
  }
7973
7997
  try {
@@ -8007,12 +8031,12 @@ async function resolveResponseRecipient(cmdName, api, signer, args) {
8007
8031
  );
8008
8032
  }
8009
8033
  function printIngestResult3(result) {
8010
- console.log(import_chalk28.default.green("\nDelivered."));
8011
- console.log(`${import_chalk28.default.bold("Event id")}: ${import_chalk28.default.cyan(result.eventId)}`);
8012
- console.log(`${import_chalk28.default.bold("Relationship id")}: ${import_chalk28.default.cyan(result.relationshipId)}`);
8013
- console.log(`${import_chalk28.default.bold("Chain index")}: ${import_chalk28.default.cyan(String(result.relationshipEventIndex))}`);
8014
- console.log(`${import_chalk28.default.bold("Server timestamp")}: ${import_chalk28.default.cyan(result.serverTimestamp)}`);
8015
- console.log(`${import_chalk28.default.bold("Server event hash")}: ${import_chalk28.default.cyan(result.serverEventHash)}`);
8034
+ console.log(import_chalk26.default.green("\nDelivered."));
8035
+ console.log(`${import_chalk26.default.bold("Event id")}: ${import_chalk26.default.cyan(result.eventId)}`);
8036
+ console.log(`${import_chalk26.default.bold("Relationship id")}: ${import_chalk26.default.cyan(result.relationshipId)}`);
8037
+ console.log(`${import_chalk26.default.bold("Chain index")}: ${import_chalk26.default.cyan(String(result.relationshipEventIndex))}`);
8038
+ console.log(`${import_chalk26.default.bold("Server timestamp")}: ${import_chalk26.default.cyan(result.serverTimestamp)}`);
8039
+ console.log(`${import_chalk26.default.bold("Server event hash")}: ${import_chalk26.default.cyan(result.serverEventHash)}`);
8016
8040
  }
8017
8041
  function parseJsonObject(cmdName, flagName, raw) {
8018
8042
  let parsed;
@@ -8050,13 +8074,13 @@ function parseParamsInput(cmdName, opts) {
8050
8074
  return parseJsonObject(cmdName, "--params", opts.params ?? "{}");
8051
8075
  }
8052
8076
  function readJsonObjectFile(cmdName, flagName, path) {
8053
- const { existsSync: existsSync7, readFileSync: readFileSync9 } = require("fs");
8054
- if (!existsSync7(path)) {
8077
+ const { existsSync: existsSync6, readFileSync: readFileSync8 } = require("fs");
8078
+ if (!existsSync6(path)) {
8055
8079
  throw new Error(`${cmdName}: ${flagName} file not found at ${path}`);
8056
8080
  }
8057
8081
  let raw;
8058
8082
  try {
8059
- raw = readFileSync9(path, "utf8");
8083
+ raw = readFileSync8(path, "utf8");
8060
8084
  } catch (err) {
8061
8085
  const detail = err instanceof Error ? err.message : String(err);
8062
8086
  throw new Error(`${cmdName}: failed to read ${flagName} (${path}): ${detail}`);
@@ -8104,7 +8128,7 @@ function parseTtl5(cmdName, raw) {
8104
8128
  }
8105
8129
  function parseRequestId(cmdName, raw) {
8106
8130
  if (raw === void 0 || raw === "") {
8107
- return (0, import_sdk16.uuidV4)();
8131
+ return (0, import_sdk15.uuidV4)();
8108
8132
  }
8109
8133
  if (raw.length === 0) {
8110
8134
  throw new Error(`${cmdName}: --request-id must be a non-empty string`);
@@ -8125,7 +8149,7 @@ function requireDid3(cmdName, did, label) {
8125
8149
  }
8126
8150
 
8127
8151
  // src/commands/work-list.ts
8128
- var import_chalk29 = __toESM(require("chalk"));
8152
+ var import_chalk27 = __toESM(require("chalk"));
8129
8153
  init_api();
8130
8154
  init_format();
8131
8155
  init_state();
@@ -8155,9 +8179,9 @@ async function runWorkList(relationshipId, opts) {
8155
8179
  const api = new ArpApiClient(opts.server);
8156
8180
  const sender = resolveSenderAgent("work-list", opts.server, opts.fromDid);
8157
8181
  if (!opts.json) {
8158
- console.log(import_chalk29.default.dim(`Server: ${api.serverUrl}`));
8159
- console.log(import_chalk29.default.dim(`Signer: ${sender.did}`));
8160
- console.log(import_chalk29.default.dim(`Relationship: ${relationshipId}`));
8182
+ console.log(import_chalk27.default.dim(`Server: ${api.serverUrl}`));
8183
+ console.log(import_chalk27.default.dim(`Signer: ${sender.did}`));
8184
+ console.log(import_chalk27.default.dim(`Relationship: ${relationshipId}`));
8161
8185
  }
8162
8186
  const query = { limit };
8163
8187
  if (state) query.state = state;
@@ -8170,7 +8194,7 @@ async function runWorkList(relationshipId, opts) {
8170
8194
  return;
8171
8195
  }
8172
8196
  if (rows.length === 0) {
8173
- console.log(import_chalk29.default.dim("\n(no work-logs for this relationship)"));
8197
+ console.log(import_chalk27.default.dim("\n(no work-logs for this relationship)"));
8174
8198
  return;
8175
8199
  }
8176
8200
  console.log("");
@@ -8187,36 +8211,36 @@ async function runWorkList(relationshipId, opts) {
8187
8211
  }));
8188
8212
  }
8189
8213
  const lastId = rows[rows.length - 1].id;
8190
- console.log(import_chalk29.default.dim(`
8214
+ console.log(import_chalk27.default.dim(`
8191
8215
  ${rows.length} work-log row(s). Paginate with --after ${lastId}.`));
8192
8216
  }
8193
8217
  function formatWorkLogLine(w, selfDid, opts = {}) {
8194
8218
  const delegationPart = opts.fullIds ? w.delegationId : idHead3(w.delegationId);
8195
8219
  const requestPart = opts.fullIds ? w.requestId : truncate3(w.requestId, 16);
8196
- const id = import_chalk29.default.bold(`${delegationPart}/${requestPart}`);
8220
+ const id = import_chalk27.default.bold(`${delegationPart}/${requestPart}`);
8197
8221
  const state = colorState3(w.state).padEnd(stateColumnWidth3());
8198
8222
  const peerCallerHead = opts.fullIds ? w.callerDid : didHead5(w.callerDid);
8199
8223
  const peerPayeeHead = opts.fullIds ? w.payeeDid : didHead5(w.payeeDid);
8200
- const direction = w.callerDid === selfDid ? `${import_chalk29.default.bold("me")} \u2192 ${import_chalk29.default.dim(peerPayeeHead)}` : `${import_chalk29.default.dim(peerCallerHead)} \u2192 ${import_chalk29.default.bold("me")}`;
8224
+ const direction = w.callerDid === selfDid ? `${import_chalk27.default.bold("me")} \u2192 ${import_chalk27.default.dim(peerPayeeHead)}` : `${import_chalk27.default.dim(peerCallerHead)} \u2192 ${import_chalk27.default.bold("me")}`;
8201
8225
  const outcome = formatOutcome(w);
8202
8226
  return `${id} ${state} ${direction} ${outcome}`;
8203
8227
  }
8204
8228
  function colorState3(s) {
8205
8229
  switch (s) {
8206
8230
  case "requested":
8207
- return import_chalk29.default.yellow("requested");
8231
+ return import_chalk27.default.yellow("requested");
8208
8232
  case "responded":
8209
- return import_chalk29.default.green("responded");
8233
+ return import_chalk27.default.green("responded");
8210
8234
  }
8211
8235
  }
8212
8236
  function stateColumnWidth3() {
8213
8237
  return 9;
8214
8238
  }
8215
8239
  function formatOutcome(w) {
8216
- if (w.state === "requested") return import_chalk29.default.dim("(in flight)");
8217
- if (w.responseError) return import_chalk29.default.red(`error ${w.responseError.code}: ${truncate3(w.responseError.message, 32)}`);
8218
- if (w.responseOutput) return import_chalk29.default.cyan("ok");
8219
- return import_chalk29.default.dim("(empty response)");
8240
+ if (w.state === "requested") return import_chalk27.default.dim("(in flight)");
8241
+ if (w.responseError) return import_chalk27.default.red(`error ${w.responseError.code}: ${truncate3(w.responseError.message, 32)}`);
8242
+ if (w.responseOutput) return import_chalk27.default.cyan("ok");
8243
+ return import_chalk27.default.dim("(empty response)");
8220
8244
  }
8221
8245
  function idHead3(id) {
8222
8246
  if (id.length <= 12) return id;
@@ -8279,10 +8303,8 @@ async function main() {
8279
8303
  registerDidDocCommand(program);
8280
8304
  registerDoctorCommand(program);
8281
8305
  registerEscrowCommands(program);
8282
- registerExamplesCommand(program);
8283
8306
  registerWhoamiCommand(program);
8284
8307
  registerLifecycleCommands(program);
8285
- registerRotateCommand(program);
8286
8308
  registerSendHandshakeCommand(program);
8287
8309
  registerSendHandshakeResponseCommand(program);
8288
8310
  registerInboxCommand(program);