@heyanon-arp/cli 0.0.15 → 0.0.16

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
@@ -34,10 +34,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
34
34
  function arpHomeDir() {
35
35
  const fromEnv = process.env.HEYARP_HOME;
36
36
  if (fromEnv && fromEnv.length > 0) return fromEnv;
37
- return (0, import_node_path.join)((0, import_node_os.homedir)(), ".arp");
37
+ return (0, import_node_path.join)((0, import_node_os.homedir)(), ".heyarp");
38
38
  }
39
39
  function homesRegistryPath() {
40
- return (0, import_node_path.join)((0, import_node_os.homedir)(), ".arp", "homes.json");
40
+ return (0, import_node_path.join)((0, import_node_os.homedir)(), ".heyarp", "homes.json");
41
41
  }
42
42
  var import_node_os, import_node_path;
43
43
  var init_paths = __esm({
@@ -354,9 +354,8 @@ var init_api = __esm({
354
354
  }
355
355
  /**
356
356
  * Signed-request authenticated GET /v1/agents/:did. Owner-only on
357
- * the server side, but in V1 it returns the same shape as
358
- * /did-document — useful as a sanity check that a stored secret
359
- * key still verifies.
357
+ * the server side; it returns the same shape as /did-document —
358
+ * useful as a sanity check that a stored secret key still verifies.
360
359
  */
361
360
  async getAgent(did, signer) {
362
361
  return this.signedRequest("GET", `/v1/agents/${encodeURIComponent(did)}`, null, signer);
@@ -723,17 +722,17 @@ var import_simple_update_notifier = __toESM(require("simple-update-notifier"));
723
722
  // package.json
724
723
  var package_default = {
725
724
  name: "@heyanon-arp/cli",
726
- version: "0.0.15",
725
+ version: "0.0.16",
727
726
  description: "Command-line client for the Agent Relationship Protocol \u2014 register agents, sign envelopes, run escrowed work cycles on Solana.",
728
727
  license: "MIT",
729
728
  keywords: ["arp", "agent-relationship-protocol", "did", "solana", "escrow", "ed25519", "agents", "a2a", "cli"],
730
729
  bin: {
731
- heyarp: "./dist/cli.js"
730
+ heyarp: "./bin/heyarp.cjs"
732
731
  },
733
732
  publishConfig: {
734
733
  access: "public"
735
734
  },
736
- files: ["dist", "LICENSE", "README.md"],
735
+ files: ["dist", "bin", "LICENSE", "README.md"],
737
736
  engines: {
738
737
  node: ">=22"
739
738
  },
@@ -1564,7 +1563,7 @@ var import_chalk6 = __toESM(require("chalk"));
1564
1563
  init_api();
1565
1564
  init_config();
1566
1565
  function registerConfigCommand(root) {
1567
- const config = root.command("config").description("Read/write persistent CLI configuration (~/.arp/config.json)").option("--server <url>", "Override the server URL whose bucket per-server keys (e.g. defaultDid) read/write to");
1566
+ const config = root.command("config").description("Read/write persistent CLI configuration (~/.heyarp/config.json)").option("--server <url>", "Override the server URL whose bucket per-server keys (e.g. defaultDid) read/write to");
1568
1567
  config.command("set <key> <value>").description(`Persist a config value. Global keys: ${GLOBAL_CONFIG_KEYS.join(", ")}. Per-server keys: ${SERVER_CONFIG_KEYS.join(", ")}`).action((key, value) => {
1569
1568
  const opts = config.opts();
1570
1569
  if (isGlobalConfigKey(key)) {
@@ -1686,7 +1685,7 @@ var import_sdk4 = require("@heyanon-arp/sdk");
1686
1685
  var import_chalk7 = __toESM(require("chalk"));
1687
1686
  init_api();
1688
1687
  var UNTIL_PHASES = [
1689
- "delegation.proposed",
1688
+ "delegation.offered",
1690
1689
  "delegation.accepted",
1691
1690
  "delegation.locked",
1692
1691
  "delegation.disputing",
@@ -1695,7 +1694,6 @@ var UNTIL_PHASES = [
1695
1694
  "work.requested",
1696
1695
  "work.responded",
1697
1696
  "receipt.proposed",
1698
- "receipt.cosigned",
1699
1697
  "relationship.pending",
1700
1698
  "relationship.active",
1701
1699
  "relationship.paused",
@@ -1931,8 +1929,8 @@ function isPhaseTerminallyUnreachable(phase, s) {
1931
1929
  }
1932
1930
  function untilPhaseMatched(phase, s) {
1933
1931
  switch (phase) {
1934
- case "delegation.proposed":
1935
- return s.latestDelegation?.state === "proposed" || s.latestDelegation?.state === "offered";
1932
+ case "delegation.offered":
1933
+ return s.latestDelegation?.state === "offered";
1936
1934
  case "delegation.accepted":
1937
1935
  return s.latestDelegation?.state === "accepted";
1938
1936
  case "delegation.locked":
@@ -1948,9 +1946,7 @@ function untilPhaseMatched(phase, s) {
1948
1946
  case "work.responded":
1949
1947
  return s.latestWorkLog?.state === "responded";
1950
1948
  case "receipt.proposed":
1951
- return s.latestReceipt?.state === "proposed";
1952
- case "receipt.cosigned":
1953
- return s.latestReceipt?.state === "cosigned";
1949
+ return s.latestReceipt != null;
1954
1950
  case "relationship.pending":
1955
1951
  return s.relationshipState === "pending";
1956
1952
  case "relationship.active":
@@ -2013,7 +2009,7 @@ async function composeStatus(api, signerDid, relationshipId, signer) {
2013
2009
  const relationship = relationships.find((r) => r.relationshipId === relationshipId);
2014
2010
  const counterpartyDid = relationship ? relationship.pairDidA === signerDid ? relationship.pairDidB : relationship.pairDidA : inferCounterpartyFromEntities(signerDid, allDelegations);
2015
2011
  const delegations = allDelegations;
2016
- const latestDelegation = pickLatestLive(delegations, ["proposed", "offered", "accepted", "pending_lock_finalization", "locked"]);
2012
+ const latestDelegation = pickLatestLive(delegations, ["offered", "accepted", "pending_lock_finalization", "locked"]);
2017
2013
  const [workLogs, receipts] = await Promise.all([
2018
2014
  latestDelegation ? fetchAllPages(
2019
2015
  (after) => api.listWorkLogs(relationshipId, signer, { limit: 100, delegationId: latestDelegation.delegationId, ...after ? { after } : {} })
@@ -2170,9 +2166,9 @@ function nextAction(input) {
2170
2166
  complete: false
2171
2167
  };
2172
2168
  }
2173
- if (latestDelegation.state === "proposed" || latestDelegation.state === "offered") {
2169
+ if (latestDelegation.state === "offered") {
2174
2170
  const iAmOfferer = latestDelegation.offererDid === signerDid;
2175
- const stateLabel = latestDelegation.state === "proposed" ? "PROPOSED" : `${latestDelegation.state.toUpperCase()} (\u2261 proposed)`;
2171
+ const stateLabel = "OFFERED";
2176
2172
  return {
2177
2173
  hint: iAmOfferer ? `Delegation ${latestDelegation.delegationId} is ${stateLabel} \u2014 counterparty owes \`heyarp delegation accept\` / \`decline\`` : `Delegation ${latestDelegation.delegationId} is ${stateLabel} \u2014 you owe \`heyarp delegation accept\` / \`decline\``,
2178
2174
  owner: iAmOfferer ? "counterparty" : "me",
@@ -2233,24 +2229,21 @@ function nextAction(input) {
2233
2229
  complete: false
2234
2230
  };
2235
2231
  }
2236
- if (latestReceipt.state === "proposed") {
2237
- const iAmCaller = latestReceipt.callerDid === signerDid;
2238
- return {
2239
- // V2: there is NO cosign — buyer consent is the on-chain
2240
- // claim_work_payment tx, worker recourse is the
2241
- // review-window self-claim.
2242
- hint: iAmCaller ? `Receipt PROPOSED \u2014 you (caller): review the deliverable and approve payment ON-CHAIN with \`heyarp escrow claim ${latestReceipt.delegationId}\` (irreversible release; \`heyarp escrow dispute open ${latestReceipt.delegationId}\` within the review window if the work is unacceptable)` : `Receipt PROPOSED \u2014 counterparty (the buyer) owes the on-chain approval (\`heyarp escrow claim\`); once the review window lapses you may self-claim with \`heyarp escrow claim ${latestReceipt.delegationId}\``,
2243
- owner: iAmCaller ? "me" : "counterparty",
2244
- complete: false
2245
- };
2246
- }
2247
- return { hint: "Cycle COMPLETE \u2014 settlement recorded", owner: "none", complete: true };
2232
+ const iAmCaller = latestReceipt.callerDid === signerDid;
2233
+ return {
2234
+ // There is no cosign step — buyer consent is the on-chain
2235
+ // claim_work_payment tx, worker recourse is the
2236
+ // review-window self-claim.
2237
+ hint: iAmCaller ? `Receipt PROPOSED \u2014 you (caller): review the deliverable and approve payment ON-CHAIN with \`heyarp escrow claim ${latestReceipt.delegationId}\` (irreversible release; \`heyarp escrow dispute open ${latestReceipt.delegationId}\` within the review window if the work is unacceptable)` : `Receipt PROPOSED \u2014 counterparty (the buyer) owes the on-chain approval (\`heyarp escrow claim\`); once the review window lapses you may self-claim with \`heyarp escrow claim ${latestReceipt.delegationId}\``,
2238
+ owner: iAmCaller ? "me" : "counterparty",
2239
+ complete: false
2240
+ };
2248
2241
  }
2249
2242
  function formatPhaseSnapshot(s) {
2250
2243
  const parts = [];
2251
2244
  parts.push(`delegation=${s.latestDelegation?.state ?? "\u2205"}`);
2252
2245
  if (s.latestWorkLog) parts.push(`work=${s.latestWorkLog.state}`);
2253
- if (s.latestReceipt) parts.push(`receipt=${s.latestReceipt.state}`);
2246
+ if (s.latestReceipt) parts.push("receipt=proposed");
2254
2247
  return parts.join(", ");
2255
2248
  }
2256
2249
  function formatStatusReport(s) {
@@ -2280,7 +2273,7 @@ function formatStatusReport(s) {
2280
2273
  lines.push("");
2281
2274
  lines.push(import_chalk7.default.bold("Latest receipt"));
2282
2275
  if (s.latestReceipt) {
2283
- lines.push(` state=${stateColor(s.latestReceipt.state)} verdict=${s.latestReceipt.verdictFinal ?? s.latestReceipt.verdictProposed}`);
2276
+ lines.push(` ${stateColor("proposed")} verdict=${s.latestReceipt.verdictProposed}`);
2284
2277
  } else {
2285
2278
  lines.push(import_chalk7.default.dim(" (none)"));
2286
2279
  }
@@ -2294,7 +2287,7 @@ function formatStatusReport(s) {
2294
2287
  }
2295
2288
  function cycleHeadline(s) {
2296
2289
  if (s.cycleComplete) {
2297
- return `${import_chalk7.default.bold("Cycle:")} ${import_chalk7.default.green.bold("COMPLETE")} ${import_chalk7.default.dim("\u2014 receipt cosigned, payment proven on chain")}`;
2290
+ return `${import_chalk7.default.bold("Cycle:")} ${import_chalk7.default.green.bold("COMPLETE")} ${import_chalk7.default.dim("\u2014 payment proven on chain")}`;
2298
2291
  }
2299
2292
  switch (s.relationshipState) {
2300
2293
  case "not_found":
@@ -2313,7 +2306,7 @@ function cycleHeadline(s) {
2313
2306
  }
2314
2307
  }
2315
2308
  function stateColor(state) {
2316
- const c = state === "active" || state === "accepted" || state === "locked" || state === "cosigned" || state === "responded" || state === "completed" ? import_chalk7.default.green : state === "pending" || state === "proposed" || state === "requested" || state === "offered" || state === "pending_lock_finalization" ? import_chalk7.default.yellow : state === "closed" || state === "declined" || state === "canceled" || state === "replaced" || state === "not_found" || // Terminal failure states deserve the same red
2309
+ const c = state === "active" || state === "accepted" || state === "locked" || state === "responded" || state === "completed" ? import_chalk7.default.green : state === "pending" || state === "requested" || state === "offered" || state === "pending_lock_finalization" ? import_chalk7.default.yellow : state === "closed" || state === "declined" || state === "canceled" || state === "replaced" || state === "not_found" || // Terminal failure states deserve the same red
2317
2310
  // treatment as declined/canceled so an operator
2318
2311
  // scanning `heyarp status` immediately sees
2319
2312
  // "this is dead, don't follow the hint blindly".
@@ -2639,6 +2632,15 @@ function resolveRpcUrl(opts) {
2639
2632
  if (fromConfig !== void 0 && fromConfig.length > 0) return fromConfig;
2640
2633
  return FALLBACK_RPC_URL;
2641
2634
  }
2635
+ function redactRpcUrl(url) {
2636
+ try {
2637
+ const u = new URL(url);
2638
+ const hasSecret = u.pathname !== "" && u.pathname !== "/" || u.search !== "" || u.username !== "" || u.password !== "";
2639
+ return hasSecret ? `${u.protocol}//${u.host}/<redacted>` : url;
2640
+ } catch {
2641
+ return "<redacted>";
2642
+ }
2643
+ }
2642
2644
  var FALLBACK_PROGRAM_ID = "7trAdKybX4kMKARia9nrRPj9rBuUjDTxRzExzwFTvvXg";
2643
2645
  async function resolveProgramIdWithSource(api, opts) {
2644
2646
  if (opts.programId !== void 0 && opts.programId !== "") {
@@ -2699,10 +2701,7 @@ function registerDerivePdas(cmd) {
2699
2701
  ).requiredOption("--delegation-id <id>", "Delegation UUID (canonical `del_<uuid>` or bare `<uuid>` \u2014 both accepted)").option("--server <url>", "Override server URL (used only for --program-id auto-discovery)").option(
2700
2702
  "--program-id <pubkey>",
2701
2703
  "Deployed ARP escrow program id. Precedence: --program-id flag > ARP_ESCROW_PROGRAM_ID env > GET /v1/escrow/config (auto-discover). NO hardcoded fallback \u2014 wrong-program PDAs are silently wrong, so resolution failure is a loud error."
2702
- ).option("--rpc-url <url>", "Accepted for symmetry with `wallet verify-release` but never read \u2014 PDAs are derived locally from `program_id + delegation_id`; no RPC needed.").option(
2703
- "--recipient-pubkey <base58>",
2704
- "Accepted for symmetry with `wallet create-lock` but never read \u2014 PDAs depend ONLY on program_id + delegation_id; recipient pubkey has no derivation role."
2705
- ).option("--condition-hash <hex>", "Accepted for symmetry with `wallet create-lock` but never read \u2014 PDAs depend ONLY on program_id + delegation_id.").option("--amount-lamports <int>", "Accepted for symmetry with `wallet create-lock` but never read \u2014 PDAs depend ONLY on program_id + delegation_id.").option("--expiry-secs <int>", "Accepted for symmetry with `wallet create-lock` but never read \u2014 PDAs depend ONLY on program_id + delegation_id.").option("--json", "Emit JSON instead of human text (jq-pipeable: `.lock_pda`, `.escrow_pda`, `.config_pda`, `.lock_id_hex`).", false).action(async (opts) => {
2704
+ ).option("--json", "Emit JSON instead of human text (jq-pipeable: `.lock_pda`, `.escrow_pda`, `.config_pda`, `.lock_id_hex`).", false).action(async (opts) => {
2706
2705
  try {
2707
2706
  const out = await derivePdasHandler(opts);
2708
2707
  if (opts.json) {
@@ -2738,8 +2737,7 @@ async function derivePdasHandler(opts) {
2738
2737
  lock_id_hex: lockIdHex,
2739
2738
  program_id: programId.toBase58(),
2740
2739
  lock_pda: lockPda.toBase58(),
2741
- // Single escrow PDA replaces the V1.5 vault + vault_authority
2742
- // pair in the new contract.
2740
+ // Single escrow PDA at `[b"escrow", lock_id]`.
2743
2741
  escrow_pda: escrowPda.toBase58(),
2744
2742
  config_pda: configPda.toBase58(),
2745
2743
  event_authority_pda: eventAuthorityPda.toBase58()
@@ -2754,14 +2752,14 @@ var TERMINAL_METHOD = {
2754
2752
  };
2755
2753
  function registerVerifyRelease(cmd) {
2756
2754
  cmd.command("verify-release").description(
2757
- "Post-cycle on-chain assertion. Decodes the Lock account and reports the V2 state verdict: `released: true` IFF the lock is `paid` (the payee was paid via claim_work_payment); exits non-zero otherwise so `set -euo pipefail` scripts catch incomplete cycles. For the full decoded Lock use `heyarp escrow show`."
2755
+ "Post-cycle on-chain assertion. Decodes the Lock account and reports the state verdict: `released: true` IFF the lock is `paid` (the payee was paid via claim_work_payment); exits non-zero otherwise so `set -euo pipefail` scripts catch incomplete cycles. For the full decoded Lock use `heyarp escrow show`."
2758
2756
  ).requiredOption("--delegation-id <id>", "Delegation UUID (canonical `del_<uuid>` or bare `<uuid>` \u2014 both accepted)").option("--server <url>", "Override ARP server URL (used only for --program-id auto-discovery)").option(
2759
2757
  "--rpc-url <url>",
2760
2758
  "Solana RPC URL. STRICT: --rpc-url flag > ARP_ESCROW_RPC_URL env > `heyarp config set rpcUrl` > FAIL \u2014 a wrong-cluster read would silently report lock_never_created."
2761
2759
  ).option(
2762
2760
  "--program-id <pubkey>",
2763
2761
  "Deployed ARP escrow program id. STRICT: flag > ARP_ESCROW_PROGRAM_ID env > GET /v1/escrow/config > FAIL \u2014 a wrong-program read would silently report lock_never_created."
2764
- ).option("--no-sig-retry", "V1 leftover, tolerated no-op \u2014 V2 locks are never closed, so there is no signature-index race to retry around.").option("--json", "Emit JSON instead of human text. jq-pipeable.", false).action(async (opts) => {
2762
+ ).option("--from-did <did>", "Accepted for scripting symmetry with the signing commands; verify-release reads on-chain state only and needs no signer, so this is ignored.").option("--json", "Emit JSON instead of human text. jq-pipeable.", false).action(async (opts) => {
2765
2763
  try {
2766
2764
  const out = await verifyReleaseHandler(opts);
2767
2765
  if (opts.json) {
@@ -2790,9 +2788,6 @@ function registerVerifyRelease(cmd) {
2790
2788
  });
2791
2789
  }
2792
2790
  async function verifyReleaseHandler(opts) {
2793
- if (opts.noSigRetry) {
2794
- process.stderr.write("wallet verify-release: --no-sig-retry is a no-op on V2 (locks are never closed) \u2014 ignoring\n");
2795
- }
2796
2791
  const normalisedDelegationId = normaliseDelegationId(opts.delegationId);
2797
2792
  const api = new ArpApiClient(opts.server);
2798
2793
  const programId = new import_web32.PublicKey(await resolveProgramIdStrict(api, opts));
@@ -2810,7 +2805,7 @@ async function verifyReleaseHandler(opts) {
2810
2805
  lock_account_exists: false,
2811
2806
  released: false,
2812
2807
  status: "lock_never_created",
2813
- rpc_url: rpcUrl
2808
+ rpc_url: redactRpcUrl(rpcUrl)
2814
2809
  };
2815
2810
  }
2816
2811
  const lock = fetched.lock;
@@ -2854,14 +2849,11 @@ function renderStatusLine(status) {
2854
2849
  }
2855
2850
  function registerCreateLock(cmd) {
2856
2851
  cmd.command("create-lock").description(
2857
- "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."
2852
+ "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. 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."
2858
2853
  ).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(
2859
2854
  "--amount <decimal>",
2860
2855
  "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."
2861
2856
  ).requiredOption("--condition-hash <hex>", "32-byte hex condition_hash from `heyarp escrow derive-condition-hash` (binds the delegation terms)").option(
2862
- "--expiry-secs <int>",
2863
- "DEPRECATED no-op \u2014 V2 derives deadlines from the on-chain Config windows; the flag is tolerated so old scripts keep running and dies with the V2 builder rewrite."
2864
- ).option(
2865
2857
  "--rpc-url <url>",
2866
2858
  `Solana RPC URL. Default precedence: --rpc-url flag > ARP_ESCROW_RPC_URL env > \`heyarp config set rpcUrl\` > built-in fallback (${FALLBACK_RPC_URL}).`
2867
2859
  ).option(
@@ -3029,9 +3021,6 @@ async function createLockHandler(opts) {
3029
3021
  const normalisedDelegationId = normaliseDelegationId(opts.delegationId);
3030
3022
  const payee = parsePubkey(opts.recipientPubkey, "--recipient-pubkey");
3031
3023
  const conditionHash = parseHex32(opts.conditionHash, "--condition-hash");
3032
- if (opts.expirySecs !== void 0) {
3033
- process.stderr.write("wallet create-lock: --expiry-secs is a no-op on V2 (deadlines come from the on-chain Config windows) \u2014 ignoring\n");
3034
- }
3035
3024
  const api = new ArpApiClient(opts.server);
3036
3025
  const offlineMode = typeof opts.programId === "string" && opts.programId !== "" || typeof process.env.ARP_ESCROW_PROGRAM_ID === "string" && process.env.ARP_ESCROW_PROGRAM_ID !== "";
3037
3026
  const clusterTag = opts.clusterTag !== void 0 ? Number.parseInt(opts.clusterTag, 10) : 0;
@@ -3161,7 +3150,7 @@ var POST_COMMIT_ERROR_CODES = /* @__PURE__ */ new Set([
3161
3150
  // against a PENDING_LOCK delegation consumes sender_sequence
3162
3151
  // even though it rejects.
3163
3152
  "DELEGATION_PENDING_LOCK",
3164
- // M6 lock-at-accept: the `fund` body handler (`handleFund`) emits
3153
+ // The `fund` body handler (`handleFund`) emits
3165
3154
  // these AFTER the event row is committed (same lifecycle as
3166
3155
  // DELEGATION_INVALID_STATE). `DELEGATION_FUNDER_NOT_OFFERER` (403)
3167
3156
  // when a non-offerer attempts the fund; `DELEGATION_ALREADY_FUNDED`
@@ -3172,7 +3161,7 @@ var POST_COMMIT_ERROR_CODES = /* @__PURE__ */ new Set([
3172
3161
  // `ENV_SEQUENCE_BACKWARDS`.
3173
3162
  "DELEGATION_FUNDER_NOT_OFFERER",
3174
3163
  "DELEGATION_ALREADY_FUNDED",
3175
- // V1.5 lock-validator mint.owner pre-flight — kept here for
3164
+ // Lock-validator mint.owner pre-flight — kept here for
3176
3165
  // documentation, but the `isPostCommitErrorCode` helper below
3177
3166
  // also matches any `ESC_LOCK_*` prefix. The full lock-validator
3178
3167
  // cross-check set (ID_MISMATCH, CONDITION_HASH_MISMATCH,
@@ -3797,7 +3786,7 @@ async function awaitDelegationLockFinalized(cmdName, api, signer, args) {
3797
3786
  `${cmdName}: delegation ${args.delegationId} disappeared from relationship ${args.relationshipId} during --wait-for-lock pre-flight. Re-check the delegation id with \`heyarp delegations ${args.relationshipId}\`.`
3798
3787
  );
3799
3788
  }
3800
- if (row.state !== "offered" && row.state !== "proposed") {
3789
+ if (row.state !== "offered") {
3801
3790
  throw new Error(
3802
3791
  `${cmdName}: delegation ${args.delegationId} transitioned to '${row.state}' while waiting for on-chain lock confirmation; cannot ${args.action}. Re-read the delegation timeline with \`heyarp delegations ${args.relationshipId}\` to see the latest state.`
3803
3792
  );
@@ -4041,8 +4030,6 @@ function formatDelegationLine(d, selfDid, opts = {}) {
4041
4030
  }
4042
4031
  function colorState(s) {
4043
4032
  switch (s) {
4044
- case "proposed":
4045
- return import_chalk9.default.yellow("proposed");
4046
4033
  // `offered` is the server's actual emitted state immediately
4047
4034
  // after `delegation offer`; `pending_lock_finalization` is the
4048
4035
  // transient state while the relayer submits create_lock. Both
@@ -4056,16 +4043,16 @@ function colorState(s) {
4056
4043
  return import_chalk9.default.yellow("pending_lock");
4057
4044
  case "accepted":
4058
4045
  return import_chalk9.default.green("accepted");
4059
- // M6 lock-at-accept: the on-chain escrow lock is confirmed.
4060
- // Distinct branch so a LOCKED row renders without hitting the
4061
- // defensive fallback (which would otherwise echo the raw state).
4046
+ // The on-chain escrow lock is confirmed. Distinct branch so a
4047
+ // LOCKED row renders without hitting the defensive fallback
4048
+ // (which would otherwise echo the raw state).
4062
4049
  case "locked":
4063
4050
  return import_chalk9.default.green("locked");
4064
4051
  case "declined":
4065
4052
  return import_chalk9.default.red("declined");
4066
4053
  case "canceled":
4067
4054
  return import_chalk9.default.dim("canceled");
4068
- // Terminal escrow outcomes (V2): completed = payee paid;
4055
+ // Terminal escrow outcomes: completed = payee paid;
4069
4056
  // failed = create_lock never landed; refunded = funds returned
4070
4057
  // to the buyer (work expired / dispute closed);
4071
4058
  // dispute_resolved = operator ruled.
@@ -4503,7 +4490,7 @@ function emit(ctx, action, signature, extra = {}) {
4503
4490
  lock_id: ctx.lock.lockId,
4504
4491
  state_before: ctx.lock.state,
4505
4492
  signature,
4506
- rpc_url: ctx.rpcUrl,
4493
+ rpc_url: redactRpcUrl(ctx.rpcUrl),
4507
4494
  ...extra
4508
4495
  };
4509
4496
  if (ctx.opts.json) {
@@ -4695,7 +4682,12 @@ async function showHandler(delegationId, opts) {
4695
4682
  const normalised = normaliseDelegationId(delegationId);
4696
4683
  const fetched = await fetchLockAccount(conn, programId, normalised);
4697
4684
  if (!fetched) {
4698
- jsonOut({ delegation_id: normalised.slice("del_".length), lock_exists: false, lock_pda: deriveLockPda(programId, (0, import_sdk10.deriveLockId)(normalised)).toBase58(), rpc_url: rpcUrl });
4685
+ jsonOut({
4686
+ delegation_id: normalised.slice("del_".length),
4687
+ lock_exists: false,
4688
+ lock_pda: deriveLockPda(programId, (0, import_sdk10.deriveLockId)(normalised)).toBase58(),
4689
+ rpc_url: redactRpcUrl(rpcUrl)
4690
+ });
4699
4691
  return;
4700
4692
  }
4701
4693
  const l = fetched.lock;
@@ -4714,7 +4706,7 @@ async function showHandler(delegationId, opts) {
4714
4706
  fee_bps_at_lock: l.feeBpsAtLock,
4715
4707
  worker_stake_at_lock: l.workerStakeAtLock.toString(),
4716
4708
  operator_dispute_fee_at_lock: l.operatorDisputeFeeAtLock.toString(),
4717
- rpc_url: rpcUrl
4709
+ rpc_url: redactRpcUrl(rpcUrl)
4718
4710
  });
4719
4711
  }
4720
4712
  function sharedFlags(cmd) {
@@ -4949,7 +4941,7 @@ function registerEventsCommand(root) {
4949
4941
  false
4950
4942
  ).option(
4951
4943
  "--full-ids",
4952
- "Print eventId, DIDs and serverEventHash in full (no truncation). The eventId column in the default human row is truncated to `evt_<head>...<tail>` \u2014 pass --full-ids to read the full UUID for `heyarp envelope <evt-id>`. NOTE: `serverEventHash` is the hash-chain anchor, NOT the value `receipt propose / cosign` require \u2014 those want `requestHash` / `responseHash`, which are exposed by `heyarp receipts <rel-id> --full-ids`, or auto-derived via `receipt propose --auto-hashes --rel-id --request-id` / `receipt cosign --auto-hashes [--request-id]`.",
4944
+ "Print eventId, DIDs and serverEventHash in full (no truncation). The eventId column in the default human row is truncated to `evt_<head>...<tail>` \u2014 pass --full-ids to read the full UUID for `heyarp envelope <evt-id>`. NOTE: `serverEventHash` is the hash-chain anchor, NOT the value `receipt propose` requires \u2014 that wants `requestHash` / `responseHash`, which are exposed by `heyarp receipts <rel-id> --full-ids`, or auto-derived via `receipt propose --auto-hashes --rel-id --request-id`.",
4953
4945
  false
4954
4946
  ).option(
4955
4947
  "--success-only",
@@ -5001,8 +4993,7 @@ async function runEvents(relationshipId, opts) {
5001
4993
  printVerbose(events, "Full event envelopes:", (ev) => ({
5002
4994
  primary: `#${ev.relationshipEventIndex} ${ev.type ?? "<unknown>"}`,
5003
4995
  // Surface BOTH the full eventId (used by `heyarp envelope
5004
- // <evt-id>`) and the full serverEventHash (used by
5005
- // `receipt propose` / `receipt cosign`).
4996
+ // <evt-id>`) and the full serverEventHash.
5006
4997
  secondary: `eventId=${ev.eventId} serverEventHash=${ev.serverEventHash}`
5007
4998
  }));
5008
4999
  }
@@ -5310,7 +5301,7 @@ var GUIDE_SECTIONS = [
5310
5301
  title: "Identity",
5311
5302
  body: [
5312
5303
  " \u2022 Each agent has a `did:arp:<base58btc>` DID + an Ed25519 identity key.",
5313
- " \u2022 Keys live in `~/.arp/agents.json` (or $HEYARP_HOME/agents.json).",
5304
+ " \u2022 Keys live in `~/.heyarp/agents.json` (or $HEYARP_HOME/agents.json).",
5314
5305
  " \u2022 State file = identity. If two agents share one home dir, EITHER can sign as",
5315
5306
  " the other. For multi-agent setups on one host, set HEYARP_HOME per agent:",
5316
5307
  " HEYARP_HOME=/tmp/agent-alice heyarp register \u2026",
@@ -5337,8 +5328,8 @@ var GUIDE_SECTIONS = [
5337
5328
  "",
5338
5329
  " (There is no separate terms-agreement step \u2014 the delegation offer",
5339
5330
  " carries the agreed terms inline and the condition_hash binds them.",
5340
- " M6 lock-at-accept: the escrow lock is funded AFTER acceptance via",
5341
- " `delegation fund`, so an un-accepted offer never strands funds.)",
5331
+ " The escrow lock is funded AFTER acceptance via `delegation fund`,",
5332
+ " so an un-accepted offer never strands funds.)",
5342
5333
  " Skipping any stage = the next stage rejects with a state-machine error.",
5343
5334
  " On-chain claim_work_payment is the closure: the buyer approves, or the",
5344
5335
  " worker self-claims after the review window expires."
@@ -5350,13 +5341,13 @@ var GUIDE_SECTIONS = [
5350
5341
  overview: true,
5351
5342
  title: "Escrow (how funds actually move)",
5352
5343
  body: [
5353
- " M6 lock-at-accept: the buyer funds escrow AFTER the worker accepts.",
5344
+ " The buyer funds escrow AFTER the worker accepts.",
5354
5345
  " `delegation offer` carries terms only (no lock). Once the worker",
5355
5346
  " accepts, `delegation fund` attaches the signed Solana `create_lock`",
5356
5347
  " tx blob; the worker waits for the lock to confirm (LOCKED) before",
5357
5348
  " starting work, knowing the cash is locked. An un-accepted offer has",
5358
5349
  " no lock to strand.",
5359
- " Payment consent is ON-CHAIN (V2): the payer sends claim_work_payment to",
5350
+ " Payment consent is ON-CHAIN: the payer sends claim_work_payment to",
5360
5351
  " approve, or the payee self-claims after the review window. Exit paths:",
5361
5352
  " \u2022 cancel_lock \u2014 buyer cancels while the lock is unaccepted",
5362
5353
  " \u2022 claim_expired_work \u2014 buyer reclaims if the work window lapses",
@@ -5557,7 +5548,7 @@ var GUIDE_SECTIONS = [
5557
5548
  " relationship : status <rel> --json \u2192 .relationshipState (NOT .state)",
5558
5549
  " delegation : status <rel> --json \u2192 .latestDelegation.state",
5559
5550
  " (or delegations <rel> --json \u2192 .[].state)",
5560
- " receipt : receipts <rel> --json \u2192 .[].state / .verdictFinal / .receiptEventHash",
5551
+ " receipt : receipts <rel> --json \u2192 .[].state / .verdictProposed / .receiptEventHash",
5561
5552
  " incoming events : inbox --json \u2192 .[].body.type / .eventId / .serverTimestamp /",
5562
5553
  " .senderDid (NOT .signer)",
5563
5554
  " worker pay key : did-doc <worker-did> --field settlementPublicKey",
@@ -6067,9 +6058,9 @@ async function runInbox(positionalDid, opts) {
6067
6058
  printVerbose(events, "Full event envelopes:", (ev) => ({
6068
6059
  primary: `#${ev.relationshipEventIndex} ${ev.type ?? "<unknown>"}`,
6069
6060
  // eventId is the cursor used by `--before-event-id`;
6070
- // serverEventHash is what `receipt propose` / `cosign`
6071
- // requires. Surface BOTH inline so a copy-paste workflow
6072
- // doesn't have to dig into the JSON below.
6061
+ // serverEventHash is what `receipt propose` requires.
6062
+ // Surface BOTH inline so a copy-paste workflow doesn't have
6063
+ // to dig into the JSON below.
6073
6064
  secondary: `eventId=${ev.eventId} serverEventHash=${ev.serverEventHash}`
6074
6065
  }));
6075
6066
  }
@@ -6221,7 +6212,7 @@ function writeSecretFile(path, body) {
6221
6212
  }
6222
6213
  function registerKeysCommand(root) {
6223
6214
  const keys = root.command("keys").description("Local key utilities");
6224
- 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) => {
6215
+ keys.command("gen").description("Generate a fresh identity + settlement keypair (no save by default)").action(() => {
6225
6216
  const identity = (0, import_sdk12.generateKeyPair)();
6226
6217
  const settlement = (0, import_sdk12.generateKeyPair)();
6227
6218
  const out = [
@@ -6237,9 +6228,6 @@ function registerKeysCommand(root) {
6237
6228
  ` ${import_chalk17.default.cyan((0, import_sdk12.formatDid)(identity.publicKey))}`
6238
6229
  ];
6239
6230
  console.log(out.join("\n"));
6240
- if (opts.save) {
6241
- console.log(import_chalk17.default.yellow("\nNote: --save is not yet implemented. Capture the secret keys above before they scroll off-screen."));
6242
- }
6243
6231
  });
6244
6232
  keys.command("export <did>").description("Export an agent\u2019s key backup bundle (SECRETS) so you can recover it on another machine with `heyarp recover`. Writes to --out (mode 0600) or stdout.").option("--server <url>", "Override ARP server base URL").option("--out <file>", "Write the bundle to this file (mode 0600) instead of stdout").action((did, opts) => {
6245
6233
  const agent = loadAgentOrThrow(opts.server, did);
@@ -6278,7 +6266,7 @@ function decodeSeed(b64) {
6278
6266
  // src/commands/list.ts
6279
6267
  var import_chalk18 = __toESM(require("chalk"));
6280
6268
  function registerListCommand(root) {
6281
- root.command("list").description("List agents registered locally (~/.arp/agents.json)").action(() => {
6269
+ root.command("list").description("List agents registered locally (~/.heyarp/agents.json)").action(() => {
6282
6270
  const rows = listAgents();
6283
6271
  if (rows.length === 0) {
6284
6272
  console.log(import_chalk18.default.dim(`No local agents. State file: ${stateFilePath()}`));
@@ -6456,7 +6444,7 @@ var import_shield2 = require("@heyanon-arp/shield");
6456
6444
  var import_chalk22 = __toESM(require("chalk"));
6457
6445
  init_api();
6458
6446
  function registerReceiptCommands(root) {
6459
- const cmd = root.command("receipt").description("Receipt envelopes \u2014 the payee proposes a delivery record (V2: payment consent is on-chain via claim_work_payment)");
6447
+ const cmd = root.command("receipt").description("Receipt envelopes \u2014 the payee proposes a delivery record (payment consent is on-chain via claim_work_payment)");
6460
6448
  registerPropose(cmd);
6461
6449
  }
6462
6450
  var POST_COMMIT_ERROR_CODES2 = /* @__PURE__ */ new Set([
@@ -6467,7 +6455,7 @@ var POST_COMMIT_ERROR_CODES2 = /* @__PURE__ */ new Set([
6467
6455
  "RECEIPT_ISSUER_IS_CALLER",
6468
6456
  "RECEIPT_NOT_FOUND",
6469
6457
  "RECEIPT_INVALID_STATE",
6470
- // M6 lock-at-accept: the receipt-propose handler's LOCKED gate emits
6458
+ // The receipt-propose handler's LOCKED gate emits
6471
6459
  // `DELEGATION_PENDING_LOCK` (409) when the delegation is funded but
6472
6460
  // the on-chain lock isn't confirmed yet (state
6473
6461
  // `pending_lock_finalization`). It fires from the body handler AFTER
@@ -6489,7 +6477,7 @@ var POST_COMMIT_ERROR_CODES2 = /* @__PURE__ */ new Set([
6489
6477
  var VERDICT_VALUES = ["accepted", "accepted_with_notes", "rejected"];
6490
6478
  var SHA256_RE = /^sha256:[0-9a-f]{64}$/;
6491
6479
  function registerPropose(parent) {
6492
- parent.command("propose").description("Send a receipt envelope as the PAYEE. Row lands PROPOSED; caller cosigns to flip to COSIGNED.").argument("<recipient-did>", "Recipient agent DID (= caller / offerer of the parent delegation)").argument("<delegation-id>", "Parent delegation id (UUID, must be ACCEPTED)").argument("[request-hash]", "sha256:<64 hex> \u2014 SHA-256 of the work_request payload being settled. Omit when --auto-hashes is set.").argument("[response-hash]", "sha256:<64 hex> \u2014 SHA-256 of the work_response payload being settled. Omit when --auto-hashes is set.").option("--server <url>", "Override ARP server base URL").option("--from-did <did>", "Sender DID \u2014 required only if multiple agents are registered against this server").option("--verdict <s>", "verdict_proposed (accepted | accepted_with_notes | rejected)", "accepted").option("--notes-hash <sha256>", "Optional sha256:<64 hex> notes hash").option("--deliverable-hash <sha256>", "Optional sha256:<64 hex> deliverable hash").option("--input-tokens <n>", "Optional usage.input_tokens").option("--output-tokens <n>", "Optional usage.output_tokens").option("--latency-ms <n>", "Optional usage.latency_ms").option("--model <name>", "Optional usage.model").option("--computed-amount <s>", "Optional usage.computed_amount").option("--ttl <seconds>", "Envelope TTL in seconds", "3600").option(
6480
+ parent.command("propose").description("Send a receipt envelope as the PAYEE. Row lands PROPOSED; the buyer approves payment on-chain via claim_work_payment.").argument("<recipient-did>", "Recipient agent DID (= caller / offerer of the parent delegation)").argument("<delegation-id>", "Parent delegation id (UUID, must be ACCEPTED)").argument("[request-hash]", "sha256:<64 hex> \u2014 SHA-256 of the work_request payload being settled. Omit when --auto-hashes is set.").argument("[response-hash]", "sha256:<64 hex> \u2014 SHA-256 of the work_response payload being settled. Omit when --auto-hashes is set.").option("--server <url>", "Override ARP server base URL").option("--from-did <did>", "Sender DID \u2014 required only if multiple agents are registered against this server").option("--verdict <s>", "verdict_proposed (accepted | accepted_with_notes | rejected)", "accepted").option("--notes-hash <sha256>", "Optional sha256:<64 hex> notes hash").option("--deliverable-hash <sha256>", "Optional sha256:<64 hex> deliverable hash").option("--input-tokens <n>", "Optional usage.input_tokens").option("--output-tokens <n>", "Optional usage.output_tokens").option("--latency-ms <n>", "Optional usage.latency_ms").option("--model <name>", "Optional usage.model").option("--computed-amount <s>", "Optional usage.computed_amount").option("--ttl <seconds>", "Envelope TTL in seconds", "3600").option(
6493
6481
  "--auto-hashes",
6494
6482
  "Compute request_hash + response_hash automatically from the work-log row at (--rel-id, <delegation-id>, --request-id). Positional <request-hash>/<response-hash> become optional; if supplied they must match the computed values (consistency check). --rel-id and --request-id auto-resolve from local state when unambiguous \u2014 pass them explicitly only if the lookup finds multiple candidates.",
6495
6483
  false
@@ -6630,7 +6618,7 @@ async function assertSenderIsReceiptPayee(api, sender, relationshipId, delegatio
6630
6618
  }
6631
6619
  if (delegation.offererDid === sender.did) {
6632
6620
  throw new Error(
6633
- `receipt propose: ${sender.did} is the CALLER on delegation ${delegationId} (matches delegation.offererDid). Only the PAYEE \u2014 the counterparty who accepted the delegation offer \u2014 can issue a receipt; as the caller your role is to COSIGN the receipt the payee proposes. Wait for it via \`heyarp status ${relationshipId} --wait --until receipt.proposed\` then run \`heyarp receipt cosign ${relationshipId} ${delegationId} --auto-hashes [--request-id <id>] --settlement-purpose <p> --settlement-expires-at <unix> --payer-sig-from-file <path> --payee-sig-from-file <path>\`.`
6621
+ `receipt propose: ${sender.did} is the CALLER on delegation ${delegationId} (matches delegation.offererDid). Only the PAYEE \u2014 the counterparty who accepted the delegation offer \u2014 can issue a receipt; as the caller your role is to approve payment ON-CHAIN via claim_work_payment once the payee proposes the receipt. Wait for it via \`heyarp status ${relationshipId} --wait --until receipt.proposed\`.`
6634
6622
  );
6635
6623
  }
6636
6624
  return delegation;
@@ -6805,19 +6793,14 @@ function requireDid2(cmdName, did, label) {
6805
6793
  // src/commands/receipts.ts
6806
6794
  var import_chalk23 = __toESM(require("chalk"));
6807
6795
  init_api();
6808
- var ALLOWED_STATES2 = /* @__PURE__ */ new Set(["proposed", "cosigned"]);
6809
6796
  function registerReceiptsCommand(root) {
6810
6797
  root.command("receipts").description(
6811
6798
  "List receipts for a relationship (one row per (delegationId, requestHash, responseHash), oldest-first). Receipt rows expose the chain hash as `receiptEventHash` (NOT `serverEventHash` \u2014 that field is the wider envelope identifier on `heyarp events` rows). Scripts using `--json | jq .receiptEventHash` get the value; `jq .serverEventHash` silently returns null because the row doesn't carry that key."
6812
- ).argument("<relationship-id>", "Relationship UUID").option("--server <url>", "Override ARP server base URL").option("--state <s>", "Filter by exact state (proposed|cosigned)").option("--delegation-id <uuid>", "Narrow to receipts under a specific delegation id").option("--after <id>", "Cursor: pass the previous page's last `id` to fetch the next page").option("--limit <n>", "Max rows to return (1..100)", "20").option("--from-did <did>", "Signer DID \u2014 required only if multiple agents are registered against this server").option(
6799
+ ).argument("<relationship-id>", "Relationship UUID").option("--server <url>", "Override ARP server base URL").option("--delegation-id <uuid>", "Narrow to receipts under a specific delegation id").option("--after <id>", "Cursor: pass the previous page's last `id` to fetch the next page").option("--limit <n>", "Max rows to return (1..100)", "20").option("--from-did <did>", "Signer DID \u2014 required only if multiple agents are registered against this server").option(
6813
6800
  "--verbose",
6814
- 'After the one-line summaries, print a framed "Full receipt payloads (N rows)" block \u2014 each row labelled with full delegationId + requestHash + responseHash (the values `receipt cosign` requires) and dumped as JSON. Mutually exclusive with --json.',
6801
+ 'After the one-line summaries, print a framed "Full receipt payloads (N rows)" block \u2014 each row labelled with full delegationId + requestHash + responseHash and dumped as JSON. Mutually exclusive with --json.',
6815
6802
  false
6816
- ).option("--json", "Machine-readable mode \u2014 emit a single JSON array of receipt rows, no chalk, no summary. Pipe-safe. Mutually exclusive with --verbose.", false).option(
6817
- "--full-ids",
6818
- "Print delegationId / requestHash / responseHash / DIDs in full (no truncation). REQUIRED for piping into `receipt cosign` which needs the full sha256s.",
6819
- false
6820
- ).action(async (relationshipId, opts) => {
6803
+ ).option("--json", "Machine-readable mode \u2014 emit a single JSON array of receipt rows, no chalk, no summary. Pipe-safe. Mutually exclusive with --verbose.", false).option("--full-ids", "Print delegationId / requestHash / responseHash / DIDs in full (no truncation).", false).action(async (relationshipId, opts) => {
6821
6804
  await runReceipts(relationshipId, opts);
6822
6805
  });
6823
6806
  }
@@ -6828,7 +6811,6 @@ async function runReceipts(relationshipId, opts) {
6828
6811
  );
6829
6812
  }
6830
6813
  const limit = parseLimit5(opts.limit);
6831
- const state = parseState2(opts.state);
6832
6814
  const api = new ArpApiClient(opts.server);
6833
6815
  const sender = resolveSenderAgent("receipts", opts.server, opts.fromDid);
6834
6816
  if (!opts.json) {
@@ -6837,7 +6819,6 @@ async function runReceipts(relationshipId, opts) {
6837
6819
  console.log(import_chalk23.default.dim(`Relationship: ${relationshipId}`));
6838
6820
  }
6839
6821
  const query = { limit };
6840
- if (state) query.state = state;
6841
6822
  if (opts.delegationId) query.delegationId = opts.delegationId;
6842
6823
  if (opts.after) query.after = opts.after;
6843
6824
  const signer = makeSigner(sender);
@@ -6856,11 +6837,10 @@ async function runReceipts(relationshipId, opts) {
6856
6837
  }
6857
6838
  if (opts.verbose) {
6858
6839
  printVerbose(rows, "Full receipt payloads:", (r) => ({
6859
- primary: `state=${r.state} verdict=${r.verdictFinal ?? r.verdictProposed}`,
6860
- // `receipt cosign` requires the FULL `requestHash` and
6861
- // `responseHash` plus `delegationId`. Putting all three on
6862
- // one inline label keeps the cosign flow grep-able without
6863
- // dropping into `--json | jq`.
6840
+ primary: `verdict=${r.verdictProposed}`,
6841
+ // Surface the FULL `requestHash` + `responseHash` + `delegationId`
6842
+ // on one inline label so the receipt-correlation flow stays
6843
+ // grep-able without dropping into `--json | jq`.
6864
6844
  secondary: `delegationId=${r.delegationId} requestHash=${r.requestHash} responseHash=${r.responseHash}`
6865
6845
  }));
6866
6846
  }
@@ -6872,29 +6852,16 @@ function formatReceiptLine(r, selfDid, opts = {}) {
6872
6852
  const delegationPart = opts.fullIds ? r.delegationId : idHead2(r.delegationId);
6873
6853
  const requestHashPart = opts.fullIds ? r.requestHash : hashHead3(r.requestHash);
6874
6854
  const id = import_chalk23.default.bold(`${delegationPart}/${requestHashPart}`);
6875
- const state = colorState2(r.state).padEnd(stateColumnWidth2());
6876
6855
  const callerHead = opts.fullIds ? r.callerDid : didHead3(r.callerDid);
6877
6856
  const payeeHead = opts.fullIds ? r.payeeDid : didHead3(r.payeeDid);
6878
6857
  const direction = r.payeeDid === selfDid ? `${import_chalk23.default.bold("me")}(payee) \u2192 ${import_chalk23.default.dim(callerHead)}` : `${import_chalk23.default.dim(payeeHead)}(payee) \u2192 ${import_chalk23.default.bold("me")}`;
6879
6858
  const verdict = formatVerdict(r);
6880
6859
  const responseTail = opts.fullIds ? `
6881
6860
  ${import_chalk23.default.dim("responseHash:")} ${import_chalk23.default.cyan(r.responseHash)}` : "";
6882
- return `${id} ${state} ${direction} ${verdict}${responseTail}`;
6883
- }
6884
- function colorState2(s) {
6885
- switch (s) {
6886
- case "proposed":
6887
- return import_chalk23.default.yellow("proposed");
6888
- case "cosigned":
6889
- return import_chalk23.default.green("cosigned");
6890
- }
6891
- }
6892
- function stateColumnWidth2() {
6893
- return 8;
6861
+ return `${id} ${direction} ${verdict}${responseTail}`;
6894
6862
  }
6895
6863
  function formatVerdict(r) {
6896
- const final = r.verdictFinal ?? r.verdictProposed;
6897
- switch (final) {
6864
+ switch (r.verdictProposed) {
6898
6865
  case "accepted":
6899
6866
  return import_chalk23.default.green("accepted");
6900
6867
  case "accepted_with_notes":
@@ -6915,13 +6882,6 @@ function didHead3(did) {
6915
6882
  if (did.length <= 20) return did;
6916
6883
  return `${did.slice(0, 20)}...`;
6917
6884
  }
6918
- function parseState2(raw) {
6919
- if (raw === void 0) return void 0;
6920
- if (!ALLOWED_STATES2.has(raw)) {
6921
- throw new Error(`receipts: --state must be one of proposed|cosigned (got '${raw}')`);
6922
- }
6923
- return raw;
6924
- }
6925
6885
  function parseLimit5(raw) {
6926
6886
  if (raw === void 0) return 20;
6927
6887
  const n = Number(raw);
@@ -6987,8 +6947,10 @@ async function runRecover(opts) {
6987
6947
  lastSenderSequence = seq.lastSenderSequence;
6988
6948
  } catch (err) {
6989
6949
  process.stderr.write(
6990
- import_chalk24.default.yellow(`\u26A0 could not read the sender sequence from the server (${err.message}). If sends are rejected as backwards, run \`heyarp escrow recover-sequence --apply\`.
6991
- `)
6950
+ import_chalk24.default.yellow(
6951
+ `\u26A0 could not read the sender sequence from the server (${err.message}). If sends are rejected as backwards, run \`heyarp escrow recover-sequence --apply\`.
6952
+ `
6953
+ )
6992
6954
  );
6993
6955
  }
6994
6956
  const state = {
@@ -7040,13 +7002,12 @@ function registerRegisterCommand(root) {
7040
7002
  // logged by CI runners (e.g. GitHub Actions echoes the
7041
7003
  // full command). Safer alternatives:
7042
7004
  // • interactive prompt (default) — never written anywhere
7043
- // • `HEYARP_PASSWORD` env var (V1.5 — tracked) reads
7044
- // from env so the secret stays out of argv even in
7045
- // scripts
7005
+ // • `HEYARP_PASSWORD` env var (tracked) reads from env so
7006
+ // the secret stays out of argv even in scripts
7046
7007
  // Treat `--password <s>` as a one-off local-dev affordance;
7047
7008
  // do NOT use it in CI pipelines without a secret-redacting
7048
7009
  // runner.
7049
- "Owner password \u2014 MUST be at least 8 characters. REQUIRED when --yes is set; otherwise the CLI prompts for it. WARNING: --password puts the secret in process argv (visible in `ps`, /proc/<pid>/cmdline, and CI logs that echo commands). Prefer the interactive prompt unless your CI runner redacts secrets in command echoes. V1.5: HEYARP_PASSWORD env var support tracked."
7010
+ "Owner password \u2014 MUST be at least 8 characters. REQUIRED when --yes is set; otherwise the CLI prompts for it. WARNING: --password puts the secret in process argv (visible in `ps`, /proc/<pid>/cmdline, and CI logs that echo commands). Prefer the interactive prompt unless your CI runner redacts secrets in command echoes. HEYARP_PASSWORD env var support is tracked."
7050
7011
  ).option(
7051
7012
  "--yes",
7052
7013
  "Strict non-interactive: fail if any required field is still missing after merging flags. With --yes, --password must be supplied explicitly (>= 8 chars).",
@@ -7057,7 +7018,6 @@ function registerRegisterCommand(root) {
7057
7018
  // success prints. Output shape:
7058
7019
  // {did, settlementPublicKeyB58, identityPublicKeyB58,
7059
7020
  // localStatePath, didDocument}
7060
- // (V1-alpha: `accountId` parked from the output.)
7061
7021
  // REQUIRES --yes (interactive prompts would corrupt the
7062
7022
  // single-doc contract).
7063
7023
  "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).",
@@ -7116,8 +7076,6 @@ async function runRegister(opts, deps = defaultRegisterDeps) {
7116
7076
  const attestation = (0, import_sdk16.signKeyLinkAttestation)({ payload, scryptKey, scryptSaltId });
7117
7077
  const body = {
7118
7078
  challengeId: challenge.challengeId,
7119
- // V1-alpha: accountId parked — server's DTO no longer accepts it.
7120
- // accountId: answers.accountId,
7121
7079
  identityPublicKey: identityPublicKeyB58,
7122
7080
  settlementPublicKey: settlementPublicKeyB58,
7123
7081
  ownerAttestation: {
@@ -7210,20 +7168,11 @@ Local state saved to ${arpHomeDir()}/agents.json (mode 0600).`));
7210
7168
  }
7211
7169
  }
7212
7170
  async function mergeAnswers(opts) {
7213
- const need = opts.yes ? {
7214
- password: false,
7215
- name: false,
7216
- description: false,
7217
- tagsCsv: false
7218
- /* accountId parked V1-alpha */
7219
- } : {
7171
+ const need = opts.yes ? { password: false, name: false, description: false, tagsCsv: false } : {
7220
7172
  password: opts.password === void 0,
7221
7173
  name: opts.name === void 0,
7222
7174
  description: opts.description === void 0,
7223
7175
  tagsCsv: opts.tag === void 0 || opts.tag.length === 0
7224
- // V1-alpha: accountId parked. Uncomment + restore the prompt
7225
- // below when launchpad↔ARP join lands.
7226
- // accountId: opts.accountId === undefined,
7227
7176
  };
7228
7177
  if (opts.yes) {
7229
7178
  const missing = [];
@@ -7275,7 +7224,6 @@ async function mergeAnswers(opts) {
7275
7224
  password: opts.password ?? prompted.password,
7276
7225
  name: opts.name ?? prompted.name,
7277
7226
  description: opts.description ?? prompted.description ?? "",
7278
- // accountId, // V1-alpha parked — see RegisterAnswers above.
7279
7227
  tags
7280
7228
  };
7281
7229
  }
@@ -7311,7 +7259,7 @@ function warnIfAgentsAlreadyRegistered(serverOverride) {
7311
7259
  const existing = listAgents().filter((row) => row.serverUrl === targetServer);
7312
7260
  if (existing.length === 0) return;
7313
7261
  const list = existing.map((row) => ` \u2022 ${import_chalk25.default.cyan(row.agent.did)}${row.agent.name ? import_chalk25.default.dim(` (${row.agent.name})`) : ""}`).join("\n");
7314
- console.log(import_chalk25.default.yellow("\n\u26A0 ~/.arp/agents.json already has agent(s) for this server:"));
7262
+ console.log(import_chalk25.default.yellow("\n\u26A0 ~/.heyarp/agents.json already has agent(s) for this server:"));
7315
7263
  console.log(list);
7316
7264
  console.log(
7317
7265
  import_chalk25.default.dim(
@@ -7371,7 +7319,7 @@ function assertJsonRequiresYes(opts) {
7371
7319
  // src/commands/relationships.ts
7372
7320
  var import_chalk26 = __toESM(require("chalk"));
7373
7321
  init_api();
7374
- var ALLOWED_STATES3 = /* @__PURE__ */ new Set(["pending", "active", "paused", "closed"]);
7322
+ var ALLOWED_STATES2 = /* @__PURE__ */ new Set(["pending", "active", "paused", "closed"]);
7375
7323
  function registerRelationshipsCommand(root) {
7376
7324
  root.command("relationships").description(
7377
7325
  "List relationships <did> belongs to (live + closed pairs, ordered by lastEventAt desc). DID can be passed positionally OR via --from-did; if both are omitted the resolver picks the sole local agent for the server (see `heyarp config set server` + multi-DID disambiguation rules)."
@@ -7381,7 +7329,7 @@ function registerRelationshipsCommand(root) {
7381
7329
  }
7382
7330
  async function runRelationships(positionalDid, opts) {
7383
7331
  const limit = parseLimit6(opts.limit);
7384
- const state = parseState3(opts.state);
7332
+ const state = parseState2(opts.state);
7385
7333
  if (positionalDid !== void 0 && opts.fromDid !== void 0 && positionalDid !== opts.fromDid) {
7386
7334
  throw new Error(`relationships: positional <did> (${positionalDid}) and --from-did (${opts.fromDid}) disagree \u2014 pass only one`);
7387
7335
  }
@@ -7422,9 +7370,9 @@ function otherPair(r, selfDid) {
7422
7370
  if (r.pairDidB === selfDid) return r.pairDidA;
7423
7371
  return `${r.pairDidA} \u2194 ${r.pairDidB}`;
7424
7372
  }
7425
- function parseState3(raw) {
7373
+ function parseState2(raw) {
7426
7374
  if (raw === void 0) return void 0;
7427
- if (!ALLOWED_STATES3.has(raw)) {
7375
+ if (!ALLOWED_STATES2.has(raw)) {
7428
7376
  throw new Error(`relationships: --state must be one of pending|active|paused|closed (got '${raw}')`);
7429
7377
  }
7430
7378
  return raw;
@@ -7490,7 +7438,11 @@ var import_sdk18 = require("@heyanon-arp/sdk");
7490
7438
  var import_chalk28 = __toESM(require("chalk"));
7491
7439
  init_api();
7492
7440
  function registerSendHandshakeCommand(root) {
7493
- root.command("send-handshake").description("Send a handshake envelope to <recipient-did>. Server creates the relationship row on first contact.").argument("<recipient-did>", "Recipient agent DID (did:arp:...)").option("--server <url>", "Override ARP server base URL").option("--from-did <did>", "Sender DID \u2014 required only if multiple agents are registered against this server").option("--greeting <s>", "Optional greeting text included in body.content").option("--intent <s>", "Optional intent text included in body.content").option("--ttl <seconds>", "Envelope TTL in seconds (max 86400 = 24h)", "3600").option("--verbose", "Print the full envelope before sending and the full server response", false).action(async (recipientDid, opts) => {
7441
+ root.command("send-handshake").description("Send a handshake envelope to <recipient-did>. Server creates the relationship row on first contact.").argument("<recipient-did>", "Recipient agent DID (did:arp:...)").option("--server <url>", "Override ARP server base URL").option("--from-did <did>", "Sender DID \u2014 required only if multiple agents are registered against this server").option("--greeting <s>", "Optional greeting text included in body.content").option("--intent <s>", "Optional intent text included in body.content").option("--ttl <seconds>", "Envelope TTL in seconds (max 86400 = 24h)", "3600").option("--verbose", "Print the full envelope before sending and the full server response. Mutually exclusive with --json.", false).option(
7442
+ "--json",
7443
+ "Machine-readable mode \u2014 emit a single JSON object on stdout ({ok, eventId, relationshipId, relationshipEventIndex, serverTimestamp, signedMessageHash, serverEventHash, prevServerEventHash, senderSequence}). The Server/Sender/Recipient prelude moves to stderr so `--json | jq` stays byte-pure. Mutually exclusive with --verbose.",
7444
+ false
7445
+ ).action(async (recipientDid, opts) => {
7494
7446
  await runSendHandshake(recipientDid, opts);
7495
7447
  });
7496
7448
  }
@@ -7498,12 +7450,17 @@ async function runSendHandshake(recipientDid, opts) {
7498
7450
  if (!isDid(recipientDid)) {
7499
7451
  throw new Error(`send-handshake: <recipient-did> must look like 'did:arp:...' (got '${recipientDid}')`);
7500
7452
  }
7453
+ if (opts.verbose && opts.json) {
7454
+ throw new Error(
7455
+ "send-handshake: --verbose and --json are mutually exclusive. --json emits the structured server response; --verbose adds envelope + response dumps that would break `--json | jq`."
7456
+ );
7457
+ }
7501
7458
  const ttlSeconds = parseTtl3(opts.ttl);
7502
7459
  const api = new ArpApiClient(opts.server);
7503
- console.log(import_chalk28.default.dim(`Server: ${api.serverUrl}`));
7460
+ progress(opts.json, import_chalk28.default.dim(`Server: ${api.serverUrl}`));
7504
7461
  const sender = resolveSenderAgent("send-handshake", opts.server, opts.fromDid);
7505
- console.log(import_chalk28.default.dim(`Sender: ${sender.did}`));
7506
- console.log(import_chalk28.default.dim(`Recipient: ${recipientDid}`));
7462
+ progress(opts.json, import_chalk28.default.dim(`Sender: ${sender.did}`));
7463
+ progress(opts.json, import_chalk28.default.dim(`Recipient: ${recipientDid}`));
7507
7464
  const content = {};
7508
7465
  if (opts.greeting) content.greeting = opts.greeting;
7509
7466
  if (opts.intent) content.intent = opts.intent;
@@ -7534,6 +7491,20 @@ async function runSendHandshake(recipientDid, opts) {
7534
7491
  }
7535
7492
  const result = await api.ingest(envelope);
7536
7493
  updateAgentLocal(opts.server, sender.did, { lastSenderSequence: nextSequence });
7494
+ if (opts.json) {
7495
+ jsonOut({
7496
+ ok: true,
7497
+ eventId: result.eventId,
7498
+ relationshipId: result.relationshipId,
7499
+ relationshipEventIndex: result.relationshipEventIndex,
7500
+ serverTimestamp: result.serverTimestamp,
7501
+ signedMessageHash: result.signedMessageHash,
7502
+ serverEventHash: result.serverEventHash,
7503
+ prevServerEventHash: result.prevServerEventHash ?? null,
7504
+ senderSequence: nextSequence
7505
+ });
7506
+ return;
7507
+ }
7537
7508
  console.log(import_chalk28.default.green("\nDelivered."));
7538
7509
  console.log(`${import_chalk28.default.bold("Event id")}: ${import_chalk28.default.cyan(result.eventId)}`);
7539
7510
  console.log(`${import_chalk28.default.bold("Relationship id")}: ${import_chalk28.default.cyan(result.relationshipId)}`);
@@ -7883,8 +7854,7 @@ function registerWhoamiCommand(root) {
7883
7854
  // `--payer-settlement-pubkey` / on-chain ops without a
7884
7855
  // server round-trip. `--local` short-circuits the signed
7885
7856
  // GET, prints just the resolved DID + pubkeys from local
7886
- // state. (V1-alpha: accountId parked, no longer in --local
7887
- // output.)
7857
+ // state.
7888
7858
  "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.",
7889
7859
  false
7890
7860
  ).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) => {
@@ -7897,10 +7867,6 @@ function registerWhoamiCommand(root) {
7897
7867
  did: local.did,
7898
7868
  settlementPublicKeyB58: local.settlementPublicKeyB58,
7899
7869
  identityPublicKeyB58: local.identityPublicKeyB58,
7900
- // V1-alpha: accountId parked — local-state type no
7901
- // longer carries the field. Uncomment when launchpad↔ARP
7902
- // join lands.
7903
- // accountId: local.accountId,
7904
7870
  name: local.name
7905
7871
  };
7906
7872
  if (opts.local) {
@@ -7970,7 +7936,7 @@ var POST_COMMIT_ERROR_CODES3 = /* @__PURE__ */ new Set([
7970
7936
  "WORK_REQUEST_NOT_FOUND",
7971
7937
  "WORK_RESPONDER_IS_CALLER",
7972
7938
  "WORK_INVALID_STATE",
7973
- // M6 lock-at-accept: the work handler's LOCKED gate emits
7939
+ // The work handler's LOCKED gate emits
7974
7940
  // `DELEGATION_PENDING_LOCK` (409) when the delegation is funded but
7975
7941
  // the on-chain lock isn't confirmed yet (state
7976
7942
  // `pending_lock_finalization`). It fires from the body handler AFTER
@@ -8232,7 +8198,7 @@ function requireDid3(cmdName, did, label) {
8232
8198
  // src/commands/work-list.ts
8233
8199
  var import_chalk33 = __toESM(require("chalk"));
8234
8200
  init_api();
8235
- var ALLOWED_STATES4 = /* @__PURE__ */ new Set(["requested", "responded"]);
8201
+ var ALLOWED_STATES3 = /* @__PURE__ */ new Set(["requested", "responded"]);
8236
8202
  function registerWorkListCommand(root) {
8237
8203
  root.command("work-list").description("List work-log rows for a relationship (one row per (delegationId, requestId), oldest-first)").argument("<relationship-id>", "Relationship UUID").option("--server <url>", "Override ARP server base URL").option("--state <s>", "Filter by exact state (requested|responded)").option("--delegation-id <uuid>", "Narrow to work-logs operating under a specific delegation id").option("--after <id>", "Cursor: pass the previous page's last `id` to fetch the next page").option("--limit <n>", "Max rows to return (1..100)", "20").option("--from-did <did>", "Signer DID \u2014 required only if multiple agents are registered against this server").option(
8238
8204
  "--verbose",
@@ -8253,7 +8219,7 @@ async function runWorkList(relationshipId, opts) {
8253
8219
  );
8254
8220
  }
8255
8221
  const limit = parseLimit7(opts.limit);
8256
- const state = parseState4(opts.state);
8222
+ const state = parseState3(opts.state);
8257
8223
  const api = new ArpApiClient(opts.server);
8258
8224
  const sender = resolveSenderAgent("work-list", opts.server, opts.fromDid);
8259
8225
  if (!opts.json) {
@@ -8296,14 +8262,14 @@ function formatWorkLogLine(w, selfDid, opts = {}) {
8296
8262
  const delegationPart = opts.fullIds ? w.delegationId : idHead3(w.delegationId);
8297
8263
  const requestPart = opts.fullIds ? w.requestId : truncate3(w.requestId, 16);
8298
8264
  const id = import_chalk33.default.bold(`${delegationPart}/${requestPart}`);
8299
- const state = colorState3(w.state).padEnd(stateColumnWidth3());
8265
+ const state = colorState2(w.state).padEnd(stateColumnWidth2());
8300
8266
  const peerCallerHead = opts.fullIds ? w.callerDid : didHead5(w.callerDid);
8301
8267
  const peerPayeeHead = opts.fullIds ? w.payeeDid : didHead5(w.payeeDid);
8302
8268
  const direction = w.callerDid === selfDid ? `${import_chalk33.default.bold("me")} \u2192 ${import_chalk33.default.dim(peerPayeeHead)}` : `${import_chalk33.default.dim(peerCallerHead)} \u2192 ${import_chalk33.default.bold("me")}`;
8303
8269
  const outcome = formatOutcome(w);
8304
8270
  return `${id} ${state} ${direction} ${outcome}`;
8305
8271
  }
8306
- function colorState3(s) {
8272
+ function colorState2(s) {
8307
8273
  switch (s) {
8308
8274
  case "requested":
8309
8275
  return import_chalk33.default.yellow("requested");
@@ -8311,7 +8277,7 @@ function colorState3(s) {
8311
8277
  return import_chalk33.default.green("responded");
8312
8278
  }
8313
8279
  }
8314
- function stateColumnWidth3() {
8280
+ function stateColumnWidth2() {
8315
8281
  return 9;
8316
8282
  }
8317
8283
  function formatOutcome(w) {
@@ -8332,9 +8298,9 @@ function truncate3(s, max) {
8332
8298
  if (s.length <= max) return s;
8333
8299
  return `${s.slice(0, max - 3)}...`;
8334
8300
  }
8335
- function parseState4(raw) {
8301
+ function parseState3(raw) {
8336
8302
  if (raw === void 0) return void 0;
8337
- if (!ALLOWED_STATES4.has(raw)) {
8303
+ if (!ALLOWED_STATES3.has(raw)) {
8338
8304
  throw new Error(`work-list: --state must be one of requested|responded (got '${raw}')`);
8339
8305
  }
8340
8306
  return raw;