@heyanon-arp/cli 0.0.2

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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/paths.ts","../src/config.ts","../src/api.ts","../src/cli.ts","../package.json","../src/commands/agents.ts","../src/format.ts","../src/commands/config.ts","../src/commands/contract.ts","../src/id-format.ts","../src/state.ts","../src/commands/delegation.ts","../src/commands/lifecycle.ts","../src/commands/wallet.ts","../src/commands/status.ts","../src/commands/contracts.ts","../src/commands/delegations.ts","../src/commands/did-doc.ts","../src/commands/doctor.ts","../src/commands/envelope.ts","../src/commands/escrow.ts","../src/commands/events.ts","../src/commands/guide.ts","../src/commands/homes.ts","../src/homes.ts","../src/commands/inbox.ts","../src/commands/keys.ts","../src/commands/list.ts","../src/commands/memory.ts","../src/commands/receipt.ts","../src/commands/receipts.ts","../src/commands/register.ts","../src/commands/relationships.ts","../src/commands/rotate.ts","../src/commands/send-handshake.ts","../src/commands/send-handshake-response.ts","../src/commands/watch.ts","../src/commands/whoami.ts","../src/commands/work.ts","../src/commands/work-list.ts"],"sourcesContent":["import { homedir } from 'node:os';\nimport { join } from 'node:path';\n\n/**\n * Resolve the directory the CLI uses for persistent state\n * (`agents.json` for keys + per-agent state, `config.json` for\n * preferences). Both `state.ts` and `config.ts` route through this\n * single helper so per-agent isolation only has to be configured\n * in one place.\n *\n * Resolution priority (high → low):\n * 1. `HEYARP_HOME` env var — points DIRECTLY at the home dir\n * (NOT at its parent). Allows per-agent isolation in\n * multi-agent-on-one-host scenarios:\n *\n * HEYARP_HOME=/tmp/agent-alice heyarp register …\n * HEYARP_HOME=/tmp/agent-bob heyarp register …\n *\n * Each shell session writes to its own `agents.json` /\n * `config.json` and never collides on sender_sequence,\n * defaultDid, or shared key custody.\n * 2. `<homedir()>/.arp` — the default convention. Same path\n * every previous CLI version used; existing users are not\n * affected unless they opt in via the env var.\n *\n * The path is NOT created here — `state.ts` / `config.ts` lazily\n * `mkdirSync(..., { recursive: true })` on first write. This keeps\n * read-only commands from creating empty directories on a\n * machine that has nothing to persist yet.\n */\nexport function arpHomeDir(): string {\n\tconst fromEnv = process.env.HEYARP_HOME;\n\tif (fromEnv && fromEnv.length > 0) return fromEnv;\n\treturn join(homedir(), '.arp');\n}\n\n/**\n * Path to the GLOBAL home-dir registry (`homes.json`). Always lives\n * at `<homedir>/.arp/homes.json` regardless of `HEYARP_HOME` — the\n * registry is the bridge between homes, so it must NOT itself be\n * isolated per home or each shell session would lose track of the\n * others.\n *\n * Schema (see `homes.ts`):\n * {\n * \"homes\": [\n * { \"path\": \"/tmp/agent-alice\", \"lastSeenAt\": \"2026-…\" },\n * { \"path\": \"/Users/x/.arp\", \"lastSeenAt\": \"2026-…\" }\n * ]\n * }\n */\nexport function homesRegistryPath(): string {\n\treturn join(homedir(), '.arp', 'homes.json');\n}\n","import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { arpHomeDir } from './paths';\n\n/**\n * Persistent CLI configuration: `~/.arp/config.json`. Lives next to\n * `agents.json` (the keys file) but is intentionally a separate file\n * — keys are server-scoped secrets, config is global preferences.\n *\n * The file is chmod 0600 like `agents.json` so future per-server\n * keys (e.g. cached session tokens) won't accidentally inherit\n * weaker perms.\n *\n * Schema is split into two scopes:\n *\n * {\n * \"server\": \"http://localhost:3000/arp\", // global: active server\n * \"servers\": { // per-server bucket\n * \"http://localhost:3000/arp\": { \"defaultDid\": \"did:arp:...\" },\n * \"https://dev.example.com/arp\": { \"defaultDid\": \"did:arp:...\" }\n * }\n * }\n *\n * Global keys (`GLOBAL_CONFIG_KEYS`): one value applies CLI-wide.\n * Currently just `server` — the active ARP server URL.\n *\n * Per-server keys (`SERVER_CONFIG_KEYS`): scoped to a server URL so\n * developers can flip between local / dev / prod without losing\n * which DID is the default in each. Currently just `defaultDid` —\n * the DID auto-applied to `--from-did` when omitted.\n *\n * Allowed keys are closed enums — typos like\n * `heyarp config set sevrer http://...` hard-fail rather than\n * silently writing fields nothing will ever read. Unknown keys read\n * from disk are dropped on the next write — defensive against stale\n * schemas.\n */\n\n/**\n * `rpcUrl` is the persistent default for the Solana RPC URL used by\n * wallet commands (create-lock, sign-settlement-release). Precedence\n * chain (high → low): --rpc-url flag > ARP_ESCROW_RPC_URL env > config\n * rpcUrl > built-in mainnet-beta public endpoint.\n */\nexport const GLOBAL_CONFIG_KEYS = ['server', 'rpcUrl'] as const;\nexport type GlobalConfigKey = (typeof GLOBAL_CONFIG_KEYS)[number];\n\n/**\n * Per-server keys are scaffolded but the V1 set is intentionally\n * empty — per-agent isolation is handled by `HEYARP_HOME` rather\n * than by per-server config keys (a single shared `~/.arp/config.json`\n * is necessarily last-writer-wins and does not scale to multi-agent\n * workflows). The scaffolding (read/write helpers, file shape) stays\n * so future legitimately-per-server keys (e.g. cached session tokens,\n * custom proxy URLs) can land without re-introducing the schema.\n */\nexport const SERVER_CONFIG_KEYS = [] as const;\nexport type ServerConfigKey = (typeof SERVER_CONFIG_KEYS)[number];\n\nexport type ConfigKey = GlobalConfigKey | ServerConfigKey;\n\ninterface ServerConfigBucket {\n\t// Reserved — populated when SERVER_CONFIG_KEYS gains its first\n\t// entry. Kept here so the read-path (which iterates known keys\n\t// and drops anything else) doesn't have a TS-zero-key dead zone.\n\t[key: string]: string | undefined;\n}\n\ninterface ConfigFile {\n\tserver?: string;\n\t// Persistent default for Solana RPC URL.\n\trpcUrl?: string;\n\tservers?: Record<string, ServerConfigBucket>;\n}\n\nexport function configFilePath(): string {\n\treturn join(arpHomeDir(), 'config.json');\n}\n\nexport function isGlobalConfigKey(key: string): key is GlobalConfigKey {\n\treturn (GLOBAL_CONFIG_KEYS as readonly string[]).includes(key);\n}\n\nexport function isServerConfigKey(key: string): key is ServerConfigKey {\n\treturn (SERVER_CONFIG_KEYS as readonly string[]).includes(key);\n}\n\nexport function isConfigKey(key: string): key is ConfigKey {\n\treturn isGlobalConfigKey(key) || isServerConfigKey(key);\n}\n\nfunction emptyConfig(): ConfigFile {\n\treturn {};\n}\n\nfunction readConfigFile(): ConfigFile {\n\tconst path = configFilePath();\n\tif (!existsSync(path)) return emptyConfig();\n\tlet raw: string;\n\ttry {\n\t\traw = readFileSync(path, 'utf8');\n\t} catch (err) {\n\t\tthrow new Error(`Failed to read config file at ${path}: ${(err as Error).message}`);\n\t}\n\tif (raw.trim().length === 0) return emptyConfig();\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(raw);\n\t} catch {\n\t\tthrow new Error(`Config file at ${path} is not valid JSON. Move or delete it before running again.`);\n\t}\n\tif (parsed === null || typeof parsed !== 'object') return emptyConfig();\n\tconst obj = parsed as Partial<ConfigFile> & Record<string, unknown>;\n\n\t// Defensive normalisation: only carry over keys we recognise + that\n\t// have the expected type. An older CLI version that wrote a\n\t// now-deprecated key shouldn't break us, and a hand-edited\n\t// `server: 42` shouldn't pollute downstream consumers.\n\tconst out: ConfigFile = {};\n\tif (typeof obj.server === 'string') {\n\t\tout.server = obj.server;\n\t}\n\tif (typeof obj.rpcUrl === 'string') {\n\t\tout.rpcUrl = obj.rpcUrl;\n\t}\n\tif (obj.servers && typeof obj.servers === 'object' && !Array.isArray(obj.servers)) {\n\t\tconst buckets: Record<string, ServerConfigBucket> = {};\n\t\tfor (const [url, raw] of Object.entries(obj.servers)) {\n\t\t\tif (raw === null || typeof raw !== 'object' || Array.isArray(raw)) continue;\n\t\t\tconst bucket: ServerConfigBucket = {};\n\t\t\tconst r = raw as Record<string, unknown>;\n\t\t\t// Carry only the currently-recognised SERVER_CONFIG_KEYS.\n\t\t\t// SERVER_CONFIG_KEYS is empty in V1 (see its JSDoc above)\n\t\t\t// so this loop is a no-op until a future slice\n\t\t\t// re-introduces a key. Any unrecognised keys on disk are\n\t\t\t// silently dropped on the next write.\n\t\t\tfor (const key of SERVER_CONFIG_KEYS) {\n\t\t\t\tif (typeof r[key] === 'string') bucket[key] = r[key] as string;\n\t\t\t}\n\t\t\tif (Object.keys(bucket).length > 0) buckets[url] = bucket;\n\t\t}\n\t\tif (Object.keys(buckets).length > 0) out.servers = buckets;\n\t}\n\treturn out;\n}\n\nfunction writeConfigFile(config: ConfigFile): void {\n\tconst path = configFilePath();\n\tconst dir = dirname(path);\n\tif (!existsSync(dir)) {\n\t\tmkdirSync(dir, { recursive: true, mode: 0o700 });\n\t}\n\tconst body = JSON.stringify(config, null, 2);\n\twriteFileSync(path, body, { encoding: 'utf8', mode: 0o600 });\n\ttry {\n\t\t// Re-apply 0600 because writeFileSync's mode is honoured only on\n\t\t// initial creation; if the file already existed with looser\n\t\t// perms we want to tighten them on every save. Same defensive\n\t\t// pattern as `state.ts`.\n\t\tchmodSync(path, 0o600);\n\t} catch {\n\t\t// Best-effort: ignore on platforms without POSIX chmod semantics.\n\t}\n}\n\n/* --------------------------------------------------------------- *\n * Global config (top-level, single value applies CLI-wide) *\n * --------------------------------------------------------------- */\n\n/**\n * Read one global config value. Returns `undefined` for keys the\n * user hasn't set, regardless of whether the file exists. Callers\n * that want to fall back to env / built-in defaults should chain\n * `??`.\n */\nexport function getGlobalConfigValue(key: GlobalConfigKey): string | undefined {\n\treturn readConfigFile()[key];\n}\n\n/**\n * Persist one global config value. Validates per-key shape — `server`\n * must parse as a URL, otherwise `heyarp config set server foo` would\n * silently break every subsequent command.\n */\nexport function setGlobalConfigValue(key: GlobalConfigKey, value: string): void {\n\tif (typeof value !== 'string' || value.length === 0) {\n\t\tthrow new Error(`Config value for ${key} must be a non-empty string`);\n\t}\n\tif (key === 'server') {\n\t\ttry {\n\t\t\t// Constructor throws for non-URL strings.\n\t\t\tnew URL(value);\n\t\t} catch {\n\t\t\tthrow new Error(`Config value for 'server' must be a valid URL (got ${value})`);\n\t\t}\n\t}\n\t// Same URL validation for rpcUrl. Catches typos like\n\t// `heyarp config set rpcUrl localhost:8899` (missing scheme) before\n\t// every subsequent wallet command silently fails.\n\tif (key === 'rpcUrl') {\n\t\ttry {\n\t\t\tnew URL(value);\n\t\t} catch {\n\t\t\tthrow new Error(`Config value for 'rpcUrl' must be a valid URL (got ${value})`);\n\t\t}\n\t}\n\tconst config = readConfigFile();\n\tconfig[key] = value;\n\twriteConfigFile(config);\n}\n\nexport function unsetGlobalConfigValue(key: GlobalConfigKey): void {\n\tconst config = readConfigFile();\n\tdelete config[key];\n\twriteConfigFile(config);\n}\n\n/* --------------------------------------------------------------- *\n * Per-server config (scoped to a server URL) *\n * --------------------------------------------------------------- */\n\n/**\n * Read one per-server config value. `serverUrl` should be the\n * already-resolved server (use `resolveServerUrl(...)` from `api.ts`\n * — it runs the same flag > env > config > default chain that\n * everything else resolves to).\n */\nexport function getServerConfigValue(serverUrl: string, key: ServerConfigKey): string | undefined {\n\tconst config = readConfigFile();\n\treturn config.servers?.[serverUrl]?.[key];\n}\n\n/**\n * Persist one per-server config value. Lazily creates the\n * `servers[<url>]` bucket if missing.\n *\n * V1: SERVER_CONFIG_KEYS is empty so this function is effectively\n * unreachable from typed call sites. Body is preserved for future\n * keys; per-key validators (e.g. shape checks for cached tokens)\n * should be re-added when keys re-enter the enum.\n */\nexport function setServerConfigValue(serverUrl: string, key: ServerConfigKey, value: string): void {\n\tif (typeof value !== 'string' || value.length === 0) {\n\t\tthrow new Error(`Config value for ${key} must be a non-empty string`);\n\t}\n\tconst config = readConfigFile();\n\tif (!config.servers) config.servers = {};\n\tif (!config.servers[serverUrl]) config.servers[serverUrl] = {};\n\tconfig.servers[serverUrl][key] = value;\n\twriteConfigFile(config);\n}\n\n/**\n * Remove one per-server config value. If the bucket becomes empty\n * after the delete, drop the bucket too — keeps the persisted JSON\n * canonical (no empty `{}` sitting around for servers the user has\n * since stopped using).\n */\nexport function unsetServerConfigValue(serverUrl: string, key: ServerConfigKey): void {\n\tconst config = readConfigFile();\n\tif (!config.servers?.[serverUrl]) return;\n\tdelete config.servers[serverUrl][key];\n\tif (Object.keys(config.servers[serverUrl]).length === 0) {\n\t\tdelete config.servers[serverUrl];\n\t}\n\tif (config.servers && Object.keys(config.servers).length === 0) {\n\t\tdelete config.servers;\n\t}\n\twriteConfigFile(config);\n}\n\n/* --------------------------------------------------------------- *\n * Snapshot helpers *\n * --------------------------------------------------------------- */\n\n/**\n * Full snapshot — used by `heyarp config list`. Only recognised keys\n * are returned; any garbage on disk is dropped at read time.\n */\nexport function listConfig(): ConfigFile {\n\treturn readConfigFile();\n}\n","import { type Envelope, canonicalBytes, sign as ed25519Sign } from '@heyanon-arp/sdk';\nimport { getGlobalConfigValue } from './config';\n\n/**\n * Default ARP server base — matches `apps/arp-server` local dev port\n * and global prefix (`/arp`). Override priority (high → low):\n * 1. `--server <url>` flag at the command level\n * 2. `ARP_SERVER_URL` environment variable\n * 3. `~/.arp/config.json`'s `server` field (`heyarp config set server …`)\n * 4. This built-in default\n */\nexport const DEFAULT_SERVER_URL = 'https://api.heyanon.ai/arp';\n\nexport interface ApiErrorBody {\n\tcode: string;\n\tmessage: string;\n\tdetails?: unknown;\n}\n\n/**\n * Thrown when the ARP server returns a structured `{ code, message }`\n * error body. CLI surface unwraps `.payload` and renders via\n * `formatApiError`; everything else is treated as a network error.\n */\nexport class ApiError extends Error {\n\tpublic readonly status: number;\n\tpublic readonly payload: ApiErrorBody;\n\n\tconstructor(status: number, payload: ApiErrorBody) {\n\t\tsuper(`${payload.code}: ${payload.message}`);\n\t\tthis.name = 'ApiError';\n\t\tthis.status = status;\n\t\tthis.payload = payload;\n\t}\n}\n\nexport interface ChallengeResponse {\n\tchallengeId: string;\n\tchallengeB64: string;\n\texpiresAt: string;\n}\n\nexport interface RegisterAgentRequest {\n\tchallengeId: string;\n\t// V1-alpha: accountId parked server-side. Server's register DTO no\n\t// longer requires it. Uncomment when launchpad↔ARP join lands.\n\t// accountId: string;\n\tidentityPublicKey: string;\n\tsettlementPublicKey: string;\n\tkeyMode: string;\n\townerAttestation: {\n\t\tpayload: Record<string, unknown>;\n\t\tsig: string;\n\t\tscrypt_salt_id: string;\n\t};\n\tscryptKeyB64: string;\n\tscryptSaltB64: string;\n\tname?: string;\n\tdescription?: string;\n\tdefaultEndpointUrl?: string;\n\t/** Capability tags — lowercase alphanumeric + dash/underscore, max 20. Used by the catalog endpoint for filtering. */\n\ttags?: string[];\n}\n\nexport interface DidDocument {\n\tid: string;\n\tverificationMethod: { id: string; type: string; controller: string; publicKeyMultibase: string }[];\n\tservice?: { id: string; type: string; serviceEndpoint: string }[];\n\tmetadata: { key_mode: string; owner_attestation_id: string; registered_at: string };\n}\n\n/**\n * V1.5 server response shape for\n * `GET /v1/escrow/protocol-fee`. Mirror of the on-chain ProgramState\n * fee/admin fields, refreshed live per request (no caching).\n */\nexport interface ProtocolFeeStatus {\n\tenabled: boolean;\n\tfeeBps: number;\n\tfeeRecipient: string;\n\tprogramId: string;\n\tclusterTag: number;\n\tpaused: boolean;\n\tadmin: string;\n}\n\nexport interface AgentRegisteredResponse {\n\tdid: string;\n\tdidDocument: DidDocument;\n}\n\n/**\n * Mirror of `AgentPublicDto` on the server. Returned by signed reads\n * + every lifecycle endpoint after the state transition lands.\n */\nexport interface AgentPublic {\n\tdid: string;\n\t// V1-alpha: accountId parked. Server's AgentPublicDto no longer\n\t// emits this field. Uncomment when launchpad↔ARP join lands.\n\t// accountId: string;\n\tidentityPublicKey: string;\n\tsettlementPublicKey: string;\n\tkeyMode: string;\n\tpublicationStatus: string;\n\tcurrentAttestationId: string;\n\tname?: string;\n\tdescription?: string;\n\tdefaultEndpointUrl?: string;\n\t/** Capability tags — always present (empty array when none). */\n\ttags: string[];\n\tregisteredAt: string;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\nexport interface UpdateAgentBody {\n\tname?: string;\n\tdescription?: string;\n\tdefaultEndpointUrl?: string;\n\t/** Capability tags — present REPLACES the whole list (send `[]` to clear). Omit to leave as-is. */\n\ttags?: string[];\n}\n\n/**\n * Mirror of `AgentCatalogDto` on the server. Returned by the public\n * `GET /v1/agents` discovery endpoint — strict subset of `AgentPublic`\n * (no accountId, no key material) tailored for callers shopping\n * for a counterparty.\n */\nexport interface AgentCatalog {\n\tid: string;\n\tdid: string;\n\tpublicationStatus: string;\n\tname?: string;\n\tdescription?: string;\n\ttags: string[];\n\tdefaultEndpointUrl?: string;\n\tregisteredAt: string;\n}\n\n/**\n * Filters for `GET /v1/agents`. All optional; `tag` AND-composes\n * (an agent must carry every supplied tag), `q` flips on full-text\n * search over name + description, `after` is the ObjectId cursor\n * from the previous page's last row.\n */\nexport interface ListAgentsQuery {\n\ttag?: string[];\n\tq?: string;\n\tlimit?: number;\n\tafter?: string;\n}\n\nexport interface RotateIdentityKeyBody {\n\tchallengeId: string;\n\tnewIdentityPublicKey: string;\n\tnewKeyAttestation: {\n\t\tpayload: Record<string, unknown>;\n\t\tsig: string;\n\t\tscrypt_salt_id: string;\n\t};\n}\n\n/**\n * Mirror of `IngestResultDto` on the server. Returned from\n * `POST /v1/messages` (HTTP 202) once the envelope has been validated\n * and a chain index allocated for the relationship.\n *\n * `prevServerEventHash` is `null` only for `relationshipEventIndex === 0`\n * — i.e. the very first event of a freshly created relationship.\n */\nexport interface IngestResult {\n\teventId: string;\n\trelationshipEventIndex: number;\n\tprevServerEventHash: string | null;\n\tsignedMessageHash: string;\n\tserverEventHash: string;\n\tserverTimestamp: string;\n\trelationshipId: string;\n}\n\n/**\n * Mirror of `RelationshipPublicDto` on the server. Returned from\n * `GET /v1/agents/:did/relationships`. `pairDidA` / `pairDidB` are the\n * lexicographically-ordered pair (A < B) — the caller is one of them.\n */\nexport interface RelationshipPublic {\n\trelationshipId: string;\n\tpairDidA: string;\n\tpairDidB: string;\n\tstate: 'pending' | 'active' | 'paused' | 'closed';\n\tlastEventIndex: number;\n\tlastServerEventHash: string | null;\n\tlastEventAt: string | null;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\n/**\n * Mirror of `EventPublicDto` on the server. Returned from inbox\n * (`GET /v1/agents/:did/inbox`) and per-relationship event listings\n * (`GET /v1/relationships/:id/events`). Includes the FULL canonical\n * envelope so the receiver can re-canonicalise + re-verify the\n * signature locally via the SDK without trusting any server-denormalised\n * field, plus the chain coordinates for audit walks.\n */\nexport interface EventPublic {\n\teventId: string;\n\tmessageId: string;\n\tsenderDid: string;\n\trecipientDid: string;\n\trelationshipId: string;\n\tsenderSequence: number;\n\tprotocolVersion: string;\n\tpurpose: string;\n\ttype: 'handshake' | 'handshake_response' | 'contract' | 'delegation' | 'work_request' | 'work_response' | 'receipt' | 'memory_delta' | 'dispute' | string;\n\tprotectedBlock: Record<string, unknown>;\n\tbody: Record<string, unknown>;\n\tattachments?: Record<string, unknown>;\n\tsenderSignature: string;\n\trelationshipEventIndex: number;\n\tprevServerEventHash: string | null;\n\tserverTimestamp: string;\n\tsignedMessageHash: string;\n\tserverEventHash: string;\n\t// Read-model outcome. `'rejected'` means the envelope was committed\n\t// to the chain (replay defence consumed `sender_sequence`) but the\n\t// body-type dispatcher threw post-commit, so no contract /\n\t// delegation / work_log / receipt row reflects this event. Legacy\n\t// events written before this field existed come back as\n\t// `'materialized'` via the schema default.\n\treadModelStatus: 'materialized' | 'rejected';\n}\n\n/**\n * Query params for `GET /v1/agents/:did/relationships`. Mirrors\n * `ListRelationshipsQueryDto` on the server.\n */\nexport interface ListRelationshipsQuery {\n\tstate?: 'pending' | 'active' | 'paused' | 'closed';\n\tlimit?: number;\n}\n\n/**\n * Query params for `GET /v1/agents/:did/inbox`. Mirrors\n * `ListInboxQueryDto` on the server.\n *\n * Two cursors:\n * - `(before, beforeEventId)` — walk BACK through history. Pass the\n * previous page's last `serverTimestamp` + `eventId` to avoid\n * skipping events that share a millisecond.\n * - `(since, sinceEventId)` — forward cursor. Pass the last event\n * a polling worker already handled so the next iteration skips\n * it (defeats double-fire on a re-run).\n */\nexport interface ListInboxQuery {\n\tbefore?: string;\n\tbeforeEventId?: string;\n\tsince?: string;\n\tsinceEventId?: string;\n\tlimit?: number;\n}\n\n/**\n * Query params for `GET /v1/relationships/:id/events`. Mirrors\n * `ListEventsQueryDto` on the server.\n */\nexport interface ListEventsQuery {\n\tsince?: number;\n\tlimit?: number;\n\t// Server-side filter on the read-model outcome so\n\t// `--rejected-only` / `--success-only` page through matching rows\n\t// correctly regardless of `limit`.\n\treadModelStatus?: 'materialized' | 'rejected';\n}\n\n/**\n * Mirror of the server's `AssetIdentifierDto` — embedded on\n * `ContractPublic.rateCurrency` and `DelegationPublic.currency`.\n * Wire shape is camelCase (DTO convention); the canonical envelope\n * body uses snake_case (`asset_id`) — the CLI's emit helpers handle\n * the conversion at the wire boundary.\n */\nexport interface AssetIdentifierWire {\n\t/** CAIP-19 chain-qualified asset id. */\n\tassetId: string;\n\t/** Decimals 0-18, used for amount → base-unit conversion. */\n\tdecimals: number;\n\t/** Optional UI hint (\"USDC\", \"SOL\"). */\n\tsymbol?: string;\n}\n\n/**\n * Mirror of `ContractPublicDto` on the server. Returned from\n * `GET /v1/relationships/:id/contracts`. One row per\n * `(contractId, version)` — a propose / counter / counter chain\n * shows up as multiple rows. `id` is the per-row server identifier\n * and the cursor for `?after=` pagination (opaque hex string —\n * don't parse).\n */\nexport interface ContractPublic {\n\tid: string;\n\tcontractId: string;\n\tversion: number;\n\trelationshipId: string;\n\tproposerDid: string;\n\tstate: 'proposed' | 'active' | 'replaced' | 'declined';\n\tscopeSummary?: string;\n\t// Narrowed from the broader {flat|quote|subscription|usage_based}\n\t// set. `quote` + `subscription` were never wired into the settlement\n\t// layer and have been dropped.\n\tpricingModel?: 'flat' | 'usage_based';\n\tsettlementModel?: 'prepaid' | 'escrow';\n\trateAmount?: string;\n\trateCurrency?: AssetIdentifierWire;\n\trateUnit?: 'task' | 'thread' | 'handoff';\n\tallowedDelegationTags?: string[];\n\tcreatedAt: string;\n\tupdatedAt: string;\n\t/** Machine-readable decline reason — present only on DECLINED rows. */\n\tdeclineReason?: string | null;\n\t/** Optional free-text elaboration that accompanied `declineReason`. */\n\tdeclineReasonDetail?: string | null;\n}\n\n/**\n * Query params for `GET /v1/relationships/:id/contracts`. Mirrors\n * `ListContractsQueryDto` on the server.\n *\n * `after` is the opaque per-row cursor — pass the previous page's\n * last `ContractPublic.id` to fetch the next page. The server runs\n * a composite `(createdAt, _id)` predicate matching its sort, so\n * pagination is consistent across multi-process deployments.\n */\nexport interface ListContractsQuery {\n\tstate?: ContractPublic['state'];\n\tafter?: string;\n\tlimit?: number;\n}\n\n/**\n * Mirror of `DelegationPublicDto` on the server. Returned from\n * `GET /v1/relationships/:id/delegations`. One row per\n * `delegationId` (delegations are single-version — re-negotiation\n * is a fresh `delegationId` referencing the same `contractId`).\n *\n * `id` is the per-row server identifier and the cursor for\n * `?after=` pagination (opaque hex string — don't parse).\n */\nexport interface DelegationPublic {\n\tid: string;\n\tdelegationId: string;\n\tcontractId: string;\n\trelationshipId: string;\n\toffererDid: string;\n\t// Delegation lifecycle states emitted by the server:\n\t// - `'offered'` — awaiting buyer acceptance.\n\t// - `'pending_lock_finalization'` — transient state while the\n\t// server waits for the on-chain create_lock tx to confirm.\n\t// The CLI's status walker treats it the same as `'offered'`.\n\t// - `'accepted'` — buyer cosigned; work can begin.\n\t// - `'awaiting_release_finalization'` — transient state while the\n\t// relayer submits release_lock after receipt cosign.\n\t// - `'completed'` — on-chain release confirmed. The\n\t// `cycle.released` phase (`status --until cycle.released`)\n\t// matches this state.\n\t// - `'declined'` / `'canceled'` — explicit lifecycle exits.\n\t// - `'failed'` — escrow worker rejected the lock tx (e.g.\n\t// ProgramState uninitialised).\n\t// - `'refunded'` — lock refunded back to the payer post-expiry.\n\t// - `'dispute_resolved'` — admin closed the delegation via the\n\t// dispute path.\n\t// All terminal failure modes must be present in the union so\n\t// the FSM walker has an explicit branch instead of falling\n\t// through to \"ACCEPTED — work request needed\" hints.\n\tstate:\n\t\t| 'proposed'\n\t\t| 'offered'\n\t\t| 'pending_lock_finalization'\n\t\t| 'accepted'\n\t\t| 'awaiting_release_finalization'\n\t\t| 'completed'\n\t\t| 'declined'\n\t\t| 'canceled'\n\t\t| 'failed'\n\t\t| 'refunded'\n\t\t| 'dispute_resolved';\n\ttitle?: string;\n\tbrief?: Record<string, unknown>;\n\tacceptanceCriteria?: string[];\n\tdeadline?: string;\n\tamount?: string;\n\tcurrency?: AssetIdentifierWire;\n\tcreatedAt: string;\n\tupdatedAt: string;\n\t/** Machine-readable decline reason — present only on DECLINED rows. */\n\tdeclineReason?: string | null;\n\t/** Optional free-text elaboration that accompanied `declineReason`. */\n\tdeclineReasonDetail?: string | null;\n}\n\n/**\n * Query params for `GET /v1/relationships/:id/delegations`. Mirrors\n * `ListDelegationsQueryDto` on the server.\n */\nexport interface ListDelegationsQuery {\n\tstate?: DelegationPublic['state'];\n\tcontractId?: string;\n\tafter?: string;\n\tlimit?: number;\n}\n\n/**\n * Mirror of `WorkLogPublicDto` on the server. Returned from\n * `GET /v1/relationships/:id/work`. One row per\n * `(delegationId, requestId)` — every work_request creates a row\n * in REQUESTED, and the matching work_response promotes it to\n * RESPONDED stamping `responseOutput` xor `responseError`.\n */\nexport interface WorkLogPublic {\n\tid: string;\n\tdelegationId: string;\n\trequestId: string;\n\trelationshipId: string;\n\tcallerDid: string;\n\tpayeeDid: string;\n\tstate: 'requested' | 'responded';\n\trequestParams: Record<string, unknown>;\n\tresponseOutput?: Record<string, unknown>;\n\tresponseError?: { code: string; message: string };\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\n/**\n * Query params for `GET /v1/relationships/:id/work`. Mirrors\n * `ListWorkLogsQueryDto` on the server.\n */\nexport interface ListWorkLogsQuery {\n\tstate?: WorkLogPublic['state'];\n\tdelegationId?: string;\n\tafter?: string;\n\tlimit?: number;\n}\n\n/**\n * Mirror of `ReceiptPublicDto` on the server. Returned from\n * `GET /v1/relationships/:id/receipts`. One row per\n * `(delegationId, requestHash, responseHash)` triple. PROPOSED\n * after the payee issues the receipt; COSIGNED after the caller\n * countersigns. `verdictFinal` mirrors `verdictProposed` while\n * PROPOSED, may be overruled by the cosign payload on COSIGNED.\n *\n * `receiptEventHash` is the chain hash of the original (PROPOSED)\n * receipt event — the cosign payload binds to it, so consumers\n * can re-verify the cosignature locally via the SDK.\n *\n * The field is deliberately named `receiptEventHash` (not\n * `serverEventHash`) to disambiguate from the generic\n * chain-envelope `serverEventHash` on every `EventPublic` row from\n * `GET /events`. The values are the same — the receipt row's\n * `receiptEventHash` IS the chain `serverEventHash` of that receipt\n * envelope — but the row-scoped name keeps JSON grep-able and\n * avoids \"is this for the receipt or for a different event?\"\n * ambiguity. Scripts pulling from `heyarp receipts --json` MUST\n * use `.receiptEventHash`; `.serverEventHash` silently returns null\n * because the row does not carry that key.\n */\nexport interface ReceiptPublic {\n\tid: string;\n\tdelegationId: string;\n\trelationshipId: string;\n\tpayeeDid: string;\n\tcallerDid: string;\n\trequestHash: string;\n\tresponseHash: string;\n\tverdictProposed: 'accepted' | 'accepted_with_notes' | 'rejected';\n\tverdictFinal?: 'accepted' | 'accepted_with_notes' | 'rejected';\n\tusage?: {\n\t\tinput_tokens?: number;\n\t\toutput_tokens?: number;\n\t\tlatency_ms?: number;\n\t\tmodel?: string;\n\t\tcomputed_amount?: string;\n\t};\n\tdeliverableHash?: string;\n\tnotesHash?: string;\n\treceiptEventHash: string;\n\tstate: 'proposed' | 'cosigned';\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\n/**\n * Query params for `GET /v1/relationships/:id/receipts`. Mirrors\n * `ListReceiptsQueryDto` on the server.\n */\nexport interface ListReceiptsQuery {\n\tstate?: ReceiptPublic['state'];\n\tdelegationId?: string;\n\tafter?: string;\n\tlimit?: number;\n}\n\n/**\n * Mirror of `MemoryEntryPublicDto` on the server. One row per\n * committed memory delta (immediate writes land directly;\n * settlement-gated writes are promoted from `memory_pending`\n * by the SettlementEventBus subscriber). `id` is the per-row\n * server identifier and the cursor for `?after=` pagination.\n *\n * `signedBy` is the array of identity-key signatures over the\n * memory content. V1 unilateral writes carry one entry (the\n * author); V1.5+ cosigned writes would carry both parties' sigs.\n * `isCosigned` is the derived flag (`signedBy.length >= 2`).\n *\n * `delegationId` is null on `commit_after: immediate` writes\n * and non-null on settlement-gated writes (the delegation whose\n * release event gated the commit).\n */\nexport interface MemoryEntryPublic {\n\tid: string;\n\trelationshipId: string;\n\tauthorDid: string;\n\tkind: string;\n\tscope: string;\n\tcontent: string;\n\tsignedBy: { did: string; sig: string }[];\n\tisCosigned: boolean;\n\tsourceEventId: string;\n\tdelegationId?: string | null;\n\tsupersedesId?: string | null;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\n/**\n * Server query filters for `GET /v1/relationships/:id/memory` and\n * `GET /v1/agents/:did/memory`. Mirrors `ListMemoryQueryDto` on\n * the server.\n */\nexport interface ListMemoryQuery {\n\tkind?: string;\n\tscope?: string;\n\tauthorDid?: string;\n\tafter?: string;\n\tlimit?: number;\n}\n\nexport interface Signer {\n\tdid: string;\n\tidentitySecretKey: Uint8Array;\n}\n\n/**\n * Resolve the ARP server base URL. Strips a trailing `/` so callers\n * can confidently template `${base}${path}` without doubling slashes.\n *\n * Resolution priority (high → low):\n * 1. `override` argument (the per-command `--server` flag)\n * 2. `ARP_SERVER_URL` env var\n * 3. `~/.arp/config.json`'s `server` field\n * 4. `DEFAULT_SERVER_URL`\n *\n * Same chain as `npm config get registry`: flag > env > userconfig >\n * builtin. Lets a developer set the server once via\n * `heyarp config set server …` and forget about `--server` everywhere.\n */\nexport function resolveServerUrl(override?: string): string {\n\tconst raw = override ?? process.env.ARP_SERVER_URL ?? getGlobalConfigValue('server') ?? DEFAULT_SERVER_URL;\n\treturn raw.endsWith('/') ? raw.slice(0, -1) : raw;\n}\n\n/**\n * Extract the URL path portion of the configured server base — that\n * is what the SignedRequestGuard expects to recompute from\n * `request.path` (Express). For `http://localhost:3000/arp`, returns\n * `/arp`; for a bare host, returns ''.\n */\nfunction basePath(serverUrl: string): string {\n\ttry {\n\t\tconst u = new URL(serverUrl);\n\t\tconst p = u.pathname.endsWith('/') ? u.pathname.slice(0, -1) : u.pathname;\n\t\treturn p === '' ? '' : p;\n\t} catch {\n\t\treturn '';\n\t}\n}\n\nexport class ArpApiClient {\n\tpublic readonly serverUrl: string;\n\tpublic readonly basePath: string;\n\n\tconstructor(serverUrl?: string) {\n\t\tthis.serverUrl = resolveServerUrl(serverUrl);\n\t\tthis.basePath = basePath(this.serverUrl);\n\t}\n\n\tasync issueChallenge(purpose: 'register' | 'rotate' = 'register'): Promise<ChallengeResponse> {\n\t\treturn this.post<ChallengeResponse>('/v1/agents/challenge', { purpose });\n\t}\n\n\tasync submitChallengeResponse(input: { challengeId: string; identityPublicKey: string; signature: string }): Promise<void> {\n\t\tawait this.post<void>('/v1/agents/challenge-response', input, { expectStatus: 204 });\n\t}\n\n\tasync register(input: RegisterAgentRequest): Promise<AgentRegisteredResponse> {\n\t\treturn this.post<AgentRegisteredResponse>('/v1/agents/register', input);\n\t}\n\n\tasync getDidDocument(did: string): Promise<DidDocument> {\n\t\treturn this.get<DidDocument>(`/v1/agents/${encodeURIComponent(did)}/did-document`);\n\t}\n\n\t/**\n\t * Public `GET /v1/escrow/protocol-fee`. Returns the V1.5 on-chain\n\t * ProgramState fee config (enabled flag, fee_bps, fee_recipient)\n\t * so operators can sanity-check before locking.\n\t * Unauthenticated — derived from on-chain state which is already\n\t * public.\n\t */\n\tasync getProtocolFee(): Promise<ProtocolFeeStatus> {\n\t\treturn this.get<ProtocolFeeStatus>('/v1/escrow/protocol-fee');\n\t}\n\n\t/**\n\t * Public `GET /v1/agents` — discovery / marketplace catalog.\n\t * Unauthenticated. Server pins `publicationStatus = active` so\n\t * drafts / paused agents never appear here.\n\t *\n\t * Filters AND-compose: pass multiple tags to require all of them,\n\t * combine with `q` for free-text. `after` is the `id` of the\n\t * previous page's last row; the server's cursor predicate matches\n\t * its `(createdAt ASC, _id ASC)` sort.\n\t */\n\tpublic async listAgents(query?: ListAgentsQuery): Promise<AgentCatalog[]> {\n\t\tconst params = new URLSearchParams();\n\t\tif (query?.tag) {\n\t\t\t// `appendAll` semantics: each `?tag=foo&tag=bar` value goes\n\t\t\t// in as a separate entry, which is what Express's qs parser\n\t\t\t// re-hydrates into an array on the server.\n\t\t\tfor (const t of query.tag) params.append('tag', t);\n\t\t}\n\t\tif (query?.q !== undefined) params.set('q', query.q);\n\t\tif (query?.limit !== undefined) params.set('limit', String(query.limit));\n\t\tif (query?.after !== undefined) params.set('after', query.after);\n\t\tconst qs = params.toString();\n\t\tconst path = qs ? `/v1/agents?${qs}` : '/v1/agents';\n\t\treturn this.get<AgentCatalog[]>(path);\n\t}\n\n\t/**\n\t * Signed-request authenticated GET /v1/agents/:did. Owner-only on\n\t * the server side, but in V1 it returns the same shape as\n\t * /did-document — useful as a sanity check that a stored secret\n\t * key still verifies.\n\t */\n\tasync getAgent(did: string, signer: Signer): Promise<AgentPublic> {\n\t\treturn this.signedRequest<AgentPublic>('GET', `/v1/agents/${encodeURIComponent(did)}`, null, signer);\n\t}\n\n\tasync updateAgent(did: string, body: UpdateAgentBody, signer: Signer): Promise<AgentPublic> {\n\t\treturn this.signedRequest<AgentPublic>('PATCH', `/v1/agents/${encodeURIComponent(did)}`, body, signer);\n\t}\n\n\tasync publishAgent(did: string, signer: Signer): Promise<AgentPublic> {\n\t\treturn this.signedRequest<AgentPublic>('POST', `/v1/agents/${encodeURIComponent(did)}/publish`, {}, signer);\n\t}\n\n\tasync pauseAgent(did: string, signer: Signer): Promise<AgentPublic> {\n\t\treturn this.signedRequest<AgentPublic>('POST', `/v1/agents/${encodeURIComponent(did)}/pause`, {}, signer);\n\t}\n\n\tasync unpauseAgent(did: string, signer: Signer): Promise<AgentPublic> {\n\t\treturn this.signedRequest<AgentPublic>('POST', `/v1/agents/${encodeURIComponent(did)}/unpause`, {}, signer);\n\t}\n\n\tasync rotateIdentityKey(did: string, body: RotateIdentityKeyBody, signer: Signer): Promise<AgentPublic> {\n\t\treturn this.signedRequest<AgentPublic>('POST', `/v1/agents/${encodeURIComponent(did)}/rotate-identity-key`, body, signer);\n\t}\n\n\t/**\n\t * Ingest a signed envelope. Endpoint is public (no\n\t * `X-ARP-Signer-DID` headers) — authentication is the envelope's\n\t * own `sender_signature`, which the server validates against the\n\t * sender's current identity key.\n\t *\n\t * Returns 202 on success. Body validation, signature verification,\n\t * and chain assignment all happen synchronously before the response\n\t * leaves, so the chain coordinates in the result are durable.\n\t */\n\tasync ingest(envelope: Envelope): Promise<IngestResult> {\n\t\treturn this.post<IngestResult>('/v1/messages', envelope, { expectStatus: 202 });\n\t}\n\n\t/**\n\t * Signed `GET /v1/agents/:did/inbox/stream` — long-lived SSE\n\t * connection that yields each new envelope as it lands plus\n\t * periodic heartbeats. Returns an async generator so callers\n\t * can `for await` and clean up via `break` (which closes the\n\t * underlying fetch connection — abort signal handling).\n\t *\n\t * Each yielded event has shape `{ type: 'connected' | 'envelope' | 'heartbeat', data: unknown, id?: string }`.\n\t * The caller decides what to do with each type — typically:\n\t * - `connected`: print \"stream open\" status\n\t * - `envelope`: parse `data` as `EventPublic` and surface\n\t * - `heartbeat`: ignore\n\t */\n\tpublic async *streamInbox(\n\t\tdid: string,\n\t\tsigner: Signer,\n\t\toptions?: { signal?: AbortSignal; relationshipId?: string },\n\t): AsyncGenerator<{ type: string; data: unknown; id?: string }> {\n\t\t// Path layering matches the rest of the client:\n\t\t// `path` is the wire URL path AFTER serverUrl (no basePath\n\t\t// prefix — fetch composes it via `${serverUrl}${path}`).\n\t\t// `fullPath` is what SignedRequestGuard recomputes from\n\t\t// Express's `request.path`, which DOES include the global\n\t\t// `/arp` prefix — that's what we sign.\n\t\tconst path = `/v1/agents/${encodeURIComponent(did)}/inbox/stream`;\n\t\tconst fullPath = `${this.basePath}${path}`;\n\t\t// Optional `?relationshipId=` filter for single-rel watch.\n\t\t// The query MUST appear in BOTH the signing input AND the URL\n\t\t// — server's `SignedRequestGuard` recomputes the canonical hash\n\t\t// from Express's parsed `req.query`; a missing key on either\n\t\t// side fails the comparison.\n\t\tconst query: Record<string, string> = {};\n\t\tif (options?.relationshipId) query.relationshipId = options.relationshipId;\n\t\tconst signingInput = canonicalBytes({ method: 'GET', path: fullPath, query, body: null });\n\t\tconst sigBytes = ed25519Sign(signingInput, signer.identitySecretKey);\n\t\tconst sigB64 = Buffer.from(sigBytes).toString('base64');\n\n\t\tconst wireQuery = Object.keys(query).length > 0 ? `?${new URLSearchParams(query).toString()}` : '';\n\t\tconst url = `${this.serverUrl}${path}${wireQuery}`;\n\t\tconst res = await fetch(url, {\n\t\t\tmethod: 'GET',\n\t\t\theaders: {\n\t\t\t\tAccept: 'text/event-stream',\n\t\t\t\t'X-ARP-Signer-DID': signer.did,\n\t\t\t\t'X-ARP-Signature': `ed25519:${sigB64}`,\n\t\t\t},\n\t\t\tsignal: options?.signal,\n\t\t});\n\t\tif (!res.ok || !res.body) {\n\t\t\tconst errBody = await res.text().catch(() => '');\n\t\t\tthrow new Error(`streamInbox: server returned ${res.status} ${res.statusText} — ${errBody}`);\n\t\t}\n\n\t\t// SSE wire format: records are separated by a blank line.\n\t\t// The blank-line separator is `\\n\\n` on most servers but\n\t\t// can arrive as `\\r\\n\\r\\n` through HTTP intermediaries\n\t\t// that normalise to CRLF. Normalise CRLF → LF on the\n\t\t// stream so the record split has one shape to handle.\n\t\tconst decoder = new TextDecoder('utf-8');\n\t\tconst reader = res.body.getReader();\n\t\tlet buffer = '';\n\t\ttry {\n\t\t\twhile (true) {\n\t\t\t\tconst { value, done } = await reader.read();\n\t\t\t\tif (done) break;\n\t\t\t\tbuffer += decoder.decode(value, { stream: true }).replace(/\\r\\n/g, '\\n');\n\t\t\t\tlet recordEnd = buffer.indexOf('\\n\\n');\n\t\t\t\twhile (recordEnd !== -1) {\n\t\t\t\t\tconst record = buffer.slice(0, recordEnd);\n\t\t\t\t\tbuffer = buffer.slice(recordEnd + 2);\n\t\t\t\t\tconst event = parseSseRecord(record);\n\t\t\t\t\tif (event !== null) yield event;\n\t\t\t\t\trecordEnd = buffer.indexOf('\\n\\n');\n\t\t\t\t}\n\t\t\t}\n\t\t} finally {\n\t\t\t// Caller `break`-ed out of the for-await OR fetch errored.\n\t\t\t// Either way, drop the reader so the underlying connection\n\t\t\t// is released back to the pool / closed.\n\t\t\ttry {\n\t\t\t\tawait reader.cancel();\n\t\t\t} catch {\n\t\t\t\t// Best-effort.\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Signed `GET /v1/agents/:did/relationships`. Owner-only on the\n\t * server; signer DID must match the path DID. Returns the caller's\n\t * relationships ordered by `lastEventAt` desc.\n\t */\n\tpublic async listRelationships(did: string, signer: Signer, query?: ListRelationshipsQuery, signal?: AbortSignal): Promise<RelationshipPublic[]> {\n\t\treturn this.signedRequest<RelationshipPublic[]>(\n\t\t\t'GET',\n\t\t\t`/v1/agents/${encodeURIComponent(did)}/relationships`,\n\t\t\tnull,\n\t\t\tsigner,\n\t\t\tquery as Record<string, string | number | boolean | undefined> | undefined,\n\t\t\tsignal,\n\t\t);\n\t}\n\n\t/**\n\t * Public, no-auth probe for the most recent event timestamp where\n\t * this DID is sender or recipient. `heyarp doctor` uses this to\n\t * elevate inbox-driven workers (no HTTP listener) from DORMANT →\n\t * LISTENING.\n\t *\n\t * 404 when the DID is unknown; `lastEventAt: null` when the DID is\n\t * known but has never been party to an event.\n\t */\n\tpublic async getActivitySummary(did: string): Promise<{ lastEventAt: string | null; asOf: string; inboxStreamActive?: boolean }> {\n\t\t// `inboxStreamActive` is optional on the response type so\n\t\t// older servers (which return `{lastEventAt, asOf}` only)\n\t\t// still type-check.\n\t\treturn this.get<{ lastEventAt: string | null; asOf: string; inboxStreamActive?: boolean }>(\n\t\t\t`/v1/agents/${encodeURIComponent(did)}/activity-summary`,\n\t\t);\n\t}\n\n\t/**\n\t * Signed `GET /v1/agents/:did/sender-sequence`. Returns the highest\n\t * `sender_sequence` the server has accepted from this signer. Used\n\t * by `heyarp escrow recover-sequence` to repair a desynced local\n\t * `lastSenderSequence` after a post-commit failure the CLI could\n\t * not auto-classify (e.g. `INTERNAL_SERVER_ERROR`).\n\t *\n\t * Owner-only on the server; signer DID must match the path DID.\n\t * Returns 0 when the agent has never sent an envelope.\n\t */\n\tpublic async getSenderSequence(did: string, signer: Signer): Promise<{ lastSenderSequence: number }> {\n\t\treturn this.signedRequest<{ lastSenderSequence: number }>('GET', `/v1/agents/${encodeURIComponent(did)}/sender-sequence`, null, signer);\n\t}\n\n\t/**\n\t * Signed `GET /v1/agents/:did/inbox`. Cross-relationship feed of\n\t * events where `did` is the recipient, ordered by `serverTimestamp`\n\t * desc. Pair `before` with `beforeEventId` for tie-breaking on\n\t * same-millisecond pages. The `since` + `sinceEventId` cursor\n\t * walks FORWARD from a watermark (polling-worker pattern).\n\t */\n\tpublic async listInbox(did: string, signer: Signer, query?: ListInboxQuery): Promise<EventPublic[]> {\n\t\treturn this.signedRequest<EventPublic[]>(\n\t\t\t'GET',\n\t\t\t`/v1/agents/${encodeURIComponent(did)}/inbox`,\n\t\t\tnull,\n\t\t\tsigner,\n\t\t\tquery as Record<string, string | number | boolean | undefined> | undefined,\n\t\t);\n\t}\n\n\t/**\n\t * Signed `GET /v1/agents/:did/events/:eventId`. Direct envelope\n\t * lookup by `eventId` — for operators who already know the id (from\n\t * an earlier `inbox` / `events` listing or from a counterparty\n\t * citation) and want to inspect the full canonical envelope without\n\t * re-pulling a whole relationship chain.\n\t *\n\t * Auth: signer must equal `did`, AND `did` must be sender or\n\t * recipient of the event. 404 on unknown id; 403 on\n\t * not-a-member-of-pair.\n\t */\n\tpublic async getEvent(did: string, eventId: string, signer: Signer): Promise<EventPublic> {\n\t\treturn this.signedRequest<EventPublic>('GET', `/v1/agents/${encodeURIComponent(did)}/events/${encodeURIComponent(eventId)}`, null, signer);\n\t}\n\n\t/**\n\t * Signed `GET /v1/relationships/:id/events`. Returns the canonical\n\t * chain order (ascending `relationshipEventIndex`). Signer must be\n\t * one of the relationship pair.\n\t */\n\tpublic async listEvents(relationshipId: string, signer: Signer, query?: ListEventsQuery): Promise<EventPublic[]> {\n\t\treturn this.signedRequest<EventPublic[]>(\n\t\t\t'GET',\n\t\t\t`/v1/relationships/${encodeURIComponent(relationshipId)}/events`,\n\t\t\tnull,\n\t\t\tsigner,\n\t\t\tquery as Record<string, string | number | boolean | undefined> | undefined,\n\t\t);\n\t}\n\n\t/**\n\t * Signed `GET /v1/relationships/:id/contracts`. One row per\n\t * `(contractId, version)`, ordered chronologically (oldest-first)\n\t * with `_id` as the deterministic tie-breaker. Signer must be one\n\t * of the relationship pair.\n\t *\n\t * Pagination cursor: pass the previous page's last\n\t * `ContractPublic.id` as `query.after`.\n\t */\n\tpublic async listContracts(relationshipId: string, signer: Signer, query?: ListContractsQuery, signal?: AbortSignal): Promise<ContractPublic[]> {\n\t\treturn this.signedRequest<ContractPublic[]>(\n\t\t\t'GET',\n\t\t\t`/v1/relationships/${encodeURIComponent(relationshipId)}/contracts`,\n\t\t\tnull,\n\t\t\tsigner,\n\t\t\tquery as Record<string, string | number | boolean | undefined> | undefined,\n\t\t\tsignal,\n\t\t);\n\t}\n\n\t/**\n\t * Signed `GET /v1/relationships/:id/delegations`. One row per\n\t * `delegationId`, ordered chronologically with the same composite\n\t * `(createdAt, _id)` cursor as `listContracts`. Signer must be\n\t * one of the relationship pair. Optional `contractId` filter\n\t * narrows to delegations operating under a single contract\n\t * umbrella.\n\t */\n\tpublic async listDelegations(relationshipId: string, signer: Signer, query?: ListDelegationsQuery, signal?: AbortSignal): Promise<DelegationPublic[]> {\n\t\treturn this.signedRequest<DelegationPublic[]>(\n\t\t\t'GET',\n\t\t\t`/v1/relationships/${encodeURIComponent(relationshipId)}/delegations`,\n\t\t\tnull,\n\t\t\tsigner,\n\t\t\tquery as Record<string, string | number | boolean | undefined> | undefined,\n\t\t\tsignal,\n\t\t);\n\t}\n\n\t/**\n\t * Signed `GET /v1/relationships/:id/work`. One row per\n\t * `(delegationId, requestId)`, ordered chronologically with the\n\t * same composite cursor as `listContracts` / `listDelegations`.\n\t * Signer must be one of the relationship pair. Optional\n\t * `delegationId` filter narrows to work-logs operating under a\n\t * single delegation umbrella.\n\t */\n\tpublic async listWorkLogs(relationshipId: string, signer: Signer, query?: ListWorkLogsQuery): Promise<WorkLogPublic[]> {\n\t\treturn this.signedRequest<WorkLogPublic[]>(\n\t\t\t'GET',\n\t\t\t`/v1/relationships/${encodeURIComponent(relationshipId)}/work`,\n\t\t\tnull,\n\t\t\tsigner,\n\t\t\tquery as Record<string, string | number | boolean | undefined> | undefined,\n\t\t);\n\t}\n\n\t/**\n\t * Signed `GET /v1/relationships/:id/receipts`. One row per\n\t * `(delegationId, requestHash, responseHash)`, ordered\n\t * chronologically with the same composite cursor as the other\n\t * relationship-scoped lists. Signer must be one of the\n\t * relationship pair.\n\t */\n\tpublic async listReceipts(relationshipId: string, signer: Signer, query?: ListReceiptsQuery): Promise<ReceiptPublic[]> {\n\t\treturn this.signedRequest<ReceiptPublic[]>(\n\t\t\t'GET',\n\t\t\t`/v1/relationships/${encodeURIComponent(relationshipId)}/receipts`,\n\t\t\tnull,\n\t\t\tsigner,\n\t\t\tquery as Record<string, string | number | boolean | undefined> | undefined,\n\t\t);\n\t}\n\n\t/**\n\t * Signed `GET /v1/relationships/:id/memory`. Committed memory\n\t * entries scoped to one relationship, newest first. Signer must\n\t * be one of the relationship pair. V1 ships only the tag-style\n\t * filters (`kind`, `scope`, `authorDid`); vector search (`?q=`)\n\t * is V1.5+ work.\n\t */\n\tpublic async listRelationshipMemory(relationshipId: string, signer: Signer, query?: ListMemoryQuery): Promise<MemoryEntryPublic[]> {\n\t\treturn this.signedRequest<MemoryEntryPublic[]>(\n\t\t\t'GET',\n\t\t\t`/v1/relationships/${encodeURIComponent(relationshipId)}/memory`,\n\t\t\tnull,\n\t\t\tsigner,\n\t\t\tquery as Record<string, string | number | boolean | undefined> | undefined,\n\t\t);\n\t}\n\n\t/**\n\t * Signed `GET /v1/agents/:did/memory`. Memory entries authored\n\t * by `:did`. Signer MUST equal the path DID — memory authored\n\t * by another agent is read via the relationship-scoped list.\n\t * Server returns `[]` (not 403) when the caller asks about a\n\t * different DID, so the endpoint can't be used to probe\n\t * existence.\n\t */\n\tpublic async listAgentMemory(did: string, signer: Signer, query?: ListMemoryQuery): Promise<MemoryEntryPublic[]> {\n\t\treturn this.signedRequest<MemoryEntryPublic[]>(\n\t\t\t'GET',\n\t\t\t`/v1/agents/${encodeURIComponent(did)}/memory`,\n\t\t\tnull,\n\t\t\tsigner,\n\t\t\tquery as Record<string, string | number | boolean | undefined> | undefined,\n\t\t);\n\t}\n\n\t/**\n\t * Signed `GET /v1/memory/:entryId`. Fetch one row by its Mongo\n\t * `_id` (hex). Server returns 404 (not 403) when the caller is\n\t * NOT a member of the relationship — masks existence, so the\n\t * endpoint can't be used to enumerate ids.\n\t */\n\tpublic async getMemoryEntry(entryId: string, signer: Signer): Promise<MemoryEntryPublic> {\n\t\treturn this.signedRequest<MemoryEntryPublic>('GET', `/v1/memory/${encodeURIComponent(entryId)}`, null, signer);\n\t}\n\n\t/**\n\t * Build the same canonical-JSON signing input the arp-server's\n\t * `SignedRequestGuard` recomputes (`{ method, path, query, body }`),\n\t * sign with the caller's identity key, dispatch with both ARP auth\n\t * headers.\n\t *\n\t * `body === null` means \"no body\" — used for GETs and any future\n\t * endpoint that drops the JSON payload entirely. Body-less POST /\n\t * PATCH callers pass `{}` so client + server agree on a non-null\n\t * canonical input.\n\t *\n\t * `query` is the parsed query map. Including it in the signing\n\t * input prevents an attacker who intercepts a single signed\n\t * request from replaying it with different `?limit=`, `?before=`,\n\t * etc. Pass `undefined` (or omit) when there are no query params;\n\t * we serialise as `{}` so client + server agree.\n\t */\n\tpublic async signedRequest<T>(\n\t\tmethod: 'GET' | 'POST' | 'PATCH' | 'DELETE',\n\t\tpath: string,\n\t\tbody: unknown | null,\n\t\tsigner: Signer,\n\t\tquery?: Record<string, string | number | boolean | undefined>,\n\t\t// Optional AbortSignal — propagated to fetch so a timeout in\n\t\t// `preflightLockCurrency` (or anywhere else with a cancellable\n\t\t// caller) can close the underlying socket instead of leaving\n\t\t// it open and keeping the Node event loop alive after the\n\t\t// command's real work is done.\n\t\tsignal?: AbortSignal,\n\t): Promise<T> {\n\t\tconst fullPath = `${this.basePath}${path}`;\n\t\t// Drop undefined values so the canonical JSON has the same\n\t\t// keys whether the caller passed them or omitted them. All\n\t\t// remaining values become strings — Express parses every\n\t\t// query value as a string regardless of declared DTO type, so\n\t\t// matching that on the client keeps the canonical bytes\n\t\t// identical.\n\t\tconst normalisedQuery = normaliseQuery(query);\n\t\tconst signingInput = canonicalBytes({\n\t\t\tmethod,\n\t\t\tpath: fullPath,\n\t\t\tquery: normalisedQuery,\n\t\t\tbody,\n\t\t});\n\t\tconst sigBytes = ed25519Sign(signingInput, signer.identitySecretKey);\n\t\tconst sigB64 = Buffer.from(sigBytes).toString('base64');\n\n\t\tconst headers: Record<string, string> = {\n\t\t\t'X-ARP-Signer-DID': signer.did,\n\t\t\t'X-ARP-Signature': `ed25519:${sigB64}`,\n\t\t};\n\t\tconst init: { method: string; headers: Record<string, string>; body?: string; signal?: AbortSignal } = {\n\t\t\tmethod,\n\t\t\theaders,\n\t\t};\n\t\tif (body !== null) {\n\t\t\theaders['Content-Type'] = 'application/json';\n\t\t\tinit.body = JSON.stringify(body);\n\t\t}\n\t\tif (signal !== undefined) init.signal = signal;\n\t\tconst pathWithQuery = appendQueryString(path, normalisedQuery);\n\t\treturn this.request<T>(pathWithQuery, init);\n\t}\n\n\tprivate async post<T>(path: string, body: unknown, opts?: { expectStatus?: number }): Promise<T> {\n\t\treturn this.request<T>(path, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: { 'Content-Type': 'application/json' },\n\t\t\tbody: JSON.stringify(body),\n\t\t\texpectStatus: opts?.expectStatus,\n\t\t});\n\t}\n\n\tprivate async get<T>(path: string): Promise<T> {\n\t\treturn this.request<T>(path, { method: 'GET' });\n\t}\n\n\tprivate async request<T>(path: string, init: { method: string; headers?: Record<string, string>; body?: string; expectStatus?: number; signal?: AbortSignal }): Promise<T> {\n\t\tconst url = `${this.serverUrl}${path}`;\n\t\tlet res: Response;\n\t\ttry {\n\t\t\tres = await fetch(url, {\n\t\t\t\tmethod: init.method,\n\t\t\t\theaders: init.headers,\n\t\t\t\tbody: init.body,\n\t\t\t\tsignal: init.signal,\n\t\t\t});\n\t\t} catch (err) {\n\t\t\t// Network-level failure (DNS, ECONNREFUSED, TLS, AbortError) —\n\t\t\t// re-throw with a stable message so the CLI top-level renders\n\t\t\t// cleanly. Aborted fetches throw a DOMException / AbortError;\n\t\t\t// downstream callers that propagated a signal can match on\n\t\t\t// the cause to distinguish \"user/timeout aborted\" from\n\t\t\t// \"network failed\".\n\t\t\tconst cause = err instanceof Error ? err.message : String(err);\n\t\t\tthrow new Error(`Network error contacting ${url}: ${cause}`);\n\t\t}\n\n\t\tconst expected = init.expectStatus ?? 200;\n\t\tif (res.status === 204 && expected === 204) {\n\t\t\treturn undefined as T;\n\t\t}\n\t\tconst text = await res.text();\n\t\tif (!res.ok) {\n\t\t\tlet payload: ApiErrorBody;\n\t\t\ttry {\n\t\t\t\tpayload = JSON.parse(text) as ApiErrorBody;\n\t\t\t\tif (typeof payload.code !== 'string' || typeof payload.message !== 'string') {\n\t\t\t\t\tthrow new Error('not an ApiError shape');\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\tpayload = {\n\t\t\t\t\tcode: `HTTP_${res.status}`,\n\t\t\t\t\tmessage: text || res.statusText || `unexpected status ${res.status}`,\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow new ApiError(res.status, payload);\n\t\t}\n\t\tif (res.status === expected && expected === 204) return undefined as T;\n\t\tif (text.length === 0) return undefined as T;\n\t\ttry {\n\t\t\treturn JSON.parse(text) as T;\n\t\t} catch {\n\t\t\tthrow new Error(`ARP server returned non-JSON body for ${path}: ${text.slice(0, 200)}`);\n\t\t}\n\t}\n}\n\n/**\n * Drop `undefined` keys, stringify everything else. Mirrors how\n * Express's query parser surfaces request.query (every value is a\n * string) so canonical bytes line up across client + server.\n */\nfunction normaliseQuery(query: Record<string, string | number | boolean | undefined> | undefined): Record<string, string> {\n\tconst out: Record<string, string> = {};\n\tif (!query) return out;\n\tfor (const [k, v] of Object.entries(query)) {\n\t\tif (v === undefined) continue;\n\t\tout[k] = String(v);\n\t}\n\treturn out;\n}\n\n/**\n * Re-attach a query string to a path for the actual HTTP request.\n * Sorted keys so the wire form is stable; Express doesn't care about\n * order but it makes the URL deterministic for logs / replay.\n */\nfunction appendQueryString(path: string, query: Record<string, string>): string {\n\tconst keys = Object.keys(query).sort();\n\tif (keys.length === 0) return path;\n\tconst params = new URLSearchParams();\n\tfor (const k of keys) params.set(k, query[k]);\n\treturn `${path}?${params.toString()}`;\n}\n\n/**\n * Parse one SSE record (the text between two blank-line separators)\n * into the `{ type, data, id }` shape `streamInbox` yields.\n *\n * SSE wire format spec:\n * event: <type> — optional; default 'message'\n * id: <id> — optional; gives the client a Last-Event-ID\n * data: <payload> — repeated lines are concatenated with '\\n'\n *\n * `data` is JSON-encoded by our server (see InboxStreamService) so\n * we attempt to parse it; on parse failure we yield the raw string\n * — better to surface a malformed event than to silently drop it.\n *\n * Records that contain only comment lines (`:`) or have no `data`\n * field are dropped (return null) — those are SSE keep-alives /\n * unknown directives that have no consumer-facing meaning.\n *\n * Exported for tests.\n */\nexport function parseSseRecord(record: string): { type: string; data: unknown; id?: string } | null {\n\tlet type = 'message';\n\tlet id: string | undefined;\n\tconst dataLines: string[] = [];\n\tfor (const rawLine of record.split('\\n')) {\n\t\tconst line = rawLine.replace(/\\r$/, '');\n\t\tif (line === '' || line.startsWith(':')) continue;\n\t\tconst colon = line.indexOf(':');\n\t\tconst field = colon === -1 ? line : line.slice(0, colon);\n\t\t// Per spec: a single space after the colon is consumed.\n\t\tconst valueRaw = colon === -1 ? '' : line.slice(colon + 1);\n\t\tconst value = valueRaw.startsWith(' ') ? valueRaw.slice(1) : valueRaw;\n\t\tif (field === 'event') type = value;\n\t\telse if (field === 'id') id = value;\n\t\telse if (field === 'data') dataLines.push(value);\n\t\t// Unknown fields silently ignored per spec.\n\t}\n\tif (dataLines.length === 0) return null;\n\tconst dataStr = dataLines.join('\\n');\n\tlet data: unknown;\n\ttry {\n\t\tdata = JSON.parse(dataStr);\n\t} catch {\n\t\t// Malformed JSON — surface the raw string. Caller decides.\n\t\tdata = dataStr;\n\t}\n\treturn id !== undefined ? { type, data, id } : { type, data };\n}\n","import { Command } from 'commander';\nimport simpleUpdateNotifier from 'simple-update-notifier';\nimport packageJson from '../package.json';\nimport { ApiError } from './api';\nimport { registerAgentsCommand } from './commands/agents';\nimport { registerConfigCommand } from './commands/config';\nimport { registerContractCommands } from './commands/contract';\nimport { registerContractsCommand } from './commands/contracts';\nimport { registerDelegationCommands } from './commands/delegation';\nimport { registerDelegationsCommand } from './commands/delegations';\nimport { registerDidDocCommand } from './commands/did-doc';\nimport { registerDoctorCommand } from './commands/doctor';\nimport { registerEnvelopeCommand } from './commands/envelope';\nimport { registerEscrowCommands } from './commands/escrow';\nimport { registerEventsCommand } from './commands/events';\nimport { registerGuideCommand } from './commands/guide';\nimport { registerHomesCommand } from './commands/homes';\nimport { registerInboxCommand } from './commands/inbox';\nimport { registerKeysCommand } from './commands/keys';\nimport { registerLifecycleCommands } from './commands/lifecycle';\nimport { registerListCommand } from './commands/list';\nimport { registerMemoryCommands } from './commands/memory';\nimport { registerReceiptCommands } from './commands/receipt';\nimport { registerReceiptsCommand } from './commands/receipts';\nimport { registerRegisterCommand } from './commands/register';\nimport { registerRelationshipsCommand } from './commands/relationships';\nimport { registerRotateCommand } from './commands/rotate';\nimport { registerSendHandshakeCommand } from './commands/send-handshake';\nimport { registerSendHandshakeResponseCommand } from './commands/send-handshake-response';\nimport { registerStatusCommand } from './commands/status';\nimport { registerWalletCommands } from './commands/wallet';\nimport { registerWatchCommand } from './commands/watch';\nimport { registerWhoamiCommand } from './commands/whoami';\nimport { registerWorkCommands } from './commands/work';\nimport { registerWorkListCommand } from './commands/work-list';\nimport { formatApiError, formatGenericError } from './format';\n\n/**\n * Background \"newer version on npm available\" check, Yarn-Berry style.\n *\n * **Currently a no-op** while `package.json` carries `\"private\": true`.\n * The plumbing + dep are in place so a single edit (drop `private`)\n * activates the check at publish time.\n *\n * ## Why simple-update-notifier (not update-notifier@7)\n *\n * 1. CJS-friendly. update-notifier@7 is ESM-only; this CLI bundles\n * as CJS (see tsup.config.ts), so a static import of the ESM\n * lib would break the build.\n * 2. No `configstore`. update-notifier writes its cache via the\n * `configstore` package (`~/.config/configstore/...`) and on a\n * read-only `HOME` registers an `exit` handler that prints\n * \"update check failed\" to stderr — defeating the surrounding\n * try/catch. simple-update-notifier caches via the OS tmpdir\n * and swallows its own errors when `debug: false` (the default).\n *\n * ## Known limitation — REDESIGN BEFORE PUBLISHING\n *\n * `simple-update-notifier` performs the registry probe via an\n * in-process `https.get`. The socket is a referenced Node handle, so\n * fast commands (`heyarp --help`, `heyarp keys gen`) finish their\n * own work but won't exit until the npm response lands — typically\n * a few seconds, longer if the registry is slow / unreachable.\n *\n * Before flipping `private: false`, swap this function to spawn a\n * detached child process that runs the check + writes a cache file,\n * and have the parent only consult the cache (no foreground network\n * I/O). That's what `update-notifier@7` does internally; we'd port\n * the same idea or shell out to `pnpm dlx update-notifier`.\n */\nasync function checkForUpdates(): Promise<void> {\n\t// Skip while we're a private package — no point hitting the\n\t// registry for a name nobody can fetch, and the open socket would\n\t// stall the foreground command's exit (see \"Known limitation\"\n\t// above). When we publish, address the redesign FIRST, then drop\n\t// this guard.\n\tif ((packageJson as { private?: boolean }).private === true) return;\n\n\ttry {\n\t\tawait simpleUpdateNotifier({\n\t\t\tpkg: { name: packageJson.name, version: packageJson.version },\n\t\t\tupdateCheckInterval: 1000 * 60 * 60 * 24,\n\t\t});\n\t} catch {\n\t\t// Best-effort: never let a failed update check leak through to\n\t\t// the user. simple-update-notifier already swallows internally\n\t\t// when debug=false (the default), but we belt-and-braces it in\n\t\t// case a future version regresses.\n\t}\n}\n\n/**\n * Single commander program. Subcommands are registered in dedicated\n * modules so each can own its own option/argument shape — keeps this\n * entry point under fifty lines and grep-able.\n */\nasync function main(): Promise<void> {\n\t// Fire-and-forget update check — runs in the background, prints on\n\t// exit if a newer version is available. Never awaited.\n\tvoid checkForUpdates();\n\n\tconst program = new Command();\n\n\tprogram\n\t\t.name('heyarp')\n\t\t.description('ARP — Agent Relationship Protocol CLI (talks to apps/arp-server)')\n\t\t.version('0.0.1')\n\t\t// Root-level error-detail flag is named `--trace` (not\n\t\t// `--verbose`) so it does not shadow subcommand-level\n\t\t// `--verbose` listing flags. Commander attaches root flags\n\t\t// before the subcommand parses its own, so a shared name\n\t\t// would silently swallow the subcommand's value.\n\t\t.option(\n\t\t\t'--trace',\n\t\t\t'Surface stack traces and error details on failure.',\n\t\t\tfalse,\n\t\t);\n\n\tregisterConfigCommand(program);\n\tregisterGuideCommand(program);\n\tregisterHomesCommand(program);\n\tregisterKeysCommand(program);\n\tregisterRegisterCommand(program);\n\tregisterListCommand(program);\n\tregisterAgentsCommand(program);\n\tregisterDidDocCommand(program);\n\tregisterDoctorCommand(program);\n\tregisterEscrowCommands(program);\n\tregisterWhoamiCommand(program);\n\tregisterLifecycleCommands(program);\n\tregisterRotateCommand(program);\n\tregisterSendHandshakeCommand(program);\n\tregisterSendHandshakeResponseCommand(program);\n\tregisterInboxCommand(program);\n\tregisterWatchCommand(program);\n\tregisterRelationshipsCommand(program);\n\tregisterStatusCommand(program);\n\tregisterEventsCommand(program);\n\tregisterEnvelopeCommand(program);\n\tregisterContractCommands(program);\n\tregisterContractsCommand(program);\n\tregisterDelegationCommands(program);\n\tregisterDelegationsCommand(program);\n\tregisterWorkCommands(program);\n\tregisterWorkListCommand(program);\n\tregisterReceiptCommands(program);\n\tregisterReceiptsCommand(program);\n\tregisterMemoryCommands(program);\n\tregisterWalletCommands(program);\n\n\ttry {\n\t\tawait program.parseAsync(process.argv);\n\t} catch (err) {\n\t\tconst verbose = !!program.opts().trace;\n\t\tif (err instanceof ApiError) {\n\t\t\tconsole.error(formatApiError(err.payload, verbose));\n\t\t} else {\n\t\t\tconsole.error(formatGenericError(err, verbose));\n\t\t}\n\t\tprocess.exit(1);\n\t}\n}\n\n// Defence in depth: every error path must exit non-zero, including\n// paths that escape commander's parseAsync try/catch. Covers:\n//\n// - Unawaited promise rejections inside any command handler that\n// escape commander's parseAsync (rare, but theoretically possible\n// with fire-and-forget side effects).\n// - Synchronous throws from non-action code paths (e.g. setup\n// code before parseAsync runs).\n// - `void checkForUpdates()` errors (currently no-op but defensive).\n//\n// Node's default behaviour for unhandled rejections has flipped\n// between major versions; pinning exit 1 here keeps the contract\n// stable across Node versions.\nprocess.on('unhandledRejection', (reason) => {\n\tconst message = reason instanceof Error ? reason.message : String(reason);\n\tconsole.error(`Error (unhandled rejection) ${message}`);\n\tprocess.exit(1);\n});\nprocess.on('uncaughtException', (err) => {\n\tconsole.error(`Error (uncaught exception) ${err.message}`);\n\tprocess.exit(1);\n});\n\nmain();\n","{\n\t\"name\": \"@heyanon-arp/cli\",\n\t\"version\": \"0.0.2\",\n\t\"description\": \"Command-line client for the Agent Relationship Protocol — register agents, sign envelopes, run escrowed work cycles on Solana.\",\n\t\"license\": \"MIT\",\n\t\"keywords\": [\n\t\t\"arp\",\n\t\t\"agent-relationship-protocol\",\n\t\t\"did\",\n\t\t\"solana\",\n\t\t\"escrow\",\n\t\t\"ed25519\",\n\t\t\"agents\",\n\t\t\"a2a\",\n\t\t\"cli\"\n\t],\n\t\"bin\": {\n\t\t\"heyarp\": \"./dist/cli.js\"\n\t},\n\t\"publishConfig\": {\n\t\t\"access\": \"public\"\n\t},\n\t\"files\": [\"dist\", \"LICENSE\", \"README.md\"],\n\t\"engines\": {\n\t\t\"node\": \">=22\"\n\t},\n\t\"scripts\": {\n\t\t\"build\": \"tsup\",\n\t\t\"start\": \"node dist/cli.js\",\n\t\t\"test\": \"jest --runInBand --detectOpenHandles --forceExit --passWithNoTests\",\n\t\t\"lint\": \"biome check . --write\",\n\t\t\"prepublishOnly\": \"pnpm run build\",\n\t\t\"prepare\": \"pnpm run build\"\n\t},\n\t\"dependencies\": {\n\t\t\"@heyanon-arp/sdk\": \"workspace:*\",\n\t\t\"@noble/hashes\": \"^1.5.0\",\n\t\t\"@solana/web3.js\": \"^1.98.4\",\n\t\t\"chalk\": \"^4.1.2\",\n\t\t\"commander\": \"^12.1.0\",\n\t\t\"prompts\": \"^2.4.2\",\n\t\t\"simple-update-notifier\": \"^2.0.0\"\n\t},\n\t\"devDependencies\": {\n\t\t\"@types/jest\": \"^29.5.2\",\n\t\t\"@types/node\": \"^22.10.7\",\n\t\t\"@types/prompts\": \"^2.4.9\",\n\t\t\"jest\": \"^29.5.0\",\n\t\t\"ts-jest\": \"^29.1.0\",\n\t\t\"ts-node\": \"^10.9.2\",\n\t\t\"tsup\": \"^8.3.5\",\n\t\t\"typescript\": \"^5.5.4\"\n\t}\n}\n","import chalk from 'chalk';\nimport type { Command } from 'commander';\nimport { type AgentCatalog, ArpApiClient, type ListAgentsQuery } from '../api';\nimport { formatJson, supportsUnicodeFrame } from '../format';\n\ninterface AgentsOptions {\n\tserver?: string;\n\ttag?: string[];\n\tquery?: string;\n\tafter?: string;\n\tlimit?: string;\n\tverbose?: boolean;\n\tfullIds?: boolean;\n\tjson?: boolean;\n}\n\n/**\n * `heyarp agents` — list published agents on the configured server\n * via the public `GET /v1/agents` discovery / marketplace catalog\n * endpoint.\n *\n * Unauthenticated (no `--from-did` needed): the catalog itself is\n * public, and the rows it returns are a privacy-safe subset of the\n * agent profile (no accountId, no key material). The intended flow is\n * `heyarp agents --tag X` → pick a DID → `heyarp send-handshake`.\n *\n * Filters AND-compose: `--tag translation --tag fr` requires both.\n * `--query <s>` flips on full-text search over name + description.\n * Pagination uses the same composite-cursor pattern as the other list\n * commands — pass the previous page's last `id` via `--after`.\n */\nexport function registerAgentsCommand(root: Command): void {\n\troot.command('agents')\n\t\t.description('Discover published agents on the server (public catalog) — filter by tag / free-text')\n\t\t.option('--server <url>', 'Override ARP server base URL')\n\t\t.option('--tag <s>', 'Filter by capability tag — repeatable; AND-semantics across tags', accumulate, [])\n\t\t.option('--query <s>', 'Full-text search over name + description')\n\t\t.option('--after <id>', \"Cursor: pass the previous page's last `id` to fetch the next page\")\n\t\t.option('--limit <n>', 'Max rows to return (1..100)', '20')\n\t\t.option(\n\t\t\t'--verbose',\n\t\t\t'After the one-line summaries, print a framed \"Full agent payloads (N rows)\" block containing the JSON array of all rows (with owner-string sanitisation for terminal safety)',\n\t\t\tfalse,\n\t\t)\n\t\t.option(\n\t\t\t'--full-ids',\n\t\t\t'Print the catalog row `id` in full (no truncation). Use when copy-pasting into `--after` for the next page; the DID itself is always printed in full regardless.',\n\t\t\tfalse,\n\t\t)\n\t\t.option(\n\t\t\t'--json',\n\t\t\t// jq-pipeable mode: emit ONLY the JSON array on stdout\n\t\t\t// — no headers, no rules, no human-readable rows. The\n\t\t\t// `--verbose` framed block (`▼ Full agent payloads\n\t\t\t// (N rows)` rule lines + ANSI) defeats parsers, so this\n\t\t\t// flag is the dedicated machine-readable surface. Every\n\t\t\t// other stdout line is suppressed and the server banner\n\t\t\t// is routed to stderr instead.\n\t\t\t'Emit only the JSON array of catalog rows on stdout (jq-pipeable). The `Server: <url>` banner is redirected to stderr (so interactive runs still show it); row summaries and the next-page hint are suppressed entirely. Owner-controlled `name`/`description` strings are terminal-sanitised (same as `--verbose`).',\n\t\t\tfalse,\n\t\t)\n\t\t.action(async (opts: AgentsOptions) => {\n\t\t\tawait runAgents(opts);\n\t\t});\n}\n\n// Exported for --verbose regression coverage.\nexport async function runAgents(opts: AgentsOptions): Promise<void> {\n\tconst limit = parseLimit(opts.limit);\n\n\tconst api = new ArpApiClient(opts.server);\n\t// `--json` redirects the banner to stderr so jq consumers see only\n\t// the JSON array on stdout. Other diagnostics (no-rows hint,\n\t// next-page hint) are silenced entirely in JSON mode — `jq '.'\n\t// <empty>` would error anyway; let scripts check `.length`\n\t// themselves.\n\tif (opts.json) {\n\t\tconsole.error(chalk.dim(`Server: ${api.serverUrl}`));\n\t} else {\n\t\tconsole.log(chalk.dim(`Server: ${api.serverUrl}`));\n\t}\n\n\tconst query: ListAgentsQuery = { limit };\n\tif (opts.tag && opts.tag.length > 0) query.tag = opts.tag.map((t) => t.trim().toLowerCase());\n\tif (opts.query) query.q = opts.query;\n\tif (opts.after) query.after = opts.after;\n\n\tconst rows = await api.listAgents(query);\n\n\t// Owner-controlled strings flow into rendered output regardless of\n\t// mode — sanitise once so neither code path can bypass it.\n\tconst safeRows = rows.map((r) => ({\n\t\t...r,\n\t\tname: r.name === undefined ? undefined : sanitizeForTerminal(r.name),\n\t\tdescription: r.description === undefined ? undefined : sanitizeForTerminal(r.description),\n\t}));\n\n\tif (opts.json) {\n\t\t// jq-pipeable mode: emit ONLY the JSON array — even on zero rows\n\t\t// (so scripts can rely on `jq length`), no banners, no hints.\n\t\tconsole.log(formatJson(safeRows));\n\t\treturn;\n\t}\n\n\tif (rows.length === 0) {\n\t\tconsole.log(chalk.dim('\\n(no agents matched)'));\n\t\treturn;\n\t}\n\n\tconsole.log('');\n\tfor (const a of rows) {\n\t\tconsole.log(formatAgentLine(a, { fullIds: !!opts.fullIds }));\n\t}\n\n\tif (opts.verbose) {\n\t\t// `JSON.stringify` only escapes ASCII C0 (`\\x00-\\x1f`) plus\n\t\t// `\"` and `\\`. DEL (`\\x7f`) and the C1 range (`\\x80-\\x9f`) — both\n\t\t// of which carry terminal control bytes — pass through verbatim.\n\t\t// `safeRows` is already sanitised above.\n\t\t// visually unmistakable section divider\n\t\t// so the operator doesn't scroll past the JSON dump without\n\t\t// realising `--verbose` did anything. Matches `printVerbose`\n\t\t// for `delegations/contracts/receipts`. The\n\t\t// `supportsUnicodeFrame()` heuristic falls back to ASCII\n\t\t// glyphs on non-UTF-8 terminals / piped output / when\n\t\t// `HEYARP_ASCII_RULES=1` is set.\n\t\tconst useUnicode = supportsUnicodeFrame();\n\t\tconst heavyRule = useUnicode ? '━'.repeat(60) : '='.repeat(60);\n\t\tconst headerGlyph = useUnicode ? '▼' : '>';\n\t\tconst rule = chalk.cyan(heavyRule);\n\t\tconsole.log(`\\n${rule}`);\n\t\tconsole.log(chalk.bold.cyan(`${headerGlyph} Full agent payloads (${safeRows.length} row${safeRows.length === 1 ? '' : 's'})`));\n\t\tconsole.log(rule);\n\t\tconsole.log(formatJson(safeRows));\n\t\tconsole.log(`${rule}\\n`);\n\t}\n\n\tif (rows.length === limit) {\n\t\t// Hint at next-page cursor only when the page was full.\n\t\t// Phrased as \"append --after X to the same command you ran\" so\n\t\t// the suggestion doesn't accidentally drop the user's --tag /\n\t\t// --query / --server flags when they copy-paste it.\n\t\tconst cursor = rows[rows.length - 1].id;\n\t\tconsole.log(chalk.dim(`\\nNext page: re-run with --after ${cursor}`));\n\t}\n}\n\n/**\n * One-line summary for a catalog row.\n *\n * <id-head> <full-did> [tag1,tag2,...] \"name\" — description\n *\n * The DID is printed in FULL (not truncated) — the documented flow is\n * \"pick one and paste into `heyarp send-handshake`\", so callers need\n * the entire `did:arp:<base58btc>` value copyable from this output.\n *\n * The catalog row `id` is normally printed truncated as\n * `<head>...<tail>` because mid-line a 24-char hex string is just\n * noise; its only operator value is feeding the next page's `--after`\n * cursor. Pass `fullIds: true` to keep the id whole — exactly the\n * shape `--after` expects.\n *\n * `name` and `description` are owner-controlled strings the server\n * accepts as-is up to a max length, so they get sanitized before\n * printing — see `sanitizeForTerminal` below. Without sanitization a\n * malicious agent could embed ANSI escapes / newlines that spoof\n * additional rows or recolour the rest of the user's session.\n *\n * Hidden via dim when missing — empty tag list shows as `[]`, missing\n * name as `(unnamed)`, missing description as the empty string.\n *\n * Exported for testability.\n */\nexport function formatAgentLine(a: AgentCatalog, opts: { fullIds?: boolean } = {}): string {\n\tconst idDisplay = opts.fullIds ? a.id : `${a.id.slice(0, 8)}...${a.id.slice(-4)}`;\n\tconst tags = `[${a.tags.join(',')}]`;\n\tconst name = a.name ? `\"${truncate(sanitizeForTerminal(a.name), 40)}\"` : chalk.dim('(unnamed)');\n\tconst description = a.description ? `— ${chalk.dim(truncate(sanitizeForTerminal(a.description), 60))}` : '';\n\treturn `${chalk.dim(idDisplay)} ${chalk.cyan(a.did)} ${chalk.magenta(tags)} ${name} ${description}`.trim();\n}\n\n/**\n * Truncate `s` to at most `max` chars (with a 3-char ellipsis when\n * truncation actually fires). Keeps line lengths predictable.\n *\n * Exported for testability.\n */\nexport function truncate(s: string, max: number): string {\n\tif (s.length <= max) return s;\n\treturn `${s.slice(0, max - 3)}...`;\n}\n\n/**\n * Strip ASCII C0 controls (`\\x00-\\x1f`), DEL (`\\x7f`), and the C1\n * range (`\\x80-\\x9f`) from a string — these are the bytes that\n * carry ANSI/VT100 escape sequences (ESC = `\\x1b`), backspace,\n * vertical tab, etc. The server's register/update DTOs validate\n * length but not content, so we treat owner-controlled `name` /\n * `description` as untrusted input on the read side.\n *\n * Exported for testability.\n */\nexport function sanitizeForTerminal(s: string): string {\n\t// biome-ignore lint/suspicious/noControlCharactersInRegex: stripping control chars is the entire point\n\treturn s.replace(/[\\x00-\\x1f\\x7f-\\x9f]/g, '');\n}\n\n/** Parse `--limit` into [1, 100] — same contract as the other list commands. */\nexport function parseLimit(raw: string | undefined): number {\n\tif (raw === undefined) return 20;\n\tconst n = Number(raw);\n\tif (!Number.isFinite(n) || !Number.isInteger(n) || n < 1 || n > 100) {\n\t\tthrow new Error(`agents: --limit must be an integer between 1 and 100 (got '${raw}')`);\n\t}\n\treturn n;\n}\n\n/** Commander accumulator for repeatable flags (--tag a --tag b → ['a','b']). */\nfunction accumulate(value: string, previous: string[]): string[] {\n\treturn [...previous, value];\n}\n","import chalk from 'chalk';\n\n/**\n * Pretty-print a `did:arp:<base58btc>` DID — the prefix dimmed, the\n * suffix in cyan, so a DID is recognisable even when surrounded by\n * other tokens.\n */\nexport function formatDid(did: string): string {\n\tconst parts = did.split(':');\n\tif (parts.length !== 3) return chalk.cyan(did);\n\treturn `${chalk.dim(`${parts[0]}:${parts[1]}:`)}${chalk.cyan(parts[2])}`;\n}\n\n/**\n * `arp` API errors come back as `{ code, message, details? }`. Surface\n * code (red) + message; show details only when `verbose` so the\n * default failure output stays readable.\n */\nexport function formatApiError(err: ApiErrorPayload, verbose = false): string {\n\tconst head = `${chalk.red('Error')} [${chalk.bold(err.code)}] ${err.message}`;\n\tif (!verbose || err.details === undefined) return head;\n\tconst body = typeof err.details === 'string' ? err.details : JSON.stringify(err.details, null, 2);\n\treturn `${head}\\n${chalk.gray(body)}`;\n}\n\n/**\n * Network / unexpected failures — anything that isn't a structured\n * ApiError. Hides the stack unless `--verbose`.\n */\nexport function formatGenericError(err: unknown, verbose = false): string {\n\tconst message = err instanceof Error ? err.message : String(err);\n\tif (!verbose || !(err instanceof Error) || !err.stack) {\n\t\treturn `${chalk.red('Error')} ${message}`;\n\t}\n\treturn `${chalk.red('Error')} ${message}\\n${chalk.gray(err.stack)}`;\n}\n\n/**\n * Per-action error formatter.\n *\n * When a command's action handler catches an error locally (to pin\n * `process.exitCode = 1` — defence-in-depth on the exit-code\n * contract), the cli.ts top-level `parseAsync` catch never runs,\n * so it can't apply the structured `[CODE]` `ApiError` formatting\n * or honour the root-level `--trace` flag. This helper restores\n * both — given the command instance commander passes as the final\n * action argument, it walks up to the root program, reads\n * `--trace`, and routes the error to the right formatter.\n *\n * Action handlers using this look like:\n *\n * .action(async (arg1, arg2, opts, cmd: Command) => {\n * try {\n * await runHandler(...);\n * } catch (err) {\n * console.error(formatActionError(err, cmd));\n * process.exitCode = 1;\n * }\n * });\n *\n * Exported for unit-test coverage.\n */\nexport function formatActionError(err: unknown, command: import('commander').Command): string {\n\t// Walk to the root program (commander stores parent on each\n\t// subcommand; root has `parent === null`). `--trace` is a\n\t// root-level flag, so it only exists on the root's opts.\n\tlet cmd: import('commander').Command = command;\n\twhile (cmd.parent) cmd = cmd.parent;\n\tconst verbose = !!(cmd.opts() as { trace?: boolean }).trace;\n\t// Lazy-import ApiError to avoid a circular dependency (api.ts\n\t// doesn't import format.ts, but format.ts importing api.ts at\n\t// top-level would create one if the dep graph ever flips).\n\tconst { ApiError } = require('./api') as typeof import('./api');\n\tif (err instanceof ApiError) {\n\t\treturn formatApiError(err.payload, verbose);\n\t}\n\treturn formatGenericError(err, verbose);\n}\n\n/**\n * Pretty-print arbitrary JSON with two-space indent. Used for DID\n * documents and registration responses where the structure matters\n * more than the colour palette.\n */\nexport function formatJson(value: unknown): string {\n\treturn JSON.stringify(value, null, 2);\n}\n\n/**\n * Per-row label used by `printVerbose` — what the CLI prints above\n * each JSON dump so the operator can quickly find the right one.\n *\n * Keeping it as a free shape (rather than nailing it to a specific\n * DTO) lets each list command pass whatever identifier makes sense\n * for its row type — `eventId` + `serverEventHash` for events,\n * `delegationId` + `state` for delegations, etc.\n */\nexport interface VerboseRowLabel {\n\tprimary: string;\n\tsecondary?: string;\n}\n\n/**\n * Print a verbose JSON dump of every list-command row, prefixed by\n * a clear separator + label so the dumps don't blur into one wall\n * of text.\n *\n * Output shape:\n *\n * ── primary │ secondary ─────────\n * {\n * ...\n * }\n *\n * The label includes any *full* identifier the row exposes\n * (full DID / full server event hash / full delegationId UUID), so\n * downstream commands like `receipt cosign` (which need the full\n * sha256) can copy-paste from `--verbose` output without going to\n * the JSON dump itself.\n */\nexport function printVerbose<T>(rows: T[], header: string, labelOf: (row: T, index: number) => VerboseRowLabel): void {\n\tif (rows.length === 0) return;\n\t// Frame the verbose section with a leading + trailing dash-rule\n\t// so it's visually unmistakable next to the row-summary headers\n\t// printed above. ASCII fallback for `TERM=dumb` / legacy\n\t// terminals / locked-down log sinks that mangle `━` / `▼` /\n\t// `──` / `│` / `─`: we probe `process.stdout.isTTY` plus the\n\t// locale env vars and degrade to `=` / `>` / `--` / `|` / `-`\n\t// when the environment cannot render the heavy-rule glyphs\n\t// cleanly. Frame + per-row separators switch together so an\n\t// ASCII-mode terminal sees a clean dump throughout, not a\n\t// framed block with mojibake inside.\n\tconst useUnicode = supportsUnicodeFrame();\n\tconst heavyRule = useUnicode ? '━'.repeat(60) : '='.repeat(60);\n\tconst headerGlyph = useUnicode ? '▼' : '>';\n\tconst rowMarker = useUnicode ? '──' : '--';\n\tconst rowSep = useUnicode ? ' │ ' : ' | ';\n\tconst rowTrailer = useUnicode ? '─' : '-';\n\tconst rule = chalk.cyan(heavyRule);\n\tconsole.log(`\\n${rule}`);\n\tconsole.log(chalk.bold.cyan(`${headerGlyph} ${header} (${rows.length} row${rows.length === 1 ? '' : 's'})`));\n\tconsole.log(rule);\n\tfor (let i = 0; i < rows.length; i++) {\n\t\tconst label = labelOf(rows[i], i);\n\t\tconst lineParts = [chalk.bold(label.primary)];\n\t\tif (label.secondary) lineParts.push(chalk.dim(label.secondary));\n\t\tconsole.log(`\\n${chalk.dim(rowMarker)} ${lineParts.join(chalk.dim(rowSep))} ${chalk.dim(rowTrailer.repeat(20))}`);\n\t\tconsole.log(formatJson(rows[i]));\n\t}\n\tconsole.log(`\\n${chalk.cyan(heavyRule)}\\n`);\n}\n\n/**\n * Heuristic for \"can this terminal render the\n * `━` U+2501 / `▼` U+25BC glyphs cleanly?\". We use:\n * - `LANG` / `LC_ALL` containing 'UTF-8' / 'UTF8'\n * - `process.stdout.isTTY` (output going to a real terminal)\n * Both true → unicode-safe. Either false → ASCII fallback.\n *\n * Why both checks: piped output (`heyarp delegations <id> > log`)\n * has `isTTY === false` but might still be read by a UTF-8-aware\n * tool — however log files written via `tee` or redirected to\n * `cat` on a legacy console can mangle the glyphs. Conservative\n * default is \"if not TTY, use ASCII\".\n *\n * Override: `HEYARP_ASCII_RULES=1` forces ASCII unconditionally,\n * useful for screenshots / docs that should never carry\n * platform-specific glyphs.\n *\n * Exported for unit tests.\n */\nexport function supportsUnicodeFrame(): boolean {\n\tif (process.env.HEYARP_ASCII_RULES === '1') return false;\n\tif (!process.stdout.isTTY) return false;\n\tconst lang = process.env.LANG ?? '';\n\tconst lcAll = process.env.LC_ALL ?? '';\n\tconst lcCtype = process.env.LC_CTYPE ?? '';\n\tconst probe = `${lang}|${lcAll}|${lcCtype}`.toUpperCase();\n\treturn probe.includes('UTF-8') || probe.includes('UTF8');\n}\n\n/**\n * Machine-readable counterpart to the human-friendly summary line +\n * `--verbose` flow. Prints a single JSON array of rows, no chalk,\n * no summary text, no pagination hints — safe to pipe into `jq`,\n * read by another script, or feed into an LLM agent that expects\n * structured input.\n *\n * Strips through the standard `JSON.stringify` so it does NOT include\n * any chalk control bytes from upstream — even if the input strings\n * contain them, JSON-encoding will escape them.\n */\nexport function printJsonArray(rows: unknown[]): void {\n\tconsole.log(JSON.stringify(rows, null, 2));\n}\n\nexport interface ApiErrorPayload {\n\tcode: string;\n\tmessage: string;\n\tdetails?: unknown;\n}\n\n/**\n * Render a list of records as a 3-column table (DID | Name | Registered).\n * Plain text, no Unicode box-drawing — copy-pastes cleanly into shell\n * notes and CI logs.\n */\nexport function formatAgentsTable(rows: { did: string; name?: string; tags?: string[]; registeredAt?: string }[]): string {\n\tif (rows.length === 0) return chalk.dim('(no agents registered locally)');\n\tconst header = ['DID', 'Name', 'Tags', 'Registered'];\n\tconst data = rows.map((r) => [r.did, r.name ?? '', (r.tags ?? []).join(','), r.registeredAt ?? '']);\n\tconst widths = header.map((h, i) => Math.max(h.length, ...data.map((row) => row[i].length)));\n\tconst pad = (cells: string[]) => cells.map((c, i) => c.padEnd(widths[i])).join(' ');\n\treturn [chalk.bold(pad(header)), chalk.dim(pad(widths.map((w) => '-'.repeat(w)))), ...data.map((r) => pad(r))].join('\\n');\n}\n","import chalk from 'chalk';\nimport type { Command } from 'commander';\nimport { resolveServerUrl } from '../api';\nimport {\n\tGLOBAL_CONFIG_KEYS,\n\ttype GlobalConfigKey,\n\tSERVER_CONFIG_KEYS,\n\ttype ServerConfigKey,\n\tconfigFilePath,\n\tgetGlobalConfigValue,\n\tgetServerConfigValue,\n\tisGlobalConfigKey,\n\tisServerConfigKey,\n\tlistConfig,\n\tsetGlobalConfigValue,\n\tsetServerConfigValue,\n\tunsetGlobalConfigValue,\n\tunsetServerConfigValue,\n} from '../config';\n\ninterface ConfigOptions {\n\tserver?: string;\n}\n\n/**\n * `heyarp config <action>` — npm-style persistent configuration.\n *\n * Storage lives at `~/.arp/config.json` (separate from `agents.json`)\n * so config is never tangled with secret keys. Allowed keys are a\n * closed enum split into two scopes:\n *\n * - Global keys (`GLOBAL_CONFIG_KEYS`) — one value applies CLI-wide.\n * Currently: `server` — the active ARP server URL, drops into\n * `resolveServerUrl`'s priority chain (flag > env > config > default).\n *\n * - Per-server keys (`SERVER_CONFIG_KEYS`) — scoped to a server URL,\n * so a single workstation can keep separate prefs for local / dev /\n * prod without one clobbering the next. Currently: `defaultDid` —\n * auto-applied to `--from-did` when omitted (in `resolveSenderAgent`).\n *\n * The set/get/unset commands route automatically: server-keys go into\n * `servers[<active-url>].<key>` where `<active-url>` is the same URL\n * every other command resolves to (via `resolveServerUrl`). The\n * top-level `--server <url>` flag overrides which bucket a server-key\n * write/read targets.\n */\nexport function registerConfigCommand(root: Command): void {\n\tconst config = root\n\t\t.command('config')\n\t\t.description('Read/write persistent CLI configuration (~/.arp/config.json)')\n\t\t.option('--server <url>', 'Override the server URL whose bucket per-server keys (e.g. defaultDid) read/write to');\n\n\tconfig\n\t\t.command('set <key> <value>')\n\t\t.description(`Persist a config value. Global keys: ${GLOBAL_CONFIG_KEYS.join(', ')}. Per-server keys: ${SERVER_CONFIG_KEYS.join(', ')}`)\n\t\t.action((key: string, value: string) => {\n\t\t\tconst opts = config.opts<ConfigOptions>();\n\t\t\tif (isGlobalConfigKey(key)) {\n\t\t\t\tsetGlobalConfigValue(key, value);\n\t\t\t\tconsole.log(`${chalk.green('✓')} ${chalk.bold(key)} = ${chalk.cyan(value)} ${chalk.dim('(global)')}`);\n\t\t\t} else if (isServerConfigKey(key)) {\n\t\t\t\tconst serverUrl = resolveServerUrl(opts.server);\n\t\t\t\tsetServerConfigValue(serverUrl, key, value);\n\t\t\t\tconsole.log(`${chalk.green('✓')} ${chalk.bold(key)} = ${chalk.cyan(value)} ${chalk.dim(`(scoped to ${serverUrl})`)}`);\n\t\t\t} else {\n\t\t\t\tthrow unknownKey(key);\n\t\t\t}\n\t\t\tconsole.log(chalk.dim(` stored in ${configFilePath()}`));\n\t\t});\n\n\tconfig\n\t\t.command('get <key>')\n\t\t.description('Print one config value')\n\t\t.action((key: string) => {\n\t\t\tconst opts = config.opts<ConfigOptions>();\n\t\t\tlet value: string | undefined;\n\t\t\tif (isGlobalConfigKey(key)) {\n\t\t\t\tvalue = getGlobalConfigValue(key);\n\t\t\t} else if (isServerConfigKey(key)) {\n\t\t\t\tconst serverUrl = resolveServerUrl(opts.server);\n\t\t\t\tvalue = getServerConfigValue(serverUrl, key);\n\t\t\t} else {\n\t\t\t\tthrow unknownKey(key);\n\t\t\t}\n\t\t\tif (value === undefined) {\n\t\t\t\tconsole.log(chalk.dim('(not set)'));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconsole.log(value);\n\t\t});\n\n\tconfig\n\t\t.command('list')\n\t\t.description('Print every config value currently set, grouped by scope')\n\t\t.action(() => {\n\t\t\tconst all = listConfig();\n\t\t\tconst globalEntries = Object.entries(all)\n\t\t\t\t.filter(([k]) => k !== 'servers')\n\t\t\t\t.filter((entry): entry is [GlobalConfigKey, string] => typeof entry[1] === 'string');\n\t\t\tconst servers = all.servers ?? {};\n\t\t\tconst serverUrls = Object.keys(servers);\n\n\t\t\tif (globalEntries.length === 0 && serverUrls.length === 0) {\n\t\t\t\tconsole.log(chalk.dim('(no config set)'));\n\t\t\t\tconsole.log(chalk.dim(` would write to ${configFilePath()}`));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (globalEntries.length > 0) {\n\t\t\t\tconsole.log(chalk.bold('global'));\n\t\t\t\tfor (const [k, v] of globalEntries) {\n\t\t\t\t\tconsole.log(` ${chalk.bold(k)} = ${chalk.cyan(v)}`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (const url of serverUrls) {\n\t\t\t\tconst bucket = servers[url];\n\t\t\t\tconst bucketEntries = Object.entries(bucket).filter((entry): entry is [ServerConfigKey, string] => typeof entry[1] === 'string');\n\t\t\t\tif (bucketEntries.length === 0) continue;\n\t\t\t\tconsole.log(`${chalk.bold('server')} ${chalk.dim(url)}`);\n\t\t\t\tfor (const [k, v] of bucketEntries) {\n\t\t\t\t\tconsole.log(` ${chalk.bold(k)} = ${chalk.cyan(v)}`);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\tconfig\n\t\t.command('unset <key>')\n\t\t.description('Remove a config value')\n\t\t.action((key: string) => {\n\t\t\tconst opts = config.opts<ConfigOptions>();\n\t\t\tif (isGlobalConfigKey(key)) {\n\t\t\t\tunsetGlobalConfigValue(key);\n\t\t\t\tconsole.log(`${chalk.green('✓')} unset ${chalk.bold(key)} ${chalk.dim('(global)')}`);\n\t\t\t} else if (isServerConfigKey(key)) {\n\t\t\t\tconst serverUrl = resolveServerUrl(opts.server);\n\t\t\t\tunsetServerConfigValue(serverUrl, key);\n\t\t\t\tconsole.log(`${chalk.green('✓')} unset ${chalk.bold(key)} ${chalk.dim(`(scoped to ${serverUrl})`)}`);\n\t\t\t} else {\n\t\t\t\tthrow unknownKey(key);\n\t\t\t}\n\t\t});\n}\n\nfunction unknownKey(key: string): Error {\n\tconst all = [...GLOBAL_CONFIG_KEYS, ...SERVER_CONFIG_KEYS];\n\treturn new Error(`Unknown config key '${key}'. Allowed: ${all.join(', ')}`);\n}\n","import {\n\ttype AssetIdentifier,\n\ttype ContractBody,\n\ttype ContractContent,\n\tDECLINE_REASONS,\n\ttype Did,\n\tPurpose,\n\ttype SignableProtected,\n\tWELL_KNOWN_ASSET_KEYS,\n\texpiresAt,\n\tresolveAsset,\n\trfc3339,\n\tsenderNonce,\n\tsignEnvelope,\n\tuuidV4,\n} from '@heyanon-arp/sdk';\nimport chalk from 'chalk';\nimport type { Command } from 'commander';\nimport { ApiError, ArpApiClient, type ContractPublic, type IngestResult, type Signer } from '../api';\nimport { formatJson } from '../format';\nimport { requireUuid as sharedRequireUuid } from '../id-format';\nimport { type AgentLocalState, resolveSenderAgent, updateAgentLocal } from '../state';\nimport { parseDeclineReason, parseReasonDetail, requireUuidNormalised } from './delegation';\nimport { makeSigner } from './lifecycle';\n\n/**\n * Error codes that indicate the server PERSISTED the event (so the\n * `sender_sequence` was consumed) but the body handler then rejected\n * the action. The CLI must advance `lastSenderSequence` for these,\n * otherwise the next envelope reuses an already-consumed sequence\n * and gets stuck on `ENV_SEQUENCE_BACKWARDS`.\n *\n * Pre-commit failures (envelope validator: `ENV_*`, `VAL_*`,\n * `AUTH_*`, `DOM_*`) leave the sequence unconsumed — the local\n * counter stays put and a retry with the same number is correct.\n *\n * Order matters here: every contract-body handler error in\n * `apps/arp-server/src/message/services/contract-handler.service.ts`\n * happens AFTER `EventService.create` writes the event row. That is\n * the source of truth for which codes belong here.\n */\nexport const POST_COMMIT_ERROR_CODES = new Set([\n\t'CONTRACT_ALREADY_EXISTS',\n\t'CONTRACT_INVALID_VERSION',\n\t'CONTRACT_INVALID_STATE',\n\t'CONTRACT_NOT_FOUND',\n\t'CONTRACT_RELATIONSHIP_MISMATCH',\n\t'CONTRACT_SIGNER_IS_PROPOSER',\n\t'CONTRACT_DECLINER_IS_PROPOSER',\n\t'CONTRACT_COUNTER_IS_PROPOSER',\n]);\n\n/**\n * `heyarp contract <action>` — full client side of the contract FSM:\n *\n * propose <recipient-did> — opens a new contract at v1\n * counter <relationship-id> <contract-id> — replies with a new version\n * sign <relationship-id> <contract-id> — promotes a PROPOSED → ACTIVE\n * decline <relationship-id> <contract-id> — terminates a PROPOSED\n *\n * Each subcommand is a thin wrapper around `sendContractEnvelope` —\n * the shared helper builds the protected block, signs, dispatches\n * `POST /v1/messages`, then advances local `lastSenderSequence` only\n * on confirmed ingest (so a network failure / server reject can be\n * retried with the same sequence number).\n *\n * `counter` / `sign` / `decline` all reference an existing version\n * of an existing contract. If `--version` is omitted we read the\n * contracts timeline (`GET /relationships/:id/contracts?state=proposed`)\n * and pick the latest PROPOSED row for that contractId — the FSM\n * keeps at most one PROPOSED per contractId at a time, so this is\n * the version the next action targets. Pass `--version <n>` to skip\n * the lookup or to act on a non-current version intentionally.\n */\nexport function registerContractCommands(root: Command): void {\n\tconst cmd = root.command('contract').description('Contract FSM actions: propose / counter / sign / decline');\n\n\tregisterPropose(cmd);\n\tregisterCounter(cmd);\n\tregisterSign(cmd);\n\tregisterDecline(cmd);\n}\n\n// ---------- propose ----------\n\ninterface ProposeOptions extends BaseSendOptions, ContractTermsOptions {\n\tcontractId?: string;\n}\n\nfunction registerPropose(parent: Command): void {\n\tparent\n\t\t.command('propose')\n\t\t.description('Open a new contract at version 1 with the given recipient.')\n\t\t.argument('<recipient-did>', 'Recipient agent DID (did:arp:...)')\n\t\t.option('--server <url>', 'Override ARP server base URL')\n\t\t.option('--from-did <did>', 'Sender DID — required only if multiple agents are registered against this server')\n\t\t.option('--contract-id <uuid>', 'Override the auto-generated contract id (UUID). Useful for replay / scripting.')\n\t\t.option('--scope <s>', 'scope_summary — short prose describing what is being offered')\n\t\t.option('--rate-amount <s>', 'rate_amount — decimal as string (e.g. \"5.00\"). REQUIRES --rate-currency if set.')\n\t\t.option(\n\t\t\t'--rate-currency <s>',\n\t\t\t`Asset identifier: shorthand (${WELL_KNOWN_ASSET_KEYS.join('|')}) OR raw CAIP-19 string (e.g. \"solana:5eykt.../spl:EPjFWdd5...\"). REQUIRES --rate-decimals if raw CAIP-19.`,\n\t\t)\n\t\t.option(\n\t\t\t'--rate-decimals <n>',\n\t\t\t'Decimal places for base-unit conversion (0-18). Required only when --rate-currency is raw CAIP-19; shorthand presets bring their own (USDC=6, SOL=9).',\n\t\t)\n\t\t.option('--rate-symbol <s>', 'Optional UI hint (\"USDC\", \"SOL\"). Free text, max 16 chars. Shorthand presets set this automatically.')\n\t\t.option('--rate-unit <s>', 'rate_unit (task|thread|handoff)')\n\t\t.option('--pricing <s>', 'pricing_model (flat|usage_based). `quote` + `subscription` were dropped from the enum because they had no settlement-layer behaviour; add them back when real semantics ship.')\n\t\t.option('--settlement <s>', 'settlement_model (prepaid|escrow)')\n\t\t.option('--delegation-tag <s>', 'allowed_delegation_tags — repeatable; pass --delegation-tag once per tag', collectRepeated, [])\n\t\t.option('--ttl <seconds>', 'Envelope TTL in seconds (max 86400 = 24h)', '3600')\n\t\t.option('--verbose', 'Print the full envelope before sending and the full server response', false)\n\t\t.action(async (recipientDid: string, opts: ProposeOptions) => {\n\t\t\tawait runPropose(recipientDid, opts);\n\t\t});\n}\n\nasync function runPropose(recipientDid: string, opts: ProposeOptions): Promise<void> {\n\trequireDid('contract propose', recipientDid, '<recipient-did>');\n\tconst ttlSeconds = parseTtl('contract propose', opts.ttl);\n\tconst terms = parseTerms('contract propose', opts);\n\tif (terms.scope_summary === undefined && terms.rate_amount === undefined) {\n\t\tthrow new Error('contract propose: at least one of --scope or --rate-amount is required (server-side validator rejects an empty proposal)');\n\t}\n\tconst contractId = parseContractId('contract propose', opts.contractId);\n\n\tconst api = new ArpApiClient(opts.server);\n\tconst sender = resolveSenderAgent('contract propose', opts.server, opts.fromDid);\n\n\tconst content: ContractContent = {\n\t\taction: 'proposal',\n\t\tcontract_id: contractId,\n\t\tversion: 1,\n\t\t...terms,\n\t};\n\tconst body: ContractBody = { type: 'contract', content };\n\n\tconsole.log(chalk.dim(`Server: ${api.serverUrl}`));\n\tconsole.log(chalk.dim(`Sender: ${sender.did}`));\n\tconsole.log(chalk.dim(`Recipient: ${recipientDid}`));\n\tconsole.log(chalk.dim(`Contract id: ${contractId} (v1)`));\n\n\tconst result = await sendContractEnvelope({ api, sender, recipientDid, body, ttlSeconds, verbose: opts.verbose, server: opts.server });\n\tprintIngestResult(result);\n\t// counter / sign / decline take `<relationship-id> <contract-id>`\n\t// as positional args (NOT a `--contract` flag). Echo a copy-pastable\n\t// next-step that matches the actual CLI shape — the operator just\n\t// substitutes which action they want.\n\tconsole.log(chalk.dim(`\\nReference this contract on subsequent calls with: heyarp contract <action> ${result.relationshipId} ${contractId}`));\n\tconsole.log(chalk.dim(` e.g. (counterparty signs) : heyarp contract sign ${result.relationshipId} ${contractId}`));\n\tconsole.log(chalk.dim(` e.g. (counterparty counters): heyarp contract counter ${result.relationshipId} ${contractId} --rate-amount <new>`));\n}\n\n// ---------- counter ----------\n\ninterface CounterOptions extends BaseSendOptions, ContractTermsOptions, ContractRefOptions {}\n\nfunction registerCounter(parent: Command): void {\n\tparent\n\t\t.command('counter')\n\t\t.description('Reply with revised terms to the latest PROPOSED version of <contract-id> in <relationship-id>.')\n\t\t.argument('<relationship-id>', 'Relationship UUID')\n\t\t.argument('<contract-id>', 'Contract UUID (proposed earlier in this relationship)')\n\t\t.option('--server <url>', 'Override ARP server base URL')\n\t\t.option('--from-did <did>', 'Sender DID — required only if multiple agents are registered against this server')\n\t\t.option('--version <n>', 'Target the previous version explicitly (default: auto-resolve to the latest PROPOSED)')\n\t\t.option('--scope <s>', 'scope_summary — short prose describing the revised terms')\n\t\t.option('--rate-amount <s>', 'rate_amount — decimal as string. REQUIRES --rate-currency if set.')\n\t\t.option('--rate-currency <s>', `Asset identifier: shorthand (${WELL_KNOWN_ASSET_KEYS.join('|')}) OR raw CAIP-19 string.`)\n\t\t.option('--rate-decimals <n>', 'Decimal places for base-unit conversion (0-18). Required only when --rate-currency is raw CAIP-19.')\n\t\t.option('--rate-symbol <s>', 'Optional UI hint (\"USDC\", \"SOL\"). Max 16 chars.')\n\t\t.option('--rate-unit <s>', 'rate_unit (task|thread|handoff)')\n\t\t.option('--pricing <s>', 'pricing_model (flat|usage_based). `quote` + `subscription` were dropped from the enum because they had no settlement-layer behaviour; add them back when real semantics ship.')\n\t\t.option('--settlement <s>', 'settlement_model (prepaid|escrow)')\n\t\t.option('--delegation-tag <s>', 'allowed_delegation_tags — repeatable', collectRepeated, [])\n\t\t.option('--ttl <seconds>', 'Envelope TTL in seconds', '3600')\n\t\t.option('--verbose', 'Print the full envelope before sending and the full server response', false)\n\t\t.action(async (relationshipId: string, contractId: string, opts: CounterOptions) => {\n\t\t\tawait runCounter(relationshipId, contractId, opts);\n\t\t});\n}\n\nasync function runCounter(relationshipId: string, contractId: string, opts: CounterOptions): Promise<void> {\n\t// Normalise positional UUID args to canonical lowercase so timeline\n\t// lookups + envelope contract_ids stay consistent. Without this,\n\t// mixed-case input would mismatch timeline rows and sign mixed-case\n\t// envelope bodies.\n\trelationshipId = requireUuidNormalised('contract counter', relationshipId, '<relationship-id>');\n\tcontractId = requireUuidNormalised('contract counter', contractId, '<contract-id>');\n\tconst ttlSeconds = parseTtl('contract counter', opts.ttl);\n\tconst terms = parseTerms('contract counter', opts);\n\tif (terms.scope_summary === undefined && terms.rate_amount === undefined) {\n\t\tthrow new Error('contract counter: at least one of --scope or --rate-amount is required (server-side validator rejects an empty counter)');\n\t}\n\n\tconst api = new ArpApiClient(opts.server);\n\tconst sender = resolveSenderAgent('contract counter', opts.server, opts.fromDid);\n\tconst signer = makeSigner(sender);\n\n\tconst previousVersion = await resolveTargetVersion('contract counter', api, signer, { relationshipId, contractId, explicit: opts.version });\n\tconst newVersion = previousVersion + 1;\n\n\tconst content: ContractContent = {\n\t\taction: 'counter',\n\t\tcontract_id: contractId,\n\t\tversion: newVersion,\n\t\t...terms,\n\t};\n\tconst body: ContractBody = { type: 'contract', content };\n\n\tconsole.log(chalk.dim(`Server: ${api.serverUrl}`));\n\tconsole.log(chalk.dim(`Sender: ${sender.did}`));\n\tconsole.log(chalk.dim(`Relationship: ${relationshipId}`));\n\tconsole.log(chalk.dim(`Contract id: ${contractId} (v${previousVersion} → v${newVersion})`));\n\n\tconst result = await sendContractEnvelope({\n\t\tapi,\n\t\tsender,\n\t\trecipientDid: await resolveCounterpartyDid(api, signer, relationshipId, sender.did),\n\t\tbody,\n\t\tttlSeconds,\n\t\tverbose: opts.verbose,\n\t\tserver: opts.server,\n\t});\n\tprintIngestResult(result);\n}\n\n// ---------- sign ----------\n\ninterface SignOptions extends BaseSendOptions, ContractRefOptions {}\n\nfunction registerSign(parent: Command): void {\n\tparent\n\t\t.command('sign')\n\t\t.description('Promote the latest PROPOSED version of <contract-id> in <relationship-id> to ACTIVE.')\n\t\t.argument('<relationship-id>', 'Relationship UUID')\n\t\t.argument('<contract-id>', 'Contract UUID')\n\t\t.option('--server <url>', 'Override ARP server base URL')\n\t\t.option('--from-did <did>', 'Sender DID — required only if multiple agents are registered against this server')\n\t\t.option('--version <n>', 'Target the version explicitly (default: auto-resolve to the latest PROPOSED)')\n\t\t.option('--ttl <seconds>', 'Envelope TTL in seconds', '3600')\n\t\t.option('--verbose', 'Print the full envelope before sending and the full server response', false)\n\t\t.action(async (relationshipId: string, contractId: string, opts: SignOptions) => {\n\t\t\tawait runSignOrDecline(relationshipId, contractId, 'sign', opts);\n\t\t});\n}\n\n// ---------- decline ----------\n\ninterface DeclineOptions extends BaseSendOptions, ContractRefOptions {\n\t/** REQUIRED decline reason code. See `DeclineReason` allowlist. */\n\treason?: string;\n\t/** Optional free-text elaboration accompanying `--reason`. */\n\treasonDetail?: string;\n}\n\nfunction registerDecline(parent: Command): void {\n\tparent\n\t\t.command('decline')\n\t\t.description('Decline the latest PROPOSED version of <contract-id> in <relationship-id>.')\n\t\t.argument('<relationship-id>', 'Relationship UUID')\n\t\t.argument('<contract-id>', 'Contract UUID')\n\t\t.option('--server <url>', 'Override ARP server base URL')\n\t\t.option('--from-did <did>', 'Sender DID — required only if multiple agents are registered against this server')\n\t\t.option('--version <n>', 'Target the version explicitly (default: auto-resolve to the latest PROPOSED)')\n\t\t.option('--ttl <seconds>', 'Envelope TTL in seconds', '3600')\n\t\t.requiredOption(\n\t\t\t'--reason <code>',\n\t\t\t// Decline envelopes MUST carry a machine-readable reason.\n\t\t\t// The allowlist comes from the SDK's `DECLINE_REASONS`\n\t\t\t// export and is mirrored in the server validator\n\t\t\t// (`VALID_DECLINE_REASONS`).\n\t\t\t`Required: decline reason code (one of: ${DECLINE_REASONS.join(', ')}). Carried in body.content.reason.`,\n\t\t)\n\t\t.option('--reason-detail <s>', 'Optional free-text elaboration alongside --reason (max 512 chars).')\n\t\t.option('--verbose', 'Print the full envelope before sending and the full server response', false)\n\t\t.action(async (relationshipId: string, contractId: string, opts: DeclineOptions) => {\n\t\t\tawait runSignOrDecline(relationshipId, contractId, 'decline', opts);\n\t\t});\n}\n\nasync function runSignOrDecline(relationshipId: string, contractId: string, action: 'sign' | 'decline', opts: SignOptions | DeclineOptions): Promise<void> {\n\tconst cmdName = `contract ${action}`;\n\t// Normalise positional UUID args.\n\trelationshipId = requireUuidNormalised(cmdName, relationshipId, '<relationship-id>');\n\tcontractId = requireUuidNormalised(cmdName, contractId, '<contract-id>');\n\tconst ttlSeconds = parseTtl(cmdName, opts.ttl);\n\n\t// Validate `--reason` (+ `--reason-detail`) BEFORE any API lookup\n\t// so bad input fails with a clean parse error rather than midway\n\t// through.\n\tlet declinePayload: { reason: ContractContent['reason']; reasonDetail?: string } | null = null;\n\tif (action === 'decline') {\n\t\tconst declineOpts = opts as DeclineOptions;\n\t\tconst reason = parseDeclineReason(cmdName, declineOpts.reason);\n\t\tconst detail = parseReasonDetail(cmdName, declineOpts.reasonDetail);\n\t\tdeclinePayload = detail ? { reason, reasonDetail: detail } : { reason };\n\t}\n\n\tconst api = new ArpApiClient(opts.server);\n\tconst sender = resolveSenderAgent(cmdName, opts.server, opts.fromDid);\n\tconst signer = makeSigner(sender);\n\n\tconst targetVersion = await resolveTargetVersion(cmdName, api, signer, { relationshipId, contractId, explicit: opts.version });\n\n\tconst content: ContractContent = {\n\t\taction,\n\t\tcontract_id: contractId,\n\t\tversion: targetVersion,\n\t};\n\tif (declinePayload) {\n\t\tcontent.reason = declinePayload.reason;\n\t\tif (declinePayload.reasonDetail) content.reason_detail = declinePayload.reasonDetail;\n\t}\n\tconst body: ContractBody = { type: 'contract', content };\n\n\tconsole.log(chalk.dim(`Server: ${api.serverUrl}`));\n\tconsole.log(chalk.dim(`Sender: ${sender.did}`));\n\tconsole.log(chalk.dim(`Relationship: ${relationshipId}`));\n\tconsole.log(chalk.dim(`Contract id: ${contractId} (v${targetVersion}, action=${action}${action === 'decline' ? `, reason=${content.reason}` : ''})`));\n\n\tconst result = await sendContractEnvelope({\n\t\tapi,\n\t\tsender,\n\t\trecipientDid: await resolveCounterpartyDid(api, signer, relationshipId, sender.did),\n\t\tbody,\n\t\tttlSeconds,\n\t\tverbose: opts.verbose,\n\t\tserver: opts.server,\n\t});\n\tprintIngestResult(result);\n}\n\n// ---------- shared helpers ----------\n\ninterface BaseSendOptions {\n\tserver?: string;\n\tfromDid?: string;\n\tttl?: string;\n\tverbose?: boolean;\n}\n\ninterface ContractTermsOptions {\n\tscope?: string;\n\trateAmount?: string;\n\trateCurrency?: string;\n\trateDecimals?: string;\n\trateSymbol?: string;\n\trateUnit?: string;\n\tpricing?: string;\n\tsettlement?: string;\n\tdelegationTag?: string[];\n}\n\ninterface ContractRefOptions {\n\tversion?: string;\n}\n\ninterface SendArgs {\n\tapi: ArpApiClient;\n\tsender: AgentLocalState;\n\trecipientDid: string;\n\tbody: ContractBody;\n\tttlSeconds: number;\n\tverbose: boolean | undefined;\n\tserver: string | undefined;\n}\n\n/**\n * Build → sign → ingest a contract envelope. Allocates the next\n * `sender_sequence` from local state.\n *\n * Sequence-bump policy is three-tier:\n *\n * 1. Success (HTTP 202): advance unconditionally — event landed.\n *\n * 2. ApiError with a code in `POST_COMMIT_ERROR_CODES`: advance\n * anyway and re-throw. The contract handler always writes\n * the event row BEFORE running its CAS / FSM checks, so a\n * `CONTRACT_INVALID_STATE` (or sibling) means the server\n * consumed the sequence even though the action was rejected.\n * Failing to bump here would leave the next envelope re-using\n * a consumed sequence — server then rejects with\n * `ENV_SEQUENCE_BACKWARDS` and the agent is wedged.\n *\n * 3. Anything else — network error, or a pre-commit reject from\n * the validator (any code prefixed `ENV_`, `VAL_`, `AUTH_`,\n * `DOM_`): leave `lastSenderSequence` untouched. The signed\n * envelope was either never seen by the server or rejected\n * before the event row was written, so the next retry uses\n * the same number safely.\n */\nasync function sendContractEnvelope(args: SendArgs): Promise<IngestResult> {\n\tconst nextSequence = (args.sender.lastSenderSequence ?? 0) + 1;\n\tconst protectedBlock: SignableProtected = {\n\t\tprotocol_version: 'arp/0.1',\n\t\tpurpose: Purpose.ENVELOPE,\n\t\tmessage_id: uuidV4(),\n\t\tsender_did: args.sender.did as Did,\n\t\trecipient_did: args.recipientDid as Did,\n\t\t// `relationship_id: null` matches the existing handshake /\n\t\t// handshake-response wrappers — the server resolves the\n\t\t// pair from `(sender_did, recipient_did)` and routes the\n\t\t// event onto the existing relationship row. No new pair is\n\t\t// minted for contract bodies.\n\t\trelationship_id: null,\n\t\tsender_sequence: nextSequence,\n\t\tsender_nonce: senderNonce(),\n\t\ttimestamp: rfc3339(),\n\t\texpires_at: expiresAt(args.ttlSeconds),\n\t\tdelivery_id: null,\n\t};\n\n\tconst signer = makeSigner(args.sender);\n\tconst envelope = signEnvelope<ContractBody>({\n\t\tprotected: protectedBlock,\n\t\tbody: args.body,\n\t\tidentitySecretKey: signer.identitySecretKey,\n\t});\n\n\tif (args.verbose) {\n\t\tconsole.log(chalk.bold('\\nEnvelope (pre-send):'));\n\t\tconsole.log(formatJson(envelope));\n\t}\n\n\ttry {\n\t\tconst result = await args.api.ingest(envelope);\n\t\tupdateAgentLocal(args.server, args.sender.did, { lastSenderSequence: nextSequence });\n\t\treturn result;\n\t} catch (err) {\n\t\tif (err instanceof ApiError && POST_COMMIT_ERROR_CODES.has(err.payload.code)) {\n\t\t\t// Server persisted the event but the body handler\n\t\t\t// rejected the action. Advance the local counter so\n\t\t\t// the next envelope uses a fresh, server-relative\n\t\t\t// sender_sequence — otherwise we wedge on\n\t\t\t// `ENV_SEQUENCE_BACKWARDS`.\n\t\t\tupdateAgentLocal(args.server, args.sender.did, { lastSenderSequence: nextSequence });\n\t\t}\n\t\tthrow err;\n\t}\n}\n\n/**\n * For counter / sign / decline. If `--version` is supplied, parse\n * and use it as-is (the server still validates that the row exists\n * in the expected state). Otherwise read the contracts timeline\n * with `state=proposed`, filter by `contractId`, and return the\n * latest PROPOSED row's version. Per `00-core/state-machines.md` at\n * most one version of a given `contractId` is in PROPOSED at a\n * time, so the auto-resolve is unambiguous.\n *\n * The server caps `limit` at `MAX_LIST_LIMIT` (100), so a\n * relationship with > 100 PROPOSED contracts can't be answered from\n * a single page. We page with `?after=<id>` until we either find a\n * match or exhaust the result set. Defensive: if a future schema\n * change allows multiple concurrent PROPOSED versions for the same\n * `contractId`, we still pick the highest version across all pages.\n */\nconst TARGET_VERSION_PAGE_SIZE = 100;\n\nexport async function resolveTargetVersion(\n\tcmdName: string,\n\tapi: Pick<ArpApiClient, 'listContracts'>,\n\tsigner: Signer,\n\targs: { relationshipId: string; contractId: string; explicit?: string },\n): Promise<number> {\n\tif (args.explicit !== undefined) {\n\t\treturn parseVersion(cmdName, args.explicit);\n\t}\n\n\tlet after: string | undefined;\n\tlet bestMatch: ContractPublic | null = null;\n\twhile (true) {\n\t\tconst page: ContractPublic[] = await api.listContracts(args.relationshipId, signer, { state: 'proposed', limit: TARGET_VERSION_PAGE_SIZE, after });\n\t\tfor (const row of page) {\n\t\t\tif (row.contractId === args.contractId) {\n\t\t\t\tif (bestMatch === null || row.version > bestMatch.version) {\n\t\t\t\t\tbestMatch = row;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (page.length < TARGET_VERSION_PAGE_SIZE) {\n\t\t\tbreak; // exhausted the result set\n\t\t}\n\t\tafter = page[page.length - 1].id;\n\t}\n\n\tif (bestMatch === null) {\n\t\tthrow new Error(\n\t\t\t`${cmdName}: no PROPOSED version of contract ${args.contractId} found in relationship ${args.relationshipId}. ` +\n\t\t\t\t`Pass --version <n> to target a specific row, or run 'heyarp contracts <relationship-id>' to inspect the timeline.`,\n\t\t);\n\t}\n\treturn bestMatch.version;\n}\n\n/**\n * Counter / sign / decline carry `recipient_did` in the protected\n * block, but the user only supplied a `relationshipId`. Look up the\n * counterparty by reading the contract timeline (state-agnostic,\n * so REPLACED / DECLINED rows still surface a useful proposer)\n * and returning the first DID that ISN'T the signer.\n *\n * Pagination: same trap as `resolveTargetVersion`. The server caps\n * each page at `MAX_LIST_LIMIT` (100). If the signer opened the\n * oldest 100 contract rows themselves and the counterparty's\n * earliest row is on page 2+, a single-page lookup would\n * incorrectly conclude \"every row was opened by me\" and refuse to\n * send. We page until we find a non-self proposer or exhaust the\n * timeline.\n *\n * Exported for unit tests.\n */\nexport async function resolveCounterpartyDid(api: Pick<ArpApiClient, 'listContracts'>, signer: Signer, relationshipId: string, selfDid: string): Promise<string> {\n\tlet after: string | undefined;\n\tlet sawSelfRow = false;\n\twhile (true) {\n\t\tconst page: ContractPublic[] = await api.listContracts(relationshipId, signer, { limit: 100, after });\n\t\tfor (const row of page) {\n\t\t\tif (row.proposerDid !== selfDid) return row.proposerDid;\n\t\t\tsawSelfRow = true;\n\t\t}\n\t\tif (page.length < 100) {\n\t\t\tbreak; // exhausted the result set\n\t\t}\n\t\tafter = page[page.length - 1].id;\n\t}\n\tif (!sawSelfRow) {\n\t\tthrow new Error(\n\t\t\t`contract: relationship ${relationshipId} has no contract rows yet — cannot resolve counterparty DID. ` +\n\t\t\t\t`Run 'heyarp contract propose <recipient-did>' first to open a contract on this relationship.`,\n\t\t);\n\t}\n\tthrow new Error(\n\t\t`contract: cannot resolve counterparty DID for relationship ${relationshipId} from the contract timeline ` +\n\t\t\t`(every row was opened by ${selfDid}). Use 'heyarp relationships ${selfDid}' to find the recipient DID, ` +\n\t\t\t`then send the next contract envelope directly with 'heyarp contract propose <recipient-did>'.`,\n\t);\n}\n\nfunction printIngestResult(result: IngestResult): void {\n\tconsole.log(chalk.green('\\nDelivered.'));\n\tconsole.log(`${chalk.bold('Event id')}: ${chalk.cyan(result.eventId)}`);\n\tconsole.log(`${chalk.bold('Relationship id')}: ${chalk.cyan(result.relationshipId)}`);\n\tconsole.log(`${chalk.bold('Chain index')}: ${chalk.cyan(String(result.relationshipEventIndex))}`);\n\tconsole.log(`${chalk.bold('Server timestamp')}: ${chalk.cyan(result.serverTimestamp)}`);\n\tconsole.log(`${chalk.bold('Server event hash')}: ${chalk.cyan(result.serverEventHash)}`);\n}\n\n/**\n * Map CLI flags onto `ContractContent` term fields. Drops empty\n * optional values so the validator sees a clean shape.\n *\n * Exported for unit tests — the action handlers call it but the\n * surface is pure (no I/O, no state).\n */\nexport function parseTerms(cmdName: string, opts: ContractTermsOptions): Partial<ContractContent> {\n\tconst out: Partial<ContractContent> = {};\n\tif (opts.scope) out.scope_summary = opts.scope;\n\tif (opts.rateAmount) {\n\t\tout.rate_amount = opts.rateAmount;\n\t\tif (!opts.rateCurrency) {\n\t\t\tthrow new Error(`${cmdName}: --rate-amount requires --rate-currency. Shorthand: ${WELL_KNOWN_ASSET_KEYS.join(', ')}, or raw CAIP-19 + --rate-decimals.`);\n\t\t}\n\t\tout.rate_currency = buildAssetIdentifier(cmdName, CONTRACT_RATE_FLAGS, opts.rateCurrency, opts.rateDecimals, opts.rateSymbol);\n\t} else if (opts.rateCurrency) {\n\t\tthrow new Error(`${cmdName}: --rate-currency without --rate-amount is meaningless; omit both or supply both.`);\n\t}\n\tif (opts.rateUnit) {\n\t\tconst allowed = new Set(['task', 'thread', 'handoff']);\n\t\tif (!allowed.has(opts.rateUnit)) throw new Error(`${cmdName}: --rate-unit must be one of task|thread|handoff (got '${opts.rateUnit}')`);\n\t\tout.rate_unit = opts.rateUnit as ContractContent['rate_unit'];\n\t}\n\tif (opts.pricing) {\n\t\t// Narrowed from {flat|quote|subscription|usage_based} to\n\t\t// {flat|usage_based}. `quote` + `subscription` existed in\n\t\t// the earlier enum but were never implemented on the\n\t\t// settlement layer (collapsed to the same code path as flat).\n\t\t// Removed to avoid false promise.\n\t\tconst allowed = new Set(['flat', 'usage_based']);\n\t\tif (!allowed.has(opts.pricing)) throw new Error(`${cmdName}: --pricing must be one of flat|usage_based (got '${opts.pricing}')`);\n\t\tout.pricing_model = opts.pricing as ContractContent['pricing_model'];\n\t}\n\tif (opts.settlement) {\n\t\tconst allowed = new Set(['prepaid', 'escrow']);\n\t\tif (!allowed.has(opts.settlement)) throw new Error(`${cmdName}: --settlement must be one of prepaid|escrow (got '${opts.settlement}')`);\n\t\tout.settlement_model = opts.settlement as ContractContent['settlement_model'];\n\t}\n\tif (opts.delegationTag && opts.delegationTag.length > 0) {\n\t\tout.allowed_delegation_tags = opts.delegationTag;\n\t}\n\treturn out;\n}\n\nexport function parseTtl(cmdName: string, raw: string | undefined): number {\n\tif (raw === undefined) return 3600;\n\tconst n = Number(raw);\n\tif (!Number.isFinite(n) || !Number.isInteger(n) || n <= 0) {\n\t\tthrow new Error(`${cmdName}: --ttl must be a positive integer number of seconds (got '${raw}')`);\n\t}\n\treturn n;\n}\n\nexport function parseVersion(cmdName: string, raw: string): number {\n\tconst n = Number(raw);\n\tif (!Number.isFinite(n) || !Number.isInteger(n) || n < 1) {\n\t\tthrow new Error(`${cmdName}: --version must be a positive integer (got '${raw}')`);\n\t}\n\treturn n;\n}\n\nexport function parseContractId(cmdName: string, raw: string | undefined): string {\n\tif (raw === undefined || raw === '') return uuidV4();\n\t// Hint-rich error if raw is a known non-UUID shape (ObjectId /\n\t// sha256 / del_-prefixed / etc.).\n\tsharedRequireUuid(cmdName, raw, '--contract-id');\n\t// Normalise to lowercase so a copy-pasted uppercase UUID lands on\n\t// the wire in the canonical case the SDK + server generate.\n\t// Without this, `97C7A4B9-...` from a user banner would\n\t// round-trip mixed-case through every subsequent command's\n\t// output, breaking visual consistency. RFC 4122 §3 says\n\t// comparisons should be case-insensitive but canonical rendering\n\t// is lowercase.\n\treturn raw.toLowerCase();\n}\n\nexport function requireDid(cmdName: string, did: string, label: string): void {\n\tif (typeof did !== 'string' || !did.startsWith('did:arp:') || did.length <= 'did:arp:'.length) {\n\t\tthrow new Error(`${cmdName}: ${label} must look like 'did:arp:...' (got '${did}')`);\n\t}\n}\n\n/**\n * Commander option-parser for repeatable string flags\n * (`--delegation-tag a --delegation-tag b`). Commander gives the\n * accumulator the previous value on each call, so we just push.\n */\nexport function collectRepeated(value: string, previous: string[]): string[] {\n\treturn [...previous, value];\n}\n\n/**\n * Resolve a CLI `--rate-currency` / `--currency` value into an\n * `AssetIdentifier`. Two modes:\n *\n * 1. Shorthand (`USDC:solana-mainnet`, `SOL:solana-devnet`, etc.):\n * looked up in the SDK's `WELL_KNOWN_ASSETS` table — `decimals`\n * and `symbol` come from the preset. Operator-provided\n * `--*-decimals` / `--*-symbol` flags override the preset (rare\n * but allowed for testing).\n *\n * 2. Raw CAIP-19 (`solana:5eykt.../spl:EPjFWdd5...`): structural\n * validation only. Operator MUST supply `--*-decimals <N>`\n * because CAIP-19 doesn't encode decimals.\n *\n * Exported for unit tests.\n */\nexport interface AssetFlagLabels {\n\t/** The currency-selector flag — e.g. `--rate-currency` for contract.propose, `--currency` for delegation.offer. */\n\tcurrencyFlag: string;\n\t/** The decimals-override flag — e.g. `--rate-decimals` vs `--currency-decimals`. */\n\tdecimalsFlag: string;\n\t/** The symbol-override flag — e.g. `--rate-symbol` vs `--currency-symbol`. */\n\tsymbolFlag: string;\n}\n\nexport function buildAssetIdentifier(\n\tcmdName: string,\n\tlabels: AssetFlagLabels,\n\trawCurrency: string,\n\trawDecimals: string | undefined,\n\trawSymbol: string | undefined,\n): AssetIdentifier {\n\tconst resolved = resolveAsset(rawCurrency);\n\tif (!resolved) {\n\t\tthrow new Error(\n\t\t\t`${cmdName}: ${labels.currencyFlag} '${rawCurrency}' is not a known shorthand or a valid CAIP-19 string. Shorthand: ${WELL_KNOWN_ASSET_KEYS.join(', ')}. Or pass a raw CAIP-19 id (e.g. \"solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/spl:EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v\") with ${labels.decimalsFlag}.`,\n\t\t);\n\t}\n\tlet decimals = resolved.decimals;\n\tif (Number.isNaN(decimals)) {\n\t\t// Raw CAIP-19 path — decimals required from operator.\n\t\tif (rawDecimals === undefined) {\n\t\t\tthrow new Error(`${cmdName}: ${labels.currencyFlag} is a raw CAIP-19 string; ${labels.decimalsFlag} (0-18) is required to convert amounts to base units.`);\n\t\t}\n\t\tconst parsed = Number(rawDecimals);\n\t\tif (!Number.isInteger(parsed) || parsed < 0 || parsed > 18) {\n\t\t\tthrow new Error(`${cmdName}: ${labels.decimalsFlag} must be an integer in [0, 18] (got '${rawDecimals}').`);\n\t\t}\n\t\tdecimals = parsed;\n\t} else if (rawDecimals !== undefined) {\n\t\t// Shorthand path with operator override.\n\t\tconst parsed = Number(rawDecimals);\n\t\tif (!Number.isInteger(parsed) || parsed < 0 || parsed > 18) {\n\t\t\tthrow new Error(`${cmdName}: ${labels.decimalsFlag} must be an integer in [0, 18] (got '${rawDecimals}').`);\n\t\t}\n\t\tdecimals = parsed;\n\t}\n\tlet symbol = resolved.symbol;\n\tif (rawSymbol !== undefined) {\n\t\tif (rawSymbol.length === 0 || rawSymbol.length > 16) {\n\t\t\tthrow new Error(`${cmdName}: ${labels.symbolFlag} must be 1-16 chars (got length ${rawSymbol.length}).`);\n\t\t}\n\t\tsymbol = rawSymbol;\n\t}\n\treturn symbol !== undefined ? { asset_id: resolved.asset_id, decimals, symbol } : { asset_id: resolved.asset_id, decimals };\n}\n\n/** Pre-built label set for contract.* commands. */\nexport const CONTRACT_RATE_FLAGS: AssetFlagLabels = {\n\tcurrencyFlag: '--rate-currency',\n\tdecimalsFlag: '--rate-decimals',\n\tsymbolFlag: '--rate-symbol',\n};\n\n/** Pre-built label set for delegation.offer. */\nexport const DELEGATION_CURRENCY_FLAGS: AssetFlagLabels = {\n\tcurrencyFlag: '--currency',\n\tdecimalsFlag: '--currency-decimals',\n\tsymbolFlag: '--currency-symbol',\n};\n","/**\n * Centralised UUID / id-shape recognition and hint-rich error\n * messages for the CLI.\n *\n * LLM-agent operators routinely juggle ≥7 id formats at the CLI\n * level — bare UUIDs (delegation/contract/relationship/request ids),\n * del_-prefixed UUIDs, evt_-prefixed ids, 24-hex Mongo ObjectIds\n * (memory entries), sha256:<hex> hashes, DIDs, etc. A generic\n * \"must be a UUID (got 'X')\" error is technically accurate but\n * does nothing to surface \"you probably pasted the wrong field.\"\n * `requireUuid` throws with an inline hint that names the likely\n * source format, and this module is the single source of truth for\n * the recognition regexes.\n */\n\n/**\n * Canonical UUID: 8-4-4-4-12 hex with dashes, case-insensitive. RFC 4122\n * canonical rendering is lowercase, but parsers stay case-insensitive\n * for copy-paste tolerance — callers should normalise to lowercase\n * AFTER validation (see `parseDelegationId`, `parseContractId`).\n */\nexport const UUID_RE = /^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$/;\n\n/**\n * Mongo ObjectId (24 lowercase-hex) — the format returned by\n * `memory list` / `memory show` for memory entry ids. Easy to\n * confuse with a delegation/contract UUID in scripted workflows;\n * the canonical-UUID regex correctly rejects but is hint-poor on\n * its own, which is why we surface a dedicated hint for this shape.\n */\nexport const OBJECT_ID_24_HEX_RE = /^[0-9a-f]{24}$/;\n\n/**\n * Server-side event-hash format: `sha256:<64 lowercase-hex>`. Used for\n * receipt_event_hash, request_hash, response_hash, deliverable_hash —\n * NOT an id, but easy to confuse with one when scripting from JSON\n * output that surfaces both side by side.\n */\nexport const SHA256_PREFIX_RE = /^sha256:[0-9a-f]{64}$/;\n\n/** UUID stripped of dashes (32 hex). Some external services emit this. */\nexport const UUID_NO_DASHES_RE = /^[a-fA-F0-9]{32}$/;\n\n/**\n * Examine a non-UUID string and return a short human hint about what\n * format it LIKELY belongs to. Returns `undefined` when no specific\n * heuristic matches (callers can fall back to the generic\n * `must be a UUID` message).\n *\n * Heuristics intentionally lean toward \"this looks like X\" — a 32-hex\n * string COULD be a UUID with dashes stripped, but it's also the shape\n * of a Solana 64-byte hash hex-encoded down to 32; we surface the\n * most likely source (UUID without dashes) and let the operator\n * confirm.\n *\n * Exported for unit-test coverage.\n */\nexport function describeNonUuidShape(raw: string): string | undefined {\n\tif (raw === '') return 'empty string';\n\tif (raw.startsWith('del_') && UUID_RE.test(raw.slice(4))) {\n\t\t// The same validator is re-used by --contract-id,\n\t\t// <relationship-id>, and other UUID fields — not just\n\t\t// delegation-id. For non-delegation fields, stripping the\n\t\t// `del_` prefix would yield a syntactically valid but\n\t\t// SEMANTICALLY WRONG id (the body uuid is a delegation_id,\n\t\t// not a contract_id / rel_id / etc.), so the hint spells\n\t\t// out both cases.\n\t\treturn \"looks like a delegation id with the canonical `del_` prefix. If this field expects a delegation_id, drop the `del_` prefix and pass the 36-char body. If this field expects a DIFFERENT id type (contract_id / relationship_id / request_id), the `del_`-prefixed value belongs to the WRONG entity — look up the right row and copy its id\";\n\t}\n\tif (raw.startsWith('evt_')) {\n\t\t// The UUID inside `evt_<uuid>` is the EVENT id, not a\n\t\t// delegation/contract/request id. Stripping the prefix\n\t\t// would yield a syntactically valid but semantically wrong\n\t\t// value, so we point at the right column instead.\n\t\treturn 'looks like an event id (evt_<uuid>) — this command expects a delegation/contract/request id (UUID), which is a DIFFERENT column. Look up the row that emitted this event (`heyarp events <rel> --json`) and copy the appropriate id field';\n\t}\n\tif (raw.startsWith('did:arp:')) {\n\t\treturn 'looks like a DID (agent identifier) — this command expects a delegation/contract/request id (UUID), not a DID';\n\t}\n\tif (SHA256_PREFIX_RE.test(raw)) {\n\t\treturn 'looks like a sha256:<hash> — this command expects a UUID, not a hash. sha256: ids show up in receipt_event_hash, request_hash, response_hash';\n\t}\n\tif (OBJECT_ID_24_HEX_RE.test(raw)) {\n\t\treturn 'looks like a Mongo ObjectId (24-hex — e.g. a memory entry id returned by `heyarp memory list` / `memory show`) rather than the expected UUID. Memory entry ids and delegation/contract ids are DIFFERENT formats';\n\t}\n\tif (UUID_NO_DASHES_RE.test(raw)) {\n\t\treturn 'looks like a UUID with no dashes — canonical UUIDs need the 8-4-4-4-12 dash pattern (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)';\n\t}\n\treturn undefined;\n}\n\n/**\n * Throw a hint-rich error when `raw` isn't a canonical UUID. The\n * hint suffix is appended only when `describeNonUuidShape` matched a\n * known non-UUID shape; the base \"must be a UUID (got 'X')\" message\n * is preserved so existing test patterns (`/must be a UUID/`) keep\n * matching.\n *\n * Use this in every CLI command parser that expects a bare UUID\n * argument; the old per-file `UUID_RE` checks are folded into\n * delegating to this function.\n */\nexport function requireUuid(cmdName: string, raw: string, label: string): void {\n\tif (UUID_RE.test(raw)) return;\n\tconst hint = describeNonUuidShape(raw);\n\tconst base = `${cmdName}: ${label} must be a UUID (got '${raw}')`;\n\tthrow new Error(hint ? `${base} — ${hint}` : base);\n}\n","import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { resolveServerUrl } from './api';\nimport { arpHomeDir } from './paths';\n\n/**\n * Local state file: `~/.arp/agents.json`. Indexed by server URL so a\n * single workstation can talk to multiple deployments (dev, staging,\n * prod) without one clobbering the next. Per-DID record holds every\n * piece of secret material the CLI needs to re-sign requests later\n * — keys and the derived scrypt key.\n *\n * SECURITY: file is chmod 0600 after every write. The first line of\n * the JSON is a `_warning` field telling humans not to commit it; the\n * file is a strict superset of secret material — keep it offline.\n */\nexport interface AgentLocalState {\n\tdid: string;\n\tidentityPublicKeyB58: string;\n\tidentitySecretKeyB64: string;\n\tsettlementPublicKeyB58: string;\n\tsettlementSecretKeyB64: string;\n\tscryptKeyB64: string;\n\tscryptSaltB64: string;\n\tscryptSaltId: string;\n\t// V1-alpha: accountId parked. See `apps/arp-server/src/database/arp-agent/schemas/arp-agent.schema.ts`\n\t// for the reactivation note. Existing state files written when the\n\t// field was required will still carry the value; new registrations\n\t// no longer write it. Loader/saver code below tolerates either\n\t// shape (`accountId?: string` would be the type-clean way; we keep\n\t// it commented so this is a 1-line uncomment when launchpad lands).\n\t// accountId: string;\n\tkeyMode: string;\n\t/** owner_id from the original KEY-LINK payload — re-used in rotation attestations to keep the chain stable. Optional only for backward-compat with state files written before V1.1. */\n\townerId?: string;\n\t/** Server-issued attestationId for the current row (KEY-LINK initially, KEY-ROTATION after rotation). Optional only for backward-compat. */\n\tcurrentAttestationId?: string;\n\tname?: string;\n\tdescription?: string;\n\tdefaultEndpointUrl?: string;\n\t/**\n\t * Capability tags — locally cached for `heyarp list` display so we\n\t * don't re-fetch the public profile on every read. Server is the\n\t * source of truth; this is a cached snapshot updated on\n\t * register / update.\n\t */\n\ttags?: string[];\n\tregisteredAt: string;\n\t/** Optional — kept only when the user opts to \"remember password\". Off by default. */\n\tpassword?: string;\n\t/**\n\t * Recovery breadcrumb written BEFORE a rotation request hits the\n\t * server, so a post-commit local-write failure cannot lock the\n\t * owner out. Cleared on successful commit + apply. If you find\n\t * one of these on disk, the new keypair is what's currently live\n\t * server-side.\n\t */\n\tpendingRotation?: {\n\t\tnewIdentityPublicKeyB58: string;\n\t\tnewIdentitySecretKeyB64: string;\n\t\tissuedAt: string;\n\t};\n\t/**\n\t * Highest `sender_sequence` we have successfully ingested for this\n\t * agent. The next outgoing envelope MUST use `lastSenderSequence + 1`\n\t * (per-sender monotonic, see protocol). Optional only for backward\n\t * compatibility with state files written before V1 messaging — when\n\t * absent, treat as 0 and start from 1.\n\t *\n\t * Persisted only AFTER the server confirms ingest, so a network /\n\t * server failure leaves state untouched and the caller can retry\n\t * the same sequence number.\n\t */\n\tlastSenderSequence?: number;\n}\n\ninterface ServerState {\n\tagents: Record<string, AgentLocalState>;\n}\n\ninterface StateFile {\n\t_warning: string;\n\tservers: Record<string, ServerState>;\n}\n\nconst STATE_WARNING = 'DO NOT COMMIT — contains private keys (Ed25519 + derived scrypt).';\n\nexport function stateFilePath(): string {\n\treturn join(arpHomeDir(), 'agents.json');\n}\n\nfunction emptyStateFile(): StateFile {\n\treturn { _warning: STATE_WARNING, servers: {} };\n}\n\nfunction readStateFile(): StateFile {\n\tconst path = stateFilePath();\n\tif (!existsSync(path)) return emptyStateFile();\n\tlet raw: string;\n\ttry {\n\t\traw = readFileSync(path, 'utf8');\n\t} catch (err) {\n\t\tthrow new Error(`Failed to read state file at ${path}: ${(err as Error).message}`);\n\t}\n\tif (raw.trim().length === 0) return emptyStateFile();\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(raw);\n\t} catch {\n\t\tthrow new Error(`State file at ${path} is not valid JSON. Move or delete it before running again.`);\n\t}\n\t// Tolerant migration: if older shape lacked `_warning`, just refresh.\n\tif (parsed === null || typeof parsed !== 'object') return emptyStateFile();\n\tconst obj = parsed as Partial<StateFile>;\n\treturn {\n\t\t_warning: STATE_WARNING,\n\t\tservers: obj.servers ?? {},\n\t};\n}\n\nfunction writeStateFile(state: StateFile): void {\n\tconst path = stateFilePath();\n\tconst dir = dirname(path);\n\tif (!existsSync(dir)) {\n\t\tmkdirSync(dir, { recursive: true, mode: 0o700 });\n\t}\n\tconst body = JSON.stringify(state, null, 2);\n\twriteFileSync(path, body, { encoding: 'utf8', mode: 0o600 });\n\ttry {\n\t\t// Re-apply 0600 because writeFileSync's mode is honoured only on\n\t\t// initial creation; if the file already existed with looser perms\n\t\t// we want to tighten them every save.\n\t\tchmodSync(path, 0o600);\n\t} catch {\n\t\t// Best-effort: ignore on platforms without POSIX chmod semantics.\n\t}\n}\n\n/**\n * Persist a freshly registered agent. Keyed by `serverUrl` (resolved\n * the same way the API client does — defaults + env + override) so\n * dev / prod state stay isolated.\n */\nexport function saveAgent(serverOverride: string | undefined, agent: AgentLocalState): void {\n\tconst key = resolveServerUrl(serverOverride);\n\tconst state = readStateFile();\n\tif (!state.servers[key]) state.servers[key] = { agents: {} };\n\tstate.servers[key].agents[agent.did] = agent;\n\twriteStateFile(state);\n}\n\nexport function loadAgent(serverOverride: string | undefined, did: string): AgentLocalState | null {\n\tconst key = resolveServerUrl(serverOverride);\n\tconst state = readStateFile();\n\treturn state.servers[key]?.agents[did] ?? null;\n}\n\n/**\n * Same as `loadAgent` but throws a CLI-friendly error instead of\n * returning `null`. Use it from command handlers that can't proceed\n * without local secret material.\n */\nexport function loadAgentOrThrow(serverOverride: string | undefined, did: string): AgentLocalState {\n\tconst agent = loadAgent(serverOverride, did);\n\tif (!agent) {\n\t\tconst url = resolveServerUrl(serverOverride);\n\t\tthrow new Error(`No local state for ${did} on ${url}. Run 'heyarp register' first or check the --server flag.`);\n\t}\n\treturn agent;\n}\n\n/**\n * Apply a partial update to a stored agent — used by `heyarp rotate` to\n * swap the identity key (DID stays frozen) and any subsequent\n * \"remember the latest profile\" caches.\n */\nexport function updateAgentLocal(serverOverride: string | undefined, did: string, patch: Partial<AgentLocalState>): void {\n\tconst key = resolveServerUrl(serverOverride);\n\tconst state = readStateFile();\n\tconst server = state.servers[key];\n\tif (!server || !server.agents[did]) {\n\t\tthrow new Error(`Cannot update local state — no record for ${did} on ${key}.`);\n\t}\n\tserver.agents[did] = { ...server.agents[did], ...patch };\n\twriteStateFile(state);\n}\n\n/**\n * Resolve the sender DID for a per-DID command (everything that\n * signs envelopes — handshake / contract / delegation / work /\n * receipt). Centralised so every command applies the same priority\n * and emits a consistent disambiguation error.\n *\n * Priority (high → low):\n * 1. `--from-did` flag — explicit per-invocation override.\n * 2. Sole agent registered for this server — the common\n * single-identity-per-host dev setup.\n * 3. >1 agent without --from-did → strict failure with the\n * candidate list. No silent fallback to a \"first one\n * alphabetical\" pick — that would silently sign as the\n * wrong DID and surface as cryptic auth errors several\n * commands later. Failing here makes the bad path obvious\n * and recoverable.\n *\n * Per-agent isolation across multiple DIDs on one host is meant\n * to be solved by `HEYARP_HOME`, not by a per-server `defaultDid`\n * config key (a single global config is necessarily last-writer-\n * wins, which silently clobbers between shells). If a user has\n * multiple DIDs sharing one home dir, `--from-did` is the answer.\n *\n * @param cmdName Short command label, used as the error prefix\n * (e.g. `'send-handshake'`, `'contract propose'`).\n * @param serverOverride The `--server` flag value (or undefined).\n * Drives the state-file lookup so a `--server`\n * flag automatically scopes to the right agent set.\n * @param explicitFromDid The `--from-did` flag value (or undefined).\n */\nexport function resolveSenderAgent(cmdName: string, serverOverride: string | undefined, explicitFromDid: string | undefined): AgentLocalState {\n\tconst resolvedServerUrl = resolveServerUrl(serverOverride);\n\n\t// 1. Explicit --from-did takes precedence over everything.\n\tif (explicitFromDid) {\n\t\treturn loadAgentOrThrow(serverOverride, explicitFromDid);\n\t}\n\n\t// 2. Sole-agent fallback — works for the single-DID-per-home dev setup.\n\tconst onServer = listAgents().filter((row) => row.serverUrl === resolvedServerUrl);\n\tif (onServer.length === 1) {\n\t\treturn onServer[0].agent;\n\t}\n\tif (onServer.length === 0) {\n\t\tthrow new Error(`${cmdName}: no agents registered for ${resolvedServerUrl}. Run 'heyarp register' first.`);\n\t}\n\n\t// 3. Multiple agents + no preference — STRICT mode. Print the\n\t// list so the operator knows exactly what to pass to --from-did\n\t// (or which HOME to scope to once HEYARP_HOME lands).\n\tconst list = onServer.map((row) => ` ${row.agent.did}${row.agent.name ? ` (${row.agent.name})` : ''}`).join('\\n');\n\tthrow new Error(\n\t\t`${cmdName}: ${onServer.length} agents registered for ${resolvedServerUrl} — refusing to silently sign as one of them. Pass --from-did <did> to disambiguate. Candidates:\\n${list}`,\n\t);\n}\n\n/**\n * List every agent across every server. The `serverUrl` is surfaced\n * alongside each record so `heyarp list` can group / filter without a\n * second pass over the file.\n */\nexport function listAgents(): { serverUrl: string; agent: AgentLocalState }[] {\n\tconst state = readStateFile();\n\tconst out: { serverUrl: string; agent: AgentLocalState }[] = [];\n\tfor (const [serverUrl, server] of Object.entries(state.servers)) {\n\t\tfor (const agent of Object.values(server.agents)) {\n\t\t\tout.push({ serverUrl, agent });\n\t\t}\n\t}\n\treturn out;\n}\n","import {\n\tDECLINE_REASONS,\n\ttype DeclineReason,\n\ttype DelegationBody,\n\ttype DelegationContent,\n\ttype Did,\n\tPurpose,\n\ttype SignableProtected,\n\tWELL_KNOWN_ASSET_KEYS,\n\texpiresAt,\n\tisDeclineReason,\n\trfc3339,\n\tsenderNonce,\n\tsignEnvelope,\n\tuuidV4,\n} from '@heyanon-arp/sdk';\nimport { readFileSync } from 'node:fs';\nimport chalk from 'chalk';\nimport type { Command } from 'commander';\nimport { ApiError, ArpApiClient, type DelegationPublic, type IngestResult, type Signer } from '../api';\nimport { formatJson } from '../format';\nimport { UUID_RE, requireUuid as sharedRequireUuid } from '../id-format';\nimport { type AgentLocalState, resolveSenderAgent, updateAgentLocal } from '../state';\nimport { DELEGATION_CURRENCY_FLAGS, buildAssetIdentifier } from './contract';\nimport { makeSigner } from './lifecycle';\nimport { type ResolveProgramIdSource, resolveProgramIdWithSource } from './wallet';\n\n/**\n * `heyarp delegation <action>` — full client side of the delegation FSM:\n *\n * offer <recipient-did> <contract-id> — open at PROPOSED\n * accept <relationship-id> <delegation-id> — promote PROPOSED → ACCEPTED\n * decline <relationship-id> <delegation-id> — terminate PROPOSED\n * cancel <relationship-id> <delegation-id> — withdraw own PROPOSED offer\n *\n * Same shape as `heyarp contract <action>` — thin wrappers around a\n * shared `sendDelegationEnvelope` helper that allocates the next\n * `sender_sequence` from local state, signs the envelope, dispatches\n * `POST /v1/messages`, and advances `lastSenderSequence` on\n * confirmed ingest OR on a post-commit body-handler reject. Pre-commit\n * rejects (envelope validator) leave the sequence untouched so a\n * retry uses the same number safely — see `POST_COMMIT_ERROR_CODES`\n * for the precise list.\n *\n * accept / decline / cancel reference an existing delegation. They\n * auto-resolve `recipient_did` and the parent `contract_id` from the\n * delegation row by reading the `/contracts` + `/delegations`\n * timeline so the operator only needs the `relationship-id` +\n * `delegation-id` pair. Pass `--contract-id <uuid>` to skip the\n * contract lookup or override it explicitly.\n */\nexport function registerDelegationCommands(root: Command): void {\n\tconst cmd = root.command('delegation').description('Delegation FSM actions: offer / accept / decline / cancel');\n\n\tregisterOffer(cmd);\n\tregisterAccept(cmd);\n\tregisterDecline(cmd);\n\tregisterCancel(cmd);\n}\n\n/**\n * Error codes that indicate the server PERSISTED the event (so the\n * `sender_sequence` was consumed) but the body handler then rejected\n * the action. Mirror of the contract list — every delegation handler\n * error in\n * `apps/arp-server/src/message/services/delegation-handler.service.ts`\n * fires AFTER the event row has been written. If we don't bump\n * `lastSenderSequence` for these the next envelope reuses an\n * already-consumed sequence and gets stuck on\n * `ENV_SEQUENCE_BACKWARDS`.\n */\nexport const POST_COMMIT_ERROR_CODES = new Set([\n\t'DELEGATION_ALREADY_EXISTS',\n\t'DELEGATION_INVALID_STATE',\n\t'DELEGATION_NOT_FOUND',\n\t'DELEGATION_RELATIONSHIP_MISMATCH',\n\t'DELEGATION_CONTRACT_MISMATCH',\n\t'DELEGATION_CONTRACT_NOT_ACTIVE',\n\t'DELEGATION_ACCEPTER_IS_OFFERER',\n\t'DELEGATION_DECLINER_IS_OFFERER',\n\t'DELEGATION_CANCELER_NOT_OFFERER',\n\t// `DELEGATION_PENDING_LOCK` fires from the body handler's\n\t// `requireDelegationInState` AFTER the event row is persisted\n\t// (same code path as DELEGATION_INVALID_STATE), so an accept\n\t// against a PENDING_LOCK delegation consumes sender_sequence\n\t// even though it rejects.\n\t'DELEGATION_PENDING_LOCK',\n\t// V1.5 lock-validator mint.owner pre-flight — kept here for\n\t// documentation, but the `isPostCommitErrorCode` helper below\n\t// also matches any `ESC_LOCK_*` prefix. The full lock-validator\n\t// cross-check set (ID_MISMATCH, CONDITION_HASH_MISMATCH,\n\t// AMOUNT_DELEGATION_MISMATCH, EXPIRY_TOO_*, PDA_*, etc.) ALSO\n\t// fires after the delegation event is committed; missing\n\t// entries here would leave `lastSenderSequence` stale and stall\n\t// retries on ENV_SEQUENCE_BACKWARDS.\n\t'ESC_LOCK_MINT_RPC_FAILED',\n\t'ESC_LOCK_MINT_NOT_FOUND',\n\t'ESC_LOCK_MINT_OWNER_MISMATCH',\n]);\n\n/**\n * Every error code surfacing from the delegation handler's escrow\n * cross-check path fires AFTER the event row is persisted.\n * Enumerating them by hand is fragile — the on-chain validator is\n * the source of truth and grows new codes per slice. Treat any code\n * matching `ESC_LOCK_*` as post-commit; the few that could fire\n * pre-commit (currently none — `ESC_LOCK_MISSING` is the only\n * candidate, and even it lives behind the validator's commit-on-\n * accept barrier) are still safer to advance the sequence on than\n * to roll back, because the server has already counted the envelope\n * toward sender_sequence.\n */\nexport function isPostCommitErrorCode(code: string): boolean {\n\t// Any SDK-layer throw that reaches the global Internal exception\n\t// filter fires AFTER the event row has been committed (the\n\t// message handler always commits before invoking body-specific\n\t// validators that call into the SDK). Treat `SDK_*` codes the\n\t// same way as `ESC_LOCK_*` so the CLI advances\n\t// `lastSenderSequence` instead of looping on\n\t// `ENV_SEQUENCE_BACKWARDS`.\n\treturn POST_COMMIT_ERROR_CODES.has(code) || code.startsWith('ESC_LOCK_') || code.startsWith('SDK_');\n}\n\n// ---------- offer ----------\n\ninterface OfferOptions extends BaseSendOptions, OfferTermsOptions {\n\tdelegationId?: string;\n\t/**\n\t * Escrow integration.\n\t *\n\t * Server's EnvelopeValidator requires `attachments.escrow_lock` on\n\t * `delegation.offer` envelopes and throws `ESC_LOCK_MISSING`\n\t * (POST_COMMIT — sender_sequence consumed) when absent. To fail-fast\n\t * BEFORE the envelope is sent:\n\t * - default behaviour: require the escrow_lock attachment\n\t * - `--no-escrow` is the explicit opt-out for test_mode servers\n\t *\n\t * Two ways to supply the attachment:\n\t * 1. `--escrow-lock-from-file <path>` — JSON output of\n\t * `heyarp wallet create-lock` (recommended; 5 fields auto-mapped).\n\t * 2. Inline flags: `--escrow-lock-blob` + `--escrow-lock-id` +\n\t * `--escrow-lock-amount` + `--escrow-lock-asset-id` +\n\t * `--escrow-lock-expiry` (all 5 required together).\n\t *\n\t * Worker→buyer sig handoff is unrelated and lives on the cosign side.\n\t */\n\tescrowLockFromFile?: string;\n\tescrowLockBlob?: string;\n\tescrowLockId?: string;\n\tescrowLockAmount?: string;\n\tescrowLockAssetId?: string;\n\tescrowLockExpiry?: string;\n\t/**\n\t * Expected on-chain program id for the pre-flight check against\n\t * the lock file's embedded program_id. Precedence: --program-id\n\t * flag > ARP_ESCROW_PROGRAM_ID env > server\n\t * `GET /v1/escrow/protocol-fee`. If all three resolve to the\n\t * hardcoded fallback placeholder, pre-flight is skipped (we\n\t * can't trust the placeholder as authoritative).\n\t */\n\tprogramId?: string;\n\t/**\n\t * Commander quirk: `.option('--no-escrow', ...)` produces\n\t * `opts.escrow === false` when the flag is supplied (negated\n\t * option semantics), NOT `opts.escrow === false === true`. The option name\n\t * here MUST match commander's auto-derived name — `escrow` — so\n\t * the runtime CLI invocation works. Default (no flag) is `true`.\n\t * Treat `opts.escrow === false` as the explicit opt-out signal.\n\t */\n\tescrow?: boolean;\n}\n\nfunction registerOffer(parent: Command): void {\n\tparent\n\t\t.command('offer')\n\t\t.description('Open a new delegation under <contract-id> (must be ACTIVE) addressed to <recipient-did>.')\n\t\t.argument('<recipient-did>', 'Recipient agent DID (did:arp:...)')\n\t\t.argument('<contract-id>', 'Contract id this delegation operates under (must be ACTIVE)')\n\t\t.option('--server <url>', 'Override ARP server base URL')\n\t\t.option('--from-did <did>', 'Sender DID — required only if multiple agents are registered against this server')\n\t\t.option('--delegation-id <uuid>', 'Override the auto-generated delegation id (UUID). Useful for replay / scripting.')\n\t\t.option('--title <s>', 'Required: human-readable title for the offer')\n\t\t.option('--brief <json>', 'Optional structured brief (JSON object)')\n\t\t.option('--criterion <s>', 'acceptance_criteria — repeatable; pass --criterion once per bullet', collectRepeated, [])\n\t\t.option('--deadline <rfc3339>', 'Optional RFC 3339 deadline (e.g. \"2026-12-31T23:59:59Z\")')\n\t\t.option('--amount <s>', 'Optional decimal-as-string amount (e.g. \"10.00\"). REQUIRES --currency if set.')\n\t\t.option('--currency <s>', `Asset identifier: shorthand (${WELL_KNOWN_ASSET_KEYS.join('|')}) OR raw CAIP-19 string.`)\n\t\t.option('--currency-decimals <n>', 'Decimal places for base-unit conversion (0-18). Required only when --currency is raw CAIP-19.')\n\t\t.option('--currency-symbol <s>', 'Optional UI hint (\"USDC\", \"SOL\"). Max 16 chars.')\n\t\t.option('--ttl <seconds>', 'Envelope TTL in seconds (max 86400 = 24h)', '3600')\n\t\t.option('--verbose', 'Print the full envelope before sending and the full server response', false)\n\t\t// Escrow flags. Pass --escrow-lock-from-file (recommended)\n\t\t// OR the full inline set. Default REQUIRES the escrow_lock\n\t\t// attachment; --no-escrow is the explicit opt-out for\n\t\t// test_mode servers.\n\t\t.option(\n\t\t\t'--escrow-lock-from-file <path>',\n\t\t\t'Path to JSON output of `heyarp wallet create-lock` (recommended). Contains all 5 escrow_lock fields: signed_tx_blob, lock_id, amount, asset_id, expiry. Mutually exclusive with the inline --escrow-lock-* flags below.',\n\t\t)\n\t\t.option('--escrow-lock-blob <base64>', 'INLINE alternative: the signed Solana tx blob (base64). Requires --escrow-lock-id, --escrow-lock-amount, --escrow-lock-asset-id, --escrow-lock-expiry together.')\n\t\t.option('--escrow-lock-id <hex32>', 'INLINE lock_id (32-byte hex). Used with --escrow-lock-blob.')\n\t\t.option('--escrow-lock-amount <int>', 'INLINE lock amount in base units (e.g. lamports for native SOL). Used with --escrow-lock-blob.')\n\t\t.option('--escrow-lock-asset-id <caip19>', 'INLINE currency CAIP-19 asset_id (e.g. solana:<cluster_id>/slip44:501). Used with --escrow-lock-blob.')\n\t\t.option('--escrow-lock-expiry <unix>', 'INLINE expiry as unix seconds. Used with --escrow-lock-blob.')\n\t\t.option(\n\t\t\t'--program-id <pubkey>',\n\t\t\t'Expected ARP escrow program id for pre-flight against the lock file\\'s embedded `program_id`. Precedence: this flag > ARP_ESCROW_PROGRAM_ID env > server protocol-fee endpoint. Mismatch throws BEFORE the envelope ships, so a wrong-program lock never silently fails on chain after the offer was already delivered. Pre-flight is skipped only for old lock files lacking `program_id`, or when no expected value can be resolved.',\n\t\t)\n\t\t// Commander stores `--no-escrow` as `opts.escrow === false`\n\t\t// (negated-option semantics). Do NOT pass an explicit default\n\t\t// here — commander defaults `escrow` to `true` when the flag\n\t\t// is absent, which is what we want.\n\t\t.option('--no-escrow', 'Opt-out for test_mode servers. Default REQUIRES the escrow_lock attachment; without --no-escrow, missing flags throw BEFORE the envelope is sent (avoids ESC_LOCK_MISSING POST_COMMIT consuming sender_sequence).')\n\t\t.action(async (recipientDid: string, contractId: string, opts: OfferOptions) => {\n\t\t\tawait runOffer(recipientDid, contractId, opts);\n\t\t});\n}\n\n/**\n * Result shape of `assembleEscrowLockAttachment`.\n *\n * - `attachment` is the wire-shaped 5-field object (`signed_tx_blob`,\n * `lock_id`, `amount`, `asset_id`, `expiry`) that goes into\n * `attachments.escrow_lock`. `delegation_id` is intentionally NOT\n * inside `attachment` — the server reads delegation_id from\n * `body.content.delegation_id` and derives `lock_id` from it; adding\n * delegation_id to the attachment would be redundant and risks the\n * envelope-validator rejecting unknown keys in future revisions.\n *\n * - `delegationIdFromLock` is populated ONLY when the from-file path is\n * used AND the file includes the `delegation_id` field (new in the\n * wallet output). Inline-flag callers must pass\n * `--delegation-id` explicitly; without it, `runOffer` throws to\n * prevent the guaranteed-mismatch flow.\n */\nexport interface EscrowAttachmentResult {\n\tattachment: Record<string, unknown>;\n\tdelegationIdFromLock?: string;\n\t/**\n\t * On-chain program id the lock tx was built against, persisted by\n\t * `wallet create-lock --json`. Populated ONLY on the from-file\n\t * path AND only when the file includes the `program_id` field.\n\t * Inline-flag callers can't recover this (no signed tx parsing\n\t * in the CLI), so pre-flight validation is from-file-only — a\n\t * known limitation documented in the offer command's --help text.\n\t *\n\t * `runOffer` cross-checks this against its own resolved program-id\n\t * (from --program-id, env, or server discovery) BEFORE shipping\n\t * the envelope. Mismatch → throw with remediation directive;\n\t * envelope never reaches the wire (no sender_sequence burn).\n\t */\n\tlockProgramId?: string;\n}\n\n/**\n * Outcome of the pre-flight program-id check.\n *\n * - `match`: lockProgramId === expectedProgramId. Envelope ships.\n * - `mismatch`: hard failure. `runOffer` throws with directive copy.\n * - `skipped_no_lock_program_id`: old lock file without `program_id`.\n * Pre-flight can't run; envelope ships but server-side check is\n * still the backstop (ESC_LOCK_TX_PROGRAM_ID_MISMATCH POST_COMMIT).\n * - `skipped_no_expected_program_id`: no --program-id flag, no env,\n * no server discovery → CLI fell back to placeholder. Don't trust\n * it as authoritative; let the envelope ship and rely on server.\n *\n * IMPORTANT: the skip-on-fallback tier is driven by the `source` tag\n * returned by `resolveProgramIdWithSource`, NOT by string-equality\n * against `FALLBACK_PROGRAM_ID`. The hardcoded fallback IS the\n * deployed contract's canonical placeholder on devnet — a value-\n * equality skip would mis-classify a perfectly-good `source=server`\n * answer as \"fell back to placeholder\" and silently disable the\n * preflight every smoke run.\n */\nexport type PreflightProgramIdResult =\n\t| { kind: 'match'; programId: string }\n\t| { kind: 'mismatch'; lockProgramId: string; expectedProgramId: string }\n\t| { kind: 'skipped_no_lock_program_id'; expectedProgramId: string }\n\t| { kind: 'skipped_no_expected_program_id'; lockProgramId: string | undefined };\n\n/**\n * Cross-check the program id baked into the lock file against the\n * operator's expected program id BEFORE shipping the envelope. Pure\n * function — easy to unit-test the four outcomes without spinning\n * up an API client.\n *\n * Why this matters: without the pre-flight, the protocol-layer\n * envelope can ship cleanly even though the lock-tx is doomed; the\n * escrow worker then invalidates the delegation seconds later with\n * no diagnostic surfaced (the offer printed `Delivered.` and exited\n * 0 alongside an `ESC_LOCK_TX_PROGRAM_ID_MISMATCH` line on stderr).\n * Catching this at the CLI BEFORE envelope-build means no\n * sender_sequence is burned and the operator gets an actionable\n * error immediately.\n *\n * `expectedSource` is the tier-of-origin from `resolveProgramIdWithSource`.\n * Only `source === 'fallback'` defeats the strict check — a server\n * answer that happens to equal `FALLBACK_PROGRAM_ID` byte-for-byte\n * is still authoritative.\n *\n * Exported for unit-test coverage.\n */\nexport function preflightLockProgramId(input: {\n\tlockProgramId: string | undefined;\n\texpectedProgramId: string;\n\texpectedSource: ResolveProgramIdSource;\n}): PreflightProgramIdResult {\n\tconst { lockProgramId, expectedProgramId, expectedSource } = input;\n\t// Tier 1: no lock-side program id (old lock file, pre-R8) → skip.\n\tif (lockProgramId === undefined) {\n\t\treturn { kind: 'skipped_no_lock_program_id', expectedProgramId };\n\t}\n\t// Tier 2: expected resolved via the hardcoded fallback (no flag,\n\t// no env, server unreachable) → skip. The lock file's value is\n\t// also probably the placeholder in this case (operator forgot to\n\t// configure both sides), so we let the server-side check be the\n\t// source of truth.\n\tif (expectedSource === 'fallback') {\n\t\treturn { kind: 'skipped_no_expected_program_id', lockProgramId };\n\t}\n\t// Tier 3: hard check.\n\tif (lockProgramId !== expectedProgramId) {\n\t\treturn { kind: 'mismatch', lockProgramId, expectedProgramId };\n\t}\n\treturn { kind: 'match', programId: expectedProgramId };\n}\n\n/**\n * Build the `attachments.escrow_lock` object from CLI flags.\n *\n * Two input paths (mutually exclusive):\n * - `--escrow-lock-from-file <path>` reads JSON output of\n * `heyarp wallet create-lock` and validates the 5 fields plus the\n * optional `delegation_id` field (used by `runOffer` to align\n * `body.content.delegation_id` with the id baked into `lock_id`).\n * - Inline `--escrow-lock-blob` + 4 metadata flags assembles\n * the same shape from individual arguments. No delegation_id is\n * recoverable here — callers MUST pass `--delegation-id` matching\n * the id used at `wallet create-lock` time.\n *\n * Returns `{ attachment, delegationIdFromLock? }`, OR `undefined` IFF\n * `--no-escrow` was passed.\n *\n * Throws on:\n * - missing all flags AND no `--no-escrow` (fail-fast)\n * - partial inline flag set (some but not all)\n * - `--no-escrow` combined with explicit flags\n * - `--from-file` combined with any inline flag\n * - unreadable / non-JSON file\n * - missing fields in the file's JSON\n * - invalid `expiry` (must be positive integer unix seconds)\n * - file `delegation_id` present but not a UUID-shaped string\n *\n * Exported for unit-test coverage.\n */\nexport function assembleEscrowLockAttachment(opts: OfferOptions): EscrowAttachmentResult | undefined {\n\tconst fromFile = opts.escrowLockFromFile;\n\tconst inlineFlags = [opts.escrowLockBlob, opts.escrowLockId, opts.escrowLockAmount, opts.escrowLockAssetId, opts.escrowLockExpiry];\n\tconst someInlineSet = inlineFlags.some((f) => f !== undefined && f !== '');\n\tconst allInlineSet = inlineFlags.every((f) => f !== undefined && f !== '');\n\n\t// Mutex: --from-file and inline cannot mix.\n\tif (fromFile && someInlineSet) {\n\t\tthrow new Error(\n\t\t\t'delegation offer: --escrow-lock-from-file and --escrow-lock-blob/--escrow-lock-* are mutually exclusive. Pick one path.',\n\t\t);\n\t}\n\n\t// Nothing supplied.\n\tif (!fromFile && !someInlineSet) {\n\t\tif (opts.escrow === false) return undefined;\n\t\tthrow new Error(\n\t\t\t'delegation offer: escrow_lock is required. Pass --escrow-lock-from-file <path> (JSON output of `heyarp wallet create-lock`), OR all of --escrow-lock-blob/--escrow-lock-id/--escrow-lock-amount/--escrow-lock-asset-id/--escrow-lock-expiry, OR --no-escrow if the server is in test_mode.',\n\t\t);\n\t}\n\n\t// Combined --no-escrow with explicit flags — operator confusion.\n\tif (opts.escrow === false) {\n\t\tthrow new Error('delegation offer: --no-escrow is mutually exclusive with explicit escrow_lock flags. Pick one path.');\n\t}\n\n\t// From-file path.\n\tif (fromFile) {\n\t\tlet raw: string;\n\t\ttry {\n\t\t\traw = readFileSync(fromFile, 'utf8');\n\t\t} catch (err) {\n\t\t\tthrow new Error(`delegation offer: failed to read --escrow-lock-from-file '${fromFile}': ${(err as Error).message}`);\n\t\t}\n\t\tlet parsed: unknown;\n\t\ttry {\n\t\t\tparsed = JSON.parse(raw);\n\t\t} catch (err) {\n\t\t\tthrow new Error(`delegation offer: --escrow-lock-from-file '${fromFile}' is not valid JSON: ${(err as Error).message}`);\n\t\t}\n\t\tif (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n\t\t\tthrow new Error(`delegation offer: --escrow-lock-from-file '${fromFile}' must be a JSON object, got ${Array.isArray(parsed) ? 'array' : typeof parsed}.`);\n\t\t}\n\t\tconst p = parsed as Record<string, unknown>;\n\t\tconst required: ReadonlyArray<keyof typeof p> = ['signed_tx_blob', 'lock_id', 'amount', 'asset_id', 'expiry'];\n\t\tconst missing = required.filter((k) => p[k] === undefined);\n\t\tif (missing.length > 0) {\n\t\t\tthrow new Error(\n\t\t\t\t`delegation offer: --escrow-lock-from-file '${fromFile}' is missing required fields: ${missing.join(', ')}. Expected JSON output of \\`heyarp wallet create-lock\\`.`,\n\t\t\t);\n\t\t}\n\t\t// Expiry must be a positive integer. Strict: reject malformed\n\t\t// strings like \"1900abc\" or \"12.5\" — Number.parseInt would\n\t\t// silently accept these. Use Number(...) which fails the\n\t\t// whole string OR round-trip the numeric representation\n\t\t// back to its raw form.\n\t\tconst expiryRaw = p.expiry;\n\t\tlet expiryNum: number;\n\t\tif (typeof expiryRaw === 'number') {\n\t\t\texpiryNum = expiryRaw;\n\t\t} else if (typeof expiryRaw === 'string') {\n\t\t\texpiryNum = Number(expiryRaw);\n\t\t\tif (String(expiryNum) !== expiryRaw.trim()) {\n\t\t\t\tthrow new Error(`delegation offer: --escrow-lock-from-file '${fromFile}' has invalid 'expiry' (must be positive integer unix seconds): ${JSON.stringify(expiryRaw)}.`);\n\t\t\t}\n\t\t} else {\n\t\t\tthrow new Error(`delegation offer: --escrow-lock-from-file '${fromFile}' has invalid 'expiry' (must be positive integer unix seconds): ${JSON.stringify(expiryRaw)}.`);\n\t\t}\n\t\tif (!Number.isFinite(expiryNum) || !Number.isInteger(expiryNum) || expiryNum <= 0) {\n\t\t\tthrow new Error(`delegation offer: --escrow-lock-from-file '${fromFile}' has invalid 'expiry' (must be positive integer unix seconds): ${JSON.stringify(expiryRaw)}.`);\n\t\t}\n\n\t\t// Pull delegation_id when the file ships it so the caller can\n\t\t// auto-align body.content.delegation_id with the id baked\n\t\t// into lock_id. Old lock files that predate this field are\n\t\t// still accepted (returns undefined → caller throws only if\n\t\t// --delegation-id was also omitted).\n\t\tlet delegationIdFromLock: string | undefined;\n\t\tif (p.delegation_id !== undefined) {\n\t\t\tif (typeof p.delegation_id !== 'string' || !UUID_RE.test(p.delegation_id)) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`delegation offer: --escrow-lock-from-file '${fromFile}' has invalid 'delegation_id' (must be a UUID): ${JSON.stringify(p.delegation_id)}.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tdelegationIdFromLock = p.delegation_id.toLowerCase();\n\t\t}\n\n\t\t// Pull program_id when the file ships it. Older lock files\n\t\t// without this field are still accepted but pre-flight\n\t\t// validation is skipped (returns undefined). New files\n\t\t// always carry it.\n\t\tlet lockProgramId: string | undefined;\n\t\tif (p.program_id !== undefined) {\n\t\t\tif (typeof p.program_id !== 'string' || p.program_id.length < 32 || p.program_id.length > 44) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`delegation offer: --escrow-lock-from-file '${fromFile}' has invalid 'program_id' (must be a base58 Solana pubkey, 32-44 chars): ${JSON.stringify(p.program_id)}.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tlockProgramId = p.program_id;\n\t\t}\n\n\t\treturn {\n\t\t\tattachment: {\n\t\t\t\tsigned_tx_blob: String(p.signed_tx_blob),\n\t\t\t\tlock_id: String(p.lock_id),\n\t\t\t\tamount: String(p.amount),\n\t\t\t\tasset_id: String(p.asset_id),\n\t\t\t\texpiry: expiryNum,\n\t\t\t},\n\t\t\tdelegationIdFromLock,\n\t\t\tlockProgramId,\n\t\t};\n\t}\n\n\t// Inline path — need all 5 flags.\n\tif (!allInlineSet) {\n\t\tthrow new Error(\n\t\t\t'delegation offer: when using inline escrow flags, --escrow-lock-blob requires all of --escrow-lock-id, --escrow-lock-amount, --escrow-lock-asset-id, --escrow-lock-expiry to be set together.',\n\t\t);\n\t}\n\t// Expiry must be a positive integer (unix seconds).\n\tconst expiryStr = opts.escrowLockExpiry ?? '';\n\tconst expiryNum = Number.parseInt(expiryStr, 10);\n\tif (!Number.isFinite(expiryNum) || !Number.isInteger(expiryNum) || expiryNum <= 0 || String(expiryNum) !== expiryStr) {\n\t\tthrow new Error(`delegation offer: --escrow-lock-expiry must be a positive integer (unix seconds), got '${expiryStr}'.`);\n\t}\n\treturn {\n\t\tattachment: {\n\t\t\tsigned_tx_blob: opts.escrowLockBlob,\n\t\t\tlock_id: opts.escrowLockId,\n\t\t\tamount: opts.escrowLockAmount,\n\t\t\tasset_id: opts.escrowLockAssetId,\n\t\t\texpiry: expiryNum,\n\t\t},\n\t\t// Inline path has no file → no delegation_id recoverable.\n\t\t// Caller MUST supply --delegation-id; runOffer enforces that.\n\t\tdelegationIdFromLock: undefined,\n\t};\n}\n\nasync function runOffer(recipientDid: string, contractId: string, opts: OfferOptions): Promise<void> {\n\trequireDid('delegation offer', recipientDid, '<recipient-did>');\n\t// Normalise contract-id positional to lowercase.\n\tcontractId = requireUuidNormalised('delegation offer', contractId, '<contract-id>');\n\tconst ttlSeconds = parseTtl('delegation offer', opts.ttl);\n\tif (!opts.title || opts.title.length === 0) {\n\t\tthrow new Error('delegation offer: --title is required (server-side validator rejects empty offers)');\n\t}\n\tconst terms = parseOfferTerms('delegation offer', opts);\n\n\t// Assemble escrow_lock BEFORE resolving the delegation id so we\n\t// can align body.content.delegation_id with the id baked into\n\t// lock_id. Without this, auto-generated delegation_id guarantees\n\t// ESC_LOCK_ID_MISMATCH post-commit.\n\tconst escrowResult = assembleEscrowLockAttachment(opts);\n\n\tconst delegationId = resolveOfferDelegationId(opts.delegationId, escrowResult);\n\n\t// Server rejects escrow-backed offers without amount + currency\n\t// in body.content with `VAL_BODY_INVALID` POST-COMMIT. Fail-fast\n\t// pre-send rather than burning a sender_sequence.\n\tif (escrowResult !== undefined && (terms.amount === undefined || terms.currency === undefined)) {\n\t\tthrow new Error(\n\t\t\t'delegation offer: escrow-backed offers require both --amount and --currency (server cross-checks body.content.amount/currency against attachments.escrow_lock.amount/asset_id).',\n\t\t);\n\t}\n\n\tconst api = new ArpApiClient(opts.server);\n\tconst sender = resolveSenderAgent('delegation offer', opts.server, opts.fromDid);\n\n\t// Pre-flight the lock's embedded program-id against the\n\t// operator's expected program-id BEFORE we build the envelope.\n\t// Skip if no escrow or no lock-side program-id (old lock file).\n\t// The check is decoupled from the offer flow when it can't fire\n\t// (graceful degradation) but throws hard on mismatch so the\n\t// operator can't burn a sender_sequence on a doomed lock.\n\tif (escrowResult?.lockProgramId !== undefined) {\n\t\tconst expected = await resolveProgramIdWithSource(api, { programId: opts.programId });\n\t\tconst result = preflightLockProgramId({\n\t\t\tlockProgramId: escrowResult.lockProgramId,\n\t\t\texpectedProgramId: expected.programId,\n\t\t\texpectedSource: expected.source,\n\t\t});\n\t\tif (result.kind === 'mismatch') {\n\t\t\tthrow new Error(\n\t\t\t\t`delegation offer: lock file program_id ${result.lockProgramId} does not match the expected escrow program ${result.expectedProgramId} (resolved from --program-id flag > ARP_ESCROW_PROGRAM_ID env > server protocol-fee). The lock tx would be rejected on chain (ESC_LOCK_TX_PROGRAM_ID_MISMATCH) and the delegation would silently fail ~26s after offer. Regenerate the lock with the correct program id via \\`heyarp wallet create-lock --program-id ${result.expectedProgramId} ...\\`.`,\n\t\t\t);\n\t\t}\n\t\t// Inform the operator when we couldn't apply the strict\n\t\t// check, so they understand why the server-side reject is\n\t\t// still possible. stderr — keeps stdout clean for any --json\n\t\t// callers in the future.\n\t\tif (result.kind === 'skipped_no_expected_program_id') {\n\t\t\tconsole.error(\n\t\t\t\tchalk.yellow(\n\t\t\t\t\t`⚠ delegation offer: no authoritative expected program-id available (--program-id missing, ARP_ESCROW_PROGRAM_ID env unset, server protocol-fee unreachable). Pre-flight skipped; server-side ESC_LOCK_TX_PROGRAM_ID_MISMATCH check is the only backstop. Set ARP_ESCROW_PROGRAM_ID or pass --program-id to enable pre-flight.`,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t}\n\n\tconst content: DelegationContent = {\n\t\taction: 'offer',\n\t\tdelegation_id: delegationId,\n\t\tcontract_id: contractId,\n\t\ttitle: opts.title,\n\t\t...terms,\n\t};\n\tconst body: DelegationBody = { type: 'delegation', content };\n\n\tconst attachments = escrowResult ? { escrow_lock: escrowResult.attachment } : undefined;\n\n\tconsole.log(chalk.dim(`Server: ${api.serverUrl}`));\n\tconsole.log(chalk.dim(`Sender: ${sender.did}`));\n\tconsole.log(chalk.dim(`Recipient: ${recipientDid}`));\n\tconsole.log(chalk.dim(`Contract: ${contractId}`));\n\tconsole.log(chalk.dim(`Delegation: ${delegationId}`));\n\tif (escrowResult) {\n\t\tconst a = escrowResult.attachment as { lock_id: string; amount: string; asset_id: string };\n\t\tconsole.log(chalk.dim(`Escrow lock attached: lock_id=${a.lock_id} amount=${a.amount} asset_id=${a.asset_id}`));\n\t}\n\n\tconst result = await sendDelegationEnvelope({ api, sender, recipientDid, body, attachments, ttlSeconds, verbose: opts.verbose, server: opts.server });\n\tprintIngestResult(result);\n\tconsole.log(chalk.dim(`\\nReference this delegation on subsequent calls with:`));\n\tconsole.log(chalk.dim(` heyarp delegation accept ${result.relationshipId} ${delegationId}`));\n\tconsole.log(chalk.dim(` heyarp delegation decline ${result.relationshipId} ${delegationId}`));\n\tconsole.log(chalk.dim(` heyarp delegation cancel ${result.relationshipId} ${delegationId}`));\n}\n\n// ---------- accept / decline / cancel ----------\n\ninterface ActionOptions extends BaseSendOptions {\n\tcontractId?: string;\n\t/** decline reason — REQUIRED when running `decline`. Ignored on accept / cancel. */\n\treason?: string;\n\t/** optional free-text elaboration accompanying `--reason`. */\n\treasonDetail?: string;\n}\n\nfunction registerAccept(parent: Command): void {\n\tparent\n\t\t.command('accept')\n\t\t.description('Accept a PROPOSED delegation — promotes to ACCEPTED. Counterparty-only.')\n\t\t.argument('<relationship-id>', 'Relationship UUID')\n\t\t.argument('<delegation-id>', 'Delegation UUID')\n\t\t.option('--server <url>', 'Override ARP server base URL')\n\t\t.option('--from-did <did>', 'Sender DID — required only if multiple agents are registered against this server')\n\t\t.option('--contract-id <uuid>', 'Override the auto-resolved contract id (default: read from the delegation row)')\n\t\t.option('--ttl <seconds>', 'Envelope TTL in seconds', '3600')\n\t\t.option('--verbose', 'Print the full envelope before sending and the full server response', false)\n\t\t.action(async (relationshipId: string, delegationId: string, opts: ActionOptions) => {\n\t\t\tawait runFollowupAction(relationshipId, delegationId, 'accept', opts);\n\t\t});\n}\n\nfunction registerDecline(parent: Command): void {\n\tparent\n\t\t.command('decline')\n\t\t.description('Decline a PROPOSED delegation — moves to DECLINED. Counterparty-only.')\n\t\t.argument('<relationship-id>', 'Relationship UUID')\n\t\t.argument('<delegation-id>', 'Delegation UUID')\n\t\t.option('--server <url>', 'Override ARP server base URL')\n\t\t.option('--from-did <did>', 'Sender DID — required only if multiple agents are registered against this server')\n\t\t.option('--contract-id <uuid>', 'Override the auto-resolved contract id (default: read from the delegation row)')\n\t\t.option('--ttl <seconds>', 'Envelope TTL in seconds', '3600')\n\t\t.requiredOption(\n\t\t\t'--reason <code>',\n\t\t\t// surface the closed enum at help time so operators\n\t\t\t// don't have to read source to find acceptable values.\n\t\t\t`Required: decline reason code (one of: ${DECLINE_REASONS.join(', ')}). Carried in body.content.reason so the counterparty's reactor can branch on it.`,\n\t\t)\n\t\t.option('--reason-detail <s>', 'Optional free-text elaboration alongside --reason (e.g. \"rate floor 0.20 USDC\"). Max 512 chars.')\n\t\t.option('--verbose', 'Print the full envelope before sending and the full server response', false)\n\t\t.action(async (relationshipId: string, delegationId: string, opts: ActionOptions) => {\n\t\t\tawait runFollowupAction(relationshipId, delegationId, 'decline', opts);\n\t\t});\n}\n\nfunction registerCancel(parent: Command): void {\n\tparent\n\t\t.command('cancel')\n\t\t.description('Cancel a PROPOSED delegation — moves to CANCELED. Offerer-only (the OTHER side uses decline).')\n\t\t.argument('<relationship-id>', 'Relationship UUID')\n\t\t.argument('<delegation-id>', 'Delegation UUID')\n\t\t.option('--server <url>', 'Override ARP server base URL')\n\t\t.option('--from-did <did>', 'Sender DID — required only if multiple agents are registered against this server')\n\t\t.option('--contract-id <uuid>', 'Override the auto-resolved contract id (default: read from the delegation row)')\n\t\t.option('--ttl <seconds>', 'Envelope TTL in seconds', '3600')\n\t\t.option('--verbose', 'Print the full envelope before sending and the full server response', false)\n\t\t.action(async (relationshipId: string, delegationId: string, opts: ActionOptions) => {\n\t\t\tawait runFollowupAction(relationshipId, delegationId, 'cancel', opts);\n\t\t});\n}\n\nasync function runFollowupAction(relationshipId: string, delegationId: string, action: 'accept' | 'decline' | 'cancel', opts: ActionOptions): Promise<void> {\n\tconst cmdName = `delegation ${action}`;\n\t// normalise positional UUID args to lowercase canonical\n\t// form so the output banner, the signed envelope's\n\t// `delegation_id`, and downstream `status` lookups all see the\n\t// same case-folded id. RFC 4122 §3 — canonical UUID is lowercase.\n\trelationshipId = requireUuidNormalised(cmdName, relationshipId, '<relationship-id>');\n\tdelegationId = requireUuidNormalised(cmdName, delegationId, '<delegation-id>');\n\tconst ttlSeconds = parseTtl(cmdName, opts.ttl);\n\n\t// Validate `--reason` (+ `--reason-detail`) BEFORE any state\n\t// lookup / API round-trip. A bogus value like `--reason garbage`\n\t// should fail with a clean parse error rather than spending\n\t// seconds resolving the delegation timeline first and then\n\t// erroring midway through. We compute the validated payload up\n\t// front and stash it for later use.\n\tlet declinePayload: { reason: DelegationContent['reason']; reasonDetail?: string } | null = null;\n\tif (action === 'decline') {\n\t\tconst reason = parseDeclineReason(cmdName, opts.reason);\n\t\tconst validatedDetail = parseReasonDetail(cmdName, opts.reasonDetail);\n\t\tdeclinePayload = validatedDetail ? { reason, reasonDetail: validatedDetail } : { reason };\n\t}\n\n\tconst api = new ArpApiClient(opts.server);\n\tconst sender = resolveSenderAgent(cmdName, opts.server, opts.fromDid);\n\tconst signer = makeSigner(sender);\n\n\t// Auto-resolve `contract_id` and `recipient_did` from the\n\t// delegation row unless the user overrode contract-id. The\n\t// resolver pages the delegation timeline so it's correct on\n\t// relationships with > 100 rows.\n\tconst resolved = await resolveDelegationRefs(cmdName, api, signer, { relationshipId, delegationId, action, selfDid: sender.did, contractIdOverride: opts.contractId });\n\n\tconst content: DelegationContent = {\n\t\taction,\n\t\tdelegation_id: delegationId,\n\t\tcontract_id: resolved.contractId,\n\t};\n\tif (declinePayload) {\n\t\tcontent.reason = declinePayload.reason;\n\t\tif (declinePayload.reasonDetail) content.reason_detail = declinePayload.reasonDetail;\n\t}\n\tconst body: DelegationBody = { type: 'delegation', content };\n\n\tconsole.log(chalk.dim(`Server: ${api.serverUrl}`));\n\tconsole.log(chalk.dim(`Sender: ${sender.did}`));\n\tconsole.log(chalk.dim(`Relationship: ${relationshipId}`));\n\tconsole.log(chalk.dim(`Delegation: ${delegationId} (action=${action}${action === 'decline' ? `, reason=${content.reason}` : ''})`));\n\n\tconst result = await sendDelegationEnvelope({\n\t\tapi,\n\t\tsender,\n\t\trecipientDid: resolved.recipientDid,\n\t\tbody,\n\t\tttlSeconds,\n\t\tverbose: opts.verbose,\n\t\tserver: opts.server,\n\t});\n\tprintIngestResult(result);\n}\n\n// ---------- shared helpers ----------\n\ninterface BaseSendOptions {\n\tserver?: string;\n\tfromDid?: string;\n\tttl?: string;\n\tverbose?: boolean;\n}\n\ninterface OfferTermsOptions {\n\ttitle?: string;\n\tbrief?: string;\n\tcriterion?: string[];\n\tdeadline?: string;\n\tamount?: string;\n\tcurrency?: string;\n\tcurrencyDecimals?: string;\n\tcurrencySymbol?: string;\n}\n\ninterface SendArgs {\n\tapi: ArpApiClient;\n\tsender: AgentLocalState;\n\trecipientDid: string;\n\tbody: DelegationBody;\n\t/** Optional `attachments` payload — currently only `escrow_lock` on `offer`. */\n\tattachments?: Record<string, unknown>;\n\tttlSeconds: number;\n\tverbose: boolean | undefined;\n\tserver: string | undefined;\n}\n\n/**\n * Build → sign → ingest a delegation envelope. Same sequence-bump\n * policy as the contract wrapper:\n *\n * 1. Success (HTTP 202): advance unconditionally.\n * 2. ApiError with a code in `POST_COMMIT_ERROR_CODES`: advance\n * anyway, the server consumed the sequence even though the\n * action was rejected.\n * 3. Anything else — network error, or a pre-commit reject from\n * the validator (any code prefixed `ENV_`, `VAL_`, `AUTH_`,\n * `DOM_`): leave `lastSenderSequence` untouched so the same\n * sequence can be retried.\n */\nasync function sendDelegationEnvelope(args: SendArgs): Promise<IngestResult> {\n\tconst nextSequence = (args.sender.lastSenderSequence ?? 0) + 1;\n\tconst protectedBlock: SignableProtected = {\n\t\tprotocol_version: 'arp/0.1',\n\t\tpurpose: Purpose.ENVELOPE,\n\t\tmessage_id: uuidV4(),\n\t\tsender_did: args.sender.did as Did,\n\t\trecipient_did: args.recipientDid as Did,\n\t\t// `relationship_id: null` matches the contract / handshake\n\t\t// wrappers — server resolves the pair from\n\t\t// `(sender_did, recipient_did)` and routes onto the\n\t\t// existing relationship row.\n\t\trelationship_id: null,\n\t\tsender_sequence: nextSequence,\n\t\tsender_nonce: senderNonce(),\n\t\ttimestamp: rfc3339(),\n\t\texpires_at: expiresAt(args.ttlSeconds),\n\t\tdelivery_id: null,\n\t};\n\n\tconst signer = makeSigner(args.sender);\n\tconst envelope = signEnvelope<DelegationBody>({\n\t\tprotected: protectedBlock,\n\t\tbody: args.body,\n\t\tidentitySecretKey: signer.identitySecretKey,\n\t\tattachments: args.attachments,\n\t});\n\n\tif (args.verbose) {\n\t\tconsole.log(chalk.bold('\\nEnvelope (pre-send):'));\n\t\tconsole.log(formatJson(envelope));\n\t}\n\n\ttry {\n\t\tconst result = await args.api.ingest(envelope);\n\t\tupdateAgentLocal(args.server, args.sender.did, { lastSenderSequence: nextSequence });\n\t\treturn result;\n\t} catch (err) {\n\t\tif (err instanceof ApiError && isPostCommitErrorCode(err.payload.code)) {\n\t\t\tupdateAgentLocal(args.server, args.sender.did, { lastSenderSequence: nextSequence });\n\t\t}\n\t\tthrow err;\n\t}\n}\n\n/**\n * For accept / decline / cancel. The user supplied\n * `<relationship-id>` and `<delegation-id>`; we need\n * `recipient_did` (for the protected block) and `contract_id` (for\n * the body). Read the delegation row via the live `/delegations`\n * endpoint, paginating defensively to handle relationships with\n * many rows.\n *\n * The recipient is whichever side of the delegation pair is NOT\n * the sender:\n * - On `accept` / `decline`: sender is the COUNTERPARTY, so\n * recipient is `delegation.offererDid`.\n * - On `cancel`: sender IS the offerer, so recipient is \"the\n * other side\". We pull event 0 of the relationship (the\n * original handshake — every relationship has one as its\n * first chain entry) and read whichever of `senderDid` /\n * `recipientDid` isn't the caller. This avoids paginating\n * `listRelationships`, which has no `after` cursor and would\n * truncate at 100 for prolific agents.\n *\n * Exported for unit tests.\n */\nexport async function resolveDelegationRefs(\n\tcmdName: string,\n\tapi: Pick<ArpApiClient, 'listDelegations' | 'listEvents'>,\n\tsigner: Signer,\n\targs: { relationshipId: string; delegationId: string; action: 'accept' | 'decline' | 'cancel'; selfDid: string; contractIdOverride?: string },\n): Promise<{ contractId: string; recipientDid: string }> {\n\t// Page the delegation list filtered to this delegationId — the\n\t// server doesn't expose a per-id GET endpoint, but the timeline\n\t// list with a chronological cursor is enough.\n\tlet after: string | undefined;\n\tlet row: DelegationPublic | null = null;\n\twhile (true) {\n\t\tconst page: DelegationPublic[] = await api.listDelegations(args.relationshipId, signer, { limit: 100, after });\n\t\trow = page.find((d) => d.delegationId === args.delegationId) ?? null;\n\t\tif (row) break;\n\t\tif (page.length < 100) break;\n\t\tafter = page[page.length - 1].id;\n\t}\n\tif (!row) {\n\t\tthrow new Error(\n\t\t\t`${cmdName}: delegation ${args.delegationId} not found in relationship ${args.relationshipId}. Run 'heyarp delegations <relationship-id>' to inspect the timeline.`,\n\t\t);\n\t}\n\n\tconst contractId = args.contractIdOverride ?? row.contractId;\n\n\tlet recipientDid: string;\n\tif (args.action === 'cancel') {\n\t\t// Sender IS the offerer. Recipient is the OTHER side of\n\t\t// the relationship pair. Fetch event 0 — the handshake —\n\t\t// to read both pair DIDs without depending on\n\t\t// `listRelationships` pagination (which has no cursor).\n\t\tconst firstEvents = await api.listEvents(args.relationshipId, signer, { since: 0, limit: 1 });\n\t\tconst handshake = firstEvents[0];\n\t\tif (!handshake) {\n\t\t\tthrow new Error(\n\t\t\t\t`${cmdName}: relationship ${args.relationshipId} has no event 0 — cannot resolve cancel recipient. This shouldn't happen if the delegation row exists.`,\n\t\t\t);\n\t\t}\n\t\tif (handshake.senderDid === args.selfDid) {\n\t\t\trecipientDid = handshake.recipientDid;\n\t\t} else if (handshake.recipientDid === args.selfDid) {\n\t\t\trecipientDid = handshake.senderDid;\n\t\t} else {\n\t\t\t// Defensive: the caller isn't even on the pair. The\n\t\t\t// SignedRequestGuard / member-of-pair check earlier\n\t\t\t// should have rejected this read, but if it slipped\n\t\t\t// through, fail loud rather than misroute.\n\t\t\tthrow new Error(\n\t\t\t\t`${cmdName}: caller ${args.selfDid} is not a member of relationship ${args.relationshipId}'s pair (${handshake.senderDid} <-> ${handshake.recipientDid}).`,\n\t\t\t);\n\t\t}\n\t} else {\n\t\t// accept / decline — sender is the counterparty, recipient\n\t\t// is the original offerer.\n\t\trecipientDid = row.offererDid;\n\t}\n\n\treturn { contractId, recipientDid };\n}\n\nfunction printIngestResult(result: IngestResult): void {\n\tconsole.log(chalk.green('\\nDelivered.'));\n\tconsole.log(`${chalk.bold('Event id')}: ${chalk.cyan(result.eventId)}`);\n\tconsole.log(`${chalk.bold('Relationship id')}: ${chalk.cyan(result.relationshipId)}`);\n\tconsole.log(`${chalk.bold('Chain index')}: ${chalk.cyan(String(result.relationshipEventIndex))}`);\n\tconsole.log(`${chalk.bold('Server timestamp')}: ${chalk.cyan(result.serverTimestamp)}`);\n\tconsole.log(`${chalk.bold('Server event hash')}: ${chalk.cyan(result.serverEventHash)}`);\n}\n\n/**\n * Map CLI flags onto `DelegationContent` term fields.\n *\n * Exported for unit tests.\n */\nexport function parseOfferTerms(cmdName: string, opts: OfferTermsOptions): Partial<DelegationContent> {\n\tconst out: Partial<DelegationContent> = {};\n\tif (opts.brief) {\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(opts.brief);\n\t\t\tif (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n\t\t\t\tthrow new Error('not a JSON object');\n\t\t\t}\n\t\t\tout.brief = parsed;\n\t\t} catch (err) {\n\t\t\tconst detail = err instanceof Error ? err.message : String(err);\n\t\t\tthrow new Error(`${cmdName}: --brief must be a JSON object literal (got '${opts.brief}': ${detail})`);\n\t\t}\n\t}\n\tif (opts.criterion && opts.criterion.length > 0) {\n\t\tout.acceptance_criteria = opts.criterion;\n\t}\n\tif (opts.deadline) out.deadline = opts.deadline;\n\tif (opts.amount) {\n\t\tout.amount = opts.amount;\n\t\tif (!opts.currency) {\n\t\t\tthrow new Error(`${cmdName}: --amount requires --currency. Shorthand: ${WELL_KNOWN_ASSET_KEYS.join(', ')}, or raw CAIP-19 + --currency-decimals.`);\n\t\t}\n\t\tout.currency = buildAssetIdentifier(cmdName, DELEGATION_CURRENCY_FLAGS, opts.currency, opts.currencyDecimals, opts.currencySymbol);\n\t} else if (opts.currency) {\n\t\tthrow new Error(`${cmdName}: --currency without --amount is meaningless; omit both or supply both.`);\n\t}\n\treturn out;\n}\n\nexport function parseTtl(cmdName: string, raw: string | undefined): number {\n\tif (raw === undefined) return 3600;\n\tconst n = Number(raw);\n\tif (!Number.isFinite(n) || !Number.isInteger(n) || n <= 0) {\n\t\tthrow new Error(`${cmdName}: --ttl must be a positive integer number of seconds (got '${raw}')`);\n\t}\n\treturn n;\n}\n\nexport function parseDelegationId(cmdName: string, raw: string | undefined): string {\n\tif (raw === undefined || raw === '') return uuidV4();\n\t// Delegate to the shared hint-rich validator so a copy-pasted\n\t// ObjectId / del_-prefixed / sha256 id surfaces the likely-source\n\t// hint instead of a bare \"must be a UUID\".\n\tsharedRequireUuid(cmdName, raw, '--delegation-id');\n\t// Canonical UUID rendering is lowercase (RFC 4122 §3). Normalise\n\t// so a copy-pasted uppercase id doesn't propagate through\n\t// subsequent commands' banners.\n\treturn raw.toLowerCase();\n}\n\n/**\n * Pick the delegation_id used in `body.content.delegation_id` after\n * considering the escrow lock.\n *\n * The on-chain create_lock instruction derives `lock_id` from a\n * specific delegation_id at lock-creation time; the server later\n * re-derives `lock_id` from `body.content.delegation_id` and rejects\n * with `ESC_LOCK_ID_MISMATCH` (post-commit) on any divergence.\n *\n * Cases:\n * 1. No escrow attachment → keep legacy behaviour (auto-generate or\n * use --delegation-id verbatim).\n * 2. Escrow attached, file path includes `delegation_id`:\n * - operator passed --delegation-id AND it matches → fine\n * - operator passed --delegation-id AND it differs → throw with a\n * clear \"lock was created against id X, you passed id Y\" message\n * - operator omitted --delegation-id → use the file's id\n * 3. Escrow attached, no file-side delegation_id (inline flags OR\n * legacy lock file): require --delegation-id explicitly. Auto-\n * generating here would produce a guaranteed lock_id mismatch.\n *\n * Exported for unit tests.\n */\nexport function resolveOfferDelegationId(rawCliId: string | undefined, escrow: EscrowAttachmentResult | undefined): string {\n\t// Validate the CLI-supplied id first so error messages are consistent\n\t// across the three cases below.\n\tlet cliId: string | undefined;\n\tif (rawCliId !== undefined && rawCliId !== '') {\n\t\tsharedRequireUuid('delegation offer', rawCliId, '--delegation-id');\n\t\tcliId = rawCliId.toLowerCase();\n\t}\n\n\t// Case 1: no escrow attached.\n\tif (escrow === undefined) {\n\t\treturn cliId ?? uuidV4();\n\t}\n\n\t// Case 2: file-side delegation_id present.\n\tif (escrow.delegationIdFromLock !== undefined) {\n\t\tconst fileId = escrow.delegationIdFromLock;\n\t\tif (cliId !== undefined && cliId !== fileId) {\n\t\t\tthrow new Error(\n\t\t\t\t`delegation offer: --delegation-id (${cliId}) disagrees with the lock file's delegation_id (${fileId}). ` +\n\t\t\t\t\t`The on-chain lock_id is derived from the lock-side id; using the CLI value would guarantee ESC_LOCK_ID_MISMATCH. ` +\n\t\t\t\t\t`Either drop --delegation-id (the lock file's id is used) or regenerate the lock with --delegation-id ${cliId}.`,\n\t\t\t);\n\t\t}\n\t\treturn fileId;\n\t}\n\n\t// Case 3: inline flags OR legacy lock file. No file-side id; CLI must\n\t// supply it explicitly because the auto-generated UUID would never\n\t// match the lock's id and offers would loop on ESC_LOCK_ID_MISMATCH.\n\tif (cliId === undefined) {\n\t\tthrow new Error(\n\t\t\t'delegation offer: escrow-backed offers require --delegation-id matching the id passed to `heyarp wallet create-lock` ' +\n\t\t\t\t'(lock_id is derived from that delegation_id; omitting it auto-generates a fresh UUID and guarantees ESC_LOCK_ID_MISMATCH). ' +\n\t\t\t\t'Recommended: re-run `heyarp wallet create-lock` so the JSON output includes `delegation_id` and use --escrow-lock-from-file.',\n\t\t);\n\t}\n\treturn cliId;\n}\n\n/**\n * Thin re-export wrapper over the shared `requireUuid` in\n * `../id-format`. Kept exported here for the existing `contract.ts`\n * import path; the wrapper carries no additional logic — the\n * hint-rich error comes from the shared implementation.\n */\nexport function requireUuid(cmdName: string, raw: string, label: string): void {\n\tsharedRequireUuid(cmdName, raw, label);\n}\n\n/**\n * Validate AND normalise a positional UUID arg to lowercase\n * canonical form. Use when the calling command intends to round-trip\n * the UUID into a server URL, an envelope body, or a banner —\n * anywhere the case will be observed.\n *\n * Distinct from `requireUuid` (validate only, no mutation) so\n * existing call sites that don't need normalisation aren't forced\n * to change.\n *\n * Exported for cross-command use + test coverage.\n */\nexport function requireUuidNormalised(cmdName: string, raw: string, label: string): string {\n\trequireUuid(cmdName, raw, label);\n\treturn raw.toLowerCase();\n}\n\nexport function requireDid(cmdName: string, did: string, label: string): void {\n\tif (typeof did !== 'string' || !did.startsWith('did:arp:') || did.length <= 'did:arp:'.length) {\n\t\tthrow new Error(`${cmdName}: ${label} must look like 'did:arp:...' (got '${did}')`);\n\t}\n}\n\n/**\n * Commander option-parser for repeatable string flags.\n */\nexport function collectRepeated(value: string, previous: string[]): string[] {\n\treturn [...previous, value];\n}\n\n/**\n * Shared `--reason <code>` parser used by `delegation decline` and\n * `contract decline` (and `send-handshake-response --decision\n * decline`). Validates against the closed `DeclineReason` allowlist\n * exported by the SDK so the CLI's accepted values and the server\n * validator's check stay in lockstep without manual mirroring.\n *\n * Exported so the other decline sites can import the same parser\n * (avoids drift between sites — fixed once and validated once).\n */\nexport function parseDeclineReason(cmdName: string, raw: string | undefined): DeclineReason {\n\tif (raw === undefined || raw === '') {\n\t\tthrow new Error(`${cmdName}: --reason is required when declining (one of: ${DECLINE_REASONS.join(', ')})`);\n\t}\n\tif (!isDeclineReason(raw)) {\n\t\tthrow new Error(`${cmdName}: --reason must be one of ${DECLINE_REASONS.join(', ')} (got '${raw}')`);\n\t}\n\treturn raw;\n}\n\n/**\n * Validate `--reason-detail`. Treats undefined / null as \"omit the\n * field\". Empty string is rejected so the CLI does not sign a\n * divergent envelope (server validator also rejects empty\n * `reason_detail`).\n *\n * Returns the validated string when present, or `undefined` when\n * the caller omitted the flag.\n */\nexport function parseReasonDetail(cmdName: string, raw: string | undefined): string | undefined {\n\tif (raw === undefined) return undefined;\n\tif (typeof raw !== 'string' || raw.length === 0) {\n\t\tthrow new Error(`${cmdName}: --reason-detail, if provided, must be a non-empty string (omit the flag to leave it unset)`);\n\t}\n\tif (raw.length > 512) {\n\t\tthrow new Error(`${cmdName}: --reason-detail too long (max 512 chars, got ${raw.length})`);\n\t}\n\treturn raw;\n}\n\n// UUID_RE lives in ../id-format and is re-imported at the top of\n// this file, so there's a single source of truth across CLI\n// command parsers.\n","import chalk from 'chalk';\nimport type { Command } from 'commander';\nimport { type AgentPublic, ArpApiClient, type Signer, type UpdateAgentBody } from '../api';\nimport { formatJson } from '../format';\nimport { type AgentLocalState, loadAgentOrThrow, updateAgentLocal } from '../state';\n\n/**\n * Owner-only lifecycle commands: `publish`, `pause`, `unpause`,\n * `update`. Each reads the local secret key for the target DID,\n * builds a `Signer`, and dispatches a signed request — the server's\n * `SignedRequestGuard` matches the signature against the agent's\n * current identity key, and `assertOwner` enforces signer == agent.\n *\n * Rotation (which adds an attestation step) lives in `rotate.ts` so\n * this file stays a thin wrapper layer.\n */\nexport function registerLifecycleCommands(root: Command): void {\n\troot.command('publish')\n\t\t.description('Publish a draft agent (draft → active). Requires defaultEndpointUrl set.')\n\t\t.argument('<did>', 'Agent DID (did:arp:...) — must have local state')\n\t\t.option('--server <url>', 'Override ARP server base URL')\n\t\t.action(async (did: string, opts: { server?: string }) => {\n\t\t\tconst agent = await actSigned(did, opts.server, (api, signer) => api.publishAgent(did, signer));\n\t\t\tprintAgent('Published', agent);\n\t\t});\n\n\troot.command('pause')\n\t\t.description('Pause an active agent (active → paused).')\n\t\t.argument('<did>')\n\t\t.option('--server <url>', 'Override ARP server base URL')\n\t\t.action(async (did: string, opts: { server?: string }) => {\n\t\t\tconst agent = await actSigned(did, opts.server, (api, signer) => api.pauseAgent(did, signer));\n\t\t\tprintAgent('Paused', agent);\n\t\t});\n\n\troot.command('unpause')\n\t\t.description('Unpause a paused agent (paused → active).')\n\t\t.argument('<did>')\n\t\t.option('--server <url>', 'Override ARP server base URL')\n\t\t.action(async (did: string, opts: { server?: string }) => {\n\t\t\tconst agent = await actSigned(did, opts.server, (api, signer) => api.unpauseAgent(did, signer));\n\t\t\tprintAgent('Unpaused', agent);\n\t\t});\n\n\troot.command('update')\n\t\t.description('Update an agent profile (name / description / endpoint URL / tags). At least one flag is required.')\n\t\t.argument('<did>')\n\t\t.option('--server <url>', 'Override ARP server base URL')\n\t\t.option('--name <s>', 'New display name')\n\t\t.option('--description <s>', 'New description')\n\t\t.option('--endpoint-url <s>', 'New default endpoint URL (HTTPS where peers POST envelopes)')\n\t\t.option('--tag <s>', 'Capability tag — REPLACES the existing list. Repeatable: --tag translation --tag fr', accumulate, [])\n\t\t.option('--clear-tags', 'Drop all tags (cannot be combined with --tag)', false)\n\t\t.action(\n\t\t\tasync (\n\t\t\t\tdid: string,\n\t\t\t\topts: {\n\t\t\t\t\tserver?: string;\n\t\t\t\t\tname?: string;\n\t\t\t\t\tdescription?: string;\n\t\t\t\t\tendpointUrl?: string;\n\t\t\t\t\ttag?: string[];\n\t\t\t\t\tclearTags?: boolean;\n\t\t\t\t},\n\t\t\t) => {\n\t\t\t\tconst body = buildUpdateBody(opts);\n\t\t\t\tif (Object.keys(body).length === 0) {\n\t\t\t\t\tthrow new Error('update: pass at least one of --name / --description / --endpoint-url / --tag / --clear-tags');\n\t\t\t\t}\n\t\t\t\tconst agent = await actSigned(did, opts.server, (api, signer) => api.updateAgent(did, body, signer));\n\t\t\t\t// Sync the locally cached profile so `heyarp list` reflects\n\t\t\t\t// the change immediately. Server response is the source\n\t\t\t\t// of truth (covers any field the server normalises /\n\t\t\t\t// rejects silently).\n\t\t\t\tupdateAgentLocal(opts.server, did, {\n\t\t\t\t\tname: agent.name,\n\t\t\t\t\tdescription: agent.description,\n\t\t\t\t\tdefaultEndpointUrl: agent.defaultEndpointUrl,\n\t\t\t\t\ttags: agent.tags,\n\t\t\t\t});\n\t\t\t\tprintAgent('Updated', agent);\n\t\t\t},\n\t\t);\n}\n\n/** Commander accumulator for repeatable flags (--tag a --tag b → ['a','b']). */\nfunction accumulate(value: string, previous: string[]): string[] {\n\treturn [...previous, value];\n}\n\n// exported for tests\nexport function buildUpdateBody(opts: { name?: string; description?: string; endpointUrl?: string; tag?: string[]; clearTags?: boolean }): UpdateAgentBody {\n\tif (opts.clearTags && opts.tag && opts.tag.length > 0) {\n\t\tthrow new Error('update: --clear-tags cannot be combined with --tag');\n\t}\n\tconst body: UpdateAgentBody = {};\n\tif (opts.name !== undefined) body.name = opts.name;\n\tif (opts.description !== undefined) body.description = opts.description;\n\tif (opts.endpointUrl !== undefined) body.defaultEndpointUrl = opts.endpointUrl;\n\t// `--tag` REPLACES wholesale (matches server semantics). `--clear-tags`\n\t// is `tags: []`. Omit both → tags field absent → server leaves\n\t// existing tags as-is.\n\tif (opts.clearTags) {\n\t\tbody.tags = [];\n\t} else if (opts.tag !== undefined && opts.tag.length > 0) {\n\t\tbody.tags = opts.tag.map((t) => t.trim().toLowerCase());\n\t}\n\treturn body;\n}\n\n/**\n * Shared \"load signer + call API + return AgentPublic\" plumbing. The\n * generic `act` callback is what each command varies — the rest is\n * identical across publish / pause / unpause / update.\n */\nasync function actSigned(did: string, serverOverride: string | undefined, act: (api: ArpApiClient, signer: Signer) => Promise<AgentPublic>): Promise<AgentPublic> {\n\tconst local = loadAgentOrThrow(serverOverride, did);\n\tconst api = new ArpApiClient(serverOverride);\n\tconsole.log(chalk.dim(`Server: ${api.serverUrl}`));\n\tconsole.log(chalk.dim(`Signer: ${local.did}`));\n\tconst signer = makeSigner(local);\n\treturn act(api, signer);\n}\n\nexport function makeSigner(s: AgentLocalState): Signer {\n\treturn {\n\t\tdid: s.did,\n\t\tidentitySecretKey: new Uint8Array(Buffer.from(s.identitySecretKeyB64, 'base64')),\n\t};\n}\n\nfunction printAgent(verb: string, agent: AgentPublic): void {\n\tconsole.log(chalk.green(`\\n${verb}.`));\n\tconsole.log(`${chalk.bold('DID')}: ${chalk.cyan(agent.did)}`);\n\tconsole.log(`${chalk.bold('Status')}: ${chalk.cyan(agent.publicationStatus)}`);\n\tconsole.log(chalk.bold('\\nAgent profile:'));\n\tconsole.log(formatJson(agent));\n}\n","/**\n * `heyarp wallet …` — Solana-side wallet helpers needed to drive the\n * escrow lifecycle end-to-end from the CLI without a separate wallet\n * adapter (Phantom / Solflare / etc).\n *\n * The agent's settlement key (stored in `agentState.settlementSecretKeyB64`)\n * doubles as the Solana keypair — Ed25519, 32-byte secret, base58\n * pubkey. The same keypair pays for `create_lock` tx fees AND signs\n * the release / refund settlement digests.\n *\n * Two subcommands ship in V1.5 W1:\n * - `create-lock` builds a signed Solana `create_lock` transaction\n * for native SOL locks and prints it as a JSON blob ready to\n * attach as `attachments.escrow_lock` on a `delegation.offer`\n * envelope.\n * - `sign-settlement-release` signs the release/partial-release\n * digest with the agent's settlement key and prints the\n * `{settlement_pubkey, sig}` JSON ready to drop into\n * `attachments.settlement_signatures.payer` (or `.payee`).\n *\n * The two commands are deliberately low-level — they output JSON\n * that the operator composes into the existing\n * `heyarp delegation offer` / `heyarp receipt cosign` flows. Higher-\n * level integration (auto-attach on offer/cosign) is a follow-up.\n *\n * SCOPE: native SOL only in this slice. SPL Token + Token-2022 paths\n * land in a follow-up — they need ATA derivation, mint preflight\n * via RPC, and a separate keypair for the ATA account when the agent\n * doesn't already have one.\n */\nimport {\n\tCREATE_LOCK_DISCRIMINATOR,\n\ttype ReleaseDigestInput,\n\tSOLANA_CLUSTER_IDS,\n\tbuildPartialReleaseDigest,\n\tbuildReleaseDigest,\n\tderiveLockId,\n\tsign as ed25519Sign,\n} from '@heyanon-arp/sdk';\nimport { hexToBytes } from '@noble/hashes/utils';\nimport { Keypair, PublicKey, Connection as SolanaConnection, SystemProgram, Transaction, TransactionInstruction } from '@solana/web3.js';\nimport { Command } from 'commander';\nimport { chmodSync, writeFileSync } from 'node:fs';\nimport { ArpApiClient, type ContractPublic, type DelegationPublic, type RelationshipPublic } from '../api';\nimport { getGlobalConfigValue } from '../config';\nimport { requireUuid as sharedRequireUuid } from '../id-format';\nimport { type AgentLocalState, resolveSenderAgent } from '../state';\nimport { makeSigner } from './lifecycle';\nimport { fetchAllPages } from './status';\n\n/** Encode bytes → base64 using the Node-built-in. Avoids pulling\n * `@scure/base` directly into the CLI dep tree.\n */\nfunction bytesToBase64(bytes: Uint8Array): string {\n\treturn Buffer.from(bytes).toString('base64');\n}\n\nfunction base64ToBytes(s: string): Uint8Array {\n\treturn new Uint8Array(Buffer.from(s, 'base64'));\n}\n\nconst BARE_UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;\n\n/**\n * Normalise --delegation-id input to the canonical `del_<uuid>` wire\n * form the SDK expects.\n *\n * `heyarp delegation offer` prints bare UUIDs in its banner, so it's\n * easy to copy-paste them into `wallet create-lock`. The SDK's strict\n * shape check is correct for the wire protocol (lex-stable\n * `del_<lowercase-canonical-uuid>`), but at the CLI boundary we can\n * accept the friendlier bare form and prefix it ourselves so\n * cross-command copy-paste flows work.\n *\n * Accepts:\n * - canonical `del_<lowercase-canonical-uuid>` (passes through verbatim)\n * - bare `<lowercase-canonical-uuid>` (auto-prefixed with `del_`)\n *\n * Throws (matching SDK message style) when neither shape is recognised.\n *\n * Exported for unit tests.\n */\nexport function normaliseDelegationId(raw: string): string {\n\tif (raw.startsWith('del_')) {\n\t\t// SDK's delegationIdToBytes16 will assert lowercase canonical;\n\t\t// pass through and let it produce the authoritative error.\n\t\treturn raw;\n\t}\n\tif (BARE_UUID_RE.test(raw)) {\n\t\treturn `del_${raw}`;\n\t}\n\tthrow new Error(`wallet: --delegation-id must be either 'del_<uuid>' or a bare canonical-lowercase UUID (got '${raw}')`);\n}\n\n/** Solana `Pubkey::default()` — all-zero. Used as the \"native SOL\" mint sentinel. */\nconst NATIVE_SOL_MINT = SystemProgram.programId;\n/** Legacy SPL Token program — required in the `token_program` slot of\n * `create_lock` even for native-SOL flows (Anchor's\n * `Interface<TokenInterface>` rejects System Program here). */\nconst SPL_TOKEN_PROGRAM_ID = new PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA');\n\nconst FALLBACK_RPC_URL = 'https://api.mainnet-beta.solana.com';\n/**\n * Resolve the Solana RPC URL with the standard precedence chain\n * documented in `wallet create-lock --help`:\n *\n * 1. `--rpc-url <url>` flag (highest precedence).\n * 2. `ARP_ESCROW_RPC_URL` env variable.\n * 3. `heyarp config set rpcUrl <url>` persisted in ~/.arp/config.json.\n * 4. Hardcoded `FALLBACK_RPC_URL` (mainnet-beta public endpoint).\n *\n * The public mainnet endpoint is heavily rate-limited and unsuitable\n * for high-throughput `sendRawTransaction`; CLI commands here only\n * use it for single-shot reads (blockhash, getAccountInfo,\n * getSignaturesForAddress) which the public endpoint handles fine\n * for typical operator usage. For sustained traffic or devnet\n * testing, configure a private RPC via `heyarp config set rpcUrl <url>`\n * or pass `--rpc-url` explicitly.\n *\n * Exported for unit-test coverage.\n */\nexport function resolveRpcUrl(opts: { rpcUrl?: string }): string {\n\tif (opts.rpcUrl !== undefined && opts.rpcUrl !== '') return opts.rpcUrl;\n\tif (process.env.ARP_ESCROW_RPC_URL !== undefined && process.env.ARP_ESCROW_RPC_URL !== '') {\n\t\treturn process.env.ARP_ESCROW_RPC_URL;\n\t}\n\tconst fromConfig = getGlobalConfigValue('rpcUrl');\n\tif (fromConfig !== undefined && fromConfig.length > 0) return fromConfig;\n\treturn FALLBACK_RPC_URL;\n}\n\n/**\n * Hardcoded fallback program ID. `wallet create-lock` /\n * `sign-settlement-release` query `GET /v1/escrow/protocol-fee` for\n * the live programId and use that when neither `--program-id` nor\n * `ARP_ESCROW_PROGRAM_ID` is set; this placeholder is reached only\n * when the server is unreachable AND no env override is configured.\n *\n * The value is ALWAYS the hardcoded canonical placeholder (no\n * `process.env` fallback at module init). Empty-string env overrides\n * would otherwise leak into `FALLBACK_PROGRAM_ID = ''` and crash\n * `new PublicKey('')` downstream; `resolveProgramId` handles env-var\n * precedence at call-time so the empty-string case is caught by its\n * `.length > 0` check.\n */\nexport const FALLBACK_PROGRAM_ID = '7trAdKybX4kMKARia9nrRPj9rBuUjDTxRzExzwFTvvXg';\n\n/**\n * Source tag for `resolveProgramIdWithSource`. Distinguishes which\n * tier of the precedence chain actually produced the value, so callers\n * can apply tier-aware policy (e.g. preflight skips ONLY when the\n * fallback tier won — never when the server itself returned a value\n * that happens to equal the hardcoded placeholder).\n *\n * This matters because `FALLBACK_PROGRAM_ID` is the deployed contract's\n * canonical placeholder address: in the local dev / devnet path the\n * hardcoded value AND the server's `/v1/escrow/protocol-fee` answer\n * are byte-identical. Without a source tag a pure value-equality check\n * (`if (id === FALLBACK_PROGRAM_ID) skip`) would incorrectly classify\n * a perfectly-good server-resolved id as \"fell back to placeholder\".\n */\nexport type ResolveProgramIdSource = 'flag' | 'env' | 'server' | 'fallback';\n\nexport interface ResolveProgramIdResult {\n\tprogramId: string;\n\tsource: ResolveProgramIdSource;\n}\n\n/**\n * Resolve the deployed escrow program id via the precedence chain\n * documented in `wallet create-lock --help`:\n *\n * 1. Explicit `--program-id <pubkey>` flag (highest precedence).\n * 2. `ARP_ESCROW_PROGRAM_ID` env variable.\n * 3. `GET /v1/escrow/protocol-fee` (auto-discover from server).\n * 4. Hardcoded `FALLBACK_PROGRAM_ID` (last resort, almost certainly\n * wrong for the operator's environment).\n *\n * The server probe is best-effort: a transient network failure falls\n * through to the fallback rather than blocking the wallet command\n * (operators can always supply `--program-id` explicitly to bypass\n * the lookup). The probe is GET (unsigned) so doesn't require local\n * agent state.\n *\n * Returns the resolved id PLUS its tier-of-origin so the preflight\n * caller can distinguish \"server confirmed this value\" from \"we fell\n * back to the placeholder\" (which happen to be identical strings on\n * the canonical devnet deployment).\n *\n * Exported for unit-test coverage.\n */\nexport async function resolveProgramIdWithSource(\n\tapi: ArpApiClient,\n\topts: { programId?: string },\n): Promise<ResolveProgramIdResult> {\n\tif (opts.programId !== undefined && opts.programId !== '') {\n\t\treturn { programId: opts.programId, source: 'flag' };\n\t}\n\tif (process.env.ARP_ESCROW_PROGRAM_ID !== undefined && process.env.ARP_ESCROW_PROGRAM_ID !== '') {\n\t\treturn { programId: process.env.ARP_ESCROW_PROGRAM_ID, source: 'env' };\n\t}\n\ttry {\n\t\tconst status = await api.getProtocolFee();\n\t\tif (status.programId && status.programId.length > 0) {\n\t\t\treturn { programId: status.programId, source: 'server' };\n\t\t}\n\t} catch {\n\t\t// Server unreachable — fall through. The fallback is almost\n\t\t// always wrong in production but loud failures downstream\n\t\t// (the relayer's `program not found` reject) beat silent\n\t\t// hangs here.\n\t}\n\treturn { programId: FALLBACK_PROGRAM_ID, source: 'fallback' };\n}\n\n/**\n * Back-compat wrapper for callers that only need the resolved id\n * string. New callers should prefer `resolveProgramIdWithSource` so\n * they can apply tier-aware policy (preflight skip tier, error message\n * accuracy).\n */\nexport async function resolveProgramId(api: ArpApiClient, opts: { programId?: string }): Promise<string> {\n\tconst r = await resolveProgramIdWithSource(api, opts);\n\treturn r.programId;\n}\n\n/**\n * strict resolver for chain config\n * — refuses to fall back to the hardcoded placeholder. Used by\n * `wallet verify-release` where account-absence is treated as\n * SUCCESS, so a wrong-chain check would silently produce a\n * false-positive verdict.\n *\n * Tiers (same as `resolveProgramId` but throws on the last):\n * 1. `--program-id` flag\n * 2. `ARP_ESCROW_PROGRAM_ID` env\n * 3. server `GET /v1/escrow/protocol-fee`\n * 4. throw — operator must pass one of the above explicitly\n */\nexport async function resolveProgramIdStrict(api: ArpApiClient, opts: { programId?: string }): Promise<string> {\n\tif (opts.programId !== undefined && opts.programId !== '') return opts.programId;\n\tif (process.env.ARP_ESCROW_PROGRAM_ID !== undefined && process.env.ARP_ESCROW_PROGRAM_ID !== '') {\n\t\treturn process.env.ARP_ESCROW_PROGRAM_ID;\n\t}\n\tlet serverErr: unknown = null;\n\ttry {\n\t\tconst status = await api.getProtocolFee();\n\t\tif (status.programId && status.programId.length > 0) return status.programId;\n\t} catch (err) {\n\t\tserverErr = err;\n\t}\n\tthrow new Error(\n\t\t`wallet verify-release: program_id could not be resolved (--program-id flag empty, ARP_ESCROW_PROGRAM_ID env unset, ${serverErr ? `server discovery failed: ${(serverErr as Error).message}` : 'server returned empty programId'}). Refusing to fall back to the hardcoded placeholder — checking PDAs on the WRONG program would silently print \"Released: ✓ YES\" against AccountNotFound from a program that doesn't have those PDAs to begin with. Pass --program-id explicitly or export ARP_ESCROW_PROGRAM_ID.`,\n\t);\n}\n\n/**\n * strict RPC resolver — symmetric\n * to `resolveProgramIdStrict`. Refuses the hardcoded localhost\n * fallback so `verify-release` can't silently check the wrong\n * cluster.\n */\nexport function resolveRpcUrlStrict(opts: { rpcUrl?: string }): string {\n\tif (opts.rpcUrl !== undefined && opts.rpcUrl !== '') return opts.rpcUrl;\n\tif (process.env.ARP_ESCROW_RPC_URL !== undefined && process.env.ARP_ESCROW_RPC_URL !== '') {\n\t\treturn process.env.ARP_ESCROW_RPC_URL;\n\t}\n\tconst cfg = getGlobalConfigValue('rpcUrl');\n\tif (cfg !== undefined && cfg !== '') return cfg;\n\tthrow new Error(\n\t\t`wallet verify-release: rpcUrl could not be resolved (--rpc-url flag empty, ARP_ESCROW_RPC_URL env unset, \\`heyarp config get rpcUrl\\` empty). Refusing to fall back to the hardcoded localhost default — checking PDAs on the WRONG cluster would silently print \"Released: ✓ YES\" against AccountNotFound from a node that never saw the create_lock tx. Pass --rpc-url explicitly, set the env var, or run \\`heyarp config set rpcUrl <url>\\`.`,\n\t);\n}\n\nexport function registerWalletCommands(root: Command): void {\n\tconst cmd = root.command('wallet').description('Solana-side helpers: build + sign create_lock tx, sign settlement digests, derive PDAs for on-chain verification, verify release post-cycle');\n\n\tregisterCreateLock(cmd);\n\tregisterSignSettlement(cmd);\n\tregisterDerivePdas(cmd);\n\tregisterVerifyRelease(cmd);\n}\n\n// =============================================================================\n// wallet derive-pdas — print Lock + Vault PDAs for a delegation_id\n// =============================================================================\n\ninterface DerivePdasOptions {\n\tdelegationId: string;\n\tserver?: string;\n\tprogramId?: string;\n\t/**\n\t * Accepted for command-line symmetry with `wallet verify-release`,\n\t * but never read. PDAs are derived deterministically from\n\t * `program_id + delegation_id`; no RPC round-trip is needed.\n\t * Documented in --help so operators know not to expect chain\n\t * queries from this command.\n\t */\n\trpcUrl?: string;\n\t/**\n\t * The next four flags are accepted as no-op aliases for symmetry\n\t * with `wallet create-lock` — operators copy-pasting between the\n\t * two subcommands hit `unknown option` errors otherwise. PDAs are\n\t * derived ONLY from program_id + delegation_id (lock_id =\n\t * sha256(\"arp-lock-v1\" || del_id_bytes16)), so these flags\n\t * genuinely have no effect on output. Help text documents the\n\t * intentional no-op behaviour.\n\t */\n\trecipientPubkey?: string;\n\tconditionHash?: string;\n\tamountLamports?: string;\n\texpirySecs?: string;\n\tjson?: boolean;\n}\n\n/**\n * Output shape of `heyarp wallet derive-pdas`. `lock_id_hex` is the\n * SAME VALUE as `create-lock`'s `lock_id` (which omits the `_hex`\n * suffix because it's part of the wire `escrow_lock` shape that the\n * server already expects under that name). The `_hex` suffix here\n * makes the encoding explicit — this is the lock_id BYTES rendered\n * as a 64-char hex string, distinct from the SDK's `Uint8Array`\n * representation.\n */\ninterface DerivePdasOutput {\n\tdelegation_id: string;\n\tlock_id_hex: string;\n\tprogram_id: string;\n\tlock_pda: string;\n\t/** Single escrow PDA replaces V1.5's vault + vault_authority pair\n\t * (new contract uses `[b\"escrow\", lock_id]`). */\n\tescrow_pda: string;\n\t/** Singleton Config PDA at `[b\"config\"]`. */\n\tconfig_pda: string;\n\t/** `#[event_cpi]` PDA at `[b\"__event_authority\"]`. */\n\tevent_authority_pda: string;\n}\n\nfunction registerDerivePdas(cmd: Command): void {\n\tcmd.command('derive-pdas')\n\t\t.description(\n\t\t\t'Print the deterministic Lock + Vault PDAs for a delegation_id. Smoke-test validators persist on-chain state across runs, so `solana account <program>` returns leftover Lock PDAs from prior cycles mixed in with the current one. This command gives you the EXPECTED PDAs from `lock_id = sha256(\"arp-lock-v1\" || del_id_bytes16)` so you can `solana account <expected-pda>` directly without grovelling through `getProgramAccounts`.',\n\t\t)\n\t\t.requiredOption('--delegation-id <id>', 'Delegation UUID (canonical `del_<uuid>` or bare `<uuid>` — both accepted)')\n\t\t.option('--server <url>', 'Override server URL (used only for --program-id auto-discovery)')\n\t\t.option(\n\t\t\t'--program-id <pubkey>',\n\t\t\t`Deployed ARP escrow program id. Precedence: --program-id flag > ARP_ESCROW_PROGRAM_ID env > GET /v1/escrow/protocol-fee (auto-discover) > hardcoded fallback (${FALLBACK_PROGRAM_ID}).`,\n\t\t)\n\t\t.option(\n\t\t\t'--rpc-url <url>',\n\t\t\t'Accepted for symmetry with `wallet verify-release` but never read — PDAs are derived locally from `program_id + delegation_id`; no RPC needed.',\n\t\t)\n\t\t.option(\n\t\t\t'--recipient-pubkey <base58>',\n\t\t\t'Accepted for symmetry with `wallet create-lock` but never read — PDAs depend ONLY on program_id + delegation_id; recipient pubkey has no derivation role.',\n\t\t)\n\t\t.option(\n\t\t\t'--condition-hash <hex>',\n\t\t\t'Accepted for symmetry with `wallet create-lock` but never read — PDAs depend ONLY on program_id + delegation_id.',\n\t\t)\n\t\t.option(\n\t\t\t'--amount-lamports <int>',\n\t\t\t'Accepted for symmetry with `wallet create-lock` but never read — PDAs depend ONLY on program_id + delegation_id.',\n\t\t)\n\t\t.option(\n\t\t\t'--expiry-secs <int>',\n\t\t\t'Accepted for symmetry with `wallet create-lock` but never read — PDAs depend ONLY on program_id + delegation_id.',\n\t\t)\n\t\t.option('--json', 'Emit JSON instead of human text (jq-pipeable: `.lock_pda`, `.escrow_pda`, `.config_pda`, `.lock_id_hex`).', false)\n\t\t.action(async (opts: DerivePdasOptions) => {\n\t\t\ttry {\n\t\t\t\tconst out = await derivePdasHandler(opts);\n\t\t\t\tif (opts.json) {\n\t\t\t\t\tconsole.log(JSON.stringify(out, null, 2));\n\t\t\t\t} else {\n\t\t\t\t\tconsole.log(`Delegation: ${out.delegation_id}`);\n\t\t\t\t\tconsole.log(`lock_id (hex): ${out.lock_id_hex}`);\n\t\t\t\t\tconsole.log(`Program ID: ${out.program_id}`);\n\t\t\t\t\tconsole.log(`Lock PDA: ${out.lock_pda}`);\n\t\t\t\t\tconsole.log(`Escrow PDA: ${out.escrow_pda}`);\n\t\t\t\t\tconsole.log(`Config PDA: ${out.config_pda}`);\n\t\t\t\t\tconsole.log(`EventAuthPDA: ${out.event_authority_pda}`);\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error((err as Error).message);\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t});\n}\n\nexport async function derivePdasHandler(opts: DerivePdasOptions): Promise<DerivePdasOutput> {\n\tconst normalisedDelegationId = normaliseDelegationId(opts.delegationId);\n\tconst api = new ArpApiClient(opts.server);\n\tconst programId = new PublicKey(await resolveProgramId(api, opts));\n\n\tconst lockIdBytes = deriveLockId(normalisedDelegationId);\n\tconst lockIdSeed = Buffer.from(lockIdBytes);\n\tconst lockIdHex = Buffer.from(lockIdBytes).toString('hex');\n\n\tconst [lockPda] = PublicKey.findProgramAddressSync([Buffer.from('lock'), lockIdSeed], programId);\n\tconst [escrowPda] = PublicKey.findProgramAddressSync([Buffer.from('escrow'), lockIdSeed], programId);\n\tconst [configPda] = PublicKey.findProgramAddressSync([Buffer.from('config')], programId);\n\tconst [eventAuthorityPda] = PublicKey.findProgramAddressSync([Buffer.from('__event_authority')], programId);\n\n\treturn {\n\t\tdelegation_id: normalisedDelegationId,\n\t\tlock_id_hex: lockIdHex,\n\t\tprogram_id: programId.toBase58(),\n\t\tlock_pda: lockPda.toBase58(),\n\t\t// Single escrow PDA replaces the V1.5 vault + vault_authority\n\t\t// pair in the new contract.\n\t\tescrow_pda: escrowPda.toBase58(),\n\t\tconfig_pda: configPda.toBase58(),\n\t\tevent_authority_pda: eventAuthorityPda.toBase58(),\n\t};\n}\n\n// =============================================================================\n// wallet verify-release — post-cycle on-chain assertion (PR-2)\n// =============================================================================\n\ninterface VerifyReleaseOptions {\n\tdelegationId: string;\n\tserver?: string;\n\trpcUrl?: string;\n\tprogramId?: string;\n\tjson?: boolean;\n\t/**\n\t * Skip the per-PDA signature-index retry loop entirely. By default\n\t * the handler retries `getSignaturesForAddress(lockPda)` up to 2\n\t * times (3s + 6s cumulative) when the initial query returns empty\n\t * AND both PDAs are absent — this masks the localnet timing gap\n\t * where `solana-test-validator` lags ~5-10s between tx finalization\n\t * and sig-index population, otherwise producing a false\n\t * `lock_never_created`. Production RPCs (Helius, Triton, mainnet)\n\t * index sigs synchronously, so the retries are a no-op on the\n\t * happy path. Pass `--no-sig-retry` (this flag) to disable for\n\t * callers who want strict, immediate semantics.\n\t */\n\tnoSigRetry?: boolean;\n}\n\n/**\n * Five-state classification of the on-chain release verdict. The\n * `released_partial` / `released_refunded` variants are required to\n * disambiguate `partial_release` and `refund_lock` from a full\n * `release_lock` — without them the closed-state cases all collapse\n * to `released_clean` (cycle-accurate but settlement-blind).\n *\n * Closed states (PDAs absent AND lock signature seen on chain):\n * - `released_clean`: lock was closed by a `release_lock` ix —\n * full lock.amount went to the payee.\n * - `released_partial`: lock was closed by a `partial_release` ix —\n * `payee_amount` went to the payee, the refund tail (lock.amount −\n * payee_amount) went to the payer.\n * - `released_refunded`: lock was closed by a `refund_lock` ix —\n * full lock.amount went BACK to the payer (no payment to payee).\n *\n * Open / undetermined states:\n * - `lock_still_present`: one or both PDAs still on chain. Release\n * never fired OR is mid-flight.\n * - `lock_never_created`: BOTH PDAs absent AND no signature history\n * for the lock PDA → operator never successfully submitted a\n * create_lock for this delegation_id.\n *\n * The released_* states are disambiguated by parsing the most-recent\n * lock-PDA transaction's Anchor log messages (\"Program log:\n * Instruction: <name>\"). If the inspection fails (RPC error, log\n * missing, transaction version unsupported), we conservatively\n * report `released_clean` with `release_method='unknown'`.\n */\nexport type VerifyReleaseStatus = 'released_clean' | 'released_partial' | 'released_refunded' | 'lock_still_present' | 'lock_never_created';\n\n/**\n * Which Anchor ix actually closed the PDAs. Parsed from the lock\n * PDA's most-recent transaction logs. `unknown` means the inspection\n * couldn't conclude (RPC failure, log missing, future ix variant) —\n * caller treats `unknown` as best-effort `released_clean`.\n */\nexport type ReleaseMethod = 'release_lock' | 'partial_release' | 'refund_lock' | 'force_refund_lock' | 'resolve_dispute' | 'rescue_stuck_funds' | 'unknown';\n\ninterface VerifyReleaseOutput {\n\tdelegation_id: string;\n\tlock_pda: string;\n\tvault_pda: string;\n\tlock_account_exists: boolean;\n\tvault_account_exists: boolean;\n\t/**\n\t * Signature-history evidence that the lock PDA was ever a\n\t * participant in a confirmed tx. Solana's\n\t * `getSignaturesForAddress(lockPda, {limit: 1})` returns ≥1 sig\n\t * when the PDA was ever touched by a confirmed tx (create or\n\t * release), 0 sigs when it never existed. Combined with the\n\t * PDA-absent check, this distinguishes \"released cleanly\" from\n\t * \"never created\" — both of which look like AccountNotFound.\n\t */\n\tlock_pda_seen_in_signatures: boolean;\n\treleased: boolean;\n\t/**\n\t * One of five discrete states the verifier can confidently\n\t * distinguish from on-chain evidence. See `VerifyReleaseStatus`\n\t * for semantics.\n\t */\n\tstatus: VerifyReleaseStatus;\n\t/**\n\t * Which Anchor instruction closed the PDAs. Only populated when\n\t * `status` is one of `released_clean`, `released_partial`,\n\t * `released_refunded`. `unknown` means the inspection couldn't\n\t * read the tx (RPC error / unsupported version / log absent).\n\t * For the closed-state cases, status follows method:\n\t * release_lock → released_clean, partial_release →\n\t * released_partial, refund_lock → released_refunded;\n\t * unknown → released_clean (conservative fallback).\n\t *\n\t * Under the R15 contract the lock account is NOT closed on\n\t * release — the state byte transitions instead. We back-derive\n\t * the canonical method from the on-chain state byte when the\n\t * tx-log classifier can't run, so this field stays populated\n\t * for the new contract path too (mapping: 1 → release_lock,\n\t * 4 → partial_release, 2 → refund_lock, 3 → resolve_dispute).\n\t */\n\trelease_method?: ReleaseMethod;\n\t/**\n\t * Raw `lock.state` byte at offset 185 of the Lock PDA. Anchor enum,\n\t * declaration order = numeric value:\n\t * 0 Locked, 1 Released, 2 Refunded, 3 DisputeResolved,\n\t * 4 PartiallyReleased.\n\t * Absent when the Lock PDA doesn't exist (legacy contract\n\t * post-release, or `lock_never_created`).\n\t */\n\tlock_state?: number;\n\trpc_url: string;\n}\n\n/**\n * Post-cycle on-chain assertion: did the release actually happen?\n * Wraps `getAccountInfo` for the Lock + Vault PDAs into one CLI\n * call so scripts don't need to compose `derive-pdas`, per-PDA\n * `solana account`, pipefail-safe inverted checks, and a balance\n * lookup. Returns a structured outcome — `released: true` IFF both\n * Lock + Vault PDAs return AccountNotFound (release_lock drained\n * and closed both).\n *\n * Exits non-zero if either PDA still exists (release didn't\n * complete) so `set -euo pipefail` scripts catch the failure.\n *\n * Exported for unit-test coverage.\n */\nfunction registerVerifyRelease(cmd: Command): void {\n\tcmd.command('verify-release')\n\t\t.description(\n\t\t\t'Post-cycle on-chain assertion. Derives the Lock + Vault PDAs for a delegation_id (same as `derive-pdas`) and checks both return AccountNotFound on the RPC. Returns `released: true` IFF both are gone (release_lock drained + closed them); exits non-zero otherwise so `set -euo pipefail` scripts catch incomplete releases.',\n\t\t)\n\t\t.requiredOption('--delegation-id <id>', 'Delegation UUID (canonical `del_<uuid>` or bare `<uuid>` — both accepted)')\n\t\t.option('--server <url>', 'Override ARP server URL (used only for --program-id auto-discovery)')\n\t\t.option(\n\t\t\t'--rpc-url <url>',\n\t\t\t`Solana RPC URL. Precedence: --rpc-url flag > ARP_ESCROW_RPC_URL env > \\`heyarp config set rpcUrl\\` > FAIL. This command refuses to fall back to the hardcoded localhost default — wrong-cluster AccountNotFound would silently print \"Released: ✓ YES\" against a node that never saw the create_lock tx.`,\n\t\t)\n\t\t.option(\n\t\t\t'--program-id <pubkey>',\n\t\t\t`Deployed ARP escrow program id. Precedence: --program-id flag > ARP_ESCROW_PROGRAM_ID env > GET /v1/escrow/protocol-fee (auto-discover) > FAIL. This command refuses to fall back to the hardcoded placeholder — wrong-program AccountNotFound would silently print \"Released: ✓ YES\" against PDAs that don't exist on the actual deployed chain.`,\n\t\t)\n\t\t.option(\n\t\t\t'--no-sig-retry',\n\t\t\t'Skip the per-PDA signature-index retry loop. By default the handler retries `getSignaturesForAddress(lockPda)` up to 2 times (3s+6s cumulative) when initial query returns empty AND both PDAs are absent — works around solana-test-validator\\'s ~5-10s lag between tx finalization and sig-index population (otherwise produces false `lock_never_created`). Production RPCs (Helius, Triton, mainnet) index sigs synchronously, so retries are a no-op on the happy path. Pass `--no-sig-retry` for strict-immediate semantics.',\n\t\t)\n\t\t.option('--json', 'Emit JSON instead of human text. jq-pipeable.', false)\n\t\t.action(async (opts: VerifyReleaseOptions) => {\n\t\t\ttry {\n\t\t\t\tconst out = await verifyReleaseHandler(opts);\n\t\t\t\tif (opts.json) {\n\t\t\t\t\tconsole.log(JSON.stringify(out, null, 2));\n\t\t\t\t} else {\n\t\t\t\t\t// Discrete status string — the `lock_never_created`\n\t\t\t\t\t// case must render distinctly from `released_clean`,\n\t\t\t\t\t// otherwise both would collapse to the same\n\t\t\t\t\t// \"Released: ✓ YES\" line and a never-created lock\n\t\t\t\t\t// would look identical to a successful release.\n\t\t\t\t\tconsole.log(`Delegation: ${out.delegation_id}`);\n\t\t\t\t\tconsole.log(`RPC URL: ${out.rpc_url}`);\n\t\t\t\t\tconsole.log(`Lock PDA: ${out.lock_pda} ${out.lock_account_exists ? '✗ still exists' : '✓ closed (AccountNotFound)'}`);\n\t\t\t\t\tconsole.log(`Vault PDA: ${out.vault_pda} ${out.vault_account_exists ? '✗ still exists' : '✓ closed (AccountNotFound)'}`);\n\t\t\t\t\tconsole.log(`Lock signatures: ${out.lock_pda_seen_in_signatures ? '✓ found (lock was created at some point)' : '✗ none (lock never created on chain)'}`);\n\t\t\t\t\t// When release_method === 'unknown' the status code\n\t\t\t\t\t// still reads `released_clean` (so backward-compatible\n\t\t\t\t\t// scripts that assert on that string for any\n\t\t\t\t\t// successful close keep working), but the\n\t\t\t\t\t// human-readable line MUST hedge. Otherwise a\n\t\t\t\t\t// degraded-RPC partial release would mis-describe\n\t\t\t\t\t// as \"full payment to payee\".\n\t\t\t\t\tconst statusLine = renderStatusLine(out.status, out.release_method);\n\t\t\t\t\tconsole.log(`Status: ${statusLine}`);\n\t\t\t\t\tif (out.release_method !== undefined) {\n\t\t\t\t\t\t// Surface the closing ix when we determined it\n\t\t\t\t\t\t// from on-chain evidence. For `unknown` we still\n\t\t\t\t\t\t// print it so the operator knows the log-parse\n\t\t\t\t\t\t// path was tried but inconclusive.\n\t\t\t\t\t\tconsole.log(`Release method: ${out.release_method}`);\n\t\t\t\t\t}\n\t\t\t\t\tconsole.log(`Released: ${out.released ? '✓ YES' : '✗ NO'}`);\n\t\t\t\t}\n\t\t\t\tif (!out.released) {\n\t\t\t\t\tprocess.exitCode = 1;\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error((err as Error).message);\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t});\n}\n\nexport async function verifyReleaseHandler(opts: VerifyReleaseOptions): Promise<VerifyReleaseOutput> {\n\tconst normalisedDelegationId = normaliseDelegationId(opts.delegationId);\n\tconst api = new ArpApiClient(opts.server);\n\t// Refuse to fall back silently on chain config. `resolveProgramId`\n\t// / `resolveRpcUrl` both have a hardcoded fallback as their last-\n\t// resort tier — for any other command (sign release digest, create\n\t// lock) that's fine because downstream submission rejects with a\n\t// loud server error if the program/RPC mismatch the deployed chain.\n\t// But `verify-release` treats account-absence as SUCCESS — if we\n\t// silently checked the wrong chain, AccountNotFound from a\n\t// placeholder program → false-positive `released: true` with exit\n\t// code 0, even though the real lock still exists on the actual\n\t// deployed chain. Hard-fail when any tier of the resolution chain\n\t// implicit-defaulted, so the operator must pass an EXPLICIT\n\t// --program-id / --rpc-url (or set env vars).\n\tconst programIdStr = await resolveProgramIdStrict(api, opts);\n\tconst rpcUrl = resolveRpcUrlStrict(opts);\n\tconst programId = new PublicKey(programIdStr);\n\n\tconst lockIdBytes = deriveLockId(normalisedDelegationId);\n\tconst lockIdSeed = Buffer.from(lockIdBytes);\n\tconst [lockPda] = PublicKey.findProgramAddressSync([Buffer.from('lock'), lockIdSeed], programId);\n\t// New contract uses a single `escrow` PDA (`[b\"escrow\", lock_id]`)\n\t// in place of the V1.5 `vault` + `vault_authority` pair. The\n\t// release flow no longer CLOSES either the Lock or the escrow\n\t// account — it just sets `lock.state` and transfers funds out of\n\t// the escrow PDA. So account-existence is no longer the right\n\t// release signal; we read the on-chain `lock.state` byte instead\n\t// (offset 185 in the Anchor Lock account; see `state/lock.rs`).\n\tconst [escrowPda] = PublicKey.findProgramAddressSync([Buffer.from('escrow'), lockIdSeed], programId);\n\n\tconst conn = new SolanaConnection(rpcUrl, 'confirmed');\n\t// `getAccountInfo` returns `null` for AccountNotFound (the\n\t// post-release happy state). It throws on RPC errors (e.g.\n\t// validator down) — let those bubble up as the error path.\n\t//\n\t// Also query signature history for the lock PDA. If the PDA was\n\t// ever a participant in a confirmed tx, `getSignaturesForAddress`\n\t// returns ≥1 entry — sufficient evidence that create_lock fired\n\t// at some point. Combined with the PDA-absent check, this lets\n\t// us distinguish \"released cleanly\" from \"never created\" — both\n\t// of which look identical via `getAccountInfo` alone.\n\t//\n\t// We fetch a small window of sigs (not just limit:1) so the\n\t// close-tx classifier can SKIP failed signatures. A failed retry\n\t// submitted AFTER the lock was closed shows up in the PDA's sig\n\t// history with `err !== null`; without filtering, the classifier\n\t// might pick a failed release_lock retry over the earlier\n\t// successful partial_release, mis-classifying the cycle. Limit:5\n\t// keeps the RPC cost roughly the same (one round-trip) while\n\t// giving the filter headroom. (`lock_pda_seen_in_signatures` still\n\t// only needs to know length > 0.)\n\tconst [lockInfo, escrowInfo, initialLockSigs] = await Promise.all([\n\t\tconn.getAccountInfo(lockPda),\n\t\tconn.getAccountInfo(escrowPda),\n\t\tconn.getSignaturesForAddress(lockPda, { limit: 5 }),\n\t]);\n\tconst lockExists = lockInfo !== null;\n\t// `vault_account_exists` retained on the output as a backward-\n\t// compat field; in the new contract the escrow PDA replaces the\n\t// vault. Surface escrow existence under that field so older\n\t// shell scripts that branch on it continue to read something\n\t// sensible.\n\tconst vaultExists = escrowInfo !== null;\n\tlet lockSeenInSignatures = initialLockSigs.length > 0;\n\n\t// Read the on-chain `lock.state` byte if the lock account is on\n\t// chain. Anchor Lock layout (see\n\t// `apps/arp-solana-contract/programs/arp-solana-contract/src/state/lock.rs`):\n\t// 0..8 discriminator\n\t// 8..40 lock_id [u8; 32]\n\t// 40..41 version: u8\n\t// 41..73 payer: Pubkey\n\t// 73..105 payee: Pubkey\n\t// 105..113 amount: u64 LE\n\t// 113..145 mint: Pubkey\n\t// 145..177 condition_hash: [u8; 32]\n\t// 177..185 expiry: u64 LE\n\t// 185 state: LockState (Anchor enum = u8)\n\t// State variants per declaration order in `lock.rs`:\n\t// 0 Locked\n\t// 1 Released\n\t// 2 Refunded\n\t// 3 DisputeResolved\n\t// 4 PartiallyReleased\n\t// undefined when lock account is absent or the buffer is too\n\t// short to reach offset 185 (defensive — Anchor accounts are\n\t// always full size, but unit-test fixtures sometimes mock null).\n\tlet lockStateByte: number | undefined;\n\tif (lockInfo && lockInfo.data.length > 185) {\n\t\tlockStateByte = lockInfo.data[185];\n\t}\n\t// Pre-classify based purely on the chain-stored state. If we have\n\t// a definitive non-Locked state, it WINS over the legacy\n\t// PDA-closed heuristic (which never fires under the new contract\n\t// since lock + escrow are never closed). Old test fixtures that\n\t// mock `getAccountInfo: null` still flow through the legacy\n\t// path — they hit the `lockExists=false` branch below.\n\t//\n\t// Mapping rationale:\n\t// 1 Released → released_clean (release_lock: full → payee)\n\t// 2 Refunded → released_refunded (refund_lock: full → payer)\n\t// 3 DisputeResolved → released_partial (resolve_dispute: split — operator\n\t// sets both payer_amount + payee_amount; semantically\n\t// a partial release, NOT a refund, even though it's\n\t// a different ix than partial_release; matches\n\t// `mapReleaseMethodToStatus('resolve_dispute')`)\n\t// 4 PartiallyReleased→ released_partial (partial_release: split)\n\tconst stateBasedStatus: VerifyReleaseStatus | undefined =\n\t\tlockStateByte === 1\n\t\t\t? 'released_clean'\n\t\t\t: lockStateByte === 4 || lockStateByte === 3\n\t\t\t\t? 'released_partial'\n\t\t\t\t: lockStateByte === 2\n\t\t\t\t\t? 'released_refunded'\n\t\t\t\t\t: lockStateByte === 0\n\t\t\t\t\t\t? 'lock_still_present'\n\t\t\t\t\t\t: undefined;\n\t// Pick the most-recent SUCCESSFUL signature (err === null). Failed\n\t// retry txs that touch the already-closed PDA show up in history\n\t// with err !== null and would otherwise be the newest entry. The\n\t// successful close is the only tx that can be a `release_lock` /\n\t// `partial_release` / `refund_lock`; failed retries reverted state,\n\t// so they don't classify into any released_* state. If no\n\t// successful sig in the window, `latestSig` stays undefined →\n\t// classifier returns `unknown` → status falls back to\n\t// `released_clean`.\n\tlet latestSig: string | undefined = pickLatestSuccessfulSignature(initialLockSigs);\n\n\t// First-pass classification (may be 'unknown' if the latest\n\t// indexed sig is the `create_lock` rather than the close — the\n\t// retry block below covers that lag case).\n\tlet releaseMethod: ReleaseMethod | undefined;\n\tif (!lockExists && !vaultExists && lockSeenInSignatures && latestSig !== undefined) {\n\t\treleaseMethod = await classifyReleaseMethod(conn, latestSig);\n\t}\n\n\t// solana-test-validator lags ~5-10s between tx finalization and\n\t// per-PDA signature-index population. Two distinct symptoms:\n\t//\n\t// (a) Initial sig query returned 0 — could be `released_clean`\n\t// (close just landed, index lagging entirely) OR genuine\n\t// `lock_never_created`.\n\t// (b) Initial sig query returned only the older `create_lock`\n\t// sig, close sig still lagging — `classifyReleaseMethod`\n\t// sees `Instruction: CreateLock` (not in the close-method\n\t// allowlist) and returns 'unknown'. Without a retry the\n\t// caller misclassifies a real `partial_release` /\n\t// `refund_lock` as `released_clean`.\n\t//\n\t// Retry up to 2 times with backoff (3s, 6s cumulative) to give\n\t// the index time to publish the close sig. Stop early as soon as\n\t// we have a non-'unknown' classification. On production RPCs\n\t// (Helius, Triton, public mainnet) the index is synchronous →\n\t// no retries fire and the happy path stays single-RPC-call.\n\t// Operator can disable both retry paths via `--no-sig-retry`\n\t// for strict-immediate semantics.\n\tconst pdasAreClosed = !lockExists && !vaultExists;\n\t// A classification is CONFIDENT when the classifier returned one\n\t// of the three known close-method ix names. Anything else\n\t// (undefined — first-pass didn't run because `latestSig` was\n\t// undefined under the all-failed-sigs-initially case; or\n\t// 'unknown' — classifier ran but couldn't find a close-method\n\t// log) is ambiguous and benefits from a retry. The\n\t// `latestSig === undefined` corner specifically needs this:\n\t// with `lockSeenInSignatures = true` and `releaseMethod ===\n\t// undefined`, a `releaseMethod === 'unknown'` retry guard\n\t// would be strictly false → no retry, silently skipping the\n\t// validator-lag scenario the retry is supposed to cover.\n\tconst hasConfidentMethod =\n\t\treleaseMethod === 'release_lock' ||\n\t\treleaseMethod === 'partial_release' ||\n\t\treleaseMethod === 'refund_lock' ||\n\t\treleaseMethod === 'force_refund_lock' ||\n\t\treleaseMethod === 'resolve_dispute' ||\n\t\treleaseMethod === 'rescue_stuck_funds';\n\tconst classificationIsAmbiguous = pdasAreClosed && !hasConfidentMethod;\n\tconst shouldRetrySigCheck = !opts.noSigRetry && classificationIsAmbiguous;\n\tif (shouldRetrySigCheck) {\n\t\tconst retryDelaysMs = [3000, 3000];\n\t\tfor (const delay of retryDelaysMs) {\n\t\t\tawait new Promise((resolve) => setTimeout(resolve, delay));\n\t\t\tconst retriedSigs = await conn.getSignaturesForAddress(lockPda, { limit: 5 });\n\t\t\tif (retriedSigs.length > 0) {\n\t\t\t\tlockSeenInSignatures = true;\n\t\t\t\tconst retriedLatest = pickLatestSuccessfulSignature(retriedSigs);\n\t\t\t\tif (retriedLatest !== undefined) {\n\t\t\t\t\tlatestSig = retriedLatest;\n\t\t\t\t\treleaseMethod = await classifyReleaseMethod(conn, retriedLatest);\n\t\t\t\t\tif (releaseMethod !== 'unknown') break;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Classify into discrete states.\n\t// Note: status='lock_never_created' wins over 'lock_still_present'\n\t// only when BOTH PDAs are absent — if even one PDA exists, the\n\t// lock IS present (we shouldn't claim \"never created\" for a\n\t// live half-released state).\n\t//\n\t// When both PDAs are absent AND a lock sig is on chain,\n\t// `releaseMethod` (resolved above + retry loop) carries the\n\t// disambiguated ix so we surface the settlement variant\n\t// (released_clean / released_partial / released_refunded) to\n\t// callers instead of collapsing them all to released_clean.\n\tlet status: VerifyReleaseStatus;\n\t// If we have a definitive on-chain `lock.state` byte, it wins\n\t// over the legacy PDA-existence heuristics — the new contract\n\t// never closes Lock or escrow accounts, so account-existence is\n\t// no longer a release signal.\n\tif (stateBasedStatus !== undefined) {\n\t\tstatus = stateBasedStatus;\n\t\tif (stateBasedStatus === 'lock_still_present') {\n\t\t\treleaseMethod = undefined; // not closed\n\t\t} else if (releaseMethod === undefined || releaseMethod === 'unknown') {\n\t\t\t// Tx-log classifier won't run (lock still on-chain in R15\n\t\t\t// contract; latestSig branch requires both PDAs closed\n\t\t\t// per the legacy heuristic). Back-derive the canonical\n\t\t\t// method from the state byte. Anchor enum mapping:\n\t\t\t// 1 Released → release_lock\n\t\t\t// 2 Refunded → refund_lock\n\t\t\t// 3 DisputeResolved → resolve_dispute\n\t\t\t// 4 PartiallyReleased→ partial_release\n\t\t\t// (state 0 = Locked, handled by the\n\t\t\t// `lock_still_present` branch above.)\n\t\t\treleaseMethod =\n\t\t\t\tlockStateByte === 1\n\t\t\t\t\t? 'release_lock'\n\t\t\t\t\t: lockStateByte === 4\n\t\t\t\t\t\t? 'partial_release'\n\t\t\t\t\t\t: lockStateByte === 2\n\t\t\t\t\t\t\t? 'refund_lock'\n\t\t\t\t\t\t\t: lockStateByte === 3\n\t\t\t\t\t\t\t\t? 'resolve_dispute'\n\t\t\t\t\t\t\t\t: releaseMethod;\n\t\t}\n\t} else if (lockExists || vaultExists) {\n\t\tstatus = 'lock_still_present';\n\t\treleaseMethod = undefined; // no close ix to surface\n\t} else if (lockSeenInSignatures) {\n\t\t// PDAs closed AND lock sigs exist → the lock was created\n\t\t// AND closed at some point. If `releaseMethod` is still\n\t\t// undefined here, it means we hit a rare edge: sigs are\n\t\t// present but `pickLatestSuccessfulSignature` returned\n\t\t// undefined (e.g., many post-close failed retries pushed\n\t\t// the actual close sig out of the limit:5 window). Status\n\t\t// is still `released_clean` — the lock IS closed — but\n\t\t// surface `release_method='unknown'` so the human-readable\n\t\t// line hedges accordingly.\n\t\tif (releaseMethod === undefined) releaseMethod = 'unknown';\n\t\tstatus = mapReleaseMethodToStatus(releaseMethod);\n\t} else {\n\t\tstatus = 'lock_never_created';\n\t\treleaseMethod = undefined;\n\t}\n\t// `released = true` for ALL three closed-by-release states: the\n\t// lock is no longer holding funds, the cycle is complete from the\n\t// chain's perspective. The status discriminator carries the\n\t// payment-direction nuance (clean = payee, partial = both,\n\t// refunded = payer-only).\n\tconst released = status === 'released_clean' || status === 'released_partial' || status === 'released_refunded';\n\n\treturn {\n\t\tdelegation_id: normalisedDelegationId,\n\t\tlock_pda: lockPda.toBase58(),\n\t\t// `vault_pda` is the old contract's vault address; the new\n\t\t// contract replaced it with the `escrow` PDA. We surface the\n\t\t// escrow address under the old field name so backward-compat\n\t\t// shell scripts still parse — the value is what the script\n\t\t// would naturally want anyway (the account holding the\n\t\t// escrowed funds).\n\t\tvault_pda: escrowPda.toBase58(),\n\t\tlock_account_exists: lockExists,\n\t\tvault_account_exists: vaultExists,\n\t\tlock_pda_seen_in_signatures: lockSeenInSignatures,\n\t\treleased,\n\t\tstatus,\n\t\t...(releaseMethod !== undefined ? { release_method: releaseMethod } : {}),\n\t\t...(lockStateByte !== undefined ? { lock_state: lockStateByte } : {}),\n\t\trpc_url: rpcUrl,\n\t};\n}\n\n/**\n * Parse the most-recent lock-PDA transaction to learn which Anchor ix\n * closed the lock. Anchor emits a \"Program log: Instruction: <name>\"\n * line for each invoked instruction; we match on that.\n *\n * Best-effort — any failure (RPC error, missing tx, unsupported tx\n * version, log absent) returns `'unknown'` so the caller can fall\n * back to a conservative `released_clean` classification.\n *\n * Why parse logs instead of the discriminator bytes? Logs are stable\n * across program upgrades, independent of the on-chain IDL\n * availability, and don't require the SDK to ship a copy of the\n * discriminator table.\n */\n/**\n * Scan a newest-first signature window and return the first one with\n * `err === null`. Failed txs that touched the already-closed PDA\n * (e.g., a release_lock retry submitted after a successful\n * partial_release) show up in history but didn't actually mutate\n * state — they must NOT be used to classify the close. Returns\n * undefined if no successful sig is present (signal to upstream that\n * classification is best-effort unavailable; status falls back to\n * `released_clean`).\n */\nfunction pickLatestSuccessfulSignature(sigs: readonly unknown[]): string | undefined {\n\tfor (const entry of sigs) {\n\t\tconst e = entry as { signature?: unknown; err?: unknown };\n\t\tif (typeof e.signature !== 'string') continue;\n\t\tif (e.err === null || e.err === undefined) return e.signature;\n\t}\n\treturn undefined;\n}\n\n/**\n * Anchor's runtime emits the instruction's PascalCase STRUCT name in\n * its `Instruction:` log line (`Instruction: PartialRelease`), NOT\n * the snake_case `pub fn` name (`Instruction: partial_release`).\n * Without matching the PascalCase form, real on-chain partial /\n * refund / full closes fall through to `unknown` → `released_clean`,\n * making the `released_partial` and `released_refunded` statuses\n * unreachable in production.\n *\n * Keep the snake_case form as a secondary match — defensive against\n * a future Anchor version that changes its logger, custom programs\n * that emit a non-Anchor log, and existing test fixtures that\n * already use snake_case for readability.\n */\nconst RELEASE_METHOD_PATTERNS: ReadonlyArray<{ method: Exclude<ReleaseMethod, 'unknown'>; patterns: readonly string[] }> = [\n\t// New contract adds three operator-gated close paths.\n\t// Match the more-specific names first so `RefundLock` doesn't\n\t// shadow `ForceRefundLock`.\n\t{ method: 'force_refund_lock', patterns: ['Instruction: ForceRefundLock', 'Instruction: force_refund_lock'] },\n\t{ method: 'resolve_dispute', patterns: ['Instruction: ResolveDispute', 'Instruction: resolve_dispute'] },\n\t{ method: 'rescue_stuck_funds', patterns: ['Instruction: RescueStuckFunds', 'Instruction: rescue_stuck_funds'] },\n\t{ method: 'partial_release', patterns: ['Instruction: PartialRelease', 'Instruction: partial_release'] },\n\t{ method: 'refund_lock', patterns: ['Instruction: RefundLock', 'Instruction: refund_lock'] },\n\t{ method: 'release_lock', patterns: ['Instruction: ReleaseLock', 'Instruction: release_lock'] },\n];\n\nasync function classifyReleaseMethod(conn: SolanaConnection, closingSig: string): Promise<ReleaseMethod> {\n\ttry {\n\t\tconst tx = await conn.getTransaction(closingSig, { maxSupportedTransactionVersion: 0, commitment: 'confirmed' });\n\t\tconst logs = tx?.meta?.logMessages ?? [];\n\t\t// Walk newest-first by log order. The FIRST match wins —\n\t\t// in real Anchor txs the outermost ix emits its\n\t\t// `Instruction:` log before any CPI nested ix.\n\t\t//\n\t\t// Within a single log line, partial_release & refund_lock\n\t\t// are checked before release_lock so the explicit ix wins\n\t\t// over the substring match (the patterns themselves don't\n\t\t// alias — `PartialRelease` doesn't contain `ReleaseLock` —\n\t\t// but the order documents intent and is cheap insurance.)\n\t\tfor (const log of logs) {\n\t\t\tfor (const { method, patterns } of RELEASE_METHOD_PATTERNS) {\n\t\t\t\tif (patterns.some((p) => log.includes(p))) return method;\n\t\t\t}\n\t\t}\n\t\treturn 'unknown';\n\t} catch (_err) {\n\t\t// RPC error / parse failure → caller falls back to clean\n\t\treturn 'unknown';\n\t}\n}\n\n/**\n * Map (status, release_method) to a human-readable description.\n * Critically, `released_clean` paired with `release_method ===\n * 'unknown'` HEDGES — it does NOT claim the close was a\n * release_lock, because the chain inspection was inconclusive\n * (degraded RPC, missing logs). The status code stays\n * `released_clean` for backward compat with scripts; only the\n * text differs.\n *\n * The fee story is also hedged. The on-chain `release_lock` /\n * `partial_release` deduct\n * `fee = (payee_slice * fee_bps_at_lock) / 10_000` before crediting\n * the payee (see programs/arp_escrow/src/instructions/release_lock.rs\n * and partial_release.rs). Saying \"full payment to payee\" overstates\n * the receipt when fees are active. We don't have the fee_bps_at_lock\n * value on hand at verify-release time (it lives on the lock account\n * we already saw close), so we phrase the lines as the cycle-level\n * payment direction and call out the fee modifier explicitly.\n *\n * Exported for unit-test coverage.\n */\nexport function renderStatusLine(status: VerifyReleaseStatus, releaseMethod?: ReleaseMethod): string {\n\tif (status === 'released_clean') {\n\t\treturn releaseMethod === 'unknown'\n\t\t\t? '✓ released — close method could not be determined from on-chain logs (RPC degraded / logs absent); PDAs are closed but the specific ix is unknown'\n\t\t\t: '✓ released_clean — lock was closed by `release_lock` (full lock.amount to payee, minus any protocol fee deducted at release time)';\n\t}\n\tif (status === 'released_partial') {\n\t\t// resolve_dispute also maps to released_partial (split shape)\n\t\t// but the trigger is operator-driven, not a payer/payee cosign.\n\t\tif (releaseMethod === 'resolve_dispute') {\n\t\t\treturn '✓ released_partial — lock was closed by `resolve_dispute` (operator-supplied split between payer + payee; no protocol fee)';\n\t\t}\n\t\treturn '✓ released_partial — lock was closed by `partial_release` (split: payee_amount minus any protocol fee to payee, refund tail = lock.amount − payee_amount to payer)';\n\t}\n\tif (status === 'released_refunded') {\n\t\t// force_refund_lock + rescue_stuck_funds also map to\n\t\t// released_refunded — call out the actual ix so operators\n\t\t// can tell a normal expiry refund from a dispute / emergency\n\t\t// rescue.\n\t\tif (releaseMethod === 'force_refund_lock') {\n\t\t\treturn '✓ released_refunded — lock was closed by `force_refund_lock` (operator-gated DisputeResolution refund: full lock.amount to payer, no fee)';\n\t\t}\n\t\tif (releaseMethod === 'rescue_stuck_funds') {\n\t\t\treturn '✓ released_refunded — lock was closed by `rescue_stuck_funds` (operator emergency rescue: full lock.amount returned, terminal state)';\n\t\t}\n\t\treturn '✓ released_refunded — lock was closed by `refund_lock` (full lock.amount refunded to payer, no payment to payee, no protocol fee)';\n\t}\n\tif (status === 'lock_still_present') {\n\t\treturn '✗ lock_still_present — one or both PDAs still on-chain; release did NOT complete';\n\t}\n\treturn '✗ lock_never_created — both PDAs absent AND no signature history; create_lock never fired on this chain';\n}\n\nfunction mapReleaseMethodToStatus(method: ReleaseMethod): VerifyReleaseStatus {\n\tswitch (method) {\n\t\tcase 'partial_release':\n\t\tcase 'resolve_dispute':\n\t\t\t// resolve_dispute splits the lock between payer + payee\n\t\t\t// per an operator-supplied verdict — same shape as\n\t\t\t// partial_release for the CLI's status surface.\n\t\t\treturn 'released_partial';\n\t\tcase 'refund_lock':\n\t\tcase 'force_refund_lock':\n\t\tcase 'rescue_stuck_funds':\n\t\t\t// All three return funds to the payer (force_refund_lock\n\t\t\t// is the operator-gated DisputeResolution branch;\n\t\t\t// rescue_stuck_funds is the emergency-rescue terminal\n\t\t\t// path). For verify-release the outcome is \"funds back\n\t\t\t// at the payer\" — same as a plain refund_lock.\n\t\t\treturn 'released_refunded';\n\t\tcase 'release_lock':\n\t\tcase 'unknown':\n\t\t\t// `unknown` falls back to `released_clean` so older\n\t\t\t// scripts that asserted on `released_clean` for any\n\t\t\t// successful close continue to pass — they only see\n\t\t\t// the new specific statuses if the log parse succeeds.\n\t\t\treturn 'released_clean';\n\t}\n}\n\n// =============================================================================\n// wallet create-lock — build + sign a native-SOL create_lock tx blob\n// =============================================================================\n\ninterface CreateLockOptions {\n\tserver?: string;\n\tfromDid?: string;\n\tdelegationId: string;\n\trecipientPubkey: string;\n\tamountLamports: string;\n\tconditionHash: string;\n\texpirySecs: string;\n\trpcUrl?: string;\n\tprogramId?: string;\n\tclusterTag?: string;\n\t/**\n\t * Optional `--contract-id <uuid>`. When given,\n\t * `preflightLockCurrency` looks up the contract directly instead\n\t * of walking relationships + delegations to find the link. This\n\t * is the only way the pre-flight can fire on the canonical\n\t * pre-offer flow — the delegation row doesn't yet exist on the\n\t * server when `create-lock` runs, so the delegation-based path\n\t * silently skips. Without --contract-id, the pre-flight still\n\t * works for re-runs and post-offer staging where the delegation\n\t * row IS already visible.\n\t */\n\tcontractId?: string;\n\t/**\n\t * Accepted as a no-op alias for symmetry with sister wallet /\n\t * register subcommands that take `--json`. The command already\n\t * emits JSON unconditionally — output is the `CreateLockOutput`\n\t * shape no matter what — so this flag has no behavioural effect.\n\t * Without the alias, operators copy-pasting `--json` from\n\t * `register --json` / `verify-release --json` / `derive-pdas\n\t * --json` get a confusing `unknown option` error.\n\t */\n\tjson?: boolean;\n}\n\nfunction registerCreateLock(cmd: Command): void {\n\tcmd.command('create-lock')\n\t\t.description(\n\t\t\t\"Build + sign a native-SOL create_lock Solana tx; output JSON ready for attachments.escrow_lock. This command does NOT submit the tx to chain — it only signs the blob locally. The actual on-chain submission happens inside `heyarp delegation offer --escrow-lock-from-file <path>` (the server's escrow worker picks up the signed blob from the offer envelope's attachments and posts it). Watch for the `lock_id` appearing on-chain only AFTER `delegation offer` runs, not after this command.\",\n\t\t)\n\t\t.option('--server <url>', 'Override server URL for sender-key resolution')\n\t\t.option('--from-did <did>', 'Sender DID (= payer of the lock). Required when more than one agent on the host.')\n\t\t.requiredOption('--delegation-id <id>', 'Delegation UUID (drives the lock_id derivation)')\n\t\t.requiredOption('--recipient-pubkey <base58>', \"Payee Solana pubkey (recipient agent's settlement_pubkey)\")\n\t\t.requiredOption('--amount-lamports <int>', 'Lock amount in lamports (1 SOL = 1_000_000_000)')\n\t\t.requiredOption('--condition-hash <hex>', '32-byte hex condition_hash from deriveConditionHash')\n\t\t.requiredOption('--expiry-secs <int>', 'Lock expiry as unix seconds')\n\t\t.option(\n\t\t\t'--rpc-url <url>',\n\t\t\t`Solana RPC URL. Default precedence: --rpc-url flag > ARP_ESCROW_RPC_URL env > \\`heyarp config set rpcUrl\\` > built-in fallback (${FALLBACK_RPC_URL}).`,\n\t\t)\n\t\t.option(\n\t\t\t'--program-id <pubkey>',\n\t\t\t`Deployed ARP escrow program id. Default precedence: --program-id flag > ARP_ESCROW_PROGRAM_ID env > GET /v1/escrow/protocol-fee (auto-discover) > hardcoded fallback (${FALLBACK_PROGRAM_ID}, almost certainly wrong outside the canonical placeholder deploy).`,\n\t\t)\n\t\t.option('--cluster-tag <int>', 'Cluster tag (0 = devnet, 1 = mainnet; default 0). Determines the CAIP-2 cluster id baked into asset_id.')\n\t\t.option(\n\t\t\t'--contract-id <uuid>',\n\t\t\t'When set, the currency pre-flight looks up THIS contract directly to verify it is native-SOL priced — bypassing the delegation lookup. Use this for the canonical pre-offer flow (create-lock → delegation offer): the delegation row does not yet exist on the server at create-lock time, so the default delegation-based pre-flight silently skips, leaving the USDC/SPL footgun uncaught. Pass --contract-id to plug that hole.',\n\t\t)\n\t\t.option('--json', 'Accepted for symmetry with sister --json flags but is a NO-OP — `create-lock` already emits JSON unconditionally.', false)\n\t\t.action(async (opts: CreateLockOptions) => {\n\t\t\ttry {\n\t\t\t\tconst out = await createLockHandler(opts);\n\t\t\t\tconsole.log(JSON.stringify(out, null, 2));\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error((err as Error).message);\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t});\n}\n\n/**\n * Output shape of `heyarp wallet create-lock`. Designed to feed\n * directly into `heyarp delegation offer --escrow-lock-from-file`.\n *\n * Schema crosswalk: this output's `lock_id` is the SAME VALUE as\n * `wallet derive-pdas` output's `lock_id_hex` (both are the 32-byte\n * hex `sha256(\"arp-lock-v1\" || del_id_bytes16)`). create-lock keeps\n * the un-suffixed name because it's part of the wire-compatible\n * `attachments.escrow_lock` payload the server consumes; derive-pdas\n * uses the `_hex` suffix to disambiguate from the lock_id BYTES at\n * the SDK level (`deriveLockId(id) → Uint8Array`).\n */\ninterface CreateLockOutput {\n\tsigned_tx_blob: string;\n\tlock_id: string;\n\tamount: string;\n\tasset_id: string;\n\texpiry: number;\n\t// Persisted so the downstream `delegation offer --escrow-lock-from-file`\n\t// can auto-align `body.content.delegation_id` with the id that drove\n\t// `deriveLockId(...)`. Without this, the offer either rejects with\n\t// ESC_LOCK_ID_MISMATCH (post-commit, eats a sender_sequence) or forces\n\t// the operator to keep the id in their head and pass it twice.\n\tdelegation_id: string;\n\t// Persist the on-chain escrow program id the signed_tx_blob\n\t// targets. Downstream `delegation offer` reads this and pre-flights\n\t// it against its own resolved program-id; mismatch throws BEFORE\n\t// the envelope ships (avoids the pattern where `delegation offer`\n\t// printed \"Delivered.\" alongside a stderr\n\t// ESC_LOCK_TX_PROGRAM_ID_MISMATCH but exited 0, leaving the\n\t// delegation to fail invisibly on chain 12-26s later).\n\tprogram_id: string;\n}\n\n/**\n * Best-effort pre-flight that asserts the delegation's contract is\n * priced in NATIVE SOL before we sign a native-SOL `create_lock` tx\n * blob. Any of:\n * - server unreachable\n * - signer-key reconstruction fails\n * - the delegation doesn't appear in any of the operator's\n * relationships yet (typical pre-offer flow)\n * - the contract row isn't visible\n * - `rateCurrency.assetId` is missing on the contract\n * ... all SKIP the check silently. We only throw when we have\n * positively-confirmed bad currency.\n *\n * Exported for unit-test coverage.\n *\n * Why \"endsWith('/slip44:501')\" instead of a full CAIP-19 parse:\n * native SOL is the only `slip44:501` asset reference in V1, and\n * the suffix anchor lets the check work across any Solana cluster\n * id (mainnet/devnet/localnet) without an exhaustive cluster list.\n */\nexport async function preflightLockCurrency(api: ArpApiClient, agent: AgentLocalState, normalisedDelegationId: string, contractId?: string): Promise<void> {\n\t// Bound the ENTIRE pre-flight (listRelationships +\n\t// per-relationship listDelegations + listContracts) under a single\n\t// 3-second timeout. A server that responds fast to\n\t// listRelationships but blackholes listDelegations would otherwise\n\t// stall `create-lock` indefinitely. We race the whole pre-flight\n\t// against a wall clock — if it doesn't finish in time, silently\n\t// skip (best-effort).\n\t//\n\t// We pair the race with an AbortController so the underlying\n\t// fetch socket actually closes when the timeout fires. Without\n\t// abort propagation, the wrapper promise would resolve but the\n\t// in-flight `fetch` would stay alive, keeping the Node event loop\n\t// running and the CLI process hanging indefinitely after the\n\t// command's real work is done. The signal is plumbed through\n\t// `signedRequest` → `request` → `fetch`; AbortError surfaces as a\n\t// rejected promise that the outer catch swallows (best-effort).\n\t//\n\t// Re-throw is gated on the marker `NF-R13-05` so only the\n\t// legitimate confirmed-currency-mismatch path bubbles up; the\n\t// inner function's network / timeout failures swallow silently.\n\tconst PREFLIGHT_TIMEOUT_MS = 3_000;\n\tconst controller = new AbortController();\n\tlet timeoutHandle: ReturnType<typeof setTimeout> | undefined;\n\ttry {\n\t\t// Race the inner pre-flight against a wall-clock timeout.\n\t\t// AbortController.abort() tells real fetch sockets to close\n\t\t// (so the Node event loop can exit), AND the Promise.race\n\t\t// guarantees the outer resolves even if the inner ignores\n\t\t// the signal (e.g., test mocks with never-resolving\n\t\t// promises). Defense-in-depth: either path completes the\n\t\t// race.\n\t\tawait Promise.race([\n\t\t\tpreflightLockCurrencyInner(api, agent, normalisedDelegationId, controller.signal, contractId),\n\t\t\tnew Promise<void>((_, reject) => {\n\t\t\t\ttimeoutHandle = setTimeout(() => {\n\t\t\t\t\tcontroller.abort();\n\t\t\t\t\treject(new Error('preflightLockCurrency: aggregate timeout — skipping'));\n\t\t\t\t}, PREFLIGHT_TIMEOUT_MS);\n\t\t\t}),\n\t\t]);\n\t} catch (err) {\n\t\t// Only the explicit currency-mismatch error (carries the\n\t\t// marker) is a real result; timeouts, network\n\t\t// errors, AbortError, and lookup failures all swallow per\n\t\t// best-effort contract.\n\t\tif (err instanceof Error && err.message.includes('NF-R13-05')) throw err;\n\t\t// Otherwise silent skip.\n\t} finally {\n\t\tif (timeoutHandle !== undefined) clearTimeout(timeoutHandle);\n\t}\n}\n\nasync function preflightLockCurrencyInner(api: ArpApiClient, agent: AgentLocalState, normalisedDelegationId: string, signal: AbortSignal, contractId?: string): Promise<void> {\n\t// `normaliseDelegationId` always returns the SDK form\n\t// `del_<uuid>` for downstream `deriveLockId`, but\n\t// `DelegationPublic.delegationId` from the API is the bare UUID.\n\t// A naive `d.delegationId === normalisedDelegationId` therefore\n\t// never matches on real CLI invocations and silently skips the\n\t// entire\n\t// pre-flight. Strip `del_` here to get the bare-UUID form the\n\t// API uses.\n\tconst bareDelegationId = normalisedDelegationId.startsWith('del_') ? normalisedDelegationId.slice('del_'.length) : normalisedDelegationId;\n\n\tlet signer: ReturnType<typeof makeSigner>;\n\ttry {\n\t\tsigner = makeSigner(agent);\n\t} catch {\n\t\t// Couldn't reconstruct the signing key (e.g., separated soft\n\t\t// keystore not unlocked). Skip — the lock build path may\n\t\t// still succeed offline.\n\t\treturn;\n\t}\n\tconst RELATIONSHIPS_PAGE_CAP = 100;\n\tlet rels: RelationshipPublic[];\n\ttry {\n\t\trels = await api.listRelationships(agent.did, signer, { limit: RELATIONSHIPS_PAGE_CAP }, signal);\n\t} catch {\n\t\treturn; // server unreachable / auth issue / abort → silent skip\n\t}\n\tfor (const r of rels) {\n\t\t// If the caller passed `--contract-id`, ADDITIONALLY check the\n\t\t// contract directly — this covers the PRE-OFFER flow where\n\t\t// the delegation doesn't yet exist on the server. This branch\n\t\t// must AUGMENT the existing delegation-based check, not\n\t\t// replace it. A stale/wrong --contract-id must not short-\n\t\t// circuit the delegation check, and a native-SOL contract\n\t\t// must not skip the delegation's own `currency` inspection.\n\t\t// So the contract-direct path only throws on CONFIRMED bad\n\t\t// currency or returns SILENTLY when the direct lookup is\n\t\t// inconclusive (contract not in this relationship, legacy\n\t\t// minimal row), letting control fall through to the\n\t\t// delegation-based check.\n\t\tif (contractId !== undefined) {\n\t\t\tlet activeContracts: ContractPublic[];\n\t\t\ttry {\n\t\t\t\tactiveContracts = await fetchAllPages<ContractPublic>((after) => api.listContracts(r.relationshipId, signer, { limit: 100, state: 'active', ...(after ? { after } : {}) }, signal));\n\t\t\t} catch {\n\t\t\t\t// Couldn't load contracts on this relationship —\n\t\t\t\t// fall through to delegation-based check (don't\n\t\t\t\t// skip the whole relationship since the delegation\n\t\t\t\t// might still be visible).\n\t\t\t\tactiveContracts = [];\n\t\t\t}\n\t\t\tconst directContract = activeContracts.find((c) => c.contractId === contractId);\n\t\t\tif (directContract !== undefined) {\n\t\t\t\tconst directAssetId = directContract.rateCurrency?.assetId;\n\t\t\t\t// Only THROW on confirmed-non-native; on missing /\n\t\t\t\t// native / inconclusive, fall through so the\n\t\t\t\t// delegation-based path below can still catch a\n\t\t\t\t// non-native delegation.currency.\n\t\t\t\tif (typeof directAssetId === 'string' && !directAssetId.endsWith('/slip44:501')) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`wallet create-lock pre-flight (NF-R13-05): contract ${contractId} is priced in '${directAssetId}' (NOT native SOL). ` +\n\t\t\t\t\t\t\t`This command only builds native-SOL locks (isNativeSol=1, no SPL Token-2022 path) — the resulting tx blob would be rejected server-side with ESC_LOCK_CURRENCY_MISMATCH or ` +\n\t\t\t\t\t\t\t`ESC_LOCK_AMOUNT_DELEGATION_MISMATCH after \\`delegation offer\\` ships it. Use a SOL-priced contract (e.g. \\`--rate-currency 'SOL:solana-mainnet'\\` on \\`contract propose\\`) ` +\n\t\t\t\t\t\t\t`or wait for SPL-token lock support to land.`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tlet dels: DelegationPublic[];\n\t\ttry {\n\t\t\tdels = await fetchAllPages<DelegationPublic>((after) => api.listDelegations(r.relationshipId, signer, { limit: 100, ...(after ? { after } : {}) }, signal));\n\t\t} catch {\n\t\t\tcontinue; // skip this relationship; try the next one (or abort propagates up)\n\t\t}\n\t\tconst match = dels.find((d) => d.delegationId === bareDelegationId);\n\t\tif (!match) continue;\n\t\t// Found the delegation. Look up its contract — pin `state:\n\t\t// 'active'` so we don't read a stale REPLACED version after\n\t\t// a counter-offer. listContracts returns ALL versions\n\t\t// chronologically (oldest-first), so a plain `find` would\n\t\t// pick the oldest REPLACED row if the contract was countered\n\t\t// with a currency change.\n\t\t//\n\t\t// When listContracts rejects after listDelegations succeeded,\n\t\t// we still have `match.currency` — that ALONE is enough to\n\t\t// know whether a native-SOL lock will be accepted. Treat a\n\t\t// failing/degraded listContracts as if it returned [] —\n\t\t// `contract` will be undefined, but the downstream check\n\t\t// reads BOTH contract.rateCurrency AND delegation.currency,\n\t\t// so a USDC delegation under a server-degraded contract\n\t\t// lookup still throws.\n\t\tlet contracts: ContractPublic[] = [];\n\t\ttry {\n\t\t\tcontracts = await fetchAllPages<ContractPublic>((after) => api.listContracts(r.relationshipId, signer, { limit: 100, state: 'active', ...(after ? { after } : {}) }, signal));\n\t\t} catch {\n\t\t\t// Leave contracts as [] and fall through — delegation\n\t\t\t// cross-check below can still catch non-native currency.\n\t\t}\n\t\tconst contract = contracts.find((c) => c.contractId === match.contractId);\n\t\t// The server cross-checks the on-chain lock asset against BOTH\n\t\t// the contract row's `rateCurrency` AND the delegation row's\n\t\t// `currency`. Either can independently veto a native-SOL lock.\n\t\t// Reject if EITHER is present and non-native-SOL — don't fall\n\t\t// back to one while ignoring the other. The two fields should\n\t\t// normally agree, but during counter-offer churn or with\n\t\t// legacy / minimal rows they can disagree; the conservative\n\t\t// move is to fail on the first non-native source we see.\n\t\tconst contractAssetId = contract?.rateCurrency?.assetId;\n\t\tconst delegationAssetId = match.currency?.assetId;\n\t\t// Handle null AND undefined uniformly. A legacy server row\n\t\t// can return `assetId: null` inside an otherwise-present\n\t\t// currency object; without this check, the `null.endsWith(...)`\n\t\t// below would throw a TypeError and abort `wallet create-lock`\n\t\t// entirely — defeating the best-effort contract.\n\t\tconst contractAssetIdPresent = typeof contractAssetId === 'string';\n\t\tconst delegationAssetIdPresent = typeof delegationAssetId === 'string';\n\t\tif (!contractAssetIdPresent && !delegationAssetIdPresent) return;\n\t\tconst isContractNonNative = contractAssetIdPresent && !contractAssetId.endsWith('/slip44:501');\n\t\tconst isDelegationNonNative = delegationAssetIdPresent && !delegationAssetId.endsWith('/slip44:501');\n\t\tif (!isContractNonNative && !isDelegationNonNative) return; // both native SOL (or only the absent / null one)\n\t\tconst offendingAssetId = isContractNonNative ? contractAssetId : delegationAssetId;\n\t\tconst sourceLabel = isContractNonNative ? `contract ${match.contractId}` : `delegation ${normalisedDelegationId}`;\n\t\tthrow new Error(\n\t\t\t`wallet create-lock pre-flight (NF-R13-05): ${sourceLabel} is priced in '${offendingAssetId}' (NOT native SOL). ` +\n\t\t\t\t`This command only builds native-SOL locks (isNativeSol=1, no SPL Token-2022 path) — the resulting tx blob would be rejected server-side with ESC_LOCK_CURRENCY_MISMATCH or ` +\n\t\t\t\t`ESC_LOCK_AMOUNT_DELEGATION_MISMATCH after \\`delegation offer\\` ships it. Use a SOL-priced contract (e.g. \\`--rate-currency 'SOL:solana-mainnet'\\` on \\`contract propose\\`) ` +\n\t\t\t\t`or wait for SPL-token lock support to land.`,\n\t\t);\n\t}\n\t// Delegation not present in any of the operator's relationships\n\t// typical pre-offer flow where create-lock pre-stages the blob.\n\t// Skip silently.\n}\n\nexport async function createLockHandler(opts: CreateLockOptions): Promise<CreateLockOutput> {\n\tconst agent = resolveSenderAgent('wallet create-lock', opts.server, opts.fromDid);\n\tconst payerKp = keypairFromAgent(agent);\n\t// Accept BOTH `del_<uuid>` and bare `<uuid>` for --delegation-id.\n\t// The SDK's `delegationIdToBytes16` requires the `del_` prefix,\n\t// but `heyarp delegation offer` prints the bare UUID in its\n\t// banner, so it's easy to copy-paste the bare form into wallet\n\t// commands. Normalising at the CLI layer keeps the SDK\n\t// strict-validation contract intact while removing the\n\t// cross-command inconsistency.\n\tconst normalisedDelegationId = normaliseDelegationId(opts.delegationId);\n\tconst payee = parsePubkey(opts.recipientPubkey, '--recipient-pubkey');\n\tconst amountLamports = parseU64(opts.amountLamports, '--amount-lamports');\n\tconst conditionHash = parseHex32(opts.conditionHash, '--condition-hash');\n\tconst expiry = parseU64(opts.expirySecs, '--expiry-secs');\n\t// Program-id precedence chain (flag > env > server probe > fallback).\n\tconst api = new ArpApiClient(opts.server);\n\n\t// Currency pre-flight. `create-lock` only builds NATIVE-SOL locks\n\t// (`isNativeSol = 1` in the ix data, no SPL Token-2022 path). If\n\t// the target delegation is attached to a contract priced in USDC\n\t// or another SPL asset, the resulting lock will fail server-side\n\t// with `ESC_LOCK_AMOUNT_DELEGATION_MISMATCH` or\n\t// `ESC_LOCK_CURRENCY_MISMATCH` AFTER the operator already paid the\n\t// tx fee — e.g. `contract propose --rate-currency\n\t// 'USDC:solana-devnet'` silently succeeds, then `create-lock\n\t// --amount-lamports` produces a tx blob that `delegation offer`\n\t// rejects as a currency mismatch one network round-trip later.\n\t//\n\t// Pre-flight: best-effort. If the delegation already exists on\n\t// chain (it usually does — operators run create-lock AFTER the\n\t// delegation offer), look up its contract and verify the\n\t// currency is native SOL. Throw before signing the tx blob when\n\t// we have CONFIRMED bad currency. Skip silently on any lookup\n\t// failure (delegation not found yet, server unreachable, etc.) —\n\t// this preserves the offline-friendly contract of create-lock\n\t// for callers who pre-stage locks before sending the offer.\n\t//\n\t// When the operator passed `--program-id` (or set\n\t// ARP_ESCROW_PROGRAM_ID), they've opted into an OFFLINE-friendly\n\t// path — the existing `resolveProgramId` avoids the server probe\n\t// in that case. Skip pre-flight here too so a blackholed ARP\n\t// server can't stall the command (the fetch client has no\n\t// timeout). The currency check is a best-effort safety net, not\n\t// a hard requirement.\n\t// Validate --contract-id shape BEFORE the pre-flight. Raw user\n\t// input could be:\n\t// - mistyped (would silently fail to find a matching row)\n\t// - prefixed (`evt_<uuid>`, `del_<uuid>`)\n\t// - uppercase (server stores canonical lowercase)\n\t// Without validation the pre-flight silently no-ops on the\n\t// caller's explicit safety request. Use `sharedRequireUuid` for\n\t// hint-rich error + normalise to lowercase.\n\tlet normalisedContractId: string | undefined;\n\tif (typeof opts.contractId === 'string' && opts.contractId !== '') {\n\t\tsharedRequireUuid('wallet create-lock', opts.contractId, '--contract-id');\n\t\tnormalisedContractId = opts.contractId.toLowerCase();\n\t}\n\tconst offlineMode = (typeof opts.programId === 'string' && opts.programId !== '') || (typeof process.env.ARP_ESCROW_PROGRAM_ID === 'string' && process.env.ARP_ESCROW_PROGRAM_ID !== '');\n\t// When the operator explicitly passed `--contract-id`, they've\n\t// ASKED for the currency safety check. Run the pre-flight\n\t// regardless of offline mode — the offline-mode skip is about\n\t// \"don't phone home without explicit request\", but\n\t// `--contract-id` IS an explicit request. Otherwise\n\t// `wallet create-lock --contract-id <USDC contract>\n\t// --program-id <pk>` would still silently sign a native-SOL lock\n\t// and fail at `delegation offer` time, defeating the whole point\n\t// of the flag.\n\tconst operatorExplicitlyRequestedPreflight = normalisedContractId !== undefined;\n\tif (!offlineMode || operatorExplicitlyRequestedPreflight) {\n\t\tawait preflightLockCurrency(api, agent, normalisedDelegationId, normalisedContractId);\n\t}\n\tconst programId = new PublicKey(await resolveProgramId(api, opts));\n\tconst rpcUrl = resolveRpcUrl(opts);\n\tconst clusterTag = opts.clusterTag !== undefined ? Number.parseInt(opts.clusterTag, 10) : 0;\n\tif (clusterTag !== 0 && clusterTag !== 1) {\n\t\tthrow new Error(`--cluster-tag must be 0 (devnet) or 1 (mainnet) (got ${clusterTag})`);\n\t}\n\tconst clusterCaip2 = clusterTag === 1 ? SOLANA_CLUSTER_IDS['solana-mainnet'] : SOLANA_CLUSTER_IDS['solana-devnet'];\n\n\tconst lockIdBytes = deriveLockId(normalisedDelegationId);\n\tconst lockIdSeed = Buffer.from(lockIdBytes);\n\n\t// PDAs derived against the new contract. The on-chain ix reads\n\t// bumps from `ctx.bumps`, so bumps no longer travel in args — we\n\t// just need the PDA addresses.\n\tconst [configPda] = PublicKey.findProgramAddressSync([Buffer.from('config')], programId);\n\tconst [lockPda] = PublicKey.findProgramAddressSync([Buffer.from('lock'), lockIdSeed], programId);\n\tconst [escrowPda] = PublicKey.findProgramAddressSync([Buffer.from('escrow'), lockIdSeed], programId);\n\t// Anchor's #[event_cpi] macro auto-injects two trailing accounts\n\t// (event_authority + program) on every emit-instruction.\n\tconst [eventAuthorityPda] = PublicKey.findProgramAddressSync([Buffer.from('__event_authority')], programId);\n\n\t// New 88-byte ix data: disc(8) + lock_id(32) + amount(u64 LE)\n\t// + condition_hash(32) + expiry(u64 LE). No is_native_sol bool,\n\t// no bumps — see SDK `buildCreateLockIxData`.\n\tconst ixData = Buffer.alloc(88);\n\tlet off = 0;\n\tBuffer.from(CREATE_LOCK_DISCRIMINATOR).copy(ixData, off);\n\toff += 8;\n\tlockIdSeed.copy(ixData, off);\n\toff += 32;\n\tixData.writeBigUInt64LE(amountLamports, off);\n\toff += 8;\n\tBuffer.from(conditionHash).copy(ixData, off);\n\toff += 32;\n\tixData.writeBigUInt64LE(expiry, off);\n\toff += 8;\n\tif (off !== 88) throw new Error(`create_lock ix data layout drift: ${off} != 88`);\n\n\t// Account context — 11 slots — matches the on-chain `CreateLock`\n\t// struct in\n\t// `apps/arp-solana-contract/programs/arp-solana-contract/src/instructions/create_lock.rs`\n\t// plus the two trailing accounts that `#[event_cpi]` appends:\n\t// 0 payer (signer + writable)\n\t// 1 payee (system account, read)\n\t// 2 config (PDA `[b\"config\"]`, read)\n\t// 3 lock (PDA `[b\"lock\", lock_id]`, writable, init)\n\t// 4 mint (read; `Pubkey::default()` for native SOL)\n\t// 5 payer_token_account (writable; placeholder for native SOL —\n\t// contract ignores the slot on the\n\t// native transfer branch)\n\t// 6 escrow_account (PDA `[b\"escrow\", lock_id]`, writable, init)\n\t// 7 system_program\n\t// 8 token_program (SPL Token — required by Anchor's\n\t// Interface<TokenInterface>, even for native;\n\t// never System Program in this slot)\n\t// 9 event_authority (PDA `[b\"__event_authority\"]`, read)\n\t// 10 program (read; self-ref)\n\tconst ix = new TransactionInstruction({\n\t\tprogramId,\n\t\tkeys: [\n\t\t\t{ pubkey: payerKp.publicKey, isSigner: true, isWritable: true },\n\t\t\t{ pubkey: payee, isSigner: false, isWritable: false },\n\t\t\t{ pubkey: configPda, isSigner: false, isWritable: false },\n\t\t\t{ pubkey: lockPda, isSigner: false, isWritable: true },\n\t\t\t// Native-SOL mint sentinel.\n\t\t\t{ pubkey: NATIVE_SOL_MINT, isSigner: false, isWritable: false },\n\t\t\t// payer_token_account placeholder — contract ignores it\n\t\t\t// on native transfers, but it must be a valid writable\n\t\t\t// account meta.\n\t\t\t{ pubkey: payerKp.publicKey, isSigner: false, isWritable: true },\n\t\t\t{ pubkey: escrowPda, isSigner: false, isWritable: true },\n\t\t\t{ pubkey: SystemProgram.programId, isSigner: false, isWritable: false },\n\t\t\t// token_program slot — Anchor's Interface<TokenInterface>\n\t\t\t// rejects System Program here even for native flows.\n\t\t\t// Use legacy SPL Token; the contract ignores the slot on\n\t\t\t// the native transfer path.\n\t\t\t{ pubkey: SPL_TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },\n\t\t\t{ pubkey: eventAuthorityPda, isSigner: false, isWritable: false },\n\t\t\t{ pubkey: programId, isSigner: false, isWritable: false },\n\t\t],\n\t\tdata: ixData,\n\t});\n\n\tconst tx = new Transaction().add(ix);\n\ttx.feePayer = payerKp.publicKey;\n\n\t// Fetch a recent blockhash so the tx is signable + acceptable on\n\t// the cluster. Without `recentBlockhash` Transaction.serialize()\n\t// throws, and the tx wouldn't be valid for submission anyway.\n\tconst conn = new SolanaConnection(rpcUrl, 'confirmed');\n\tconst { blockhash } = await conn.getLatestBlockhash('confirmed');\n\ttx.recentBlockhash = blockhash;\n\ttx.sign(payerKp);\n\n\tconst blob = tx.serialize({ requireAllSignatures: true, verifySignatures: true });\n\treturn {\n\t\tsigned_tx_blob: blob.toString('base64'),\n\t\tlock_id: Buffer.from(lockIdBytes).toString('hex'),\n\t\tamount: amountLamports.toString(),\n\t\t// CAIP-19 for native SOL on the configured cluster. The\n\t\t// server's Caip19ResolverService cross-checks this prefix\n\t\t// against ARP_ESCROW_CLUSTER_TAG; baking in the wrong\n\t\t// genesis-hash here would surface as ESC_LOCK_MINT_WRONG_CLUSTER.\n\t\tasset_id: `solana:${clusterCaip2}/slip44:501`,\n\t\texpiry: Number(expiry),\n\t\t// Persist the BARE UUID form. The consumer is\n\t\t// `delegation offer --escrow-lock-from-file`, which validates\n\t\t// this field with a bare-UUID regex (the wire form for\n\t\t// `body.content.delegation_id`). The `del_<uuid>` prefix is an\n\t\t// SDK-internal byte-encoding marker — not the wire-form. Keeping\n\t\t// the file's value as bare matches the existing consumer\n\t\t// contract; `wallet sign-settlement-release` normalises both\n\t\t// shapes at its CLI boundary, so this is symmetrical.\n\t\tdelegation_id: normalisedDelegationId.slice('del_'.length),\n\t\t// Record the program id the create_lock ix was built against.\n\t\t// `delegation offer` cross-checks this pre-flight so a stale\n\t\t// ESCRoW... fallback lock doesn't ship silently.\n\t\tprogram_id: programId.toBase58(),\n\t};\n}\n\n// =============================================================================\n// wallet sign-settlement-release — sign release / partial digest\n// =============================================================================\n\ninterface SignSettlementOptions {\n\tserver?: string;\n\tfromDid?: string;\n\tdelegationId: string;\n\tpayerSettlementPubkey: string;\n\tpayeeSettlementPubkey: string;\n\tmintPubkey: string;\n\tlockAmount: string;\n\tconditionHash: string;\n\treceiptEventHash: string;\n\tdeliverableHash: string;\n\texpiresAt: string;\n\tfeeBpsAtLock?: string;\n\tfeeRecipientAtLock?: string;\n\tclusterTag?: string;\n\tprogramId?: string;\n\tpartialPayeeAmount?: string;\n\twriteTo?: string;\n}\n\nfunction registerSignSettlement(cmd: Command): void {\n\tcmd.command('sign-settlement-release')\n\t\t.description('Sign an ARP-SOLANA-RELEASE-v1.5 or -PARTIAL-RELEASE-v1.5 digest with the agent settlement key')\n\t\t.option('--server <url>', 'Override server URL for sender-key resolution')\n\t\t.option('--from-did <did>', 'Sender DID (= signing party — payer or payee)')\n\t\t.requiredOption('--delegation-id <id>', 'Delegation UUID')\n\t\t.requiredOption('--payer-settlement-pubkey <base58>', 'Payer settlement pubkey')\n\t\t.requiredOption('--payee-settlement-pubkey <base58>', 'Payee settlement pubkey')\n\t\t.requiredOption('--mint-pubkey <base58>', 'Lock mint (NATIVE_SOL_MINT for native = 1...1)')\n\t\t.requiredOption('--lock-amount <int>', 'Lock amount in base units')\n\t\t.requiredOption('--condition-hash <hex>', '32-byte hex condition_hash')\n\t\t.requiredOption('--receipt-event-hash <sha256:hex>', 'Receipt event hash (sha256:64-hex)')\n\t\t.requiredOption('--deliverable-hash <sha256:hex>', 'Work-response canonical sha256 (sha256:64-hex)')\n\t\t.requiredOption('--expires-at <unix>', 'Settlement digest expires_at (unix seconds)')\n\t\t.option('--fee-bps-at-lock <int>', 'fee_bps_at_lock denormalised on the Lock (default 0)')\n\t\t.option('--fee-recipient-at-lock <base58>', 'fee_recipient_at_lock denormalised on the Lock (default 1...1)')\n\t\t.option('--cluster-tag <int>', 'Cluster tag (0 = devnet, 1 = mainnet; default 0)')\n\t\t.option(\n\t\t\t'--program-id <pubkey>',\n\t\t\t`Deployed ARP escrow program id. Default precedence: --program-id flag > ARP_ESCROW_PROGRAM_ID env > GET /v1/escrow/protocol-fee (auto-discover) > hardcoded fallback (${FALLBACK_PROGRAM_ID}).`,\n\t\t)\n\t\t.option('--partial-payee-amount <int>', 'If set, signs ARP-SOLANA-PARTIAL-RELEASE-v1.5 with this payee_amount; otherwise full release')\n\t\t.option(\n\t\t\t'--write-to <path>',\n\t\t\t// Persist the signed `{settlement_pubkey, sig, digest_hex,\n\t\t\t// purpose}` blob to a canonical on-disk location so the\n\t\t\t// cross-party handoff is in-band-with-respect-to-the-filesystem\n\t\t\t// instead of \"paste the JSON over Slack\". `heyarp receipt\n\t\t\t// cosign --payee-sig-from-file` / `--payer-sig-from-file`\n\t\t\t// consumes the same shape. The file is force-chmod'd to\n\t\t\t// 0o600 (sig is settlement-material — anyone who reads it\n\t\t\t// can co-author a release tx with the matching counterparty\n\t\t\t// sig). chmod runs even if the path already existed with\n\t\t\t// looser perms.\n\t\t\t'Persist the signed JSON `{settlement_pubkey, sig, digest_hex, purpose}` to this path and chmod 0o600 (sig is settlement-material). The counterparty consumes it via `heyarp receipt cosign --payer-sig-from-file` / `--payee-sig-from-file`. Output still echoes to stdout.',\n\t\t)\n\t\t.action(async (opts: SignSettlementOptions) => {\n\t\t\ttry {\n\t\t\t\tconst out = await signSettlementHandler(opts);\n\t\t\t\tconsole.log(JSON.stringify(out, null, 2));\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error((err as Error).message);\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t});\n}\n\ninterface SignSettlementOutput {\n\tsettlement_pubkey: string;\n\tsig: string;\n\tdigest_hex: string;\n\tpurpose: string;\n}\n\nexport async function signSettlementHandler(opts: SignSettlementOptions): Promise<SignSettlementOutput> {\n\tconst agent = resolveSenderAgent('wallet sign-settlement-release', opts.server, opts.fromDid);\n\tconst signerKp = keypairFromAgent(agent);\n\n\t// Same program-id precedence chain as createLockHandler.\n\tconst api = new ArpApiClient(opts.server);\n\tconst programId = new PublicKey(await resolveProgramId(api, opts));\n\tconst clusterTag = opts.clusterTag !== undefined ? Number.parseInt(opts.clusterTag, 10) : 0;\n\tif (clusterTag !== 0 && clusterTag !== 1) {\n\t\tthrow new Error(`--cluster-tag must be 0 or 1 (got ${clusterTag})`);\n\t}\n\tconst payerPubkey = parsePubkey(opts.payerSettlementPubkey, '--payer-settlement-pubkey');\n\tconst payeePubkey = parsePubkey(opts.payeeSettlementPubkey, '--payee-settlement-pubkey');\n\tconst mint = parsePubkey(opts.mintPubkey, '--mint-pubkey');\n\n\t// Same delegation-id normalisation as createLockHandler.\n\tconst normalisedDelegationId = normaliseDelegationId(opts.delegationId);\n\tconst lockIdBytes = deriveLockId(normalisedDelegationId);\n\tconst conditionHash = parseHex32(opts.conditionHash, '--condition-hash');\n\tconst deliverableHash = parseSha256(opts.deliverableHash, '--deliverable-hash');\n\tconst receiptEventHash = parseSha256(opts.receiptEventHash, '--receipt-event-hash');\n\tconst expiresAt = parseU64(opts.expiresAt, '--expires-at');\n\tconst feeBpsAtLock = opts.feeBpsAtLock !== undefined ? Number.parseInt(opts.feeBpsAtLock, 10) : 0;\n\tif (!Number.isInteger(feeBpsAtLock) || feeBpsAtLock < 0 || feeBpsAtLock > 1000) {\n\t\tthrow new Error(`--fee-bps-at-lock must be 0..1000 (got ${feeBpsAtLock})`);\n\t}\n\tconst feeRecipientAtLock = opts.feeRecipientAtLock ? parsePubkey(opts.feeRecipientAtLock, '--fee-recipient-at-lock') : NATIVE_SOL_MINT;\n\tconst lockAmount = parseU64(opts.lockAmount, '--lock-amount');\n\n\tconst base: ReleaseDigestInput = {\n\t\tclusterTag: clusterTag as 0 | 1,\n\t\tprogramId: programId.toBytes(),\n\t\tlockId: lockIdBytes,\n\t\tpayerSettlementPubkey: payerPubkey.toBytes(),\n\t\tpayeeSettlementPubkey: payeePubkey.toBytes(),\n\t\tmint: mint.toBytes(),\n\t\tamount: lockAmount,\n\t\tconditionHash,\n\t\tdelegationId: normalisedDelegationId,\n\t\treceiptEventHash,\n\t\tdeliverableHash,\n\t\texpiresAt,\n\t\tfeeBpsAtLock,\n\t\tfeeRecipientAtLock: feeRecipientAtLock.toBytes(),\n\t};\n\n\tlet digest: Uint8Array;\n\tlet purpose: string;\n\tif (opts.partialPayeeAmount !== undefined) {\n\t\tconst payeeAmount = parseU64(opts.partialPayeeAmount, '--partial-payee-amount');\n\t\tdigest = buildPartialReleaseDigest({ ...base, payeeAmount });\n\t\tpurpose = 'ARP-SOLANA-PARTIAL-RELEASE-v1.5';\n\t} else {\n\t\tdigest = buildReleaseDigest(base);\n\t\tpurpose = 'ARP-SOLANA-RELEASE-v1.5';\n\t}\n\n\tconst sigBytes = ed25519Sign(digest, signerKp.secretKey.slice(0, 32));\n\t// IMPORTANT: settlement_signatures.{payer,payee}.sig is RAW base64\n\t// (no `ed25519:` prefix). The server's\n\t// ReceiptCosignValidatorService.parseBase64Sig() decodes 64 bytes\n\t// directly without prefix stripping. Other ARP sigs (envelope\n\t// sender_signature, co_signature.sig) DO carry the prefix —\n\t// this is a deliberate inconsistency at the settlement boundary\n\t// because that block is consumed by Solana Ed25519Program at\n\t// release-tx-builder time, where prefixed strings would break.\n\tconst out: SignSettlementOutput = {\n\t\tsettlement_pubkey: signerKp.publicKey.toBase58(),\n\t\tsig: bytesToBase64(sigBytes),\n\t\tdigest_hex: Buffer.from(digest).toString('hex'),\n\t\tpurpose,\n\t};\n\n\t// Persist the JSON to the operator-chosen path for the cosign-side\n\t// `--payer-sig-from-file` / `--payee-sig-from-file` consumers.\n\t// Mode 0o600 — `writeFileSync({ mode })` only takes effect on file\n\t// CREATION (per Node docs), so we follow up with an explicit\n\t// `chmodSync` to enforce the documented contract even when the\n\t// path already exists with looser perms (sigs are\n\t// settlement-material; loose perms on a re-used path would leak\n\t// to local group/other).\n\tif (opts.writeTo !== undefined && opts.writeTo !== '') {\n\t\ttry {\n\t\t\twriteFileSync(opts.writeTo, JSON.stringify(out, null, 2), { mode: 0o600 });\n\t\t\tchmodSync(opts.writeTo, 0o600);\n\t\t} catch (err) {\n\t\t\tthrow new Error(`wallet sign-settlement-release: failed to write --write-to '${opts.writeTo}': ${(err as Error).message}`);\n\t\t}\n\t}\n\n\treturn out;\n}\n\n// =============================================================================\n// Helpers\n// =============================================================================\n\n/**\n * Reconstruct a Solana Keypair from the agent's stored settlement key.\n * The settlement secret is stored as a 64-byte base64 (Ed25519 expanded\n * keypair format: 32-byte seed || 32-byte public).\n */\nfunction keypairFromAgent(agent: AgentLocalState): Keypair {\n\tconst stored = base64ToBytes(agent.settlementSecretKeyB64);\n\t// `register` persists the 32-byte Ed25519 seed (matches the\n\t// SDK's `generateKeyPair()` output) — convert to Solana's\n\t// 64-byte expanded form via `Keypair.fromSeed`. As a defensive\n\t// fallback we also accept the 64-byte form in case a future\n\t// state-file migration switches to it.\n\tif (stored.length === 32) {\n\t\treturn Keypair.fromSeed(stored);\n\t}\n\tif (stored.length === 64) {\n\t\treturn Keypair.fromSecretKey(stored);\n\t}\n\tthrow new Error(`agent ${agent.did}: settlementSecretKeyB64 must decode to 32 bytes (Ed25519 seed) or 64 bytes (Solana expanded form); got ${stored.length}`);\n}\n\nfunction parsePubkey(value: string, flag: string): PublicKey {\n\ttry {\n\t\treturn new PublicKey(value);\n\t} catch (err) {\n\t\tthrow new Error(`${flag}: invalid base58 pubkey '${value}': ${(err as Error).message}`);\n\t}\n}\n\nfunction parseU64(value: string, flag: string): bigint {\n\tif (!/^[0-9]+$/.test(value)) {\n\t\tthrow new Error(`${flag} must be a non-negative integer string (got '${value}')`);\n\t}\n\tconst n = BigInt(value);\n\tif (n < 0n || n > 0xffff_ffff_ffff_ffffn) {\n\t\tthrow new Error(`${flag} out of u64 range (got ${value})`);\n\t}\n\treturn n;\n}\n\nfunction parseHex32(value: string, flag: string): Uint8Array {\n\tconst hex = value.startsWith('0x') ? value.slice(2) : value;\n\tif (!/^[0-9a-fA-F]{64}$/.test(hex)) {\n\t\tthrow new Error(`${flag} must be 32-byte hex (64 chars, optional 0x prefix)`);\n\t}\n\treturn hexToBytes(hex.toLowerCase());\n}\n\nfunction parseSha256(value: string, flag: string): Uint8Array {\n\tif (!/^sha256:[0-9a-f]{64}$/.test(value)) {\n\t\tthrow new Error(`${flag} must match 'sha256:<64 lowercase hex>' (got '${value}')`);\n\t}\n\treturn hexToBytes(value.slice('sha256:'.length));\n}\n","import { canonicalSha256Hex } from '@heyanon-arp/sdk';\nimport chalk from 'chalk';\nimport type { Command } from 'commander';\nimport { ApiError, ArpApiClient, type ContractPublic, type DelegationPublic, type ReceiptPublic, type RelationshipPublic, type WorkLogPublic } from '../api';\nimport { resolveSenderAgent } from '../state';\nimport { makeSigner } from './lifecycle';\n\n// `--wait` blocking poll until the FSM hint flips. Replaces the\n// `until heyarp status | grep \"cycle complete\"; do sleep 3; done`\n// idiom operators were writing manually around the one-shot status,\n// with a clean timeout + interval baked in.\nexport interface StatusOptions {\n\tserver?: string;\n\tfromDid?: string;\n\tjson?: boolean;\n\twait?: boolean;\n\twaitTimeout?: string;\n\twaitInterval?: string;\n\t/** Per-tick progress lines during --wait. */\n\twaitVerbose?: boolean;\n\t/**\n\t * Narrower phase-specific exit predicate for scripted flows. When\n\t * set, `--wait` exits on the named entity transition instead of\n\t * the default \"your turn or terminal\" FSM predicate. See\n\t * `UNTIL_PHASES` for the full list.\n\t */\n\tuntil?: string;\n}\n\n/**\n * Closed set of phases that `--until` accepts.\n *\n * FSM-aware \"your turn\" doesn't always match operator scripted\n * idioms — e.g. `until heyarp contracts --json | grep -q\n * '\"state\":\"active\"'; do sleep 10; done` cares about \"contract went\n * active\", not \"now I owe the next move\". `--until` exposes the\n * per-entity transitions directly so scripted flows can wait on\n * the exact state they care about.\n *\n * Categories:\n * - `contract.*` — latestContract state matches\n * - `delegation.*` — latestDelegation state matches\n * - `work.*` — latestWorkLog state matches\n * - `receipt.*` — latestReceipt state matches\n * - `relationship.*` — relationshipState matches\n * - `cycle.complete` — summary.cycleComplete (== receipt cosigned)\n * - `cycle.released` — delegation reached `completed` (on-chain\n * release confirmed; both Lock + Vault PDAs closed). Strictly\n * stronger than `cycle.complete` — wait for THIS when audit\n * needs the on-chain settlement, not just the cosigned\n * receipt.\n */\nexport const UNTIL_PHASES = [\n\t'contract.proposed',\n\t'contract.active',\n\t'contract.replaced',\n\t'contract.declined',\n\t'delegation.proposed',\n\t'delegation.accepted',\n\t'delegation.canceled',\n\t'delegation.declined',\n\t'work.requested',\n\t'work.responded',\n\t'receipt.proposed',\n\t'receipt.cosigned',\n\t'relationship.pending',\n\t'relationship.active',\n\t'relationship.paused',\n\t'relationship.closed',\n\t'cycle.complete',\n\t'cycle.released',\n] as const;\nexport type UntilPhase = (typeof UNTIL_PHASES)[number];\n\n/** Default poll cadence for `--wait`. Tight enough to feel snappy on a quick FSM step, loose enough to not spam the server during long LLM thinking windows. */\nconst WAIT_DEFAULT_INTERVAL_SEC = 3;\n/** Default ceiling for `--wait` so a wedged peer doesn't hang the CLI forever. */\nconst WAIT_DEFAULT_TIMEOUT_SEC = 300;\n\n/**\n * `heyarp status <rel-id>` — one-shot \"where am I in the work cycle\"\n * summary for a single relationship.\n *\n * Operators routinely lose their place in the FSM after a context\n * switch (\"I proposed a contract — what now?\"). The existing list\n * commands each give a slice (`heyarp contracts`, `heyarp delegations`,\n * `heyarp work-list`, `heyarp receipts`); status composes them into\n * the answer to \"whose turn is it?\".\n *\n * # No new server endpoints\n *\n * Pure aggregation across existing signed reads — `listRelationships`\n * (to find the rel + own DID's role) + `listContracts` +\n * `listDelegations` + `listWorkLogs` + `listReceipts`. Five parallel\n * HTTP calls, one render. If a future protocol-aware \"summary\"\n * endpoint lands server-side this command can swap to it without\n * changing its surface.\n */\nexport function registerStatusCommand(root: Command): void {\n\troot.command('status')\n\t\t.description('Where am I in the work cycle? FSM state + next-action hint for ONE relationship (signed reads)')\n\t\t.argument('<relationship-id>', 'Relationship UUID')\n\t\t.option('--server <url>', 'Override ARP server base URL')\n\t\t.option('--from-did <did>', 'Signer DID — required only if multiple agents are registered against this server')\n\t\t.option('--json', 'Machine-readable: single JSON object with the composed summary. Pipe-safe.', false)\n\t\t// Blocking poll until the operator has something to do, OR the\n\t\t// cycle terminates.\n\t\t.option(\n\t\t\t'--wait',\n\t\t\t`Block and poll until you can act (\\`nextActionOwner === 'me'\\` OR \\`nextActionOwner === 'either' AND relationshipState === 'active'\\`) OR the cycle terminates (COMPLETE / closed / not_found). Exits immediately if either condition is already true at first read. Default cadence ${WAIT_DEFAULT_INTERVAL_SEC}s, --wait-timeout ${WAIT_DEFAULT_TIMEOUT_SEC}s. Pairs with --json so a wrapping script can branch on the new state. Exit code 124 on timeout (unix \\`timeout\\` convention). Combine with --wait-verbose to see per-tick state snapshots during long waits — useful for \"is it alive or stuck?\" diagnosis without spawning a separate \\`inbox --tail\\` shell.`,\n\t\t\tfalse,\n\t\t)\n\t\t.option(\n\t\t\t'--wait-timeout <seconds>',\n\t\t\t`Max wall-clock seconds to wait when --wait is set (default ${WAIT_DEFAULT_TIMEOUT_SEC}). Process exits code 124 on timeout, matching the unix \\`timeout\\` convention.`,\n\t\t\tString(WAIT_DEFAULT_TIMEOUT_SEC),\n\t\t)\n\t\t.option(\n\t\t\t'--wait-interval <seconds>',\n\t\t\t`Seconds between polls when --wait is set (default ${WAIT_DEFAULT_INTERVAL_SEC}). Bound to [1, 60].`,\n\t\t\tString(WAIT_DEFAULT_INTERVAL_SEC),\n\t\t)\n\t\t.option(\n\t\t\t'--wait-verbose',\n\t\t\t\"Emit one dim line per poll tick showing the current state (e.g. `[--wait tick 12/200] state=active, contract=proposed (not yet contract.active)`). Useful for debugging long waits where the operator can't tell if the poll is alive or stuck on the network.\",\n\t\t\tfalse,\n\t\t)\n\t\t// Scripted flows often want a narrower exit predicate than\n\t\t// \"your turn or terminal\" (e.g. CI checks \"wait for\n\t\t// receipt.cosigned\" specifically). `--until` adds phase-\n\t\t// anchored exit on top of the FSM-aware default.\n\t\t.option(\n\t\t\t'--until <phase>',\n\t\t\t`When --wait is set, exit ONLY when this specific phase is reached (instead of the default \"your turn or cycle terminated\" predicate). One of: ${UNTIL_PHASES.join(', ')}. Useful for scripts that need a specific transition (e.g. \\`--until contract.active\\` to wait for sign without caring about delegation/work phases). Combine with --wait-timeout to bound the wait.`,\n\t\t)\n\t\t.action(async (relationshipId: string, opts: StatusOptions) => {\n\t\t\tawait runStatus(relationshipId, opts);\n\t\t});\n}\n\n/**\n * Aggregated summary for one relationship — exposed via `--json`.\n *\n * `nextActionHint` is the operator-facing instruction string and\n * `nextActionOwner` distinguishes \"you owe …\" from \"counterparty\n * owes …\" so a wrapper can branch.\n */\nexport interface StatusSummary {\n\trelationshipId: string;\n\tsignerDid: string;\n\tcounterpartyDid: string | null;\n\t/**\n\t * Authoritative `pending | active | paused | closed` when the\n\t * relationship row was found on `listRelationships`'s first page.\n\t *\n\t * `not_found` when membership probes failed (relationship doesn't\n\t * exist or signer is not a party).\n\t *\n\t * `unknown` is the recovery state: membership was\n\t * confirmed via the relationship-scoped contracts probe (so the\n\t * signer IS a member) but the rel-id fell off the\n\t * `listRelationships` first-page window — the authoritative state\n\t * (paused vs active vs closed) cannot be read without the\n\t * server-side `?relationshipId=` filter (tracked V1.5). The FSM\n\t * walker still produces a best-effort hint based on the entity\n\t * layer; consumers MUST treat the hint as advisory and re-verify\n\t * via `heyarp relationships --from-did X` before acting on it.\n\t */\n\trelationshipState: RelationshipPublic['state'] | 'not_found' | 'unknown';\n\tlatestContract: ContractPublic | null;\n\tlatestDelegation: DelegationPublic | null;\n\tlatestWorkLog: WorkLogPublic | null;\n\tlatestReceipt: ReceiptPublic | null;\n\tnextActionHint: string;\n\tnextActionOwner: 'me' | 'counterparty' | 'either' | 'none';\n\tcycleComplete: boolean;\n}\n\n// Exported for test coverage of the --wait poll loop. The run\n// function is the entire command behaviour; the helper tests\n// (parseTtl, fsm walker, etc.) live alongside `composeStatus` /\n// `nextAction`.\nexport async function runStatus(relationshipId: string, opts: StatusOptions): Promise<void> {\n\tconst api = new ArpApiClient(opts.server);\n\tconst sender = resolveSenderAgent('status', opts.server, opts.fromDid);\n\n\tif (!opts.json) {\n\t\tconsole.log(chalk.dim(`Server: ${api.serverUrl}`));\n\t\tconsole.log(chalk.dim(`Signer: ${sender.did}`));\n\t\tconsole.log(chalk.dim(`Relationship: ${relationshipId}`));\n\t}\n\n\tconst signer = makeSigner(sender);\n\n\tif (!opts.wait) {\n\t\t// One-shot — the original status behaviour.\n\t\tconst summary = await composeStatus(api, sender.did, relationshipId, signer);\n\t\tif (opts.json) {\n\t\t\tconsole.log(JSON.stringify(summary));\n\t\t\treturn;\n\t\t}\n\t\tconsole.log('');\n\t\tconsole.log(formatStatusReport(summary));\n\t\treturn;\n\t}\n\n\t// --wait: block until the operator has SOMETHING TO ACT ON,\n\t// the cycle terminates, OR the timeout fires.\n\t//\n\t// The exit predicate reads the operator's mental model directly.\n\t// \"I want to wait until I should ACT\" maps to:\n\t// `nextActionOwner === 'me' AND state !== 'unknown'` (clear me-owes)\n\t// OR\n\t// `nextActionOwner === 'either' AND state === 'active'` (open-action\n\t// point: no live contract, no live delegation — operator CAN act)\n\t// \"I want to know when the cycle is DONE\" maps to\n\t// `cycleComplete || state ∈ {closed, not_found}` — terminal.\n\t// Anything else is what we block on:\n\t// isActionable(s) || isTerminal(s) → return immediately\n\t// counterparty owes / pending+either / paused+either / advisory\n\t// → poll loop\n\t// timeout → exit 124\n\t//\n\t// This matches `until peer-responds; do sleep; done` patterns\n\t// operators already write by hand around the one-shot status\n\t// command.\n\tconst waitTimeout = parseWaitTimeout(opts.waitTimeout);\n\tconst waitInterval = parseWaitInterval(opts.waitInterval);\n\tconst until = parseUntilPhase(opts.until);\n\n\tconst outcome = await runWaitLoop({\n\t\tfetchSummary: () => composeStatus(api, sender.did, relationshipId, signer),\n\t\twaitIntervalSec: waitInterval,\n\t\twaitTimeoutSec: waitTimeout,\n\t\twaitVerbose: !!opts.waitVerbose,\n\t\tjson: !!opts.json,\n\t\tlog: (line) => console.log(line),\n\t\tuntil,\n\t});\n\n\tif (outcome.timedOut) {\n\t\tprocess.exitCode = 124;\n\t}\n}\n\n/**\n * Extracted wait-loop semantics. Takes an async `fetchSummary`\n * callback so tests can inject a scripted sequence of summaries\n * without spinning the full composeStatus + signed-read stack.\n * Returns `{ timedOut, last }` so the caller can set the process\n * exit code.\n *\n * Behaviour (matches the runStatus inline notes):\n * - First fetchSummary is the \"initial\" snapshot.\n * - If initial is terminal OR actionable → return immediately.\n * - Otherwise loop: sleep (clamped to remaining budget) →\n * fetchSummary → exit on actionable | terminal | timeout.\n *\n * Exported for unit tests.\n */\nexport interface RunWaitLoopOpts {\n\tfetchSummary: () => Promise<StatusSummary>;\n\twaitIntervalSec: number;\n\twaitTimeoutSec: number;\n\tjson: boolean;\n\tlog: (line: string) => void;\n\t/** Pluggable sleep — tests inject a controllable timer. Defaults to setTimeout. */\n\tsleepMs?: (ms: number) => Promise<void>;\n\t/** Pluggable clock — tests inject a deterministic monotonic source. Defaults to Date.now. */\n\tnow?: () => number;\n\t/**\n\t * When set, replaces the default FSM-aware exit predicate\n\t * (\"your turn or cycle terminated\") with a narrower phase-match\n\t * check. Operators waiting for a specific transition (e.g.\n\t * `contract.active`, `receipt.cosigned`) get the script-friendly\n\t * semantics they reach for; default behaviour is unchanged when\n\t * `until` is omitted.\n\t */\n\tuntil?: UntilPhase;\n\t/**\n\t * When true, emit one dim line per poll tick with the current\n\t * state. Helps debug long waits where the operator can't tell if\n\t * the poll is alive or stuck. Suppressed in JSON mode (one event\n\t * per tick would break stdout's \"single JSON document at the end\"\n\t * contract).\n\t */\n\twaitVerbose?: boolean;\n}\n\nexport interface RunWaitLoopOutcome {\n\ttimedOut: boolean;\n\tlast: StatusSummary;\n}\n\nexport async function runWaitLoop(opts: RunWaitLoopOpts): Promise<RunWaitLoopOutcome> {\n\tconst isTerminal = (s: StatusSummary): boolean => s.cycleComplete || s.relationshipState === 'closed' || s.relationshipState === 'not_found';\n\tconst isActionable = (s: StatusSummary): boolean => {\n\t\t// `me` is always actionable (clear ownership). `either` is\n\t\t// the FSM walker's bucket for \"more than one path could fire\";\n\t\t// the `pending` / `paused` cases must NOT trip `--wait`\n\t\t// (relationship hasn't committed yet, operator owes nothing),\n\t\t// but the `active + either` cases ARE the operator-actionable\n\t\t// points: no live contract → buyer can propose; no live\n\t\t// delegation → buyer can offer; etc. We disambiguate by\n\t\t// relationship state.\n\t\tif (s.nextActionOwner === 'me') {\n\t\t\t// `unknown` is the advisory fallback — never treat as\n\t\t\t// clean success.\n\t\t\tif (s.relationshipState === 'unknown') return false;\n\t\t\treturn true;\n\t\t}\n\t\tif (s.nextActionOwner === 'either' && s.relationshipState === 'active') {\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t};\n\t// Phase-specific exit predicate overrides the FSM-aware default\n\t// when --until is supplied. We use a NARROWER terminal check\n\t// (`isPhaseTerminallyUnreachable`) so that:\n\t// - `--until relationship.closed` keeps waiting through\n\t// `cycleComplete=true` on an active relationship.\n\t// - `--until contract.active` bails on `not_found` / `closed`\n\t// where the phase genuinely can't be reached.\n\t// The generic `isTerminal` is still used for the default predicate\n\t// because the FSM-aware default treats cycleComplete itself as a\n\t// success.\n\tconst exitPredicate = opts.until !== undefined ? (s: StatusSummary): boolean => untilPhaseMatched(opts.until!, s) || isPhaseTerminallyUnreachable(opts.until!, s) : (s: StatusSummary): boolean => isActionable(s) || isTerminal(s);\n\t// Separately tracked so `--until` doesn't claim success when the\n\t// loop exited because of an unrelated terminal state.\n\tconst isUntilReached = opts.until !== undefined ? (s: StatusSummary): boolean => untilPhaseMatched(opts.until!, s) : null;\n\tconst localSleep = opts.sleepMs ?? sleep;\n\tconst localNow = opts.now ?? (() => Date.now());\n\n\tconst initial = await opts.fetchSummary();\n\tif (!opts.json) {\n\t\topts.log('');\n\t\topts.log(formatStatusReport(initial));\n\t}\n\n\t// --until short-circuits BEFORE the default predicates so\n\t// \"wait for contract.active\" exits even when nextActionOwner would\n\t// otherwise have classified the state as not-yet-actionable for\n\t// the signer.\n\tif (isUntilReached !== null && isUntilReached(initial)) {\n\t\tif (opts.json) opts.log(JSON.stringify(initial));\n\t\telse opts.log(chalk.dim(`\\n[--wait] Phase '${opts.until!}' already reached — exiting without polling.`));\n\t\treturn { timedOut: false, last: initial };\n\t}\n\t// Initial terminal-state branch:\n\t// - default path (no --until): generic `isTerminal` — cycleComplete\n\t// OR closed OR not_found all count as \"we're done\".\n\t// - --until path: only the narrower `isPhaseTerminallyUnreachable`\n\t// so e.g. `--until relationship.closed` correctly keeps waiting\n\t// when cycleComplete=true on an active relationship.\n\tconst initialTerminal = opts.until !== undefined ? isPhaseTerminallyUnreachable(opts.until, initial) : isTerminal(initial);\n\tif (initialTerminal) {\n\t\tconst terminalUnmatchedJson = opts.until !== undefined && isUntilReached !== null && !isUntilReached(initial);\n\t\t// Emit `_waitTimedOut: true` on the terminal-without-match\n\t\t// JSON path so consumers can distinguish \"phase unreachable\"\n\t\t// from a normal terminal status. Default-path JSON keeps the\n\t\t// original shape.\n\t\tif (opts.json) opts.log(JSON.stringify(terminalUnmatchedJson ? { ...initial, _waitTimedOut: true } : initial));\n\t\telse {\n\t\t\t// When --until was requested, surface that the loop bailed\n\t\t\t// on terminal state rather than the requested phase.\n\t\t\tif (opts.until !== undefined) {\n\t\t\t\topts.log(chalk.yellow(`\\n[--wait] Terminal state (${initial.relationshipState}, cycleComplete=${initial.cycleComplete}) reached before phase '${opts.until}' — exiting; phase unreachable.`));\n\t\t\t} else {\n\t\t\t\topts.log(chalk.dim(`\\n[--wait] Already terminal — exiting.`));\n\t\t\t}\n\t\t}\n\t\t// --until: terminal-without-match counts as a wait failure so\n\t\t// the wrapping script can branch on exit code 124.\n\t\treturn { timedOut: terminalUnmatchedJson, last: initial };\n\t}\n\tif (opts.until === undefined && isActionable(initial)) {\n\t\tif (opts.json) opts.log(JSON.stringify(initial));\n\t\telse opts.log(chalk.dim(`\\n[--wait] Your turn already (nextActionOwner=${initial.nextActionOwner}) — exiting without polling.`));\n\t\treturn { timedOut: false, last: initial };\n\t}\n\n\tif (!opts.json) {\n\t\t// The hint label has to reflect what's actually blocking.\n\t\t// `counterparty` ⇒ peer owes; `either` ⇒ neither side has\n\t\t// committed to acting; anything else (`unknown`, `pending`,\n\t\t// `paused`) is an advisory state the FSM walker hasn't\n\t\t// classified. Don't lie to operators about \"Counterparty owes\"\n\t\t// when the blocker is something else.\n\t\tconst blockerLabel =\n\t\t\topts.until !== undefined\n\t\t\t\t? `Awaiting phase '${opts.until}'`\n\t\t\t\t: initial.nextActionOwner === 'counterparty'\n\t\t\t\t\t? 'Counterparty owes the next move'\n\t\t\t\t\t: initial.nextActionOwner === 'either'\n\t\t\t\t\t\t? 'Either side may act'\n\t\t\t\t\t\t: `Awaiting state change (currently ${initial.relationshipState}, nextActionOwner=${initial.nextActionOwner})`;\n\t\topts.log(chalk.dim(`\\n[--wait] ${blockerLabel}. Polling every ${opts.waitIntervalSec}s, timeout ${opts.waitTimeoutSec}s.`));\n\t\topts.log(chalk.dim(`[--wait] Initial hint: ${initial.nextActionHint}`));\n\t}\n\n\tconst startedAt = localNow();\n\tconst deadline = startedAt + opts.waitTimeoutSec * 1000;\n\tlet last = initial;\n\t// Known limitation: `--wait-timeout` is a LOOP-ITERATION deadline,\n\t// not a wall-clock guarantee. A single in-flight `fetchSummary()`\n\t// can hang past the deadline if the server stops responding (the\n\t// surrounding signed-read stack doesn't yet take an AbortSignal).\n\t// The loop exits at the next boundary check, so the CLI\n\t// eventually returns, but the promised timeout is missed by\n\t// however long the wedged request takes. Future: plumb an\n\t// `AbortController.signal` from the remaining budget through\n\t// `composeStatus` → `ArpApiClient` → `signedRequest` so the\n\t// request itself is racing the deadline.\n\t//\n\t// Tick counter for --wait-verbose: total expected ticks =\n\t// ceil(timeoutSec / intervalSec). Helps the operator see\n\t// progress against the budget.\n\tconst maxTicks = Math.max(1, Math.ceil(opts.waitTimeoutSec / opts.waitIntervalSec));\n\tlet tickIndex = 0;\n\twhile (localNow() < deadline) {\n\t\t// Clamp the sleep interval to the remaining budget so a long\n\t\t// `--wait-interval` near the deadline doesn't oversleep +\n\t\t// overshoot the promised timeout.\n\t\tconst remainingMs = deadline - localNow();\n\t\tif (remainingMs <= 0) break;\n\t\tawait localSleep(Math.min(opts.waitIntervalSec * 1000, remainingMs));\n\t\t// Poll one more time after the final sleep so a transition\n\t\t// during the last window isn't reported as timeout.\n\t\tconst next = await opts.fetchSummary();\n\t\ttickIndex += 1;\n\t\t// Per-tick progress line (suppressed in JSON mode so stdout\n\t\t// stays one document at the end). Check whether the phase is\n\t\t// already matched on THIS tick before labelling the suffix —\n\t\t// otherwise the final tick prints \"not yet X\" immediately\n\t\t// before the success banner says X was reached.\n\t\tif (opts.waitVerbose && !opts.json) {\n\t\t\tlet target: string;\n\t\t\tif (opts.until !== undefined) {\n\t\t\t\ttarget = isUntilReached !== null && isUntilReached(next) ? `reached ${opts.until} ✓` : `not yet ${opts.until}`;\n\t\t\t} else {\n\t\t\t\ttarget = `nextActionOwner=${next.nextActionOwner}`;\n\t\t\t}\n\t\t\topts.log(chalk.dim(`[--wait tick ${tickIndex}/${maxTicks}] state=${next.relationshipState}, ${formatPhaseSnapshot(next)} (${target})`));\n\t\t}\n\t\tif (exitPredicate(next)) {\n\t\t\t// Distinguish \"phase reached\" from \"loop bailed on\n\t\t\t// terminal state without reaching phase\". The former is a\n\t\t\t// clean success (timedOut=false); the latter is reported\n\t\t\t// as timeout-equivalent so the wrapping script can tell\n\t\t\t// the target phase never materialised.\n\t\t\tconst phaseReached = isUntilReached !== null ? isUntilReached(next) : false;\n\t\t\tconst terminalUnmatched = isUntilReached !== null && !phaseReached && isTerminal(next);\n\t\t\tif (opts.json) opts.log(JSON.stringify(terminalUnmatched ? { ...next, _waitTimedOut: true } : next));\n\t\t\telse {\n\t\t\t\topts.log('');\n\t\t\t\tif (opts.until !== undefined) {\n\t\t\t\t\tif (phaseReached) {\n\t\t\t\t\t\topts.log(chalk.green(`[--wait] Phase '${opts.until}' reached.`));\n\t\t\t\t\t} else {\n\t\t\t\t\t\topts.log(chalk.yellow(`[--wait] Terminal state (${next.relationshipState}, cycleComplete=${next.cycleComplete}) reached before phase '${opts.until}' — phase unreachable.`));\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\topts.log(chalk.green(`[--wait] ${isTerminal(next) ? 'Cycle terminated' : `Your turn (owner=${next.nextActionOwner})`}.`));\n\t\t\t\t}\n\t\t\t\topts.log(formatStatusReport(next));\n\t\t\t}\n\t\t\treturn { timedOut: terminalUnmatched, last: next };\n\t\t}\n\t\tlast = next;\n\t}\n\n\tif (opts.json) {\n\t\topts.log(JSON.stringify({ ...last, _waitTimedOut: true }));\n\t} else {\n\t\tif (opts.until !== undefined) {\n\t\t\topts.log(chalk.yellow(`\\n[--wait] Timed out after ${opts.waitTimeoutSec}s without reaching phase '${opts.until}' (latest state: ${last.relationshipState}, hint: ${last.nextActionHint}).`));\n\t\t} else {\n\t\t\topts.log(chalk.yellow(`\\n[--wait] Timed out after ${opts.waitTimeoutSec}s without an actionable or terminal transition (your turn never came, cycle still in flight).`));\n\t\t}\n\t}\n\treturn { timedOut: true, last };\n}\n\n/**\n * Parse `--wait-timeout` into a positive seconds value with a sane\n * upper bound. 0 / negative / non-integer → loud error so the\n * operator catches typos before the poll loop hangs.\n *\n * Exported for unit tests.\n */\nexport function parseWaitTimeout(raw: string | undefined): number {\n\tif (raw === undefined) return WAIT_DEFAULT_TIMEOUT_SEC;\n\tconst n = Number(raw);\n\tif (!Number.isFinite(n) || !Number.isInteger(n) || n <= 0) {\n\t\tthrow new Error(`status: --wait-timeout must be a positive integer number of seconds (got '${raw}')`);\n\t}\n\t// Hard cap at 1 hour — anything longer is operator error\n\t// (CLI users get tired before that and Ctrl-C anyway).\n\tif (n > 3600) {\n\t\tthrow new Error(`status: --wait-timeout must be <= 3600 seconds (1h). Got ${n}; if you really need to wait longer, script a loop around \\`heyarp status\\`.`);\n\t}\n\treturn n;\n}\n\n/**\n * Parse `--until <phase>` into a typed `UntilPhase`, or `undefined`\n * when omitted. Loud error on unknown phases so a typo (e.g.\n * `--until contract-active`) doesn't silently degrade to the default\n * FSM-aware predicate.\n *\n * Exported for unit tests.\n */\nexport function parseUntilPhase(raw: string | undefined): UntilPhase | undefined {\n\tif (raw === undefined || raw === '') return undefined;\n\tif (!(UNTIL_PHASES as readonly string[]).includes(raw)) {\n\t\tthrow new Error(`status: --until must be one of: ${UNTIL_PHASES.join(', ')} (got '${raw}')`);\n\t}\n\treturn raw as UntilPhase;\n}\n\n/**\n * Is the named phase genuinely unreachable given the summary's\n * current state? Used by the --until exit predicate to short-circuit\n * when the relationship has reached a state from which the target\n * can NEVER fire — without overlapping with the generic `isTerminal`\n * test, which classifies `cycleComplete=true` as terminal (but\n * `relationship.closed` is still reachable from a cycle-complete\n * active relationship, so cycleComplete alone must NOT bail an\n * --until wait).\n *\n * Rules:\n * - If the phase is already matched, it is NOT unreachable\n * (caller handles that case directly).\n * - `relationshipState === 'not_found'` → unreachable for any\n * phase (no relationship exists).\n * - `relationshipState === 'closed'` → unreachable for everything\n * except `relationship.closed` itself (closed is terminal for\n * all further protocol motion).\n * - Otherwise: still in flight, keep polling.\n *\n * Exported for unit tests.\n */\nexport function isPhaseTerminallyUnreachable(phase: UntilPhase, s: StatusSummary): boolean {\n\tif (untilPhaseMatched(phase, s)) return false;\n\tif (s.relationshipState === 'not_found') return true;\n\tif (s.relationshipState === 'closed' && phase !== 'relationship.closed') return true;\n\treturn false;\n}\n\n/**\n * Per-phase predicate over a `StatusSummary`. Returns true when the\n * named transition has been reached. Mirrors the entity states the\n * FSM walker recognises plus the rolled-up `cycle.complete`.\n *\n * Exported for unit tests.\n */\nexport function untilPhaseMatched(phase: UntilPhase, s: StatusSummary): boolean {\n\tswitch (phase) {\n\t\tcase 'contract.proposed':\n\t\t\treturn s.latestContract?.state === 'proposed';\n\t\tcase 'contract.active':\n\t\t\treturn s.latestContract?.state === 'active';\n\t\tcase 'contract.replaced':\n\t\t\treturn s.latestContract?.state === 'replaced';\n\t\tcase 'contract.declined':\n\t\t\treturn s.latestContract?.state === 'declined';\n\t\tcase 'delegation.proposed':\n\t\t\t// Server emits `'offered'` after `delegation offer` is\n\t\t\t// processed (passes through a brief\n\t\t\t// `'pending_lock_finalization'` intermediate first while\n\t\t\t// the relayer confirms the on-chain create_lock). All\n\t\t\t// three names map to the same awaiting-acceptance phase.\n\t\t\treturn s.latestDelegation?.state === 'proposed' || s.latestDelegation?.state === 'offered' || s.latestDelegation?.state === 'pending_lock_finalization';\n\t\tcase 'delegation.accepted':\n\t\t\treturn s.latestDelegation?.state === 'accepted';\n\t\tcase 'delegation.canceled':\n\t\t\treturn s.latestDelegation?.state === 'canceled';\n\t\tcase 'delegation.declined':\n\t\t\treturn s.latestDelegation?.state === 'declined';\n\t\tcase 'work.requested':\n\t\t\treturn s.latestWorkLog?.state === 'requested';\n\t\tcase 'work.responded':\n\t\t\treturn s.latestWorkLog?.state === 'responded';\n\t\tcase 'receipt.proposed':\n\t\t\treturn s.latestReceipt?.state === 'proposed';\n\t\tcase 'receipt.cosigned':\n\t\t\treturn s.latestReceipt?.state === 'cosigned';\n\t\tcase 'relationship.pending':\n\t\t\treturn s.relationshipState === 'pending';\n\t\tcase 'relationship.active':\n\t\t\treturn s.relationshipState === 'active';\n\t\tcase 'relationship.paused':\n\t\t\treturn s.relationshipState === 'paused';\n\t\tcase 'relationship.closed':\n\t\t\treturn s.relationshipState === 'closed';\n\t\tcase 'cycle.complete':\n\t\t\treturn s.cycleComplete;\n\t\tcase 'cycle.released':\n\t\t\t// Strictly stronger than `cycle.complete` — receipt\n\t\t\t// cosigned AND on-chain release confirmed (delegation row\n\t\t\t// advanced to `completed`, meaning the server's indexer\n\t\t\t// saw the release_lock tx land). The post-release FSM\n\t\t\t// progression is:\n\t\t\t// pending_lock_finalization → accepted →\n\t\t\t// awaiting_release_finalization → completed\n\t\t\treturn s.latestDelegation?.state === 'completed';\n\t}\n}\n\n/**\n * Parse `--wait-interval`. Clamped to [1, 60] — sub-second polls\n * hammer the server, > 60s cadence defeats the purpose of `--wait`\n * (operator might as well script their own polling).\n *\n * Exported for unit tests.\n */\nexport function parseWaitInterval(raw: string | undefined): number {\n\tif (raw === undefined) return WAIT_DEFAULT_INTERVAL_SEC;\n\tconst n = Number(raw);\n\tif (!Number.isFinite(n) || !Number.isInteger(n) || n <= 0) {\n\t\tthrow new Error(`status: --wait-interval must be a positive integer number of seconds (got '${raw}')`);\n\t}\n\tif (n < 1 || n > 60) {\n\t\tthrow new Error(`status: --wait-interval must be in [1, 60] seconds (got ${n}). Sub-second polling spams the server; > 60s defeats the point of --wait.`);\n\t}\n\treturn n;\n}\n\nfunction sleep(ms: number): Promise<void> {\n\treturn new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Compose a `StatusSummary` for one relationship.\n *\n * # Pagination + scoping\n *\n * Two correctness invariants worth pinning here:\n *\n * 1. **All entity lists are oldest-first** (server contract for\n * contracts / delegations / work_logs / receipts). A single\n * `limit:100` page would return the OLDEST 100 rows, not the\n * most recent — `pickLatest` over that gives stale answers on\n * any long-lived relationship. `fetchAllPages` walks `?after=`\n * until the server returns fewer rows than the limit so we\n * always see the true tail.\n *\n * 2. **Child entities are filtered by parent.** Latest delegation\n * must be under the LATEST contract; latest work_log under the\n * latest delegation; latest receipt under the latest\n * delegation. Without that scope, an old completed delegation\n * can make `status` say \"cycle complete\" while the user has a\n * live un-fulfilled contract sitting next to it. We use the\n * server-side `contractId` / `delegationId` query filters\n * (defined on `ListDelegationsQuery` / `ListWorkLogsQuery` /\n * `ListReceiptsQuery`) to keep the query cheap.\n *\n * Exported for testability + reuse.\n */\nexport async function composeStatus(api: ArpApiClient, signerDid: string, relationshipId: string, signer: Parameters<typeof api.listContracts>[1]): Promise<StatusSummary> {\n\t// Step 1: dual-probe membership.\n\t//\n\t// `listRelationships` accepts no cursor (see `ListRelationshipsQuery`\n\t// in `api.ts`) and the server caps the page at 100 ordered by\n\t// `lastEventAt` desc. For signers with > 100 live + closed\n\t// relationships, an older rel-id falls off this page — using it\n\t// alone would falsely report `not_found`. The recovery path is\n\t// to probe the relationship-scoped `listContracts` endpoint\n\t// directly:\n\t//\n\t// - listContracts returning rows (or `[]`) → signer IS member;\n\t// proceed with the contract list we just fetched.\n\t// - listContracts throwing 403 / 404 → not_found (signer is\n\t// either not a member, or the rel doesn't exist server-side).\n\t//\n\t// We issue both calls in parallel — the membership signal lives\n\t// on the contracts response either way, and the listRelationships\n\t// page (if it has the row) gives us authoritative `state` +\n\t// `counterpartyDid`. When the rel falls off the page we infer\n\t// counterparty from entity rows and surface state as 'active'\n\t// (which is the only state in which entity reads succeed +\n\t// further protocol work is possible — paused refuses POSTs but\n\t// still allows the read; pending wouldn't have any contracts).\n\tconst [relationshipsOrNull, contractsOrError] = await Promise.all([\n\t\tapi.listRelationships(signerDid, signer, { limit: 100 }).catch(() => null),\n\t\tfetchAllPages<ContractPublic>((after) => api.listContracts(relationshipId, signer, { limit: 100, ...(after ? { after } : {}) })).catch((err) => err as Error),\n\t]);\n\n\tif (contractsOrError instanceof Error) {\n\t\t// listContracts threw — translate auth/not-found into the\n\t\t// `not_found` summary; surface anything else as a real error\n\t\t// (server outage etc).\n\t\tif (contractsOrError instanceof ApiError && (contractsOrError.status === 403 || contractsOrError.status === 404)) {\n\t\t\tconst { hint, owner, complete } = nextAction({\n\t\t\t\tsignerDid,\n\t\t\t\trelationship: undefined,\n\t\t\t\tlatestContract: null,\n\t\t\t\tlatestDelegation: null,\n\t\t\t\tlatestWorkLog: null,\n\t\t\t\tlatestReceipt: null,\n\t\t\t});\n\t\t\treturn {\n\t\t\t\trelationshipId,\n\t\t\t\tsignerDid,\n\t\t\t\tcounterpartyDid: null,\n\t\t\t\trelationshipState: 'not_found',\n\t\t\t\tlatestContract: null,\n\t\t\t\tlatestDelegation: null,\n\t\t\t\tlatestWorkLog: null,\n\t\t\t\tlatestReceipt: null,\n\t\t\t\tnextActionHint: hint,\n\t\t\t\tnextActionOwner: owner,\n\t\t\t\tcycleComplete: complete,\n\t\t\t};\n\t\t}\n\t\tthrow contractsOrError;\n\t}\n\n\tconst contracts = contractsOrError;\n\tconst relationships = relationshipsOrNull ?? [];\n\tconst relationship = relationships.find((r) => r.relationshipId === relationshipId);\n\n\t// Step 2: contracts — already fetched in the parallel probe.\n\t//\n\t// Live-preference: spec allows concurrent active contracts on one\n\t// relationship (different scope tags). The \"latest by updatedAt\"\n\t// row can be a freshly-declined / replaced one even while another\n\t// is still live; prefer `proposed` / `active` first so the FSM\n\t// walker doesn't say \"no live contract\" while live work exists.\n\tconst latestContract = pickLatestLive(contracts, ['proposed', 'active']);\n\t// Counterparty resolution: prefer the relationship row when we\n\t// have it (authoritative); otherwise infer from entity rows.\n\tconst counterpartyDid = relationship\n\t\t? relationship.pairDidA === signerDid\n\t\t\t? relationship.pairDidB\n\t\t\t: relationship.pairDidA\n\t\t: inferCounterpartyFromEntities(signerDid, contracts);\n\n\t// Step 3: delegations are scoped to the LATEST contract. Same\n\t// live-preference rule: a delegation that was just declined /\n\t// canceled shouldn't shadow a sibling that's proposed-or-accepted.\n\tconst delegations: DelegationPublic[] = latestContract\n\t\t? await fetchAllPages<DelegationPublic>((after) =>\n\t\t\t\tapi.listDelegations(relationshipId, signer, { limit: 100, contractId: latestContract.contractId, ...(after ? { after } : {}) }),\n\t\t\t)\n\t\t: [];\n\t// Include all non-terminal awaiting-* states alongside 'proposed'\n\t// so a delegation in any awaiting-acceptance or awaiting-release\n\t// state is preferred over an older terminal sibling. Specifically:\n\t//\n\t// - 'offered' / 'pending_lock_finalization' — pre-acceptance\n\t// transients on the offerer's side.\n\t// - 'accepted' — buyer has cosigned; work can begin.\n\t// - 'awaiting_release_finalization' — transient during\n\t// release_lock submission, mirror of `pending_lock_finalization`\n\t// on the other side.\n\t//\n\t// Do NOT include 'completed' — it is TERMINAL. Including it would\n\t// let a recently-released delegation shadow a still-live `accepted`\n\t// sibling under the same contract (pickLatestLive ranks by\n\t// updatedAt among matching states, so a fresh `completed` row\n\t// would beat an older `accepted` row). `pickLatestLive`'s\n\t// fallback (no live row → pickLatest of all rows) already covers\n\t// the \"all delegations completed\" case, so `cycle.released` still\n\t// resolves on single-delegation contracts.\n\tconst latestDelegation = pickLatestLive(delegations, [\n\t\t'proposed',\n\t\t'offered',\n\t\t'pending_lock_finalization',\n\t\t'accepted',\n\t\t'awaiting_release_finalization',\n\t]);\n\n\t// Step 4 + 5: work_logs and receipts are scoped to the LATEST\n\t// delegation. Both endpoints accept `?delegationId=` server-side.\n\tconst [workLogs, receipts] = await Promise.all([\n\t\tlatestDelegation\n\t\t\t? fetchAllPages<WorkLogPublic>((after) =>\n\t\t\t\t\tapi.listWorkLogs(relationshipId, signer, { limit: 100, delegationId: latestDelegation.delegationId, ...(after ? { after } : {}) }),\n\t\t\t\t)\n\t\t\t: Promise.resolve([] as WorkLogPublic[]),\n\t\tlatestDelegation\n\t\t\t? fetchAllPages<ReceiptPublic>((after) =>\n\t\t\t\t\tapi.listReceipts(relationshipId, signer, { limit: 100, delegationId: latestDelegation.delegationId, ...(after ? { after } : {}) }),\n\t\t\t\t)\n\t\t\t: Promise.resolve([] as ReceiptPublic[]),\n\t]);\n\t// Live-preference for work_logs: if a delegation\n\t// has multiple work_requests, prefer an OUTSTANDING (REQUESTED)\n\t// one over a newer-by-updatedAt completed pair. Otherwise an old\n\t// un-responded request gets shadowed by a newer responded one and\n\t// `status` falsely reports the cycle as further along than it is.\n\tconst latestWorkLog = pickLatestLive(workLogs, ['requested']);\n\t// Receipts are filtered by delegationId server-side, but a\n\t// delegation can host MULTIPLE work_request/work_response\n\t// pairs — each produces its own receipt. A naive timestamp\n\t// heuristic (receipt younger than latest work_log = \"belongs\n\t// to it\") is wrong when receipts are proposed out-of-order\n\t// (operator\n\t// catches up on an old request after a new one already\n\t// responded). Pair via the canonical hash chain: the receipt\n\t// for a work_log has `requestHash` = SHA-256 of the canonical\n\t// work_request body and `responseHash` = SHA-256 of the\n\t// canonical work_response body. We compute the same hashes\n\t// from the work_log fields and match exactly.\n\t//\n\t// If no receipt matches (or work_log has no response yet), the\n\t// receipt slot is null and the FSM walker correctly asks for\n\t// `receipt propose`.\n\tconst latestReceipt = latestWorkLog ? findReceiptForWorkLog(receipts, latestWorkLog, workLogs) : null;\n\n\t// FSM walker takes an authoritative relationship row when we\n\t// have it; otherwise a minimal placeholder that lets it walk\n\t// the contract/delegation/work/receipt branches normally.\n\t// `relationshipState` on the returned summary reflects the\n\t// truthfulness of the state — `'unknown'` when we inferred via\n\t// the dual-probe path so the JSON consumer can tell \"verified\n\t// active\" apart from \"we don't actually know — could be\n\t// paused/closed\", and we suffix the human hint with an advisory.\n\tconst inferredRelationship: RelationshipPublic = relationship ?? {\n\t\trelationshipId,\n\t\tpairDidA: signerDid,\n\t\tpairDidB: counterpartyDid ?? 'unknown',\n\t\t// Placeholder ONLY for the FSM walker — `relationshipState`\n\t\t// below preserves the honest \"we don't know\" answer.\n\t\tstate: 'active',\n\t\tlastEventIndex: 0,\n\t\tlastServerEventHash: null,\n\t\tlastEventAt: null,\n\t\tcreatedAt: '',\n\t\tupdatedAt: '',\n\t};\n\tconst fsmResult = nextAction({\n\t\tsignerDid,\n\t\trelationship: inferredRelationship,\n\t\tlatestContract,\n\t\tlatestDelegation,\n\t\tlatestWorkLog,\n\t\tlatestReceipt,\n\t});\n\tconst honestState: RelationshipPublic['state'] | 'unknown' = relationship?.state ?? 'unknown';\n\tconst nextActionHint = relationship\n\t\t? fsmResult.hint\n\t\t: `${fsmResult.hint}\\n ⚠ state inferred — relationship row not on the first 100 of listRelationships. Verify via \\`heyarp relationships --from-did ${signerDid}\\` before acting; the hint above assumes active.`;\n\n\treturn {\n\t\trelationshipId,\n\t\tsignerDid,\n\t\tcounterpartyDid,\n\t\trelationshipState: honestState,\n\t\tlatestContract,\n\t\tlatestDelegation,\n\t\tlatestWorkLog,\n\t\tlatestReceipt,\n\t\tnextActionHint,\n\t\tnextActionOwner: fsmResult.owner,\n\t\tcycleComplete: fsmResult.complete,\n\t};\n}\n\n/**\n * Counterparty inference for the high-volume recovery path. When the\n * relationship row falls off `listRelationships`'s\n * first 100 page, we still have authoritative member-of-pair access\n * (because the relationship-scoped reads succeeded) but no\n * `pairDidA` / `pairDidB`. Scan the contracts we already fetched for\n * a DID that is NOT the signer — `proposerDid` is the contract row's\n * counterparty marker. Returns `null` when no contract exists yet (a\n * brand-new relationship with no entities — unlikely to hit the\n * >100 ceiling at the same time, but defensive).\n *\n * Exported for testability.\n */\nexport function inferCounterpartyFromEntities(signerDid: string, contracts: ContractPublic[]): string | null {\n\tfor (const c of contracts) {\n\t\tif (c.proposerDid && c.proposerDid !== signerDid) return c.proposerDid;\n\t}\n\treturn null;\n}\n\n/**\n * Pair a receipt to a specific work_log via canonical-hash match,\n * with a single-work_log fallback for V1 placeholder hashes.\n *\n * The receipt body's `requestHash` is `sha256:<hex of canonical\n * work_request body>` (per `00-core/protocol.md`) — we reconstruct\n * the same body shape from the work_log's `requestId` /\n * `delegationId` / `requestParams` fields and hash it. The\n * `responseHash` covers the matching work_response body\n * (`{ output }` xor `{ error }`).\n *\n * The V1 validator only checks hash SHAPE (`sha256:<64-hex>`), not\n * equality against the work_log payload — so until the payload-aware\n * validator lands, payees routinely use placeholder hashes (per\n * guide §9). When that happens, canonical-hash pairing yields zero\n * matches and `latestReceipt` falsely reports `null`, which derails\n * the `nextAction` walker into a stale \"owes propose\" hint.\n *\n * Fallback rule: ONLY when this delegation has exactly one responded\n * work_log (the typical case — one request, one response, one\n * receipt), and the canonical-hash pairing missed, return the newest\n * same-delegation receipt that doesn't already exact-match this\n * work_log. In a multi-work_log delegation we abstain — placeholder\n * hashes make cross-attribution unsafe (a stale placeholder receipt\n * for an older work_log must not falsely advance the newer work_log's\n * receipt slot).\n *\n * Picking the newest by `updatedAt` covers the receipt-replay\n * case (V1.x payload-aware validator may produce duplicates if a\n * payee re-proposes).\n *\n * Exported for testability.\n */\nexport function findReceiptForWorkLog(receipts: ReceiptPublic[], workLog: WorkLogPublic, allWorkLogs: WorkLogPublic[] = [workLog]): ReceiptPublic | null {\n\t// work_log only carries `requestParams` (the inner `params`\n\t// object) but the protocol hashes the FULL canonical body. The\n\t// body shape is `{ type, content: { delegation_id, request_id,\n\t// params } }` — we reconstruct it deterministically.\n\tconst requestBody = {\n\t\ttype: 'work_request',\n\t\tcontent: {\n\t\t\tdelegation_id: workLog.delegationId,\n\t\t\trequest_id: workLog.requestId,\n\t\t\tparams: workLog.requestParams,\n\t\t},\n\t};\n\tconst responseBody =\n\t\tworkLog.responseOutput !== undefined\n\t\t\t? { type: 'work_response', content: { delegation_id: workLog.delegationId, request_id: workLog.requestId, output: workLog.responseOutput } }\n\t\t\t: workLog.responseError !== undefined\n\t\t\t\t? { type: 'work_response', content: { delegation_id: workLog.delegationId, request_id: workLog.requestId, error: workLog.responseError } }\n\t\t\t\t: null;\n\tif (!responseBody) return null; // work_log not yet responded — no receipt can exist\n\n\t// SDK's `canonicalSha256Hex` already returns the full\n\t// `sha256:<hex>` literal — do NOT prepend another `sha256:` here.\n\t// A string-shape assertion in the corresponding spec guards against\n\t// a regression that double-prefixes to `sha256:sha256:<hex>`.\n\tconst expectedRequestHash = canonicalSha256Hex(requestBody);\n\tconst expectedResponseHash = canonicalSha256Hex(responseBody);\n\tconst matches = receipts.filter((r) => r.requestHash === expectedRequestHash && r.responseHash === expectedResponseHash);\n\tif (matches.length > 0) return pickLatest(matches);\n\n\t// Fallback: only fire when this delegation has a single responded\n\t// work_log. In that case, any placeholder-hash receipt under the\n\t// delegation can only have been intended for THIS work_log —\n\t// there's nowhere else for it to belong. With multiple responded\n\t// work_logs, placeholder hashes are ambiguous and we abstain\n\t// (avoids reusing orphan receipts across work_logs).\n\tconst respondedSiblings = allWorkLogs.filter(\n\t\t(wl) => wl.delegationId === workLog.delegationId && (wl.responseOutput !== undefined || wl.responseError !== undefined),\n\t).length;\n\tif (respondedSiblings > 1) return null;\n\n\tconst sameDelegation = receipts.filter((r) => r.delegationId === workLog.delegationId);\n\treturn pickLatest(sameDelegation);\n}\n\n/**\n * Walk a paginated listing endpoint until exhaustion. `fetchPage`\n * is invoked with the previous page's cursor (`undefined` on first\n * call) and must return up to `limit` rows for that page. We stop\n * when a page returns fewer rows than the previous page (the\n * server's \"end of stream\" signal — page size below limit means no\n * more data).\n *\n * Hard cap of 50 pages × 100 = 5000 rows per call so an\n * unbounded/looping endpoint can't trap the CLI. Exceeding the\n * cap raises — V1 deployments aren't expected to come anywhere\n * near 5000 entities on a single relationship.\n *\n * Exported for testability.\n */\nexport async function fetchAllPages<T extends { id?: string; relationshipId?: string }>(fetchPage: (after: string | undefined) => Promise<T[]>): Promise<T[]> {\n\tconst PAGE_SIZE = 100;\n\tconst HARD_PAGE_CAP = 50;\n\tconst all: T[] = [];\n\tlet after: string | undefined = undefined;\n\tfor (let p = 0; p < HARD_PAGE_CAP; p++) {\n\t\tconst page = await fetchPage(after);\n\t\tall.push(...page);\n\t\tif (page.length < PAGE_SIZE) return all; // less than full page → end of stream\n\t\tconst last = page[page.length - 1];\n\t\tconst nextCursor = typeof last.id === 'string' ? last.id : typeof last.relationshipId === 'string' ? last.relationshipId : undefined;\n\t\tif (!nextCursor || nextCursor === after) return all; // safety: refuse to loop forever\n\t\tafter = nextCursor;\n\t}\n\tthrow new Error(`status: pagination exceeded ${HARD_PAGE_CAP * PAGE_SIZE} rows on one endpoint — relationship is unusually large; refusing to scan further`);\n}\n\n/**\n * Pick the newest row by `updatedAt` descending. Returns `null`\n * when the list is empty. Exported for testability.\n */\nexport function pickLatest<T extends { updatedAt: string }>(rows: T[]): T | null {\n\tif (rows.length === 0) return null;\n\treturn [...rows].sort((a, b) => (a.updatedAt < b.updatedAt ? 1 : a.updatedAt > b.updatedAt ? -1 : 0))[0];\n}\n\n/**\n * Prefer LIVE rows over terminal rows when answering \"which one is\n * the user actually working with?\". The protocol spec permits\n * concurrent active contracts on one relationship, so picking the\n * newest row by `updatedAt` can surface a freshly-declined\n * / replaced contract and report \"no live contract\" while an older\n * one is still active. Same risk for delegations (declined / canceled\n * can sit alongside a live proposal-or-acceptance).\n *\n * Strategy: filter to live states; if any survive, pick newest among\n * them; otherwise fall back to newest of all (for context, the FSM\n * walker handles terminal states explicitly).\n *\n * Exported for testability.\n */\nexport function pickLatestLive<T extends { updatedAt: string; state: string }>(rows: T[], liveStates: readonly string[]): T | null {\n\tconst live = rows.filter((r) => liveStates.includes(r.state));\n\tif (live.length > 0) return pickLatest(live);\n\treturn pickLatest(rows);\n}\n\n/**\n * FSM-aware next-action computation. Pure function over the latest-\n * row snapshots; encapsulates the protocol's turn-taking rules so\n * the renderer + JSON consumers see the same answer.\n *\n * relationship state → contract presence/state → delegation\n * presence/state → work_log presence/state → receipt\n * presence/state → DONE\n *\n * \"me\" / \"counterparty\" / \"either\" / \"none\" answers the question\n * \"whose move?\". `either` is used for ambiguous open states (e.g.\n * relationship active but no contract exists — both sides CAN\n * propose, neither MUST). `none` is the terminal cycle-complete\n * answer.\n *\n * Exported for testability.\n */\nexport function nextAction(input: {\n\tsignerDid: string;\n\trelationship: RelationshipPublic | undefined;\n\tlatestContract: ContractPublic | null;\n\tlatestDelegation: DelegationPublic | null;\n\tlatestWorkLog: WorkLogPublic | null;\n\tlatestReceipt: ReceiptPublic | null;\n}): { hint: string; owner: 'me' | 'counterparty' | 'either' | 'none'; complete: boolean } {\n\tconst { signerDid, relationship, latestContract, latestDelegation, latestWorkLog, latestReceipt } = input;\n\tif (!relationship) {\n\t\treturn {\n\t\t\thint: 'Relationship not found in your live + closed list — wrong id, or you are not a member of the pair',\n\t\t\towner: 'none',\n\t\t\tcomplete: false,\n\t\t};\n\t}\n\tif (relationship.state === 'pending') {\n\t\t// Identify whose turn: the receiver of the initial handshake\n\t\t// is the one who owes the handshake_response.\n\t\t// `listRelationships` doesn't tell us who initiated — we can\n\t\t// infer from event-log if needed, but for V1 status we just\n\t\t// say \"counterparty/you owe handshake_response\" and let the\n\t\t// operator infer.\n\t\treturn {\n\t\t\thint: 'Relationship is PENDING — one side owes `heyarp send-handshake-response <peer> --decision accept | decline`',\n\t\t\towner: 'either',\n\t\t\tcomplete: false,\n\t\t};\n\t}\n\tif (relationship.state === 'paused') {\n\t\treturn { hint: 'Relationship is PAUSED — owner must `heyarp unpause` before any envelopes flow', owner: 'either', complete: false };\n\t}\n\tif (relationship.state === 'closed') {\n\t\treturn { hint: 'Relationship is CLOSED — terminal state, no further action possible. Start a fresh handshake to reopen.', owner: 'none', complete: false };\n\t}\n\n\t// relationship.state === 'active' from here on.\n\tif (!latestContract || (latestContract.state !== 'proposed' && latestContract.state !== 'active')) {\n\t\t// No live contract at all (none, or every existing one is\n\t\t// replaced/declined). Either side can propose a new one.\n\t\treturn {\n\t\t\thint: 'No live contract — buyer issues `heyarp contract propose <peer> --contract-id <new-uuid> --scope … --rate-amount … --rate-currency USDC:solana-devnet --rate-unit task --pricing flat`',\n\t\t\towner: 'either',\n\t\t\tcomplete: false,\n\t\t};\n\t}\n\tif (latestContract.state === 'proposed') {\n\t\tconst iAmProposer = latestContract.proposerDid === signerDid;\n\t\treturn {\n\t\t\thint: iAmProposer\n\t\t\t\t? `Contract ${latestContract.contractId} v${latestContract.version} is PROPOSED — counterparty owes \\`heyarp contract sign\\` / \\`counter\\` / \\`decline\\``\n\t\t\t\t: `Contract ${latestContract.contractId} v${latestContract.version} is PROPOSED — you owe \\`heyarp contract sign\\` / \\`counter\\` / \\`decline\\``,\n\t\t\towner: iAmProposer ? 'counterparty' : 'me',\n\t\t\tcomplete: false,\n\t\t};\n\t}\n\n\t// Contract is ACTIVE — move to delegation layer.\n\tif (!latestDelegation || latestDelegation.state === 'declined' || latestDelegation.state === 'canceled') {\n\t\t// Either no delegation yet, or last one was rejected/withdrawn —\n\t\t// buyer (= contract proposer in V1, or anyone who fits the\n\t\t// access rules; spec doesn't gate this beyond pair membership)\n\t\t// can open a fresh one.\n\t\treturn {\n\t\t\thint: `Contract ${latestContract.contractId} is ACTIVE — buyer can issue \\`heyarp delegation offer <peer> ${latestContract.contractId} --delegation-id <new-uuid> --title … --amount … --currency USDC:solana-devnet --deadline …\\``,\n\t\t\towner: 'either',\n\t\t\tcomplete: false,\n\t\t};\n\t}\n\t// Terminal-failure substates the server emits outside the happy\n\t// path. Each must have an explicit branch — without one, the FSM\n\t// walker falls through to \"Delegation is ACCEPTED — work request\n\t// needed\", and the operator hits `WORK_DELEGATION_NOT_ACTIVE`\n\t// downstream. Each state has its own remediation copy so the\n\t// operator knows WHY the delegation is dead before issuing a\n\t// fresh offer:\n\t// - failed: on-chain escrow failure (lock not finalised)\n\t// - refunded: lock was refunded after expiry\n\t// - dispute_resolved: admin closed the delegation via dispute\n\t// All three are terminal; the remediation is the same: open a\n\t// fresh `delegation offer` with a NEW delegation_id. The FSM\n\t// does NOT auto-retry — that's a deliberate spec choice so the\n\t// operator can review the failure context first.\n\tif (latestDelegation.state === 'failed' || latestDelegation.state === 'refunded' || latestDelegation.state === 'dispute_resolved') {\n\t\tconst stateLabel = latestDelegation.state.toUpperCase();\n\t\tconst reason =\n\t\t\tlatestDelegation.state === 'failed'\n\t\t\t\t? 'on-chain escrow lock failed to finalise (typical causes: insufficient payer funds, wrong program-id, ProgramState PDA uninitialised — check `heyarp delegations <rel-id> --json | jq .[].escrowError` for the worker-side reason)'\n\t\t\t\t: latestDelegation.state === 'refunded'\n\t\t\t\t\t? 'lock was refunded after expiry — no work was delivered against this delegation'\n\t\t\t\t\t: 'admin closed the delegation via the dispute-resolution path';\n\t\treturn {\n\t\t\thint: `Delegation ${latestDelegation.delegationId} is ${stateLabel} (terminal) — ${reason}. Issue a fresh \\`heyarp delegation offer <peer> ${latestContract.contractId} --delegation-id <new-uuid> …\\` to retry (FSM does not auto-retry).`,\n\t\t\towner: 'either',\n\t\t\tcomplete: false,\n\t\t};\n\t}\n\t// The server emits `'offered'` for an awaiting-acceptance\n\t// delegation (with `'pending_lock_finalization'` as a brief\n\t// intermediate during on-chain lock creation). All three names\n\t// map to the same awaiting-acceptance phase; without explicit\n\t// branches the walker falls through to \"Delegation is ACCEPTED\n\t// — move to work layer\" prematurely, producing hints pointing\n\t// one step ahead of reality and downstream\n\t// `WORK_DELEGATION_NOT_ACTIVE` errors.\n\t// `pending_lock_finalization` resolves automatically to `offered`\n\t// once the relayer confirms the on-chain create_lock — operator\n\t// just waits.\n\tif (latestDelegation.state === 'proposed' || latestDelegation.state === 'offered' || latestDelegation.state === 'pending_lock_finalization') {\n\t\tconst iAmOfferer = latestDelegation.offererDid === signerDid;\n\t\t// Show the ACTUAL server-emitted state in the hint so\n\t\t// operators reading `heyarp status` + `heyarp delegations\n\t\t// <rel-id>` side-by-side see the same word. We quote the\n\t\t// canonical row state and only annotate with `(≡ proposed)`\n\t\t// when the FSM-walker alias collapses an `offered` or\n\t\t// `pending_lock_finalization` row into the PROPOSED branch.\n\t\tconst stateLabel = latestDelegation.state === 'proposed' ? 'PROPOSED' : `${latestDelegation.state.toUpperCase()} (≡ proposed)`;\n\t\treturn {\n\t\t\thint: iAmOfferer\n\t\t\t\t? `Delegation ${latestDelegation.delegationId} is ${stateLabel} — counterparty owes \\`heyarp delegation accept\\` / \\`decline\\``\n\t\t\t\t: `Delegation ${latestDelegation.delegationId} is ${stateLabel} — you owe \\`heyarp delegation accept\\` / \\`decline\\``,\n\t\t\towner: iAmOfferer ? 'counterparty' : 'me',\n\t\t\tcomplete: false,\n\t\t};\n\t}\n\n\t// Delegation is ACCEPTED — move to work layer.\n\tif (!latestWorkLog) {\n\t\tconst iAmOfferer = latestDelegation.offererDid === signerDid;\n\t\t// The offerer is the caller — they issue work_request.\n\t\treturn {\n\t\t\thint: iAmOfferer\n\t\t\t\t? `Delegation ${latestDelegation.delegationId} is ACCEPTED — you owe \\`heyarp work request <peer> ${latestDelegation.delegationId} --request-id <new-uuid> --params '{…}'\\``\n\t\t\t\t: `Delegation ${latestDelegation.delegationId} is ACCEPTED — counterparty (the caller) owes \\`heyarp work request\\``,\n\t\t\towner: iAmOfferer ? 'me' : 'counterparty',\n\t\t\tcomplete: false,\n\t\t};\n\t}\n\tif (latestWorkLog.state === 'requested') {\n\t\tconst iAmPayee = latestWorkLog.payeeDid === signerDid;\n\t\treturn {\n\t\t\thint: iAmPayee\n\t\t\t\t? `work_request ${latestWorkLog.requestId} is REQUESTED — you owe \\`heyarp work respond\\` (output OR --error)`\n\t\t\t\t: `work_request ${latestWorkLog.requestId} is REQUESTED — counterparty (payee) owes \\`heyarp work respond\\``,\n\t\t\towner: iAmPayee ? 'me' : 'counterparty',\n\t\t\tcomplete: false,\n\t\t};\n\t}\n\n\t// work_log is RESPONDED — move to receipt layer.\n\tif (!latestReceipt) {\n\t\tconst iAmPayee = latestWorkLog.payeeDid === signerDid;\n\t\treturn {\n\t\t\thint: iAmPayee\n\t\t\t\t? // --auto-hashes is the canonical path. It pulls\n\t\t\t\t\t// request / response canonical hashes from the\n\t\t\t\t\t// work_log row at (--rel-id, --request-id) — no\n\t\t\t\t\t// manual sha256. Note that `heyarp work-list`\n\t\t\t\t\t// surfaces delegationId + requestId, NOT the\n\t\t\t\t\t// hashes, so callers can't grep them from there.\n\t\t\t\t\t`work_response landed — you (payee) owe \\`heyarp receipt propose <caller> ${latestDelegation.delegationId} --auto-hashes --rel-id ${latestWorkLog.relationshipId} --request-id ${latestWorkLog.requestId} --verdict accepted\\``\n\t\t\t\t: // Direct the caller to the wait pattern up front\n\t\t\t\t\t// so they don't reflexively try to propose the\n\t\t\t\t\t// receipt themselves (propose is payee-only and\n\t\t\t\t\t// the CLI fail-fasts on it, but it's cleaner to\n\t\t\t\t\t// pre-empt the footgun in the hint).\n\t\t\t\t\t`work_response landed — counterparty (payee) owes \\`heyarp receipt propose\\`. You (caller): wait via \\`heyarp status ${latestWorkLog.relationshipId} --wait --until receipt.proposed\\` then \\`heyarp receipt cosign\\` (do NOT call propose yourself — that is payee-only).`,\n\t\t\towner: iAmPayee ? 'me' : 'counterparty',\n\t\t\tcomplete: false,\n\t\t};\n\t}\n\tif (latestReceipt.state === 'proposed') {\n\t\tconst iAmCaller = latestReceipt.callerDid === signerDid;\n\t\treturn {\n\t\t\thint: iAmCaller\n\t\t\t\t? `Receipt PROPOSED — you (caller) owe \\`heyarp receipt cosign <rel-id> ${latestReceipt.delegationId} ${latestReceipt.requestHash} ${latestReceipt.responseHash}\\``\n\t\t\t\t: `Receipt PROPOSED — counterparty (caller) owes \\`heyarp receipt cosign\\``,\n\t\t\towner: iAmCaller ? 'me' : 'counterparty',\n\t\t\tcomplete: false,\n\t\t};\n\t}\n\t// receipt.state === 'cosigned' → DONE.\n\treturn { hint: 'Cycle COMPLETE — receipt cosigned, payment proven on chain', owner: 'none', complete: true };\n}\n\n/**\n * Render a `StatusSummary` for human display. Exported for testability.\n *\n * Surfaces the rolled-up cycle state at the TOP of the report\n * (\"Cycle: COMPLETE\" / \"Cycle: ACTIVE\" / \"Cycle: CLOSED\" / \"Cycle:\n * NOT FOUND\") so the operator sees the answer to \"is this thing\n * done?\" before scrolling past the per-entity sections. The footer's\n * \"✓ Cycle complete.\" line stays as the detailed marker; this is\n * the executive summary.\n */\n/**\n * One-line snapshot of the FSM-layer state for `--wait-verbose`\n * per-tick output. Compact intentionally — the line wraps a single\n * `[--wait tick N/M]` log; the full report would be 10+ lines per\n * tick.\n *\n * Exported for unit tests.\n */\nexport function formatPhaseSnapshot(s: StatusSummary): string {\n\tconst parts: string[] = [];\n\tparts.push(`contract=${s.latestContract?.state ?? '∅'}`);\n\tparts.push(`delegation=${s.latestDelegation?.state ?? '∅'}`);\n\tif (s.latestWorkLog) parts.push(`work=${s.latestWorkLog.state}`);\n\tif (s.latestReceipt) parts.push(`receipt=${s.latestReceipt.state}`);\n\treturn parts.join(', ');\n}\n\nexport function formatStatusReport(s: StatusSummary): string {\n\tconst lines: string[] = [];\n\t// Top-line rolled-up state.\n\tlines.push(cycleHeadline(s));\n\tlines.push('');\n\tlines.push(chalk.bold('Relationship'));\n\tlines.push(` state: ${stateColor(s.relationshipState)}`);\n\tif (s.counterpartyDid) lines.push(` counterparty: ${chalk.cyan(s.counterpartyDid)}`);\n\n\tlines.push('');\n\tlines.push(chalk.bold('Latest contract'));\n\tif (s.latestContract) {\n\t\tlines.push(` ${s.latestContract.contractId} v${s.latestContract.version} state=${stateColor(s.latestContract.state)}`);\n\t\tlines.push(` proposer: ${chalk.cyan(s.latestContract.proposerDid)}`);\n\t\tif (s.latestContract.scopeSummary) lines.push(` scope: ${s.latestContract.scopeSummary}`);\n\t} else {\n\t\tlines.push(chalk.dim(' (none)'));\n\t}\n\n\tlines.push('');\n\tlines.push(chalk.bold('Latest delegation'));\n\tif (s.latestDelegation) {\n\t\tlines.push(` ${s.latestDelegation.delegationId} state=${stateColor(s.latestDelegation.state)}`);\n\t\tlines.push(` offerer: ${chalk.cyan(s.latestDelegation.offererDid)}`);\n\t\tif (s.latestDelegation.title) lines.push(` title: ${s.latestDelegation.title}`);\n\t} else {\n\t\tlines.push(chalk.dim(' (none)'));\n\t}\n\n\tlines.push('');\n\tlines.push(chalk.bold('Latest work_log'));\n\tif (s.latestWorkLog) {\n\t\tlines.push(` request_id=${s.latestWorkLog.requestId} state=${stateColor(s.latestWorkLog.state)}`);\n\t} else {\n\t\tlines.push(chalk.dim(' (none)'));\n\t}\n\n\tlines.push('');\n\tlines.push(chalk.bold('Latest receipt'));\n\tif (s.latestReceipt) {\n\t\tlines.push(` state=${stateColor(s.latestReceipt.state)} verdict=${s.latestReceipt.verdictFinal ?? s.latestReceipt.verdictProposed}`);\n\t} else {\n\t\tlines.push(chalk.dim(' (none)'));\n\t}\n\n\tlines.push('');\n\tlines.push(chalk.bold('Next action'));\n\tconst ownerLabel =\n\t\ts.nextActionOwner === 'me'\n\t\t\t? chalk.green('me')\n\t\t\t: s.nextActionOwner === 'counterparty'\n\t\t\t\t? chalk.yellow('counterparty')\n\t\t\t\t: s.nextActionOwner === 'either'\n\t\t\t\t\t? chalk.cyan('either side')\n\t\t\t\t\t: chalk.dim('—');\n\tlines.push(` whose turn: ${ownerLabel}`);\n\tlines.push(` hint: ${s.nextActionHint}`);\n\tif (s.cycleComplete) lines.push(` ${chalk.green('✓ Cycle complete.')}`);\n\n\treturn lines.join('\\n');\n}\n\n/**\n * Rolled-up \"where am I overall?\" line. Distinct from the per-entity\n * state cells below so the operator can scan the top of the report\n * and immediately know whether to act.\n *\n * • COMPLETE — receipt cosigned, cycle done.\n * • ACTIVE — relationship active + ongoing work.\n * • PAUSED — relationship is paused (operator intervention needed).\n * • CLOSED — relationship is closed (terminal).\n * • PENDING — fresh relationship awaiting handshake_response.\n * • NOT FOUND — relationship doesn't exist or signer is not a member.\n * • UNKNOWN — best-effort recovery (membership confirmed but state\n * not directly readable).\n *\n * Exported for unit tests.\n */\nexport function cycleHeadline(s: StatusSummary): string {\n\tif (s.cycleComplete) {\n\t\treturn `${chalk.bold('Cycle:')} ${chalk.green.bold('COMPLETE')} ${chalk.dim('— receipt cosigned, payment proven on chain')}`;\n\t}\n\tswitch (s.relationshipState) {\n\t\tcase 'not_found':\n\t\t\treturn `${chalk.bold('Cycle:')} ${chalk.red.bold('NOT FOUND')} ${chalk.dim('— relationship missing or signer is not a member')}`;\n\t\tcase 'unknown':\n\t\t\treturn `${chalk.bold('Cycle:')} ${chalk.yellow.bold('UNKNOWN')} ${chalk.dim('— state probe inconclusive; hint below is advisory')}`;\n\t\tcase 'closed':\n\t\t\treturn `${chalk.bold('Cycle:')} ${chalk.red.bold('CLOSED')} ${chalk.dim('— relationship terminal, no further protocol action')}`;\n\t\tcase 'paused':\n\t\t\treturn `${chalk.bold('Cycle:')} ${chalk.yellow.bold('PAUSED')} ${chalk.dim('— relationship soft-disabled, resume to continue')}`;\n\t\tcase 'pending':\n\t\t\treturn `${chalk.bold('Cycle:')} ${chalk.yellow.bold('PENDING')} ${chalk.dim('— awaiting handshake_response')}`;\n\t\tcase 'active':\n\t\tdefault:\n\t\t\treturn `${chalk.bold('Cycle:')} ${chalk.cyan.bold('ACTIVE')} ${chalk.dim('— work in progress; see \"Next action\" below')}`;\n\t}\n}\n\nfunction stateColor(state: string): string {\n\tconst c =\n\t\tstate === 'active' || state === 'accepted' || state === 'cosigned' || state === 'responded' || state === 'completed'\n\t\t\t? chalk.green\n\t\t\t: state === 'pending' || state === 'proposed' || state === 'requested' || state === 'offered' || state === 'pending_lock_finalization' || state === 'awaiting_release_finalization'\n\t\t\t\t? chalk.yellow\n\t\t\t\t: state === 'closed' ||\n\t\t\t\t\t state === 'declined' ||\n\t\t\t\t\t state === 'canceled' ||\n\t\t\t\t\t state === 'replaced' ||\n\t\t\t\t\t state === 'not_found' ||\n\t\t\t\t\t // Terminal failure states deserve the same red\n\t\t\t\t\t // treatment as declined/canceled so an operator\n\t\t\t\t\t // scanning `heyarp status` immediately sees\n\t\t\t\t\t // \"this is dead, don't follow the hint blindly\".\n\t\t\t\t\t state === 'failed' ||\n\t\t\t\t\t state === 'refunded' ||\n\t\t\t\t\t state === 'dispute_resolved'\n\t\t\t\t\t? chalk.red\n\t\t\t\t\t: chalk.cyan;\n\treturn c(state);\n}\n","import chalk from 'chalk';\nimport type { Command } from 'commander';\nimport { ArpApiClient, type ContractPublic, type ListContractsQuery } from '../api';\nimport { printJsonArray, printVerbose } from '../format';\nimport { type AgentLocalState, resolveSenderAgent } from '../state';\nimport { makeSigner } from './lifecycle';\n\n// Exported alongside `runContracts` for test coverage of the\n// --verbose / --json mutual-exclusion guard.\nexport interface ContractsOptions {\n\tserver?: string;\n\tstate?: string;\n\tafter?: string;\n\tlimit?: string;\n\tfromDid?: string;\n\tverbose?: boolean;\n\tjson?: boolean;\n\tfullIds?: boolean;\n}\n\nconst ALLOWED_STATES = new Set(['proposed', 'active', 'replaced', 'declined']);\n\n/**\n * `heyarp contracts <relationship-id>` — list the contract timeline\n * for a relationship via signed\n * `GET /v1/relationships/:id/contracts`. Member-only on the server\n * (signer must be one of `pairDidA` / `pairDidB`); rows are\n * ordered chronologically with `_id` as the deterministic\n * tie-breaker. Pagination cursor: `--after <id>` from the previous\n * page's last row.\n */\nexport function registerContractsCommand(root: Command): void {\n\troot.command('contracts')\n\t\t.description('List contracts for a relationship (one row per (contractId, version), oldest-first)')\n\t\t.argument('<relationship-id>', 'Relationship UUID')\n\t\t.option('--server <url>', 'Override ARP server base URL')\n\t\t.option('--state <s>', 'Filter by exact state (proposed|active|replaced|declined)')\n\t\t.option('--after <id>', \"Cursor: pass the previous page's last `id` to fetch the next page\")\n\t\t.option('--limit <n>', 'Max rows to return (1..100)', '20')\n\t\t.option('--from-did <did>', 'Signer DID — required only if multiple agents are registered against this server')\n\t\t.option(\n\t\t\t'--verbose',\n\t\t\t'After the one-line summaries, print a framed \"Full contract payloads (N rows)\" block — each row labelled with full contractId + version + state and dumped as JSON. Mutually exclusive with --json.',\n\t\t\tfalse,\n\t\t)\n\t\t.option('--json', 'Machine-readable mode — emit a single JSON array of contract rows, no chalk, no summary. Pipe-safe. Mutually exclusive with --verbose.', false)\n\t\t.option('--full-ids', 'Print contractId / DIDs in full (no `aabbccdd...90ab` truncation). Use when you want to copy-paste an id straight into the next command.', false)\n\t\t.action(async (relationshipId: string, opts: ContractsOptions) => {\n\t\t\tawait runContracts(relationshipId, opts);\n\t\t});\n}\n\n// Exported for regression-test coverage of the --verbose path.\nexport async function runContracts(relationshipId: string, opts: ContractsOptions): Promise<void> {\n\t// --verbose and --json are mutually exclusive.\n\tif (opts.verbose && opts.json) {\n\t\tthrow new Error(\n\t\t\t'contracts: --verbose and --json are mutually exclusive. --json already emits the full payload; --verbose adds the framed dump on top of the human summary.',\n\t\t);\n\t}\n\tconst limit = parseLimit(opts.limit);\n\tconst state = parseState(opts.state);\n\n\tconst api = new ArpApiClient(opts.server);\n\tconst sender = resolveSenderAgent('contracts', opts.server, opts.fromDid);\n\t// Prelude is gated on `!--json` so a `… --json | jq` pipeline\n\t// gets pure JSON on stdout.\n\tif (!opts.json) {\n\t\tconsole.log(chalk.dim(`Server: ${api.serverUrl}`));\n\t\tconsole.log(chalk.dim(`Signer: ${sender.did}`));\n\t\tconsole.log(chalk.dim(`Relationship: ${relationshipId}`));\n\t}\n\n\tconst query: ListContractsQuery = { limit };\n\tif (state) query.state = state;\n\tif (opts.after) query.after = opts.after;\n\n\tconst signer = makeSigner(sender);\n\tconst rows = await api.listContracts(relationshipId, signer, query);\n\n\tif (opts.json) {\n\t\tprintJsonArray(rows);\n\t\treturn;\n\t}\n\n\tif (rows.length === 0) {\n\t\tconsole.log(chalk.dim('\\n(no contracts for this relationship)'));\n\t\treturn;\n\t}\n\n\tconsole.log('');\n\tfor (const c of rows) {\n\t\tconsole.log(formatContractLine(c, sender.did, { fullIds: !!opts.fullIds }));\n\t}\n\n\tif (opts.verbose) {\n\t\tprintVerbose(rows, 'Full contract payloads:', (c) => ({\n\t\t\tprimary: `v${c.version} state=${c.state}`,\n\t\t\t// Full contractId is what `contract sign / counter / decline`\n\t\t\t// expect — surface inline so the operator doesn't have to\n\t\t\t// dig into the JSON below.\n\t\t\tsecondary: `contractId=${c.contractId}`,\n\t\t}));\n\t}\n\n\tconst lastId = rows[rows.length - 1].id;\n\tconsole.log(chalk.dim(`\\n${rows.length} contract row(s). Paginate with --after ${lastId}.`));\n}\n\n/**\n * One-line summary per contract row:\n *\n * contractId-head@vN state proposer rate (currency unit) scope\n *\n * \"proposer\" reads `me` / `other` relative to the signer so the\n * operator can spot at a glance who sent each version. Rate +\n * scope are echoed when present so the timeline is readable\n * without `--verbose`.\n *\n * Exported for unit tests.\n */\nexport function formatContractLine(c: ContractPublic, selfDid: string, opts: { fullIds?: boolean } = {}): string {\n\tconst id = opts.fullIds ? c.contractId : idHead(c.contractId);\n\tconst idAndVersion = `${chalk.bold(`${id}@v${c.version}`)}`;\n\tconst state = colorState(c.state).padEnd(stateColumnWidth());\n\tconst proposer = c.proposerDid === selfDid ? chalk.bold('me') : chalk.dim(opts.fullIds ? c.proposerDid : didHead(c.proposerDid));\n\tconst rate = formatRate(c);\n\tconst scope = c.scopeSummary ? chalk.dim(`\"${truncate(c.scopeSummary, 40)}\"`) : chalk.dim('(no scope)');\n\t// Append the decline reason to DECLINED rows so the operator\n\t// doesn't need `--verbose` / `--json` to see why a contract\n\t// closed. Both fields are nullable; render only what's\n\t// present.\n\tlet declineSuffix = '';\n\tif (c.state === 'declined' && c.declineReason) {\n\t\tconst detail = c.declineReasonDetail ? `: ${truncate(c.declineReasonDetail, 40)}` : '';\n\t\tdeclineSuffix = ` ${chalk.dim(`(reason: ${c.declineReason}${detail})`)}`;\n\t}\n\treturn `${idAndVersion} ${state} ${proposer} ${rate} ${scope}${declineSuffix}`;\n}\n\nfunction colorState(s: ContractPublic['state']): string {\n\tswitch (s) {\n\t\tcase 'proposed':\n\t\t\treturn chalk.yellow('proposed');\n\t\tcase 'active':\n\t\t\treturn chalk.green('active ');\n\t\tcase 'replaced':\n\t\t\treturn chalk.dim('replaced');\n\t\tcase 'declined':\n\t\t\treturn chalk.red('declined');\n\t}\n}\n\nfunction stateColumnWidth(): number {\n\t// Longest visible state label is \"declined\" / \"proposed\" / \"replaced\"\n\t// — all 8 chars; \"active\" is padded above.\n\treturn 8;\n}\n\nfunction formatRate(c: ContractPublic): string {\n\tif (!c.rateAmount) return chalk.dim('(no rate)');\n\t// Prefer the human-friendly `symbol` hint when present (e.g.\n\t// \"USDC\"); fall back to the CAIP-19 `asset_id` so the line is\n\t// never opaque. A short `?` placeholder reads worse than the full\n\t// id even when the latter is verbose — operators can grep on\n\t// `asset_id` substrings.\n\tconst currency = c.rateCurrency ? (c.rateCurrency.symbol ?? c.rateCurrency.assetId) : '?';\n\tconst unit = c.rateUnit ? `/${c.rateUnit}` : '';\n\treturn chalk.cyan(`${c.rateAmount} ${currency}${unit}`);\n}\n\nfunction idHead(id: string): string {\n\tif (id.length <= 12) return id;\n\treturn `${id.slice(0, 8)}...${id.slice(-4)}`;\n}\n\nfunction didHead(did: string): string {\n\tif (did.length <= 20) return did;\n\treturn `${did.slice(0, 20)}...`;\n}\n\nfunction truncate(s: string, max: number): string {\n\tif (s.length <= max) return s;\n\treturn `${s.slice(0, max - 3)}...`;\n}\n\nexport function parseState(raw: string | undefined): ContractPublic['state'] | undefined {\n\tif (raw === undefined) return undefined;\n\tif (!ALLOWED_STATES.has(raw)) {\n\t\tthrow new Error(`contracts: --state must be one of proposed|active|replaced|declined (got '${raw}')`);\n\t}\n\treturn raw as ContractPublic['state'];\n}\n\nexport function parseLimit(raw: string | undefined): number {\n\tif (raw === undefined) return 20;\n\tconst n = Number(raw);\n\tif (!Number.isFinite(n) || !Number.isInteger(n) || n < 1 || n > 100) {\n\t\tthrow new Error(`contracts: --limit must be an integer between 1 and 100 (got '${raw}')`);\n\t}\n\treturn n;\n}\n","import chalk from 'chalk';\nimport type { Command } from 'commander';\nimport { ArpApiClient, type DelegationPublic, type ListDelegationsQuery } from '../api';\nimport { printJsonArray, printVerbose } from '../format';\nimport { type AgentLocalState, resolveSenderAgent } from '../state';\nimport { makeSigner } from './lifecycle';\n\n// Exported alongside `runDelegations` so tests can construct opts\n// without the looser `Parameters<typeof runX>[1]` cast (which would\n// hide a future signature drift).\nexport interface DelegationsOptions {\n\tserver?: string;\n\tstate?: string;\n\tcontractId?: string;\n\tafter?: string;\n\tlimit?: string;\n\tfromDid?: string;\n\tverbose?: boolean;\n\tjson?: boolean;\n\tfullIds?: boolean;\n}\n\nconst ALLOWED_STATES = new Set(['proposed', 'accepted', 'declined', 'canceled']);\n\n/**\n * `heyarp delegations <relationship-id>` — list the delegation\n * timeline for a relationship via signed\n * `GET /v1/relationships/:id/delegations`. Member-only on the\n * server (signer must be one of `pairDidA` / `pairDidB`); rows are\n * ordered chronologically (oldest-first) with the same composite\n * `(createdAt, _id)` cursor as the contracts list.\n *\n * `--contract-id` narrows to delegations operating under a single\n * contract umbrella (one ACTIVE contract can host many delegations).\n */\nexport function registerDelegationsCommand(root: Command): void {\n\troot.command('delegations')\n\t\t.description('List delegations for a relationship (one row per delegationId, oldest-first)')\n\t\t.argument('<relationship-id>', 'Relationship UUID')\n\t\t.option('--server <url>', 'Override ARP server base URL')\n\t\t.option('--state <s>', 'Filter by exact state (proposed|accepted|declined|canceled)')\n\t\t.option('--contract-id <uuid>', 'Narrow to delegations operating under a specific contract id')\n\t\t.option('--after <id>', \"Cursor: pass the previous page's last `id` to fetch the next page\")\n\t\t.option('--limit <n>', 'Max rows to return (1..100)', '20')\n\t\t.option('--from-did <did>', 'Signer DID — required only if multiple agents are registered against this server')\n\t\t.option(\n\t\t\t'--verbose',\n\t\t\t'After the one-line summaries, print a framed \"Full delegation payloads (N rows)\" block — each row labelled with full delegationId + contractId (`delegation accept` / `delegation decline` / `work request` need them) and dumped as JSON. Mutually exclusive with --json.',\n\t\t\tfalse,\n\t\t)\n\t\t.option('--json', 'Machine-readable mode — emit a single JSON array of delegation rows, no chalk, no summary. Pipe-safe. Mutually exclusive with --verbose.', false)\n\t\t.option('--full-ids', 'Print delegationId / contractId / DIDs in full (no truncation). Use when you want to copy-paste an id straight into the next command.', false)\n\t\t.action(async (relationshipId: string, opts: DelegationsOptions) => {\n\t\t\tawait runDelegations(relationshipId, opts);\n\t\t});\n}\n\n// Exported so tests can drive the full flow + spy on console.log to\n// assert the verbose dump renders.\nexport async function runDelegations(relationshipId: string, opts: DelegationsOptions): Promise<void> {\n\t// --verbose and --json are mutually exclusive. --json\n\t// short-circuits and would otherwise silently ignore --verbose.\n\t// Surface the conflict so a user who passed both gets a clean\n\t// error rather than thinking --verbose did nothing.\n\tif (opts.verbose && opts.json) {\n\t\tthrow new Error(\n\t\t\t'delegations: --verbose and --json are mutually exclusive. --json already emits the full payload; --verbose adds the framed dump on top of the human summary.',\n\t\t);\n\t}\n\tconst limit = parseLimit(opts.limit);\n\tconst state = parseState(opts.state);\n\n\tconst api = new ArpApiClient(opts.server);\n\tconst sender = resolveSenderAgent('delegations', opts.server, opts.fromDid);\n\t// Prelude is gated on `!--json` so a `… --json | jq` pipeline\n\t// gets pure JSON on stdout.\n\tif (!opts.json) {\n\t\tconsole.log(chalk.dim(`Server: ${api.serverUrl}`));\n\t\tconsole.log(chalk.dim(`Signer: ${sender.did}`));\n\t\tconsole.log(chalk.dim(`Relationship: ${relationshipId}`));\n\t}\n\n\tconst query: ListDelegationsQuery = { limit };\n\tif (state) query.state = state;\n\tif (opts.contractId) query.contractId = opts.contractId;\n\tif (opts.after) query.after = opts.after;\n\n\tconst signer = makeSigner(sender);\n\tconst rows = await api.listDelegations(relationshipId, signer, query);\n\n\tif (opts.json) {\n\t\tprintJsonArray(rows);\n\t\treturn;\n\t}\n\n\tif (rows.length === 0) {\n\t\tconsole.log(chalk.dim('\\n(no delegations for this relationship)'));\n\t\treturn;\n\t}\n\n\tconsole.log('');\n\tfor (const d of rows) {\n\t\tconsole.log(formatDelegationLine(d, sender.did, { fullIds: !!opts.fullIds }));\n\t}\n\n\tif (opts.verbose) {\n\t\tprintVerbose(rows, 'Full delegation payloads:', (d) => ({\n\t\t\tprimary: `state=${d.state}`,\n\t\t\t// Full delegationId is what `delegation accept / decline /\n\t\t\t// cancel` and `work request` need.\n\t\t\tsecondary: `delegationId=${d.delegationId} contractId=${d.contractId}`,\n\t\t}));\n\t}\n\n\tconst lastId = rows[rows.length - 1].id;\n\tconsole.log(chalk.dim(`\\n${rows.length} delegation row(s). Paginate with --after ${lastId}.`));\n}\n\n/**\n * One-line summary per delegation row:\n *\n * delegationId-head state offerer amount title\n *\n * Exported for unit tests.\n */\nexport function formatDelegationLine(d: DelegationPublic, selfDid: string, opts: { fullIds?: boolean } = {}): string {\n\tconst idHead_ = chalk.bold(opts.fullIds ? d.delegationId : idHead(d.delegationId));\n\tconst state = colorState(d.state).padEnd(stateColumnWidth());\n\tconst offerer = d.offererDid === selfDid ? chalk.bold('me') : chalk.dim(opts.fullIds ? d.offererDid : didHead(d.offererDid));\n\tconst amount = formatAmount(d);\n\tconst title = d.title ? chalk.dim(`\"${truncate(d.title, 40)}\"`) : chalk.dim('(no title)');\n\t// Append the decline reason on DECLINED rows so operators don't\n\t// need `--verbose` / `--json` to investigate why a delegation\n\t// closed. Same pattern as the contracts listing.\n\tlet declineSuffix = '';\n\tif (d.state === 'declined' && d.declineReason) {\n\t\tconst detail = d.declineReasonDetail ? `: ${truncate(d.declineReasonDetail, 40)}` : '';\n\t\tdeclineSuffix = ` ${chalk.dim(`(reason: ${d.declineReason}${detail})`)}`;\n\t}\n\t// `delegation accept` uses `delegationId`; `contracts list --after`\n\t// uses `contractId`. Both are useful copy-paste targets when the\n\t// operator runs `--full-ids`; surface the parent contractId on a\n\t// continuation line so the listing is self-sufficient.\n\tconst contractTail = opts.fullIds ? `\\n ${chalk.dim('contractId:')} ${chalk.cyan(d.contractId)}` : '';\n\treturn `${idHead_} ${state} ${offerer} ${amount} ${title}${declineSuffix}${contractTail}`;\n}\n\nfunction colorState(s: DelegationPublic['state']): string {\n\tswitch (s) {\n\t\tcase 'proposed':\n\t\t\treturn chalk.yellow('proposed');\n\t\t// `offered` is the server's actual emitted state immediately\n\t\t// after `delegation offer`; `pending_lock_finalization` is the\n\t\t// transient state while the relayer submits create_lock. Both\n\t\t// must have explicit branches here — without them, `colorState`\n\t\t// returns `undefined` and `formatDelegationLine` crashes with\n\t\t// `TypeError: Cannot read properties of undefined (reading\n\t\t// 'padEnd')` on any listing containing such a row.\n\t\tcase 'offered':\n\t\t\treturn chalk.yellow('offered');\n\t\tcase 'pending_lock_finalization':\n\t\t\treturn chalk.yellow('pending_lock');\n\t\tcase 'accepted':\n\t\t\treturn chalk.green('accepted');\n\t\tcase 'declined':\n\t\t\treturn chalk.red('declined');\n\t\tcase 'canceled':\n\t\t\treturn chalk.dim('canceled');\n\t\tdefault: {\n\t\t\t// Defensive fallback: if the server adds another state to the\n\t\t\t// FSM and the CLI is one release behind, render the raw value\n\t\t\t// instead of crashing. The exhaustiveness assertion below\n\t\t\t// catches the same gap at compile time.\n\t\t\tconst _exhaustive: never = s;\n\t\t\tvoid _exhaustive;\n\t\t\treturn String(s);\n\t\t}\n\t}\n}\n\nfunction stateColumnWidth(): number {\n\t// Longest rendered state label is 'pending_lock' (12 chars — we\n\t// alias `pending_lock_finalization` down to it for column hygiene).\n\t// All other states fit comfortably under this width.\n\treturn 12;\n}\n\nfunction formatAmount(d: DelegationPublic): string {\n\tif (!d.amount) return chalk.dim('(no amount)');\n\t// Prefer `symbol` when present (e.g. \"USDC\"); fall back to the\n\t// full CAIP-19 `asset_id` rather than `?` so operators always\n\t// have something greppable.\n\tconst currency = d.currency ? (d.currency.symbol ?? d.currency.assetId) : '?';\n\treturn chalk.cyan(`${d.amount} ${currency}`);\n}\n\nfunction idHead(id: string): string {\n\tif (id.length <= 12) return id;\n\treturn `${id.slice(0, 8)}...${id.slice(-4)}`;\n}\n\nfunction didHead(did: string): string {\n\tif (did.length <= 20) return did;\n\treturn `${did.slice(0, 20)}...`;\n}\n\nfunction truncate(s: string, max: number): string {\n\tif (s.length <= max) return s;\n\treturn `${s.slice(0, max - 3)}...`;\n}\n\nexport function parseState(raw: string | undefined): DelegationPublic['state'] | undefined {\n\tif (raw === undefined) return undefined;\n\tif (!ALLOWED_STATES.has(raw)) {\n\t\tthrow new Error(`delegations: --state must be one of proposed|accepted|declined|canceled (got '${raw}')`);\n\t}\n\treturn raw as DelegationPublic['state'];\n}\n\nexport function parseLimit(raw: string | undefined): number {\n\tif (raw === undefined) return 20;\n\tconst n = Number(raw);\n\tif (!Number.isFinite(n) || !Number.isInteger(n) || n < 1 || n > 100) {\n\t\tthrow new Error(`delegations: --limit must be an integer between 1 and 100 (got '${raw}')`);\n\t}\n\treturn n;\n}\n","import { isValidDid } from '@heyanon-arp/sdk';\nimport type { Command } from 'commander';\nimport { ArpApiClient } from '../api';\nimport { formatJson } from '../format';\n\n/**\n * `heyarp did-doc <did>` — public DID-document resolution. No auth, no\n * local-state lookup; just GET /v1/agents/:did/did-document and\n * pretty-print.\n */\nexport function registerDidDocCommand(root: Command): void {\n\troot.command('did-doc')\n\t\t.description('Fetch and pretty-print the DID document for a did:arp:<...>')\n\t\t.argument('<did>', 'did:arp:<base58btc> identifier')\n\t\t.option('--server <url>', 'Override ARP server base URL')\n\t\t// did-doc already emits JSON to stdout. `--json` is accepted\n\t\t// as an explicit no-op alias so scripts can pass it for\n\t\t// symmetry with `heyarp agents --json` / `heyarp delegations\n\t\t// --json` / etc. Without this, commander errors with\n\t\t// \"unknown option '--json'\".\n\t\t.option('--json', 'Emit the DID document as JSON on stdout (default; accepted for symmetry with other commands).', false)\n\t\t.action(async (did: string, opts: { server?: string; json?: boolean }) => {\n\t\t\tif (!isValidDid(did)) {\n\t\t\t\tthrow new Error(`'${did}' is not a syntactically valid did:arp identifier`);\n\t\t\t}\n\t\t\tconst api = new ArpApiClient(opts.server);\n\t\t\tconst doc = await api.getDidDocument(did);\n\t\t\tconsole.log(formatJson(doc));\n\t\t});\n}\n","import { isValidDid } from '@heyanon-arp/sdk';\nimport chalk from 'chalk';\nimport type { Command } from 'commander';\nimport { ApiError, ArpApiClient, type DidDocument } from '../api';\n\ninterface DoctorOptions {\n\tserver?: string;\n\ttimeout?: string;\n\tjson?: boolean;\n}\n\n/**\n * `heyarp doctor <did>` — liveness probe for a counterparty agent.\n *\n * Buyers waste handshake budget engaging workers that are listed\n * `publicationStatus=active` in the catalog but have a dead process\n * — `active` means LISTED, not ONLINE (see `heyarp guide` §8). A\n * cheap pre-flight ping before `send-handshake` cuts that waste.\n *\n * # What it does\n *\n * 1. Resolve `did:arp:<...>` → public DID document\n * (`GET /v1/agents/:did/did-document`, no auth).\n * 2. Pluck `serviceEndpoint` from the DID document's `service[]`\n * array (the ARPEndpoint entry).\n * 3. HEAD the endpoint with a configurable timeout (default 3 s).\n * Falls back to GET if HEAD returns 405 (some receivers don't\n * implement HEAD).\n * 4. Classify into one of four verdicts:\n * • `LIVE` — endpoint answered HTTP 2xx; worker is up AND\n * the ARP endpoint route is healthy.\n * • `REACHABLE` — endpoint answered HTTP non-2xx (404, 405, 500,\n * etc.); host's process is up but the route may\n * be misconfigured. The split between REACHABLE\n * and LIVE surfaces the difference between \"host\n * up\" and \"agent actually working\" so a wrapper\n * script can cross-check via `heyarp inbox`\n * before sending.\n * • `DORMANT` — endpoint unreachable (DNS fail, TCP refused,\n * TLS error, timeout); likely dead worker.\n * • `UNKNOWN` — DID not found OR has no endpoint published\n * (draft profile, paused worker that hasn't\n * set defaultEndpointUrl).\n *\n * # Why pure-CLI (no server proxy)\n *\n * Proxying ping through arp-server would centralise the outbound\n * request — useful when client networks are firewalled, but at the\n * cost of an SSRF surface (worker-controlled URLs evaluated\n * server-side). CLI-side ping pushes the trust + reachability\n * concern back to the operator. The DID document is the public\n * source-of-truth for the endpoint URL; the catalog already\n * advertises the same value.\n */\nexport function registerDoctorCommand(root: Command): void {\n\troot.command('doctor')\n\t\t.description('Liveness probe for a counterparty: resolve DID document + ping endpoint. No auth.')\n\t\t.argument('<did>', 'did:arp:<base58btc> of the agent to probe')\n\t\t.option('--server <url>', 'Override ARP server base URL')\n\t\t.option('--timeout <ms>', 'Endpoint ping timeout in milliseconds (1..30000)', '3000')\n\t\t.option('--json', 'Machine-readable: single JSON object on stdout. Pipe-safe.', false)\n\t\t.action(async (did: string, opts: DoctorOptions) => {\n\t\t\tawait runDoctor(did, opts);\n\t\t});\n}\n\n/**\n * Result of a single doctor run. Exposed via `--json` and consumed\n * by the human formatter; structured so wrappers can pivot on\n * `verdict` without re-parsing the text.\n */\nexport interface DoctorResult {\n\tdid: string;\n\tserver: string;\n\tdidDocument: { found: boolean; registeredAt?: string };\n\tendpoint: { url?: string; reachable?: boolean; httpStatus?: number; latencyMs?: number; error?: string };\n\t// Inbox-activity probe supports the LISTENING tier — an agent\n\t// with no HTTP listener but recent events flowing through its\n\t// relationships is reachable via the protocol, just not directly.\n\t// `inboxStreamActive` adds an instant signal that the agent is\n\t// holding an open SSE inbox subscription on the central server.\n\tactivity?: {\n\t\tlastEventAt: string | null;\n\t\tasOf: string;\n\t\tageSeconds: number | null;\n\t\tinboxStreamActive?: boolean;\n\t};\n\tverdict: 'LIVE' | 'LISTENING' | 'REACHABLE' | 'DORMANT' | 'UNKNOWN';\n\treason: string;\n}\n\n/**\n * How recent must `lastEventAt` be to count as LISTENING.\n * 15 minutes — tight enough that a long-idle agent doesn't get a\n * false-positive; loose enough that an autonomous LLM worker with\n * a polling cadence of a few minutes still registers.\n */\nexport const LISTENING_THRESHOLD_SECONDS = 15 * 60;\n\nasync function runDoctor(did: string, opts: DoctorOptions): Promise<void> {\n\tif (!isValidDid(did)) {\n\t\tthrow new Error(`'${did}' is not a syntactically valid did:arp identifier`);\n\t}\n\tconst timeoutMs = parseTimeout(opts.timeout);\n\tconst api = new ArpApiClient(opts.server);\n\n\tconst result = await probe(api, did, timeoutMs);\n\n\t// Print first (human or JSON), set exit code last — same exit-\n\t// status contract regardless of output mode, so wrappers like\n\t// `heyarp doctor X && heyarp send-handshake X` and\n\t// `heyarp doctor --json X | jq && heyarp send-handshake X`\n\t// both gate correctly on the verdict.\n\tif (opts.json) {\n\t\tconsole.log(JSON.stringify(result));\n\t} else {\n\t\tconsole.log(formatDoctorReport(result));\n\t}\n\t// Exit-code contract for CI wrappers:\n\t// - LIVE → exit 0 (HTTP healthy — most confident)\n\t// - LISTENING → exit 0 (inbox-active via protocol; the worker\n\t// is reacting, just not over HTTP)\n\t// - REACHABLE / DORMANT / UNKNOWN → exit 1. REACHABLE is host-up\n\t// but agent-uncertain; operators who want to gate on \"host up\n\t// at all\" should branch on the JSON verdict explicitly rather\n\t// than rely on the exit code.\n\tif (result.verdict !== 'LIVE' && result.verdict !== 'LISTENING') {\n\t\tprocess.exitCode = 1;\n\t}\n}\n\n/**\n * Pure probing function — exported for testability + reuse from\n * higher-level CLI flows that want pre-flight liveness without\n * spawning subprocesses.\n */\nexport async function probe(api: ArpApiClient, did: string, timeoutMs: number): Promise<DoctorResult> {\n\tconst base: DoctorResult = {\n\t\tdid,\n\t\tserver: api.serverUrl,\n\t\tdidDocument: { found: false },\n\t\tendpoint: {},\n\t\tverdict: 'UNKNOWN',\n\t\treason: '',\n\t};\n\n\tlet doc: DidDocument;\n\ttry {\n\t\tdoc = await api.getDidDocument(did);\n\t} catch (err) {\n\t\tif (err instanceof ApiError && err.status === 404) {\n\t\t\treturn { ...base, verdict: 'UNKNOWN', reason: 'DID not registered on this server' };\n\t\t}\n\t\t// Network / unexpected — surface as UNKNOWN with the message.\n\t\t// We don't classify a server-side outage as DORMANT for the\n\t\t// target DID (it's about US, not THEM).\n\t\treturn { ...base, verdict: 'UNKNOWN', reason: `DID document fetch failed: ${(err as Error).message}` };\n\t}\n\n\tbase.didDocument = { found: true, registeredAt: doc.metadata?.registered_at };\n\n\tconst endpointEntry = (doc.service ?? []).find((s) => s.type === 'ARPEndpoint' && typeof s.serviceEndpoint === 'string' && s.serviceEndpoint.length > 0);\n\tif (!endpointEntry) {\n\t\t// DID registered but no service URL published — owner hasn't\n\t\t// called `heyarp update --endpoint-url …` yet (still draft\n\t\t// profile, or paused before setting one).\n\t\treturn { ...base, verdict: 'UNKNOWN', reason: 'DID document has no ARPEndpoint service entry — agent has not published an endpoint URL' };\n\t}\n\tbase.endpoint.url = endpointEntry.serviceEndpoint;\n\n\tconst pingResult = await pingEndpoint(endpointEntry.serviceEndpoint, timeoutMs);\n\tbase.endpoint = { ...base.endpoint, ...pingResult };\n\n\t// Inbox-activity probe — best-effort. 404 / network failure here\n\t// just means the LISTENING tier is unavailable; we fall back to\n\t// the HTTP-only verdict. We also read `inboxStreamActive` so a\n\t// fresh worker that hasn't emitted anything yet but is holding\n\t// an open SSE inbox connection is still classified as LISTENING.\n\tlet activity: DoctorResult['activity'];\n\ttry {\n\t\tconst summary = await api.getActivitySummary(did);\n\t\tconst asOfMs = new Date(summary.asOf).getTime();\n\t\tconst lastMs = summary.lastEventAt ? new Date(summary.lastEventAt).getTime() : null;\n\t\tconst ageSeconds = lastMs !== null ? Math.max(0, Math.floor((asOfMs - lastMs) / 1000)) : null;\n\t\tactivity = {\n\t\t\tlastEventAt: summary.lastEventAt,\n\t\t\tasOf: summary.asOf,\n\t\t\tageSeconds,\n\t\t\tinboxStreamActive: summary.inboxStreamActive,\n\t\t};\n\t} catch {\n\t\t// Server might not yet expose activity-summary — silently\n\t\t// degrade to the HTTP-only classifier.\n\t\tactivity = undefined;\n\t}\n\n\tconst status = pingResult.httpStatus ?? 0;\n\tconst httpLive = pingResult.reachable && status >= 200 && status < 300;\n\tconst httpReachable = pingResult.reachable === true;\n\tconst recentlyActive = activity?.ageSeconds !== null && activity?.ageSeconds !== undefined && activity.ageSeconds <= LISTENING_THRESHOLD_SECONDS;\n\tconst inboxStreamActive = activity?.inboxStreamActive === true;\n\n\tconst result: DoctorResult = { ...base, activity };\n\n\t// Verdict priority:\n\t// 1. HTTP 2xx → LIVE (most confident — endpoint healthy)\n\t// 2a. inboxStreamActive=true → LISTENING (instant signal;\n\t// fresh workers with no outbound events yet still elevate\n\t// from DORMANT)\n\t// 2b. Recent inbox activity → LISTENING (alive via protocol\n\t// even if HTTP is unreachable or returns non-2xx)\n\t// 3. HTTP non-2xx reachable → REACHABLE (host up; agent\n\t// uncertain)\n\t// 4. unreachable, no recent activity → DORMANT\n\tif (httpLive) {\n\t\treturn { ...result, verdict: 'LIVE', reason: `endpoint responded HTTP ${status} in ${pingResult.latencyMs}ms` };\n\t}\n\tif (inboxStreamActive) {\n\t\tconst httpNote = httpReachable ? `HTTP ${status}` : `HTTP ${pingResult.error ?? 'unreachable'}`;\n\t\treturn {\n\t\t\t...result,\n\t\t\tverdict: 'LISTENING',\n\t\t\treason: `inbox-stream attached (active SSE subscription on the central server) but ${httpNote} — protocol-reachable; worker hasn't emitted events yet but is actively waiting`,\n\t\t};\n\t}\n\tif (recentlyActive) {\n\t\tconst ageStr = activity?.ageSeconds !== undefined && activity?.ageSeconds !== null ? `${activity.ageSeconds}s ago` : 'recently';\n\t\tconst httpNote = httpReachable ? `HTTP ${status}` : `HTTP ${pingResult.error ?? 'unreachable'}`;\n\t\treturn {\n\t\t\t...result,\n\t\t\tverdict: 'LISTENING',\n\t\t\treason: `inbox-active (last event ${ageStr}) but ${httpNote} — protocol-reachable via the central ARP server even without a direct HTTP listener`,\n\t\t};\n\t}\n\tif (httpReachable) {\n\t\treturn {\n\t\t\t...result,\n\t\t\tverdict: 'REACHABLE',\n\t\t\treason: `endpoint hosted at HTTP ${status} in ${pingResult.latencyMs}ms (host is up; agent liveness is separate — cross-check via \\`heyarp inbox\\` before relying on it)`,\n\t\t};\n\t}\n\treturn { ...result, verdict: 'DORMANT', reason: pingResult.error ?? 'endpoint unreachable' };\n}\n\n/**\n * HEAD-then-GET-fallback ping with an enforced timeout. Any HTTP\n * status (including 4xx / 5xx) counts as \"reachable\" — the worker\n * process is up enough to answer; whether the specific endpoint\n * route exists is a different question we don't gate liveness on.\n *\n * Exported for testability.\n */\nexport async function pingEndpoint(url: string, timeoutMs: number): Promise<{ reachable: boolean; httpStatus?: number; latencyMs?: number; error?: string }> {\n\tconst controller = new AbortController();\n\tconst timer = setTimeout(() => controller.abort(), timeoutMs);\n\tconst start = Date.now();\n\ttry {\n\t\tlet response: Response;\n\t\ttry {\n\t\t\tresponse = await fetch(url, { method: 'HEAD', signal: controller.signal });\n\t\t} catch (firstErr) {\n\t\t\t// HEAD often gets 405-rejected by Express-lite servers. Only\n\t\t\t// retry on a 405; for any other error (DNS, refused, TLS)\n\t\t\t// the second attempt would fail identically.\n\t\t\tif (firstErr instanceof Error && firstErr.name === 'AbortError') throw firstErr;\n\t\t\t// If HEAD itself errored at the transport layer (DNS, etc),\n\t\t\t// we can't distinguish \"method unsupported\" — bubble up.\n\t\t\tthrow firstErr;\n\t\t}\n\t\t// HEAD landed but the server returned 405 — fall back to GET\n\t\t// (some receivers only implement GET / POST).\n\t\tif (response.status === 405) {\n\t\t\tresponse = await fetch(url, { method: 'GET', signal: controller.signal });\n\t\t}\n\t\tconst latencyMs = Date.now() - start;\n\t\treturn { reachable: true, httpStatus: response.status, latencyMs };\n\t} catch (err) {\n\t\tconst e = err as Error;\n\t\tif (e.name === 'AbortError') {\n\t\t\treturn { reachable: false, latencyMs: Date.now() - start, error: `timeout after ${timeoutMs}ms` };\n\t\t}\n\t\treturn { reachable: false, latencyMs: Date.now() - start, error: e.message };\n\t} finally {\n\t\tclearTimeout(timer);\n\t}\n}\n\n/**\n * Render a `DoctorResult` as a multi-line operator-friendly report.\n * Exported for testability + reuse.\n */\nexport function formatDoctorReport(r: DoctorResult): string {\n\tconst lines: string[] = [];\n\tlines.push(`${chalk.dim('Server:')} ${r.server}`);\n\tlines.push(`${chalk.dim('Target DID:')} ${r.did}`);\n\tif (!r.didDocument.found) {\n\t\tlines.push(`${chalk.dim('DID doc:')} ${chalk.red('✗')} not found`);\n\t} else {\n\t\tconst registered = r.didDocument.registeredAt ? ` (registered ${r.didDocument.registeredAt})` : '';\n\t\tlines.push(`${chalk.dim('DID doc:')} ${chalk.green('✓')} resolved${registered}`);\n\t}\n\tif (r.endpoint.url) {\n\t\tlines.push(`${chalk.dim('Endpoint:')} ${r.endpoint.url}`);\n\t\tif (r.endpoint.reachable === true) {\n\t\t\tlines.push(`${chalk.dim('Ping:')} ${chalk.green('✓')} HTTP ${r.endpoint.httpStatus} in ${r.endpoint.latencyMs}ms`);\n\t\t} else if (r.endpoint.reachable === false) {\n\t\t\t// When the agent is LISTENING via the inbox-stream signal,\n\t\t\t// an HTTP ping failure is EXPECTED — the worker is using\n\t\t\t// SSE-inbox-only, not serving HTTP. Render with a dim\n\t\t\t// yellow `~` (not the red `✗`) so operators triaging\n\t\t\t// don't read it as a true failure. The Verdict line below\n\t\t\t// already explains the inbox-stream path in plain English.\n\t\t\tconst inboxOnlyListening = r.verdict === 'LISTENING' && r.activity?.inboxStreamActive === true;\n\t\t\tif (inboxOnlyListening) {\n\t\t\t\tlines.push(`${chalk.dim('Ping:')} ${chalk.yellow('~')} HTTP unreachable (expected — agent is inbox-stream-only; see Verdict)`);\n\t\t\t} else {\n\t\t\t\tlines.push(`${chalk.dim('Ping:')} ${chalk.red('✗')} ${r.endpoint.error}`);\n\t\t\t}\n\t\t}\n\t} else if (r.didDocument.found) {\n\t\tlines.push(`${chalk.dim('Endpoint:')} ${chalk.yellow('(none published)')}`);\n\t}\n\t// Surface the activity probe when the server supports it.\n\tif (r.activity) {\n\t\tif (r.activity.lastEventAt === null) {\n\t\t\tlines.push(`${chalk.dim('Activity:')} ${chalk.dim('(no events ever — fresh agent)')}`);\n\t\t} else {\n\t\t\tconst ageMin = r.activity.ageSeconds !== null ? Math.floor(r.activity.ageSeconds / 60) : null;\n\t\t\tconst ageStr = ageMin !== null && ageMin > 0 ? `${ageMin}m ago` : `${r.activity.ageSeconds}s ago`;\n\t\t\tlines.push(`${chalk.dim('Activity:')} last event ${ageStr} (${r.activity.lastEventAt})`);\n\t\t}\n\t}\n\tconst verdictColor =\n\t\tr.verdict === 'LIVE'\n\t\t\t? chalk.green\n\t\t\t: r.verdict === 'LISTENING'\n\t\t\t\t? chalk.green\n\t\t\t\t: r.verdict === 'REACHABLE'\n\t\t\t\t\t? chalk.cyan\n\t\t\t\t\t: r.verdict === 'DORMANT'\n\t\t\t\t\t\t? chalk.red\n\t\t\t\t\t\t: chalk.yellow;\n\tlines.push('');\n\tlines.push(`${chalk.bold('Verdict:')} ${verdictColor(r.verdict)} — ${r.reason}`);\n\treturn lines.join('\\n');\n}\n\n/** Parse `--timeout` into [1, 30000] ms. */\nexport function parseTimeout(raw: string | undefined): number {\n\tif (raw === undefined) return 3000;\n\tconst n = Number(raw);\n\tif (!Number.isFinite(n) || !Number.isInteger(n) || n < 1 || n > 30000) {\n\t\tthrow new Error(`doctor: --timeout must be an integer between 1 and 30000 ms (got '${raw}')`);\n\t}\n\treturn n;\n}\n","import chalk from 'chalk';\nimport type { Command } from 'commander';\nimport { ArpApiClient, type EventPublic } from '../api';\nimport { formatJson } from '../format';\nimport { resolveSenderAgent } from '../state';\nimport { makeSigner } from './lifecycle';\n\ninterface EnvelopeOptions {\n\tserver?: string;\n\tfromDid?: string;\n\tjson?: boolean;\n}\n\n/**\n * `heyarp envelope <event-id>` — fetch one canonical envelope by its\n * `eventId`. operators\n * routinely had an `eventId` (from a counterparty citation, a\n * receipt's hash bind, or an earlier `inbox` / `events` listing) and\n * wanted the full envelope without grepping a paginated list.\n *\n * Owner-only: signer must equal the resolved DID, and the DID must\n * be one of the event's pair (sender or recipient). Server returns\n * 403 + the documented `EVENT_FORBIDDEN` code on miss.\n *\n * Output is the same `EventPublicDto` shape `heyarp inbox` /\n * `heyarp events` already use, so existing parsers downstream\n * (`jq` recipes, second-tier tooling) work unchanged.\n */\nexport function registerEnvelopeCommand(root: Command): void {\n\troot.command('envelope')\n\t\t.description('Fetch one canonical envelope by eventId — full body for inspection (signed read)')\n\t\t.argument('<event-id>', 'Event UUID — copy from `heyarp inbox`, `heyarp events`, or a counterparty citation')\n\t\t.option('--server <url>', 'Override ARP server base URL')\n\t\t.option('--from-did <did>', 'Signer DID — required only if multiple agents are registered against this server')\n\t\t.option('--json', 'Machine-readable: emit only the envelope JSON object on stdout (no prelude, no chalk). Pipe-safe.', false)\n\t\t.action(async (eventId: string, opts: EnvelopeOptions) => {\n\t\t\tawait runEnvelope(eventId, opts);\n\t\t});\n}\n\nasync function runEnvelope(eventId: string, opts: EnvelopeOptions): Promise<void> {\n\tconst api = new ArpApiClient(opts.server);\n\tconst sender = resolveSenderAgent('envelope', opts.server, opts.fromDid);\n\n\tif (!opts.json) {\n\t\t// Same banner pattern as the other signed reads — gated on\n\t\t// `!--json` so a pipe gets pure JSON on stdout.\n\t\tconsole.log(chalk.dim(`Server: ${api.serverUrl}`));\n\t\tconsole.log(chalk.dim(`Signer: ${sender.did}`));\n\t\tconsole.log(chalk.dim(`Event: ${eventId}`));\n\t}\n\n\tconst signer = makeSigner(sender);\n\tconst event = await api.getEvent(sender.did, eventId, signer);\n\n\tif (opts.json) {\n\t\t// Single object on stdout — `jq` consumes it without --slurp.\n\t\t// LAST byte of stdout is `}` so pipelines can rely on it.\n\t\tconsole.log(JSON.stringify(event));\n\t\treturn;\n\t}\n\n\tconsole.log('');\n\tconsole.log(chalk.bold('Envelope:'));\n\tconsole.log(formatJson(event));\n\tconsole.log('');\n\tconsole.log(formatHints(event));\n}\n\n/**\n * Inline operator hints under the envelope dump. The fields\n * highlighted are the ones operators most commonly need to copy-paste\n * elsewhere — surface them above the noise so they don't have to grep\n * the JSON.\n *\n * Exported for testability.\n */\nexport function formatHints(event: EventPublic): string {\n\tconst lines: string[] = [];\n\tlines.push(`${chalk.dim('relationshipId:')} ${chalk.cyan(event.relationshipId)}`);\n\tlines.push(`${chalk.dim('serverEventHash:')} ${chalk.cyan(event.serverEventHash)}`);\n\tlines.push(`${chalk.dim('eventId:')} ${chalk.cyan(event.eventId)}`);\n\tlines.push(`${chalk.dim('relationshipEventIndex:')} ${chalk.cyan(String(event.relationshipEventIndex))}`);\n\treturn lines.join('\\n');\n}\n","// `heyarp escrow info` reports the on-chain protocol fee\n// configuration so operators can sanity-check before locking. The\n// contract denormalizes fee_bps + fee_recipient at create_lock time\n// (anti-retroactive-fee-theft); operators who want to lock against\n// a specific fee should verify the current config first.\n//\n// `heyarp escrow derive-condition-hash <rel-id> <contract-id>`\n// fetches a contract row and computes the canonical condition_hash\n// that the on-chain create_lock instruction binds. Output is a\n// 64-char hex string ready to paste into\n// `heyarp wallet create-lock --condition-hash <hex>`. Without this\n// helper, operators have to drop to SDK code OR use a placeholder\n// (`printf '%064d' 1`) that the validator only accepts in dev.\n\nimport { type ContractLikeInput, deriveConditionHash } from '@heyanon-arp/sdk';\nimport { bytesToHex } from '@noble/hashes/utils';\nimport chalk from 'chalk';\nimport type { Command } from 'commander';\nimport { ApiError, ArpApiClient, type ContractPublic, type ProtocolFeeStatus, type Signer } from '../api';\nimport { resolveSenderAgent, updateAgentLocal } from '../state';\nimport { requireUuidNormalised } from './delegation';\nimport { makeSigner } from './lifecycle';\n\ninterface InfoOptions {\n\tserver?: string;\n\tjson?: boolean;\n}\n\ninterface DeriveConditionHashOptions {\n\tserver?: string;\n\tfromDid?: string;\n\tversion?: string;\n\tjson?: boolean;\n}\n\ninterface RecoverSequenceOptions {\n\tserver?: string;\n\tfromDid?: string;\n\tapply?: boolean;\n\tjson?: boolean;\n}\n\nexport function registerEscrowCommands(root: Command): void {\n\tconst cmd = root.command('escrow').description('Escrow inspection — protocol fee, on-chain state, condition_hash helpers.');\n\n\tcmd.command('info')\n\t\t.description('Show the on-chain protocol fee config + cluster + pause state. Public read; no auth.')\n\t\t.option('--server <url>', 'Override ARP server base URL')\n\t\t.option('--json', 'Machine-readable JSON output', false)\n\t\t.action(async (opts: InfoOptions) => {\n\t\t\tawait runEscrowInfo(opts);\n\t\t});\n\n\tcmd.command('derive-condition-hash')\n\t\t.description(\"Compute canonical condition_hash (32-byte hex) for `heyarp wallet create-lock --condition-hash <hex>`. Fetches the contract row, projects to the canonical subset, and hashes via SDK deriveConditionHash. Mirrors what the on-chain create_lock instruction binds.\")\n\t\t.argument('<relationship-id>', 'Relationship UUID hosting the contract')\n\t\t.argument('<contract-id>', 'Contract UUID')\n\t\t.option('--server <url>', 'Override ARP server base URL')\n\t\t.option('--from-did <did>', 'Sender DID — required only if multiple agents are registered against this server')\n\t\t.option('--version <n>', 'Pin a specific contract version (default: latest non-replaced row)')\n\t\t.option('--json', 'Machine-readable JSON: {contract_id, version, condition_hash_hex, projected_subset}', false)\n\t\t.action(async (relationshipId: string, contractId: string, opts: DeriveConditionHashOptions) => {\n\t\t\tawait runDeriveConditionHash(relationshipId, contractId, opts);\n\t\t});\n\n\tcmd.command('recover-sequence')\n\t\t.description(\n\t\t\t\"Repair a desynced local `lastSenderSequence` after a post-commit failure the CLI couldn't auto-classify (e.g. `INTERNAL_SERVER_ERROR` from the global Internal filter — pre-/post-commit origin is ambiguous, so auto-advance is unsafe). Queries the server's owner-only `/sender-sequence` endpoint and compares; with --apply, updates local agent state to match. Default is dry-run — prints the diff and exits 0 if in-sync, 1 if drift detected.\",\n\t\t)\n\t\t.option('--server <url>', 'Override ARP server base URL')\n\t\t.option('--from-did <did>', 'Sender DID — required only if multiple agents are registered against this server')\n\t\t.option('--apply', 'Apply the fix (write the server-known value to local state). Default: dry-run.', false)\n\t\t.option('--json', 'Machine-readable JSON: {local, server, drift, applied}', false)\n\t\t.action(async (opts: RecoverSequenceOptions) => {\n\t\t\tawait runRecoverSequence(opts);\n\t\t});\n}\n\nasync function runEscrowInfo(opts: InfoOptions): Promise<void> {\n\tconst api = new ArpApiClient(opts.server);\n\tconst status = await api.getProtocolFee();\n\tif (opts.json) {\n\t\tconsole.log(JSON.stringify(status));\n\t} else {\n\t\tconsole.log(formatProtocolFeeStatus(api.serverUrl, status));\n\t}\n}\n\n/**\n * Format the protocol-fee status as a human-readable operator report.\n * Exported for testability — the formatter mirrors the doctor command's\n * style so both render with the same cadence.\n */\nexport function formatProtocolFeeStatus(serverUrl: string, s: ProtocolFeeStatus): string {\n\tconst lines: string[] = [];\n\tconst cluster = s.clusterTag === 0 ? 'devnet' : s.clusterTag === 1 ? 'mainnet-beta' : `unknown(${s.clusterTag})`;\n\tlines.push(`${chalk.dim('Server:')} ${serverUrl}`);\n\tlines.push(`${chalk.dim('Program ID:')} ${s.programId}`);\n\tlines.push(`${chalk.dim('Cluster:')} ${cluster} (tag=${s.clusterTag})`);\n\tlines.push(`${chalk.dim('Admin:')} ${s.admin}`);\n\tlines.push(`${chalk.dim('Paused:')} ${s.paused ? chalk.yellow('YES (new locks rejected)') : chalk.green('no')}`);\n\tlines.push('');\n\tlines.push(chalk.bold('Protocol fee:'));\n\tif (!s.enabled || s.feeBps === 0) {\n\t\tlines.push(` ${chalk.green('DISABLED')}`);\n\t\tlines.push(` ${chalk.dim('fee_bps:')} ${s.feeBps}`);\n\t\tlines.push(` ${chalk.dim('fee_recipient:')} ${s.feeRecipient}`);\n\t\tlines.push('');\n\t\tlines.push(chalk.dim(` New locks will denormalize fee_bps=0 — payee receives 100% on release.`));\n\t} else {\n\t\tconst pct = (s.feeBps / 100).toFixed(2);\n\t\tlines.push(` ${chalk.yellow('ENABLED')} — ${pct}% of payee slice (${s.feeBps} bps)`);\n\t\tlines.push(` ${chalk.dim('fee_recipient:')} ${s.feeRecipient}`);\n\t\tlines.push('');\n\t\tlines.push(chalk.dim(` New locks will denormalize fee_bps=${s.feeBps} onto themselves.`));\n\t\tlines.push(chalk.dim(` Existing locks keep their lock-time snapshot — no retroactive change.`));\n\t}\n\treturn lines.join('\\n');\n}\n\n// ---------- derive-condition-hash ----------\n\n/**\n * Page through `/v1/relationships/:id/contracts` to find a single\n * contract row matching `contractId` (and optionally `--version`).\n *\n * Selection rule:\n * - If `--version <n>` is supplied, pick the row whose\n * `(contractId, version)` matches exactly. Throw if not found.\n * - Otherwise, pick the LATEST version (max `version` field) among\n * rows with matching `contractId`. State doesn't matter — we'll\n * hash any row's terms; condition_hash is content-derived. Throw\n * if no rows match the contractId.\n *\n * Exported for unit-test coverage.\n */\nexport async function findContractRow(\n\tapi: ArpApiClient,\n\tsigner: Signer,\n\trelationshipId: string,\n\tcontractId: string,\n\tversionPin: number | undefined,\n): Promise<ContractPublic> {\n\tconst PAGE = 100;\n\tlet after: string | undefined;\n\tconst matches: ContractPublic[] = [];\n\t// Paginated walk — the relationship may have many contracts.\n\t// Bounded loop to avoid runaway; 50 pages × 100 = 5000 rows is\n\t// far beyond realistic per-relationship traffic.\n\tfor (let page = 0; page < 50; page++) {\n\t\tconst rows = await api.listContracts(relationshipId, signer, { limit: PAGE, after });\n\t\tif (rows.length === 0) break;\n\t\tfor (const r of rows) {\n\t\t\tif (r.contractId === contractId) matches.push(r);\n\t\t}\n\t\tif (rows.length < PAGE) break;\n\t\tafter = rows[rows.length - 1].id;\n\t}\n\tif (matches.length === 0) {\n\t\tthrow new Error(`escrow derive-condition-hash: no contract found with contractId=${contractId} on relationship ${relationshipId}`);\n\t}\n\tif (versionPin !== undefined) {\n\t\tconst pinned = matches.find((r) => r.version === versionPin);\n\t\tif (!pinned) {\n\t\t\tconst versions = matches.map((r) => r.version).join(', ');\n\t\t\tthrow new Error(`escrow derive-condition-hash: contract ${contractId} has no version ${versionPin} (available: ${versions})`);\n\t\t}\n\t\treturn pinned;\n\t}\n\t// Latest version wins.\n\treturn matches.reduce((best, cur) => (cur.version > best.version ? cur : best));\n}\n\n/**\n * Project a ContractPublic row to the canonical `ContractLikeInput`\n * shape that SDK `deriveConditionHash` consumes. Strips wire-only\n * fields (state, timestamps, relationshipId, decline metadata) so\n * the hash is content-only and matches the on-chain bind.\n *\n * Exported for unit-test coverage.\n */\nexport function projectContractForHash(c: ContractPublic): ContractLikeInput {\n\tconst out: ContractLikeInput = {\n\t\tcontractId: c.contractId,\n\t\tversion: c.version,\n\t\tscopeSummary: c.scopeSummary,\n\t\tpricingModel: c.pricingModel,\n\t\tsettlementModel: c.settlementModel,\n\t};\n\tif (c.rateAmount !== undefined) out.rateAmount = c.rateAmount;\n\tif (c.rateCurrency !== undefined) {\n\t\t// Wire shape uses camelCase `assetId`; SDK's `AssetIdentifier`\n\t\t// uses snake_case `asset_id` to match the on-chain canonical\n\t\t// JSON layout. Translate here so the hash matches what the\n\t\t// server / contract reconstruct.\n\t\tout.rateCurrency = {\n\t\t\tasset_id: c.rateCurrency.assetId,\n\t\t\tdecimals: c.rateCurrency.decimals,\n\t\t\t...(c.rateCurrency.symbol !== undefined ? { symbol: c.rateCurrency.symbol } : {}),\n\t\t};\n\t}\n\tif (c.rateUnit !== undefined) out.rateUnit = c.rateUnit;\n\tif (c.allowedDelegationTags !== undefined) out.allowedDelegationTags = c.allowedDelegationTags;\n\treturn out;\n}\n\nasync function runDeriveConditionHash(relationshipId: string, contractId: string, opts: DeriveConditionHashOptions): Promise<void> {\n\trelationshipId = requireUuidNormalised('escrow derive-condition-hash', relationshipId, '<relationship-id>');\n\tcontractId = requireUuidNormalised('escrow derive-condition-hash', contractId, '<contract-id>');\n\tlet versionPin: number | undefined;\n\tif (opts.version !== undefined && opts.version !== '') {\n\t\tconst n = Number.parseInt(opts.version, 10);\n\t\tif (!Number.isFinite(n) || !Number.isInteger(n) || n <= 0 || String(n) !== opts.version) {\n\t\t\tthrow new Error(`escrow derive-condition-hash: --version must be a positive integer, got '${opts.version}'`);\n\t\t}\n\t\tversionPin = n;\n\t}\n\n\tconst api = new ArpApiClient(opts.server);\n\tconst sender = resolveSenderAgent('escrow derive-condition-hash', opts.server, opts.fromDid);\n\tconst signer = makeSigner(sender);\n\n\tlet contract: ContractPublic;\n\ttry {\n\t\tcontract = await findContractRow(api, signer, relationshipId, contractId, versionPin);\n\t} catch (err) {\n\t\tif (err instanceof ApiError) {\n\t\t\tthrow new Error(`escrow derive-condition-hash: server rejected listContracts (${err.payload.code ?? err.message})`);\n\t\t}\n\t\tthrow err;\n\t}\n\n\tconst subset = projectContractForHash(contract);\n\tconst hashBytes = deriveConditionHash(subset);\n\tconst hex = bytesToHex(hashBytes);\n\n\tif (opts.json) {\n\t\tconsole.log(\n\t\t\tJSON.stringify({\n\t\t\t\tcontract_id: contract.contractId,\n\t\t\t\tversion: contract.version,\n\t\t\t\tcondition_hash_hex: hex,\n\t\t\t\tprojected_subset: subset,\n\t\t\t}),\n\t\t);\n\t\treturn;\n\t}\n\n\tconsole.log(chalk.dim(`Relationship: ${relationshipId}`));\n\tconsole.log(chalk.dim(`Contract: ${contract.contractId} (version ${contract.version}, state=${contract.state})`));\n\tconsole.log(chalk.dim('Subset hashed:'));\n\tconsole.log(chalk.dim(` scopeSummary: ${subset.scopeSummary ?? '(unset)'}`));\n\tconsole.log(chalk.dim(` pricingModel: ${subset.pricingModel ?? '(unset)'}`));\n\tconsole.log(chalk.dim(` settlementModel: ${subset.settlementModel ?? '(unset)'}`));\n\tif (subset.rateAmount !== undefined) console.log(chalk.dim(` rateAmount: ${subset.rateAmount}`));\n\tif (subset.rateCurrency !== undefined) console.log(chalk.dim(` rateCurrency.asset_id: ${subset.rateCurrency.asset_id}`));\n\tif (subset.rateUnit !== undefined) console.log(chalk.dim(` rateUnit: ${subset.rateUnit}`));\n\tif (subset.allowedDelegationTags !== undefined) console.log(chalk.dim(` allowedDelegationTags: ${JSON.stringify(subset.allowedDelegationTags)}`));\n\tconsole.log('');\n\tconsole.log(`${chalk.bold('condition_hash:')} ${hex}`);\n\tconsole.log('');\n\tconsole.log(chalk.dim(`Pass to: heyarp wallet create-lock --condition-hash ${hex} ...`));\n}\n\n// ---------- recover-sequence ----------\n\n/**\n * Pure mapping from (local, server) sender_sequence values to one of\n * three outcomes:\n *\n * - `in-sync` — local matches server; no action.\n * - `behind` — local < server; the server saw envelopes the CLI\n * didn't bump for (typical: post-commit failure\n * where the CLI couldn't classify the response as\n * POST_COMMIT-eligible, so the catch path left state\n * alone). `--apply` writes server value to local.\n * - `ahead` — local > server; impossible under normal protocol\n * flow (server is the source of truth — local should\n * never advance without a 2xx). Surface as an\n * anomaly that needs investigation; do NOT apply.\n *\n * Exported for unit tests.\n */\nexport type RecoverOutcome = { kind: 'in-sync'; value: number } | { kind: 'behind'; local: number; server: number; drift: number } | { kind: 'ahead'; local: number; server: number; drift: number };\n\nexport function classifyRecoverOutcome(local: number, server: number): RecoverOutcome {\n\tif (local === server) return { kind: 'in-sync', value: local };\n\tif (local < server) return { kind: 'behind', local, server, drift: server - local };\n\treturn { kind: 'ahead', local, server, drift: local - server };\n}\n\nasync function runRecoverSequence(opts: RecoverSequenceOptions): Promise<void> {\n\tconst sender = resolveSenderAgent('escrow recover-sequence', opts.server, opts.fromDid);\n\tconst signer = makeSigner(sender);\n\tconst api = new ArpApiClient(opts.server);\n\tconst local = sender.lastSenderSequence ?? 0;\n\n\tlet server: number;\n\ttry {\n\t\tconst resp = await api.getSenderSequence(sender.did, signer);\n\t\tserver = resp.lastSenderSequence;\n\t} catch (err) {\n\t\tif (err instanceof ApiError) {\n\t\t\tthrow new Error(`escrow recover-sequence: server rejected /sender-sequence (${err.payload.code ?? err.message})`);\n\t\t}\n\t\tthrow err;\n\t}\n\n\tconst outcome = classifyRecoverOutcome(local, server);\n\n\tif (opts.json) {\n\t\tconsole.log(\n\t\t\tJSON.stringify({\n\t\t\t\tdid: sender.did,\n\t\t\t\tlocal,\n\t\t\t\tserver,\n\t\t\t\t...(outcome.kind !== 'in-sync' ? { drift: outcome.kind === 'behind' ? outcome.drift : -outcome.drift } : {}),\n\t\t\t\tkind: outcome.kind,\n\t\t\t\tapplied: opts.apply === true && outcome.kind === 'behind',\n\t\t\t}),\n\t\t);\n\t} else {\n\t\tconsole.log(chalk.dim(`DID: ${sender.did}`));\n\t\tconsole.log(chalk.dim(`Server: ${api.serverUrl}`));\n\t\tconsole.log('');\n\t\tconsole.log(`${chalk.bold('Local lastSenderSequence:')} ${local}`);\n\t\tconsole.log(`${chalk.bold('Server lastSenderSequence:')} ${server}`);\n\t\tconsole.log('');\n\t\tif (outcome.kind === 'in-sync') {\n\t\t\tconsole.log(chalk.green('✓ In sync — no recovery needed.'));\n\t\t} else if (outcome.kind === 'behind') {\n\t\t\tconsole.log(chalk.yellow(`⚠ Local is BEHIND by ${outcome.drift}. Server has accepted envelopes the CLI didn't classify as post-commit.`));\n\t\t\tif (opts.apply) {\n\t\t\t\tconsole.log(chalk.dim('Writing server value to local state...'));\n\t\t\t} else {\n\t\t\t\tconsole.log(chalk.dim('Dry-run. Pass --apply to update local state to match server.'));\n\t\t\t}\n\t\t} else {\n\t\t\t// 'ahead' — anomaly; do NOT apply\n\t\t\tconsole.log(chalk.red(`✗ Local is AHEAD of server by ${outcome.drift}. This should not happen under normal protocol flow.`));\n\t\t\tconsole.log(chalk.dim('NOT applying — manual investigation needed. Possible causes:'));\n\t\t\tconsole.log(chalk.dim(' - Local agents.json edited by hand to a wrong value'));\n\t\t\tconsole.log(chalk.dim(' - Server data lost / rolled back'));\n\t\t\tconsole.log(chalk.dim(' - HEYARP_HOME pointed at a wrong account'));\n\t\t}\n\t}\n\n\tif (outcome.kind === 'behind' && opts.apply) {\n\t\tupdateAgentLocal(opts.server, sender.did, { lastSenderSequence: outcome.server });\n\t\tif (!opts.json) console.log(chalk.green(`✓ Local lastSenderSequence updated: ${local} → ${outcome.server}`));\n\t}\n\n\t// Exit non-zero on drift so wrapping shell scripts can branch.\n\t// In-sync = 0; behind without --apply = 1 (drift detected, not fixed);\n\t// behind with --apply = 0 (fixed); ahead = 2 (anomaly, never applied).\n\tif (outcome.kind === 'behind' && !opts.apply) process.exitCode = 1;\n\tif (outcome.kind === 'ahead') process.exitCode = 2;\n}\n","import chalk from 'chalk';\nimport type { Command } from 'commander';\nimport { ArpApiClient, type EventPublic, type ListEventsQuery } from '../api';\nimport { printJsonArray, printVerbose } from '../format';\nimport { type AgentLocalState, resolveSenderAgent } from '../state';\nimport { makeSigner } from './lifecycle';\n\n// exported alongside `runEvents` for mutual-exclusion test coverage.\nexport interface EventsOptions {\n\tserver?: string;\n\tsince?: string;\n\tlimit?: string;\n\tfromDid?: string;\n\tverbose?: boolean;\n\tjson?: boolean;\n\tfullIds?: boolean;\n\tsuccessOnly?: boolean;\n\trejectedOnly?: boolean;\n}\n\n/**\n * `heyarp events <relationship-id>` — list the canonical event chain for\n * a relationship, ordered ascending by `relationshipEventIndex`. Signer\n * must be one of the relationship pair, so this command resolves a\n * `--from-did` (or auto-picks the only local agent for the server)\n * before issuing the signed read.\n */\nexport function registerEventsCommand(root: Command): void {\n\troot.command('events')\n\t\t.description('List events for a relationship (chain order, ascending index)')\n\t\t.argument('<relationship-id>', 'Relationship UUID')\n\t\t.option('--server <url>', 'Override ARP server base URL')\n\t\t.option('--since <n>', 'Cursor: only events with relationshipEventIndex >= since')\n\t\t.option('--limit <n>', 'Max events to return (1..100)', '20')\n\t\t.option('--from-did <did>', 'Signer DID — required only if multiple agents are registered against this server')\n\t\t.option(\n\t\t\t'--verbose',\n\t\t\t'After the summary table, print a framed \"Full event payloads (N rows)\" block — each event labelled with full eventId + serverEventHash and dumped as JSON. Mutually exclusive with --json.',\n\t\t\tfalse,\n\t\t)\n\t\t.option(\n\t\t\t'--json',\n\t\t\t// The human row labels are display-only and don't map 1:1\n\t\t\t// to wire keys (e.g. `signer` vs `senderDid`, the absence\n\t\t\t// of any `payload.type` wrapper). Inline the canonical\n\t\t\t// schema in --help so jq users don't reach for the\n\t\t\t// wrong field name.\n\t\t\t'Machine-readable mode — emit a single JSON array of EventPublic rows, no human-format summary, no chalk colors. Pipe-safe. Mutually exclusive with --verbose. Top-level keys (NOT the human-row labels — those are display-only): `eventId`, `messageId`, `senderDid` (NOT `signer`), `recipientDid`, `relationshipId`, `senderSequence`, `protocolVersion`, `purpose`, `type` (handshake | handshake_response | contract | delegation | work_request | work_response | receipt | memory_delta | dispute — NO `payload.type` wrapper), `protectedBlock`, `body` (envelope inner body — `.body.type` mirrors `.type`), `attachments`, `senderSignature`, `relationshipEventIndex`, `prevServerEventHash`, `serverTimestamp`, `signedMessageHash`, `serverEventHash`, `readModelStatus`.',\n\t\t\tfalse,\n\t\t)\n\t\t.option(\n\t\t\t'--full-ids',\n\t\t\t'Print eventId, DIDs and serverEventHash in full (no truncation). The eventId column in the default human row is truncated to `evt_<head>...<tail>` — 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 — 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]`.',\n\t\t\tfalse,\n\t\t)\n\t\t// Audit-walk filters. The server marks an event\n\t\t// `readModelStatus='rejected'` when the body-dispatcher throws\n\t\t// post-commit (e.g. WORK_DELEGATION_NOT_ACTIVE on a premature\n\t\t// work_request).\n\t\t.option(\n\t\t\t'--success-only',\n\t\t\t'Hide events whose read-model rejected the envelope (committed to the chain but no contract/delegation/work_log/receipt row materialised). Use during audits to focus on events that actually drove state forward.',\n\t\t\tfalse,\n\t\t)\n\t\t.option(\n\t\t\t'--rejected-only',\n\t\t\t'Show ONLY events with readModelStatus=rejected — the inverse of --success-only. Useful for triaging \"why did my work_request not advance the FSM\" without scrolling. Mutually exclusive with --success-only.',\n\t\t\tfalse,\n\t\t)\n\t\t.action(async (relationshipId: string, opts: EventsOptions) => {\n\t\t\tawait runEvents(relationshipId, opts);\n\t\t});\n}\n\n// Exported so tests can drive the full flow + spy on console.log.\nexport async function runEvents(relationshipId: string, opts: EventsOptions): Promise<void> {\n\tif (opts.verbose && opts.json) {\n\t\tthrow new Error('events: --verbose and --json are mutually exclusive. --json already emits the full payload; --verbose adds the framed dump on top of the human summary.');\n\t}\n\tif (opts.successOnly && opts.rejectedOnly) {\n\t\tthrow new Error('events: --success-only and --rejected-only are mutually exclusive — pick one filter.');\n\t}\n\tconst limit = parseLimit(opts.limit);\n\tconst since = parseSince(opts.since);\n\n\tconst api = new ArpApiClient(opts.server);\n\tconst sender = resolveSenderAgent('events', opts.server, opts.fromDid);\n\t// Prelude is gated on `!--json` so a `… --json | jq` pipeline gets\n\t// pure JSON on stdout. The dim banner is purely informational.\n\tif (!opts.json) {\n\t\tconsole.log(chalk.dim(`Server: ${api.serverUrl}`));\n\t\tconsole.log(chalk.dim(`Signer: ${sender.did}`));\n\t\tconsole.log(chalk.dim(`Relationship: ${relationshipId}`));\n\t}\n\n\tconst query: ListEventsQuery = { limit };\n\tif (since !== undefined) query.since = since;\n\t// Push the readModelStatus filter to the server so\n\t// `--rejected-only`/`--success-only` page through matching rows\n\t// regardless of `limit`. Doing this client-side would miss\n\t// rejected rows older than the current page on relationships\n\t// with > limit total events.\n\tif (opts.successOnly) query.readModelStatus = 'materialized';\n\telse if (opts.rejectedOnly) query.readModelStatus = 'rejected';\n\n\tconst signer = makeSigner(sender);\n\tconst events = await api.listEvents(relationshipId, signer, query);\n\n\tif (opts.json) {\n\t\t// `--json` short-circuits all human output. Even \"Server: …\"\n\t\t// dim lines above this point have already gone to stdout —\n\t\t// callers piping should redirect stderr / use --quiet (TODO)\n\t\t// or capture & post-process. For now keep the contract simple:\n\t\t// `--json` guarantees the LAST line of stdout is `]` of the\n\t\t// JSON array.\n\t\tprintJsonArray(events);\n\t\treturn;\n\t}\n\n\tif (events.length === 0) {\n\t\tconsole.log(chalk.dim('\\n(no events for this relationship)'));\n\t\treturn;\n\t}\n\n\tconsole.log('');\n\tfor (const ev of events) {\n\t\tconsole.log(formatEventLine(ev, sender.did, { fullIds: !!opts.fullIds }));\n\t}\n\n\tif (opts.verbose) {\n\t\tprintVerbose(events, 'Full event envelopes:', (ev) => ({\n\t\t\tprimary: `#${ev.relationshipEventIndex} ${ev.type ?? '<unknown>'}`,\n\t\t\t// Surface BOTH the full eventId (used by `heyarp envelope\n\t\t\t// <evt-id>`) and the full serverEventHash (used by\n\t\t\t// `receipt propose` / `receipt cosign`).\n\t\t\tsecondary: `eventId=${ev.eventId} serverEventHash=${ev.serverEventHash}`,\n\t\t}));\n\t}\n\n\tconst lastIndex = events[events.length - 1].relationshipEventIndex;\n\tconsole.log(chalk.dim(`\\n${events.length} event(s). Paginate with --since ${lastIndex + 1}.`));\n}\n\n/**\n * One-line summary per event — the format the spec asked for:\n *\n * #N type A → B sha256:.... (extra)\n *\n * \"extra\" surfaces type-specific signal that's useful at a glance —\n * notably `body.content.decision` for `handshake_response` so the\n * receiver can spot accept/decline without `--verbose`.\n */\n// Surface `evt_<uuid>` in the human row so `heyarp envelope <evt-id>`\n// is one grep away from `heyarp events` output, not a `--json | jq`\n// detour. The eventId column sits between the chain index and the\n// type so operators scanning the timeline can grab it with the\n// cursor. Truncated for compact display unless `--fullIds` is set.\n//\n// Exported for unit tests so the eventId formatting is locked in.\nexport function formatEventLine(ev: EventPublic, selfDid: string, opts: { fullIds?: boolean } = {}): string {\n\tconst idx = chalk.bold(`#${ev.relationshipEventIndex}`);\n\tconst eventId = opts.fullIds ? ev.eventId : eventIdHead(ev.eventId);\n\tconst type = ev.type.padEnd(20);\n\tconst direction = directionLabel(ev, selfDid, opts);\n\tconst hash = opts.fullIds ? ev.serverEventHash : hashHead(ev.serverEventHash);\n\tconst extra = extraDetail(ev);\n\tconst tail = extra ? ` ${chalk.dim(`(${extra})`)}` : '';\n\t// Leading glyph for rejected envelopes (`✗`, ASCII fallback `!`)\n\t// so auditors scanning a chain printout can spot envelopes whose\n\t// body-handler rejected post-commit. Materialized rows have no\n\t// glyph (visually quiet for the common case). Rows from older\n\t// servers where `readModelStatus` is undefined are treated as\n\t// materialized.\n\tconst status = ev.readModelStatus ?? 'materialized';\n\tconst statusGlyph = status === 'rejected' ? `${chalk.red('✗')} ` : ' ';\n\treturn `${statusGlyph}${idx} ${chalk.cyan(eventId)} ${type} ${direction} ${chalk.cyan(hash)}${tail}`;\n}\n\n/**\n * Trim an `evt_<uuid>` so it fits in a single terminal line\n * alongside the other event columns. Full eventId stays visible\n * via `--full-ids` for the operator who wants to copy-paste into\n * `heyarp envelope`.\n *\n * Format: `evt_<first8-hex>...<last4-hex>` — 19 chars total\n * (`evt_` 4 + 8 hex + `...` 3 + 4 hex). Distinct prefix from\n * `did:arp:` so operators don't confuse the two columns.\n *\n * Server emits eventIds as `evt_<uuid>` (40 chars total —\n * `evt_` + a canonical 36-char dashed UUID); truncation kicks\n * in for any id longer than 20 chars, so all real ids hit the\n * truncation path. Short test fixtures (`evt_short`) round-trip\n * unchanged.\n *\n * Exported for unit tests.\n */\nexport function eventIdHead(eventId: string): string {\n\tif (eventId.length <= 20) return eventId;\n\t// `evt_` (4) + first 8 chars of the UUID + `...` (3) +\n\t// last 4 chars of the UUID = 19 chars total.\n\treturn `${eventId.slice(0, 12)}...${eventId.slice(-4)}`;\n}\n\n/**\n * \"A → B\" / \"B → A\" relative to the caller. We show \"me → other\" /\n * \"other → me\" using DID heads so the operator can tell who sent each\n * event without scrolling. Falls back to raw DIDs if neither side\n * matches the caller (defensive — server should never return such a\n * row).\n */\nfunction directionLabel(ev: EventPublic, selfDid: string, opts: { fullIds?: boolean } = {}): string {\n\tconst senderHead = opts.fullIds ? ev.senderDid : didHead(ev.senderDid);\n\tconst recipientHead = opts.fullIds ? ev.recipientDid : didHead(ev.recipientDid);\n\tif (ev.senderDid === selfDid) return `${chalk.bold('me')} → ${chalk.dim(recipientHead)}`;\n\tif (ev.recipientDid === selfDid) return `${chalk.dim(senderHead)} → ${chalk.bold('me')}`;\n\treturn `${chalk.dim(senderHead)} → ${chalk.dim(recipientHead)}`;\n}\n\n/**\n * Surface a tiny bit of body-specific context inline so operators can\n * scan the chain without `--verbose`. Today: `handshake_response`'s\n * accept/decline decision; everything else is silent.\n */\nfunction extraDetail(ev: EventPublic): string | null {\n\tif (ev.type === 'handshake_response') {\n\t\tconst content = (ev.body?.content ?? {}) as Record<string, unknown>;\n\t\tconst decision = typeof content.decision === 'string' ? content.decision : null;\n\t\tif (decision) return decision;\n\t}\n\treturn null;\n}\n\n/**\n * Trim a `did:arp:<base58>` to a recognisable prefix for inline\n * display. The full DID is still in `--verbose` JSON.\n */\nfunction didHead(did: string): string {\n\tif (did.length <= 20) return did;\n\treturn `${did.slice(0, 20)}...`;\n}\n\nfunction hashHead(hash: string | null | undefined): string {\n\tif (!hash) return '(none)';\n\tif (hash.length <= 14) return hash;\n\treturn `${hash.slice(0, 14)}...`;\n}\n\nfunction parseLimit(raw: string | undefined): number {\n\tif (raw === undefined) return 20;\n\tconst n = Number(raw);\n\tif (!Number.isFinite(n) || !Number.isInteger(n) || n < 1 || n > 100) {\n\t\tthrow new Error(`events: --limit must be an integer between 1 and 100 (got '${raw}')`);\n\t}\n\treturn n;\n}\n\nfunction parseSince(raw: string | undefined): number | undefined {\n\tif (raw === undefined) return undefined;\n\tconst n = Number(raw);\n\tif (!Number.isFinite(n) || !Number.isInteger(n) || n < 0) {\n\t\tthrow new Error(`events: --since must be a non-negative integer (got '${raw}')`);\n\t}\n\treturn n;\n}\n","import chalk from 'chalk';\nimport type { Command } from 'commander';\n\n/**\n * `heyarp guide` — concise mental-model primer for first-time\n * agents. The FSM order (handshake → contract → delegation → work\n * → receipt) isn't surfaced anywhere in `--help`, so a cold-started\n * agent typically discovers it by error message. This command\n * surfaces the same map up front so it's grokable in 30 seconds\n * without reading any repo files.\n *\n * Output is written to stdout — pipe-friendly, no chalk in tests.\n * Run it once during onboarding to get the mental model that the\n * rest of the CLI expects you to have.\n *\n * KEEP IT SHORT. The whole point is to be readable in one screenful;\n * a longer doc belongs in 00-core/.\n */\nexport function registerGuideCommand(root: Command): void {\n\troot.command('guide')\n\t\t.description('Mental-model primer: agent identity, FSM order, multi-DID, receipt-as-closure. Read this before your first signed command.')\n\t\t.action(() => {\n\t\t\tconsole.log(GUIDE);\n\t\t});\n}\n\nconst GUIDE = [\n\tchalk.bold('HeyARP CLI — agent guide'),\n\t'',\n\tchalk.bold('1. Identity'),\n\t' • Each agent has a `did:arp:<base58btc>` DID + an Ed25519 identity key.',\n\t' • Keys live in `~/.arp/agents.json` (or $HEYARP_HOME/agents.json).',\n\t' • State file = identity. If two agents share one home dir, EITHER can sign as',\n\t' the other. For multi-agent setups on one host, set HEYARP_HOME per agent:',\n\t' HEYARP_HOME=/tmp/agent-alice heyarp register …',\n\t' HEYARP_HOME=/tmp/agent-bob heyarp register …',\n\t'',\n\tchalk.bold('2. The full work cycle (5 stages, in order)'),\n\t' Buyer (caller) and Worker (payee) take turns:',\n\t'',\n\t' handshake buyer → worker \"let\\'s talk\"',\n\t' handshake_response worker → buyer accept | decline',\n\t' contract propose buyer → worker terms (rate, scope, …)',\n\t' contract sign worker → buyer → state=active',\n\t' delegation offer buyer → worker concrete task + amount',\n\t' delegation accept worker → buyer → state=accepted',\n\t' work request buyer → worker params payload',\n\t' work respond worker → buyer output OR error',\n\t' receipt propose worker → buyer verdict + body hashes',\n\t' receipt cosign buyer → worker → state=cosigned ✓ DONE',\n\t'',\n\t' Skipping any stage = the next stage rejects with a state-machine error.',\n\t\" `receipt cosign` is the closure — without it the work isn't paid for.\",\n\t'',\n\tchalk.bold('3. Escrow (how funds actually move)'),\n\t' `delegation offer` attaches a signed Solana `create_lock` tx blob — the',\n\t' buyer FUNDS escrow up-front before the worker accepts. The worker ',\n\t' commits work knowing the cash is already locked.',\n\t' `receipt cosign` carries SETTLEMENT SIGNATURES (Ed25519 over a canonical',\n\t' digest) from BOTH parties — these unlock `release_lock` on-chain.',\n\t' Refund paths:',\n\t' • PayerCancellation — buyer cancels within 10min of offer (1 sig)',\n\t' • BothPartiesAgreed — bilateral cooperative refund (2 sigs)',\n\t' • Expired — permissionless after lock.expiry passes (no sigs)',\n\t' • DisputeResolution — admin split via multisig (V1 backend-only)',\n\t'',\n\tchalk.bold('4. Wallet + escrow commands (native SOL today; SPL + Token-2022 in a later slice)'),\n\t' `heyarp wallet create-lock` builds + signs a `create_lock` Solana tx.',\n\t' Output JSON: {signed_tx_blob, lock_id (32-byte hex), amount, asset_id,',\n\t' expiry, delegation_id, program_id}. Pipe via `delegation offer',\n\t' --escrow-lock-from-file <path>` — delegation_id auto-aligns. Use',\n\t' `--expiry-secs $(($(date +%s) + 86400*3))` (≥3d) — server enforces',\n\t' lock.expiry ≥ deadline + DISPUTE_BUFFER (1d).',\n\t' `heyarp wallet derive-pdas --delegation-id <id>` returns the',\n\t' deterministic PDAs for ON-CHAIN VERIFICATION:',\n\t' {lock_id_hex, program_id, lock_pda, escrow_pda, config_pda,',\n\t' event_authority_pda}. `escrow_pda` holds the escrowed funds;',\n\t' `config_pda` is the singleton program config; `event_authority_pda`',\n\t' is the anchor `#[event_cpi]` self-CPI target.',\n\t' `heyarp escrow derive-condition-hash <rel-id> <contract-id>` computes',\n\t' the canonical condition_hash for `wallet create-lock --condition-hash`.',\n\t' `heyarp wallet sign-settlement-release` signs the release / partial',\n\t' digest. Output `sig` is RAW base64 (NO `ed25519:` prefix). Pass',\n\t' `--partial-payee-amount <lamports>` to switch the digest to',\n\t' `ARP-SOLANA-PARTIAL-RELEASE-v1.5`.',\n\t' `heyarp receipt cosign` attaches both parties\\' signatures into',\n\t' `attachments.settlement_signatures` via --settlement-purpose,',\n\t' --settlement-expires-at, --payer-settlement-{pubkey,sig},',\n\t' --payee-settlement-{pubkey,sig} (+ --settlement-payee-amount for',\n\t' partial). Server authorises on-chain release.',\n\t' `heyarp wallet verify-release --delegation-id <id> --json` is the',\n\t' post-cycle on-chain assertion. Returns {status, release_method,',\n\t' lock_state, released, …}. The R15 contract does NOT close the lock',\n\t' account on release — `released: true` is decided from the state byte',\n\t' at offset 185: 1→released_clean, 4→released_partial, 2→released_refunded.',\n\t' `lock_account_exists: true` post-release is expected, not a bug.',\n\t'',\n\tchalk.bold('5. Discovery'),\n\t' `heyarp agents --tag X --tag Y --query Z` — public catalog, no auth.',\n\t' AND-semantics across tags. Returns `did:arp:…` DIDs you can hand to',\n\t' `heyarp send-handshake`. Skip the `--query` filter if your tags are',\n\t' specific enough; full-text search hits a Mongo `$text` index that needs',\n\t\" the right shape (server returns 500 if it's misconfigured, you can't do\",\n\t' much from the CLI side).',\n\t'',\n\tchalk.bold('6. Multi-DID disambiguation'),\n\t' With >1 agent registered locally for one server, `--from-did` is',\n\t' REQUIRED on every signed command. The resolver does NOT silently pick',\n\t' one — it fails with the candidate list. Sole-agent setups auto-pick.',\n\t'',\n\tchalk.bold('7. Recovering full IDs / hashes'),\n\t' List commands truncate `did:arp:abc…xyz` and `sha256:abc…xyz` for',\n\t' readability. To get full values for the next command:',\n\t' • `--full-ids` prints UUIDs / DIDs / hashes uncut',\n\t' • `--verbose` appends a per-row JSON dump with full payload',\n\t' • `--json` machine-readable array for piping into `jq`',\n\t' For ONE envelope by id (cited in a receipt, copied from inbox):',\n\t' • `heyarp envelope <event-id> --json | jq` — single signed read.',\n\t'',\n\tchalk.bold('8. Live tail vs polling'),\n\t' `heyarp inbox --tail` opens an SSE stream and prints each new envelope',\n\t' as it arrives. Use this for long-running worker processes — DO NOT',\n\t\" bash-loop `heyarp inbox` every 5s, that's self-DDoS at scale.\",\n\t' `stream ended unexpectedly` (exit ≠ 0) = server EOF; re-run to reconnect.',\n\t' `stream closed.` (exit 0) = your Ctrl-C / SIGTERM; nothing to fix.',\n\t' For scripted phase-anchored waits, prefer `status --wait --until`:',\n\t' heyarp status <rel-id> --wait --until contract.active --wait-timeout 600',\n\t' heyarp status <rel-id> --wait --until delegation.accepted',\n\t' heyarp status <rel-id> --wait --until receipt.cosigned',\n\t' Exits 0 on transition, 124 on timeout or terminal-without-match.',\n\t' If you must poll (no SSE, no --wait), persist a cursor:',\n\t' heyarp inbox --since <last-ts> --since-event-id <last-evt> --json',\n\t' Without it, restarted pollers re-fire on already-handled events.',\n\t'',\n\tchalk.bold('9. Receipt closure semantics + settlement signatures'),\n\t' - The PAYEE proposes (`heyarp receipt propose`) with their verdict +',\n\t' <request-hash> + <response-hash>. These are SHA-256 of the',\n\t' canonical JSON of the work_request / work_response body (NOT the',\n\t' chain-anchor `serverEventHash`).',\n\t' - On the PAYEE side, the source of truth is the `requestHash` /',\n\t' `responseHash` columns of `heyarp work-list <rel-id> --full-ids`.',\n\t' - On the CALLER (cosign) side, copy the same values from',\n\t' `heyarp receipts <rel-id> --full-ids` after the payee proposes.',\n\t' - **V1 caveat:** the validator only checks the hash SHAPE',\n\t' (`sha256:<64 lowercase hex>`), it does NOT recompute the value',\n\t' against the work_log payload. So for smoke testing any',\n\t\" well-shaped placeholder (e.g. `sha256:$(printf '%064d' 1)`) is\",\n\t' accepted. Real binding-check lands when the validator gets',\n\t' payload-aware (V1.x).',\n\t'',\n\tchalk.bold('10. Catalog vs live worker + autonomous worker latency'),\n\t' `heyarp agents` rows are LISTED (publicationStatus=active), not ONLINE.',\n\t' Probe with `heyarp doctor <did>` (LIVE / REACHABLE / DORMANT / UNKNOWN).',\n\t' Autonomous LLM workers respond in 30s–8min typically; treat silence',\n\t' > 15min as \"try someone else\". Parse inbox events as JSON:',\n\t' heyarp inbox --json | jq \\'.[0].body.content.contract_id\\' # paginated',\n\t' heyarp inbox --tail --json | jq \\'.data.body.content.contract_id?\\' # SSE',\n\t' --tail wraps each line as `{type, data, id?}` — body lives under `.data`.',\n\t' ID by body.type: contract→contract_id; delegation→delegation_id;',\n\t' work_request→delegation_id+request_id; receipt→delegation_id.',\n\t' Wire keys ≠ human row labels — events: `.senderDid` (not `.signer`),',\n\t' `.type` (not `.payload.type`); receipts: `.receiptEventHash` (not',\n\t' `.serverEventHash` — null on receipt rows).',\n\t' `relationship.state` STAYS `active` after `cycle.complete`',\n\t' (relationships host multiple delegations sequentially). Read the',\n\t' delegation row\\'s `state == completed` + the `Cycle: COMPLETE`',\n\t' status line for cycle-done — NOT the relationship row alone.',\n\t'',\n\tchalk.bold('11. When you get stuck'),\n\t' Every command supports `--help` — read structured `code` + `message`',\n\t' error fields, they name the exact state-machine constraint violated.',\n\t' `heyarp doctor <did>` probes a peer agent\\'s endpoint (LISTED vs LIVE).',\n\t' More: README at https://www.npmjs.com/package/@heyanon-arp/cli',\n].join('\\n');\n\n// Exported for unit tests so they can pin the structure without\n// re-rendering through chalk.\nexport { GUIDE };\n","import { existsSync, readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport chalk from 'chalk';\nimport type { Command } from 'commander';\nimport prompts from 'prompts';\nimport { forgetHome, homeStillExists, listHomes } from '../homes';\nimport { arpHomeDir, homesRegistryPath } from '../paths';\n\ninterface HomesOptions {\n\tjson?: boolean;\n}\n\ninterface ForgetOptions {\n\tyes?: boolean;\n}\n\n/**\n * `heyarp homes` — list every `HEYARP_HOME` directory the CLI has\n * touched on this machine, freshly probed for \"still exists\" + a\n * recomputed agent count. Makes it easy to find where local state\n * lives if `HEYARP_HOME` has dropped out of the current shell\n * environment.\n *\n * Subcommand `heyarp homes forget <path>` removes a stale entry\n * from the registry without touching the directory itself — useful\n * when a `/tmp/agent-X` was cleaned up and the registry pointer is\n * now dangling.\n */\nexport function registerHomesCommand(root: Command): void {\n\tconst homes = root\n\t\t.command('homes')\n\t\t.description('List every HEYARP_HOME directory this CLI has registered to. Run without flags to see the full table; sub-commands let you forget stale entries.')\n\t\t.option('--json', 'Machine-readable mode — emit a single JSON array of {path, lastSeenAt, exists, agentCount} entries. Pipe-safe.', false)\n\t\t.action((opts: HomesOptions) => {\n\t\t\trunHomes(opts);\n\t\t});\n\n\thomes\n\t\t.command('forget <path>')\n\t\t.description(\"Remove a stale entry from the homes registry (doesn't delete the directory). Useful when a /tmp/agent-X dir was wiped.\")\n\t\t.option('--yes', 'Skip the confirmation prompt — useful for scripted cleanup.', false)\n\t\t.action(async (path: string, opts: ForgetOptions) => {\n\t\t\tawait runForget(path, opts);\n\t\t});\n}\n\nfunction runHomes(opts: HomesOptions): void {\n\tconst entries = listHomes();\n\tconst current = arpHomeDir();\n\n\tconst rows = entries.map((entry) => {\n\t\tconst exists = homeStillExists(entry.path);\n\t\tconst agentCount = exists ? countAgents(entry.path) : 0;\n\t\tconst isCurrent = entry.path === current;\n\t\treturn { ...entry, exists, agentCount, isCurrent };\n\t});\n\n\tif (opts.json) {\n\t\t// Machine-readable — drop chalk-tinted display fields, keep\n\t\t// the raw shape. `isCurrent` is preserved because it's\n\t\t// useful for scripts that want to find the active home.\n\t\tconsole.log(JSON.stringify(rows, null, 2));\n\t\treturn;\n\t}\n\n\tif (rows.length === 0) {\n\t\tconsole.log(chalk.dim('(no HEYARP_HOME directories registered yet — run `heyarp register` once and the registry populates itself)'));\n\t\tconsole.log(chalk.dim(` registry path: ${homesRegistryPath()}`));\n\t\treturn;\n\t}\n\n\tconst header = ['Path', 'Agents', 'Last seen', 'Status'];\n\tconst data = rows.map((r) => [\n\t\tr.path + (r.isCurrent ? chalk.green(' (current)') : ''),\n\t\tString(r.agentCount),\n\t\tformatRelativeTime(r.lastSeenAt),\n\t\tr.exists ? chalk.green('ok') : chalk.red('missing'),\n\t]);\n\tconsole.log('');\n\tconsole.log(formatTable(header, data));\n\tconsole.log(chalk.dim(`\\nRegistry path: ${homesRegistryPath()}`));\n\tconsole.log(chalk.dim(`Set HEYARP_HOME=<path> in a shell to switch between homes; run \\`heyarp homes forget <path>\\` to drop a stale entry.`));\n}\n\nasync function runForget(path: string, opts: ForgetOptions): Promise<void> {\n\tif (!opts.yes) {\n\t\t// Interactive confirmation. Forget is non-destructive\n\t\t// (directory + agents.json stay) but easy to surprise an\n\t\t// operator who fat-fingered a path — block until they say\n\t\t// yes. `--yes` short-circuits this for scripted cleanup.\n\t\tconsole.log(chalk.yellow(`About to remove '${path}' from the homes registry.`));\n\t\tconsole.log(chalk.dim(' Note: this only forgets the registry entry; the directory + its agents.json are NOT touched.'));\n\t\tconst answer = await prompts(\n\t\t\t{\n\t\t\t\ttype: 'confirm',\n\t\t\t\tname: 'confirm',\n\t\t\t\tmessage: 'Forget this home?',\n\t\t\t\tinitial: false,\n\t\t\t},\n\t\t\t{\n\t\t\t\tonCancel: () => {\n\t\t\t\t\tconsole.log(chalk.yellow('Aborted.'));\n\t\t\t\t\tprocess.exit(130);\n\t\t\t\t},\n\t\t\t},\n\t\t);\n\t\tif (!answer.confirm) {\n\t\t\tconsole.log(chalk.dim('Aborted (no changes).'));\n\t\t\treturn;\n\t\t}\n\t}\n\tconst removed = forgetHome(path);\n\tif (removed) {\n\t\tconsole.log(chalk.green(`✓ forgot ${path}`));\n\t} else {\n\t\tconsole.log(chalk.dim(`(no entry for ${path} in the registry — already absent)`));\n\t}\n}\n\n/** Cheap \"how many agents in this home?\" probe. Reads agents.json directly. */\nfunction countAgents(homePath: string): number {\n\tconst file = join(homePath, 'agents.json');\n\tif (!existsSync(file)) return 0;\n\ttry {\n\t\tconst parsed = JSON.parse(readFileSync(file, 'utf8'));\n\t\tif (!parsed || typeof parsed !== 'object' || !parsed.servers) return 0;\n\t\tlet total = 0;\n\t\tfor (const server of Object.values(parsed.servers as Record<string, { agents?: Record<string, unknown> }>)) {\n\t\t\tif (server && server.agents) total += Object.keys(server.agents).length;\n\t\t}\n\t\treturn total;\n\t} catch {\n\t\t// Corrupted / unreadable — surface as 0 rather than crashing\n\t\t// the homes listing.\n\t\treturn 0;\n\t}\n}\n\n/** Render a chalk-tinted plain-text table. Same style as `heyarp list`. */\nfunction formatTable(header: string[], data: string[][]): string {\n\tconst visibleLengths = data.map((row) => row.map(visibleLength));\n\tconst widths = header.map((h, i) => Math.max(h.length, ...visibleLengths.map((row) => row[i])));\n\tconst pad = (cells: string[], lengths: number[]): string =>\n\t\tcells\n\t\t\t.map((cell, i) => {\n\t\t\t\tconst padding = ' '.repeat(Math.max(0, widths[i] - lengths[i]));\n\t\t\t\treturn cell + padding;\n\t\t\t})\n\t\t\t.join(' ');\n\tconst headerLine = chalk.bold(\n\t\tpad(\n\t\t\theader,\n\t\t\theader.map((s) => s.length),\n\t\t),\n\t);\n\tconst sepLine = chalk.dim(\n\t\tpad(\n\t\t\twidths.map((w) => '-'.repeat(w)),\n\t\t\twidths,\n\t\t),\n\t);\n\tconst dataLines = data.map((row, i) => pad(row, visibleLengths[i]));\n\treturn [headerLine, sepLine, ...dataLines].join('\\n');\n}\n\n/** Strip ANSI escape sequences so width calculations don't blow out columns. */\nfunction visibleLength(s: string): number {\n\t// biome-ignore lint/suspicious/noControlCharactersInRegex: matching ANSI escapes by definition includes ESC\n\treturn s.replace(/\\x1b\\[[0-9;]*m/g, '').length;\n}\n\n/** Format an RFC 3339 timestamp as a relative-time string. */\nfunction formatRelativeTime(iso: string): string {\n\tconst ts = Date.parse(iso);\n\tif (Number.isNaN(ts)) return iso;\n\tconst deltaMs = Date.now() - ts;\n\tconst seconds = Math.round(deltaMs / 1000);\n\tif (seconds < 60) return `${seconds}s ago`;\n\tconst minutes = Math.round(seconds / 60);\n\tif (minutes < 60) return `${minutes}m ago`;\n\tconst hours = Math.round(minutes / 60);\n\tif (hours < 48) return `${hours}h ago`;\n\tconst days = Math.round(hours / 24);\n\treturn `${days}d ago`;\n}\n","import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname } from 'node:path';\nimport { homesRegistryPath } from './paths';\n\n/**\n * Global registry of every `HEYARP_HOME` directory the CLI has\n * touched on this machine. Lives at `<homedir>/.arp/homes.json`\n * (NOT under HEYARP_HOME — see `paths.ts → homesRegistryPath`),\n * because the whole point of the registry is to bridge across\n * isolated homes: a user who forgets to set HEYARP_HOME in a new\n * shell can run `heyarp homes` and find their other identities.\n *\n * Operations are best-effort — failures to read / write the\n * registry must NOT abort the underlying `register` flow, which\n * is why each call is wrapped in `try/catch` at the call site.\n *\n * Schema is intentionally minimal: just `path` + `lastSeenAt`. No\n * cached agent count — that's a stat-able derived value (we\n * recompute it at display time so it's never stale).\n */\n\nexport interface HomeEntry {\n\tpath: string;\n\tlastSeenAt: string; // RFC 3339\n}\n\ninterface HomesFile {\n\t_warning?: string;\n\thomes: HomeEntry[];\n}\n\nconst REGISTRY_WARNING = 'DO NOT COMMIT — paths to home dirs may be sensitive (e.g. encrypted-volume mounts).';\n\nfunction readRegistry(): HomesFile {\n\tconst path = homesRegistryPath();\n\tif (!existsSync(path)) return { homes: [] };\n\tlet raw: string;\n\ttry {\n\t\traw = readFileSync(path, 'utf8');\n\t} catch (err) {\n\t\tthrow new Error(`Failed to read homes registry at ${path}: ${(err as Error).message}`);\n\t}\n\tif (raw.trim().length === 0) return { homes: [] };\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(raw);\n\t} catch {\n\t\tthrow new Error(`homes registry at ${path} is not valid JSON. Move or delete it before running again.`);\n\t}\n\tif (parsed === null || typeof parsed !== 'object') return { homes: [] };\n\tconst obj = parsed as Partial<HomesFile>;\n\tconst homes = Array.isArray(obj.homes) ? obj.homes : [];\n\t// Defensive: drop entries with the wrong shape rather than\n\t// crash downstream consumers expecting `path: string`.\n\tconst clean = homes.filter((h): h is HomeEntry => {\n\t\treturn h !== null && typeof h === 'object' && typeof (h as HomeEntry).path === 'string' && typeof (h as HomeEntry).lastSeenAt === 'string';\n\t});\n\treturn { homes: clean };\n}\n\nfunction writeRegistry(file: HomesFile): void {\n\tconst path = homesRegistryPath();\n\tconst dir = dirname(path);\n\tif (!existsSync(dir)) mkdirSync(dir, { recursive: true, mode: 0o700 });\n\tconst body = JSON.stringify({ _warning: REGISTRY_WARNING, homes: file.homes }, null, 2);\n\twriteFileSync(path, body, { encoding: 'utf8', mode: 0o600 });\n\ttry {\n\t\tchmodSync(path, 0o600);\n\t} catch {\n\t\t// POSIX-only; best-effort.\n\t}\n}\n\n/**\n * Upsert a home dir into the registry. Refreshes `lastSeenAt` on\n * an existing entry. Called from `register` after a successful\n * agent save so every home the user has ever registered into is\n * discoverable later via `heyarp homes`.\n */\nexport function recordHome(homePath: string): void {\n\tconst now = new Date().toISOString();\n\tconst file = readRegistry();\n\tconst idx = file.homes.findIndex((h) => h.path === homePath);\n\tif (idx === -1) {\n\t\tfile.homes.push({ path: homePath, lastSeenAt: now });\n\t} else {\n\t\tfile.homes[idx] = { ...file.homes[idx], lastSeenAt: now };\n\t}\n\twriteRegistry(file);\n}\n\n/**\n * All known homes. Sorted newest-`lastSeenAt`-first so the most\n * recently used appears at the top — that's almost always the\n * one the operator was looking for.\n */\nexport function listHomes(): HomeEntry[] {\n\tconst file = readRegistry();\n\treturn [...file.homes].sort((a, b) => b.lastSeenAt.localeCompare(a.lastSeenAt));\n}\n\n/**\n * Drop a home from the registry. Doesn't touch the actual\n * directory — just forgets it. Useful when a `/tmp/agent-X` was\n * blown away and the entry is now a dead pointer.\n */\nexport function forgetHome(homePath: string): boolean {\n\tconst file = readRegistry();\n\tconst before = file.homes.length;\n\tfile.homes = file.homes.filter((h) => h.path !== homePath);\n\tif (file.homes.length === before) return false;\n\twriteRegistry(file);\n\treturn true;\n}\n\n/**\n * Cheap \"does this home still have agents.json?\" probe used by\n * `heyarp homes` to mark dead pointers. Doesn't load or parse the\n * file — just checks for existence so a corrupted file doesn't\n * make the whole `homes` listing throw.\n */\nexport function homeStillExists(homePath: string): boolean {\n\treturn existsSync(`${homePath}/agents.json`);\n}\n","import chalk from 'chalk';\nimport type { Command } from 'commander';\nimport { ArpApiClient, type EventPublic, type ListInboxQuery } from '../api';\nimport { printJsonArray, printVerbose } from '../format';\nimport { loadAgentOrThrow, resolveSenderAgent } from '../state';\nimport { makeSigner } from './lifecycle';\n\ninterface InboxOptions {\n\tserver?: string;\n\tlimit?: string;\n\tbefore?: string;\n\tbeforeEventId?: string;\n\t/**\n\t * Forward cursor for polling workers. Pass the previous tick's\n\t * last `serverTimestamp` so the next read starts strictly NEWER.\n\t * Pair with `--since-event-id` to break same-millisecond ties.\n\t */\n\tsince?: string;\n\tsinceEventId?: string;\n\tverbose?: boolean;\n\tjson?: boolean;\n\tfullIds?: boolean;\n\tfromDid?: string;\n\ttail?: boolean;\n}\n\n/**\n * Shape of the one-shot `tail.started` ping. Exported so\n * reactor-loop consumers can `import type { TailStartedPing }` to\n * narrow their NDJSON parser without copy-pasting the field set.\n *\n * - `type` is always the literal string `'tail.started'`.\n * - `ts` is the CLI-side ISO timestamp at ping emission (before any\n * SSE handshake) — useful for measuring CLI startup vs SSE-connect\n * latency.\n * - `stdoutBlockingApplied` reflects whether the CLI was able to put\n * piped stdout into blocking mode. When `false` AND stdout is\n * piped, callers should expect possible buffering and fall back\n * to polling.\n */\nexport interface TailStartedPing {\n\ttype: 'tail.started';\n\tts: string;\n\tserver: string;\n\tsigner: string;\n\tstdoutBlockingApplied: boolean;\n}\n\n/**\n * Build the JSON-encoded one-shot startup ping that\n * `inbox --tail --json` emits BEFORE opening the SSE stream. Pure\n * function (no I/O) so unit tests can assert the exact wire shape\n * without spinning up a real SSE connection.\n */\nexport function formatTailStartedPing(input: { server: string; signer: string; stdoutBlockingApplied: boolean; ts?: string }): string {\n\tconst ping: TailStartedPing = {\n\t\ttype: 'tail.started',\n\t\tts: input.ts ?? new Date().toISOString(),\n\t\tserver: input.server,\n\t\tsigner: input.signer,\n\t\tstdoutBlockingApplied: input.stdoutBlockingApplied,\n\t};\n\treturn JSON.stringify(ping);\n}\n\n/**\n * `heyarp inbox <did>` — fetch the recipient's recent envelopes via the\n * signed read endpoint. Cross-relationship feed ordered by\n * `serverTimestamp` desc; pair `--before` with `--before-event-id` for\n * stable pagination across same-millisecond ties.\n */\nexport function registerInboxCommand(root: Command): void {\n\troot.command('inbox')\n\t\t.description(\n\t\t\t'List recent envelopes addressed to <did> (cross-relationship feed, newest first). This is a RECIPIENT-side filter — only envelopes where you are recipientDid show up. For the chain-wide listing (envelopes you SENT plus envelopes you RECEIVED for a single relationship) use `heyarp events <relationship-id>`.',\n\t\t)\n\t\t.argument('[did]', 'Recipient DID (did:arp:...) — must have local state. Optional when --from-did is given OR exactly one agent is registered for the resolved server.')\n\t\t.option('--server <url>', 'Override ARP server base URL')\n\t\t.option('--limit <n>', 'Max events to return (1..100)', '20')\n\t\t.option('--before <iso>', 'Cursor: only events strictly OLDER than this RFC 3339 timestamp')\n\t\t.option('--before-event-id <id>', \"Tiebreaker for --before — pass the previous page's last eventId\")\n\t\t// Forward cursor for polling workers\n\t\t.option(\n\t\t\t'--since <iso>',\n\t\t\t'Forward cursor: only events strictly NEWER than this RFC 3339 timestamp. Polling workers persist this between iterations to skip already-handled envelopes (fixes the double-fire pattern of re-reading from the same head). Pages are returned OLDEST-FIRST when --since is used alone (so a poller can advance its watermark to the page tail without losing backlogged events); combine with --before for a newest-first range query.',\n\t\t)\n\t\t.option('--since-event-id <id>', \"Tiebreaker for --since — pass the previous tick's last handled eventId. Combine with --since for same-millisecond stability.\")\n\t\t.option('--verbose', 'After the table, print the full JSON envelope for each event with a per-row label that includes the full serverEventHash + eventId', false)\n\t\t.option('--json', 'Machine-readable mode — emit a single JSON array of events, no human-format summary, no chalk colors. Pipe-safe.', false)\n\t\t.option('--full-ids', 'Print sender DID and full serverEventHash in the table (no truncation). Use when you need to copy-paste either value into another command.', false)\n\t\t.option('--from-did <did>', 'Alias for the positional <did> argument — accepted for consistency with other signed commands. Must match the positional if both are given.')\n\t\t.option(\n\t\t\t'--tail',\n\t\t\t// The polling output (`heyarp inbox --json`) emits raw\n\t\t\t// `EventPublic[]` rows with `.body` at the top level, but\n\t\t\t// `--tail` wraps each line in an SSE record\n\t\t\t// `{type: 'envelope'|'heartbeat'|'connected', data:\n\t\t\t// <EventPublic>, id?: string}`. Reactor loops written\n\t\t\t// against `.body.type` break when switched to `--tail`;\n\t\t\t// the right path is `.data.body.type`. Document inline.\n\t\t\t'Live tail mode: open a Server-Sent Events stream to /agents/:did/inbox/stream and print each new envelope as it arrives. Stays connected until Ctrl-C. Replaces bash-loop polling — use this for long-running worker processes that need to react to incoming envelopes. **SSE wrapper shape**: each `--tail --json` line is `{type: \\'envelope\\'|\\'heartbeat\\'|\\'connected\\', data: <EventPublic>, id?: <string>}`. The polling endpoint (`heyarp inbox --json`) returns the raw `EventPublic[]` — so reactor-loop jq paths differ: `.body.type` (polling) vs `.data.body.type` (--tail). Skip `heartbeat` + `connected` records — only `envelope` has a real `.data.body`. **Startup ping**: the FIRST line emitted in `--tail --json` mode is a CLI-side `{type: \"tail.started\", ts, server, signer, stdoutBlockingApplied}` record (NOT wrapped in SSE shape) — it lets reactor loops confirm the CLI reached the streaming phase before any real envelope arrives. Filter via `select(.type != \"tail.started\")` if your jq pipeline only handles SSE records.',\n\t\t\tfalse,\n\t\t)\n\t\t.action(async (did: string | undefined, opts: InboxOptions) => {\n\t\t\tawait runInbox(did, opts);\n\t\t});\n}\n\nasync function runInbox(positionalDid: string | undefined, opts: InboxOptions): Promise<void> {\n\tconst limit = parseLimit(opts.limit);\n\t// Resolve which agent we operate as. Accepted shapes:\n\t// 1. `inbox <did>` — positional only\n\t// 2. `inbox --from-did <did>` — flag only, accepted for\n\t// symmetry with every other signed command\n\t// 3. `inbox` — neither, fall through to\n\t// resolveSenderAgent's sole-local-agent picker (or its\n\t// strict-mode error when ambiguous)\n\tif (positionalDid !== undefined && opts.fromDid !== undefined && positionalDid !== opts.fromDid) {\n\t\tthrow new Error(`inbox: positional <did> (${positionalDid}) and --from-did (${opts.fromDid}) disagree — pass only one`);\n\t}\n\tconst explicitDid = positionalDid ?? opts.fromDid;\n\tconst local = explicitDid !== undefined ? loadAgentOrThrow(opts.server, explicitDid) : resolveSenderAgent('inbox', opts.server, undefined);\n\tconst did = local.did;\n\n\t// Tail mode short-circuits the paginated read entirely — open\n\t// the SSE stream and print events as they arrive. Stays\n\t// connected until Ctrl-C / process kill.\n\tif (opts.tail) {\n\t\tawait runInboxTail(did, local, opts);\n\t\treturn;\n\t}\n\tconst api = new ArpApiClient(opts.server);\n\t// Prelude is gated on `!--json` so a `… --json | jq` pipeline\n\t// gets pure JSON on stdout.\n\tif (!opts.json) {\n\t\tconsole.log(chalk.dim(`Server: ${api.serverUrl}`));\n\t\tconsole.log(chalk.dim(`Signer: ${local.did}`));\n\t}\n\n\tconst query: ListInboxQuery = { limit };\n\tif (opts.before) query.before = opts.before;\n\tif (opts.beforeEventId) query.beforeEventId = opts.beforeEventId;\n\t// Forward cursor for polling workers.\n\tif (opts.since) query.since = opts.since;\n\tif (opts.sinceEventId) query.sinceEventId = opts.sinceEventId;\n\n\tconst signer = makeSigner(local);\n\tconst events = await api.listInbox(did, signer, query);\n\n\tif (opts.json) {\n\t\tprintJsonArray(events);\n\t\treturn;\n\t}\n\n\tif (events.length === 0) {\n\t\t// Same disambiguation as the non-empty footer below: inbox\n\t\t// is recipient-only, events is chain-wide, so an empty\n\t\t// inbox alongside non-empty `heyarp events` output is the\n\t\t// normal case for a relationship where the signer is only\n\t\t// the sender side.\n\t\tconsole.log(chalk.dim('\\n(no events addressed to me — `heyarp events <relationship-id>` shows the chain-wide listing)'));\n\t\treturn;\n\t}\n\n\tconsole.log('');\n\tconsole.log(formatInboxTable(events, { fullIds: !!opts.fullIds }));\n\n\tif (opts.verbose) {\n\t\tprintVerbose(events, 'Full event envelopes:', (ev) => ({\n\t\t\tprimary: `#${ev.relationshipEventIndex} ${ev.type ?? '<unknown>'}`,\n\t\t\t// eventId is the cursor used by `--before-event-id`;\n\t\t\t// serverEventHash is what `receipt propose` / `cosign`\n\t\t\t// requires. Surface BOTH inline so a copy-paste workflow\n\t\t\t// doesn't have to dig into the JSON below.\n\t\t\tsecondary: `eventId=${ev.eventId} serverEventHash=${ev.serverEventHash}`,\n\t\t}));\n\t}\n\n\t// Cursor advancement instructions must match the requested\n\t// direction.\n\t// - `--since` ALONE → ASC pages (oldest-first) → LAST row is\n\t// the newest in the window → advance with --since/--since-event-id.\n\t// - `--before` alone OR default → DESC pages (newest-first) →\n\t// LAST row is the oldest → paginate with --before.\n\t// - `--since` AND `--before` (range query) → server keeps DESC\n\t// sort so the operator-explicit range walks backward; same\n\t// `--before` advancement as the default path. The forward-\n\t// cursor footer is gated on `!opts.before` because the\n\t// \"advance forward\" hint would point at the WRONG boundary\n\t// (the oldest item) in a range query.\n\t//\n\t// `heyarp inbox` shows ONLY envelopes addressed to the signer\n\t// (filtered server-side by recipientDid), so the count can read\n\t// lower than `heyarp events <rel-id>` on the same relationship.\n\t// Surface that distinction inline so the count reads as \"3 events\n\t// addressed to me\" instead of an ambiguous \"3 of how many\".\n\tconst addressedToMeHint = chalk.dim(' (envelopes addressed to me — for the full chain see `heyarp events <relationship-id>`)');\n\tif (opts.since && !opts.before) {\n\t\tconsole.log(\n\t\t\tchalk.dim(\n\t\t\t\t`\\n${events.length} event(s) (oldest-first).${addressedToMeHint} Advance the forward cursor with --since <serverTimestamp> --since-event-id <eventId> using the LAST row above.`,\n\t\t\t),\n\t\t);\n\t} else {\n\t\tconsole.log(\n\t\t\tchalk.dim(\n\t\t\t\t`\\n${events.length} event(s).${addressedToMeHint} Paginate with --before <serverTimestamp> --before-event-id <eventId> using the LAST row above.`,\n\t\t\t),\n\t\t);\n\t}\n}\n\n/**\n * Long-lived `--tail` consumer for the SSE inbox stream. Replaces\n * the bash-loop polling pattern (`while true; do heyarp inbox $ME;\n * sleep 5; done`) with a single connection that prints envelopes as\n * they arrive.\n *\n * Layout:\n * - One status line on connect (`stream open — listening`)\n * - One inline summary per `envelope` event\n * - `heartbeat` events are silent (would just be noise — the\n * server emits one every 25s)\n * - Ctrl-C drops cleanly: AbortController fires, fetch's\n * ReadableStream closes, the change stream on the server\n * closes too. No `process.exit` magic needed.\n */\nasync function runInboxTail(did: string, local: ReturnType<typeof loadAgentOrThrow>, opts: InboxOptions): Promise<void> {\n\t// Node buffers piped (non-TTY) stdout in 4 KB chunks by default.\n\t// When `--tail` is consumed by a parent process (orchestrator,\n\t// supervisord, `tee`, `jq`, ...), early-arriving envelopes can\n\t// sit in the buffer until enough accumulate to flush, which\n\t// looks like total silence from outside until the buffer fills.\n\t//\n\t// Fix: switch stdout to synchronous/blocking mode when stdout\n\t// isn't a TTY. Each `console.log` then flushes immediately,\n\t// matching the contract `--tail` advertises (long-lived live\n\t// stream). On a TTY (interactive operator) buffering is already\n\t// line-oriented; no change needed.\n\t//\n\t// Cross-runtime caveat: some orchestrators wrap stdout in a way\n\t// that bypasses `_handle.setBlocking`, and `_handle` is undefined\n\t// in some Node versions. We log a warning to STDERR if we can't\n\t// apply the call so the operator can fall back to polling\n\t// proactively instead of debugging missing-events ghosts.\n\t//\n\t// We also track the blocking-mode outcome so we can include it\n\t// in the startup ping below — operators piping --tail --json\n\t// into a buffered runtime want to see the flag immediately, not\n\t// wait for the first event.\n\tlet stdoutBlockingApplied = false;\n\tif (!process.stdout.isTTY) {\n\t\tconst handle = (process.stdout as unknown as { _handle?: { setBlocking?: (b: boolean) => void } })._handle;\n\t\tconst setBlocking = handle?.setBlocking;\n\t\tif (typeof setBlocking === 'function') {\n\t\t\tsetBlocking.call(handle, true);\n\t\t\tstdoutBlockingApplied = true;\n\t\t} else {\n\t\t\t// stderr — doesn't pollute the stdout NDJSON stream that\n\t\t\t// callers pipe into jq.\n\t\t\tconsole.error(\n\t\t\t\tchalk.yellow(\n\t\t\t\t\t'⚠ inbox --tail: stdout is piped but `process.stdout._handle.setBlocking` is unavailable in this Node runtime. Buffered writes may delay event delivery. Fall back to polling (`heyarp inbox --json`) if events stop arriving.',\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t}\n\tconst api = new ArpApiClient(opts.server);\n\n\t// One-shot startup ping: emit a deterministic `tail.started` line\n\t// BEFORE opening the SSE stream so callers can distinguish \"SSE\n\t// is alive but no events yet\" from \"process is hung pre-stream\".\n\t// Distinct from the server-driven `'connected'` event which\n\t// arrives later (after SSE handshake).\n\tif (opts.json) {\n\t\tconsole.log(formatTailStartedPing({ server: api.serverUrl, signer: local.did, stdoutBlockingApplied }));\n\t} else {\n\t\tconsole.log(chalk.dim(`Server: ${api.serverUrl}`));\n\t\tconsole.log(chalk.dim(`Signer: ${local.did}`));\n\t\tconsole.log(chalk.dim('Mode: --tail (live SSE, Ctrl-C to stop)'));\n\t}\n\n\tconst controller = new AbortController();\n\t// Track whether the user explicitly aborted (Ctrl-C / SIGTERM)\n\t// vs the stream ending for some other reason (server restart,\n\t// proxy timeout, mongo blip). Worker mode promises a long-\n\t// lived tail — silent EOF must be a non-zero exit, not \"looks\n\t// like the work succeeded\".\n\tlet userAborted = false;\n\tconst onSignal = () => {\n\t\tuserAborted = true;\n\t\tcontroller.abort();\n\t};\n\tprocess.once('SIGINT', onSignal);\n\tprocess.once('SIGTERM', onSignal);\n\n\tconst signer = makeSigner(local);\n\n\ttry {\n\t\tfor await (const event of api.streamInbox(did, signer, { signal: controller.signal })) {\n\t\t\tif (opts.json) {\n\t\t\t\t// Machine-readable mode: one JSON object per line\n\t\t\t\t// (NDJSON), pipe-safe into `jq -c`.\n\t\t\t\tconsole.log(JSON.stringify(event));\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (event.type === 'heartbeat') continue; // silent\n\t\t\tif (event.type === 'connected') {\n\t\t\t\tconsole.log(chalk.green('● stream open — listening for envelopes...'));\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (event.type === 'envelope') {\n\t\t\t\tconst ev = event.data as EventPublic;\n\t\t\t\tconsole.log(formatInboxTable([ev], { fullIds: !!opts.fullIds }));\n\t\t\t\tif (opts.verbose) {\n\t\t\t\t\tprintVerbose([ev], 'Full event envelope:', (e) => ({\n\t\t\t\t\t\tprimary: `#${e.relationshipEventIndex} ${e.type ?? '<unknown>'}`,\n\t\t\t\t\t\tsecondary: `eventId=${e.eventId} serverEventHash=${e.serverEventHash}`,\n\t\t\t\t\t}));\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// Unknown event type — surface it dim so we don't drop new server-side directives silently.\n\t\t\tconsole.log(chalk.dim(`(unknown event: ${event.type})`));\n\t\t}\n\n\t\t// `for await` exited without throwing AND without abort\n\t\t// firing. Server-driven EOF — the stream went quiet on\n\t\t// us. For worker-loop callers this is a real failure\n\t\t// (the process advertised \"long-lived tail\" and just\n\t\t// stopped listening); surface it as a non-zero exit so\n\t\t// supervisor scripts can restart.\n\t\tif (!userAborted) {\n\t\t\tthrow new Error('inbox --tail: stream ended unexpectedly (server may have restarted, or change stream errored). Re-run to reconnect.');\n\t\t}\n\t} catch (err) {\n\t\t// AbortError is the expected exit path on Ctrl-C; quiet it.\n\t\tconst name = (err as { name?: string }).name;\n\t\tif (name === 'AbortError' || userAborted) {\n\t\t\tif (!opts.json) console.log(chalk.dim('\\nstream closed.'));\n\t\t\treturn;\n\t\t}\n\t\tthrow err;\n\t} finally {\n\t\tprocess.off('SIGINT', onSignal);\n\t\tprocess.off('SIGTERM', onSignal);\n\t}\n}\n\n/**\n * Render inbox events as a 5-column table: time, type, sender,\n * relationship event index, and the head of the server event hash.\n * The full eventId + serverTimestamp are shown below the table so the\n * operator can manually paginate without copy-paste truncation.\n */\nfunction formatInboxTable(events: EventPublic[], opts: { fullIds?: boolean } = {}): string {\n\tconst header = opts.fullIds ? ['Time', 'Type', 'From (full DID)', 'Index', 'serverEventHash'] : ['Time', 'Type', 'From', 'Index', 'Hash (head)'];\n\tconst data = events.map((ev) => [\n\t\tev.serverTimestamp,\n\t\tev.type,\n\t\tev.senderDid,\n\t\tString(ev.relationshipEventIndex),\n\t\topts.fullIds ? ev.serverEventHash : hashHead(ev.serverEventHash),\n\t]);\n\tconst widths = header.map((h, i) => Math.max(h.length, ...data.map((row) => row[i].length)));\n\tconst pad = (cells: string[]): string => cells.map((c, i) => c.padEnd(widths[i])).join(' ');\n\tconst lines = [chalk.bold(pad(header)), chalk.dim(pad(widths.map((w) => '-'.repeat(w)))), ...data.map((row) => pad(row))];\n\tconst detail = events.map((ev) => ` ${chalk.dim('eventId:')} ${chalk.cyan(ev.eventId)} ${chalk.dim('serverTimestamp:')} ${chalk.cyan(ev.serverTimestamp)}`).join('\\n');\n\treturn `${lines.join('\\n')}\\n\\n${chalk.bold('Pagination cursors')} (last → first):\\n${detail}`;\n}\n\n/**\n * Trim a `sha256:<hex>` hash down to a recognisable prefix for table\n * display. Operator can match it against the \"Full events\" dump below\n * when `--verbose`.\n */\nfunction hashHead(hash: string | null | undefined): string {\n\tif (!hash) return chalk.dim('(none)');\n\tif (hash.length <= 14) return hash;\n\treturn `${hash.slice(0, 14)}...`;\n}\n\nfunction parseLimit(raw: string | undefined): number {\n\tif (raw === undefined) return 20;\n\tconst n = Number(raw);\n\tif (!Number.isFinite(n) || !Number.isInteger(n) || n < 1 || n > 100) {\n\t\tthrow new Error(`inbox: --limit must be an integer between 1 and 100 (got '${raw}')`);\n\t}\n\treturn n;\n}\n","import { base58btcEncode, generateKeyPair, getPublicKey, formatDid as sdkFormatDid } from '@heyanon-arp/sdk';\nimport chalk from 'chalk';\nimport type { Command } from 'commander';\n\n/**\n * `heyarp keys gen` — emit a fresh identity + settlement keypair pair.\n *\n * No I/O by default; pure stdout. Output is deliberately verbose\n * (labelled fields rather than a JSON blob) because the operator is\n * almost always copy-pasting one piece of it into a shell.\n *\n * `--save` is intentionally a TODO: storing keys without a DID isn't\n * meaningful for the V1 state shape — we'd need a \"scratch\" namespace.\n * Leaving the flag wired up + a clear message so the surface is\n * discoverable when we revisit.\n */\nexport function registerKeysCommand(root: Command): void {\n\tconst keys = root.command('keys').description('Local key utilities');\n\n\tkeys.command('gen')\n\t\t.description('Generate a fresh identity + settlement keypair (no save by default)')\n\t\t.option('--save', 'Reserved for future scratch-key storage; currently a no-op with a notice', false)\n\t\t.action((opts: { save?: boolean }) => {\n\t\t\tconst identity = generateKeyPair();\n\t\t\tconst settlement = generateKeyPair();\n\n\t\t\tconst out = [\n\t\t\t\tchalk.bold('Identity key (Ed25519)'),\n\t\t\t\t` public (base58btc): ${chalk.cyan(base58btcEncode(identity.publicKey))}`,\n\t\t\t\t` secret (base64) : ${chalk.yellow(Buffer.from(identity.secretKey).toString('base64'))}`,\n\t\t\t\t'',\n\t\t\t\tchalk.bold('Settlement key (Ed25519)'),\n\t\t\t\t` public (base58btc): ${chalk.cyan(base58btcEncode(settlement.publicKey))}`,\n\t\t\t\t` secret (base64) : ${chalk.yellow(Buffer.from(settlement.secretKey).toString('base64'))}`,\n\t\t\t\t'',\n\t\t\t\tchalk.bold('Resulting DID'),\n\t\t\t\t` ${chalk.cyan(sdkFormatDid(identity.publicKey))}`,\n\t\t\t];\n\t\t\tconsole.log(out.join('\\n'));\n\n\t\t\tif (opts.save) {\n\t\t\t\t// TODO: implement --save once we decide the scratch-key\n\t\t\t\t// state shape (probably a separate `scratch` bucket keyed by\n\t\t\t\t// fingerprint, ttl-pruned). For now don't silently succeed.\n\t\t\t\tconsole.log(chalk.yellow('\\nNote: --save is not yet implemented. Capture the secret keys above before they scroll off-screen.'));\n\t\t\t}\n\t\t});\n\n\tkeys.command('whoami')\n\t\t.description('Print the DID derived from a base64-encoded identity secret key')\n\t\t.argument('<secret-key-b64>', '32-byte Ed25519 seed, base64')\n\t\t.action((secretKeyB64: string) => {\n\t\t\tconst seed = decodeSeed(secretKeyB64);\n\t\t\tconst pub = getPublicKey(seed);\n\t\t\tconst did = sdkFormatDid(pub);\n\t\t\tconsole.log(`${chalk.bold('DID')}: ${chalk.cyan(did)}`);\n\t\t\tconsole.log(`${chalk.bold('Identity public key (base58btc)')}: ${chalk.cyan(base58btcEncode(pub))}`);\n\t\t});\n}\n\n/**\n * Decode a 32-byte seed from base64. Throws a CLI-friendly error if\n * the string isn't the right length — Ed25519 has a fixed seed size,\n * and a wrong length almost always means the user pasted the public\n * key by mistake.\n */\nfunction decodeSeed(b64: string): Uint8Array {\n\tlet bytes: Buffer;\n\ttry {\n\t\tbytes = Buffer.from(b64, 'base64');\n\t} catch {\n\t\tthrow new Error('whoami: argument is not valid base64');\n\t}\n\tif (bytes.length !== 32) {\n\t\tthrow new Error(`whoami: expected a 32-byte Ed25519 seed, got ${bytes.length} bytes — did you paste the wrong field?`);\n\t}\n\treturn new Uint8Array(bytes);\n}\n","import chalk from 'chalk';\nimport type { Command } from 'commander';\nimport { formatAgentsTable } from '../format';\nimport { listAgents, stateFilePath } from '../state';\n\n/**\n * `heyarp list` — read-only dump of the local state file. Groups by\n * server URL because the same workstation may have agents registered\n * against multiple deployments (dev / prod). No network calls.\n */\nexport function registerListCommand(root: Command): void {\n\troot.command('list')\n\t\t.description('List agents registered locally (~/.arp/agents.json)')\n\t\t.action(() => {\n\t\t\tconst rows = listAgents();\n\t\t\tif (rows.length === 0) {\n\t\t\t\tconsole.log(chalk.dim(`No local agents. State file: ${stateFilePath()}`));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst grouped = new Map<string, typeof rows>();\n\t\t\tfor (const r of rows) {\n\t\t\t\tif (!grouped.has(r.serverUrl)) grouped.set(r.serverUrl, []);\n\t\t\t\tgrouped.get(r.serverUrl)!.push(r);\n\t\t\t}\n\t\t\tlet first = true;\n\t\t\tfor (const [serverUrl, group] of grouped) {\n\t\t\t\tif (!first) console.log('');\n\t\t\t\tfirst = false;\n\t\t\t\tconsole.log(chalk.bold(`Server: ${serverUrl}`));\n\t\t\t\tconsole.log(formatAgentsTable(group.map(({ agent }) => ({ did: agent.did, name: agent.name, tags: agent.tags, registeredAt: agent.registeredAt }))));\n\t\t\t}\n\t\t});\n}\n","import { type Did, type MemoryDeltaBody, type MemoryDeltaContent, Purpose, type SignableProtected, expiresAt, rfc3339, senderNonce, signEnvelope, uuidV4 } from '@heyanon-arp/sdk';\nimport chalk from 'chalk';\nimport type { Command } from 'commander';\nimport { ApiError, ArpApiClient, type IngestResult, type MemoryEntryPublic, type Signer } from '../api';\nimport { formatJson } from '../format';\nimport { type AgentLocalState, resolveSenderAgent, updateAgentLocal } from '../state';\nimport { makeSigner } from './lifecycle';\n\n/**\n * `heyarp memory <subcommand>` — operator interface to the\n * memory-delta body type.\n *\n * add <recipient-did> --kind X --scope Y --content \"…\"\n * [--commit-after Z --delegation-id D]\n * [--supersedes <entry-id>] [--ttl N] [--verbose]\n * Builds + signs a `memory_delta` envelope and sends it.\n *\n * list <relationship-id> [--kind K] [--scope S] [--author-did D]\n * [--after CURSOR] [--limit N]\n * Read `memory_entries` for the relationship newest-first.\n *\n * show <entry-id> [--json]\n * Fetch one row by its server Mongo `_id`.\n *\n * Add fires a `memory_delta` envelope. With `--commit-after immediate`\n * (default) the row lands in `memory_entries` straight away. With\n * `--commit-after settlement_finalized` it stages in `memory_pending`\n * gated on the linked delegation's settlement (release / partial /\n * refund) — the server's `SettlementEventBus` subscriber commits or\n * cancels the row when the indexer projects the on-chain event.\n *\n * V1 ships unilateral writes only — `signedBy` will carry a single\n * entry (the author). Cosigned writes (`signedBy.length >= 2`) are\n * a V1.5+ extension that requires a counter-sign round trip; the\n * CLI surface here doesn't model it.\n */\nexport function registerMemoryCommands(root: Command): void {\n\tconst cmd = root.command('memory').description('Memory deltas: write, list, fetch one.');\n\n\tregisterAdd(cmd);\n\tregisterList(cmd);\n\tregisterShow(cmd);\n}\n\n/**\n * Error codes that indicate the server PERSISTED the memory_delta\n * event row (so the `sender_sequence` was consumed) but the body\n * handler then rejected or downgraded the action. Mirror of the\n * delegation/contract policies: advance `lastSenderSequence` so the\n * NEXT envelope doesn't wedge on `ENV_SEQUENCE_BACKWARDS`.\n *\n * Both `DOM_MEMORY_SUPERSEDES_*` codes fire AFTER the event row\n * persists (POST_COMMIT semantics), so the CLI must bump the\n * sender_sequence even on rejection — otherwise the next memory\n * write reuses a consumed sequence and wedges.\n *\n * `MEMORY_SUPERSEDES_NOT_FOUND` (legacy, no DOM_ prefix) retained\n * for forward-compat with any older server build still in\n * production; new code paths emit the `DOM_*` form.\n */\nexport const POST_COMMIT_ERROR_CODES = new Set([\n\t'MEMORY_DELEGATION_NOT_FOUND',\n\t'MEMORY_DELEGATION_NOT_SETTLED',\n\t'MEMORY_RELATIONSHIP_MISMATCH',\n\t'MEMORY_COMMIT_AFTER_REQUIRES_DELEGATION',\n\t'MEMORY_SUPERSEDES_NOT_FOUND',\n\t'DOM_MEMORY_SUPERSEDES_NOT_FOUND',\n\t'DOM_MEMORY_SUPERSEDES_AUTHOR_MISMATCH',\n]);\n\n// =========================================================================\n// memory add\n// =========================================================================\n\ninterface AddOptions {\n\tserver?: string;\n\tfromDid?: string;\n\tkind?: string;\n\tscope?: string;\n\tcontent?: string;\n\tcommitAfter?: string;\n\tdelegationId?: string;\n\tsupersedes?: string;\n\tttl?: string;\n\tverbose?: boolean;\n}\n\nconst VALID_KINDS = new Set(['intro', 'handoff', 'preference', 'note', 'decision', 'continuity']);\nconst VALID_SCOPES = new Set(['thread_only', 'thread_and_pilot']);\nconst VALID_COMMIT_AFTER = new Set(['immediate', 'settlement_finalized', 'release_lock_finalized', 'partial_release_finalized']);\n\nfunction registerAdd(parent: Command): void {\n\tparent\n\t\t.command('add')\n\t\t.description('Send a `memory_delta` envelope to <recipient-did>. Lands in memory_entries (immediate) or memory_pending (settlement-gated).')\n\t\t.argument('<recipient-did>', 'Recipient agent DID (did:arp:...)')\n\t\t.option('--server <url>', 'Override ARP server base URL')\n\t\t.option('--from-did <did>', 'Sender DID — required only if multiple agents are registered against this server')\n\t\t.option('--kind <s>', 'Memory kind — one of: intro, handoff, preference, note, decision, continuity. REQUIRED.')\n\t\t.option('--scope <s>', 'Memory scope — one of: thread_only, thread_and_pilot. REQUIRED.')\n\t\t.option('--content <s>', 'Memory content (free-form string, max 5000 chars per V1 body schema). REQUIRED.')\n\t\t.option(\n\t\t\t'--commit-after <s>',\n\t\t\t\"When the row commits to `memory_entries`. `immediate` (default) lands the row instantly. `settlement_finalized` / `release_lock_finalized` / `partial_release_finalized` stage in `memory_pending` and commit when the linked delegation's settlement event projects. REQUIRES --delegation-id when not `immediate`.\",\n\t\t\t'immediate',\n\t\t)\n\t\t.option('--delegation-id <uuid>', 'Delegation whose settlement gates the commit. REQUIRED when --commit-after != immediate.')\n\t\t.option(\n\t\t\t'--supersedes <entry-id>',\n\t\t\t\"Optional `id` of an earlier memory entry this one supersedes (for revising prior memory). The value is the `id` field returned by `heyarp memory list` (24-hex Mongo ObjectId string). The server enforces that the supersede target MUST exist in this relationship AND be authored by the sender — cross-author hijack rejects with `DOM_MEMORY_SUPERSEDES_AUTHOR_MISMATCH`; dangling pointers reject with `DOM_MEMORY_SUPERSEDES_NOT_FOUND`.\",\n\t\t)\n\t\t.option('--ttl <seconds>', 'Envelope TTL in seconds (max 86400 = 24h).', '3600')\n\t\t.option('--verbose', 'Print the full envelope before sending and the full server response.', false)\n\t\t.action(async (recipientDid: string, opts: AddOptions) => {\n\t\t\tawait runAdd(recipientDid, opts);\n\t\t});\n}\n\nexport interface MemoryAddBodyShape {\n\tkind: MemoryDeltaContent['kind'];\n\tscope: MemoryDeltaContent['scope'];\n\tcontent: string;\n\tsupersedes?: string;\n\tcommit_after?: string;\n\tdelegation_id?: string;\n}\n\n/**\n * Pure mapper from CLI options to the `body.content` JSON the SDK\n * envelope signer accepts. Exported for unit tests so the option-parsing\n * + validation surface is testable without spinning the full HTTP stack.\n */\nexport function parseAddOptions(cmdName: string, opts: AddOptions): MemoryAddBodyShape {\n\tif (typeof opts.kind !== 'string' || !VALID_KINDS.has(opts.kind)) {\n\t\tthrow new Error(`${cmdName}: --kind must be one of ${[...VALID_KINDS].join('|')} (got '${opts.kind ?? '(undefined)'}')`);\n\t}\n\tif (typeof opts.scope !== 'string' || !VALID_SCOPES.has(opts.scope)) {\n\t\tthrow new Error(`${cmdName}: --scope must be one of ${[...VALID_SCOPES].join('|')} (got '${opts.scope ?? '(undefined)'}')`);\n\t}\n\tif (typeof opts.content !== 'string' || opts.content.length === 0) {\n\t\tthrow new Error(`${cmdName}: --content is required (non-empty string, max 5000 chars).`);\n\t}\n\tif (opts.content.length > 5000) {\n\t\tthrow new Error(`${cmdName}: --content is ${opts.content.length} chars; V1 body schema caps at 5000.`);\n\t}\n\tconst commitAfter = opts.commitAfter ?? 'immediate';\n\tif (!VALID_COMMIT_AFTER.has(commitAfter)) {\n\t\tthrow new Error(`${cmdName}: --commit-after must be one of ${[...VALID_COMMIT_AFTER].join('|')} (got '${commitAfter}').`);\n\t}\n\tif (commitAfter !== 'immediate' && (typeof opts.delegationId !== 'string' || opts.delegationId.length === 0)) {\n\t\tthrow new Error(`${cmdName}: --commit-after=${commitAfter} requires --delegation-id <uuid> (the delegation whose settlement gates the commit).`);\n\t}\n\tif (commitAfter === 'immediate' && opts.delegationId !== undefined) {\n\t\t// Allowed but warn — operator probably meant settlement_finalized.\n\t\tconsole.error(chalk.yellow(`${cmdName}: --delegation-id is set but --commit-after=immediate; the delegation_id will be persisted but not used as a settlement gate.`));\n\t}\n\n\tconst out: MemoryAddBodyShape = {\n\t\tkind: opts.kind as MemoryDeltaContent['kind'],\n\t\tscope: opts.scope as MemoryDeltaContent['scope'],\n\t\tcontent: opts.content,\n\t};\n\tif (opts.supersedes) out.supersedes = opts.supersedes;\n\t// `commit_after` is omitted when immediate (the server defaults).\n\tif (commitAfter !== 'immediate') {\n\t\tout.commit_after = commitAfter;\n\t\tout.delegation_id = opts.delegationId as string;\n\t} else if (opts.delegationId) {\n\t\tout.delegation_id = opts.delegationId;\n\t}\n\treturn out;\n}\n\nasync function runAdd(recipientDid: string, opts: AddOptions): Promise<void> {\n\tconst api = new ArpApiClient(opts.server);\n\tconst sender = resolveSenderAgent('memory add', opts.server, opts.fromDid);\n\tconst ttlSeconds = parseTtl('memory add', opts.ttl);\n\tconst bodyContent = parseAddOptions('memory add', opts);\n\n\t// `MemoryDeltaContent` is missing the catch-all `[extra: string]:\n\t// unknown` index signature that ContractContent / DelegationContent\n\t// have, so the `signEnvelope` generic narrows to a stricter `Body`\n\t// shape. Cast through `unknown` matches what `contract.ts` does for\n\t// the same reason — local to the CLI, harmless since the server\n\t// re-validates the body shape anyway.\n\tconst body = {\n\t\ttype: 'memory_delta',\n\t\tcontent: bodyContent,\n\t} as unknown as MemoryDeltaBody;\n\n\tconst result = await sendMemoryEnvelope({\n\t\tapi,\n\t\tsender,\n\t\trecipientDid,\n\t\tbody,\n\t\tttlSeconds,\n\t\tverbose: opts.verbose,\n\t\tserver: opts.server,\n\t});\n\n\tif (opts.verbose) {\n\t\tconsole.log(chalk.bold('\\nServer response:'));\n\t\tconsole.log(formatJson(result));\n\t}\n\tconsole.log(chalk.green(`\\nmemory_delta event ${result.eventId} accepted (commit_after=${bodyContent.commit_after ?? 'immediate'})`));\n\tconsole.log(chalk.dim(`relationshipId: ${result.relationshipId}`));\n\tconsole.log(chalk.dim(`serverEventHash: ${result.serverEventHash}`));\n}\n\ninterface SendArgs {\n\tapi: ArpApiClient;\n\tsender: AgentLocalState;\n\trecipientDid: string;\n\tbody: MemoryDeltaBody;\n\tttlSeconds: number;\n\tverbose: boolean | undefined;\n\tserver: string | undefined;\n}\n\nasync function sendMemoryEnvelope(args: SendArgs): Promise<IngestResult> {\n\tconst nextSequence = (args.sender.lastSenderSequence ?? 0) + 1;\n\tconst protectedBlock: SignableProtected = {\n\t\tprotocol_version: 'arp/0.1',\n\t\tpurpose: Purpose.ENVELOPE,\n\t\tmessage_id: uuidV4(),\n\t\tsender_did: args.sender.did as Did,\n\t\trecipient_did: args.recipientDid as Did,\n\t\trelationship_id: null,\n\t\tsender_sequence: nextSequence,\n\t\tsender_nonce: senderNonce(),\n\t\ttimestamp: rfc3339(),\n\t\texpires_at: expiresAt(args.ttlSeconds),\n\t\tdelivery_id: null,\n\t};\n\n\tconst signer = makeSigner(args.sender);\n\t// Same widening cast as in `runAdd`: signEnvelope's Body generic\n\t// requires `content` to extend `Record<string, unknown>`; the\n\t// MemoryDeltaContent type doesn't carry an index signature. Cast\n\t// is harmless — the SDK consumes the body bytes opaquely once\n\t// signing starts.\n\tconst envelope = signEnvelope({\n\t\tprotected: protectedBlock,\n\t\tbody: args.body as unknown as Parameters<typeof signEnvelope>[0]['body'],\n\t\tidentitySecretKey: signer.identitySecretKey,\n\t});\n\n\tif (args.verbose) {\n\t\tconsole.log(chalk.bold('\\nEnvelope (pre-send):'));\n\t\tconsole.log(formatJson(envelope));\n\t}\n\n\ttry {\n\t\tconst result = await args.api.ingest(envelope);\n\t\tupdateAgentLocal(args.server, args.sender.did, { lastSenderSequence: nextSequence });\n\t\treturn result;\n\t} catch (err) {\n\t\tif (err instanceof ApiError && POST_COMMIT_ERROR_CODES.has(err.payload.code)) {\n\t\t\tupdateAgentLocal(args.server, args.sender.did, { lastSenderSequence: nextSequence });\n\t\t}\n\t\tthrow err;\n\t}\n}\n\n// =========================================================================\n// memory list\n// =========================================================================\n\ninterface ListOptions {\n\tserver?: string;\n\tfromDid?: string;\n\tkind?: string;\n\tscope?: string;\n\tauthorDid?: string;\n\tafter?: string;\n\tlimit?: string;\n\tjson?: boolean;\n}\n\nfunction registerList(parent: Command): void {\n\tparent\n\t\t.command('list')\n\t\t.description('List committed memory entries for a relationship (newest first).')\n\t\t.argument('<relationship-id>', 'Relationship UUID')\n\t\t.option('--server <url>', 'Override ARP server base URL')\n\t\t.option('--from-did <did>', 'Signer DID — required only if multiple agents are registered against this server')\n\t\t.option('--kind <s>', 'Filter by kind (intro|handoff|preference|note|decision|continuity)')\n\t\t.option('--scope <s>', 'Filter by scope (thread_only|thread_and_pilot)')\n\t\t.option('--author-did <did>', 'Filter by author DID — only return entries written by this agent')\n\t\t.option('--after <id>', \"Pagination cursor — Mongo `_id` from the previous page's last row\")\n\t\t.option('--limit <n>', 'Maximum rows per page (default 20)', '20')\n\t\t.option('--json', 'Machine-readable: emit only the JSON array on stdout (no chalk).', false)\n\t\t.action(async (relationshipId: string, opts: ListOptions) => {\n\t\t\tawait runList(relationshipId, opts);\n\t\t});\n}\n\nasync function runList(relationshipId: string, opts: ListOptions): Promise<void> {\n\tconst api = new ArpApiClient(opts.server);\n\tconst sender = resolveSenderAgent('memory list', opts.server, opts.fromDid);\n\tconst signer = makeSigner(sender);\n\n\tconst limitN = parseLimit('memory list', opts.limit);\n\tconst rows = await api.listRelationshipMemory(relationshipId, signer, {\n\t\tkind: opts.kind,\n\t\tscope: opts.scope,\n\t\tauthorDid: opts.authorDid,\n\t\tafter: opts.after,\n\t\tlimit: limitN,\n\t});\n\n\tif (opts.json) {\n\t\tconsole.log(JSON.stringify(rows));\n\t\treturn;\n\t}\n\n\tif (rows.length === 0) {\n\t\tconsole.log(chalk.dim('(no memory entries)'));\n\t\treturn;\n\t}\n\tfor (const r of rows) {\n\t\tconsole.log(formatMemoryLine(r));\n\t}\n\tif (rows.length === limitN) {\n\t\tconst lastId = rows[rows.length - 1].id;\n\t\tconsole.log(chalk.dim(`\\nPage may not be complete — paginate with --after ${lastId}`));\n\t}\n}\n\n/**\n * Single-line memory row format:\n *\n * <id-head> | <kind> | <scope> | <authorDid-tail> | \"<content-preview>\"\n *\n * Exported for unit tests.\n */\nexport function formatMemoryLine(r: MemoryEntryPublic): string {\n\tconst idHead = `${r.id.slice(0, 8)}...${r.id.slice(-4)}`;\n\tconst authorTail = r.authorDid.length > 20 ? `${r.authorDid.slice(0, 14)}...${r.authorDid.slice(-4)}` : r.authorDid;\n\tconst contentPreview = r.content.length > 60 ? `${r.content.slice(0, 57)}...` : r.content;\n\tconst cosignedTag = r.isCosigned ? chalk.yellow(' (cosigned)') : '';\n\tconst gatedTag = r.delegationId ? chalk.cyan(' (settlement-gated)') : '';\n\treturn `${chalk.dim(idHead)} | ${chalk.magenta(r.kind)} | ${chalk.dim(r.scope)} | ${chalk.dim(authorTail)} | ${chalk.cyan(`\"${contentPreview}\"`)}${cosignedTag}${gatedTag}`;\n}\n\n// =========================================================================\n// memory show\n// =========================================================================\n\ninterface ShowOptions {\n\tserver?: string;\n\tfromDid?: string;\n\tjson?: boolean;\n}\n\nfunction registerShow(parent: Command): void {\n\tparent\n\t\t.command('show')\n\t\t.description('Fetch one memory entry by its server `_id`.')\n\t\t.argument('<entry-id>', 'Memory entry `id` (24-hex string). Get this from `heyarp memory list <rel-id> --json | jq \".[].id\"`. The public DTO surfaces Mongo `_id` as the `id` field.')\n\t\t.option('--server <url>', 'Override ARP server base URL')\n\t\t.option('--from-did <did>', 'Signer DID — required only if multiple agents are registered against this server')\n\t\t.option('--json', 'Machine-readable: emit only the JSON object on stdout (no chalk).', false)\n\t\t.action(async (entryId: string, opts: ShowOptions) => {\n\t\t\tawait runShow(entryId, opts);\n\t\t});\n}\n\nasync function runShow(entryId: string, opts: ShowOptions): Promise<void> {\n\tconst api = new ArpApiClient(opts.server);\n\tconst sender = resolveSenderAgent('memory show', opts.server, opts.fromDid);\n\tconst signer = makeSigner(sender);\n\n\tconst row = await api.getMemoryEntry(entryId, signer);\n\tif (opts.json) {\n\t\tconsole.log(JSON.stringify(row));\n\t\treturn;\n\t}\n\n\tconsole.log(chalk.bold('Memory entry:'));\n\tconsole.log(formatJson(row));\n\tconsole.log('');\n\tconsole.log(`${chalk.dim('id:')} ${chalk.cyan(row.id)}`);\n\tconsole.log(`${chalk.dim('relationshipId:')} ${chalk.cyan(row.relationshipId)}`);\n\tconsole.log(`${chalk.dim('authorDid:')} ${chalk.cyan(row.authorDid)}`);\n\tconsole.log(`${chalk.dim('kind / scope:')} ${chalk.cyan(`${row.kind} / ${row.scope}`)}`);\n\tif (row.delegationId) {\n\t\tconsole.log(`${chalk.dim('delegationId:')} ${chalk.cyan(row.delegationId)} (settlement-gated)`);\n\t}\n\tif (row.supersedesId) {\n\t\tconsole.log(`${chalk.dim('supersedes:')} ${chalk.cyan(row.supersedesId)}`);\n\t}\n}\n\n// =========================================================================\n// shared helpers — exported for tests\n// =========================================================================\n\nexport function parseTtl(cmdName: string, raw: string | undefined): number {\n\tif (raw === undefined) return 3600;\n\tconst n = Number(raw);\n\tif (!Number.isFinite(n) || !Number.isInteger(n) || n <= 0) {\n\t\tthrow new Error(`${cmdName}: --ttl must be a positive integer (seconds); got '${raw}'`);\n\t}\n\tif (n > 86_400) {\n\t\tthrow new Error(`${cmdName}: --ttl ${n}s exceeds the 86400 (24h) cap`);\n\t}\n\treturn n;\n}\n\nexport function parseLimit(cmdName: string, raw: string | undefined): number {\n\tif (raw === undefined) return 20;\n\tconst n = Number(raw);\n\tif (!Number.isFinite(n) || !Number.isInteger(n) || n <= 0) {\n\t\tthrow new Error(`${cmdName}: --limit must be a positive integer; got '${raw}'`);\n\t}\n\tif (n > 100) {\n\t\tthrow new Error(`${cmdName}: --limit ${n} exceeds the 100 server cap`);\n\t}\n\treturn n;\n}\n","import {\n\ttype Did,\n\tPurpose,\n\ttype ReceiptBody,\n\ttype ReceiptContent,\n\ttype ReceiptCosignPayload,\n\ttype SignableProtected,\n\tcanonicalSha256Hex,\n\texpiresAt,\n\trfc3339,\n\tsenderNonce,\n\tsignCosignature,\n\tsignEnvelope,\n\tuuidV4,\n} from '@heyanon-arp/sdk';\nimport chalk from 'chalk';\nimport type { Command } from 'commander';\nimport { readFileSync } from 'node:fs';\nimport { ApiError, ArpApiClient, type DelegationPublic, type IngestResult, type ReceiptPublic, type RelationshipPublic, type Signer, type WorkLogPublic } from '../api';\nimport { formatActionError, formatJson } from '../format';\nimport { requireUuid as sharedRequireUuid } from '../id-format';\nimport { type AgentLocalState, resolveSenderAgent, updateAgentLocal } from '../state';\nimport { makeSigner } from './lifecycle';\nimport { fetchAllPages } from './status';\n\n/**\n * `heyarp receipt <action>` — bilateral commit cycle on top of an\n * ACCEPTED delegation:\n *\n * propose <recipient-did> <delegation-id> <request-hash> <response-hash>\n * [--verdict accepted|accepted_with_notes|rejected]\n * [--notes-hash <sha256>] [--deliverable-hash <sha256>]\n * [--input-tokens N --output-tokens N --latency-ms N --model NAME]\n * → posts the receipt envelope as the PAYEE; row lands PROPOSED.\n *\n * cosign <relationship-id> <delegation-id> <request-hash> <response-hash>\n * [--verdict accepted|accepted_with_notes|rejected]\n * [--notes-hash <sha256>]\n * → posts the cosign envelope as the CALLER. Auto-resolves\n * `recipient_did` (= payee) and `receipt_event_hash` from\n * the existing PROPOSED row; constructs + signs the\n * ReceiptCosignPayload; promotes the row to COSIGNED.\n *\n * Same shape as the other CLI body groups. Sequence-bump policy is\n * shared via `sendReceiptEnvelope`: advance unconditionally on 202,\n * advance on `POST_COMMIT_ERROR_CODES` ApiErrors (server consumed\n * the sequence even on body-handler reject), leave untouched on\n * pre-commit / network failure.\n */\nexport function registerReceiptCommands(root: Command): void {\n\tconst cmd = root.command('receipt').description('Receipt envelopes — payee proposes, caller cosigns');\n\n\tregisterPropose(cmd);\n\tregisterCosign(cmd);\n}\n\n/**\n * Error codes that indicate the server PERSISTED the event (so the\n * `sender_sequence` was consumed) but the body handler then rejected\n * the action. Mirror of the contract / delegation / work handler\n * lists.\n */\nexport const POST_COMMIT_ERROR_CODES = new Set([\n\t'RECEIPT_ALREADY_EXISTS',\n\t'RECEIPT_DELEGATION_NOT_FOUND',\n\t'RECEIPT_DELEGATION_NOT_ACTIVE',\n\t'RECEIPT_RELATIONSHIP_MISMATCH',\n\t'RECEIPT_ISSUER_IS_CALLER',\n\t'RECEIPT_NOT_FOUND',\n\t'RECEIPT_INVALID_STATE',\n\t'RECEIPT_COSIGNER_NOT_CALLER',\n\t'RECEIPT_COSIGN_AGENT_MISMATCH',\n\t'RECEIPT_COSIGN_PURPOSE_INVALID',\n\t'RECEIPT_COSIGN_INVALID',\n\t// Settlement-side rejections from the receipt cosign path.\n\t// Receipt-handler invokes\n\t// `ReceiptCosignValidatorService.enqueueReleaseOp` AFTER the\n\t// message-ingest commits the event row, so the sender sequence\n\t// is consumed even when the validator rejects. Without these\n\t// on the allowlist, a CLI retry after fixing the attachment\n\t// would reuse the old sequence and trip\n\t// `ENV_SEQUENCE_BACKWARDS`.\n\t//\n\t// This list MUST stay in lockstep with every `ESC_*` thrown by\n\t// `apps/arp-server/src/escrow/services/receipt-cosign-validator.service.ts`\n\t// + the settlement preflight in\n\t// `apps/arp-server/src/message/services/receipt-handler.service.ts`.\n\t// Sourced via:\n\t// grep -h \"'ESC_\" \\\n\t// apps/arp-server/src/escrow/services/receipt-cosign-validator.service.ts \\\n\t// apps/arp-server/src/message/services/receipt-handler.service.ts \\\n\t// | sed -E \"s/.*'(ESC_[A-Z_]+)'.*/\\1/\" | sort -u\n\t'ESC_LOCK_NOT_FOUND',\n\t'ESC_LOCK_NOT_LOCKED',\n\t'ESC_SETTLEMENT_EXPIRES_AT_EXCEEDS_LOCK',\n\t'ESC_SETTLEMENT_EXPIRES_AT_INVALID',\n\t'ESC_SETTLEMENT_EXPIRES_AT_PAST',\n\t'ESC_SETTLEMENT_EXPIRES_AT_TOO_SOON',\n\t'ESC_SETTLEMENT_PAYEE_AMOUNT_EXCEEDS',\n\t'ESC_SETTLEMENT_PAYEE_AMOUNT_MISSING',\n\t'ESC_SETTLEMENT_PUBKEY_MISMATCH',\n\t'ESC_SETTLEMENT_PURPOSE_INVALID',\n\t'ESC_SETTLEMENT_SIGS_MISSING',\n\t'ESC_SETTLEMENT_SIG_INVALID',\n\t// Server rejects receipt cosign when contract is usage_based AND\n\t// settlement_signatures.payee_amount !=\n\t// receipt.usage.computed_amount. Both fields are decimal-integer\n\t// base-unit strings compared as BigInt. Fires AFTER the cosign\n\t// event row commits, so the CLI advances lastSenderSequence.\n\t'ESC_USAGE_COMPUTED_AMOUNT_MISMATCH',\n\t// Server rejects usage_based propose when computed_amount >\n\t// lock.amount. Same lifecycle classification as MISMATCH — event\n\t// committed, body action rejected, CLI advances\n\t// lastSenderSequence.\n\t'ESC_USAGE_COMPUTED_AMOUNT_EXCEEDS_LOCK',\n]);\n\nconst VERDICT_VALUES = ['accepted', 'accepted_with_notes', 'rejected'] as const;\ntype Verdict = (typeof VERDICT_VALUES)[number];\n\nconst SHA256_RE = /^sha256:[0-9a-f]{64}$/;\n\n// ---------- propose ----------\n\ninterface ProposeOptions extends BaseSendOptions {\n\tverdict?: string;\n\tnotesHash?: string;\n\tdeliverableHash?: string;\n\tinputTokens?: string;\n\toutputTokens?: string;\n\tlatencyMs?: string;\n\tmodel?: string;\n\tcomputedAmount?: string;\n\tautoHashes?: boolean;\n\trelId?: string;\n\trequestId?: string;\n}\n\nfunction registerPropose(parent: Command): void {\n\tparent\n\t\t.command('propose')\n\t\t.description('Send a receipt envelope as the PAYEE. Row lands PROPOSED; caller cosigns to flip to COSIGNED.')\n\t\t.argument('<recipient-did>', 'Recipient agent DID (= caller / offerer of the parent delegation)')\n\t\t.argument('<delegation-id>', 'Parent delegation id (UUID, must be ACCEPTED)')\n\t\t.argument('[request-hash]', 'sha256:<64 hex> — SHA-256 of the work_request payload being settled. Omit when --auto-hashes is set.')\n\t\t.argument('[response-hash]', 'sha256:<64 hex> — SHA-256 of the work_response payload being settled. Omit when --auto-hashes is set.')\n\t\t.option('--server <url>', 'Override ARP server base URL')\n\t\t.option('--from-did <did>', 'Sender DID — required only if multiple agents are registered against this server')\n\t\t.option('--verdict <s>', 'verdict_proposed (accepted | accepted_with_notes | rejected)', 'accepted')\n\t\t.option('--notes-hash <sha256>', 'Optional sha256:<64 hex> notes hash')\n\t\t.option('--deliverable-hash <sha256>', 'Optional sha256:<64 hex> deliverable hash')\n\t\t.option('--input-tokens <n>', 'Optional usage.input_tokens')\n\t\t.option('--output-tokens <n>', 'Optional usage.output_tokens')\n\t\t.option('--latency-ms <n>', 'Optional usage.latency_ms')\n\t\t.option('--model <name>', 'Optional usage.model')\n\t\t.option('--computed-amount <s>', 'Optional usage.computed_amount')\n\t\t.option('--ttl <seconds>', 'Envelope TTL in seconds', '3600')\n\t\t.option(\n\t\t\t'--auto-hashes',\n\t\t\t'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 — pass them explicitly only if the lookup finds multiple candidates.',\n\t\t\tfalse,\n\t\t)\n\t\t.option(\n\t\t\t'--rel-id <id>',\n\t\t\t'Relationship UUID hosting the delegation. Required when --auto-hashes is set AND the delegation appears in >1 relationship. When omitted under --auto-hashes, the CLI auto-resolves by listing your relationships and picking the unique one that contains <delegation-id>.',\n\t\t)\n\t\t.option(\n\t\t\t'--request-id <r>',\n\t\t\t'work_request id (the same value you passed to `heyarp work request --request-id`). Required when --auto-hashes is set AND the delegation has >1 outstanding \"responded\" work_log. When omitted, the CLI auto-resolves to the unique responded work_log.',\n\t\t)\n\t\t.option('--verbose', 'Print the full envelope before sending and the full server response', false)\n\t\t.action(async (recipientDid: string, delegationId: string, requestHash: string | undefined, responseHash: string | undefined, opts: ProposeOptions, cmd: Command) => {\n\t\t\t// Defence-in-depth on the exit-code contract: the outer\n\t\t\t// `program.parseAsync` try/catch in `cli.ts` already\n\t\t\t// prints + exits 1 on a thrown error, but catching here\n\t\t\t// AND setting `process.exitCode = 1` (graceful — lets\n\t\t\t// stdio drain naturally vs. `process.exit(1)` racing the\n\t\t\t// buffered stderr write) closes the leak in case any\n\t\t\t// pipe-aware shell idiom would otherwise see exit 0\n\t\t\t// after a printed error.\n\t\t\t//\n\t\t\t// Routes via `formatActionError` so structured `[CODE]`\n\t\t\t// `ApiError` formatting + `--trace` behaviour are\n\t\t\t// preserved (the inner catch bypasses the outer cli.ts\n\t\t\t// formatter entirely).\n\t\t\ttry {\n\t\t\t\tawait runPropose(recipientDid, delegationId, requestHash, responseHash, opts);\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(formatActionError(err, cmd));\n\t\t\t\tprocess.exitCode = 1;\n\t\t\t}\n\t\t});\n}\n\nasync function runPropose(\n\trecipientDid: string,\n\tdelegationId: string,\n\trequestHashArg: string | undefined,\n\tresponseHashArg: string | undefined,\n\topts: ProposeOptions,\n): Promise<void> {\n\trequireDid('receipt propose', recipientDid, '<recipient-did>');\n\t// Normalise delegationId (signed into the body) + opts.relId\n\t// (URL path) so mixed-case input matches server-stored canonical\n\t// lowercase rows.\n\tdelegationId = requireUuidNormalised('receipt propose', delegationId, '<delegation-id>');\n\tif (opts.relId) opts.relId = requireUuidNormalised('receipt propose', opts.relId, '--rel-id');\n\tconst verdict = parseVerdict('receipt propose', opts.verdict);\n\tconst ttlSeconds = parseTtl('receipt propose', opts.ttl);\n\tif (opts.notesHash) requireSha256('receipt propose', opts.notesHash, '--notes-hash');\n\tif (opts.deliverableHash) requireSha256('receipt propose', opts.deliverableHash, '--deliverable-hash');\n\n\tconst usage = parseUsage('receipt propose', opts);\n\n\tconst api = new ArpApiClient(opts.server);\n\tconst sender = resolveSenderAgent('receipt propose', opts.server, opts.fromDid);\n\n\t// When --auto-hashes is set, auto-resolve --rel-id (and\n\t// downstream --request-id) from local state if the operator\n\t// omitted either. Do this BEFORE the payee-bind assertion below\n\t// so the resolved rel-id flows through.\n\t//\n\t// LLM-agent operators typically hit two sequential errors before\n\t// getting both flags right (first missing --rel-id, then missing\n\t// --request-id). When the delegation appears in exactly one of\n\t// the operator's relationships AND has exactly one 'responded'\n\t// work_log, the auto-resolution removes both errors entirely.\n\tif (opts.autoHashes && !opts.relId) {\n\t\topts.relId = await resolveAutoRelId(api, sender, delegationId);\n\t\tconsole.log(chalk.dim(`[auto-rel-id] resolved --rel-id=${opts.relId} (delegation found in exactly one of your relationships; pass --rel-id explicitly to override)`));\n\t}\n\n\t// Fail-fast: only the payee may propose. When --rel-id is\n\t// supplied (mandatory under --auto-hashes, but possibly\n\t// auto-resolved above), look up the delegation row and throw if\n\t// the sender is the caller. Skipped when --rel-id is absent —\n\t// the server still rejects post-commit in that case.\n\tif (opts.relId) {\n\t\tawait assertSenderIsReceiptPayee(api, sender, opts.relId, delegationId);\n\t}\n\n\t// Derive request_hash / response_hash from the work-log row when\n\t// `--auto-hashes` is set, sourced from the SDK's canonical\n\t// JCS+sha256 helper to match what the protocol expects.\n\tlet requestHash: string;\n\tlet responseHash: string;\n\tif (opts.autoHashes) {\n\t\t// rel-id was either explicit (validated above) or just\n\t\t// auto-resolved. Either way it must be present here.\n\t\tif (!opts.relId) {\n\t\t\tthrow new Error('receipt propose: --auto-hashes requires --rel-id <uuid> (work-log lookup is scoped to a relationship) — auto-resolution failed; pass it explicitly');\n\t\t}\n\t\tif (!opts.requestId) {\n\t\t\topts.requestId = await resolveAutoRequestId(api, sender, opts.relId, delegationId);\n\t\t\tconsole.log(chalk.dim(`[auto-request-id] resolved --request-id=${opts.requestId} (unique 'responded' work_log under this delegation; pass --request-id explicitly to override)`));\n\t\t}\n\t\t// opts.relId already normalised above; this is a defensive\n\t\t// no-throw shape check in case a future refactor moves the\n\t\t// normalisation.\n\t\trequireUuid('receipt propose', opts.relId, '--rel-id');\n\t\tconst computed = await computeWorkLogHashes(api, sender, opts.relId, delegationId, opts.requestId);\n\t\t// If the operator ALSO passed explicit positionals, treat\n\t\t// them as a consistency assertion against the computed\n\t\t// values — catches \"wrong delegation/request id\" before the\n\t\t// envelope ships.\n\t\tif (requestHashArg !== undefined && requestHashArg !== computed.requestHash) {\n\t\t\tthrow new Error(\n\t\t\t\t`receipt propose: --auto-hashes computed request_hash ${computed.requestHash}, but positional <request-hash> ${requestHashArg} disagrees — drop one or fix the inputs`,\n\t\t\t);\n\t\t}\n\t\tif (responseHashArg !== undefined && responseHashArg !== computed.responseHash) {\n\t\t\tthrow new Error(\n\t\t\t\t`receipt propose: --auto-hashes computed response_hash ${computed.responseHash}, but positional <response-hash> ${responseHashArg} disagrees — drop one or fix the inputs`,\n\t\t\t);\n\t\t}\n\t\trequestHash = computed.requestHash;\n\t\tresponseHash = computed.responseHash;\n\t\tconsole.log(chalk.dim(`[auto-hashes] request_hash: ${requestHash} (from work-log ${opts.relId}/${delegationId}/${opts.requestId})`));\n\t\tconsole.log(chalk.dim(`[auto-hashes] response_hash: ${responseHash}`));\n\t} else {\n\t\tif (requestHashArg === undefined || responseHashArg === undefined) {\n\t\t\tthrow new Error('receipt propose: <request-hash> and <response-hash> are required (or pass --auto-hashes + --rel-id + --request-id to derive them from the work-log)');\n\t\t}\n\t\trequireSha256('receipt propose', requestHashArg, '<request-hash>');\n\t\trequireSha256('receipt propose', responseHashArg, '<response-hash>');\n\t\trequestHash = requestHashArg;\n\t\tresponseHash = responseHashArg;\n\t}\n\n\tconst content: ReceiptContent = {\n\t\tdelegation_id: delegationId,\n\t\trequest_hash: requestHash as ReceiptContent['request_hash'],\n\t\tresponse_hash: responseHash as ReceiptContent['response_hash'],\n\t\tverdict_proposed: verdict,\n\t};\n\tif (opts.notesHash) content.notes_hash = opts.notesHash as ReceiptContent['notes_hash'];\n\tif (opts.deliverableHash) content.deliverable_hash = opts.deliverableHash as ReceiptContent['deliverable_hash'];\n\tif (usage) content.usage = usage;\n\tconst body: ReceiptBody = { type: 'receipt', content };\n\n\tconsole.log(chalk.dim(`Server: ${api.serverUrl}`));\n\tconsole.log(chalk.dim(`Sender (payee): ${sender.did}`));\n\tconsole.log(chalk.dim(`Recipient (caller): ${recipientDid}`));\n\tconsole.log(chalk.dim(`Delegation: ${delegationId}`));\n\tconsole.log(chalk.dim(`Verdict (proposed): ${verdict}`));\n\n\tconst result = await sendReceiptEnvelope({ api, sender, recipientDid, body, attachments: undefined, ttlSeconds, verbose: opts.verbose, server: opts.server });\n\tprintIngestResult(result);\n\tconsole.log(chalk.dim(`\\nReceipt event hash: ${chalk.cyan(result.serverEventHash)}`));\n\tconsole.log(chalk.dim(`The caller cosigns with:`));\n\tconsole.log(chalk.dim(` heyarp receipt cosign ${result.relationshipId} ${delegationId} ${requestHash} ${responseHash} --verdict ${verdict}`));\n}\n\n/**\n * Look up the work-log row for (relationshipId, delegationId,\n * requestId) and compute the canonical `sha256:<hex>` values that\n * the receipt body's `request_hash` / `response_hash` fields expect.\n *\n * Matches the server's hash semantics exactly: SHA-256 of canonical\n * JSON (RFC 8785) of the FULL work_request / work_response body —\n * the `{ type, content: {...} }` envelope shape, not just the inner\n * `params`/`output`. Mirrors `findReceiptForWorkLog` from\n * `commands/status.ts`; both pieces of code use the same body\n * reconstruction so a future spec drift in canonical-form has one\n * place to update.\n *\n * Throws if:\n * - work-log row for (delegationId, requestId) isn't found\n * - work-log is still in REQUESTED (no response yet → no\n * response-body to hash)\n *\n * Exported for testability.\n */\n/**\n * CLI-side fail-fast for the \"caller accidentally tries to issue a\n * receipt\" footgun. The server enforces with\n * `RECEIPT_ISSUER_IS_CALLER`, but that's a POST_COMMIT error — the\n * envelope was already persisted and `sender_sequence` advanced, so\n * the CLI has to retry from the NEXT sequence. Catching the\n * role-swap CLI-side before the POST keeps the chain log clean (no\n * rejected envelope at chain index #N) and gives the operator an\n * actionable hint instead of a post-mortem trace.\n *\n * Mechanism: look up the delegation row by `(relationshipId,\n * delegationId)`. If `delegation.offererDid === sender.did`, the\n * sender is the CALLER (the buyer who proposed the delegation),\n * NOT the PAYEE (the worker who accepted it). Only the payee may\n * issue a receipt.\n *\n * Requires `relationshipId` — the only way to scope the\n * delegation list. When `--rel-id` is absent on `receipt propose`\n * (legacy positional-hashes path), the check is skipped and the\n * server's post-commit reject remains the only signal.\n *\n * Exported for unit-test coverage.\n */\nexport async function assertSenderIsReceiptPayee(\n\tapi: ArpApiClient,\n\tsender: AgentLocalState,\n\trelationshipId: string,\n\tdelegationId: string,\n): Promise<void> {\n\tconst signer = makeSigner(sender);\n\tconst rows = await fetchAllPages<DelegationPublic>((after) =>\n\t\tapi.listDelegations(relationshipId, signer, { limit: 100, ...(after ? { after } : {}) }),\n\t);\n\tconst delegation = rows.find((d) => d.delegationId === delegationId);\n\tif (!delegation) {\n\t\t// Don't fail here — downstream hash-compute / send path will\n\t\t// produce a more specific error (\"no work-log row found\" or\n\t\t// the server's DELEGATION_NOT_FOUND). We only own the role-\n\t\t// swap check; missing-delegation is a different concern.\n\t\treturn;\n\t}\n\tif (delegation.offererDid === sender.did) {\n\t\tthrow new Error(\n\t\t\t`receipt propose: ${sender.did} is the CALLER on delegation ${delegationId} (matches delegation.offererDid). Only the PAYEE — the counterparty who accepted the delegation offer — 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>\\`.`,\n\t\t);\n\t}\n}\n\n/**\n * Symmetric fail-fast for the other role mistake — payee trying to\n * issue `receipt cosign`. Mirror of `assertSenderIsReceiptPayee`.\n * Server rejects with `RECEIPT_COSIGNER_NOT_CALLER` post-commit\n * (PRE_MATERIALIZATION — sender_sequence consumed), but we can\n * catch it client-side for the same UX wins (no chain noise,\n * directive next step).\n *\n * Mechanism: same delegation lookup. If `delegation.offererDid\n * !== sender.did`, the sender is the PAYEE (not the caller) and\n * `receipt cosign` is the wrong move — they should have\n * `receipt propose`d first, the caller then cosigns.\n *\n * Requires `relationshipId` — the receipt cosign command already\n * has it as a positional, so this assertion always has scope.\n *\n * Exported for unit-test coverage.\n */\nexport async function assertSenderIsReceiptCaller(\n\tapi: ArpApiClient,\n\tsender: AgentLocalState,\n\trelationshipId: string,\n\tdelegationId: string,\n): Promise<void> {\n\tconst signer = makeSigner(sender);\n\tconst rows = await fetchAllPages<DelegationPublic>((after) =>\n\t\tapi.listDelegations(relationshipId, signer, { limit: 100, ...(after ? { after } : {}) }),\n\t);\n\tconst delegation = rows.find((d) => d.delegationId === delegationId);\n\tif (!delegation) {\n\t\t// Same scoping rationale as assertSenderIsReceiptPayee —\n\t\t// missing-delegation lookups own the canonical error\n\t\t// (resolveProposedReceiptHashes will throw with full context).\n\t\treturn;\n\t}\n\tif (delegation.offererDid !== sender.did) {\n\t\tthrow new Error(\n\t\t\t`receipt cosign: ${sender.did} is the PAYEE on delegation ${delegationId} (does NOT match delegation.offererDid). Only the CALLER — the agent who offered the delegation — can cosign; as the payee your role is to PROPOSE the receipt (the caller then cosigns it). If you haven't proposed yet, run \\`heyarp receipt propose <caller-did> ${delegationId} --auto-hashes --rel-id ${relationshipId} --request-id <id> --verdict accepted\\`. If you already proposed, wait for the caller's cosign via \\`heyarp status ${relationshipId} --wait --until receipt.cosigned\\`.`,\n\t\t);\n\t}\n}\n\n/**\n * Auto-resolve --rel-id for `receipt propose --auto-hashes` when\n * the operator omitted it. Strategy:\n * 1. List the sender's relationships (paginated — single-page\n * lookup would lose delegations on accounts with >100 active\n * relationships).\n * 2. For each relationship, list delegations and check whether\n * the target delegationId is present.\n * 3. If exactly one relationship hosts the delegation → return\n * its id. Else throw with a clear \"ambiguous / not found\"\n * message naming the candidates so the operator can pass\n * --rel-id explicitly.\n *\n * Exported for unit-test coverage.\n */\nexport async function resolveAutoRelId(api: ArpApiClient, sender: AgentLocalState, delegationId: string): Promise<string> {\n\tconst signer = makeSigner(sender);\n\t// RelationshipPublic exposes the id as `relationshipId` (NOT\n\t// `id`); keying off the wrong field would call listDelegations\n\t// with `undefined` and break the auto-resolve path entirely.\n\t//\n\t// `listRelationships` does NOT accept an `after` cursor\n\t// (ListRelationshipsQuery has only `state` + `limit`), so\n\t// `fetchAllPages` would re-fetch the first page indefinitely.\n\t// We single-page with limit 100 instead and explicitly document\n\t// the upper bound: if the operator has ≥100 active relationships,\n\t// they must pass --rel-id explicitly. The error path below\n\t// names that constraint so the fallback is discoverable.\n\tconst RELATIONSHIPS_PAGE_CAP = 100;\n\tconst rels = await api.listRelationships(sender.did, signer, { limit: RELATIONSHIPS_PAGE_CAP });\n\tconst matches: string[] = [];\n\tfor (const r of rels) {\n\t\tconst dels = await fetchAllPages<DelegationPublic>((after) => api.listDelegations(r.relationshipId, signer, { limit: 100, ...(after ? { after } : {}) }));\n\t\tif (dels.some((d) => d.delegationId === delegationId)) {\n\t\t\tmatches.push(r.relationshipId);\n\t\t}\n\t}\n\tif (matches.length === 0) {\n\t\tconst overflowHint = rels.length === RELATIONSHIPS_PAGE_CAP ? ` (Note: auto-resolve only scans the first ${RELATIONSHIPS_PAGE_CAP} of your relationships — if you have more, pass --rel-id explicitly.)` : '';\n\t\tthrow new Error(\n\t\t\t`receipt propose --auto-hashes: could not auto-resolve --rel-id — none of your ${rels.length} relationship(s) contains delegation ${delegationId}. Pass --rel-id explicitly, or check that <delegation-id> is correct.${overflowHint}`,\n\t\t);\n\t}\n\tif (matches.length > 1) {\n\t\tthrow new Error(\n\t\t\t`receipt propose --auto-hashes: delegation ${delegationId} appears in ${matches.length} relationships (${matches.join(', ')}). Pass --rel-id explicitly to disambiguate.`,\n\t\t);\n\t}\n\treturn matches[0];\n}\n\n/**\n * Auto-resolve --request-id from the work_log table when the\n * operator omitted it under --auto-hashes. Filter to\n * `state='responded'` rows (receipt propose requires a response\n * hash to compute, so only responded rows are candidates). If\n * exactly one matches under (rel-id, delegation-id) → return its\n * request_id; else throw with the candidate list (first 5) so the\n * operator can pin --request-id explicitly.\n *\n * Exported for unit-test coverage.\n */\nexport async function resolveAutoRequestId(api: ArpApiClient, sender: AgentLocalState, relationshipId: string, delegationId: string): Promise<string> {\n\tconst signer = makeSigner(sender);\n\tconst logs = await fetchAllPages<WorkLogPublic>((after) => api.listWorkLogs(relationshipId, signer, { delegationId, state: 'responded', limit: 100, ...(after ? { after } : {}) }));\n\tif (logs.length === 0) {\n\t\tthrow new Error(\n\t\t\t`receipt propose --auto-hashes: no 'responded' work_log under delegation ${delegationId} in relationship ${relationshipId} — the payee must send \\`work respond\\` before a receipt can be proposed. Pass --request-id explicitly if you have a known one.`,\n\t\t);\n\t}\n\tif (logs.length > 1) {\n\t\tconst ids = logs.slice(0, 5).map((l) => l.requestId).join(', ');\n\t\tconst suffix = logs.length > 5 ? ` (and ${logs.length - 5} more)` : '';\n\t\tthrow new Error(\n\t\t\t`receipt propose --auto-hashes: ${logs.length} 'responded' work_logs under delegation ${delegationId} (request_ids: ${ids}${suffix}). Pass --request-id explicitly to pin which one to receipt.`,\n\t\t);\n\t}\n\treturn logs[0].requestId;\n}\n\nexport async function computeWorkLogHashes(\n\tapi: ArpApiClient,\n\tsender: AgentLocalState,\n\trelationshipId: string,\n\tdelegationId: string,\n\trequestId: string,\n): Promise<{ requestHash: string; responseHash: string }> {\n\tconst signer = makeSigner(sender);\n\t// Paginate listWorkLogs: it returns oldest-first capped at 100\n\t// per page. A delegation that ran >100 work_request /\n\t// work_response cycles would lose newer rows on a single-page\n\t// fetch — same pattern + helper as `status.composeStatus`.\n\t// `fetchAllPages` walks `?after=` to exhaustion with the\n\t// existing cursor-loop + hard-cap guards.\n\tconst rows = await fetchAllPages<WorkLogPublic>((after) => api.listWorkLogs(relationshipId, signer, { delegationId, limit: 100, ...(after ? { after } : {}) }));\n\tconst workLog = rows.find((w) => w.requestId === requestId);\n\tif (!workLog) {\n\t\tthrow new Error(\n\t\t\t`receipt propose --auto-hashes: no work-log row found for (relationshipId=${relationshipId}, delegationId=${delegationId}, requestId=${requestId}). Did the work_request envelope land yet?`,\n\t\t);\n\t}\n\tif (workLog.state !== 'responded') {\n\t\tthrow new Error(\n\t\t\t`receipt propose --auto-hashes: work-log row ${requestId} is in state '${workLog.state}', not 'responded'. The payee must \\`work respond\\` before a receipt can be proposed.`,\n\t\t);\n\t}\n\tconst requestBody = {\n\t\ttype: 'work_request',\n\t\tcontent: { delegation_id: workLog.delegationId, request_id: workLog.requestId, params: workLog.requestParams },\n\t};\n\tconst responseBody =\n\t\tworkLog.responseOutput !== undefined\n\t\t\t? { type: 'work_response', content: { delegation_id: workLog.delegationId, request_id: workLog.requestId, output: workLog.responseOutput } }\n\t\t\t: { type: 'work_response', content: { delegation_id: workLog.delegationId, request_id: workLog.requestId, error: workLog.responseError } };\n\t// `canonicalSha256Hex` already returns the full `sha256:<hex>`\n\t// literal that the receipt body's `request_hash` /\n\t// `response_hash` fields expect (per `00-core/protocol.md`).\n\t// Don't prepend another `sha256:` — that produces the\n\t// `sha256:sha256:<hex>` shape SHA256_RE rejects.\n\treturn {\n\t\trequestHash: canonicalSha256Hex(requestBody),\n\t\tresponseHash: canonicalSha256Hex(responseBody),\n\t};\n}\n\n// ---------- cosign ----------\n\n// `--auto-hashes` was promised by the spec but originally\n// missing on `receipt cosign` (\"unknown option '--auto-hashes'\").\n// The proposed receipt row already carries `requestHash` +\n// `responseHash` — under `(relationshipId, delegationId)`\n// there's at most ONE row in PROPOSED state at any time, so we\n// can derive them. The flag implements that plus a consistency\n// check when positionals are also given.\ninterface CosignOptions extends BaseSendOptions {\n\tverdict?: string;\n\tnotesHash?: string;\n\tclearNotes?: boolean;\n\tautoHashes?: boolean;\n\t/**\n\t * A delegation with multiple work_requests can have multiple\n\t * PROPOSED receipts awaiting cosign (one per request_id). When\n\t * --auto-hashes is set, `--request-id` disambiguates which one\n\t * to cosign. Without it, the resolver errors loud asking the\n\t * operator to supply --request-id OR fall back to positional\n\t * hashes.\n\t */\n\trequestId?: string;\n\t/**\n\t * Escrow integration. If ALL settlement flags are supplied,\n\t * the cosign envelope gets an `attachments.settlement_signatures`\n\t * block — server consumes it via `ReceiptCosignValidatorService`\n\t * to enqueue the on-chain `release_lock` / `partial_release` op.\n\t *\n\t * The settlement digest itself is signed via\n\t * `heyarp wallet sign-settlement-release` (separately by each\n\t * party); cosign just attaches the resulting sigs. Sig values are\n\t * raw base64 (NO `ed25519:` prefix — that's envelope-sig only).\n\t *\n\t * Worker→buyer sig handoff is OUT OF SCOPE for this slice —\n\t * agents coordinate via shared file system, persistent\n\t * messaging, or any other out-of-band channel. A V1.5+ slice\n\t * could extend `receipt propose` to carry the payee's pending\n\t * sig in its own attachment.\n\t */\n\tsettlementPurpose?: string;\n\tsettlementExpiresAt?: string;\n\tpayerSettlementPubkey?: string;\n\tpayerSettlementSig?: string;\n\tpayeeSettlementPubkey?: string;\n\tpayeeSettlementSig?: string;\n\tsettlementPayeeAmount?: string;\n\t/**\n\t * Read the counterparty's `{settlement_pubkey, sig}` from the\n\t * JSON file produced by\n\t * `heyarp wallet sign-settlement-release --write-to <path>`.\n\t * The file is the canonical handoff channel between the two\n\t * cosign parties. Either side can use these flags. Mutually\n\t * exclusive with the matching `--payer-settlement-{pubkey,sig}`\n\t * / `--payee-settlement-{pubkey,sig}` explicit flags — pass\n\t * either the file OR the values, not both.\n\t */\n\tpayerSigFromFile?: string;\n\tpayeeSigFromFile?: string;\n\t/**\n\t * Commander quirk: `.option('--no-settlement', ...)` produces\n\t * `opts.settlement === false` when the flag is supplied (negated\n\t * option semantics), NOT `opts.settlement === false === true`. The option\n\t * name MUST match commander's auto-derived name — `settlement` —\n\t * so the runtime CLI invocation works. Default (no flag) is `true`.\n\t * Treat `opts.settlement === false` as the explicit opt-out signal\n\t * for test_mode servers.\n\t *\n\t * Without `--no-settlement`, settlement_signatures is REQUIRED —\n\t * production server's ReceiptHandler.handleCosign throws\n\t * `ESC_SETTLEMENT_SIGS_MISSING` (a POST_COMMIT error, so the\n\t * sender_sequence is consumed). Reading `opts.settlement` (not\n\t * `opts.no_settlement`) is essential here: commander rewrites\n\t * `--no-X` into `opts.X === false`.\n\t */\n\tsettlement?: boolean;\n}\n\nfunction registerCosign(parent: Command): void {\n\tparent\n\t\t.command('cosign')\n\t\t.description('Cosign an existing PROPOSED receipt — promotes to COSIGNED. Caller-only.')\n\t\t.argument('<relationship-id>', 'Relationship UUID')\n\t\t.argument('<delegation-id>', 'Parent delegation id (UUID)')\n\t\t// Positional hashes are OPTIONAL. With `--auto-hashes`, the\n\t\t// cosign reads them from the PROPOSED receipt row. Without\n\t\t// `--auto-hashes`, they're still required.\n\t\t.argument('[request-hash]', 'sha256:<64 hex> — must match the existing receipt row. Omit when --auto-hashes is set (derived from the PROPOSED row).')\n\t\t.argument('[response-hash]', 'sha256:<64 hex> — must match the existing receipt row. Omit when --auto-hashes is set.')\n\t\t.option('--server <url>', 'Override ARP server base URL')\n\t\t.option('--from-did <did>', 'Sender DID — required only if multiple agents are registered against this server')\n\t\t.option('--verdict <s>', \"Final verdict; defaults to the row's verdict_proposed (accepted | accepted_with_notes | rejected)\")\n\t\t.option('--notes-hash <sha256>', \"Override the notes hash bound into the cosign payload (overwrites the row's notesHash). Default: preserve whatever the payee proposed.\")\n\t\t.option('--clear-notes', \"Explicitly clear the notes binding — the cosign payload's notes_hash will be null, $unset on the row.\", false)\n\t\t.option(\n\t\t\t'--auto-hashes',\n\t\t\t'Read request_hash + response_hash from the PROPOSED receipt row at (relationship-id, delegation-id). Positional <request-hash>/<response-hash> become optional; if supplied they must match (consistency check). When a delegation has multiple PROPOSED receipts (one per request_id), also pass --request-id to disambiguate.',\n\t\t\tfalse,\n\t\t)\n\t\t.option(\n\t\t\t'--request-id <id>',\n\t\t\t// Disambiguator when a delegation has multiple PROPOSED\n\t\t\t// receipts (one per request_id). The resolver filters to\n\t\t\t// receipts whose work_log row matches this request_id.\n\t\t\t// Ignored when --auto-hashes is not set OR when there's\n\t\t\t// exactly one proposed row.\n\t\t\t'Disambiguator for --auto-hashes when the delegation has multiple PROPOSED receipts (one per request_id). Pin the exact work_request whose receipt you want to cosign.',\n\t\t)\n\t\t.option('--ttl <seconds>', 'Envelope TTL in seconds', '3600')\n\t\t.option('--verbose', 'Print the full envelope before sending and the full server response', false)\n\t\t// Escrow flags. Pass all of these together to attach\n\t\t// `settlement_signatures` to the cosign envelope; server then\n\t\t// enqueues the on-chain release_lock / partial_release op.\n\t\t// Each sig is signed separately via\n\t\t// `heyarp wallet sign-settlement-release`; cosign just\n\t\t// attaches them. Sig format: raw base64 (NO `ed25519:` prefix).\n\t\t.option(\n\t\t\t'--settlement-purpose <s>',\n\t\t\t'Settlement digest purpose: `ARP-SOLANA-RELEASE-v1.5` (full) or `ARP-SOLANA-PARTIAL-RELEASE-v1.5` (partial; requires --settlement-payee-amount).',\n\t\t)\n\t\t.option('--settlement-expires-at <unix>', 'Settlement expires_at (unix seconds) — must match the value signed by BOTH parties when they ran `heyarp wallet sign-settlement-release`.')\n\t\t.option('--payer-settlement-pubkey <b58>', 'Payer settlement pubkey (base58) — must equal `lock.payer`. Mutually exclusive with --payer-sig-from-file.')\n\t\t.option('--payer-settlement-sig <base64>', 'Payer Ed25519 settlement signature (raw base64, NO `ed25519:` prefix). Mutually exclusive with --payer-sig-from-file.')\n\t\t.option('--payee-settlement-pubkey <b58>', 'Payee settlement pubkey (base58) — must equal `lock.payee`. Mutually exclusive with --payee-sig-from-file.')\n\t\t.option('--payee-settlement-sig <base64>', 'Payee Ed25519 settlement signature (raw base64, NO `ed25519:` prefix). Mutually exclusive with --payee-sig-from-file.')\n\t\t// In-band file handoff. Each party signs the digest with\n\t\t// `heyarp wallet sign-settlement-release --write-to <path>`\n\t\t// and hands the path to the cosign caller (typically the\n\t\t// buyer-payer). The caller passes both files to cosign — no\n\t\t// manual JSON copy-paste, no \"what was the pubkey again\"\n\t\t// round-trips.\n\t\t.option(\n\t\t\t'--payer-sig-from-file <path>',\n\t\t\t'Read `{settlement_pubkey, sig}` for the PAYER side from the JSON file produced by `heyarp wallet sign-settlement-release --write-to <path>`. Populates --payer-settlement-pubkey + --payer-settlement-sig.',\n\t\t)\n\t\t.option(\n\t\t\t'--payee-sig-from-file <path>',\n\t\t\t'Read `{settlement_pubkey, sig}` for the PAYEE side from the JSON file produced by `heyarp wallet sign-settlement-release --write-to <path>`. Populates --payee-settlement-pubkey + --payee-settlement-sig.',\n\t\t)\n\t\t.option('--settlement-payee-amount <int>', 'Required ONLY when --settlement-purpose=ARP-SOLANA-PARTIAL-RELEASE-v1.5. Payee receives this many base units; payer is refunded `lock.amount - payee_amount`.')\n\t\t// Commander stores `--no-settlement` as `opts.settlement === false`\n\t\t// (negated-option semantics). Do NOT pass an explicit default\n\t\t// here — commander defaults `settlement` to `true` when the\n\t\t// flag is absent.\n\t\t.option('--no-settlement', 'Opt out of settlement_signatures attachment. Default behavior REQUIRES the full settlement flag set; without --no-settlement, omitting flags errors loud BEFORE the envelope is sent. Use --no-settlement only against a server running in test_mode.')\n\t\t.action(async (relationshipId: string, delegationId: string, requestHashArg: string | undefined, responseHashArg: string | undefined, opts: CosignOptions, cmd: Command) => {\n\t\t\t// Same defence-in-depth as `receipt propose`. Cosign sees\n\t\t\t// the same cross-validation + settlement-attachment\n\t\t\t// throws; they should all exit non-zero regardless of\n\t\t\t// pipe/redirect shape AND preserve structured `[CODE]`\n\t\t\t// ApiError formatting + `--trace` behaviour via\n\t\t\t// `formatActionError`.\n\t\t\ttry {\n\t\t\t\tawait runCosign(relationshipId, delegationId, requestHashArg, responseHashArg, opts);\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(formatActionError(err, cmd));\n\t\t\t\tprocess.exitCode = 1;\n\t\t\t}\n\t\t});\n}\n\n/**\n * Load a `{settlement_pubkey, sig, digest_hex, purpose}` quad from\n * the JSON file produced by\n * `heyarp wallet sign-settlement-release --write-to <path>`.\n *\n * Validates that all four fields are non-empty strings (the wallet\n * always emits them; rejecting partial files catches truncation /\n * hand-edited files). `digest_hex` and `purpose` flow through for\n * cross-file consistency checks in\n * `assembleSettlementSignaturesAttachment` — mismatched-digest\n * errors are surfaced CLI-side before the envelope is sent and\n * sender_sequence is consumed.\n *\n * `flagPrefix` is `'--payer-sig-from-file'` or\n * `'--payee-sig-from-file'` so error messages name the\n * originating flag.\n *\n * Exported for unit-test coverage.\n */\nexport function loadSettlementSigFromFile(\n\tpath: string,\n\tflagPrefix: string,\n): { settlement_pubkey: string; sig: string; digest_hex: string; purpose: string } {\n\tlet raw: string;\n\ttry {\n\t\traw = readFileSync(path, 'utf8');\n\t} catch (err) {\n\t\tthrow new Error(`receipt cosign: failed to read ${flagPrefix} '${path}': ${(err as Error).message}`);\n\t}\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(raw);\n\t} catch (err) {\n\t\tthrow new Error(`receipt cosign: ${flagPrefix} '${path}' is not valid JSON: ${(err as Error).message}`);\n\t}\n\tif (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n\t\tthrow new Error(`receipt cosign: ${flagPrefix} '${path}' must be a JSON object, got ${Array.isArray(parsed) ? 'array' : typeof parsed}.`);\n\t}\n\tconst p = parsed as Record<string, unknown>;\n\tconst pubkey = p.settlement_pubkey;\n\tconst sig = p.sig;\n\tconst digestHex = p.digest_hex;\n\tconst purpose = p.purpose;\n\tif (typeof pubkey !== 'string' || pubkey.length === 0) {\n\t\tthrow new Error(`receipt cosign: ${flagPrefix} '${path}' missing required field 'settlement_pubkey' (string). Expected JSON output of \\`heyarp wallet sign-settlement-release\\`.`);\n\t}\n\tif (typeof sig !== 'string' || sig.length === 0) {\n\t\tthrow new Error(`receipt cosign: ${flagPrefix} '${path}' missing required field 'sig' (string). Expected JSON output of \\`heyarp wallet sign-settlement-release\\`.`);\n\t}\n\tif (typeof digestHex !== 'string' || digestHex.length === 0) {\n\t\tthrow new Error(`receipt cosign: ${flagPrefix} '${path}' missing required field 'digest_hex' (string). Expected JSON output of \\`heyarp wallet sign-settlement-release\\`.`);\n\t}\n\tif (typeof purpose !== 'string' || purpose.length === 0) {\n\t\tthrow new Error(`receipt cosign: ${flagPrefix} '${path}' missing required field 'purpose' (string). Expected JSON output of \\`heyarp wallet sign-settlement-release\\`.`);\n\t}\n\treturn { settlement_pubkey: pubkey, sig, digest_hex: digestHex, purpose };\n}\n\n/**\n * Assemble `settlement_signatures` attachment from CosignOptions.\n *\n * Returns the wire-shaped block IFF all required settlement flags are\n * present. Returns `undefined` if NO settlement flags are supplied\n * (= test-mode cosign, no on-chain release expected).\n *\n * Throws on partial flag set — either ALL settlement flags or NONE.\n * This is a CLI-side fail-fast: the server would otherwise reject with\n * `ESC_SETTLEMENT_SIGS_MISSING` or `VAL_BODY_INVALID` AFTER the receipt\n * row already transitioned to COSIGNED (post-commit error per\n * `POST_COMMIT_ERROR_CODES`), consuming the sender_sequence.\n *\n * `--payer-sig-from-file` / `--payee-sig-from-file` are hydrated\n * to the corresponding `--*-settlement-{pubkey,sig}` flags before\n * validation. Supplying both the file AND the explicit flags for\n * the same side errors (ambiguous source of truth).\n *\n * Exported for unit-test coverage.\n */\nexport function assembleSettlementSignaturesAttachment(opts: CosignOptions): Record<string, unknown> | undefined {\n\t// Hydrate payer/payee from file, fail-fast on conflict.\n\tlet payerPubkey = opts.payerSettlementPubkey;\n\tlet payerSig = opts.payerSettlementSig;\n\tlet payerFile: { digest_hex: string; purpose: string } | undefined;\n\tif (opts.payerSigFromFile !== undefined && opts.payerSigFromFile !== '') {\n\t\tif ((payerPubkey !== undefined && payerPubkey !== '') || (payerSig !== undefined && payerSig !== '')) {\n\t\t\tthrow new Error(\n\t\t\t\t`receipt cosign: --payer-sig-from-file is mutually exclusive with --payer-settlement-pubkey / --payer-settlement-sig. Pass either the file OR the explicit values, not both.`,\n\t\t\t);\n\t\t}\n\t\tconst loaded = loadSettlementSigFromFile(opts.payerSigFromFile, '--payer-sig-from-file');\n\t\tpayerPubkey = loaded.settlement_pubkey;\n\t\tpayerSig = loaded.sig;\n\t\tpayerFile = { digest_hex: loaded.digest_hex, purpose: loaded.purpose };\n\t}\n\tlet payeePubkey = opts.payeeSettlementPubkey;\n\tlet payeeSig = opts.payeeSettlementSig;\n\tlet payeeFile: { digest_hex: string; purpose: string } | undefined;\n\tif (opts.payeeSigFromFile !== undefined && opts.payeeSigFromFile !== '') {\n\t\tif ((payeePubkey !== undefined && payeePubkey !== '') || (payeeSig !== undefined && payeeSig !== '')) {\n\t\t\tthrow new Error(\n\t\t\t\t`receipt cosign: --payee-sig-from-file is mutually exclusive with --payee-settlement-pubkey / --payee-settlement-sig. Pass either the file OR the explicit values, not both.`,\n\t\t\t);\n\t\t}\n\t\tconst loaded = loadSettlementSigFromFile(opts.payeeSigFromFile, '--payee-sig-from-file');\n\t\tpayeePubkey = loaded.settlement_pubkey;\n\t\tpayeeSig = loaded.sig;\n\t\tpayeeFile = { digest_hex: loaded.digest_hex, purpose: loaded.purpose };\n\t}\n\n\t// Cross-file consistency. Both parties signed the SAME release\n\t// digest with the SAME purpose; if their files disagree\n\t// (different expires_at → different digest, or one signed full\n\t// and the other partial), the cosign would reach the server\n\t// with mismatched sigs and fail post-commit, consuming the\n\t// sender_sequence. Catch CLI-side before the envelope is sent.\n\tif (payerFile && payeeFile) {\n\t\tif (payerFile.digest_hex !== payeeFile.digest_hex) {\n\t\t\tthrow new Error(\n\t\t\t\t`receipt cosign: --payer-sig-from-file and --payee-sig-from-file disagree on the signed digest (payer digest_hex='${payerFile.digest_hex}', payee digest_hex='${payeeFile.digest_hex}'). The two parties must sign the SAME release digest — different expires_at, condition_hash, receipt_event_hash, deliverable_hash, lock_amount, or partial-vs-full payee_amount produce different digests. Re-run \\`heyarp wallet sign-settlement-release\\` on both sides with identical settlement parameters.`,\n\t\t\t);\n\t\t}\n\t\tif (payerFile.purpose !== payeeFile.purpose) {\n\t\t\tthrow new Error(\n\t\t\t\t`receipt cosign: --payer-sig-from-file and --payee-sig-from-file disagree on purpose (payer='${payerFile.purpose}', payee='${payeeFile.purpose}'). Both sides must sign either ARP-SOLANA-RELEASE-v1.5 (full) or ARP-SOLANA-PARTIAL-RELEASE-v1.5 (partial).`,\n\t\t\t);\n\t\t}\n\t}\n\t// If the operator also set --settlement-purpose explicitly, it must\n\t// match what the file(s) signed for — otherwise the attachment goes\n\t// to the server with the explicit purpose, but the sigs were\n\t// computed over a digest built for a different purpose, and the\n\t// Ed25519Program verification fails on-chain.\n\tconst filePurpose = payerFile?.purpose ?? payeeFile?.purpose;\n\tif (filePurpose !== undefined && opts.settlementPurpose !== undefined && opts.settlementPurpose !== filePurpose) {\n\t\tthrow new Error(\n\t\t\t`receipt cosign: --settlement-purpose='${opts.settlementPurpose}' disagrees with the purpose signed in the sig file ('${filePurpose}'). Either drop --settlement-purpose (the file's value will be used) or re-sign with the desired purpose.`,\n\t\t);\n\t}\n\n\tconst settlementFlags = [\n\t\topts.settlementPurpose,\n\t\topts.settlementExpiresAt,\n\t\tpayerPubkey,\n\t\tpayerSig,\n\t\tpayeePubkey,\n\t\tpayeeSig,\n\t];\n\tconst someSet = settlementFlags.some((f) => f !== undefined && f !== '');\n\tconst allSet = settlementFlags.every((f) => f !== undefined && f !== '');\n\n\t// Fail-fast. Production server (default mode) requires\n\t// settlement_signatures and throws ESC_SETTLEMENT_SIGS_MISSING\n\t// after the receipt row has transitioned to COSIGNED —\n\t// sender_sequence is consumed. We refuse to send the envelope\n\t// unless EITHER the full flag set is supplied OR the operator\n\t// explicitly opts out via --no-settlement (= server is in\n\t// test_mode).\n\tif (!someSet) {\n\t\tif (opts.settlement === false) return undefined;\n\t\tthrow new Error(\n\t\t\t'receipt cosign: settlement_signatures is required. Supply --settlement-purpose, --settlement-expires-at, --payer-settlement-{pubkey,sig}, --payee-settlement-{pubkey,sig} (and --settlement-payee-amount for partial). Or pass --no-settlement if the server is in test_mode.',\n\t\t);\n\t}\n\tif (!allSet) {\n\t\tthrow new Error(\n\t\t\t'receipt cosign: settlement flags must be supplied together. Required: --settlement-purpose, --settlement-expires-at, --payer-settlement-pubkey, --payer-settlement-sig, --payee-settlement-pubkey, --payee-settlement-sig (and --settlement-payee-amount for partial-release).',\n\t\t);\n\t}\n\tif (opts.settlement === false) {\n\t\tthrow new Error('receipt cosign: --no-settlement is mutually exclusive with explicit settlement flags. Pick one path.');\n\t}\n\n\t// Purpose validation.\n\tconst purpose = opts.settlementPurpose;\n\tif (purpose !== 'ARP-SOLANA-RELEASE-v1.5' && purpose !== 'ARP-SOLANA-PARTIAL-RELEASE-v1.5') {\n\t\tthrow new Error(\n\t\t\t`receipt cosign: --settlement-purpose must be 'ARP-SOLANA-RELEASE-v1.5' or 'ARP-SOLANA-PARTIAL-RELEASE-v1.5', got '${purpose}'.`,\n\t\t);\n\t}\n\tconst isPartial = purpose === 'ARP-SOLANA-PARTIAL-RELEASE-v1.5';\n\n\t// payee_amount required for partial, forbidden for full.\n\tif (isPartial && (opts.settlementPayeeAmount === undefined || opts.settlementPayeeAmount === '')) {\n\t\tthrow new Error('receipt cosign: --settlement-payee-amount is required when --settlement-purpose=ARP-SOLANA-PARTIAL-RELEASE-v1.5.');\n\t}\n\tif (!isPartial && opts.settlementPayeeAmount !== undefined && opts.settlementPayeeAmount !== '') {\n\t\tthrow new Error('receipt cosign: --settlement-payee-amount applies only to ARP-SOLANA-PARTIAL-RELEASE-v1.5; remove it for full release.');\n\t}\n\n\t// expires_at must be a positive integer (unix seconds).\n\tconst expiresAtNum = Number.parseInt(opts.settlementExpiresAt ?? '', 10);\n\tif (!Number.isFinite(expiresAtNum) || expiresAtNum <= 0 || String(expiresAtNum) !== opts.settlementExpiresAt) {\n\t\tthrow new Error(`receipt cosign: --settlement-expires-at must be a positive integer (unix seconds), got '${opts.settlementExpiresAt}'.`);\n\t}\n\n\t// payee_amount (partial only) must be a positive integer string\n\t// (server-side parser is strict regex `/^[0-9]+$/`).\n\tif (isPartial && !/^[0-9]+$/.test(opts.settlementPayeeAmount ?? '')) {\n\t\tthrow new Error(`receipt cosign: --settlement-payee-amount must be a non-negative integer string (base units), got '${opts.settlementPayeeAmount}'.`);\n\t}\n\n\tconst attachment: Record<string, unknown> = {\n\t\tpurpose,\n\t\texpires_at: expiresAtNum,\n\t\tpayer: {\n\t\t\tsettlement_pubkey: payerPubkey,\n\t\t\tsig: payerSig,\n\t\t},\n\t\tpayee: {\n\t\t\tsettlement_pubkey: payeePubkey,\n\t\t\tsig: payeeSig,\n\t\t},\n\t};\n\tif (isPartial) attachment.payee_amount = opts.settlementPayeeAmount;\n\treturn attachment;\n}\n\nasync function runCosign(\n\trelationshipId: string,\n\tdelegationId: string,\n\trequestHashArg: string | undefined,\n\tresponseHashArg: string | undefined,\n\topts: CosignOptions,\n): Promise<void> {\n\t// Normalise BOTH positional UUIDs before any server lookup.\n\t// resolveProposedReceiptHashes, computeWorkLogHashes, and\n\t// resolveCosignTargets all do exact server-side matches on\n\t// these values; mixed-case input from a copy-pasted banner would\n\t// silently miss the row before cosign attempts.\n\trelationshipId = requireUuidNormalised('receipt cosign', relationshipId, '<relationship-id>');\n\tdelegationId = requireUuidNormalised('receipt cosign', delegationId, '<delegation-id>');\n\tif (opts.notesHash) requireSha256('receipt cosign', opts.notesHash, '--notes-hash');\n\tif (opts.notesHash && opts.clearNotes) {\n\t\tthrow new Error('receipt cosign: --notes-hash and --clear-notes are mutually exclusive');\n\t}\n\tconst ttlSeconds = parseTtl('receipt cosign', opts.ttl);\n\n\t// Derive request_hash + response_hash via `--auto-hashes` OR\n\t// require explicit positionals. The auto path looks up the\n\t// PROPOSED receipt row (at most one per delegation by FSM\n\t// invariant) and uses its hashes. If positionals were also\n\t// supplied, verify they agree (a typo-catching consistency\n\t// check, same shape as `receipt propose --auto-hashes`).\n\tlet requestHash: string;\n\tlet responseHash: string;\n\tconst api = new ArpApiClient(opts.server);\n\tconst sender = resolveSenderAgent('receipt cosign', opts.server, opts.fromDid);\n\tconst signer = makeSigner(sender);\n\n\t// Symmetric fail-fast — mirror of the propose role-check. The\n\t// cosign side rejects payee senders before envelope ships, with\n\t// a directive pointing them at the propose path. Same shape as\n\t// `assertSenderIsReceiptPayee` in `runPropose`.\n\tawait assertSenderIsReceiptCaller(api, sender, relationshipId, delegationId);\n\n\tif (opts.autoHashes) {\n\t\t// Two derivation paths.\n\t\t//\n\t\t// 1. With --request-id: pin the exact work_log row and\n\t\t// compute canonical hashes via the SDK's\n\t\t// `computeWorkLogHashes` (same as `receipt propose\n\t\t// --auto-hashes`). Works for ANY delegation, including\n\t\t// ones with multiple PROPOSED receipts.\n\t\t//\n\t\t// 2. Without --request-id: shortcut for single-pending-\n\t\t// receipt delegations — paginate receipts filtered to\n\t\t// `state=proposed`, assert exactly one row, return its\n\t\t// hashes. If multiple PROPOSED rows exist the resolver\n\t\t// errors loud asking for --request-id.\n\t\tlet derived: { requestHash: string; responseHash: string };\n\t\tif (opts.requestId) {\n\t\t\t// computeWorkLogHashes takes the full sender (state file\n\t\t\t// row) — not the Signer abstraction — because it signs\n\t\t\t// the work-log query itself.\n\t\t\tderived = await computeWorkLogHashes(api, sender, relationshipId, delegationId, opts.requestId);\n\t\t} else {\n\t\t\tderived = await resolveProposedReceiptHashes('receipt cosign', api, signer, {\n\t\t\t\trelationshipId,\n\t\t\t\tdelegationId,\n\t\t\t});\n\t\t}\n\t\trequestHash = derived.requestHash;\n\t\tresponseHash = derived.responseHash;\n\t\tif (requestHashArg) {\n\t\t\trequireSha256('receipt cosign', requestHashArg, '<request-hash>');\n\t\t\tif (requestHashArg !== requestHash) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`receipt cosign: --auto-hashes derived request_hash ${requestHash}, but positional <request-hash> ${requestHashArg} disagrees — drop one or fix the inputs`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tif (responseHashArg) {\n\t\t\trequireSha256('receipt cosign', responseHashArg, '<response-hash>');\n\t\t\tif (responseHashArg !== responseHash) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`receipt cosign: --auto-hashes derived response_hash ${responseHash}, but positional <response-hash> ${responseHashArg} disagrees — drop one or fix the inputs`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t} else {\n\t\tif (!requestHashArg || !responseHashArg) {\n\t\t\tthrow new Error('receipt cosign: <request-hash> and <response-hash> are required (or pass --auto-hashes to derive them from the PROPOSED receipt row)');\n\t\t}\n\t\trequireSha256('receipt cosign', requestHashArg, '<request-hash>');\n\t\trequireSha256('receipt cosign', responseHashArg, '<response-hash>');\n\t\trequestHash = requestHashArg;\n\t\tresponseHash = responseHashArg;\n\t}\n\n\t// Auto-resolve `recipient_did` (= payee), the row's\n\t// `receiptEventHash`, the original verdict, and the\n\t// proposed `notesHash`. The caller must be the offerer of the\n\t// parent delegation; if the resolver finds the row but\n\t// `callerDid !== sender.did` we throw client-side instead of\n\t// letting the server's `RECEIPT_COSIGNER_NOT_CALLER` consume\n\t// the sender_sequence.\n\tconst resolved = await resolveCosignTargets('receipt cosign', api, signer, { relationshipId, delegationId, requestHash, responseHash, selfDid: sender.did });\n\n\t// Default verdict to the row's verdict_proposed when omitted —\n\t// the caller can pass --verdict to overrule.\n\tconst verdict = parseVerdict('receipt cosign', opts.verdict ?? resolved.verdictProposed);\n\n\t// Notes-hash preservation policy:\n\t// --clear-notes → null (server $unsets the row's notesHash)\n\t// --notes-hash <hash> → use the supplied hash\n\t// neither → preserve the payee's proposed notesHash\n\t// (or null if the payee didn't propose any)\n\t// Without this, omitting `--notes-hash` would default to null\n\t// and silently erase the payee's audit binding even on a \"just\n\t// confirm what was proposed\" cosign.\n\tlet cosignNotesHash: ReceiptCosignPayload['notes_hash'];\n\tif (opts.clearNotes) {\n\t\tcosignNotesHash = null;\n\t} else if (opts.notesHash) {\n\t\tcosignNotesHash = opts.notesHash as ReceiptCosignPayload['notes_hash'];\n\t} else {\n\t\tcosignNotesHash = (resolved.notesHash as ReceiptCosignPayload['notes_hash']) ?? null;\n\t}\n\n\t// Build + sign the cosign payload, attach to the envelope, post.\n\tconst cosignPayload: ReceiptCosignPayload = {\n\t\tpurpose: 'ARP-RECEIPT-v1',\n\t\tdelegation_id: delegationId,\n\t\treceipt_event_hash: resolved.receiptEventHash as ReceiptCosignPayload['receipt_event_hash'],\n\t\tverdict,\n\t\tnotes_hash: cosignNotesHash,\n\t};\n\tconst cosignature = signCosignature({ payload: cosignPayload, signerDid: sender.did as Did, identitySecretKey: signer.identitySecretKey });\n\n\tconst content: ReceiptContent = {\n\t\tdelegation_id: delegationId,\n\t\trequest_hash: requestHash as ReceiptContent['request_hash'],\n\t\tresponse_hash: responseHash as ReceiptContent['response_hash'],\n\t\tverdict_proposed: verdict,\n\t};\n\t// Match the cosign payload's notes_hash on the body content\n\t// so the row's verdict-final + notesHash CAS update sees the\n\t// same value the cosign payload binds to.\n\tif (cosignNotesHash !== null) {\n\t\tcontent.notes_hash = cosignNotesHash;\n\t}\n\tconst body: ReceiptBody = { type: 'receipt', content };\n\n\tconsole.log(chalk.dim(`Server: ${api.serverUrl}`));\n\tconsole.log(chalk.dim(`Sender (caller): ${sender.did}`));\n\tconsole.log(chalk.dim(`Recipient (payee): ${resolved.payeeDid}`));\n\tconsole.log(chalk.dim(`Delegation: ${delegationId}`));\n\tconsole.log(chalk.dim(`Verdict (final): ${verdict}`));\n\tconsole.log(chalk.dim(`Receipt event hash bound: ${resolved.receiptEventHash}`));\n\tif (cosignNotesHash !== null) {\n\t\tconsole.log(chalk.dim(`Notes hash bound: ${cosignNotesHash}`));\n\t} else if (opts.clearNotes) {\n\t\tconsole.log(chalk.dim('Notes binding: cleared (--clear-notes)'));\n\t}\n\n\t// Attach settlement_signatures if escrow flags supplied.\n\t// Throws on partial flag set — fail-fast before sequence is\n\t// consumed.\n\tconst settlementSigs = assembleSettlementSignaturesAttachment(opts);\n\tconst attachments: Record<string, unknown> = { co_signature: cosignature };\n\tif (settlementSigs) {\n\t\tattachments.settlement_signatures = settlementSigs;\n\t\tconsole.log(chalk.dim(`Settlement signatures attached: purpose=${(settlementSigs as { purpose: string }).purpose}`));\n\t}\n\n\tconst result = await sendReceiptEnvelope({\n\t\tapi,\n\t\tsender,\n\t\trecipientDid: resolved.payeeDid,\n\t\tbody,\n\t\tattachments,\n\t\tttlSeconds,\n\t\tverbose: opts.verbose,\n\t\tserver: opts.server,\n\t});\n\tprintIngestResult(result);\n}\n\n// ---------- shared helpers ----------\n\ninterface BaseSendOptions {\n\tserver?: string;\n\tfromDid?: string;\n\tttl?: string;\n\tverbose?: boolean;\n}\n\ninterface SendArgs {\n\tapi: ArpApiClient;\n\tsender: AgentLocalState;\n\trecipientDid: string;\n\tbody: ReceiptBody;\n\tattachments?: Record<string, unknown>;\n\tttlSeconds: number;\n\tverbose: boolean | undefined;\n\tserver: string | undefined;\n}\n\n/**\n * Build → sign → ingest a receipt envelope. Same sequence-bump\n * policy as the contract / delegation / work wrappers.\n */\nasync function sendReceiptEnvelope(args: SendArgs): Promise<IngestResult> {\n\tconst nextSequence = (args.sender.lastSenderSequence ?? 0) + 1;\n\tconst protectedBlock: SignableProtected = {\n\t\tprotocol_version: 'arp/0.1',\n\t\tpurpose: Purpose.ENVELOPE,\n\t\tmessage_id: uuidV4(),\n\t\tsender_did: args.sender.did as Did,\n\t\trecipient_did: args.recipientDid as Did,\n\t\trelationship_id: null,\n\t\tsender_sequence: nextSequence,\n\t\tsender_nonce: senderNonce(),\n\t\ttimestamp: rfc3339(),\n\t\texpires_at: expiresAt(args.ttlSeconds),\n\t\tdelivery_id: null,\n\t};\n\n\tconst signer = makeSigner(args.sender);\n\tconst envelope = signEnvelope({\n\t\tprotected: protectedBlock,\n\t\tbody: args.body,\n\t\tidentitySecretKey: signer.identitySecretKey,\n\t\tattachments: args.attachments,\n\t});\n\n\tif (args.verbose) {\n\t\tconsole.log(chalk.bold('\\nEnvelope (pre-send):'));\n\t\tconsole.log(formatJson(envelope));\n\t}\n\n\ttry {\n\t\tconst result = await args.api.ingest(envelope);\n\t\tupdateAgentLocal(args.server, args.sender.did, { lastSenderSequence: nextSequence });\n\t\treturn result;\n\t} catch (err) {\n\t\tif (err instanceof ApiError && POST_COMMIT_ERROR_CODES.has(err.payload.code)) {\n\t\t\tupdateAgentLocal(args.server, args.sender.did, { lastSenderSequence: nextSequence });\n\t\t}\n\t\tthrow err;\n\t}\n}\n\n/**\n * For `cosign`: page through `/receipts` filtered by delegationId\n * to find the existing PROPOSED row. Returns the bits the cosign\n * envelope needs (`payeeDid` for routing, `receiptEventHash` for\n * the cosign payload binding, `verdictProposed` as a default,\n * `notesHash` for the preserve-by-default notes-hash policy).\n *\n * Pre-flight guards mirror the work `respond` resolver: reject\n * client-side when the row is already COSIGNED or the local agent\n * isn't the caller, so the operator gets a clear hint and we\n * don't burn `sender_sequence` on a guaranteed-rejected envelope.\n *\n * Exported for unit tests.\n */\n/**\n * find the SINGLE PROPOSED receipt row for a given\n * `(relationshipId, delegationId)` pair and return its\n * `requestHash` + `responseHash`. Used by `receipt cosign\n * --auto-hashes` to derive the positional hashes from server\n * state instead of asking the operator to copy-paste them.\n *\n * Invariants:\n * - At most ONE PROPOSED receipt per delegation by FSM design\n * (the propose action CAS-creates the row; cosign promotes\n * it to COSIGNED; both transitions are guarded by state).\n * - Multiple non-PROPOSED rows for the same delegation are\n * possible only if a future flow allows superseded receipts\n * — not in V1 — so the error path \"more than one proposed\"\n * fires for genuine bugs.\n *\n * Errors:\n * - No proposed row → clear \"did the payee `receipt propose` yet?\"\n * - Multiple proposed rows → unexpected; ask the operator to\n * pass the positional hashes manually to disambiguate.\n *\n * Exported for unit tests.\n */\nexport async function resolveProposedReceiptHashes(\n\tcmdName: string,\n\tapi: Pick<ArpApiClient, 'listReceipts'>,\n\tsigner: Signer,\n\targs: { relationshipId: string; delegationId: string },\n): Promise<{ requestHash: string; responseHash: string }> {\n\t// Use the shared `fetchAllPages` helper from status.ts — same\n\t// cursor-stagnation + max-page guard as the rest of the CLI's\n\t// pagination call sites. A hand-rolled `while (true)` loop\n\t// without that guard would spin forever on a buggy server or\n\t// proxy that returns a full page with the same last `id`.\n\tconst rows = await fetchAllPages<ReceiptPublic>((after) =>\n\t\tapi.listReceipts(args.relationshipId, signer, { delegationId: args.delegationId, state: 'proposed', limit: 100, ...(after ? { after } : {}) }),\n\t);\n\tconst proposed: { requestHash: string; responseHash: string }[] = [];\n\tfor (const row of rows) {\n\t\t// Defensive — the server-side `state` filter should\n\t\t// already exclude non-proposed rows, but if the filter\n\t\t// is dropped in a future schema change we still want\n\t\t// the right semantic here.\n\t\tif (row.state === 'proposed') {\n\t\t\tproposed.push({ requestHash: row.requestHash, responseHash: row.responseHash });\n\t\t}\n\t}\n\tif (proposed.length === 0) {\n\t\tthrow new Error(`${cmdName} --auto-hashes: no PROPOSED receipt found for delegation ${args.delegationId}. Did the payee \\`heyarp receipt propose\\` yet?`);\n\t}\n\tif (proposed.length > 1) {\n\t\t// Surface `--request-id` as the operator's disambiguation\n\t\t// path — a delegation with multiple work_requests\n\t\t// legitimately has multiple PROPOSED receipts (one per\n\t\t// request_id), and refusing to cosign without giving the\n\t\t// operator a way out would defeat the whole `--auto-hashes`\n\t\t// shortcut.\n\t\tthrow new Error(\n\t\t\t`${cmdName} --auto-hashes: found ${proposed.length} PROPOSED receipt rows for delegation ${args.delegationId}. Pass --request-id <id> to disambiguate (pins the work_request whose receipt you want to cosign) OR pass explicit <request-hash> + <response-hash> positionally.`,\n\t\t);\n\t}\n\treturn proposed[0];\n}\n\nexport async function resolveCosignTargets(\n\tcmdName: string,\n\tapi: Pick<ArpApiClient, 'listReceipts'>,\n\tsigner: Signer,\n\targs: { relationshipId: string; delegationId: string; requestHash: string; responseHash: string; selfDid: string },\n): Promise<{ payeeDid: string; receiptEventHash: string; verdictProposed: string; notesHash: string | undefined }> {\n\t// Route through `fetchAllPages` (status.ts) so we inherit the\n\t// cursor-stagnation + HARD_PAGE_CAP guard. A hand-rolled\n\t// `while (true)` loop without that guard would spin forever on\n\t// a buggy server returning a full page with the same `id`.\n\t// Same fix pattern as `resolveProposedReceiptHashes`.\n\tconst rows = await fetchAllPages<ReceiptPublic>((after) =>\n\t\tapi.listReceipts(args.relationshipId, signer, { delegationId: args.delegationId, limit: 100, ...(after ? { after } : {}) }),\n\t);\n\tconst row = rows.find((r) => r.requestHash === args.requestHash && r.responseHash === args.responseHash);\n\tif (!row) {\n\t\tthrow new Error(\n\t\t\t`${cmdName}: no receipt found for delegation ${args.delegationId} with the given request/response hashes. Run 'heyarp receipts <relationship-id>' to inspect the timeline.`,\n\t\t);\n\t}\n\tif (row.state !== 'proposed') {\n\t\tthrow new Error(`${cmdName}: receipt is already in state '${row.state}' — only PROPOSED receipts can be cosigned.`);\n\t}\n\tif (row.callerDid !== args.selfDid) {\n\t\tthrow new Error(`${cmdName}: this receipt's caller is ${row.callerDid}; only the caller can cosign. Switch with --from-did.`);\n\t}\n\treturn { payeeDid: row.payeeDid, receiptEventHash: row.receiptEventHash, verdictProposed: row.verdictProposed, notesHash: row.notesHash };\n}\n\nfunction printIngestResult(result: IngestResult): void {\n\tconsole.log(chalk.green('\\nDelivered.'));\n\tconsole.log(`${chalk.bold('Event id')}: ${chalk.cyan(result.eventId)}`);\n\tconsole.log(`${chalk.bold('Relationship id')}: ${chalk.cyan(result.relationshipId)}`);\n\tconsole.log(`${chalk.bold('Chain index')}: ${chalk.cyan(String(result.relationshipEventIndex))}`);\n\tconsole.log(`${chalk.bold('Server timestamp')}: ${chalk.cyan(result.serverTimestamp)}`);\n\tconsole.log(`${chalk.bold('Server event hash')}: ${chalk.cyan(result.serverEventHash)}`);\n}\n\nexport function parseVerdict(cmdName: string, raw: string | undefined): Verdict {\n\tif (raw === undefined || raw === '') return 'accepted';\n\tif (!(VERDICT_VALUES as readonly string[]).includes(raw)) {\n\t\tthrow new Error(`${cmdName}: --verdict must be one of ${VERDICT_VALUES.join(' | ')} (got '${raw}')`);\n\t}\n\treturn raw as Verdict;\n}\n\nexport function parseUsage(\n\tcmdName: string,\n\topts: { inputTokens?: string; outputTokens?: string; latencyMs?: string; model?: string; computedAmount?: string },\n): ReceiptContent['usage'] | undefined {\n\tconst usage: NonNullable<ReceiptContent['usage']> = {};\n\tif (opts.inputTokens !== undefined) usage.input_tokens = parseInteger(cmdName, '--input-tokens', opts.inputTokens);\n\tif (opts.outputTokens !== undefined) usage.output_tokens = parseInteger(cmdName, '--output-tokens', opts.outputTokens);\n\tif (opts.latencyMs !== undefined) usage.latency_ms = parseInteger(cmdName, '--latency-ms', opts.latencyMs);\n\tif (opts.model) usage.model = opts.model;\n\tif (opts.computedAmount) usage.computed_amount = opts.computedAmount;\n\tif (Object.keys(usage).length === 0) return undefined;\n\treturn usage;\n}\n\nexport function parseTtl(cmdName: string, raw: string | undefined): number {\n\tif (raw === undefined) return 3600;\n\tconst n = Number(raw);\n\tif (!Number.isFinite(n) || !Number.isInteger(n) || n <= 0) {\n\t\tthrow new Error(`${cmdName}: --ttl must be a positive integer number of seconds (got '${raw}')`);\n\t}\n\treturn n;\n}\n\nexport function parseInteger(cmdName: string, flag: string, raw: string): number {\n\tconst n = Number(raw);\n\tif (!Number.isFinite(n) || !Number.isInteger(n) || n < 0) {\n\t\tthrow new Error(`${cmdName}: ${flag} must be a non-negative integer (got '${raw}')`);\n\t}\n\treturn n;\n}\n\n// Validate + normalise a positional UUID arg to lowercase\n// canonical form. Mirror of work.ts / delegation.ts helpers —\n// exported for symmetry + cross-command callable.\n//\n// RFC 4122 §3: canonical UUID is lowercase. Mixed-case operator\n// input (banner copy-paste) would otherwise miss exact-match\n// server-side lookups.\nexport function requireUuidNormalised(cmdName: string, raw: string, label: string): string {\n\trequireUuid(cmdName, raw, label);\n\treturn raw.toLowerCase();\n}\n\n/**\n * Thin wrapper over the shared `requireUuid` in `../id-format`.\n * Kept here for the existing exported surface; the hint-rich error\n * comes from the centralised implementation.\n */\nexport function requireUuid(cmdName: string, raw: string, label: string): void {\n\tsharedRequireUuid(cmdName, raw, label);\n}\n\nexport function requireSha256(cmdName: string, raw: string, label: string): void {\n\tif (!SHA256_RE.test(raw)) {\n\t\tthrow new Error(`${cmdName}: ${label} must match 'sha256:<64 lowercase hex>' (got '${raw}')`);\n\t}\n}\n\nexport function requireDid(cmdName: string, did: string, label: string): void {\n\tif (typeof did !== 'string' || !did.startsWith('did:arp:') || did.length <= 'did:arp:'.length) {\n\t\tthrow new Error(`${cmdName}: ${label} must look like 'did:arp:...' (got '${did}')`);\n\t}\n}\n","import chalk from 'chalk';\nimport type { Command } from 'commander';\nimport { ArpApiClient, type ListReceiptsQuery, type ReceiptPublic } from '../api';\nimport { printJsonArray, printVerbose } from '../format';\nimport { type AgentLocalState, resolveSenderAgent } from '../state';\nimport { makeSigner } from './lifecycle';\n\n// exported alongside `runReceipts` for mutual-exclusion test coverage.\nexport interface ReceiptsOptions {\n\tserver?: string;\n\tstate?: string;\n\tdelegationId?: string;\n\tafter?: string;\n\tlimit?: string;\n\tfromDid?: string;\n\tverbose?: boolean;\n\tjson?: boolean;\n\tfullIds?: boolean;\n}\n\nconst ALLOWED_STATES = new Set(['proposed', 'cosigned']);\n\n/**\n * `heyarp receipts <relationship-id>` — list the receipt timeline\n * for a relationship via signed\n * `GET /v1/relationships/:id/receipts`. Member-only (signer must be\n * one of the pair); rows are ordered chronologically with the same\n * composite cursor as the contracts / delegations / work lists.\n *\n * Top-level `heyarp receipt` is owned by `commands/receipt.ts` (the\n * propose / cosign subcommand group), so this list command is a\n * sibling at top level (`heyarp receipts`) — same separation as\n * contracts / delegations / work-list.\n */\nexport function registerReceiptsCommand(root: Command): void {\n\troot.command('receipts')\n\t\t.description(\n\t\t\t\"List receipts for a relationship (one row per (delegationId, requestHash, responseHash), oldest-first). Receipt rows expose the chain hash as `receiptEventHash` (NOT `serverEventHash` — 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.\",\n\t\t)\n\t\t.argument('<relationship-id>', 'Relationship UUID')\n\t\t.option('--server <url>', 'Override ARP server base URL')\n\t\t.option('--state <s>', 'Filter by exact state (proposed|cosigned)')\n\t\t.option('--delegation-id <uuid>', 'Narrow to receipts under a specific delegation id')\n\t\t.option('--after <id>', \"Cursor: pass the previous page's last `id` to fetch the next page\")\n\t\t.option('--limit <n>', 'Max rows to return (1..100)', '20')\n\t\t.option('--from-did <did>', 'Signer DID — required only if multiple agents are registered against this server')\n\t\t.option(\n\t\t\t'--verbose',\n\t\t\t'After the one-line summaries, print a framed \"Full receipt payloads (N rows)\" block — each row labelled with full delegationId + requestHash + responseHash (the values `receipt cosign` requires) and dumped as JSON. Mutually exclusive with --json.',\n\t\t\tfalse,\n\t\t)\n\t\t.option('--json', 'Machine-readable mode — emit a single JSON array of receipt rows, no chalk, no summary. Pipe-safe. Mutually exclusive with --verbose.', false)\n\t\t.option(\n\t\t\t'--full-ids',\n\t\t\t'Print delegationId / requestHash / responseHash / DIDs in full (no truncation). REQUIRED for piping into `receipt cosign` which needs the full sha256s.',\n\t\t\tfalse,\n\t\t)\n\t\t.action(async (relationshipId: string, opts: ReceiptsOptions) => {\n\t\t\tawait runReceipts(relationshipId, opts);\n\t\t});\n}\n\n// Exported for --verbose regression coverage.\nexport async function runReceipts(relationshipId: string, opts: ReceiptsOptions): Promise<void> {\n\t// --verbose and --json are mutually exclusive.\n\tif (opts.verbose && opts.json) {\n\t\tthrow new Error(\n\t\t\t'receipts: --verbose and --json are mutually exclusive. --json already emits the full payload; --verbose adds the framed dump on top of the human summary.',\n\t\t);\n\t}\n\tconst limit = parseLimit(opts.limit);\n\tconst state = parseState(opts.state);\n\n\tconst api = new ArpApiClient(opts.server);\n\tconst sender = resolveSenderAgent('receipts', opts.server, opts.fromDid);\n\t// Prelude is gated on `!--json` so a `… --json | jq` pipeline\n\t// gets pure JSON on stdout.\n\tif (!opts.json) {\n\t\tconsole.log(chalk.dim(`Server: ${api.serverUrl}`));\n\t\tconsole.log(chalk.dim(`Signer: ${sender.did}`));\n\t\tconsole.log(chalk.dim(`Relationship: ${relationshipId}`));\n\t}\n\n\tconst query: ListReceiptsQuery = { limit };\n\tif (state) query.state = state;\n\tif (opts.delegationId) query.delegationId = opts.delegationId;\n\tif (opts.after) query.after = opts.after;\n\n\tconst signer = makeSigner(sender);\n\tconst rows = await api.listReceipts(relationshipId, signer, query);\n\n\tif (opts.json) {\n\t\tprintJsonArray(rows);\n\t\treturn;\n\t}\n\n\tif (rows.length === 0) {\n\t\tconsole.log(chalk.dim('\\n(no receipts for this relationship)'));\n\t\treturn;\n\t}\n\n\tconsole.log('');\n\tfor (const r of rows) {\n\t\tconsole.log(formatReceiptLine(r, sender.did, { fullIds: !!opts.fullIds }));\n\t}\n\n\tif (opts.verbose) {\n\t\tprintVerbose(rows, 'Full receipt payloads:', (r) => ({\n\t\t\tprimary: `state=${r.state} verdict=${r.verdictFinal ?? r.verdictProposed}`,\n\t\t\t// `receipt cosign` requires the FULL `requestHash` and\n\t\t\t// `responseHash` plus `delegationId`. Putting all three on\n\t\t\t// one inline label keeps the cosign flow grep-able without\n\t\t\t// dropping into `--json | jq`.\n\t\t\tsecondary: `delegationId=${r.delegationId} requestHash=${r.requestHash} responseHash=${r.responseHash}`,\n\t\t}));\n\t}\n\n\tconst lastId = rows[rows.length - 1].id;\n\tconsole.log(chalk.dim(`\\n${rows.length} receipt row(s). Paginate with --after ${lastId}.`));\n}\n\n/**\n * One-line summary per receipt row:\n *\n * delegationHead/requestHash-head state direction verdict\n *\n * Exported for unit tests.\n */\nexport function formatReceiptLine(r: ReceiptPublic, selfDid: string, opts: { fullIds?: boolean } = {}): string {\n\tconst delegationPart = opts.fullIds ? r.delegationId : idHead(r.delegationId);\n\tconst requestHashPart = opts.fullIds ? r.requestHash : hashHead(r.requestHash);\n\tconst id = chalk.bold(`${delegationPart}/${requestHashPart}`);\n\tconst state = colorState(r.state).padEnd(stateColumnWidth());\n\tconst callerHead = opts.fullIds ? r.callerDid : didHead(r.callerDid);\n\tconst payeeHead = opts.fullIds ? r.payeeDid : didHead(r.payeeDid);\n\tconst direction = r.payeeDid === selfDid ? `${chalk.bold('me')}(payee) → ${chalk.dim(callerHead)}` : `${chalk.dim(payeeHead)}(payee) → ${chalk.bold('me')}`;\n\tconst verdict = formatVerdict(r);\n\t// `receipt cosign` requires BOTH requestHash and responseHash. The\n\t// summary line only fits one (delegationId/requestHash) without\n\t// wrapping; under --full-ids surface responseHash on a continuation\n\t// line so the cosign-from-listing copy-paste path is complete.\n\tconst responseTail = opts.fullIds ? `\\n ${chalk.dim('responseHash:')} ${chalk.cyan(r.responseHash)}` : '';\n\treturn `${id} ${state} ${direction} ${verdict}${responseTail}`;\n}\n\nfunction colorState(s: ReceiptPublic['state']): string {\n\tswitch (s) {\n\t\tcase 'proposed':\n\t\t\treturn chalk.yellow('proposed');\n\t\tcase 'cosigned':\n\t\t\treturn chalk.green('cosigned');\n\t}\n}\n\nfunction stateColumnWidth(): number {\n\treturn 8;\n}\n\nfunction formatVerdict(r: ReceiptPublic): string {\n\tconst final = r.verdictFinal ?? r.verdictProposed;\n\tswitch (final) {\n\t\tcase 'accepted':\n\t\t\treturn chalk.green('accepted');\n\t\tcase 'accepted_with_notes':\n\t\t\treturn chalk.yellow('accepted_with_notes');\n\t\tcase 'rejected':\n\t\t\treturn chalk.red('rejected');\n\t}\n}\n\nfunction idHead(id: string): string {\n\tif (id.length <= 12) return id;\n\treturn `${id.slice(0, 8)}...${id.slice(-4)}`;\n}\n\nfunction hashHead(hash: string): string {\n\t// `sha256:<64 hex>` — show `sha256:<first-7-of-hex>...`.\n\tif (hash.length <= 17) return hash;\n\treturn `${hash.slice(0, 14)}...`;\n}\n\nfunction didHead(did: string): string {\n\tif (did.length <= 20) return did;\n\treturn `${did.slice(0, 20)}...`;\n}\n\nexport function parseState(raw: string | undefined): ReceiptPublic['state'] | undefined {\n\tif (raw === undefined) return undefined;\n\tif (!ALLOWED_STATES.has(raw)) {\n\t\tthrow new Error(`receipts: --state must be one of proposed|cosigned (got '${raw}')`);\n\t}\n\treturn raw as ReceiptPublic['state'];\n}\n\nexport function parseLimit(raw: string | undefined): number {\n\tif (raw === undefined) return 20;\n\tconst n = Number(raw);\n\tif (!Number.isFinite(n) || !Number.isInteger(n) || n < 1 || n > 100) {\n\t\tthrow new Error(`receipts: --limit must be an integer between 1 and 100 (got '${raw}')`);\n\t}\n\treturn n;\n}\n","import { randomBytes } from 'node:crypto';\nimport { existsSync, readFileSync } from 'node:fs';\nimport {\n\ttype KeyLinkPayload,\n\tbase58btcEncode,\n\tderiveScryptKey,\n\tgenerateKeyPair,\n\tgetPublicKey,\n\trfc3339,\n\tformatDid as sdkFormatDid,\n\tsenderNonce,\n\tsignChallenge,\n\tsignKeyLinkAttestation,\n\tuuidV4,\n} from '@heyanon-arp/sdk';\nimport chalk from 'chalk';\nimport type { Command } from 'commander';\nimport prompts from 'prompts';\nimport { ArpApiClient, type RegisterAgentRequest, resolveServerUrl } from '../api';\nimport { formatJson } from '../format';\nimport { listHomes, recordHome } from '../homes';\nimport { arpHomeDir } from '../paths';\nimport { listAgents, saveAgent } from '../state';\n\ninterface RegisterOptions {\n\tserver?: string;\n\tfromKeys?: string;\n\t// Non-interactive flag layer — any of these skips the matching\n\t// prompt. Pass `--yes` to hard-fail when something required is\n\t// still missing after merging flags (CI / scripted use).\n\t// (No `--verbose` here: register has no useful verbose output;\n\t// stack traces are controlled by the root-level `--trace`.)\n\tname?: string;\n\tdescription?: string;\n\tendpointUrl?: string;\n\ttag?: string[];\n\t// V1-alpha: accountId parked. The `--account-id` Commander flag is\n\t// also commented out below — scripts passing it will get an\n\t// \"unknown option\" error rather than a silent ignore (deliberate:\n\t// surfaces stale callers loudly so they can be cleaned up).\n\t// Uncomment + re-include in the request body when launchpad↔ARP\n\t// join lands.\n\t// accountId?: string;\n\tpassword?: string;\n\tyes?: boolean;\n\t/**\n\t * Controls whether the agent is auto-published into the discovery\n\t * catalog after a successful registration. Default `active` — the\n\t * common case for both worker and buyer agents who want to be\n\t * discoverable immediately. Pass `--publication draft` to keep\n\t * the agent out of the catalog (curate profile first, then\n\t * `heyarp publish <did>` manually).\n\t */\n\tpublication?: 'active' | 'draft' | string;\n\t/**\n\t * Machine-readable mode. When set, the human-friendly success\n\t * prints are suppressed and a single JSON object is emitted on\n\t * stdout instead:\n\t *\n\t * {did, settlementPublicKeyB58, identityPublicKeyB58,\n\t * keyMode, publication, didDocument}\n\t *\n\t * (V1-alpha: `accountId` is parked from the output until\n\t * launchpad↔ARP join lands.)\n\t *\n\t * Useful for scripted setups that want to feed the DID +\n\t * settlement pubkey directly into `solana airdrop` /\n\t * `heyarp delegation offer` without parsing free-form text.\n\t * `--json` REQUIRES `--yes` (interactive prompts would\n\t * mangle the single-doc contract).\n\t */\n\tjson?: boolean;\n}\n\n/**\n * `heyarp register` — full owner-driven registration flow.\n *\n * 1. Generate (or load) identity + settlement keypairs.\n * 2. Prompt for password / name / description / endpoint.\n * (V1-alpha: accountId prompt parked.)\n * 3. Derive scrypt key (16-byte salt → 32-byte key, ~few hundred ms).\n * 4. POST /agents/challenge → sign challenge bytes → POST /challenge-response.\n * 5. Build ARP-KEY-LINK-v1 payload + scrypt-password attestation.\n * 6. POST /agents/register with the assembled body.\n * 7. Persist secret material to ~/.arp/agents.json (chmod 0600).\n *\n * Failures bubble up as ApiError / Error → top-level CLI handler\n * formats them. A failed registration leaves no partial state on disk.\n */\nexport function registerRegisterCommand(root: Command): void {\n\troot.command('register')\n\t\t// Surface the `--password` 8-char minimum + the `--yes`\n\t\t// REQUIRED-with semantics in the command's own help blurb\n\t\t// so operators don't get hit with a runtime error after\n\t\t// they've typed the rest of the flags.\n\t\t.description(\n\t\t\t[\n\t\t\t\t'Register a new ARP agent. Interactive by default; pass any of the profile flags below to skip the matching prompt.',\n\t\t\t\t'',\n\t\t\t\t'`--password` is REQUIRED — must be at least 8 characters. In interactive mode (--yes omitted) the CLI prompts for it; with --yes it must be passed explicitly.',\n\t\t\t\t'`--yes` is the non-interactive switch — every required field must arrive via flags (no prompts). Use this for scripted setups.',\n\t\t\t].join('\\n'),\n\t\t)\n\t\t.option('--server <url>', 'Override ARP server base URL')\n\t\t.option('--from-keys <file>', 'Load identity + settlement keys from a JSON file instead of generating')\n\t\t.option('--name <s>', 'Display name (skips the name prompt)')\n\t\t.option('--description <s>', 'Description (skips the description prompt)')\n\t\t.option('--endpoint-url <s>', 'Public ARP endpoint URL (skips the endpoint prompt)')\n\t\t.option('--tag <s>', 'Capability tag — repeatable, e.g. --tag translation --tag fr', accumulate, [])\n\t\t// V1-alpha: `--account-id` flag parked. Server's DTO no longer\n\t\t// accepts accountId; the flag is removed to avoid scripts\n\t\t// thinking they're passing meaningful state. Uncomment when\n\t\t// launchpad↔ARP join lands.\n\t\t// .option('--account-id <uuid>', 'Pre-set the accountId (skips the prompt)')\n\t\t.option(\n\t\t\t'--password <s>',\n\t\t\t// `--password` puts the secret in `argv` — visible via\n\t\t\t// `ps aux` / kernel process table on shared hosts,\n\t\t\t// recorded by `/proc/<pid>/cmdline`, and almost always\n\t\t\t// logged by CI runners (e.g. GitHub Actions echoes the\n\t\t\t// full command). Safer alternatives:\n\t\t\t// • interactive prompt (default) — never written anywhere\n\t\t\t// • `HEYARP_PASSWORD` env var (V1.5 — tracked) reads\n\t\t\t// from env so the secret stays out of argv even in\n\t\t\t// scripts\n\t\t\t// Treat `--password <s>` as a one-off local-dev affordance;\n\t\t\t// do NOT use it in CI pipelines without a secret-redacting\n\t\t\t// runner.\n\t\t\t'Owner password — 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.',\n\t\t)\n\t\t.option(\n\t\t\t'--yes',\n\t\t\t'Strict non-interactive: fail if any required field is still missing after merging flags. With --yes, --password must be supplied explicitly (>= 8 chars).',\n\t\t\tfalse,\n\t\t)\n\t\t.option(\n\t\t\t'--publication <state>',\n\t\t\t\"Post-register publication mode. 'active' (default) auto-publishes the agent into the discovery catalog so other agents can find it immediately via `heyarp agents`. 'draft' keeps it out of the catalog — curate the profile first, then run `heyarp publish <did>` manually.\",\n\t\t\t'active',\n\t\t)\n\t\t.option(\n\t\t\t'--json',\n\t\t\t// Emit a single JSON object instead of human-friendly\n\t\t\t// success prints. Output shape:\n\t\t\t// {did, settlementPublicKeyB58, identityPublicKeyB58,\n\t\t\t// keyMode, publication, didDocument}\n\t\t\t// (V1-alpha: `accountId` parked from the output.)\n\t\t\t// REQUIRES --yes (interactive prompts would corrupt the\n\t\t\t// single-doc contract). The auto-publish branch reports\n\t\t\t// its outcome under `.publication` ('active', 'draft',\n\t\t\t// 'skip-no-endpoint', or 'failed:<reason>') instead of\n\t\t\t// emitting human-readable lines.\n\t\t\t'Machine-readable mode — emit `{did, settlementPublicKeyB58, …, didDocument}` JSON instead of human prints. REQUIRES --yes (interactive prompts would corrupt the single-doc JSON output).',\n\t\t\tfalse,\n\t\t)\n\t\t// register has no `--verbose`; operators use `heyarp --trace\n\t\t// register …` for stack traces (the root-level flag).\n\t\t.action(async (opts: RegisterOptions) => {\n\t\t\tawait runRegister(opts);\n\t\t});\n}\n\n/** Commander accumulator for repeatable flags (--tag a --tag b → ['a','b']). */\nfunction accumulate(value: string, previous: string[]): string[] {\n\treturn [...previous, value];\n}\n\nasync function runRegister(opts: RegisterOptions): Promise<void> {\n\t// Parse publication mode FIRST so a typo (e.g. `--publication\n\t// public`) fails before any side effects (challenge round-trip,\n\t// scrypt derivation, server register, local agents.json write).\n\t// Otherwise a mistyped flag could silently produce a DRAFT\n\t// agent despite the documented \"loud error on unknown values\"\n\t// behaviour.\n\tconst publication = parsePublicationMode(opts.publication ?? 'active');\n\n\t// --json mode is strictly non-interactive. With prompts in the\n\t// mix, stdout would have human text intermixed with the final\n\t// JSON blob — broken contract. Reject early so the operator\n\t// gets a clear error instead of confusing parse failures\n\t// downstream.\n\tassertJsonRequiresYes(opts);\n\n\tconst api = new ArpApiClient(opts.server);\n\tif (!opts.json) console.log(chalk.dim(`Server: ${api.serverUrl}`));\n\n\t// Collision warning. Operators sometimes assume they're isolated\n\t// because they ran register first, then hit auth-mismatch errors\n\t// because `~/.arp/agents.json` already had other agents from\n\t// concurrent processes. Surface this UP FRONT so the operator\n\t// can either set `HEYARP_HOME=…` (per-agent state isolation) or\n\t// pass `--from-did` going forward.\n\t//\n\t// Skipped in --json mode — advisory-only, would print human\n\t// text that would corrupt the single-doc JSON contract.\n\t// --yes implies non-interactive operator who's already opted\n\t// into scripted use; the collision risk is theirs to manage\n\t// out-of-band.\n\tif (!opts.json) {\n\t\twarnIfAgentsAlreadyRegistered(opts.server);\n\t\t// Orphan-home warning. If HEYARP_HOME is unset BUT the registry\n\t\t// shows other home directories on this machine, there's a real\n\t\t// chance the operator forgot to export their env var and is\n\t\t// about to silently create a brand-new identity in `~/.arp/`\n\t\t// instead of adding to one of the existing homes. Surface the\n\t\t// list so they can ctrl-c and redo with the right env.\n\t\twarnIfOrphanHomesPresent();\n\t}\n\n\t// Step 1 — keys\n\tconst keys = opts.fromKeys ? loadKeysFromFile(opts.fromKeys) : freshKeys();\n\tconst did = sdkFormatDid(keys.identityPublicKey);\n\tif (!opts.json) console.log(chalk.dim(`DID will be: ${did}`));\n\n\t// Step 2 — flag/prompt merge. Each field is \"supplied via flag\"\n\t// or \"prompted\"; `--yes` rejects the prompt path entirely so CI\n\t// / agent runners get a hard error rather than blocking on stdin.\n\t// Tags can ONLY come via `--tag` (repeatable) — no prompt for\n\t// them; the interactive flow asks for a CSV via the description-\n\t// adjacent prompt below.\n\tconst answers = await mergeAnswers(opts);\n\n\t// Step 3 — scrypt\n\tconst scryptSalt = randomBytes(16);\n\tif (!opts.json) console.log(chalk.dim('Deriving scrypt key, this may take a moment...'));\n\tconst scryptKey = deriveScryptKey(answers.password, new Uint8Array(scryptSalt));\n\n\t// Step 4 — challenge round-trip\n\tconst challenge = await api.issueChallenge('register');\n\tconst challengeBytes = base64UrlNoPadDecode(challenge.challengeB64);\n\tif (challengeBytes.length !== 32) {\n\t\tthrow new Error(`Server returned a ${challengeBytes.length}-byte challenge; expected 32`);\n\t}\n\tconst challengeSig = signChallenge(challengeBytes, keys.identitySecretKey);\n\tconst identityPublicKeyB58 = base58btcEncode(keys.identityPublicKey);\n\tawait api.submitChallengeResponse({\n\t\tchallengeId: challenge.challengeId,\n\t\tidentityPublicKey: identityPublicKeyB58,\n\t\tsignature: Buffer.from(challengeSig).toString('base64'),\n\t});\n\n\t// Step 5 — KEY-LINK payload + attestation\n\tconst settlementPublicKeyB58 = base58btcEncode(keys.settlementPublicKey);\n\tconst scryptSaltId = uuidV4();\n\tconst ownerId = uuidV4();\n\tconst payload: KeyLinkPayload = {\n\t\tpurpose: 'ARP-KEY-LINK-v1',\n\t\tagent_did: did,\n\t\tidentity_public_key: identityPublicKeyB58,\n\t\tsettlement_public_key: settlementPublicKeyB58,\n\t\tkey_mode: 'separated_soft',\n\t\towner_id: ownerId,\n\t\towner_signing_method: 'scrypt_password_proof',\n\t\tlink_method: 'manual',\n\t\tcreated_at: rfc3339(),\n\t\tnonce: senderNonce(),\n\t};\n\tconst attestation = signKeyLinkAttestation({ payload, scryptKey, scryptSaltId });\n\n\t// Step 6 — POST /register\n\tconst body: RegisterAgentRequest = {\n\t\tchallengeId: challenge.challengeId,\n\t\t// V1-alpha: accountId parked — server's DTO no longer accepts it.\n\t\t// accountId: answers.accountId,\n\t\tidentityPublicKey: identityPublicKeyB58,\n\t\tsettlementPublicKey: settlementPublicKeyB58,\n\t\tkeyMode: 'separated_soft',\n\t\townerAttestation: {\n\t\t\tpayload: attestation.payload as unknown as Record<string, unknown>,\n\t\t\tsig: attestation.sig,\n\t\t\tscrypt_salt_id: attestation.scrypt_salt_id,\n\t\t},\n\t\tscryptKeyB64: Buffer.from(scryptKey).toString('base64'),\n\t\tscryptSaltB64: Buffer.from(scryptSalt).toString('base64'),\n\t\tname: answers.name,\n\t\tdescription: answers.description ? answers.description : undefined,\n\t\tdefaultEndpointUrl: answers.defaultEndpointUrl ? answers.defaultEndpointUrl : undefined,\n\t\ttags: answers.tags.length > 0 ? answers.tags : undefined,\n\t};\n\tconst result = await api.register(body);\n\n\t// Step 7 — persist (only after the server confirms; partial state is worse than none)\n\tsaveAgent(opts.server, {\n\t\tdid: result.did,\n\t\tidentityPublicKeyB58,\n\t\tidentitySecretKeyB64: Buffer.from(keys.identitySecretKey).toString('base64'),\n\t\tsettlementPublicKeyB58,\n\t\tsettlementSecretKeyB64: Buffer.from(keys.settlementSecretKey).toString('base64'),\n\t\tscryptKeyB64: Buffer.from(scryptKey).toString('base64'),\n\t\tscryptSaltB64: Buffer.from(scryptSalt).toString('base64'),\n\t\tscryptSaltId,\n\t\townerId,\n\t\t// `metadata.owner_attestation_id` is the canonical name in the\n\t\t// DID document — same value as server's `currentAttestationId`\n\t\t// at the moment of registration.\n\t\tcurrentAttestationId: result.didDocument.metadata.owner_attestation_id,\n\t\t// V1-alpha: accountId parked — local state file no longer\n\t\t// records the field. Existing state files written when the\n\t\t// field was required will still carry the value; readers\n\t\t// tolerate either shape.\n\t\t// accountId: answers.accountId,\n\t\tkeyMode: 'separated_soft',\n\t\tname: answers.name,\n\t\tdescription: answers.description || undefined,\n\t\tdefaultEndpointUrl: answers.defaultEndpointUrl || undefined,\n\t\ttags: answers.tags.length > 0 ? answers.tags : undefined,\n\t\tregisteredAt: new Date().toISOString(),\n\t});\n\n\t// Record the home dir into the global registry so a future\n\t// `heyarp homes` invocation can rediscover this identity even\n\t// from a shell where HEYARP_HOME isn't set. Best-effort —\n\t// registry write failure must NOT undo the agent save above.\n\ttry {\n\t\trecordHome(arpHomeDir());\n\t} catch (registryErr) {\n\t\t// Surface the failure but don't abort. The agent IS\n\t\t// registered server-side and on disk; only the discoverability\n\t\t// affordance is reduced.\n\t\tif (!opts.json) console.log(chalk.dim(`(homes registry write failed: ${(registryErr as Error).message})`));\n\t}\n\n\tif (!opts.json) {\n\t\tconsole.log(chalk.green('\\nRegistered.'));\n\t\tconsole.log(`${chalk.bold('DID')}: ${chalk.cyan(result.did)}`);\n\t\t// Operators need the raw base58 settlement pubkey to fund the\n\t\t// on-chain account with SOL before `heyarp wallet create-lock`\n\t\t// can build a real escrow tx. The DID doc echo below renders\n\t\t// the same key as a `publicKeyMultibase` (z-prefixed\n\t\t// multibase), which is the wrong shape for Solana faucets /\n\t\t// `solana transfer` / Phantom paste. Echoing the raw b58\n\t\t// upfront saves the agents.json dig.\n\t\tconsole.log(`${chalk.bold('Settlement pubkey')} ${chalk.dim('(fund with SOL)')}: ${chalk.cyan(settlementPublicKeyB58)}`);\n\t\tconsole.log(chalk.bold('DID document:'));\n\t\tconsole.log(formatJson(result.didDocument));\n\t}\n\n\t// Auto-publish unless the operator opted into draft. The common\n\t// case is \"register + appear in catalog\"; `--publication draft`\n\t// is the explicit opt-out for \"I want to curate first\".\n\tconst decision = decideAutoPublish({ publication, defaultEndpointUrl: answers.defaultEndpointUrl });\n\t// Track the publication outcome string for the --json summary.\n\t// Mirrors the human-text branches below.\n\tlet publicationOutcome: 'published' | 'draft' | 'skip-no-endpoint' | string;\n\tif (decision === 'try') {\n\t\ttry {\n\t\t\tconst signer = makeSignerFromSecret(keys.identitySecretKey, result.did);\n\t\t\tawait api.publishAgent(result.did, signer);\n\t\t\tpublicationOutcome = 'published';\n\t\t\tif (!opts.json) console.log(chalk.green(`\\n✓ Published — discoverable now via \\`heyarp agents\\`.`));\n\t\t} catch (err) {\n\t\t\t// Don't fail registration on publish failure — agent IS\n\t\t\t// registered server-side and on disk. Surface the gap so\n\t\t\t// the operator can retry with `heyarp publish <did>` later.\n\t\t\tpublicationOutcome = `failed: ${(err as Error).message}`;\n\t\t\tif (!opts.json) console.log(chalk.yellow(`\\n⚠ Auto-publish failed (${(err as Error).message}). Agent saved as DRAFT — run \\`heyarp publish ${result.did}\\` to make it discoverable.`));\n\t\t}\n\t} else if (decision === 'skip-no-endpoint') {\n\t\t// Endpoint-less agents (buyer-only flow) would fail server-\n\t\t// side with AGENT_MISSING_ENDPOINT. Skip the doomed call and\n\t\t// explain, so the operator doesn't see a scary\n\t\t// `⚠ Auto-publish failed` warning when they intentionally\n\t\t// had no endpoint.\n\t\tpublicationOutcome = 'skip-no-endpoint';\n\t\tif (!opts.json) {\n\t\t\tconsole.log(chalk.dim(`\\nAuto-publish skipped: no --endpoint-url supplied (buyer-only registration). Agent is saved as DRAFT.`));\n\t\t\tconsole.log(chalk.dim(`If this agent should also accept work, re-register with \\`--endpoint-url <https://…>\\` OR run`));\n\t\t\tconsole.log(chalk.dim(`\\`heyarp rotate ${result.did} --endpoint-url <https://…>\\` then \\`heyarp publish ${result.did}\\`.`));\n\t\t}\n\t} else {\n\t\t// decision === 'skip-draft'\n\t\tpublicationOutcome = 'draft';\n\t\tif (!opts.json) {\n\t\t\tconsole.log(chalk.dim(`\\nPublication mode: DRAFT. Agent is registered but NOT discoverable via \\`heyarp agents\\`.`));\n\t\t\tconsole.log(chalk.dim(`Run \\`heyarp publish ${result.did}\\` when ready to appear in the catalog.`));\n\t\t}\n\t}\n\t// Respect `HEYARP_HOME` in the success message. Operators\n\t// running with `HEYARP_HOME=/tmp/...` see their override path\n\t// instead of a hard-coded `~/.arp/`, so the printed path matches\n\t// where the state file actually lives.\n\tif (!opts.json) console.log(chalk.dim(`\\nLocal state saved to ${arpHomeDir()}/agents.json (mode 0600).`));\n\n\t// Single-doc JSON output. All human prints above were gated on\n\t// `!opts.json`; stdout is now empty (apart from any commander /\n\t// parse messages). Emit one JSON object — the keys mirror what\n\t// scripts would otherwise have to grep from the human output.\n\tif (opts.json) {\n\t\tconsole.log(\n\t\t\tJSON.stringify(\n\t\t\t\t{\n\t\t\t\t\tdid: result.did,\n\t\t\t\t\tsettlementPublicKeyB58,\n\t\t\t\t\tidentityPublicKeyB58,\n\t\t\t\t\t// V1-alpha: accountId parked — `--json` output no longer\n\t\t\t\t\t// includes it. Uncomment when launchpad↔ARP join lands.\n\t\t\t\t\t// accountId: answers.accountId,\n\t\t\t\t\tkeyMode: 'separated_soft',\n\t\t\t\t\tpublication: publicationOutcome,\n\t\t\t\t\tlocalStatePath: `${arpHomeDir()}/agents.json`,\n\t\t\t\t\tdidDocument: result.didDocument,\n\t\t\t\t},\n\t\t\t\tnull,\n\t\t\t\t2,\n\t\t\t),\n\t\t);\n\t}\n}\n\n/** Final answer set after merging CLI flags + interactive prompts. */\ninterface RegisterAnswers {\n\tpassword: string;\n\tname: string;\n\tdescription: string;\n\tdefaultEndpointUrl: string;\n\t// V1-alpha: accountId parked. Server no longer requires it; CLI\n\t// stops prompting + stops sending it on the wire. Uncomment when\n\t// launchpad↔ARP join lands. See `apps/arp-server/src/database/arp-agent/schemas/arp-agent.schema.ts`.\n\t// accountId: string;\n\ttags: string[];\n}\n\n/**\n * Merge `--*` flags with interactive prompts.\n *\n * Behaviour:\n * - `--name`, `--description`, `--endpoint-url`, `--password` skip\n * the matching prompt outright. (V1-alpha: `--account-id` is\n * parked — flag and prompt both commented out.)\n * - `--tag` (repeatable) is the ONLY way to set tags; the\n * interactive path prompts for a comma-separated string and\n * splits it locally. Server-side validation rejects bad tags\n * either way.\n * - `--yes` enforces strict non-interactive mode: any required\n * field still missing (password / name) → hard fail. Optional\n * fields (description, endpointUrl, tags) just resolve to empty.\n * - When prompts ARE shown, fields covered by flags are skipped\n * so the user isn't asked to repeat themselves.\n */\nasync function mergeAnswers(opts: RegisterOptions): Promise<RegisterAnswers> {\n\t// What still needs prompting (only the unsupplied required +\n\t// optional fields). Under `--yes` (strict non-interactive) we\n\t// suppress ALL prompts — optional fields just resolve to ''\n\t// rather than blocking on stdin.\n\tconst need = opts.yes\n\t\t? { password: false, name: false, description: false, defaultEndpointUrl: false, tagsCsv: false /* accountId parked V1-alpha */ }\n\t\t: {\n\t\t\t\tpassword: opts.password === undefined,\n\t\t\t\tname: opts.name === undefined,\n\t\t\t\tdescription: opts.description === undefined,\n\t\t\t\tdefaultEndpointUrl: opts.endpointUrl === undefined,\n\t\t\t\ttagsCsv: opts.tag === undefined || opts.tag.length === 0,\n\t\t\t\t// V1-alpha: accountId parked. Uncomment + restore the prompt\n\t\t\t\t// below when launchpad↔ARP join lands.\n\t\t\t\t// accountId: opts.accountId === undefined,\n\t\t\t};\n\n\t// Strict non-interactive mode: required fields must be supplied via flags.\n\t// (V1-alpha: `--account-id` is parked — the flag, prompt, and request\n\t// field are all commented out until launchpad↔ARP join lands. Until\n\t// then the server's register DTO no longer accepts accountId so there\n\t// is nothing to validate / require here.)\n\tif (opts.yes) {\n\t\tconst missing: string[] = [];\n\t\tif (opts.password === undefined) missing.push('--password');\n\t\tif (opts.name === undefined) missing.push('--name');\n\t\tif (missing.length > 0) {\n\t\t\tthrow new Error(`register --yes: missing required flag${missing.length > 1 ? 's' : ''}: ${missing.join(', ')}`);\n\t\t}\n\t}\n\n\t// Mirror the interactive password prompt's 8-char minimum: a\n\t// `--password` flag is just another input path and shouldn't be\n\t// allowed to slip past the validator the prompt already enforces.\n\tif (opts.password !== undefined && opts.password.length < 8) {\n\t\tthrow new Error('register --password: password must be at least 8 characters');\n\t}\n\n\tconst promptDefs: prompts.PromptObject[] = [];\n\tif (need.password) {\n\t\tpromptDefs.push({\n\t\t\ttype: 'password',\n\t\t\tname: 'password',\n\t\t\tmessage: 'Owner password (used to derive the scrypt key)',\n\t\t\tvalidate: (v: string) => (v.length >= 8 ? true : 'must be at least 8 characters'),\n\t\t});\n\t}\n\tif (need.name) {\n\t\tpromptDefs.push({\n\t\t\ttype: 'text',\n\t\t\tname: 'name',\n\t\t\tmessage: 'Agent name (display only)',\n\t\t\tvalidate: (v: string) => (v.length > 0 ? true : 'required'),\n\t\t});\n\t}\n\tif (need.description) {\n\t\tpromptDefs.push({ type: 'text', name: 'description', message: 'Description (optional)', initial: '' });\n\t}\n\tif (need.defaultEndpointUrl) {\n\t\tpromptDefs.push({ type: 'text', name: 'defaultEndpointUrl', message: 'Default endpoint URL (optional, blank to skip)', initial: '' });\n\t}\n\tif (need.tagsCsv) {\n\t\tpromptDefs.push({\n\t\t\ttype: 'text',\n\t\t\tname: 'tagsCsv',\n\t\t\tmessage: 'Tags (comma-separated, optional — e.g. translation,fr,en)',\n\t\t\tinitial: '',\n\t\t});\n\t}\n\t// V1-alpha: accountId prompt parked. Uncomment when launchpad↔ARP\n\t// join lands.\n\t// if (need.accountId) {\n\t// \tpromptDefs.push({\n\t// \t\ttype: 'text',\n\t// \t\tname: 'accountId',\n\t// \t\tmessage: 'Account ID (UUID — V1 accepts any value; press Enter for a fresh one)',\n\t// \t\tinitial: uuidV4(),\n\t// \t});\n\t// }\n\n\tconst prompted =\n\t\tpromptDefs.length > 0\n\t\t\t? await prompts(promptDefs, {\n\t\t\t\t\tonCancel: () => {\n\t\t\t\t\t\tconsole.log(chalk.yellow('\\nAborted.'));\n\t\t\t\t\t\tprocess.exit(130);\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t: ({} as Record<string, unknown>);\n\n\t// Merge: flag wins; prompt fills the gap.\n\tconst tags = (opts.tag && opts.tag.length > 0 ? opts.tag : parseTagsCsv(typeof prompted.tagsCsv === 'string' ? prompted.tagsCsv : ''))\n\t\t.map((t) => t.trim().toLowerCase())\n\t\t.filter((t) => t.length > 0);\n\n\t// V1-alpha: accountId parked. The fall-through chain below was\n\t// (--account-id flag → interactive prompt → fresh uuidV4()).\n\t// Stop deriving + stop including in RegisterAnswers. Uncomment\n\t// when launchpad↔ARP join lands.\n\t// const accountId = opts.accountId ?? (prompted.accountId as string | undefined) ?? uuidV4();\n\n\treturn {\n\t\tpassword: opts.password ?? (prompted.password as string),\n\t\tname: opts.name ?? (prompted.name as string),\n\t\tdescription: opts.description ?? (prompted.description as string | undefined) ?? '',\n\t\tdefaultEndpointUrl: opts.endpointUrl ?? (prompted.defaultEndpointUrl as string | undefined) ?? '',\n\t\t// accountId, // V1-alpha parked — see RegisterAnswers above.\n\t\ttags,\n\t};\n}\n\n/**\n * Print a one-time warning when HEYARP_HOME is unset AND the\n * homes registry knows about other directories on this machine.\n * This catches the multi-shell foot-gun: operator opens a new\n * terminal, forgets to export HEYARP_HOME, runs `heyarp register`,\n * silently creates a brand-new identity in `~/.arp/` instead of\n * adding to one of the existing homes.\n *\n * Doesn't block — just prints a banner. Under `--yes` (strict\n * non-interactive) the warning is informational, not a prompt.\n *\n * Exported for tests.\n */\nexport function warnIfOrphanHomesPresent(): void {\n\tif (process.env.HEYARP_HOME && process.env.HEYARP_HOME.length > 0) {\n\t\t// Env is set — operator clearly knows what they're doing.\n\t\treturn;\n\t}\n\tconst current = arpHomeDir();\n\t// Best-effort. The registry is a discoverability affordance; a\n\t// stale / corrupt file must NOT abort registration. Quietly\n\t// swallow read errors and continue.\n\tlet others: Awaited<ReturnType<typeof listHomes>>;\n\ttry {\n\t\tothers = listHomes().filter((h) => h.path !== current);\n\t} catch (registryErr) {\n\t\tconsole.log(chalk.dim(`(homes registry unreadable, skipping orphan-home check: ${(registryErr as Error).message})`));\n\t\treturn;\n\t}\n\tif (others.length === 0) return;\n\tconst list = others.map((h) => ` • ${chalk.cyan(h.path)} ${chalk.dim(`(last seen ${h.lastSeenAt})`)}`).join('\\n');\n\tconsole.log(chalk.yellow(`\\n⚠ HEYARP_HOME is unset, but other agent homes are registered on this machine:`));\n\tconsole.log(list);\n\tconsole.log(\n\t\tchalk.dim(\n\t\t\t` Registering will create a NEW agent under ${current}.\\n` +\n\t\t\t\t' If you meant to add to an existing home, abort (Ctrl-C) and re-run with:\\n' +\n\t\t\t\t' HEYARP_HOME=<path> heyarp register …\\n' +\n\t\t\t\t' Run `heyarp homes` to inspect the registry.\\n',\n\t\t),\n\t);\n}\n\n/**\n * Print a one-time warning when `~/.arp/agents.json` already holds\n * other agents for the resolved server. Without this, a fresh\n * register call on a populated home dir tends to surface as\n * `AUTH_NOT_RELATIONSHIP_MEMBER` errors several commands later —\n * the new DID doesn't auto-become the default `--from-did`, and\n * the resolver falls back to the first agent in state, which\n * silently signs envelopes as someone else.\n *\n * Surfacing this at register-time gives the operator two choices,\n * spelled out inline:\n * 1. `HEYARP_HOME=/path/per/agent` for full process isolation\n * (the prod pattern — see ARCH-1)\n * 2. Always pass `--from-did <new-did>` on subsequent commands\n *\n * Exported for tests.\n */\nexport function warnIfAgentsAlreadyRegistered(serverOverride: string | undefined): void {\n\tconst targetServer = resolveServerUrl(serverOverride);\n\tconst existing = listAgents().filter((row) => row.serverUrl === targetServer);\n\tif (existing.length === 0) return;\n\n\tconst list = existing.map((row) => ` • ${chalk.cyan(row.agent.did)}${row.agent.name ? chalk.dim(` (${row.agent.name})`) : ''}`).join('\\n');\n\tconsole.log(chalk.yellow('\\n⚠ ~/.arp/agents.json already has agent(s) for this server:'));\n\tconsole.log(list);\n\tconsole.log(\n\t\tchalk.dim(\n\t\t\t' After this register completes, you will have multiple local DIDs sharing one state file.\\n' +\n\t\t\t\t' To keep their state isolated, run with HEYARP_HOME pointing at a per-agent dir, e.g.\\n' +\n\t\t\t\t' HEYARP_HOME=/tmp/agent-alice heyarp register …\\n' +\n\t\t\t\t' Otherwise, pass --from-did <did> explicitly on every signed command.\\n',\n\t\t),\n\t);\n}\n\n/** Split a CSV string into trimmed non-empty tokens. Exported for tests. */\nexport function parseTagsCsv(raw: string): string[] {\n\tif (!raw) return [];\n\treturn raw\n\t\t.split(',')\n\t\t.map((t) => t.trim())\n\t\t.filter((t) => t.length > 0);\n}\n\nfunction freshKeys() {\n\tconst identity = generateKeyPair();\n\tconst settlement = generateKeyPair();\n\treturn {\n\t\tidentityPublicKey: identity.publicKey,\n\t\tidentitySecretKey: identity.secretKey,\n\t\tsettlementPublicKey: settlement.publicKey,\n\t\tsettlementSecretKey: settlement.secretKey,\n\t};\n}\n\ninterface FromKeysFile {\n\tidentitySecretKeyB64: string;\n\tsettlementSecretKeyB64: string;\n}\n\n/**\n * Load keys from a JSON file with `{ identitySecretKeyB64,\n * settlementSecretKeyB64 }`. Public keys are derived from the seeds —\n * we never read them from the file because the seed is the source of\n * truth and a file mismatch would silently produce a wrong DID.\n */\n// exported for tests\nexport function loadKeysFromFile(path: string) {\n\tif (!existsSync(path)) {\n\t\tthrow new Error(`--from-keys: file not found at ${path}`);\n\t}\n\tlet parsed: FromKeysFile;\n\ttry {\n\t\tparsed = JSON.parse(readFileSync(path, 'utf8')) as FromKeysFile;\n\t} catch (err) {\n\t\tthrow new Error(`--from-keys: ${path} is not valid JSON: ${(err as Error).message}`);\n\t}\n\tif (!parsed.identitySecretKeyB64 || !parsed.settlementSecretKeyB64) {\n\t\tthrow new Error('--from-keys: file must define identitySecretKeyB64 + settlementSecretKeyB64');\n\t}\n\tconst identitySecret = new Uint8Array(Buffer.from(parsed.identitySecretKeyB64, 'base64'));\n\tconst settlementSecret = new Uint8Array(Buffer.from(parsed.settlementSecretKeyB64, 'base64'));\n\tif (identitySecret.length !== 32) throw new Error('--from-keys: identitySecretKeyB64 is not a 32-byte Ed25519 seed');\n\tif (settlementSecret.length !== 32) throw new Error('--from-keys: settlementSecretKeyB64 is not a 32-byte Ed25519 seed');\n\treturn {\n\t\tidentityPublicKey: getPublicKey(identitySecret),\n\t\tidentitySecretKey: identitySecret,\n\t\tsettlementPublicKey: getPublicKey(settlementSecret),\n\t\tsettlementSecretKey: settlementSecret,\n\t};\n}\n\n/**\n * Decode base64url-no-pad bytes. The challenge endpoint emits exactly\n * this format (per arp-server), so we don't try to be tolerant of\n * standard base64 — a mismatch usually points to a server-side\n * deviation we'd rather surface than paper over.\n */\nfunction base64UrlNoPadDecode(s: string): Uint8Array {\n\t// Convert base64url to standard base64 by reversing alphabet + padding.\n\tconst replaced = s.replace(/-/g, '+').replace(/_/g, '/');\n\tconst padded = replaced + '=='.slice(0, (4 - (replaced.length % 4)) % 4);\n\treturn new Uint8Array(Buffer.from(padded, 'base64'));\n}\n\n/**\n * Parse `--publication <state>` into the accepted enum. Loud error\n * on unknown values so a typo (e.g. `--publication public` or\n * `--publication on`) doesn't silently degrade to a default.\n *\n * Exported for unit tests.\n */\n/**\n * `--json` REQUIRES `--yes`. With `--yes` omitted the CLI may\n * issue interactive prompts to fill missing fields — those prompts\n * go to stdout and would corrupt the single-doc JSON output.\n * Reject early at the start of `runRegister` with a directive\n * error so the operator sees the constraint instead of an\n * unrelated parse failure downstream.\n *\n * Exported for unit-test coverage.\n */\nexport function assertJsonRequiresYes(opts: { json?: boolean; yes?: boolean }): void {\n\tif (opts.json && !opts.yes) {\n\t\tthrow new Error('register --json REQUIRES --yes (interactive prompts would corrupt the single-doc JSON output)');\n\t}\n}\n\nexport function parsePublicationMode(raw: string): 'active' | 'draft' {\n\tif (raw === 'active' || raw === 'draft') return raw;\n\tthrow new Error(`register: --publication must be 'active' or 'draft' (got '${raw}')`);\n}\n\n/**\n * Decide what to do after register completes — try the catalog-\n * publish call, skip because the agent has no endpoint URL (server\n * would 422 with AGENT_MISSING_ENDPOINT), or skip because the\n * operator picked `--publication draft`.\n *\n * Pre-empting the endpoint-less buyer case gives the operator a\n * calm, directive message instead of a scary `⚠ Auto-publish failed\n * (AGENT_MISSING_ENDPOINT)` warning for an intentionally absent\n * endpoint.\n *\n * Returns:\n * - `'try'` — operator wants active publication AND has an\n * endpoint URL the server can index.\n * - `'skip-no-endpoint'` — operator wants active publication\n * but didn't supply an endpoint URL. Common case for\n * buyer-only agents; we explain calmly rather than warn.\n * - `'skip-draft'` — operator explicitly opted out via\n * `--publication draft`. We point them at `heyarp publish`.\n *\n * Exported for unit tests.\n */\nexport function decideAutoPublish(input: {\n\tpublication: 'active' | 'draft';\n\tdefaultEndpointUrl?: string;\n}): 'try' | 'skip-no-endpoint' | 'skip-draft' {\n\tif (input.publication !== 'active') return 'skip-draft';\n\tif (!input.defaultEndpointUrl) return 'skip-no-endpoint';\n\treturn 'try';\n}\n\n/**\n * Build a `Signer` for an in-flight registration. Used post-register\n * to fire the auto-publish call — we already have the secret key +\n * new DID in memory, no need to round-trip through the filesystem\n * state loader.\n */\nfunction makeSignerFromSecret(identitySecretKey: Uint8Array, did: string): import('../api').Signer {\n\treturn { did, identitySecretKey };\n}\n","import chalk from 'chalk';\nimport type { Command } from 'commander';\nimport { ArpApiClient, type ListRelationshipsQuery, type RelationshipPublic } from '../api';\nimport { formatJson } from '../format';\nimport { loadAgentOrThrow, resolveSenderAgent } from '../state';\nimport { makeSigner } from './lifecycle';\n\ninterface RelationshipsOptions {\n\tserver?: string;\n\tstate?: string;\n\tlimit?: string;\n\tverbose?: boolean;\n\tfromDid?: string;\n}\n\nconst ALLOWED_STATES = new Set(['pending', 'active', 'paused', 'closed']);\n\n/**\n * `heyarp relationships <did>` — list pairs the agent participates in,\n * via signed `GET /v1/agents/:did/relationships`. Owner-only on the\n * server (signer DID must match path DID); ordered by `lastEventAt`\n * desc.\n */\nexport function registerRelationshipsCommand(root: Command): void {\n\troot.command('relationships')\n\t\t.description(\n\t\t\t'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).',\n\t\t)\n\t\t.argument('[did]', 'Agent DID (did:arp:...) — must have local state. Optional when --from-did is given OR exactly one agent is registered for the resolved server.')\n\t\t.option('--server <url>', 'Override ARP server base URL')\n\t\t.option('--state <s>', 'Filter by relationship state (pending|active|paused|closed)')\n\t\t.option('--limit <n>', 'Max relationships to return (1..100)', '20')\n\t\t.option('--verbose', 'Print the full JSON for each relationship in addition to the table', false)\n\t\t.option('--from-did <did>', 'Alias for the positional <did> argument — accepted for consistency with other signed commands. Must match the positional if both are given.')\n\t\t.action(async (did: string | undefined, opts: RelationshipsOptions) => {\n\t\t\tawait runRelationships(did, opts);\n\t\t});\n}\n\nasync function runRelationships(positionalDid: string | undefined, opts: RelationshipsOptions): Promise<void> {\n\tconst limit = parseLimit(opts.limit);\n\tconst state = parseState(opts.state);\n\t// Resolve which agent we operate as. Three accepted shapes:\n\t// 1. `relationships <did>` — positional only\n\t// 2. `relationships --from-did <did>` — flag only, accepted\n\t// for symmetry with every other signed command\n\t// 3. `relationships` — neither, fall through\n\t// to resolveSenderAgent's sole-local-agent picker (or its\n\t// strict-mode error when ambiguous)\n\t// If both positional + flag are given, they must match — silent\n\t// disagreement would hide a real bug.\n\tif (positionalDid !== undefined && opts.fromDid !== undefined && positionalDid !== opts.fromDid) {\n\t\tthrow new Error(`relationships: positional <did> (${positionalDid}) and --from-did (${opts.fromDid}) disagree — pass only one`);\n\t}\n\tconst explicitDid = positionalDid ?? opts.fromDid;\n\tconst local = explicitDid !== undefined ? loadAgentOrThrow(opts.server, explicitDid) : resolveSenderAgent('relationships', opts.server, undefined);\n\tconst did = local.did;\n\tconst api = new ArpApiClient(opts.server);\n\tconsole.log(chalk.dim(`Server: ${api.serverUrl}`));\n\tconsole.log(chalk.dim(`Signer: ${local.did}`));\n\n\tconst query: ListRelationshipsQuery = { limit };\n\tif (state) query.state = state;\n\n\tconst signer = makeSigner(local);\n\tconst rows = await api.listRelationships(did, signer, query);\n\n\tif (rows.length === 0) {\n\t\tconsole.log(chalk.dim('\\n(no relationships)'));\n\t\treturn;\n\t}\n\n\tconsole.log('');\n\tconsole.log(formatRelationshipsTable(rows, did));\n\n\tif (opts.verbose) {\n\t\tconsole.log(chalk.bold('\\nFull relationships:'));\n\t\tfor (const r of rows) {\n\t\t\tconsole.log(formatJson(r));\n\t\t}\n\t}\n\n\tconsole.log(chalk.dim(`\\n${rows.length} relationship(s).`));\n}\n\n/**\n * Render relationships as a 5-column table. \"Pair (other)\" shows\n * whichever of `pairDidA` / `pairDidB` is NOT the caller's DID — the\n * caller already knows themselves, so showing the counterpart is more\n * useful at a glance.\n */\nfunction formatRelationshipsTable(rows: RelationshipPublic[], selfDid: string): string {\n\tconst header = ['Relationship ID', 'Pair (other)', 'State', 'Last Event', 'Last Index'];\n\tconst data = rows.map((r) => [r.relationshipId, otherPair(r, selfDid), r.state, r.lastEventAt ?? '(none)', String(r.lastEventIndex)]);\n\tconst widths = header.map((h, i) => Math.max(h.length, ...data.map((row) => row[i].length)));\n\tconst pad = (cells: string[]): string => cells.map((c, i) => c.padEnd(widths[i])).join(' ');\n\treturn [chalk.bold(pad(header)), chalk.dim(pad(widths.map((w) => '-'.repeat(w)))), ...data.map((row) => pad(row))].join('\\n');\n}\n\n/**\n * Server stores pairs in lexicographic order (A < B); the caller's DID\n * is one of the two — return the other so the operator can read the\n * row without comparing against their own DID every time.\n */\nfunction otherPair(r: RelationshipPublic, selfDid: string): string {\n\tif (r.pairDidA === selfDid) return r.pairDidB;\n\tif (r.pairDidB === selfDid) return r.pairDidA;\n\t// Defensive: server should never return a relationship the caller\n\t// isn't part of, but if it does, surface both sides honestly.\n\treturn `${r.pairDidA} ↔ ${r.pairDidB}`;\n}\n\nfunction parseState(raw: string | undefined): RelationshipPublic['state'] | undefined {\n\tif (raw === undefined) return undefined;\n\tif (!ALLOWED_STATES.has(raw)) {\n\t\tthrow new Error(`relationships: --state must be one of pending|active|paused|closed (got '${raw}')`);\n\t}\n\treturn raw as RelationshipPublic['state'];\n}\n\nfunction parseLimit(raw: string | undefined): number {\n\tif (raw === undefined) return 20;\n\tconst n = Number(raw);\n\tif (!Number.isFinite(n) || !Number.isInteger(n) || n < 1 || n > 100) {\n\t\tthrow new Error(`relationships: --limit must be an integer between 1 and 100 (got '${raw}')`);\n\t}\n\treturn n;\n}\n","import { type KeyRotationPayload, base58btcEncode, generateKeyPair, rfc3339, senderNonce, signChallenge, signKeyRotationAttestation } from '@heyanon-arp/sdk';\nimport chalk from 'chalk';\nimport type { Command } from 'commander';\nimport prompts from 'prompts';\nimport { ArpApiClient, type RotateIdentityKeyBody } from '../api';\nimport { formatJson } from '../format';\nimport { loadAgentOrThrow, updateAgentLocal } from '../state';\nimport { makeSigner } from './lifecycle';\n\n/**\n * Rotation reasons accepted by the SDK / protocol per\n * `00-core/identity.md`. Keep this list in sync with\n * `KeyRotationPayload.rotation_reason` in `@heyanon-arp/sdk` — adding\n * a value here without bumping the SDK type produces non-conformant\n * attestations the server will accept (we don't validate the field\n * server-side) but other implementations may reject.\n */\n// exported for tests\nexport const ROTATION_REASONS = ['scheduled', 'compromise', 'lost_device', 'other'] as const;\ntype RotationReason = (typeof ROTATION_REASONS)[number];\n\ninterface RotateOptions {\n\tserver?: string;\n\tyes?: boolean;\n\treason?: RotationReason;\n}\n\n/**\n * `heyarp rotate <did>` — full identity-key rotation flow.\n *\n * 1. Confirm intent (rotation invalidates the OLD private key).\n * 2. Generate fresh identity keypair.\n * 3. Issue a `purpose: 'rotate'` challenge; sign it with the\n * NEW key → /agents/challenge-response. Proves we hold the\n * new private key.\n * 4. Build an `ARP-KEY-ROTATION-v1` attestation HMAC'd with the\n * stored scrypt key (owner password is unchanged), reusing the\n * original `scrypt_salt_id` and `owner_id` so the chain stays\n * stable.\n * 5. POST /agents/:did/rotate-identity-key — request itself signed\n * by the CURRENT identity key (server's SignedRequestGuard\n * asserts that).\n * 6. Update local state in-place (DID stays frozen; identity keys\n * and `currentAttestationId` move).\n *\n * On any failure before step 6 the local state is untouched — old\n * key still works. After step 6 succeeds the old key is dead;\n * arp-server will reject envelopes signed with it once the V1.5\n * blacklist lands.\n */\nexport function registerRotateCommand(root: Command): void {\n\troot.command('rotate')\n\t\t.description('Rotate the agent identity key (DID stays frozen). Requires local state with ownerId + currentAttestationId.')\n\t\t.argument('<did>')\n\t\t.option('--server <url>', 'Override ARP server base URL')\n\t\t.option('--yes', 'Skip the destructive-action confirmation prompt', false)\n\t\t.option('--reason <s>', `Rotation reason — one of ${ROTATION_REASONS.join(' | ')}`, 'scheduled')\n\t\t.action(async (did: string, opts: RotateOptions) => {\n\t\t\tif (opts.reason && !ROTATION_REASONS.includes(opts.reason)) {\n\t\t\t\tthrow new Error(`rotate: --reason must be one of ${ROTATION_REASONS.join(', ')} (got '${opts.reason}')`);\n\t\t\t}\n\t\t\tawait runRotate(did, opts);\n\t\t});\n}\n\nasync function runRotate(did: string, opts: RotateOptions): Promise<void> {\n\tconst local = loadAgentOrThrow(opts.server, did);\n\n\t// Pre-flight: rotation needs metadata that may not exist on\n\t// state files written before V1.1. Surface a clean message so\n\t// the user knows to re-register, not chase a cryptic mismatch.\n\tif (!local.ownerId || !local.currentAttestationId) {\n\t\tthrow new Error('rotate: local state is missing ownerId / currentAttestationId. State predates the rotation flow — please re-register.');\n\t}\n\n\tconst api = new ArpApiClient(opts.server);\n\tconsole.log(chalk.dim(`Server: ${api.serverUrl}`));\n\tconsole.log(chalk.dim(`Rotating: ${local.did}`));\n\n\tif (!opts.yes) {\n\t\tconst confirm = await prompts({\n\t\t\ttype: 'confirm',\n\t\t\tname: 'go',\n\t\t\tmessage: 'Rotation invalidates the CURRENT private key the moment the server commits. Continue?',\n\t\t\tinitial: false,\n\t\t});\n\t\tif (!confirm.go) {\n\t\t\tconsole.log(chalk.yellow('Aborted.'));\n\t\t\treturn;\n\t\t}\n\t}\n\n\t// Step 2 — fresh keypair\n\tconst next = generateKeyPair();\n\tconst newIdentityPublicKeyB58 = base58btcEncode(next.publicKey);\n\n\t// Step 3 — new-key challenge round\n\tconst challenge = await api.issueChallenge('rotate');\n\tconst challengeBytes = base64UrlNoPadDecode(challenge.challengeB64);\n\tif (challengeBytes.length !== 32) {\n\t\tthrow new Error(`Server returned a ${challengeBytes.length}-byte challenge; expected 32`);\n\t}\n\tconst challengeSig = signChallenge(challengeBytes, next.secretKey);\n\tawait api.submitChallengeResponse({\n\t\tchallengeId: challenge.challengeId,\n\t\tidentityPublicKey: newIdentityPublicKeyB58,\n\t\tsignature: Buffer.from(challengeSig).toString('base64'),\n\t});\n\n\t// Step 4 — KEY-ROTATION-v1 payload + attestation\n\tconst scryptKey = new Uint8Array(Buffer.from(local.scryptKeyB64, 'base64'));\n\tif (scryptKey.length !== 32) {\n\t\tthrow new Error('rotate: stored scryptKeyB64 is not 32 bytes — local state is corrupted, re-register.');\n\t}\n\tconst reason: RotationReason = opts.reason ?? 'scheduled';\n\tconst payload: KeyRotationPayload = {\n\t\tpurpose: 'ARP-KEY-ROTATION-v1',\n\t\tagent_did: did,\n\t\tcurrent_identity_public_key: local.identityPublicKeyB58,\n\t\tnew_identity_public_key: newIdentityPublicKeyB58,\n\t\tsettlement_public_key: local.settlementPublicKeyB58,\n\t\tsupersedes_attestation_id: local.currentAttestationId,\n\t\towner_id: local.ownerId,\n\t\towner_signing_method: 'scrypt_password_proof',\n\t\trotation_reason: reason,\n\t\tcreated_at: rfc3339(),\n\t\tnonce: senderNonce(),\n\t};\n\tconst attestation = signKeyRotationAttestation({\n\t\tpayload,\n\t\tscryptKey,\n\t\tscryptSaltId: local.scryptSaltId,\n\t});\n\n\t// Step 5a — write the recovery breadcrumb BEFORE the server call.\n\t// If the post-commit local write fails (step 6), this row is\n\t// what tells the operator the new keypair was already activated.\n\tconst newIdentitySecretKeyB64 = Buffer.from(next.secretKey).toString('base64');\n\tupdateAgentLocal(opts.server, did, {\n\t\tpendingRotation: {\n\t\t\tnewIdentityPublicKeyB58,\n\t\t\tnewIdentitySecretKeyB64,\n\t\t\tissuedAt: new Date().toISOString(),\n\t\t},\n\t});\n\n\t// Step 5b — signed POST /rotate-identity-key. Signer is the\n\t// CURRENT identity (about to be retired); server verifies it\n\t// against the agent's stored identityPublicKey before accepting.\n\tconst body: RotateIdentityKeyBody = {\n\t\tchallengeId: challenge.challengeId,\n\t\tnewIdentityPublicKey: newIdentityPublicKeyB58,\n\t\tnewKeyAttestation: {\n\t\t\tpayload: attestation.payload as unknown as Record<string, unknown>,\n\t\t\tsig: attestation.sig,\n\t\t\tscrypt_salt_id: attestation.scrypt_salt_id,\n\t\t},\n\t};\n\tconst signer = makeSigner(local);\n\tlet updated;\n\ttry {\n\t\tupdated = await api.rotateIdentityKey(did, body, signer);\n\t} catch (err) {\n\t\t// Server did NOT commit. Clear the breadcrumb so the next\n\t\t// rotation attempt starts clean.\n\t\ttry {\n\t\t\tupdateAgentLocal(opts.server, did, { pendingRotation: undefined });\n\t\t} catch {\n\t\t\t// Best-effort — leaking a breadcrumb is fine, surfacing the\n\t\t\t// original API error matters more.\n\t\t}\n\t\tthrow err;\n\t}\n\n\t// Step 6 — flip local state. If THIS write fails, the breadcrumb\n\t// from 5a still has the new secret key, and we print it to stderr\n\t// so the operator has a copy in shell scrollback.\n\ttry {\n\t\tupdateAgentLocal(opts.server, did, {\n\t\t\tidentityPublicKeyB58: newIdentityPublicKeyB58,\n\t\t\tidentitySecretKeyB64: newIdentitySecretKeyB64,\n\t\t\tcurrentAttestationId: updated.currentAttestationId,\n\t\t\tpendingRotation: undefined,\n\t\t});\n\t} catch (err) {\n\t\tconsole.error(chalk.red('\\nServer rotation succeeded but local state write failed.'));\n\t\tconsole.error(chalk.red('Capture these values now — the new key is already live server-side:'));\n\t\tconsole.error(` ${chalk.bold('identityPublicKeyB58')} : ${newIdentityPublicKeyB58}`);\n\t\tconsole.error(` ${chalk.bold('identitySecretKeyB64')} : ${newIdentitySecretKeyB64}`);\n\t\tconsole.error(` ${chalk.bold('currentAttestationId')} : ${updated.currentAttestationId}`);\n\t\tconsole.error(chalk.dim(`(Also persisted in pendingRotation at ~/.arp/agents.json before the server call.)`));\n\t\tconsole.error(chalk.dim(`Underlying error: ${(err as Error).message}`));\n\t\tthrow err;\n\t}\n\n\tconsole.log(chalk.green('\\nRotated.'));\n\tconsole.log(`${chalk.bold('DID')}: ${chalk.cyan(updated.did)} ${chalk.dim('(unchanged)')}`);\n\tconsole.log(`${chalk.bold('New identity public key')}: ${chalk.cyan(newIdentityPublicKeyB58)}`);\n\tconsole.log(`${chalk.bold('New attestation id')}: ${chalk.cyan(updated.currentAttestationId)}`);\n\tconsole.log(chalk.bold('\\nAgent profile:'));\n\tconsole.log(formatJson(updated));\n\tconsole.log(chalk.dim('\\nLocal state updated; old private key is no longer valid.'));\n}\n\n/**\n * Decode base64url-no-pad bytes — same shape `heyarp register` accepts\n * from the server's challenge endpoint. Duplicated here to keep\n * commands self-contained; once a third caller appears we'll lift\n * it into a shared util.\n */\nfunction base64UrlNoPadDecode(s: string): Uint8Array {\n\tconst replaced = s.replace(/-/g, '+').replace(/_/g, '/');\n\tconst padded = replaced + '=='.slice(0, (4 - (replaced.length % 4)) % 4);\n\treturn new Uint8Array(Buffer.from(padded, 'base64'));\n}\n","import { type Did, type HandshakeBody, type HandshakeContent, Purpose, type SignableProtected, expiresAt, rfc3339, senderNonce, signEnvelope, uuidV4 } from '@heyanon-arp/sdk';\nimport chalk from 'chalk';\nimport type { Command } from 'commander';\nimport { ArpApiClient, type IngestResult } from '../api';\nimport { formatJson } from '../format';\nimport { type AgentLocalState, resolveSenderAgent, updateAgentLocal } from '../state';\nimport { makeSigner } from './lifecycle';\n\ninterface SendHandshakeOptions {\n\tserver?: string;\n\tfromDid?: string;\n\tgreeting?: string;\n\tintent?: string;\n\tttl?: string; // commander surfaces option args as strings; we coerce below\n\tverbose?: boolean;\n}\n\n/**\n * `heyarp send-handshake <recipient-did>` — first end-to-end envelope flow.\n *\n * 1. Resolve sender (explicit `--from-did`, or the only agent registered\n * against the configured server).\n * 2. Build a `handshake` body — `greeting` / `intent` are optional;\n * omitted fields are dropped from `content` so the validator sees a\n * clean shape.\n * 3. Allocate `sender_sequence = (lastSenderSequence ?? 0) + 1` from\n * local state.\n * 4. Build a `ProtectedBlock` (without `body_hash` / `attachments_hash`\n * — the SDK injects those) with `relationship_id: null` (server\n * mints the relationship row on first contact).\n * 5. `signEnvelope` → POST /v1/messages.\n * 6. On success, persist the new `lastSenderSequence`. Failure leaves\n * state unchanged so the same sequence can be retried safely.\n *\n * The body type is restricted to `handshake` because that's the only\n * variant the V1 first slice of `EnvelopeValidatorService` accepts —\n * other types (`handshake_response`, `contract`, …) are deferred to\n * subsequent slices.\n */\nexport function registerSendHandshakeCommand(root: Command): void {\n\troot.command('send-handshake')\n\t\t.description('Send a handshake envelope to <recipient-did>. Server creates the relationship row on first contact.')\n\t\t.argument('<recipient-did>', 'Recipient agent DID (did:arp:...)')\n\t\t.option('--server <url>', 'Override ARP server base URL')\n\t\t.option('--from-did <did>', 'Sender DID — required only if multiple agents are registered against this server')\n\t\t.option('--greeting <s>', 'Optional greeting text included in body.content')\n\t\t.option('--intent <s>', 'Optional intent text included in body.content')\n\t\t.option('--ttl <seconds>', 'Envelope TTL in seconds (max 86400 = 24h)', '3600')\n\t\t.option('--verbose', 'Print the full envelope before sending and the full server response', false)\n\t\t.action(async (recipientDid: string, opts: SendHandshakeOptions) => {\n\t\t\tawait runSendHandshake(recipientDid, opts);\n\t\t});\n}\n\nasync function runSendHandshake(recipientDid: string, opts: SendHandshakeOptions): Promise<void> {\n\tif (!isDid(recipientDid)) {\n\t\tthrow new Error(`send-handshake: <recipient-did> must look like 'did:arp:...' (got '${recipientDid}')`);\n\t}\n\n\tconst ttlSeconds = parseTtl(opts.ttl);\n\tconst api = new ArpApiClient(opts.server);\n\tconsole.log(chalk.dim(`Server: ${api.serverUrl}`));\n\n\t// Step 1 — resolve sender from local state.\n\tconst sender = resolveSenderAgent('send-handshake', opts.server, opts.fromDid);\n\tconsole.log(chalk.dim(`Sender: ${sender.did}`));\n\tconsole.log(chalk.dim(`Recipient: ${recipientDid}`));\n\n\t// Step 2 — body. Trim out empty optional fields so the validator\n\t// doesn't see `{ greeting: undefined }` after JSON round-trip.\n\tconst content: HandshakeContent = {};\n\tif (opts.greeting) content.greeting = opts.greeting;\n\tif (opts.intent) content.intent = opts.intent;\n\tconst body: HandshakeBody = { type: 'handshake', content };\n\n\t// Step 3 — next sender_sequence. Default-init from 0 for state files\n\t// written before this field was added; first envelope is therefore 1.\n\tconst nextSequence = (sender.lastSenderSequence ?? 0) + 1;\n\n\t// Step 4 — protected block. SDK signEnvelope injects body_hash /\n\t// attachments_hash; we deliberately omit them here so the typed\n\t// input matches `SignableProtected`.\n\tconst protectedBlock: SignableProtected = {\n\t\tprotocol_version: 'arp/0.1',\n\t\tpurpose: Purpose.ENVELOPE,\n\t\tmessage_id: uuidV4(),\n\t\tsender_did: sender.did as Did,\n\t\trecipient_did: recipientDid as Did,\n\t\trelationship_id: null,\n\t\tsender_sequence: nextSequence,\n\t\tsender_nonce: senderNonce(),\n\t\ttimestamp: rfc3339(),\n\t\texpires_at: expiresAt(ttlSeconds),\n\t\tdelivery_id: null,\n\t};\n\n\tconst signer = makeSigner(sender);\n\tconst envelope = signEnvelope<HandshakeBody>({\n\t\tprotected: protectedBlock,\n\t\tbody,\n\t\tidentitySecretKey: signer.identitySecretKey,\n\t});\n\n\tif (opts.verbose) {\n\t\tconsole.log(chalk.bold('\\nEnvelope (pre-send):'));\n\t\tconsole.log(formatJson(envelope));\n\t}\n\n\t// Step 5 — POST /v1/messages. On any server-side failure (validation,\n\t// replay, signature) ApiError bubbles up and we leave state alone.\n\tconst result: IngestResult = await api.ingest(envelope);\n\n\t// Step 6 — only now persist the new sequence; this means a network\n\t// failure or a server reject leaves `lastSenderSequence` untouched\n\t// and the operator can retry with the same number.\n\tupdateAgentLocal(opts.server, sender.did, { lastSenderSequence: nextSequence });\n\n\tconsole.log(chalk.green('\\nDelivered.'));\n\tconsole.log(`${chalk.bold('Event id')}: ${chalk.cyan(result.eventId)}`);\n\tconsole.log(`${chalk.bold('Relationship id')}: ${chalk.cyan(result.relationshipId)}`);\n\tconsole.log(`${chalk.bold('Chain index')}: ${chalk.cyan(String(result.relationshipEventIndex))}`);\n\tconsole.log(`${chalk.bold('Server timestamp')}: ${chalk.cyan(result.serverTimestamp)}`);\n\tconsole.log(`${chalk.bold('Signed message hash')}: ${chalk.cyan(result.signedMessageHash)}`);\n\tconsole.log(`${chalk.bold('Server event hash')}: ${chalk.cyan(result.serverEventHash)}`);\n\tif (result.prevServerEventHash) {\n\t\tconsole.log(`${chalk.bold('Prev server event hash')}: ${chalk.cyan(result.prevServerEventHash)}`);\n\t} else {\n\t\tconsole.log(`${chalk.bold('Prev server event hash')}: ${chalk.dim('(null — first event of this relationship)')}`);\n\t}\n\n\tif (opts.verbose) {\n\t\tconsole.log(chalk.bold('\\nFull server response:'));\n\t\tconsole.log(formatJson(result));\n\t}\n\n\tconsole.log(chalk.dim(`\\nLocal sender_sequence advanced to ${nextSequence}.`));\n}\n\n/**\n * Parse `--ttl` into a positive integer seconds value. Commander's\n * default value is the string `'3600'`, so this also handles the\n * \"user didn't pass a flag\" path.\n */\nfunction parseTtl(raw: string | undefined): number {\n\tif (raw === undefined) return 3600;\n\tconst n = Number(raw);\n\tif (!Number.isFinite(n) || !Number.isInteger(n) || n <= 0) {\n\t\tthrow new Error(`send-handshake: --ttl must be a positive integer number of seconds (got '${raw}')`);\n\t}\n\treturn n;\n}\n\nfunction isDid(s: string): boolean {\n\treturn typeof s === 'string' && s.startsWith('did:arp:') && s.length > 'did:arp:'.length;\n}\n","import {\n\tDECLINE_REASONS,\n\ttype Did,\n\ttype HandshakeResponseBody,\n\ttype HandshakeResponseContent,\n\tPurpose,\n\ttype SignableProtected,\n\texpiresAt,\n\trfc3339,\n\tsenderNonce,\n\tsignEnvelope,\n\tuuidV4,\n} from '@heyanon-arp/sdk';\nimport chalk from 'chalk';\nimport type { Command } from 'commander';\nimport { ArpApiClient, type IngestResult, type RelationshipPublic, type Signer } from '../api';\nimport { formatJson } from '../format';\nimport { type AgentLocalState, resolveSenderAgent, updateAgentLocal } from '../state';\nimport { parseDeclineReason, parseReasonDetail } from './delegation';\nimport { makeSigner } from './lifecycle';\n\ninterface SendHandshakeResponseOptions {\n\tserver?: string;\n\tfromDid?: string;\n\tdecision?: string;\n\tnotes?: string;\n\tttl?: string;\n\tverbose?: boolean;\n\t/** Required when --decision=decline. See `DeclineReason`. */\n\treason?: string;\n\t/** Optional free-text elaboration alongside `--reason`. */\n\treasonDetail?: string;\n\t/**\n\t * Bypass the pre-send idempotency probe. Default behaviour\n\t * short-circuits when the relationship is already `active` (the\n\t * response previously landed; re-sending would burn a\n\t * sender_sequence on a DOM_INVALID_TRANSITION reject). Operators\n\t * who really do want to re-fire the envelope (e.g. testing FSM\n\t * guards) can pass --force to skip the probe.\n\t */\n\tforce?: boolean;\n}\n\nconst ALLOWED_DECISIONS = new Set(['accept', 'decline']);\n\n/**\n * `heyarp send-handshake-response <recipient-did>` — accept / decline an\n * inbound handshake. Mirrors `send-handshake` end-to-end:\n *\n * 1. Resolve sender (explicit `--from-did`, or the only agent\n * registered against the configured server).\n * 2. Build a `handshake_response` body — `decision` is required,\n * `notes` is optional.\n * 3. Allocate `sender_sequence = (lastSenderSequence ?? 0) + 1` from\n * local state.\n * 4. Build a `ProtectedBlock` (without `body_hash` /\n * `attachments_hash`) with `relationship_id: null` — the server\n * reuses the existing relationship row created by the prior\n * `handshake`, so no new pair is minted here.\n * 5. `signEnvelope` → POST /v1/messages.\n * 6. On success, persist the new `lastSenderSequence`. Failure\n * leaves state unchanged so the same sequence can be retried.\n *\n * `--decision` is validated locally first so we don't burn a server\n * round-trip on an obvious typo. The server's envelope validator\n * also enforces `decision ∈ {accept, decline}`, but matching it\n * client-side keeps the failure message readable.\n */\nexport function registerSendHandshakeResponseCommand(root: Command): void {\n\troot.command('send-handshake-response')\n\t\t.description('Accept or decline an inbound handshake from <recipient-did>. Server reuses the existing relationship row.')\n\t\t.argument('<recipient-did>', 'Recipient agent DID (did:arp:...) — the original handshake sender')\n\t\t.option('--server <url>', 'Override ARP server base URL')\n\t\t.option('--from-did <did>', 'Sender DID — required only if multiple agents are registered against this server')\n\t\t.option('--decision <s>', 'REQUIRED: accept or decline')\n\t\t.option('--notes <s>', 'Optional notes included in body.content')\n\t\t.option(\n\t\t\t'--reason <code>',\n\t\t\t// REQUIRED when --decision=decline. Optional otherwise.\n\t\t\t// We don't use commander's requiredOption because it\n\t\t\t// would fire for the accept path too; validate manually\n\t\t\t// after decision is parsed.\n\t\t\t`When --decision=decline: required reason code (one of: ${DECLINE_REASONS.join(', ')}). Carried in body.content.reason.`,\n\t\t)\n\t\t.option('--reason-detail <s>', 'Optional free-text elaboration alongside --reason (max 512 chars).')\n\t\t.option('--ttl <seconds>', 'Envelope TTL in seconds (max 86400 = 24h)', '3600')\n\t\t.option('--verbose', 'Print the full envelope before sending and the full server response', false)\n\t\t// Idempotency probe override.\n\t\t.option(\n\t\t\t'--force',\n\t\t\t\"Skip the pre-send relationship-state probe. Default: when the relationship with <recipient-did> is already 'active', the command short-circuits successfully (the previous response already landed). Pass --force to re-send anyway — the server still gates with DOM_INVALID_TRANSITION, so this is mostly useful for FSM-guard tests.\",\n\t\t\tfalse,\n\t\t)\n\t\t.action(async (recipientDid: string, opts: SendHandshakeResponseOptions) => {\n\t\t\tawait runSendHandshakeResponse(recipientDid, opts);\n\t\t});\n}\n\nasync function runSendHandshakeResponse(recipientDid: string, opts: SendHandshakeResponseOptions): Promise<void> {\n\tif (!isDid(recipientDid)) {\n\t\tthrow new Error(`send-handshake-response: <recipient-did> must look like 'did:arp:...' (got '${recipientDid}')`);\n\t}\n\n\tconst decision = parseDecision(opts.decision);\n\tconst ttlSeconds = parseTtl(opts.ttl);\n\n\t// Validate `--reason` (+ `--reason-detail`) right after\n\t// `--decision` and BEFORE any state lookup / API round-trip, so\n\t// bad input fails with a clean parse error rather than midway\n\t// through. Same rationale as the contract / delegation decline\n\t// sites.\n\tlet declinePayload: { reason: HandshakeResponseContent['reason']; reasonDetail?: string } | null = null;\n\tif (decision === 'decline') {\n\t\tconst reason = parseDeclineReason('send-handshake-response', opts.reason);\n\t\tconst detail = parseReasonDetail('send-handshake-response', opts.reasonDetail);\n\t\tdeclinePayload = detail ? { reason, reasonDetail: detail } : { reason };\n\t}\n\n\tconst api = new ArpApiClient(opts.server);\n\tconsole.log(chalk.dim(`Server: ${api.serverUrl}`));\n\n\t// Step 1 — resolve sender from local state.\n\tconst sender = resolveSenderAgent('send-handshake-response', opts.server, opts.fromDid);\n\tconsole.log(chalk.dim(`Sender: ${sender.did}`));\n\tconsole.log(chalk.dim(`Recipient: ${recipientDid}`));\n\tconsole.log(chalk.dim(`Decision: ${decision}`));\n\n\t// Step 1.5 — idempotency probe.\n\t//\n\t// Workers without a cursor-aware listen loop sometimes fire\n\t// `handshake_response` twice; the second fires against an\n\t// already-active relationship and hits DOM_INVALID_TRANSITION.\n\t// The server's FSM guard prevents corruption, but the worker LLM\n\t// logs the error and can continue in a partial state.\n\t//\n\t// Defense-in-depth: probe the relationship state BEFORE building\n\t// the envelope. If the pair is already `active`, the response\n\t// previously landed — short-circuit successfully with a clear\n\t// \"(already responded)\" banner instead of re-firing.\n\t//\n\t// Probe is best-effort: a sender with >100 relationships might\n\t// page off the relationship; the server is still the source of\n\t// truth either way. `--force` bypasses entirely for operators\n\t// running FSM-guard tests.\n\tconst signer = makeSigner(sender);\n\tif (!opts.force) {\n\t\ttry {\n\t\t\tconst existing = await findExistingRelationship(api, signer, sender.did, recipientDid);\n\t\t\tconst initialOutcome = classifyIdempotencyOutcome(decision, existing);\n\t\t\tif (initialOutcome.kind === 'error') {\n\t\t\t\tthrow new Error(initialOutcome.message);\n\t\t\t}\n\t\t\tif (initialOutcome.kind === 'short-circuit' && existing) {\n\t\t\t\t// state === 'active' alone doesn't prove THIS signer\n\t\t\t\t// was the responder. The pair could have gone active\n\t\t\t\t// via THIS signer's accept (legit idempotent retry\n\t\t\t\t// — short-circuit) OR via the PEER's accept of this\n\t\t\t\t// signer's outbound handshake (illegitimate \"respond\n\t\t\t\t// to your own handshake\" — server would reject).\n\t\t\t\t// Disambiguate by walking the relationship event log\n\t\t\t\t// for a handshake_response sent by this signer. If\n\t\t\t\t// found, short-circuit confidently. If absent, fall\n\t\t\t\t// through to the network send so the server gets to\n\t\t\t\t// issue its real verdict instead of us silently\n\t\t\t\t// exiting 0.\n\t\t\t\tconst events = await api.listEvents(existing.relationshipId, signer);\n\t\t\t\tconst previousResponseFromMe = events.find((e) => e.senderDid === sender.did && e.type === 'handshake_response');\n\t\t\t\tif (previousResponseFromMe) {\n\t\t\t\t\tconsole.log(chalk.yellow(`\\n[--idempotency] Relationship ${existing.relationshipId} with ${recipientDid} is already 'active'.`));\n\t\t\t\t\tconsole.log(chalk.dim(`A previous accept from this signer (event ${previousResponseFromMe.eventId}) landed successfully. Skipping re-send (use --force to override).`));\n\t\t\t\t\tconsole.log(chalk.dim(`Last event index: ${existing.lastEventIndex}, last server event hash: ${existing.lastServerEventHash ?? '(none)'}`));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t// Active relationship but no prior handshake_response\n\t\t\t\t// from this signer → THIS signer was the initiator.\n\t\t\t\t// Trying to \"accept\" their own handshake is an FSM\n\t\t\t\t// violation. Surface explicitly so the worker LLM sees\n\t\t\t\t// the real cause instead of a misleading no-op.\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`send-handshake-response: relationship ${existing.relationshipId} is already 'active', but no handshake_response from ${sender.did} exists on the event log. ` +\n\t\t\t\t\t\t`This signer is the original initiator of the handshake — initiators cannot respond to their own handshake. ` +\n\t\t\t\t\t\t`Pass --force to send anyway and let the server reject with DOM_INVALID_TRANSITION.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\t// kind === 'proceed' → fall through to envelope build.\n\t\t} catch (probeErr) {\n\t\t\t// Probe failure is non-fatal UNLESS it's our own classifier\n\t\t\t// throwing an intent-mismatch / terminated / wrong-direction\n\t\t\t// error: re-raise those so the operator sees the actual\n\t\t\t// problem. Best-effort network failures still degrade\n\t\t\t// gracefully — the server is the source of truth either way.\n\t\t\tif (probeErr instanceof Error && /CLOSED|terminated|already 'active' from a previous ACCEPT|original initiator/i.test(probeErr.message)) {\n\t\t\t\tthrow probeErr;\n\t\t\t}\n\t\t\tconsole.log(chalk.dim(`(idempotency probe failed; proceeding anyway: ${(probeErr as Error).message})`));\n\t\t}\n\t}\n\n\t// Step 2 — body. Drop empty optional `notes` so the validator sees\n\t// a clean shape after JSON round-trip.\n\tconst content: HandshakeResponseContent = { decision };\n\tif (opts.notes) content.notes = opts.notes;\n\tif (declinePayload) {\n\t\tcontent.reason = declinePayload.reason;\n\t\tif (declinePayload.reasonDetail) content.reason_detail = declinePayload.reasonDetail;\n\t}\n\tconst body: HandshakeResponseBody = { type: 'handshake_response', content };\n\n\t// Step 3 — next sender_sequence. Default-init from 0 for state\n\t// files written before this field was added.\n\tconst nextSequence = (sender.lastSenderSequence ?? 0) + 1;\n\n\t// Step 4 — protected block. SDK signEnvelope injects body_hash /\n\t// attachments_hash, so we omit them here; the typed input matches\n\t// `SignableProtected`. `relationship_id` stays null — the server\n\t// is responsible for matching this envelope back to the existing\n\t// pending relationship.\n\tconst protectedBlock: SignableProtected = {\n\t\tprotocol_version: 'arp/0.1',\n\t\tpurpose: Purpose.ENVELOPE,\n\t\tmessage_id: uuidV4(),\n\t\tsender_did: sender.did as Did,\n\t\trecipient_did: recipientDid as Did,\n\t\trelationship_id: null,\n\t\tsender_sequence: nextSequence,\n\t\tsender_nonce: senderNonce(),\n\t\ttimestamp: rfc3339(),\n\t\texpires_at: expiresAt(ttlSeconds),\n\t\tdelivery_id: null,\n\t};\n\n\t// `signer` was already constructed above for the idempotency probe.\n\tconst envelope = signEnvelope<HandshakeResponseBody>({\n\t\tprotected: protectedBlock,\n\t\tbody,\n\t\tidentitySecretKey: signer.identitySecretKey,\n\t});\n\n\tif (opts.verbose) {\n\t\tconsole.log(chalk.bold('\\nEnvelope (pre-send):'));\n\t\tconsole.log(formatJson(envelope));\n\t}\n\n\t// Step 5 — POST /v1/messages. ApiError bubbles up on any rejection;\n\t// we leave local state unchanged so a retry uses the same sequence.\n\tconst result: IngestResult = await api.ingest(envelope);\n\n\t// Step 6 — persist the new sequence only on confirmed ingest.\n\tupdateAgentLocal(opts.server, sender.did, { lastSenderSequence: nextSequence });\n\n\tconsole.log(chalk.green('\\nDelivered.'));\n\tconsole.log(`${chalk.bold('Event id')}: ${chalk.cyan(result.eventId)}`);\n\tconsole.log(`${chalk.bold('Relationship id')}: ${chalk.cyan(result.relationshipId)}`);\n\tconsole.log(`${chalk.bold('Chain index')}: ${chalk.cyan(String(result.relationshipEventIndex))}`);\n\tconsole.log(`${chalk.bold('Server timestamp')}: ${chalk.cyan(result.serverTimestamp)}`);\n\tconsole.log(`${chalk.bold('Signed message hash')}: ${chalk.cyan(result.signedMessageHash)}`);\n\tconsole.log(`${chalk.bold('Server event hash')}: ${chalk.cyan(result.serverEventHash)}`);\n\tif (result.prevServerEventHash) {\n\t\tconsole.log(`${chalk.bold('Prev server event hash')}: ${chalk.cyan(result.prevServerEventHash)}`);\n\t} else {\n\t\tconsole.log(`${chalk.bold('Prev server event hash')}: ${chalk.dim('(null — first event of this relationship)')}`);\n\t}\n\n\tif (opts.verbose) {\n\t\tconsole.log(chalk.bold('\\nFull server response:'));\n\t\tconsole.log(formatJson(result));\n\t}\n\n\tconsole.log(chalk.dim(`\\nLocal sender_sequence advanced to ${nextSequence}.`));\n}\n\n/**\n * Parse + validate `--decision`. The server's envelope validator\n * enforces the same enum, but matching it client-side gives a cleaner\n * error than letting the server reject the envelope.\n */\nfunction parseDecision(raw: string | undefined): 'accept' | 'decline' {\n\tif (raw === undefined || raw === '') {\n\t\tthrow new Error(\"send-handshake-response: --decision is required (must be 'accept' or 'decline')\");\n\t}\n\tif (!ALLOWED_DECISIONS.has(raw)) {\n\t\tthrow new Error(`send-handshake-response: --decision must be 'accept' or 'decline' (got '${raw}')`);\n\t}\n\treturn raw as 'accept' | 'decline';\n}\n\n/**\n * Parse `--ttl` into a positive integer seconds value. Commander's\n * default value is the string `'3600'`, so this also handles the\n * \"user didn't pass a flag\" path.\n */\nfunction parseTtl(raw: string | undefined): number {\n\tif (raw === undefined) return 3600;\n\tconst n = Number(raw);\n\tif (!Number.isFinite(n) || !Number.isInteger(n) || n <= 0) {\n\t\tthrow new Error(`send-handshake-response: --ttl must be a positive integer number of seconds (got '${raw}')`);\n\t}\n\treturn n;\n}\n\nfunction isDid(s: string): boolean {\n\treturn typeof s === 'string' && s.startsWith('did:arp:') && s.length > 'did:arp:'.length;\n}\n\n/**\n * Outcome of the idempotency probe — a pure mapping from\n * (operator's intent, observed relationship state) to one of three\n * actions:\n * - `short-circuit`: previous response of the SAME kind already\n * landed; exit successfully without re-sending.\n * - `error`: the operator's intent is incompatible with the\n * observed state (e.g. decline-after-accept). The `message`\n * field carries the operator-facing explanation.\n * - `proceed`: probe found nothing relevant (or the state is\n * `pending`/`paused`); build + send the envelope as usual.\n *\n * Classifying by `decision` (not just state) keeps the\n * decline-after-accept case from silently no-op'ing — that\n * mismatch must surface loudly instead of exiting 0.\n *\n * Exported for unit tests.\n */\nexport type IdempotencyOutcome = { kind: 'short-circuit' } | { kind: 'error'; message: string } | { kind: 'proceed' };\n\nexport function classifyIdempotencyOutcome(decision: 'accept' | 'decline', existing: RelationshipPublic | undefined): IdempotencyOutcome {\n\tif (!existing) return { kind: 'proceed' };\n\tif (existing.state === 'active') {\n\t\tif (decision === 'decline') {\n\t\t\t// State == active means a previous ACCEPT landed; the\n\t\t\t// FSM is now under contract/delegation/etc. control.\n\t\t\t// A decline cannot reverse that.\n\t\t\treturn {\n\t\t\t\tkind: 'error',\n\t\t\t\tmessage:\n\t\t\t\t\t`send-handshake-response: relationship ${existing.relationshipId} is already 'active' from a previous ACCEPT. ` +\n\t\t\t\t\t`A decline cannot reverse that — the active relationship is now under FSM control. ` +\n\t\t\t\t\t`If you want to terminate, close the relationship explicitly; pass --force to ignore this check and send the decline (which the server will reject with DOM_INVALID_TRANSITION).`,\n\t\t\t};\n\t\t}\n\t\t// decision === 'accept' — idempotent re-issue, short-circuit.\n\t\treturn { kind: 'short-circuit' };\n\t}\n\tif (existing.state === 'closed') {\n\t\treturn {\n\t\t\tkind: 'error',\n\t\t\tmessage:\n\t\t\t\t`send-handshake-response: relationship ${existing.relationshipId} is CLOSED. ` +\n\t\t\t\t`Cannot respond to handshake on a terminated relationship — start a fresh handshake instead.`,\n\t\t};\n\t}\n\t// state === 'pending' or 'paused': pending is the expected\n\t// pre-response state (proceed); paused is unusual but harmless\n\t// to send into (server will reject if invalid).\n\treturn { kind: 'proceed' };\n}\n\n/**\n * Probe `listRelationships` for the (sender, recipient) pair to\n * detect \"handshake_response already landed\" before the next\n * envelope burns a sender_sequence on `DOM_INVALID_TRANSITION`.\n *\n * Best-effort: walks one page (server caps at 100, ordered by\n * `lastEventAt` desc — recent activity is highly likely to be near\n * the top). Returns `undefined` when no matching pair is found OR\n * the server returns an unexpected shape. The caller's contract is\n * \"if you got a hit, use it; otherwise proceed and let the server\n * decide\".\n *\n * Exported for unit-test coverage.\n */\nexport async function findExistingRelationship(api: ArpApiClient, signer: Signer, senderDid: string, recipientDid: string): Promise<RelationshipPublic | undefined> {\n\tconst page = await api.listRelationships(senderDid, signer, { limit: 100 });\n\tif (!Array.isArray(page)) return undefined;\n\tfor (const row of page) {\n\t\tif ((row.pairDidA === senderDid && row.pairDidB === recipientDid) || (row.pairDidA === recipientDid && row.pairDidB === senderDid)) {\n\t\t\treturn row;\n\t\t}\n\t}\n\treturn undefined;\n}\n","import chalk from 'chalk';\nimport type { Command } from 'commander';\nimport { ArpApiClient, type EventPublic } from '../api';\nimport { printVerbose } from '../format';\nimport { resolveSenderAgent } from '../state';\nimport { makeSigner } from './lifecycle';\n\ninterface WatchOptions {\n\tserver?: string;\n\tfromDid?: string;\n\tverbose?: boolean;\n\tjson?: boolean;\n\tfullIds?: boolean;\n}\n\n/**\n * `heyarp watch <rel-id>` — single-relationship live tail.\n *\n * Worker daemons running multiple active relationships otherwise\n * have to use `heyarp inbox --tail` and mentally demultiplex the\n * firehose. A per-relationship filter makes the operator's attention\n * surface match the operator's intent — \"what's happening on rel-X\n * specifically?\".\n *\n * # Wire\n *\n * Re-uses the existing `/v1/agents/:did/inbox/stream` SSE route\n * with the new `?relationshipId=<rel>` query parameter. The server\n * verifies the signer is a member of that relationship pair\n * BEFORE opening the change stream — a filter on a non-member's\n * rel-id is rejected up front with `AUTH_NOT_RELATIONSHIP_MEMBER`\n * (403), not silently swallowed as \"zero events\".\n *\n * # Difference from `inbox --tail`\n *\n * `inbox --tail` is a firehose across every relationship the agent\n * participates in. `watch` is the same wire mechanic with the\n * change-stream `$match` narrowed server-side to one rel-id. Both\n * inherit the same exit-code contract:\n * - Ctrl-C / SIGTERM → quiet `stream closed.` + exit 0\n * - Server-driven EOF → `stream ended unexpectedly` + exit 1\n * (so a supervisor like pm2 / systemd / k8s liveness can\n * restart the wrapper)\n */\nexport function registerWatchCommand(root: Command): void {\n\troot.command('watch')\n\t\t.description('Live tail filtered to a single relationship (SSE). Server-side $match; only envelopes belonging to <rel-id> are streamed.')\n\t\t.argument('<relationship-id>', 'Relationship UUID to watch')\n\t\t.option('--server <url>', 'Override ARP server base URL')\n\t\t.option('--from-did <did>', 'Signer DID — required only if multiple agents are registered against this server')\n\t\t.option('--verbose', 'After each envelope, print the full JSON with a per-row label including eventId + serverEventHash', false)\n\t\t.option('--json', 'Machine-readable: one NDJSON object per line. Pipe-safe into `jq -c`.', false)\n\t\t.option('--full-ids', 'Print DIDs + serverEventHash in full (no truncation).', false)\n\t\t.action(async (relationshipId: string, opts: WatchOptions) => {\n\t\t\tawait runWatch(relationshipId, opts);\n\t\t});\n}\n\nasync function runWatch(relationshipId: string, opts: WatchOptions): Promise<void> {\n\tconst local = resolveSenderAgent('watch', opts.server, opts.fromDid);\n\tconst api = new ArpApiClient(opts.server);\n\n\tif (!opts.json) {\n\t\tconsole.log(chalk.dim(`Server: ${api.serverUrl}`));\n\t\tconsole.log(chalk.dim(`Signer: ${local.did}`));\n\t\tconsole.log(chalk.dim(`Watching: ${relationshipId}`));\n\t}\n\n\tconst controller = new AbortController();\n\t// Same userAborted contract as `inbox --tail` — distinguishes\n\t// \"user pressed Ctrl-C\" (exit 0) from \"server closed the stream\n\t// unexpectedly\" (exit 1). The latter is a real failure for a\n\t// long-running daemon and supervisors must restart.\n\tlet userAborted = false;\n\tconst onSignal = () => {\n\t\tuserAborted = true;\n\t\tcontroller.abort();\n\t};\n\tprocess.once('SIGINT', onSignal);\n\tprocess.once('SIGTERM', onSignal);\n\n\tconst signer = makeSigner(local);\n\n\ttry {\n\t\tfor await (const event of api.streamInbox(local.did, signer, { signal: controller.signal, relationshipId })) {\n\t\t\tif (opts.json) {\n\t\t\t\tconsole.log(JSON.stringify(event));\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (event.type === 'heartbeat') continue; // silent\n\t\t\tif (event.type === 'connected') {\n\t\t\t\tconsole.log(chalk.green(`● stream open — watching ${relationshipId}`));\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (event.type === 'envelope') {\n\t\t\t\tconst ev = event.data as EventPublic;\n\t\t\t\tconsole.log(formatWatchLine(ev, local.did, { fullIds: !!opts.fullIds }));\n\t\t\t\tif (opts.verbose) {\n\t\t\t\t\tprintVerbose([ev], 'Full event envelope:', (e) => ({\n\t\t\t\t\t\tprimary: `#${e.relationshipEventIndex} ${e.type ?? '<unknown>'}`,\n\t\t\t\t\t\tsecondary: `eventId=${e.eventId} serverEventHash=${e.serverEventHash}`,\n\t\t\t\t\t}));\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconsole.log(chalk.dim(`(unknown event: ${event.type})`));\n\t\t}\n\n\t\tif (!userAborted) {\n\t\t\tthrow new Error(`watch ${relationshipId}: stream ended unexpectedly (server may have restarted, or the change stream errored). Re-run to reconnect.`);\n\t\t}\n\t} catch (err) {\n\t\tconst name = (err as { name?: string }).name;\n\t\tif (name === 'AbortError' || userAborted) {\n\t\t\tif (!opts.json) console.log(chalk.dim('\\nstream closed.'));\n\t\t\treturn;\n\t\t}\n\t\tthrow err;\n\t} finally {\n\t\tprocess.off('SIGINT', onSignal);\n\t\tprocess.off('SIGTERM', onSignal);\n\t}\n}\n\n/**\n * One-line summary for one envelope arriving on the watched\n * relationship. Mirrors `formatEventLine` from the per-relationship\n * `events` command but without the chain-index prefix (since the\n * stream is live and the chain order is implicit). Exported for\n * testability.\n *\n * Format:\n *\n * HH:MM:SS type me → other hash\n */\nexport function formatWatchLine(ev: EventPublic, selfDid: string, opts: { fullIds?: boolean } = {}): string {\n\tconst ts = formatClock(ev.serverTimestamp);\n\tconst type = ev.type.padEnd(20);\n\tconst direction = directionLabel(ev, selfDid, opts);\n\tconst hash = opts.fullIds ? ev.serverEventHash : hashHead(ev.serverEventHash);\n\treturn `${chalk.dim(`[${ts}]`)} ${type} ${direction} ${chalk.cyan(hash)}`;\n}\n\nfunction directionLabel(ev: EventPublic, selfDid: string, opts: { fullIds?: boolean } = {}): string {\n\tconst senderHead = opts.fullIds ? ev.senderDid : didHead(ev.senderDid);\n\tconst recipientHead = opts.fullIds ? ev.recipientDid : didHead(ev.recipientDid);\n\tif (ev.senderDid === selfDid) return `${chalk.bold('me')} → ${chalk.dim(recipientHead)}`;\n\tif (ev.recipientDid === selfDid) return `${chalk.dim(senderHead)} → ${chalk.bold('me')}`;\n\treturn `${chalk.dim(senderHead)} → ${chalk.dim(recipientHead)}`;\n}\n\nfunction didHead(did: string): string {\n\tif (did.length <= 20) return did;\n\treturn `${did.slice(0, 20)}...`;\n}\n\nfunction hashHead(hash: string | null | undefined): string {\n\tif (!hash) return chalk.dim('(none)');\n\tif (hash.length <= 14) return hash;\n\treturn `${hash.slice(0, 14)}...`;\n}\n\n/**\n * Render the RFC 3339 `serverTimestamp` as a HH:MM:SS clock — local\n * tail readability beats absolute timestamps when the stream is\n * live (operator already knows the wall-clock date). Falls back to\n * the raw timestamp if parsing fails.\n *\n * Exported for testability.\n */\nexport function formatClock(iso: string): string {\n\tconst d = new Date(iso);\n\tif (Number.isNaN(d.getTime())) return iso;\n\tconst pad = (n: number): string => n.toString().padStart(2, '0');\n\treturn `${pad(d.getUTCHours())}:${pad(d.getUTCMinutes())}:${pad(d.getUTCSeconds())}`;\n}\n","import chalk from 'chalk';\nimport type { Command } from 'commander';\nimport { ArpApiClient } from '../api';\nimport { formatActionError, formatJson } from '../format';\nimport { resolveSenderAgent } from '../state';\nimport { makeSigner } from './lifecycle';\n\n/**\n * `heyarp whoami [did]` — fetch the agent's profile via the\n * signed-request endpoint. Doubles as a sanity check that:\n *\n * 1. the local secret key for `did` still corresponds to the\n * agent's CURRENT identity key on the server (rotation may\n * have moved it under us);\n * 2. the server is reachable + the cookie / cert path is\n * configured correctly.\n *\n * On signature mismatch the server returns\n * `AUTH_SIGNATURE_VERIFICATION_FAILED` (401) — which usually means\n * the key was rotated externally and the local state is stale.\n *\n * `<did>` is OPTIONAL. When omitted, uses the same sole-agent\n * fallback as every other signed command (`resolveSenderAgent`) —\n * so a single-agent dev setup can run `heyarp whoami` with no args\n * to identify itself. `--local` mode prints local-state pubkeys\n * (settlement + identity) WITHOUT contacting the server, so scripts\n * can grab them straight from the canonical state-file layout\n * (`agents.json` nested under `.servers[<url>].agents[<did>]`)\n * rather than reaching into the file by hand.\n */\nexport function registerWhoamiCommand(root: Command): void {\n\troot.command('whoami')\n\t\t.description(\n\t\t\t'Identify the local agent: print DID + settlement pubkey + identity pubkey (with --local), and/or fetch the server profile via signed GET /agents/:did. When <did> is omitted, uses the same sole-agent resolution as other signed commands.',\n\t\t)\n\t\t.argument('[did]', 'Agent DID (did:arp:...) — omit when there is exactly ONE local agent (sole-agent fallback)')\n\t\t.option('--server <url>', 'Override ARP server base URL')\n\t\t.option('--from-did <did>', 'Explicit sender DID — same precedence as the positional arg, surfaced for symmetry with other commands')\n\t\t.option(\n\t\t\t'--local',\n\t\t\t// Persona scripts want the local settlement pubkey for\n\t\t\t// `--payer-settlement-pubkey` / on-chain ops without a\n\t\t\t// server round-trip. `--local` short-circuits the signed\n\t\t\t// GET, prints just the resolved DID + pubkeys + keyMode\n\t\t\t// from local state. (V1-alpha: accountId parked, no longer\n\t\t\t// in --local output.)\n\t\t\t'Print local-state info only (DID + settlement + identity pubkeys + keyMode). Skips the signed server fetch — 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.',\n\t\t\tfalse,\n\t\t)\n\t\t.option('--json', 'JSON output (jq-pipeable). Combines local + server data when --local is unset, or just local when --local is set.', false)\n\t\t.action(async (didArg: string | undefined, opts: { server?: string; fromDid?: string; local?: boolean; json?: boolean }, cmd: Command) => {\n\t\t\ttry {\n\t\t\t\t// Resolve which agent: positional > --from-did > sole-\n\t\t\t\t// agent fallback (same precedence as resolveSenderAgent).\n\t\t\t\tconst explicitDid = didArg ?? opts.fromDid;\n\t\t\t\tconst local = resolveSenderAgent('whoami', opts.server, explicitDid);\n\n\t\t\t\tconst localJson = {\n\t\t\t\t\tdid: local.did,\n\t\t\t\t\tsettlementPublicKeyB58: local.settlementPublicKeyB58,\n\t\t\t\t\tidentityPublicKeyB58: local.identityPublicKeyB58,\n\t\t\t\t\t// V1-alpha: accountId parked — local-state type no\n\t\t\t\t\t// longer carries the field. Uncomment when launchpad↔ARP\n\t\t\t\t\t// join lands.\n\t\t\t\t\t// accountId: local.accountId,\n\t\t\t\t\tkeyMode: local.keyMode,\n\t\t\t\t\tname: local.name,\n\t\t\t\t};\n\n\t\t\t\tif (opts.local) {\n\t\t\t\t\tif (opts.json) {\n\t\t\t\t\t\tconsole.log(formatJson(localJson));\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconsole.log(chalk.bold('Local agent:'));\n\t\t\t\t\t\tconsole.log(` DID: ${chalk.cyan(local.did)}`);\n\t\t\t\t\t\tconsole.log(` Settlement pubkey: ${chalk.cyan(local.settlementPublicKeyB58)}`);\n\t\t\t\t\t\tconsole.log(` Identity pubkey: ${chalk.cyan(local.identityPublicKeyB58)}`);\n\t\t\t\t\t\t// V1-alpha: accountId parked. Uncomment when launchpad↔ARP\n\t\t\t\t\t\t// join lands and the field is restored on AgentLocalState.\n\t\t\t\t\t\t// console.log(` Account ID: ${local.accountId}`);\n\t\t\t\t\t\tconsole.log(` Key mode: ${local.keyMode}`);\n\t\t\t\t\t\tif (local.name) console.log(` Name: ${local.name}`);\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst api = new ArpApiClient(opts.server);\n\t\t\t\tconst signer = makeSigner(local);\n\t\t\t\tconst agent = await api.getAgent(local.did, signer);\n\n\t\t\t\tif (opts.json) {\n\t\t\t\t\tconsole.log(formatJson({ local: localJson, server: agent }));\n\t\t\t\t} else {\n\t\t\t\t\tconsole.log(chalk.dim(`Server: ${api.serverUrl}`));\n\t\t\t\t\tconsole.log(chalk.bold('\\nLocal agent:'));\n\t\t\t\t\tconsole.log(` DID: ${chalk.cyan(local.did)}`);\n\t\t\t\t\tconsole.log(` Settlement pubkey: ${chalk.cyan(local.settlementPublicKeyB58)}`);\n\t\t\t\t\tconsole.log(` Identity pubkey: ${chalk.cyan(local.identityPublicKeyB58)}`);\n\t\t\t\t\tconsole.log(chalk.bold('\\nServer profile:'));\n\t\t\t\t\tconsole.log(formatJson(agent));\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(formatActionError(err, cmd));\n\t\t\t\tprocess.exitCode = 1;\n\t\t\t}\n\t\t});\n}\n","import {\n\ttype Did,\n\tPurpose,\n\ttype SignableProtected,\n\ttype WorkRequestBody,\n\ttype WorkRequestContent,\n\ttype WorkResponseBody,\n\ttype WorkResponseContent,\n\texpiresAt,\n\trfc3339,\n\tsenderNonce,\n\tsignEnvelope,\n\tuuidV4,\n} from '@heyanon-arp/sdk';\nimport chalk from 'chalk';\nimport type { Command } from 'commander';\nimport { ApiError, ArpApiClient, type IngestResult, type Signer, type WorkLogPublic } from '../api';\nimport { formatJson } from '../format';\nimport { requireUuid as sharedRequireUuid } from '../id-format';\nimport { type AgentLocalState, resolveSenderAgent, updateAgentLocal } from '../state';\nimport { makeSigner } from './lifecycle';\n\n/**\n * `heyarp work <action>` — client side of the work_request /\n * work_response cycle:\n *\n * request <recipient-did> <delegation-id> --params <json>\n * → opens a REQUESTED work_log row under an ACCEPTED delegation\n *\n * respond <relationship-id> <delegation-id> <request-id>\n * (--output <json> | --error <code>:<message>)\n * → CAS-promotes the matching row REQUESTED → RESPONDED\n *\n * Same shape as `heyarp contract <action>` and `heyarp delegation <action>`\n * — thin wrappers around a shared `sendWorkEnvelope` helper that\n * allocates the next sender_sequence, signs the envelope, dispatches\n * `POST /v1/messages`, and advances `lastSenderSequence` on confirmed\n * ingest OR on a post-commit body-handler reject.\n *\n * `respond` auto-resolves `recipient_did` from the existing\n * work_log row (caller = recipient of the response). Pass\n * `--from-did` to disambiguate when multiple agents are registered\n * for the same server.\n */\nexport function registerWorkCommands(root: Command): void {\n\tconst cmd = root.command('work').description('Work envelopes inside an ACCEPTED delegation: request / respond');\n\n\tregisterRequest(cmd);\n\tregisterRespond(cmd);\n}\n\n/**\n * Error codes that indicate the server PERSISTED the event (so the\n * `sender_sequence` was consumed) but the body handler then rejected\n * the action. Mirror of the contract / delegation handler error\n * lists; failing to bump `lastSenderSequence` on these codes wedges\n * the agent on `ENV_SEQUENCE_BACKWARDS`.\n */\nexport const POST_COMMIT_ERROR_CODES = new Set([\n\t'WORK_DELEGATION_NOT_FOUND',\n\t'WORK_DELEGATION_NOT_ACTIVE',\n\t'WORK_RELATIONSHIP_MISMATCH',\n\t'WORK_REQUESTER_NOT_OFFERER',\n\t'WORK_REQUEST_ALREADY_EXISTS',\n\t'WORK_REQUEST_NOT_FOUND',\n\t'WORK_RESPONDER_IS_CALLER',\n\t'WORK_INVALID_STATE',\n]);\n\n// ---------- request ----------\n\ninterface RequestOptions extends BaseSendOptions {\n\trequestId?: string;\n\tparams?: string;\n\tparamsFile?: string;\n}\n\nfunction registerRequest(parent: Command): void {\n\tparent\n\t\t.command('request')\n\t\t.description('Send a work_request to <recipient-did> under <delegation-id> (must be ACCEPTED).')\n\t\t.argument('<recipient-did>', 'Recipient agent DID (the payee — the OTHER side of the delegation pair)')\n\t\t.argument('<delegation-id>', 'Parent delegation id (UUID, must be ACCEPTED)')\n\t\t.option('--server <url>', 'Override ARP server base URL')\n\t\t.option('--from-did <did>', 'Sender DID — required only if multiple agents are registered against this server')\n\t\t.option('--request-id <id>', 'Override the auto-generated request id (must be unique within the delegation)')\n\t\t.option(\n\t\t\t'--params <json>',\n\t\t\t'JSON object payload as a literal string. Defaults to {}. Mutually exclusive with --params-file. Brittle against shell quoting — prefer --params-file for non-trivial bodies.',\n\t\t)\n\t\t.option(\n\t\t\t'--params-file <path>',\n\t\t\t\"Read the JSON payload from a file. Mutually exclusive with --params. Use this for any payload large or quote-heavy enough that `--params '{...}'` would fight your shell.\",\n\t\t)\n\t\t.option('--ttl <seconds>', 'Envelope TTL in seconds (max 86400 = 24h)', '3600')\n\t\t.option('--verbose', 'Print the full envelope before sending and the full server response', false)\n\t\t.action(async (recipientDid: string, delegationId: string, opts: RequestOptions) => {\n\t\t\tawait runRequest(recipientDid, delegationId, opts);\n\t\t});\n}\n\nasync function runRequest(recipientDid: string, delegationId: string, opts: RequestOptions): Promise<void> {\n\trequireDid('work request', recipientDid, '<recipient-did>');\n\t// Normalise positional UUID to lowercase canonical form so\n\t// server-side delegationId lookups match what the chain stored.\n\t// Mixed-case input from a copy-pasted banner would otherwise miss\n\t// the row and reject the work_request.\n\tdelegationId = requireUuidNormalised('work request', delegationId, '<delegation-id>');\n\tconst ttlSeconds = parseTtl('work request', opts.ttl);\n\tconst params = parseParamsInput('work request', opts);\n\tconst requestId = parseRequestId('work request', opts.requestId);\n\n\tconst api = new ArpApiClient(opts.server);\n\tconst sender = resolveSenderAgent('work request', opts.server, opts.fromDid);\n\n\tconst content: WorkRequestContent = {\n\t\tdelegation_id: delegationId,\n\t\trequest_id: requestId,\n\t\tparams,\n\t};\n\tconst body: WorkRequestBody = { type: 'work_request', content };\n\n\tconsole.log(chalk.dim(`Server: ${api.serverUrl}`));\n\tconsole.log(chalk.dim(`Sender: ${sender.did}`));\n\tconsole.log(chalk.dim(`Recipient: ${recipientDid}`));\n\tconsole.log(chalk.dim(`Delegation: ${delegationId}`));\n\tconsole.log(chalk.dim(`Request id: ${requestId}`));\n\n\tconst result = await sendWorkEnvelope({ api, sender, recipientDid, body, ttlSeconds, verbose: opts.verbose, server: opts.server });\n\tprintIngestResult(result);\n\tconsole.log(chalk.dim(`\\nThe payee can reply with:`));\n\tconsole.log(chalk.dim(` heyarp work respond ${result.relationshipId} ${delegationId} ${requestId} --output '<json>'`));\n\tconsole.log(chalk.dim(` heyarp work respond ${result.relationshipId} ${delegationId} ${requestId} --error CODE:message`));\n}\n\n// ---------- respond ----------\n\ninterface RespondOptions extends BaseSendOptions {\n\toutput?: string;\n\toutputFile?: string;\n\terror?: string;\n}\n\nfunction registerRespond(parent: Command): void {\n\tparent\n\t\t.command('respond')\n\t\t.description('Send a work_response under <relationship-id> for <delegation-id> / <request-id>. Payee-only.')\n\t\t.argument('<relationship-id>', 'Relationship UUID')\n\t\t.argument('<delegation-id>', 'Parent delegation id (UUID)')\n\t\t.argument('<request-id>', 'Request id supplied on the work_request')\n\t\t.option('--server <url>', 'Override ARP server base URL')\n\t\t.option('--from-did <did>', 'Sender DID — required only if multiple agents are registered against this server')\n\t\t.option('--output <json>', 'Success payload as a JSON object literal. Mutually exclusive with --error and --output-file.')\n\t\t.option(\n\t\t\t'--output-file <path>',\n\t\t\t'Read the success payload from a file. Mutually exclusive with --output and --error. Use this for any payload large or quote-heavy enough to fight your shell.',\n\t\t)\n\t\t.option('--error <code:message>', 'Failure payload as `CODE:message`. Mutually exclusive with --output / --output-file.')\n\t\t.option('--ttl <seconds>', 'Envelope TTL in seconds', '3600')\n\t\t.option('--verbose', 'Print the full envelope before sending and the full server response', false)\n\t\t.action(async (relationshipId: string, delegationId: string, requestId: string, opts: RespondOptions) => {\n\t\t\tawait runRespond(relationshipId, delegationId, requestId, opts);\n\t\t});\n}\n\nasync function runRespond(relationshipId: string, delegationId: string, requestId: string, opts: RespondOptions): Promise<void> {\n\t// Normalise both positional UUIDs. relationshipId flows into URL\n\t// paths; delegationId flows into the signed body — mixed-case\n\t// slips past the CLI but the server's exact-match query rejects.\n\trelationshipId = requireUuidNormalised('work respond', relationshipId, '<relationship-id>');\n\tdelegationId = requireUuidNormalised('work respond', delegationId, '<delegation-id>');\n\tconst ttlSeconds = parseTtl('work respond', opts.ttl);\n\tconst responsePayload = parseResponsePayload('work respond', opts);\n\n\tconst api = new ArpApiClient(opts.server);\n\tconst sender = resolveSenderAgent('work respond', opts.server, opts.fromDid);\n\tconst signer = makeSigner(sender);\n\n\t// Auto-resolve `recipient_did` from the work_log row — the\n\t// caller (= recipient of the response) is logged on the row\n\t// when work_request was inserted. Avoids forcing the operator\n\t// to look up the DID separately.\n\tconst recipientDid = await resolveResponseRecipient('work respond', api, signer, { relationshipId, delegationId, requestId, selfDid: sender.did });\n\n\tconst content: WorkResponseContent = {\n\t\tdelegation_id: delegationId,\n\t\trequest_id: requestId,\n\t\t...responsePayload,\n\t};\n\tconst body: WorkResponseBody = { type: 'work_response', content };\n\n\tconsole.log(chalk.dim(`Server: ${api.serverUrl}`));\n\tconsole.log(chalk.dim(`Sender: ${sender.did}`));\n\tconsole.log(chalk.dim(`Recipient: ${recipientDid}`));\n\tconsole.log(chalk.dim(`Relationship: ${relationshipId}`));\n\tconsole.log(chalk.dim(`Delegation: ${delegationId}`));\n\tconsole.log(chalk.dim(`Request id: ${requestId}`));\n\tconsole.log(chalk.dim(`Outcome: ${responsePayload.output ? 'success' : 'error'}`));\n\n\tconst result = await sendWorkEnvelope({ api, sender, recipientDid, body, ttlSeconds, verbose: opts.verbose, server: opts.server });\n\tprintIngestResult(result);\n}\n\n// ---------- shared helpers ----------\n\ninterface BaseSendOptions {\n\tserver?: string;\n\tfromDid?: string;\n\tttl?: string;\n\tverbose?: boolean;\n}\n\ninterface SendArgs {\n\tapi: ArpApiClient;\n\tsender: AgentLocalState;\n\trecipientDid: string;\n\tbody: WorkRequestBody | WorkResponseBody;\n\tttlSeconds: number;\n\tverbose: boolean | undefined;\n\tserver: string | undefined;\n}\n\n/**\n * Build → sign → ingest a work envelope. Same sequence-bump\n * policy as the contract / delegation wrappers:\n *\n * 1. Success (HTTP 202): advance unconditionally.\n * 2. ApiError with a code in `POST_COMMIT_ERROR_CODES`: advance\n * anyway — server consumed the sequence even though the\n * action was rejected.\n * 3. Anything else — network error, or a pre-commit reject from\n * the validator (any code prefixed `ENV_`, `VAL_`, `AUTH_`,\n * `DOM_`): leave `lastSenderSequence` untouched so the same\n * sequence can be retried.\n */\nasync function sendWorkEnvelope(args: SendArgs): Promise<IngestResult> {\n\tconst nextSequence = (args.sender.lastSenderSequence ?? 0) + 1;\n\tconst protectedBlock: SignableProtected = {\n\t\tprotocol_version: 'arp/0.1',\n\t\tpurpose: Purpose.ENVELOPE,\n\t\tmessage_id: uuidV4(),\n\t\tsender_did: args.sender.did as Did,\n\t\trecipient_did: args.recipientDid as Did,\n\t\trelationship_id: null,\n\t\tsender_sequence: nextSequence,\n\t\tsender_nonce: senderNonce(),\n\t\ttimestamp: rfc3339(),\n\t\texpires_at: expiresAt(args.ttlSeconds),\n\t\tdelivery_id: null,\n\t};\n\n\tconst signer = makeSigner(args.sender);\n\tconst envelope = signEnvelope({\n\t\tprotected: protectedBlock,\n\t\tbody: args.body,\n\t\tidentitySecretKey: signer.identitySecretKey,\n\t});\n\n\tif (args.verbose) {\n\t\tconsole.log(chalk.bold('\\nEnvelope (pre-send):'));\n\t\tconsole.log(formatJson(envelope));\n\t}\n\n\ttry {\n\t\tconst result = await args.api.ingest(envelope);\n\t\tupdateAgentLocal(args.server, args.sender.did, { lastSenderSequence: nextSequence });\n\t\treturn result;\n\t} catch (err) {\n\t\tif (err instanceof ApiError && POST_COMMIT_ERROR_CODES.has(err.payload.code)) {\n\t\t\tupdateAgentLocal(args.server, args.sender.did, { lastSenderSequence: nextSequence });\n\t\t}\n\t\tthrow err;\n\t}\n}\n\n/**\n * Look up the work_log row to find the caller (= recipient of the\n * response). Pages defensively in case the relationship has > 100\n * work-logs.\n *\n * Exported for unit tests.\n */\nexport async function resolveResponseRecipient(\n\tcmdName: string,\n\tapi: Pick<ArpApiClient, 'listWorkLogs'>,\n\tsigner: Signer,\n\targs: { relationshipId: string; delegationId: string; requestId: string; selfDid: string },\n): Promise<string> {\n\tlet after: string | undefined;\n\twhile (true) {\n\t\tconst page: WorkLogPublic[] = await api.listWorkLogs(args.relationshipId, signer, { delegationId: args.delegationId, limit: 100, after });\n\t\tconst row = page.find((w) => w.requestId === args.requestId);\n\t\tif (row) {\n\t\t\t// Pre-flight state guard: a duplicate response on an\n\t\t\t// already-RESPONDED row would still be signed, posted,\n\t\t\t// land on the chain, and only THEN get rejected by the\n\t\t\t// handler with WORK_INVALID_STATE — burning the\n\t\t\t// sender_sequence and littering the chain with a\n\t\t\t// useless failed audit event. Catch it client-side\n\t\t\t// while we already have the row state in hand.\n\t\t\tif (row.state !== 'requested') {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`${cmdName}: work_request ${args.requestId} for delegation ${args.delegationId} is already in state '${row.state}' — only requests in state 'requested' can be responded to.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (row.callerDid === args.selfDid) {\n\t\t\t\t// The work_log says I'm the caller — but I'm trying\n\t\t\t\t// to RESPOND. The server will reject this with\n\t\t\t\t// `WORK_RESPONDER_IS_CALLER`; surface a clearer\n\t\t\t\t// client-side error since we have the info.\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`${cmdName}: the local agent ${args.selfDid} is the CALLER of work ${args.requestId} — only the payee (counterparty) can respond. Switch to the payee with --from-did <other-did>.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn row.callerDid;\n\t\t}\n\t\tif (page.length < 100) break;\n\t\tafter = page[page.length - 1].id;\n\t}\n\tthrow new Error(\n\t\t`${cmdName}: work_request ${args.requestId} for delegation ${args.delegationId} not found in relationship ${args.relationshipId}. Run 'heyarp work-list <relationship-id>' to inspect the timeline.`,\n\t);\n}\n\nfunction printIngestResult(result: IngestResult): void {\n\tconsole.log(chalk.green('\\nDelivered.'));\n\tconsole.log(`${chalk.bold('Event id')}: ${chalk.cyan(result.eventId)}`);\n\tconsole.log(`${chalk.bold('Relationship id')}: ${chalk.cyan(result.relationshipId)}`);\n\tconsole.log(`${chalk.bold('Chain index')}: ${chalk.cyan(String(result.relationshipEventIndex))}`);\n\tconsole.log(`${chalk.bold('Server timestamp')}: ${chalk.cyan(result.serverTimestamp)}`);\n\tconsole.log(`${chalk.bold('Server event hash')}: ${chalk.cyan(result.serverEventHash)}`);\n}\n\n/**\n * Parse + validate the `--params` (request) or `--output`\n * (response) JSON literal. Must be a non-null object (not array,\n * not primitive).\n *\n * Exported for unit tests.\n */\nexport function parseJsonObject(cmdName: string, flagName: string, raw: string): Record<string, unknown> {\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(raw);\n\t} catch (err) {\n\t\tconst detail = err instanceof Error ? err.message : String(err);\n\t\t// `--output` / `--params` expect a JSON OBJECT LITERAL, not\n\t\t// free-form text. A multi-byte string passed raw fails with\n\t\t// `Unexpected token 'X'` from the JSON parser, which reads as\n\t\t// a UTF-8 problem and sends operators down the wrong rabbit\n\t\t// hole. Detect the \"looks like raw text\" shape (doesn't start\n\t\t// with `{`, `[`, or `\"`) and surface a directive hint with\n\t\t// paste-ready examples instead.\n\t\tconst looksLikeRawText = !/^\\s*[{[\"]/.test(raw);\n\t\tif (looksLikeRawText) {\n\t\t\tconst truncated = JSON.stringify(raw.length > 80 ? `${raw.slice(0, 77)}...` : raw);\n\t\t\t// When raw text comes from a `*-file` flag (--params-file\n\t\t\t// / --output-file), the user is ALREADY using the file\n\t\t\t// path — telling them to \"use --output-file <path>\"\n\t\t\t// recursively is misleading. Branch the hint message:\n\t\t\t// file-flag callers get a \"fix the file contents\"\n\t\t\t// directive; inline-flag callers get the wrap-or-use-file\n\t\t\t// alternatives.\n\t\t\tif (flagName.endsWith('-file')) {\n\t\t\t\t// Try to recover the corresponding inline flag (--params-file\n\t\t\t\t// → --params, --output-file → --output) for the alternative\n\t\t\t\t// shape.\n\t\t\t\tconst inlineFlag = flagName.replace(/-file$/, '');\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`${cmdName}: ${flagName} contents must be a JSON object literal, not free-form text. ` +\n\t\t\t\t\t\t`Got: ${truncated} (length ${raw.length}). ` +\n\t\t\t\t\t\t`Replace the file's contents with a JSON object — e.g. \\`{\"translation\":\"…\",\"src\":\"en\",\"dst\":\"ru\"}\\` — or pass ${inlineFlag} '<json>' inline instead.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tthrow new Error(\n\t\t\t\t`${cmdName}: ${flagName} must be a JSON object literal, not free-form text. ` +\n\t\t\t\t\t`Got: ${truncated} (length ${raw.length}). ` +\n\t\t\t\t\t`To send a structured payload wrap your data in an object: ${flagName} '{\"translation\":\"…\",\"src\":\"en\",\"dst\":\"ru\"}'. ` +\n\t\t\t\t\t`For payloads heavy on quotes/multi-line text use ${flagName}-file <path> instead — it skips shell-quoting hell.`,\n\t\t\t);\n\t\t}\n\t\tthrow new Error(`${cmdName}: ${flagName} must be valid JSON (got '${raw}': ${detail})`);\n\t}\n\tif (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n\t\tthrow new Error(`${cmdName}: ${flagName} must be a JSON object literal (got '${raw}')`);\n\t}\n\treturn parsed as Record<string, unknown>;\n}\n\n/**\n * Resolve `--params` (JSON literal) XOR `--params-file` (path) for\n * `work request`. The file path is the documented escape hatch for\n * payloads heavy on quotes / multi-line text, where inline JSON\n * fights the shell. Both omitted → defaults to `{}`.\n *\n * Exported for unit tests.\n */\nexport function parseParamsInput(cmdName: string, opts: { params?: string; paramsFile?: string }): Record<string, unknown> {\n\tif (opts.params !== undefined && opts.paramsFile !== undefined) {\n\t\tthrow new Error(`${cmdName}: pass --params OR --params-file, not both — they're alternative input shapes for the same payload`);\n\t}\n\tif (opts.paramsFile !== undefined) {\n\t\treturn readJsonObjectFile(cmdName, '--params-file', opts.paramsFile);\n\t}\n\t// `--params` defaults to `{}` (commander default), so an unset\n\t// flag still hits this branch with the empty-object literal.\n\treturn parseJsonObject(cmdName, '--params', opts.params ?? '{}');\n}\n\n/**\n * Read a JSON file from disk, validate it parses to a plain object.\n * Same shape constraint as `parseJsonObject` (no top-level arrays /\n * primitives) since the protocol's request/response payloads are\n * keyed maps. Imports `node:fs` lazily inside the helper to keep the\n * happy-path startup time unchanged.\n *\n * Exported for unit tests.\n */\nexport function readJsonObjectFile(cmdName: string, flagName: string, path: string): Record<string, unknown> {\n\t// Use require-style import; this file already runs in a CJS bundle.\n\tconst { existsSync, readFileSync } = require('node:fs') as typeof import('node:fs');\n\tif (!existsSync(path)) {\n\t\tthrow new Error(`${cmdName}: ${flagName} file not found at ${path}`);\n\t}\n\tlet raw: string;\n\ttry {\n\t\traw = readFileSync(path, 'utf8');\n\t} catch (err) {\n\t\tconst detail = err instanceof Error ? err.message : String(err);\n\t\tthrow new Error(`${cmdName}: failed to read ${flagName} (${path}): ${detail}`);\n\t}\n\treturn parseJsonObject(cmdName, flagName, raw);\n}\n\n/**\n * For `respond`: parse `--output` XOR `--error`. Exactly one is\n * required, both is rejected, and `--error` must be in the\n * `CODE:message` format (matches the SDK shape).\n *\n * Exported for unit tests.\n */\nexport function parseResponsePayload(\n\tcmdName: string,\n\topts: { output?: string; outputFile?: string; error?: string },\n): { output?: Record<string, unknown>; error?: { code: string; message: string } } {\n\tconst hasOutput = opts.output !== undefined;\n\tconst hasOutputFile = opts.outputFile !== undefined;\n\tconst hasError = opts.error !== undefined;\n\tif (hasOutput && hasOutputFile) {\n\t\tthrow new Error(`${cmdName}: pass --output OR --output-file, not both — they're alternative input shapes for the same payload`);\n\t}\n\tif ((hasOutput || hasOutputFile) && hasError) {\n\t\tthrow new Error(`${cmdName}: pass --output / --output-file OR --error, not both — work_response carries exactly one outcome`);\n\t}\n\tif (!hasOutput && !hasOutputFile && !hasError) {\n\t\tthrow new Error(`${cmdName}: --output, --output-file, or --error is required — work_response carries exactly one outcome`);\n\t}\n\tif (hasOutputFile) {\n\t\treturn { output: readJsonObjectFile(cmdName, '--output-file', opts.outputFile as string) };\n\t}\n\tif (hasOutput) {\n\t\treturn { output: parseJsonObject(cmdName, '--output', opts.output as string) };\n\t}\n\t// --error format: `CODE:message`. The CODE half is split on the\n\t// first `:` so `message` can contain colons.\n\tconst raw = opts.error as string;\n\tconst idx = raw.indexOf(':');\n\tif (idx <= 0 || idx >= raw.length - 1) {\n\t\tthrow new Error(`${cmdName}: --error must be 'CODE:message' (got '${raw}')`);\n\t}\n\tconst code = raw.slice(0, idx).trim();\n\tconst message = raw.slice(idx + 1).trim();\n\tif (code.length === 0 || message.length === 0) {\n\t\tthrow new Error(`${cmdName}: --error must be 'CODE:message' with non-empty halves (got '${raw}')`);\n\t}\n\treturn { error: { code, message } };\n}\n\nexport function parseTtl(cmdName: string, raw: string | undefined): number {\n\tif (raw === undefined) return 3600;\n\tconst n = Number(raw);\n\tif (!Number.isFinite(n) || !Number.isInteger(n) || n <= 0) {\n\t\tthrow new Error(`${cmdName}: --ttl must be a positive integer number of seconds (got '${raw}')`);\n\t}\n\treturn n;\n}\n\nexport function parseRequestId(cmdName: string, raw: string | undefined): string {\n\tif (raw === undefined || raw === '') {\n\t\t// The SDK leaves `request_id` opaque (any non-empty\n\t\t// string is fine), but auto-generating a UUID gives the\n\t\t// CLI a sensible default and mirrors `parseDelegationId`.\n\t\treturn uuidV4();\n\t}\n\tif (raw.length === 0) {\n\t\tthrow new Error(`${cmdName}: --request-id must be a non-empty string`);\n\t}\n\treturn raw;\n}\n\n// Validate + normalise a positional UUID arg to lowercase canonical\n// form. Mirror of the helper in delegation.ts — kept local to avoid a\n// cross-command import for a 4-line function. RFC 4122 §3: canonical\n// UUID is lowercase.\n//\n// Exported for unit tests + symmetry with delegation.ts's API.\nexport function requireUuidNormalised(cmdName: string, raw: string, label: string): string {\n\trequireUuid(cmdName, raw, label);\n\treturn raw.toLowerCase();\n}\n\n/**\n * Thin wrapper over the shared `requireUuid` in `../id-format`. The\n * hint-rich error comes from the centralised implementation.\n */\nexport function requireUuid(cmdName: string, raw: string, label: string): void {\n\tsharedRequireUuid(cmdName, raw, label);\n}\n\nexport function requireDid(cmdName: string, did: string, label: string): void {\n\tif (typeof did !== 'string' || !did.startsWith('did:arp:') || did.length <= 'did:arp:'.length) {\n\t\tthrow new Error(`${cmdName}: ${label} must look like 'did:arp:...' (got '${did}')`);\n\t}\n}\n","import chalk from 'chalk';\nimport type { Command } from 'commander';\nimport { ArpApiClient, type ListWorkLogsQuery, type WorkLogPublic } from '../api';\nimport { printJsonArray, printVerbose } from '../format';\nimport { type AgentLocalState, resolveSenderAgent } from '../state';\nimport { makeSigner } from './lifecycle';\n\n// exported alongside `runWorkList` for mutual-exclusion test coverage.\nexport interface WorkListOptions {\n\tserver?: string;\n\tstate?: string;\n\tdelegationId?: string;\n\tafter?: string;\n\tlimit?: string;\n\tfromDid?: string;\n\tverbose?: boolean;\n\tjson?: boolean;\n\tfullIds?: boolean;\n}\n\nconst ALLOWED_STATES = new Set(['requested', 'responded']);\n\n/**\n * `heyarp work list <relationship-id>` — list the work-log timeline\n * for a relationship via signed `GET /v1/relationships/:id/work`.\n * Member-only (signer must be one of the pair); rows are ordered\n * chronologically with the same composite cursor as the contracts\n * / delegations lists.\n *\n * Top-level `heyarp work` is owned by `commands/work.ts` (the\n * request / respond subcommand group), so this list command is\n * registered as a SIBLING — `heyarp work-list <relationship-id>` —\n * to avoid a name collision with `heyarp work request`. The\n * dedicated file mirrors the relationship between\n * `commands/contract.ts` (FSM) and `commands/contracts.ts` (list).\n */\nexport function registerWorkListCommand(root: Command): void {\n\troot.command('work-list')\n\t\t.description('List work-log rows for a relationship (one row per (delegationId, requestId), oldest-first)')\n\t\t.argument('<relationship-id>', 'Relationship UUID')\n\t\t.option('--server <url>', 'Override ARP server base URL')\n\t\t.option('--state <s>', 'Filter by exact state (requested|responded)')\n\t\t.option('--delegation-id <uuid>', 'Narrow to work-logs operating under a specific delegation id')\n\t\t.option('--after <id>', \"Cursor: pass the previous page's last `id` to fetch the next page\")\n\t\t.option('--limit <n>', 'Max rows to return (1..100)', '20')\n\t\t.option('--from-did <did>', 'Signer DID — required only if multiple agents are registered against this server')\n\t\t.option(\n\t\t\t'--verbose',\n\t\t\t'After the summary, print a framed \"Full work-log payloads (N rows)\" block — each row labelled with full delegationId + requestId and dumped as JSON, including `requestParams` (the work_request payload the worker was asked) and `responseOutput` / `responseError`. Mutually exclusive with --json.',\n\t\t\tfalse,\n\t\t)\n\t\t.option('--json', 'Machine-readable mode — emit a single JSON array of work-log rows, no chalk, no summary. Pipe-safe. Mutually exclusive with --verbose.', false)\n\t\t.option(\n\t\t\t'--full-ids',\n\t\t\t'Print delegationId / requestId / DIDs in full (no truncation). Use when you want to copy-paste an id straight into `work respond` or `receipt propose`.',\n\t\t\tfalse,\n\t\t)\n\t\t.action(async (relationshipId: string, opts: WorkListOptions) => {\n\t\t\tawait runWorkList(relationshipId, opts);\n\t\t});\n}\n\n// Exported so tests can drive the full flow + spy on console.log.\nexport async function runWorkList(relationshipId: string, opts: WorkListOptions): Promise<void> {\n\tif (opts.verbose && opts.json) {\n\t\tthrow new Error(\n\t\t\t'work-list: --verbose and --json are mutually exclusive. --json already emits the full payload; --verbose adds the framed dump on top of the human summary.',\n\t\t);\n\t}\n\tconst limit = parseLimit(opts.limit);\n\tconst state = parseState(opts.state);\n\n\tconst api = new ArpApiClient(opts.server);\n\tconst sender = resolveSenderAgent('work-list', opts.server, opts.fromDid);\n\t// Prelude is gated on `!--json` so a `… --json | jq` pipeline\n\t// gets pure JSON on stdout.\n\tif (!opts.json) {\n\t\tconsole.log(chalk.dim(`Server: ${api.serverUrl}`));\n\t\tconsole.log(chalk.dim(`Signer: ${sender.did}`));\n\t\tconsole.log(chalk.dim(`Relationship: ${relationshipId}`));\n\t}\n\n\tconst query: ListWorkLogsQuery = { limit };\n\tif (state) query.state = state;\n\tif (opts.delegationId) query.delegationId = opts.delegationId;\n\tif (opts.after) query.after = opts.after;\n\n\tconst signer = makeSigner(sender);\n\tconst rows = await api.listWorkLogs(relationshipId, signer, query);\n\n\tif (opts.json) {\n\t\tprintJsonArray(rows);\n\t\treturn;\n\t}\n\n\tif (rows.length === 0) {\n\t\tconsole.log(chalk.dim('\\n(no work-logs for this relationship)'));\n\t\treturn;\n\t}\n\n\tconsole.log('');\n\tfor (const w of rows) {\n\t\tconsole.log(formatWorkLogLine(w, sender.did, { fullIds: !!opts.fullIds }));\n\t}\n\n\tif (opts.verbose) {\n\t\tprintVerbose(rows, 'Full work-log payloads:', (w) => ({\n\t\t\t// `requestId` is short + caller-chosen, `delegationId` is\n\t\t\t// the UUID `work request` / `work respond` need; surface\n\t\t\t// both at full length next to the JSON dump.\n\t\t\tprimary: `${w.requestId} state=${w.state}`,\n\t\t\tsecondary: `delegationId=${w.delegationId}`,\n\t\t}));\n\t}\n\n\tconst lastId = rows[rows.length - 1].id;\n\tconsole.log(chalk.dim(`\\n${rows.length} work-log row(s). Paginate with --after ${lastId}.`));\n}\n\n/**\n * One-line summary per work-log row:\n *\n * delegationHead/requestId state direction (outcome)\n *\n * Exported for unit tests.\n */\nexport function formatWorkLogLine(w: WorkLogPublic, selfDid: string, opts: { fullIds?: boolean } = {}): string {\n\tconst delegationPart = opts.fullIds ? w.delegationId : idHead(w.delegationId);\n\tconst requestPart = opts.fullIds ? w.requestId : truncate(w.requestId, 16);\n\tconst id = chalk.bold(`${delegationPart}/${requestPart}`);\n\tconst state = colorState(w.state).padEnd(stateColumnWidth());\n\tconst peerCallerHead = opts.fullIds ? w.callerDid : didHead(w.callerDid);\n\tconst peerPayeeHead = opts.fullIds ? w.payeeDid : didHead(w.payeeDid);\n\tconst direction = w.callerDid === selfDid ? `${chalk.bold('me')} → ${chalk.dim(peerPayeeHead)}` : `${chalk.dim(peerCallerHead)} → ${chalk.bold('me')}`;\n\tconst outcome = formatOutcome(w);\n\treturn `${id} ${state} ${direction} ${outcome}`;\n}\n\nfunction colorState(s: WorkLogPublic['state']): string {\n\tswitch (s) {\n\t\tcase 'requested':\n\t\t\treturn chalk.yellow('requested');\n\t\tcase 'responded':\n\t\t\treturn chalk.green('responded');\n\t}\n}\n\nfunction stateColumnWidth(): number {\n\t// \"responded\" is 9 chars; \"requested\" too. Equal padding.\n\treturn 9;\n}\n\nfunction formatOutcome(w: WorkLogPublic): string {\n\tif (w.state === 'requested') return chalk.dim('(in flight)');\n\tif (w.responseError) return chalk.red(`error ${w.responseError.code}: ${truncate(w.responseError.message, 32)}`);\n\tif (w.responseOutput) return chalk.cyan('ok');\n\t// Should be impossible per the FSM, but guard.\n\treturn chalk.dim('(empty response)');\n}\n\nfunction idHead(id: string): string {\n\tif (id.length <= 12) return id;\n\treturn `${id.slice(0, 8)}...${id.slice(-4)}`;\n}\n\nfunction didHead(did: string): string {\n\tif (did.length <= 20) return did;\n\treturn `${did.slice(0, 20)}...`;\n}\n\nfunction truncate(s: string, max: number): string {\n\tif (s.length <= max) return s;\n\treturn `${s.slice(0, max - 3)}...`;\n}\n\nexport function parseState(raw: string | undefined): WorkLogPublic['state'] | undefined {\n\tif (raw === undefined) return undefined;\n\tif (!ALLOWED_STATES.has(raw)) {\n\t\tthrow new Error(`work-list: --state must be one of requested|responded (got '${raw}')`);\n\t}\n\treturn raw as WorkLogPublic['state'];\n}\n\nexport function parseLimit(raw: string | undefined): number {\n\tif (raw === undefined) return 20;\n\tconst n = Number(raw);\n\tif (!Number.isFinite(n) || !Number.isInteger(n) || n < 1 || n > 100) {\n\t\tthrow new Error(`work-list: --limit must be an integer between 1 and 100 (got '${raw}')`);\n\t}\n\treturn n;\n}\n"],"mappings":"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","names":["raw","import_node_path","ed25519Sign","import_chalk","chalk","ApiError","probe","chalk","import_chalk","chalk","import_sdk","import_chalk","import_node_fs","import_node_path","import_sdk","import_node_fs","import_chalk","import_chalk","accumulate","chalk","import_sdk","import_node_fs","import_sdk","import_chalk","chalk","SolanaConnection","expiresAt","ed25519Sign","expiryNum","result","chalk","requireUuid","POST_COMMIT_ERROR_CODES","registerDecline","collectRepeated","requireDid","parseTtl","chalk","printIngestResult","import_chalk","parseLimit","chalk","truncate","import_chalk","ALLOWED_STATES","parseLimit","parseState","chalk","idHead","colorState","stateColumnWidth","didHead","truncate","import_sdk","import_sdk","import_chalk","chalk","import_chalk","chalk","import_sdk","import_utils","import_chalk","chalk","import_chalk","parseLimit","chalk","didHead","import_chalk","chalk","import_node_fs","import_node_path","import_chalk","import_node_fs","import_node_path","chalk","prompts","import_chalk","parseLimit","chalk","hashHead","import_sdk","import_chalk","chalk","sdkFormatDid","import_chalk","chalk","import_sdk","import_chalk","POST_COMMIT_ERROR_CODES","chalk","parseTtl","parseLimit","idHead","import_sdk","import_chalk","import_node_fs","registerPropose","POST_COMMIT_ERROR_CODES","runPropose","requireDid","requireUuidNormalised","parseTtl","chalk","requireUuid","printIngestResult","import_chalk","ALLOWED_STATES","parseLimit","parseState","chalk","idHead","hashHead","colorState","stateColumnWidth","didHead","import_node_fs","import_sdk","import_chalk","import_prompts","accumulate","chalk","sdkFormatDid","prompts","import_chalk","ALLOWED_STATES","parseLimit","parseState","chalk","import_sdk","import_chalk","import_prompts","chalk","prompts","base64UrlNoPadDecode","import_sdk","import_chalk","parseTtl","chalk","import_sdk","import_chalk","isDid","parseTtl","chalk","import_chalk","chalk","directionLabel","hashHead","didHead","import_chalk","chalk","import_sdk","import_chalk","POST_COMMIT_ERROR_CODES","requireDid","requireUuidNormalised","parseTtl","chalk","printIngestResult","existsSync","readFileSync","requireUuid","import_chalk","ALLOWED_STATES","parseLimit","parseState","chalk","idHead","truncate","colorState","stateColumnWidth","didHead","simpleUpdateNotifier"]}