@heyanon-arp/cli 0.0.8 → 0.0.10

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
@@ -643,6 +643,22 @@ function formatGenericError(err, verbose = false) {
643
643
  return `${import_chalk.default.red("Error")} ${message}
644
644
  ${import_chalk.default.gray(err.stack)}`;
645
645
  }
646
+ function onboardingHelpFooter() {
647
+ return [
648
+ "",
649
+ "New here? The guides ship inside the CLI \u2014 read them first, no docs site needed:",
650
+ ` ${import_chalk.default.cyan("heyarp guide")} ${import_chalk.default.dim("role-based walkthrough (worker / buyer)")}`,
651
+ ` ${import_chalk.default.cyan("heyarp guide --setup")} ${import_chalk.default.dim("one-time setup: keys, server, multi-agent isolation")}`,
652
+ ` ${import_chalk.default.cyan("heyarp guide --troubleshoot")} ${import_chalk.default.dim("common errors \u2192 fixes")}`,
653
+ "",
654
+ `${import_chalk.default.bold("Driving heyarp from an AI agent?")} Pipe YOUR role's guide into its system prompt`,
655
+ import_chalk.default.dim("(role is per-deal: BUYER if you send the offer + pay; WORKER if an offer comes to you):"),
656
+ ` ${import_chalk.default.cyan("heyarp guide --role worker --format prompt")} ${import_chalk.default.dim("# you do tasks, get paid")}`,
657
+ ` ${import_chalk.default.cyan("heyarp guide --role buyer --format prompt")} ${import_chalk.default.dim("# you order tasks, pay")}`,
658
+ "",
659
+ `${import_chalk.default.dim("Then:")} ${import_chalk.default.cyan("heyarp register")} ${import_chalk.default.dim("\u2192 handshake \u2192 delegation \u2192 work \u2192 receipt \u2192 settlement.")}`
660
+ ].join("\n");
661
+ }
646
662
  function toCliErrorJson(err, includeStack = false) {
647
663
  const { ApiError: ApiError2 } = (init_api(), __toCommonJS(api_exports));
648
664
  if (err instanceof ApiError2) {
@@ -3547,9 +3563,15 @@ async function readOnChainLock(api, opts, delegationId) {
3547
3563
  const programId = new import_web33.PublicKey(resolved.programId);
3548
3564
  const { lockPda } = deriveLockPda(programId, delegationId);
3549
3565
  const conn = new import_web33.Connection(rpcUrl, "confirmed");
3550
- const info = await conn.getAccountInfo(lockPda);
3566
+ let info = await conn.getAccountInfo(lockPda);
3567
+ for (let attempt = 1; attempt <= LOCK_READ_NOT_VISIBLE_RETRIES && !info; attempt++) {
3568
+ await new Promise((r) => setTimeout(r, LOCK_READ_RETRY_DELAY_MS));
3569
+ info = await conn.getAccountInfo(lockPda);
3570
+ }
3551
3571
  if (!info) {
3552
- return { skipReason: `lock account ${lockPda.toBase58()} not visible on this RPC yet (create_lock may still be confirming)` };
3572
+ return {
3573
+ skipReason: `lock account ${lockPda.toBase58()} not visible on this RPC yet after ${LOCK_READ_NOT_VISIBLE_RETRIES + 1} attempts (create_lock may still be confirming / RPC lag)`
3574
+ };
3553
3575
  }
3554
3576
  const lock = decodeLockAccount(info.data);
3555
3577
  if (!lock) {
@@ -3832,7 +3854,7 @@ async function autoSignAndDeliverPayeeSig(opts, cmdName = "receipt propose") {
3832
3854
  serverTimestamp: result.serverTimestamp
3833
3855
  };
3834
3856
  }
3835
- var import_sdk10, import_utils3, import_web33, import_chalk17, NATIVE_SOL_MINT2, SETTLEMENT_MIN_EXPIRY_HEADROOM_SECS, SETTLEMENT_REFRESH_HEADROOM_SECS;
3857
+ var import_sdk10, import_utils3, import_web33, import_chalk17, NATIVE_SOL_MINT2, SETTLEMENT_MIN_EXPIRY_HEADROOM_SECS, SETTLEMENT_REFRESH_HEADROOM_SECS, LOCK_READ_NOT_VISIBLE_RETRIES, LOCK_READ_RETRY_DELAY_MS;
3836
3858
  var init_settlement = __esm({
3837
3859
  "src/commands/settlement.ts"() {
3838
3860
  import_sdk10 = require("@heyanon-arp/sdk");
@@ -3852,6 +3874,8 @@ var init_settlement = __esm({
3852
3874
  NATIVE_SOL_MINT2 = "11111111111111111111111111111111";
3853
3875
  SETTLEMENT_MIN_EXPIRY_HEADROOM_SECS = 120;
3854
3876
  SETTLEMENT_REFRESH_HEADROOM_SECS = 600;
3877
+ LOCK_READ_NOT_VISIBLE_RETRIES = 3;
3878
+ LOCK_READ_RETRY_DELAY_MS = 2e3;
3855
3879
  }
3856
3880
  });
3857
3881
 
@@ -3907,6 +3931,14 @@ function registerPropose(parent) {
3907
3931
  await runPropose(recipientDid, delegationId, requestHash, responseHash, opts);
3908
3932
  } catch (err) {
3909
3933
  emitActionError(err, cmd);
3934
+ if (!opts.json && err instanceof ApiError && err.payload.code === "RECEIPT_ALREADY_EXISTS") {
3935
+ console.error(
3936
+ import_chalk18.default.dim(
3937
+ ` This receipt already exists (a prior propose committed it). Do NOT re-propose \u2014 to (re)deliver the payee settlement signature, run:
3938
+ 'heyarp receipt send-payee-sig ${recipientDid} --delegation-id ${delegationId} --auto --cluster-tag ${opts.clusterTag ?? "<0|1>"}'`
3939
+ )
3940
+ );
3941
+ }
3910
3942
  process.exitCode = 1;
3911
3943
  }
3912
3944
  });
@@ -4054,7 +4086,12 @@ async function runPropose(recipientDid, delegationId, requestHashArg, responseHa
4054
4086
  json.settlement = {
4055
4087
  delivered: false,
4056
4088
  error: settlementError.message,
4057
- recovery: `heyarp receipt send-payee-sig ${recipientDid} --delegation-id ${delegationId} --receipt-event-hash ${result.serverEventHash} --sig-from-file <path> --expires-at <unix> (after signing with 'heyarp wallet sign-settlement-release')`
4089
+ // Authoritative recovery (SR-2/SR-3): re-sign + re-deliver via
4090
+ // --auto, which resolves condition_hash + the on-chain lock
4091
+ // snapshot itself — no hand-typed hashes, no sig file, no
4092
+ // lock_id/condition_hash trap. Do NOT re-run `receipt propose`
4093
+ // (the receipt already exists; a second propose is a duplicate).
4094
+ recovery: `heyarp receipt send-payee-sig ${recipientDid} --delegation-id ${delegationId} --auto --cluster-tag ${opts.clusterTag ?? "<0|1>"} (do NOT re-run 'receipt propose' \u2014 the receipt already exists, a second propose is rejected as a duplicate)`
4058
4095
  };
4059
4096
  } else if (settlementResult) {
4060
4097
  json.settlement = {
@@ -4079,14 +4116,9 @@ Receipt event hash: ${import_chalk18.default.cyan(result.serverEventHash)}`));
4079
4116
  if (settlementError) {
4080
4117
  console.error(import_chalk18.default.yellow("\nWARNING: receipt proposed, but the payee settlement signature was NOT delivered."));
4081
4118
  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:"));
4084
- console.error(
4085
- import_chalk18.default.dim(
4086
- ` 'heyarp wallet sign-settlement-release ... --write-to <path>' then
4087
- 'heyarp receipt send-payee-sig ${recipientDid} --delegation-id ${delegationId} --receipt-event-hash ${result.serverEventHash} --sig-from-file <path> --expires-at <unix>'`
4088
- )
4089
- );
4119
+ console.error(import_chalk18.default.dim(" The receipt stays committed \u2014 do NOT re-run `receipt propose` (the receipt already exists; a second propose is rejected as a duplicate)."));
4120
+ console.error(import_chalk18.default.dim(" Recover authoritatively \u2014 this resolves condition_hash + the on-chain lock snapshot for you (no manual hashes, no sig file):"));
4121
+ console.error(import_chalk18.default.dim(` 'heyarp receipt send-payee-sig ${recipientDid} --delegation-id ${delegationId} --auto --cluster-tag ${opts.clusterTag ?? "<0|1>"}'`));
4090
4122
  } else if (settlementResult?.delivered) {
4091
4123
  console.log(import_chalk18.default.green("\nPayee settlement signature signed + delivered (escrow)."));
4092
4124
  console.log(
@@ -4551,18 +4583,32 @@ async function runCosign(relationshipId, delegationId, requestHashArg, responseH
4551
4583
  }
4552
4584
  }
4553
4585
  function registerSendPayeeSig(parent) {
4554
- parent.command("send-payee-sig").description("Send the payee's settlement signature to the buyer via a settlement_signature envelope. Replaces /tmp/*.json coordination for cross-host escrow cycles.").argument("<recipient-did>", "Buyer DID (= caller / offerer of the parent delegation; the cycle sends the sig to the side that will cosign)").requiredOption("--delegation-id <id>", "Parent delegation UUID \u2014 must match what was passed to `heyarp wallet sign-settlement-release`.").requiredOption(
4586
+ parent.command("send-payee-sig").description(
4587
+ "Send the payee's settlement signature to the buyer via a settlement_signature envelope. Replaces /tmp/*.json coordination for cross-host escrow cycles. Two modes: (1) MANUAL \u2014 supply --receipt-event-hash + --sig-from-file + --expires-at from a prior `wallet sign-settlement-release`; (2) --auto (RECOMMENDED for recovery) \u2014 resolves condition_hash + the on-chain lock snapshot AUTHORITATIVELY and re-signs (force), so you pass NO --sig-from-file and NO hand-typed hashes. Use --auto to recover when `receipt propose` did not deliver the sig (e.g. the just-confirmed lock was not yet RPC-visible); do NOT re-run `receipt propose` (the receipt already exists \u2014 a second propose is rejected as a duplicate)."
4588
+ ).argument(
4589
+ "[recipient-did]",
4590
+ "Buyer DID (= caller / offerer of the parent delegation; the cycle sends the sig to the side that will cosign). Optional under --auto \u2014 the buyer is resolved from the delegation/receipt."
4591
+ ).requiredOption("--delegation-id <id>", "Parent delegation UUID \u2014 must match what was passed to `heyarp wallet sign-settlement-release`.").option(
4592
+ "--auto",
4593
+ "Authoritative recovery: resolve condition_hash (over the delegation terms) + the on-chain lock snapshot (mint / amount / expiry / fee) and re-sign the release digest (force), then deliver it. Use this to recover when `receipt propose` did not deliver the sig \u2014 you do NOT pass --sig-from-file or --receipt-event-hash with --auto, and there is no lock_id/condition_hash trap. Requires --cluster-tag; mutually exclusive with --sig-from-file. Do NOT re-run `receipt propose` (the receipt already exists; a second propose is rejected as a duplicate)."
4594
+ ).option(
4595
+ "--cluster-tag <0|1>",
4596
+ "REQUIRED under --auto: 0 = devnet, 1 = mainnet-beta. Binds the cluster into the signed release digest (no safe default; a wrong cluster fails at the buyer cosign)."
4597
+ ).option(
4598
+ "--rpc-url <url>",
4599
+ "Solana RPC endpoint for the --auto on-chain lock read (resolves mint / amount / expiry / fee). Falls back to ARP_ESCROW_RPC_URL then `heyarp config get rpcUrl`; when none is set the on-chain check is skipped and the server stays the boundary."
4600
+ ).option("--program-id <pubkey>", "Escrow program id for the --auto on-chain lock read (auto-discovered from the server when omitted).").option("--rel-id <id>", "Relationship UUID \u2014 under --auto, auto-derived from the delegation when omitted.").option(
4555
4601
  "--receipt-event-hash <sha256:hex>",
4556
- "Server-assigned `serverEventHash` of the receipt-propose envelope this signature settles. Read it from the JSON response of `heyarp receipt propose` (the field is `Server event hash` in human output, or `.serverEventHash` in --json). MUST equal the value the digest was signed over \u2014 the server cross-checks against `Receipt.receiptEventHash` and rejects with SETTLEMENT_SIG_RECEIPT_NOT_FOUND otherwise."
4557
- ).requiredOption(
4602
+ "MANUAL path: server-assigned `serverEventHash` of the receipt-propose envelope this signature settles. Read it from the JSON response of `heyarp receipt propose` (the field is `Server event hash` in human output, or `.serverEventHash` in --json). MUST equal the value the digest was signed over \u2014 the server cross-checks against `Receipt.receiptEventHash` and rejects with SETTLEMENT_SIG_RECEIPT_NOT_FOUND otherwise. NOT needed with --auto (the helper resolves the receipt; pass it only to disambiguate >1 proposed receipt)."
4603
+ ).option(
4558
4604
  "--sig-from-file <path>",
4559
- "JSON file produced by `heyarp wallet sign-settlement-release --write-to <path>`. Reads `{settlement_pubkey, sig, purpose, digest_hex}` \u2014 the digest_hex is bound through for cross-file consistency (catches truncated or hand-edited files)."
4560
- ).requiredOption(
4605
+ "MANUAL path: JSON file produced by `heyarp wallet sign-settlement-release --write-to <path>`. Reads `{settlement_pubkey, sig, purpose, digest_hex}` \u2014 the digest_hex is bound through for cross-file consistency (catches truncated or hand-edited files). MUTUALLY EXCLUSIVE with --auto."
4606
+ ).option(
4561
4607
  "--expires-at <unix>",
4562
- "Unix-seconds expires_at value baked into the signed digest \u2014 MUST match the value passed to `--expires-at` on `heyarp wallet sign-settlement-release`. Server cross-checks against the buyer-side value at cosign time; wrong value \u2192 ESC_SETTLEMENT_EXPIRES_AT_PAST/_TOO_SOON."
4608
+ "MANUAL path: unix-seconds expires_at value baked into the signed digest \u2014 MUST match the value passed to `--expires-at` on `heyarp wallet sign-settlement-release`. Server cross-checks against the buyer-side value at cosign time; wrong value \u2192 ESC_SETTLEMENT_EXPIRES_AT_PAST/_TOO_SOON. Under --auto this is optional (derived from the delegation deadline; pass it only to override)."
4563
4609
  ).option(
4564
4610
  "--payee-amount <int>",
4565
- "Base-unit decimal-integer payee_amount \u2014 REQUIRED when the sig file's purpose is `ARP-SOLANA-PARTIAL-RELEASE-v1.5` (usage_based delegations). Same value passed to `--partial-payee-amount` on sign-settlement-release. FORBIDDEN for `ARP-SOLANA-RELEASE-v1.5` (full release settles the whole lock)."
4611
+ "Base-unit decimal-integer payee_amount \u2014 REQUIRED on the MANUAL path when the sig file's purpose is `ARP-SOLANA-PARTIAL-RELEASE-v1.5` (usage_based delegations). Same value passed to `--partial-payee-amount` on sign-settlement-release. FORBIDDEN for `ARP-SOLANA-RELEASE-v1.5` (full release settles the whole lock). Under --auto the partial amount is bound from the receipt; pass it only as a confirmation that must match."
4566
4612
  ).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 (= payee)").option("--ttl <seconds>", "Envelope TTL in seconds", "3600").option("--verbose", "Print the full envelope before sending and the full server response", false).action(async (recipientDid, opts, cmd) => {
4567
4613
  try {
4568
4614
  await runSendPayeeSig(recipientDid, opts);
@@ -4574,20 +4620,85 @@ function registerSendPayeeSig(parent) {
4574
4620
  }
4575
4621
  async function runSendPayeeSig(recipientDid, opts) {
4576
4622
  const cmdName = "receipt send-payee-sig";
4623
+ if (opts.auto) {
4624
+ if (opts.sigFromFile !== void 0 && opts.sigFromFile !== "") {
4625
+ throw new Error(
4626
+ `${cmdName}: --auto and --sig-from-file are mutually exclusive. --auto re-signs the release digest AUTHORITATIVELY (it resolves condition_hash + the on-chain lock itself); a --sig-from-file is the MANUAL path's pre-signed input. Pick one: --auto for recovery, or the manual --sig-from-file + --receipt-event-hash + --expires-at trio.`
4627
+ );
4628
+ }
4629
+ if (opts.clusterTag === void 0 || opts.clusterTag === "") {
4630
+ throw new Error(
4631
+ `${cmdName}: --cluster-tag is required with --auto (0 = devnet, 1 = mainnet-beta). It binds the cluster into the signed release digest; there is no safe default \u2014 pass the cluster where the create_lock lives.`
4632
+ );
4633
+ }
4634
+ if (opts.clusterTag !== "0" && opts.clusterTag !== "1") {
4635
+ throw new Error(`${cmdName}: --cluster-tag must be '0' (devnet) or '1' (mainnet-beta), got '${opts.clusterTag}'`);
4636
+ }
4637
+ const delegationIdAuto = requireUuidNormalised2(cmdName, opts.delegationId, "--delegation-id");
4638
+ if (recipientDid !== void 0 && recipientDid !== "") {
4639
+ requireDid2(cmdName, recipientDid, "[recipient-did]");
4640
+ }
4641
+ const { autoSignAndDeliverPayeeSig: autoSignAndDeliverPayeeSig2 } = await Promise.resolve().then(() => (init_settlement(), settlement_exports));
4642
+ await autoSignAndDeliverPayeeSig2(
4643
+ {
4644
+ server: opts.server,
4645
+ fromDid: opts.fromDid,
4646
+ delegationId: delegationIdAuto,
4647
+ ...opts.relId !== void 0 ? { relId: opts.relId } : {},
4648
+ clusterTag: opts.clusterTag,
4649
+ ...opts.expiresAt !== void 0 ? { expiresAt: opts.expiresAt } : {},
4650
+ ...opts.rpcUrl !== void 0 ? { rpcUrl: opts.rpcUrl } : {},
4651
+ ...opts.programId !== void 0 ? { programId: opts.programId } : {},
4652
+ ...opts.payeeAmount !== void 0 ? { partialPayeeAmount: opts.payeeAmount } : {},
4653
+ ...opts.receiptEventHash !== void 0 ? { receiptEventHash: opts.receiptEventHash } : {},
4654
+ // Recovery semantics: re-sign + re-deliver even if a (bad) sig
4655
+ // already exists. The helper short-circuits a cosigned receipt.
4656
+ force: true
4657
+ // `send-payee-sig` has no --json flag (the manual path prints a
4658
+ // plain human block); leave the helper in its human-output mode.
4659
+ // Do NOT pass silent — the helper owns + prints the recovery output.
4660
+ },
4661
+ cmdName
4662
+ );
4663
+ return;
4664
+ }
4665
+ if (recipientDid === void 0 || recipientDid === "") {
4666
+ throw new Error(
4667
+ `${cmdName}: <recipient-did> (the buyer DID) is required on the manual path. Pass it, or use --auto --cluster-tag <0|1> to resolve the buyer + re-sign authoritatively.`
4668
+ );
4669
+ }
4577
4670
  requireDid2(cmdName, recipientDid, "<recipient-did>");
4671
+ const recipient = recipientDid;
4578
4672
  const delegationId = requireUuidNormalised2(cmdName, opts.delegationId, "--delegation-id");
4673
+ if (opts.sigFromFile === void 0 || opts.sigFromFile === "") {
4674
+ throw new Error(
4675
+ `${cmdName}: --sig-from-file is required (the MANUAL path's pre-signed input). For authoritative recovery without a sig file, use --auto --cluster-tag <0|1> instead.`
4676
+ );
4677
+ }
4678
+ if (opts.receiptEventHash === void 0 || opts.receiptEventHash === "") {
4679
+ throw new Error(
4680
+ `${cmdName}: --receipt-event-hash is required on the manual path. For authoritative recovery without hand-typed hashes, use --auto --cluster-tag <0|1> instead.`
4681
+ );
4682
+ }
4683
+ if (opts.expiresAt === void 0 || opts.expiresAt === "") {
4684
+ throw new Error(
4685
+ `${cmdName}: --expires-at is required on the manual path (must match the value signed). For authoritative recovery, use --auto --cluster-tag <0|1> instead.`
4686
+ );
4687
+ }
4579
4688
  requireSha256(cmdName, opts.receiptEventHash, "--receipt-event-hash");
4689
+ const receiptEventHash = opts.receiptEventHash;
4690
+ const sigFromFile = opts.sigFromFile;
4580
4691
  const expiresAtSeconds = parseInteger(cmdName, "--expires-at", opts.expiresAt);
4581
4692
  if (expiresAtSeconds <= 0) {
4582
4693
  throw new Error(`${cmdName}: --expires-at must be a positive unix-seconds integer (got ${opts.expiresAt})`);
4583
4694
  }
4584
4695
  const ttlSeconds = parseTtl2(cmdName, opts.ttl);
4585
- const sigFile = loadSettlementSigFromFile(opts.sigFromFile, "--sig-from-file");
4696
+ const sigFile = loadSettlementSigFromFile(sigFromFile, "--sig-from-file");
4586
4697
  const isPartial = sigFile.purpose === "ARP-SOLANA-PARTIAL-RELEASE-v1.5";
4587
4698
  const isFull = sigFile.purpose === "ARP-SOLANA-RELEASE-v1.5";
4588
4699
  if (!isPartial && !isFull) {
4589
4700
  throw new Error(
4590
- `${cmdName}: sig file at '${opts.sigFromFile}' has purpose='${sigFile.purpose}' but only ARP-SOLANA-RELEASE-v1.5 and ARP-SOLANA-PARTIAL-RELEASE-v1.5 are valid on a settlement_signature envelope. (REFUND-v1 sigs ride other paths \u2014 they don't bind to receipt_event_hash, so this envelope isn't the right channel for them.)`
4701
+ `${cmdName}: sig file at '${sigFromFile}' has purpose='${sigFile.purpose}' but only ARP-SOLANA-RELEASE-v1.5 and ARP-SOLANA-PARTIAL-RELEASE-v1.5 are valid on a settlement_signature envelope. (REFUND-v1 sigs ride other paths \u2014 they don't bind to receipt_event_hash, so this envelope isn't the right channel for them.)`
4591
4702
  );
4592
4703
  }
4593
4704
  if (isPartial && (opts.payeeAmount === void 0 || opts.payeeAmount === "")) {
@@ -4609,7 +4720,7 @@ async function runSendPayeeSig(recipientDid, opts) {
4609
4720
  const api = new ArpApiClient(opts.server);
4610
4721
  const content = {
4611
4722
  delegation_id: delegationId,
4612
- receipt_event_hash: opts.receiptEventHash,
4723
+ receipt_event_hash: receiptEventHash,
4613
4724
  purpose: sigFile.purpose,
4614
4725
  payee_settlement_pubkey: sigFile.settlement_pubkey,
4615
4726
  sig: sigFile.sig,
@@ -4618,9 +4729,9 @@ async function runSendPayeeSig(recipientDid, opts) {
4618
4729
  };
4619
4730
  console.log(import_chalk18.default.dim(`Server: ${api.serverUrl}`));
4620
4731
  console.log(import_chalk18.default.dim(`Sender (payee): ${sender.did}`));
4621
- console.log(import_chalk18.default.dim(`Recipient (buyer): ${recipientDid}`));
4732
+ console.log(import_chalk18.default.dim(`Recipient (buyer): ${recipient}`));
4622
4733
  console.log(import_chalk18.default.dim(`Delegation: ${delegationId}`));
4623
- console.log(import_chalk18.default.dim(`Receipt event hash: ${opts.receiptEventHash}`));
4734
+ console.log(import_chalk18.default.dim(`Receipt event hash: ${receiptEventHash}`));
4624
4735
  console.log(import_chalk18.default.dim(`Purpose: ${sigFile.purpose}`));
4625
4736
  if (isPartial) {
4626
4737
  console.log(import_chalk18.default.dim(`Payee amount: ${opts.payeeAmount}`));
@@ -4630,7 +4741,7 @@ async function runSendPayeeSig(recipientDid, opts) {
4630
4741
  const result = await sendSettlementSignatureEnvelope({
4631
4742
  api,
4632
4743
  sender,
4633
- recipientDid,
4744
+ recipientDid: recipient,
4634
4745
  content,
4635
4746
  ttlSeconds,
4636
4747
  verbose: opts.verbose,
@@ -4934,7 +5045,7 @@ var import_simple_update_notifier = __toESM(require("simple-update-notifier"));
4934
5045
  // package.json
4935
5046
  var package_default = {
4936
5047
  name: "@heyanon-arp/cli",
4937
- version: "0.0.8",
5048
+ version: "0.0.10",
4938
5049
  description: "Command-line client for the Agent Relationship Protocol \u2014 register agents, sign envelopes, run escrowed work cycles on Solana.",
4939
5050
  license: "MIT",
4940
5051
  keywords: ["arp", "agent-relationship-protocol", "did", "solana", "escrow", "ed25519", "agents", "a2a", "cli"],
@@ -4944,7 +5055,7 @@ var package_default = {
4944
5055
  publishConfig: {
4945
5056
  access: "public"
4946
5057
  },
4947
- files: ["dist", "scripts/postinstall.mjs", "LICENSE", "README.md"],
5058
+ files: ["dist", "LICENSE", "README.md"],
4948
5059
  engines: {
4949
5060
  node: ">=22"
4950
5061
  },
@@ -4954,8 +5065,7 @@ var package_default = {
4954
5065
  test: "jest --runInBand --detectOpenHandles --forceExit --passWithNoTests",
4955
5066
  lint: "biome check . --write",
4956
5067
  prepublishOnly: "pnpm run build",
4957
- prepare: "pnpm run build",
4958
- postinstall: "node scripts/postinstall.mjs"
5068
+ prepare: "pnpm run build"
4959
5069
  },
4960
5070
  dependencies: {
4961
5071
  "@heyanon-arp/sdk": "workspace:*",
@@ -5820,7 +5930,7 @@ var GUIDE_SECTIONS = [
5820
5930
  { when: "a `work_request` arrives", then: "do the task, then `heyarp work respond <rel-id> <del-id> <req-id> --output '<json>'`" },
5821
5931
  {
5822
5932
  when: "your `work respond` is sent",
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."
5933
+ 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 (e.g. the just-confirmed lock was not yet RPC-visible), recover AUTHORITATIVELY with `heyarp receipt send-payee-sig <buyer-did> --delegation-id <del-id> --auto --cluster-tag <0|1>` \u2014 it resolves condition_hash + the on-chain lock snapshot itself, so you hand-type NO hashes and supply NO sig file. Do NOT re-run `receipt propose` (the receipt already exists; a second propose is rejected as a duplicate)."
5824
5934
  },
5825
5935
  { when: "the buyer cosigns (cycle released)", then: "you are paid \u2014 the cycle is done; wait for the next offer" }
5826
5936
  ],
@@ -6016,7 +6126,17 @@ var GUIDE_SECTIONS = [
6016
6126
  " `heyarp wallet sign-settlement-release` signs the release / partial",
6017
6127
  " digest. Output `sig` is RAW base64 (NO `ed25519:` prefix). Pass",
6018
6128
  " `--partial-payee-amount <lamports>` to switch the digest to",
6019
- " `ARP-SOLANA-PARTIAL-RELEASE-v1.5`.",
6129
+ " `ARP-SOLANA-PARTIAL-RELEASE-v1.5`. WARNING: `--condition-hash` here is",
6130
+ " the SAME value `heyarp escrow derive-condition-hash` produces (the hash",
6131
+ " OVER THE TERMS) / the condition_hash on the on-chain lock \u2014 it is NOT",
6132
+ " the `lock_id` from `delegation.fund` attachments. lock_id",
6133
+ ' (`sha256("arp-lock-v1"||delegation_id)`) and condition_hash',
6134
+ " (`sha256(terms)`) are DIFFERENT 32-byte values; the release digest binds",
6135
+ " condition_hash, so passing lock_id signs a digest the buyer cosign",
6136
+ " rejects (ESC_SETTLEMENT_SIG_INVALID). For the payee side, prefer",
6137
+ " `heyarp receipt send-payee-sig <buyer> --delegation-id <id> --auto`,",
6138
+ " which resolves condition_hash + the on-chain lock for you instead of",
6139
+ " hand-signing.",
6020
6140
  " `heyarp receipt cosign` attaches both parties' signatures into",
6021
6141
  " `attachments.settlement_signatures` via --settlement-purpose,",
6022
6142
  " --settlement-expires-at, --payer-settlement-{pubkey,sig},",
@@ -6231,6 +6351,13 @@ var GUIDE_SECTIONS = [
6231
6351
  " account for that mint exists.",
6232
6352
  " \u2022 handshake stuck `pending` / delegation stuck `offered` \u2192 the COUNTERPARTY",
6233
6353
  " has not acted; block on it with `heyarp status <rel-id> --wait --until <state>`.",
6354
+ " \u2022 `ESC_SETTLEMENT_SIG_INVALID` at `receipt cosign` \u2192 the payee signed the",
6355
+ " WRONG release digest \u2014 usually `--condition-hash` was set to the `lock_id`",
6356
+ " from a `delegation.fund` attachment (lock_id \u2260 condition_hash; the digest",
6357
+ " binds condition_hash). The payee re-delivers a correct sig with `heyarp",
6358
+ " receipt send-payee-sig <buyer> --delegation-id <id> --auto --cluster-tag",
6359
+ " <0|1>`, which resolves condition_hash from the on-chain lock (no manual",
6360
+ " hashes). Do NOT re-run `receipt propose` (the receipt already exists).",
6234
6361
  ' \u2022 "wrong move for my role" \u2192 you mixed up buyer vs worker; role is',
6235
6362
  ' PER-RELATIONSHIP \u2014 re-check with `heyarp guide` ("Which role am I?").',
6236
6363
  " More: README at https://www.npmjs.com/package/@heyanon-arp/cli"
@@ -7069,13 +7196,11 @@ async function runRegister(opts, deps = defaultRegisterDeps) {
7069
7196
  });
7070
7197
  const settlementPublicKeyB58 = (0, import_sdk12.base58btcEncode)(keys.settlementPublicKey);
7071
7198
  const scryptSaltId = (0, import_sdk12.uuidV4)();
7072
- const ownerId = (0, import_sdk12.uuidV4)();
7073
7199
  const payload = {
7074
7200
  purpose: "ARP-KEY-LINK-v1",
7075
7201
  agent_did: did,
7076
7202
  identity_public_key: identityPublicKeyB58,
7077
7203
  settlement_public_key: settlementPublicKeyB58,
7078
- owner_id: ownerId,
7079
7204
  owner_signing_method: "scrypt_password_proof",
7080
7205
  link_method: "manual",
7081
7206
  created_at: (0, import_sdk12.rfc3339)(),
@@ -7108,7 +7233,6 @@ async function runRegister(opts, deps = defaultRegisterDeps) {
7108
7233
  scryptKeyB64: Buffer.from(scryptKey).toString("base64"),
7109
7234
  scryptSaltB64: Buffer.from(scryptSalt).toString("base64"),
7110
7235
  scryptSaltId,
7111
- ownerId,
7112
7236
  // Placeholder until the server confirms registration and returns
7113
7237
  // the canonical attestation id (finalized in Step 8 below).
7114
7238
  currentAttestationId: "",
@@ -8293,6 +8417,7 @@ async function main() {
8293
8417
  process.stderr.write(str);
8294
8418
  }
8295
8419
  });
8420
+ program.addHelpText("after", () => onboardingHelpFooter());
8296
8421
  registerConfigCommand(program);
8297
8422
  registerGuideCommand(program);
8298
8423
  registerHomesCommand(program);