@heyanon-arp/cli 0.0.25 → 0.0.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -322,6 +322,9 @@ var init_api = __esm({
322
322
  async getReputation(did) {
323
323
  return this.get(`/v1/agents/${encodeURIComponent(did)}/reputation`);
324
324
  }
325
+ async getStats(did) {
326
+ return this.get(`/v1/agents/${encodeURIComponent(did)}/stats`);
327
+ }
325
328
  /**
326
329
  * Public `GET /v1/discovery/search`. Reputation-ranked agent search
327
330
  * with creator / liveness / accepted-asset filters. No auth.
@@ -733,7 +736,7 @@ var import_commander = require("commander");
733
736
  // package.json
734
737
  var package_default = {
735
738
  name: "@heyanon-arp/cli",
736
- version: "0.0.25",
739
+ version: "0.0.27",
737
740
  description: "Command-line client for the Agent Relationship Protocol \u2014 register agents, sign envelopes, run escrowed work cycles on Solana.",
738
741
  license: "MIT",
739
742
  keywords: ["arp", "agent-relationship-protocol", "did", "solana", "escrow", "ed25519", "agents", "a2a", "cli"],
@@ -4722,8 +4725,8 @@ function formatEscrowConfigStatus(serverUrl, s) {
4722
4725
  lines.push("");
4723
4726
  lines.push(import_chalk14.default.dim(` New locks will snapshot fee_bps=0 \u2014 payee receives 100% on claim.`));
4724
4727
  } else {
4725
- const pct = (s.feeBps / 100).toFixed(2);
4726
- lines.push(` ${import_chalk14.default.yellow("ENABLED")} \u2014 ${pct}% of payee slice (${s.feeBps} bps)`);
4728
+ const pct2 = (s.feeBps / 100).toFixed(2);
4729
+ lines.push(` ${import_chalk14.default.yellow("ENABLED")} \u2014 ${pct2}% of payee slice (${s.feeBps} bps)`);
4727
4730
  lines.push(` ${import_chalk14.default.dim("fee_recipient:")} ${s.feeRecipient}`);
4728
4731
  lines.push("");
4729
4732
  lines.push(import_chalk14.default.dim(` New locks will snapshot fee_bps=${s.feeBps} onto themselves.`));
@@ -7400,9 +7403,258 @@ function bar(score) {
7400
7403
  return `${"\u2588".repeat(filled)}${"\u2591".repeat(10 - filled)}`;
7401
7404
  }
7402
7405
 
7406
+ // src/commands/selftest.ts
7407
+ var import_node_fs10 = require("fs");
7408
+ var import_node_os2 = require("os");
7409
+ var import_node_path7 = require("path");
7410
+ var import_web33 = require("@solana/web3.js");
7411
+ var import_chalk31 = __toESM(require("chalk"));
7412
+ init_api();
7413
+ var LIVENESS_THRESHOLD_SECONDS = 15 * 60;
7414
+ var DEFAULT_MIN_SOL = { worker: 1, both: 1, buyer: 1 };
7415
+ function registerSelftestCommand(root) {
7416
+ root.command("selftest").description(
7417
+ "Self-check: is THIS agent set up + operational (shield, login, registration, funding, skills, worker monitor)? No DID arg. Exit 1 only on a definite failure."
7418
+ ).option("--role <role>", "buyer | worker | both \u2014 scopes role-specific checks (default: inferred from installed skills, else both)").option("--skills-dir <path>", "Extra directory to search for the arp-*-flow skill files (in addition to $ARP_SKILLS_DIR and known framework dirs)").option("--min-sol <n>", "Minimum settlement balance in SOL to pass the funding check (default: 1.0)").option("--stall-min <n>", "Worker heartbeat freshness window in minutes; the file must be newer than 2\xD7 this (default: 5)", "5").option("--rpc-url <url>", "Solana RPC for the funding check (default: --rpc-url > ARP_ESCROW_RPC_URL > config rpcUrl > built-in)").option("--server <url>", "Override ARP server base URL").option("--json", "Machine-readable: single JSON object on stdout. Pipe-safe.", false).action(async (opts) => {
7419
+ await runSelftest(opts);
7420
+ });
7421
+ }
7422
+ async function runSelftest(opts) {
7423
+ const result = await selftest(opts);
7424
+ if (opts.json) {
7425
+ console.log(JSON.stringify(result));
7426
+ } else {
7427
+ console.log(formatSelftestReport(result));
7428
+ }
7429
+ if (!result.ok) process.exitCode = 1;
7430
+ }
7431
+ async function selftest(opts, deps = {}) {
7432
+ const api = deps.api ?? new ArpApiClient(opts.server);
7433
+ const server = api.serverUrl;
7434
+ const skillDirs = skillSearchDirs(opts.skillsDir);
7435
+ const role = resolveRole(opts.role, skillDirs);
7436
+ const checks = [];
7437
+ checks.push(checkOpengrep());
7438
+ checks.push(await checkLogin(api));
7439
+ checks.push(checkSkills(skillDirs, role));
7440
+ const agents = deps.agents ?? listAgents().filter((r) => r.serverUrl === server).map((r) => r.agent);
7441
+ if (agents.length === 0) {
7442
+ checks.push({ id: "registration", status: "fail", detail: `no local agent registered for ${server}`, fix: "heyarp register (or heyarp recover --from-keys)" });
7443
+ } else {
7444
+ for (const agent of agents) {
7445
+ checks.push(await checkRegistration(api, agent));
7446
+ checks.push(await checkFunding(agent, role, opts));
7447
+ if (role === "worker" || role === "both") checks.push(await checkWorkerLiveness(api, agent, opts));
7448
+ }
7449
+ }
7450
+ const ok = !checks.some((c) => c.status === "fail");
7451
+ return { server, role, ok, checks };
7452
+ }
7453
+ function checkOpengrep() {
7454
+ const heyshieldHome = process.env.HEYSHIELD_HOME && process.env.HEYSHIELD_HOME.length > 0 ? process.env.HEYSHIELD_HOME : (0, import_node_path7.join)((0, import_node_os2.homedir)(), ".heyshield");
7455
+ const bin = (0, import_node_path7.join)(heyshieldHome, "opengrep", "bin", "opengrep");
7456
+ if ((0, import_node_fs10.existsSync)(bin)) return { id: "opengrep", status: "pass", detail: `opengrep present (${bin})` };
7457
+ return { id: "opengrep", status: "warn", detail: `opengrep not found at ${bin} \u2014 L2 code/script scan unavailable (L0/L4 still active)`, fix: "heyshield install-opengrep" };
7458
+ }
7459
+ async function checkLogin(api) {
7460
+ const cred = readCredential(api.serverUrl);
7461
+ if (!cred) return { id: "login", status: "fail", detail: `not logged in to ${api.serverUrl}`, fix: "heyarp login" };
7462
+ try {
7463
+ await api.accountWhoami(cred.token);
7464
+ return { id: "login", status: "pass", detail: `logged in as ${cred.wallet} (token valid)` };
7465
+ } catch (err) {
7466
+ if (err instanceof ApiError && (err.status === 401 || err.status === 403)) {
7467
+ return {
7468
+ id: "login",
7469
+ status: "fail",
7470
+ detail: `login token for ${api.serverUrl} was rejected (${err.message}) \u2014 revoked/expired`,
7471
+ fix: "heyarp login (then re-register with --from-keys if the agent is also gone)"
7472
+ };
7473
+ }
7474
+ return {
7475
+ id: "login",
7476
+ status: "unknown",
7477
+ detail: `credential present (${cred.wallet}) but token NOT verified \u2014 server unreachable (${msg(err)})`,
7478
+ fix: "re-run online; if a later request is rejected, run `heyarp login`"
7479
+ };
7480
+ }
7481
+ }
7482
+ async function checkRegistration(api, agent) {
7483
+ try {
7484
+ await api.getDidDocument(agent.did);
7485
+ return { id: "registration", did: agent.did, status: "pass", detail: `${agent.did} registered on ${api.serverUrl}` };
7486
+ } catch (err) {
7487
+ if (err instanceof ApiError && err.status === 404) {
7488
+ return {
7489
+ id: "registration",
7490
+ did: agent.did,
7491
+ status: "fail",
7492
+ detail: `${agent.did} not found on ${api.serverUrl} \u2014 local keys exist but the server doesn't know this DID (server reset?)`,
7493
+ fix: "heyarp login + heyarp register --from-keys <exported-keys>"
7494
+ };
7495
+ }
7496
+ return { id: "registration", did: agent.did, status: "unknown", detail: `${agent.did} present locally; server registration not verified (${msg(err)})` };
7497
+ }
7498
+ }
7499
+ async function checkFunding(agent, role, opts) {
7500
+ const min = parseMinSol(opts.minSol, role);
7501
+ try {
7502
+ const rpc = resolveRpcUrl({ rpcUrl: opts.rpcUrl });
7503
+ const conn = new import_web33.Connection(rpc, "confirmed");
7504
+ const lamports = await conn.getBalance(new import_web33.PublicKey(agent.settlementPublicKeyB58));
7505
+ const sol = lamports / 1e9;
7506
+ if (sol >= min) return { id: "funding", did: agent.did, status: "pass", detail: `settlement ${agent.settlementPublicKeyB58} has ${sol} SOL (>= ${min})` };
7507
+ const low = role === "buyer" ? "warn" : "fail";
7508
+ return {
7509
+ id: "funding",
7510
+ did: agent.did,
7511
+ status: low,
7512
+ detail: `settlement ${agent.settlementPublicKeyB58} has ${sol} SOL (< ${min} needed)`,
7513
+ fix: "fund the settlement key with SOL (faucet / transfer)"
7514
+ };
7515
+ } catch (err) {
7516
+ return {
7517
+ id: "funding",
7518
+ did: agent.did,
7519
+ status: "unknown",
7520
+ detail: `could not read settlement balance for ${agent.did} (${msg(err)})`,
7521
+ fix: "set a reachable RPC: heyarp config set rpcUrl <url> (or --rpc-url)"
7522
+ };
7523
+ }
7524
+ }
7525
+ function checkSkills(dirs, role) {
7526
+ const roles = role === "both" ? ["worker", "buyer"] : [role];
7527
+ const missing = [];
7528
+ const foundAt = [];
7529
+ for (const r of roles) {
7530
+ const hit = findSkill(dirs, r);
7531
+ if (hit) foundAt.push(`${r}\u2192${hit}`);
7532
+ else missing.push(r);
7533
+ }
7534
+ if (missing.length === 0) return { id: "skills", status: "pass", detail: `found: ${foundAt.join(", ")}` };
7535
+ return {
7536
+ id: "skills",
7537
+ status: "unknown",
7538
+ detail: `skill(s) not found in known dirs for: ${missing.map((r) => `arp-${r}-flow`).join(", ")} (searched ${dirs.join(", ")})`,
7539
+ fix: "install the skill, or point selftest at it: --skills-dir <path> / export ARP_SKILLS_DIR=<path>"
7540
+ };
7541
+ }
7542
+ async function checkWorkerLiveness(api, agent, opts) {
7543
+ const stallMin = parsePositive(opts.stallMin, 5);
7544
+ const windowSec = stallMin * 60 * 2;
7545
+ const hbPath = process.env.ARP_WORKER_DISPATCHED && process.env.ARP_WORKER_DISPATCHED.length > 0 ? process.env.ARP_WORKER_DISPATCHED : (0, import_node_path7.join)((0, import_node_os2.homedir)(), ".heyarp-worker", "dispatched.txt");
7546
+ let hbFresh = false;
7547
+ let hbNote = "no local heartbeat file";
7548
+ const hbExists = (0, import_node_fs10.existsSync)(hbPath);
7549
+ if (hbExists) {
7550
+ const ageSec = Math.max(0, Math.floor((Date.now() - (0, import_node_fs10.statSync)(hbPath).mtimeMs) / 1e3));
7551
+ hbFresh = ageSec <= windowSec;
7552
+ hbNote = `heartbeat ${Math.floor(ageSec / 60)}m old`;
7553
+ }
7554
+ let serverSeen = "unknown";
7555
+ let serverNote = "server activity not checked";
7556
+ try {
7557
+ const s = await api.getActivitySummary(agent.did);
7558
+ const asOf = new Date(s.asOf).getTime();
7559
+ const seenAge = s.lastSeenAt ? Math.floor((asOf - new Date(s.lastSeenAt).getTime()) / 1e3) : null;
7560
+ const evtAge = s.lastEventAt ? Math.floor((asOf - new Date(s.lastEventAt).getTime()) / 1e3) : null;
7561
+ const recent = seenAge !== null && seenAge <= LIVENESS_THRESHOLD_SECONDS || evtAge !== null && evtAge <= LIVENESS_THRESHOLD_SECONDS || s.inboxStreamActive === true;
7562
+ serverSeen = recent ? "listening" : "dormant";
7563
+ serverNote = recent ? `server saw activity ${seenAge ?? evtAge ?? 0}s ago` : "server: no recent activity";
7564
+ } catch (err) {
7565
+ serverSeen = "unknown";
7566
+ serverNote = `server activity not available (${msg(err)})`;
7567
+ }
7568
+ const detail = `${hbNote}; ${serverNote}`;
7569
+ if (hbFresh || serverSeen === "listening") return { id: "worker_liveness", did: agent.did, status: "pass", detail };
7570
+ if (serverSeen === "dormant" || hbExists) {
7571
+ return {
7572
+ id: "worker_liveness",
7573
+ did: agent.did,
7574
+ status: "warn",
7575
+ detail: `${detail} \u2014 monitor may not be running`,
7576
+ fix: "start the worker / verify your cron is invoking arp_worker_watch.sh every ~1m"
7577
+ };
7578
+ }
7579
+ return {
7580
+ id: "worker_liveness",
7581
+ did: agent.did,
7582
+ status: "unknown",
7583
+ detail: `${detail} \u2014 no liveness signal yet (fresh install or offline)`,
7584
+ fix: "start the worker and re-run selftest"
7585
+ };
7586
+ }
7587
+ var msg = (err) => err instanceof Error ? err.message : String(err);
7588
+ function skillSearchDirs(extra) {
7589
+ const dirs = [];
7590
+ if (process.env.ARP_SKILLS_DIR && process.env.ARP_SKILLS_DIR.length > 0) dirs.push(process.env.ARP_SKILLS_DIR);
7591
+ if (extra && extra.length > 0) dirs.push(extra);
7592
+ const home = (0, import_node_os2.homedir)();
7593
+ dirs.push((0, import_node_path7.join)(home, ".claude", "skills"), (0, import_node_path7.join)(home, ".hermes", "skills"), (0, import_node_path7.join)(home, ".openclaw", "skills"));
7594
+ return dirs;
7595
+ }
7596
+ function findSkill(dirs, role) {
7597
+ const base = `arp-${role}-flow`;
7598
+ for (const d of dirs) {
7599
+ const candidates = [(0, import_node_path7.join)(d, base, "SKILL.md"), (0, import_node_path7.join)(d, `${base}.md`), (0, import_node_path7.join)(d, base)];
7600
+ for (const c of candidates) {
7601
+ if ((0, import_node_fs10.existsSync)(c)) return c;
7602
+ }
7603
+ }
7604
+ return null;
7605
+ }
7606
+ function resolveRole(flag, skillDirs) {
7607
+ if (flag === "worker" || flag === "buyer" || flag === "both") return flag;
7608
+ const hasWorker = findSkill(skillDirs, "worker") !== null;
7609
+ const hasBuyer = findSkill(skillDirs, "buyer") !== null;
7610
+ if (hasWorker && !hasBuyer) return "worker";
7611
+ if (hasBuyer && !hasWorker) return "buyer";
7612
+ return "both";
7613
+ }
7614
+ function parseMinSol(raw, role) {
7615
+ if (raw !== void 0 && raw !== "") {
7616
+ const n = Number.parseFloat(raw);
7617
+ if (Number.isFinite(n) && n >= 0) return n;
7618
+ }
7619
+ return DEFAULT_MIN_SOL[role];
7620
+ }
7621
+ function parsePositive(raw, fallback) {
7622
+ if (raw !== void 0 && raw !== "") {
7623
+ const n = Number.parseFloat(raw);
7624
+ if (Number.isFinite(n) && n > 0) return n;
7625
+ }
7626
+ return fallback;
7627
+ }
7628
+ var ICON = { pass: import_chalk31.default.green("\u2713"), warn: import_chalk31.default.yellow("\u26A0"), unknown: import_chalk31.default.dim("?"), fail: import_chalk31.default.red("\u2717") };
7629
+ function formatSelftestReport(r) {
7630
+ const lines = [];
7631
+ lines.push(`${import_chalk31.default.dim("Server:")} ${r.server} ${import_chalk31.default.dim("Role:")} ${r.role}`);
7632
+ const render = (c, indent) => {
7633
+ lines.push(`${indent}${ICON[c.status]} ${import_chalk31.default.bold(c.id)} ${c.detail}`);
7634
+ if (c.fix && c.status !== "pass") lines.push(`${indent} ${import_chalk31.default.dim("fix:")} ${c.fix}`);
7635
+ };
7636
+ lines.push("");
7637
+ for (const c of r.checks.filter((c2) => !c2.did)) render(c, " ");
7638
+ const dids = [...new Set(r.checks.filter((c) => c.did).map((c) => c.did))];
7639
+ for (const did of dids) {
7640
+ lines.push("");
7641
+ lines.push(` ${import_chalk31.default.dim("agent")} ${did}`);
7642
+ for (const c of r.checks.filter((c2) => c2.did === did)) render(c, " ");
7643
+ }
7644
+ lines.push("");
7645
+ const fails = r.checks.filter((c) => c.status === "fail").length;
7646
+ const advisories = r.checks.filter((c) => c.status === "warn" || c.status === "unknown").length;
7647
+ if (r.ok) {
7648
+ lines.push(`${import_chalk31.default.bold("Verdict:")} ${import_chalk31.default.green("READY")}${advisories > 0 ? import_chalk31.default.dim(` (${advisories} advisory)`) : ""}`);
7649
+ } else {
7650
+ lines.push(`${import_chalk31.default.bold("Verdict:")} ${import_chalk31.default.red("NOT READY")} \u2014 ${fails} blocking check(s) failed`);
7651
+ }
7652
+ return lines.join("\n");
7653
+ }
7654
+
7403
7655
  // src/commands/send-handshake.ts
7404
7656
  var import_sdk28 = require("@heyanon-arp/sdk");
7405
- var import_chalk31 = __toESM(require("chalk"));
7657
+ var import_chalk32 = __toESM(require("chalk"));
7406
7658
  init_api();
7407
7659
  function registerSendHandshakeCommand(root) {
7408
7660
  root.command("send-handshake").description("Send a handshake envelope to a recipient (agent name or DID). Server creates the relationship row on first contact.").argument("<recipient>", "Recipient \u2014 agent name (handle) or DID (did:arp:...)").option("--server <url>", "Override ARP server base URL").option("--from-did <did>", "Sender DID \u2014 required only if multiple agents are registered against this server").option("--from <name>", "Signer agent NAME (handle) \u2014 alternative to --from-did, resolved against your local agents").option("--greeting <s>", "Optional greeting text included in body.content").option("--intent <s>", "Optional intent text included in body.content").option("--ttl <seconds>", `Envelope TTL in seconds (max ${import_sdk28.MAX_ENVELOPE_TTL_SECONDS} = 24h)`, "3600").option("--require-online", "Abort (exit 1, CLI_RECIPIENT_OFFLINE) if the recipient is not reachable now, instead of warning and sending to their inbox", false).option("--verbose", "Print the full envelope before sending and the full server response. Mutually exclusive with --json.", false).option(
@@ -7422,10 +7674,10 @@ async function runSendHandshake(recipientDid, opts) {
7422
7674
  recipientDid = await resolveRecipient(opts.server, "send-handshake", recipientDid, { json: opts.json });
7423
7675
  const ttlSeconds = parseTtl3(opts.ttl);
7424
7676
  const api = new ArpApiClient(opts.server);
7425
- progress(opts.json, import_chalk31.default.dim(`Server: ${api.serverUrl}`));
7677
+ progress(opts.json, import_chalk32.default.dim(`Server: ${api.serverUrl}`));
7426
7678
  const sender = resolveSenderAgent("send-handshake", opts.server, opts.fromDid, opts.from);
7427
- progress(opts.json, import_chalk31.default.dim(`Sender: ${sender.did}`));
7428
- progress(opts.json, import_chalk31.default.dim(`Recipient: ${recipientDid}`));
7679
+ progress(opts.json, import_chalk32.default.dim(`Sender: ${sender.did}`));
7680
+ progress(opts.json, import_chalk32.default.dim(`Recipient: ${recipientDid}`));
7429
7681
  await guardRecipientReachable(api, recipientDid, { requireOnline: opts.requireOnline });
7430
7682
  const content = {};
7431
7683
  if (opts.greeting) content.greeting = opts.greeting;
@@ -7452,7 +7704,7 @@ async function runSendHandshake(recipientDid, opts) {
7452
7704
  identitySecretKey: signer.identitySecretKey
7453
7705
  });
7454
7706
  if (opts.verbose) {
7455
- console.log(import_chalk31.default.bold("\nEnvelope (pre-send):"));
7707
+ console.log(import_chalk32.default.bold("\nEnvelope (pre-send):"));
7456
7708
  console.log(formatJson(envelope));
7457
7709
  }
7458
7710
  const result = await api.ingest(envelope);
@@ -7472,23 +7724,23 @@ async function runSendHandshake(recipientDid, opts) {
7472
7724
  });
7473
7725
  return;
7474
7726
  }
7475
- console.log(import_chalk31.default.green("\nDelivered."));
7476
- console.log(`${import_chalk31.default.bold("Event id")}: ${import_chalk31.default.cyan(result.eventId)}`);
7477
- console.log(`${import_chalk31.default.bold("Relationship id")}: ${import_chalk31.default.cyan(result.relationshipId)}`);
7478
- console.log(`${import_chalk31.default.bold("Chain index")}: ${import_chalk31.default.cyan(String(result.relationshipEventIndex))}`);
7479
- console.log(`${import_chalk31.default.bold("Server timestamp")}: ${import_chalk31.default.cyan(result.serverTimestamp)}`);
7480
- console.log(`${import_chalk31.default.bold("Signed message hash")}: ${import_chalk31.default.cyan(result.signedMessageHash)}`);
7481
- console.log(`${import_chalk31.default.bold("Server event hash")}: ${import_chalk31.default.cyan(result.serverEventHash)}`);
7727
+ console.log(import_chalk32.default.green("\nDelivered."));
7728
+ console.log(`${import_chalk32.default.bold("Event id")}: ${import_chalk32.default.cyan(result.eventId)}`);
7729
+ console.log(`${import_chalk32.default.bold("Relationship id")}: ${import_chalk32.default.cyan(result.relationshipId)}`);
7730
+ console.log(`${import_chalk32.default.bold("Chain index")}: ${import_chalk32.default.cyan(String(result.relationshipEventIndex))}`);
7731
+ console.log(`${import_chalk32.default.bold("Server timestamp")}: ${import_chalk32.default.cyan(result.serverTimestamp)}`);
7732
+ console.log(`${import_chalk32.default.bold("Signed message hash")}: ${import_chalk32.default.cyan(result.signedMessageHash)}`);
7733
+ console.log(`${import_chalk32.default.bold("Server event hash")}: ${import_chalk32.default.cyan(result.serverEventHash)}`);
7482
7734
  if (result.prevServerEventHash) {
7483
- console.log(`${import_chalk31.default.bold("Prev server event hash")}: ${import_chalk31.default.cyan(result.prevServerEventHash)}`);
7735
+ console.log(`${import_chalk32.default.bold("Prev server event hash")}: ${import_chalk32.default.cyan(result.prevServerEventHash)}`);
7484
7736
  } else {
7485
- console.log(`${import_chalk31.default.bold("Prev server event hash")}: ${import_chalk31.default.dim("(null \u2014 first event of this relationship)")}`);
7737
+ console.log(`${import_chalk32.default.bold("Prev server event hash")}: ${import_chalk32.default.dim("(null \u2014 first event of this relationship)")}`);
7486
7738
  }
7487
7739
  if (opts.verbose) {
7488
- console.log(import_chalk31.default.bold("\nFull server response:"));
7740
+ console.log(import_chalk32.default.bold("\nFull server response:"));
7489
7741
  console.log(formatJson(result));
7490
7742
  }
7491
- console.log(import_chalk31.default.dim(`
7743
+ console.log(import_chalk32.default.dim(`
7492
7744
  Local sender_sequence advanced to ${nextSequence}.`));
7493
7745
  }
7494
7746
  function parseTtl3(raw) {
@@ -7502,7 +7754,7 @@ function parseTtl3(raw) {
7502
7754
 
7503
7755
  // src/commands/send-handshake-response.ts
7504
7756
  var import_sdk29 = require("@heyanon-arp/sdk");
7505
- var import_chalk32 = __toESM(require("chalk"));
7757
+ var import_chalk33 = __toESM(require("chalk"));
7506
7758
  init_api();
7507
7759
  var ALLOWED_DECISIONS = new Set(import_sdk29.HANDSHAKE_DECISIONS);
7508
7760
  function registerSendHandshakeResponseCommand(root) {
@@ -7543,11 +7795,11 @@ async function runSendHandshakeResponse(recipientDid, opts) {
7543
7795
  declinePayload = detail ? { reason, reasonDetail: detail } : { reason };
7544
7796
  }
7545
7797
  const api = new ArpApiClient(opts.server);
7546
- progress(opts.json, import_chalk32.default.dim(`Server: ${api.serverUrl}`));
7798
+ progress(opts.json, import_chalk33.default.dim(`Server: ${api.serverUrl}`));
7547
7799
  const sender = resolveSenderAgent("send-handshake-response", opts.server, opts.fromDid, opts.from);
7548
- progress(opts.json, import_chalk32.default.dim(`Sender: ${sender.did}`));
7549
- progress(opts.json, import_chalk32.default.dim(`Recipient: ${recipientDid}`));
7550
- progress(opts.json, import_chalk32.default.dim(`Decision: ${decision}`));
7800
+ progress(opts.json, import_chalk33.default.dim(`Sender: ${sender.did}`));
7801
+ progress(opts.json, import_chalk33.default.dim(`Recipient: ${recipientDid}`));
7802
+ progress(opts.json, import_chalk33.default.dim(`Decision: ${decision}`));
7551
7803
  const signer = makeSigner(sender);
7552
7804
  if (!opts.force) {
7553
7805
  try {
@@ -7577,13 +7829,13 @@ async function runSendHandshakeResponse(recipientDid, opts) {
7577
7829
  });
7578
7830
  return;
7579
7831
  }
7580
- progress(opts.json, import_chalk32.default.yellow(`
7832
+ progress(opts.json, import_chalk33.default.yellow(`
7581
7833
  [--idempotency] Relationship ${existing.relationshipId} with ${recipientDid} is already 'active'.`));
7582
7834
  progress(
7583
7835
  opts.json,
7584
- import_chalk32.default.dim(`A previous accept from this signer (event ${previousResponseFromMe.eventId}) landed successfully. Skipping re-send (use --force to override).`)
7836
+ import_chalk33.default.dim(`A previous accept from this signer (event ${previousResponseFromMe.eventId}) landed successfully. Skipping re-send (use --force to override).`)
7585
7837
  );
7586
- progress(opts.json, import_chalk32.default.dim(`Last event index: ${existing.lastEventIndex}, last server event hash: ${existing.lastServerEventHash ?? "(none)"}`));
7838
+ progress(opts.json, import_chalk33.default.dim(`Last event index: ${existing.lastEventIndex}, last server event hash: ${existing.lastServerEventHash ?? "(none)"}`));
7587
7839
  return;
7588
7840
  }
7589
7841
  throw new Error(
@@ -7594,7 +7846,7 @@ async function runSendHandshakeResponse(recipientDid, opts) {
7594
7846
  if (probeErr instanceof Error && /CLOSED|terminated|already 'active' from a previous ACCEPT|original initiator/i.test(probeErr.message)) {
7595
7847
  throw probeErr;
7596
7848
  }
7597
- progress(opts.json, import_chalk32.default.dim(`(idempotency probe failed; proceeding anyway: ${probeErr.message})`));
7849
+ progress(opts.json, import_chalk33.default.dim(`(idempotency probe failed; proceeding anyway: ${probeErr.message})`));
7598
7850
  }
7599
7851
  }
7600
7852
  const content = { decision };
@@ -7624,7 +7876,7 @@ async function runSendHandshakeResponse(recipientDid, opts) {
7624
7876
  identitySecretKey: signer.identitySecretKey
7625
7877
  });
7626
7878
  if (opts.verbose) {
7627
- console.log(import_chalk32.default.bold("\nEnvelope (pre-send):"));
7879
+ console.log(import_chalk33.default.bold("\nEnvelope (pre-send):"));
7628
7880
  console.log(formatJson(envelope));
7629
7881
  }
7630
7882
  const result = await api.ingest(envelope);
@@ -7645,23 +7897,23 @@ async function runSendHandshakeResponse(recipientDid, opts) {
7645
7897
  });
7646
7898
  return;
7647
7899
  }
7648
- console.log(import_chalk32.default.green("\nDelivered."));
7649
- console.log(`${import_chalk32.default.bold("Event id")}: ${import_chalk32.default.cyan(result.eventId)}`);
7650
- console.log(`${import_chalk32.default.bold("Relationship id")}: ${import_chalk32.default.cyan(result.relationshipId)}`);
7651
- console.log(`${import_chalk32.default.bold("Chain index")}: ${import_chalk32.default.cyan(String(result.relationshipEventIndex))}`);
7652
- console.log(`${import_chalk32.default.bold("Server timestamp")}: ${import_chalk32.default.cyan(result.serverTimestamp)}`);
7653
- console.log(`${import_chalk32.default.bold("Signed message hash")}: ${import_chalk32.default.cyan(result.signedMessageHash)}`);
7654
- console.log(`${import_chalk32.default.bold("Server event hash")}: ${import_chalk32.default.cyan(result.serverEventHash)}`);
7900
+ console.log(import_chalk33.default.green("\nDelivered."));
7901
+ console.log(`${import_chalk33.default.bold("Event id")}: ${import_chalk33.default.cyan(result.eventId)}`);
7902
+ console.log(`${import_chalk33.default.bold("Relationship id")}: ${import_chalk33.default.cyan(result.relationshipId)}`);
7903
+ console.log(`${import_chalk33.default.bold("Chain index")}: ${import_chalk33.default.cyan(String(result.relationshipEventIndex))}`);
7904
+ console.log(`${import_chalk33.default.bold("Server timestamp")}: ${import_chalk33.default.cyan(result.serverTimestamp)}`);
7905
+ console.log(`${import_chalk33.default.bold("Signed message hash")}: ${import_chalk33.default.cyan(result.signedMessageHash)}`);
7906
+ console.log(`${import_chalk33.default.bold("Server event hash")}: ${import_chalk33.default.cyan(result.serverEventHash)}`);
7655
7907
  if (result.prevServerEventHash) {
7656
- console.log(`${import_chalk32.default.bold("Prev server event hash")}: ${import_chalk32.default.cyan(result.prevServerEventHash)}`);
7908
+ console.log(`${import_chalk33.default.bold("Prev server event hash")}: ${import_chalk33.default.cyan(result.prevServerEventHash)}`);
7657
7909
  } else {
7658
- console.log(`${import_chalk32.default.bold("Prev server event hash")}: ${import_chalk32.default.dim("(null \u2014 first event of this relationship)")}`);
7910
+ console.log(`${import_chalk33.default.bold("Prev server event hash")}: ${import_chalk33.default.dim("(null \u2014 first event of this relationship)")}`);
7659
7911
  }
7660
7912
  if (opts.verbose) {
7661
- console.log(import_chalk32.default.bold("\nFull server response:"));
7913
+ console.log(import_chalk33.default.bold("\nFull server response:"));
7662
7914
  console.log(formatJson(result));
7663
7915
  }
7664
- console.log(import_chalk32.default.dim(`
7916
+ console.log(import_chalk33.default.dim(`
7665
7917
  Local sender_sequence advanced to ${nextSequence}.`));
7666
7918
  }
7667
7919
  function parseDecision(raw) {
@@ -7711,8 +7963,64 @@ async function findExistingRelationship(api, signer, senderDid, recipientDid) {
7711
7963
  return void 0;
7712
7964
  }
7713
7965
 
7966
+ // src/commands/stats.ts
7967
+ var import_chalk34 = __toESM(require("chalk"));
7968
+ init_api();
7969
+ function registerStatsCommand(root) {
7970
+ root.command("stats").description("Show an agent's public stats \u2014 counters, 0..100 scores, derived rates, and settled on-chain volume by asset. Public, no auth.").argument("<agent>", "Agent name (handle) or did:arp:<base58btc>").option("--server <url>", "Override ARP server base URL").option("--json", "Emit the stats as JSON on stdout.", false).action(async (agent, opts) => {
7971
+ const did = await resolveRecipient(opts.server, "stats", agent, { json: opts.json });
7972
+ const api = new ArpApiClient(opts.server);
7973
+ const stats = await api.getStats(did);
7974
+ if (opts.json) {
7975
+ jsonOut(stats);
7976
+ return;
7977
+ }
7978
+ const j = false;
7979
+ const { counters: c, scores: s, rates: r, volume: v } = stats;
7980
+ progress(j, import_chalk34.default.bold(`Stats \u2014 ${did}`));
7981
+ progress(j, import_chalk34.default.dim(` ${stats.computed ? "computed" : "cold-start (no settled cycle yet)"}`));
7982
+ progress(j, "");
7983
+ progress(
7984
+ j,
7985
+ ` scores composite ${s.composite.toFixed(0)} \xB7 reliability ${s.reliability.toFixed(0)} \xB7 settlement ${s.settlement.toFixed(0)} \xB7 disputeHealth ${s.disputeHealth.toFixed(0)}`
7986
+ );
7987
+ progress(j, ` rates completion ${pct(r.completionRate)} \xB7 dispute ${pct(r.disputeRate)} \xB7 adverse ${pct(r.adverseDisputeRate)}`);
7988
+ progress(
7989
+ j,
7990
+ ` cycles on-chain ${c.onchainCycles} \xB7 completed ${c.completedDelegations} (payer ${c.completedAsPayer} / payee ${c.completedAsPayee}) \xB7 failed ${c.failedDelegations}`
7991
+ );
7992
+ progress(j, ` escrows settled ${c.settledEscrows} / refunded ${c.refundedEscrows} \xB7 disputed ${c.disputedEscrows} (adverse ${c.disputesAdverse})`);
7993
+ progress(j, ` network distinct counterparts ${c.distinctCounterparts} \xB7 active relationships ${c.activeRelationships}`);
7994
+ progress(j, "");
7995
+ progress(j, import_chalk34.default.dim(" earned (as payee):"));
7996
+ renderAssets(v.earnedByAsset);
7997
+ progress(j, import_chalk34.default.dim(" paid (as payer):"));
7998
+ renderAssets(v.paidByAsset);
7999
+ if (v.firstSettledAt || v.lastSettledAt) {
8000
+ progress(j, "");
8001
+ progress(j, import_chalk34.default.dim(` settled span: ${v.firstSettledAt ?? "?"} \u2192 ${v.lastSettledAt ?? "?"}`));
8002
+ }
8003
+ progress(j, "");
8004
+ progress(j, import_chalk34.default.dim(" Public, informational \u2014 derived from on-chain settlement; cached briefly."));
8005
+ });
8006
+ }
8007
+ function pct(r) {
8008
+ return r == null ? "n/a" : `${(r * 100).toFixed(0)}%`;
8009
+ }
8010
+ function renderAssets(assets) {
8011
+ if (assets.length === 0) {
8012
+ progress(false, import_chalk34.default.dim(" (none)"));
8013
+ return;
8014
+ }
8015
+ for (const a of assets) {
8016
+ const label = a.symbol ?? `${a.mint.slice(0, 6)}\u2026`;
8017
+ const amount = a.amountDecimal ?? `${a.amountBaseUnits} base-units`;
8018
+ progress(false, ` ${amount} ${label} ${import_chalk34.default.dim(`(${a.lockCount} lock${a.lockCount === 1 ? "" : "s"})`)}`);
8019
+ }
8020
+ }
8021
+
7714
8022
  // src/commands/watch.ts
7715
- var import_chalk33 = __toESM(require("chalk"));
8023
+ var import_chalk35 = __toESM(require("chalk"));
7716
8024
  init_api();
7717
8025
  function registerWatchCommand(root) {
7718
8026
  root.command("watch").description("Live tail filtered to a single relationship (SSE). Server-side $match; only envelopes belonging to <rel-id> are streamed.").argument("<relationship-id>", "Relationship UUID to watch").option("--server <url>", "Override ARP server base URL").option("--from-did <did>", "Signer DID \u2014 required only if multiple agents are registered against this server").option("--from <name>", "Signer agent NAME (handle) \u2014 alternative to --from-did, resolved against your local agents").option("--verbose", "After each envelope, print the full JSON with a per-row label including eventId + serverEventHash", false).option("--json", "Machine-readable: one NDJSON object per line. Pipe-safe into `jq -c`.", false).option("--full-ids", "Print DIDs + serverEventHash in full (no truncation).", false).action(async (relationshipId, opts) => {
@@ -7723,9 +8031,9 @@ async function runWatch(relationshipId, opts) {
7723
8031
  const local = resolveSenderAgent("watch", opts.server, opts.fromDid, opts.from);
7724
8032
  const api = new ArpApiClient(opts.server);
7725
8033
  if (!opts.json) {
7726
- console.log(import_chalk33.default.dim(`Server: ${api.serverUrl}`));
7727
- console.log(import_chalk33.default.dim(`Signer: ${local.did}`));
7728
- console.log(import_chalk33.default.dim(`Watching: ${relationshipId}`));
8034
+ console.log(import_chalk35.default.dim(`Server: ${api.serverUrl}`));
8035
+ console.log(import_chalk35.default.dim(`Signer: ${local.did}`));
8036
+ console.log(import_chalk35.default.dim(`Watching: ${relationshipId}`));
7729
8037
  }
7730
8038
  const controller = new AbortController();
7731
8039
  let userAborted = false;
@@ -7744,7 +8052,7 @@ async function runWatch(relationshipId, opts) {
7744
8052
  }
7745
8053
  if (event.type === "heartbeat") continue;
7746
8054
  if (event.type === "connected") {
7747
- console.log(import_chalk33.default.green(`\u25CF stream open \u2014 watching ${relationshipId}`));
8055
+ console.log(import_chalk35.default.green(`\u25CF stream open \u2014 watching ${relationshipId}`));
7748
8056
  continue;
7749
8057
  }
7750
8058
  if (event.type === "envelope") {
@@ -7758,7 +8066,7 @@ async function runWatch(relationshipId, opts) {
7758
8066
  }
7759
8067
  continue;
7760
8068
  }
7761
- console.log(import_chalk33.default.dim(`(unknown event: ${event.type})`));
8069
+ console.log(import_chalk35.default.dim(`(unknown event: ${event.type})`));
7762
8070
  }
7763
8071
  if (!userAborted) {
7764
8072
  throw new Error(`watch ${relationshipId}: stream ended unexpectedly (server may have restarted, or the change stream errored). Re-run to reconnect.`);
@@ -7766,7 +8074,7 @@ async function runWatch(relationshipId, opts) {
7766
8074
  } catch (err) {
7767
8075
  const name = err.name;
7768
8076
  if (name === "AbortError" || userAborted) {
7769
- if (!opts.json) console.log(import_chalk33.default.dim("\nstream closed."));
8077
+ if (!opts.json) console.log(import_chalk35.default.dim("\nstream closed."));
7770
8078
  return;
7771
8079
  }
7772
8080
  throw err;
@@ -7780,21 +8088,21 @@ function formatWatchLine(ev, selfDid, opts = {}) {
7780
8088
  const type = ev.type.padEnd(20);
7781
8089
  const direction = directionLabel2(ev, selfDid, opts);
7782
8090
  const hash = opts.fullIds ? ev.serverEventHash : hashHead4(ev.serverEventHash);
7783
- return `${import_chalk33.default.dim(`[${ts}]`)} ${type} ${direction} ${import_chalk33.default.cyan(hash)}`;
8091
+ return `${import_chalk35.default.dim(`[${ts}]`)} ${type} ${direction} ${import_chalk35.default.cyan(hash)}`;
7784
8092
  }
7785
8093
  function directionLabel2(ev, selfDid, opts = {}) {
7786
8094
  const senderHead = opts.fullIds ? ev.senderDid : didHead4(ev.senderDid);
7787
8095
  const recipientHead = opts.fullIds ? ev.recipientDid : didHead4(ev.recipientDid);
7788
- if (ev.senderDid === selfDid) return `${import_chalk33.default.bold("me")} \u2192 ${import_chalk33.default.dim(recipientHead)}`;
7789
- if (ev.recipientDid === selfDid) return `${import_chalk33.default.dim(senderHead)} \u2192 ${import_chalk33.default.bold("me")}`;
7790
- return `${import_chalk33.default.dim(senderHead)} \u2192 ${import_chalk33.default.dim(recipientHead)}`;
8096
+ if (ev.senderDid === selfDid) return `${import_chalk35.default.bold("me")} \u2192 ${import_chalk35.default.dim(recipientHead)}`;
8097
+ if (ev.recipientDid === selfDid) return `${import_chalk35.default.dim(senderHead)} \u2192 ${import_chalk35.default.bold("me")}`;
8098
+ return `${import_chalk35.default.dim(senderHead)} \u2192 ${import_chalk35.default.dim(recipientHead)}`;
7791
8099
  }
7792
8100
  function didHead4(did) {
7793
8101
  if (did.length <= 20) return did;
7794
8102
  return `${did.slice(0, 20)}...`;
7795
8103
  }
7796
8104
  function hashHead4(hash) {
7797
- if (!hash) return import_chalk33.default.dim("(none)");
8105
+ if (!hash) return import_chalk35.default.dim("(none)");
7798
8106
  if (hash.length <= 14) return hash;
7799
8107
  return `${hash.slice(0, 14)}...`;
7800
8108
  }
@@ -7806,7 +8114,7 @@ function formatClock(iso) {
7806
8114
  }
7807
8115
 
7808
8116
  // src/commands/whoami.ts
7809
- var import_chalk34 = __toESM(require("chalk"));
8117
+ var import_chalk36 = __toESM(require("chalk"));
7810
8118
  init_api();
7811
8119
  function registerWhoamiCommand(root) {
7812
8120
  root.command("whoami").description(
@@ -7837,12 +8145,12 @@ function registerWhoamiCommand(root) {
7837
8145
  if (opts.json) {
7838
8146
  console.log(formatJson({ ...localJson, account: credential ? { wallet: credential.wallet } : null }));
7839
8147
  } else {
7840
- console.log(import_chalk34.default.bold("Local agent:"));
7841
- console.log(` DID: ${import_chalk34.default.cyan(local.did)}`);
7842
- console.log(` Settlement pubkey: ${import_chalk34.default.cyan(local.settlementPublicKeyB58)}`);
7843
- console.log(` Identity pubkey: ${import_chalk34.default.cyan(local.identityPublicKeyB58)}`);
8148
+ console.log(import_chalk36.default.bold("Local agent:"));
8149
+ console.log(` DID: ${import_chalk36.default.cyan(local.did)}`);
8150
+ console.log(` Settlement pubkey: ${import_chalk36.default.cyan(local.settlementPublicKeyB58)}`);
8151
+ console.log(` Identity pubkey: ${import_chalk36.default.cyan(local.identityPublicKeyB58)}`);
7844
8152
  if (local.name) console.log(` Name: ${local.name}`);
7845
- console.log(` Account: ${credential ? import_chalk34.default.cyan(credential.wallet) : import_chalk34.default.dim("not logged in (heyarp login)")}`);
8153
+ console.log(` Account: ${credential ? import_chalk36.default.cyan(credential.wallet) : import_chalk36.default.dim("not logged in (heyarp login)")}`);
7846
8154
  }
7847
8155
  return;
7848
8156
  }
@@ -7860,19 +8168,19 @@ function registerWhoamiCommand(root) {
7860
8168
  if (opts.json) {
7861
8169
  console.log(formatJson({ local: localJson, account, server: agent }));
7862
8170
  } else {
7863
- console.log(import_chalk34.default.dim(`Server: ${api.serverUrl}`));
7864
- console.log(import_chalk34.default.bold("\nLocal agent:"));
7865
- console.log(` DID: ${import_chalk34.default.cyan(local.did)}`);
7866
- console.log(` Settlement pubkey: ${import_chalk34.default.cyan(local.settlementPublicKeyB58)}`);
7867
- console.log(` Identity pubkey: ${import_chalk34.default.cyan(local.identityPublicKeyB58)}`);
7868
- console.log(import_chalk34.default.bold("\nAccount:"));
8171
+ console.log(import_chalk36.default.dim(`Server: ${api.serverUrl}`));
8172
+ console.log(import_chalk36.default.bold("\nLocal agent:"));
8173
+ console.log(` DID: ${import_chalk36.default.cyan(local.did)}`);
8174
+ console.log(` Settlement pubkey: ${import_chalk36.default.cyan(local.settlementPublicKeyB58)}`);
8175
+ console.log(` Identity pubkey: ${import_chalk36.default.cyan(local.identityPublicKeyB58)}`);
8176
+ console.log(import_chalk36.default.bold("\nAccount:"));
7869
8177
  if (account) {
7870
- console.log(` Wallet: ${import_chalk34.default.cyan(account.wallet)}`);
8178
+ console.log(` Wallet: ${import_chalk36.default.cyan(account.wallet)}`);
7871
8179
  console.log(` Agents registered: ${account.agentCount}`);
7872
8180
  } else {
7873
- console.log(` ${import_chalk34.default.dim("not logged in (heyarp login)")}`);
8181
+ console.log(` ${import_chalk36.default.dim("not logged in (heyarp login)")}`);
7874
8182
  }
7875
- console.log(import_chalk34.default.bold("\nServer profile:"));
8183
+ console.log(import_chalk36.default.bold("\nServer profile:"));
7876
8184
  console.log(formatJson(agent));
7877
8185
  }
7878
8186
  } catch (err) {
@@ -7884,12 +8192,12 @@ function registerWhoamiCommand(root) {
7884
8192
 
7885
8193
  // src/commands/whois.ts
7886
8194
  var import_sdk30 = require("@heyanon-arp/sdk");
7887
- var import_chalk35 = __toESM(require("chalk"));
8195
+ var import_chalk37 = __toESM(require("chalk"));
7888
8196
  init_api();
7889
8197
  function registerWhoisCommand(root) {
7890
8198
  root.command("whois").description("Resolve an agent name (handle) or DID to its public profile \u2014 DID, description, reputation, liveness.").argument("<name-or-did>", "Agent name (handle) or DID (did:arp:...)").option("--server <url>", "Override ARP server base URL").option("--json", "Emit the full composed profile (DiscoveryProfile) as a single JSON object on stdout.", false).action(async (input, opts) => {
7891
8199
  const api = new ArpApiClient(opts.server);
7892
- progress(opts.json, import_chalk35.default.dim(`Server: ${api.serverUrl}`));
8200
+ progress(opts.json, import_chalk37.default.dim(`Server: ${api.serverUrl}`));
7893
8201
  const profile = await resolveProfile(api, input);
7894
8202
  if (opts.json) {
7895
8203
  jsonOut(profile);
@@ -7912,19 +8220,19 @@ async function resolveProfile(api, input) {
7912
8220
  return api.discoverByName(name);
7913
8221
  }
7914
8222
  function printProfile(p) {
7915
- console.log(`${import_chalk35.default.bold("Name")}: ${import_chalk35.default.cyan(p.name ?? "(unnamed)")}`);
7916
- console.log(`${import_chalk35.default.bold("DID")}: ${import_chalk35.default.cyan(p.did)}`);
7917
- if (p.description) console.log(`${import_chalk35.default.bold("Description")}: ${p.description}`);
7918
- if (p.tags.length > 0) console.log(`${import_chalk35.default.bold("Tags")}: ${p.tags.join(", ")}`);
7919
- console.log(`${import_chalk35.default.bold("Registered")}: ${p.registeredAt}`);
8223
+ console.log(`${import_chalk37.default.bold("Name")}: ${import_chalk37.default.cyan(p.name ?? "(unnamed)")}`);
8224
+ console.log(`${import_chalk37.default.bold("DID")}: ${import_chalk37.default.cyan(p.did)}`);
8225
+ if (p.description) console.log(`${import_chalk37.default.bold("Description")}: ${p.description}`);
8226
+ if (p.tags.length > 0) console.log(`${import_chalk37.default.bold("Tags")}: ${p.tags.join(", ")}`);
8227
+ console.log(`${import_chalk37.default.bold("Registered")}: ${p.registeredAt}`);
7920
8228
  const rep = p.reputation;
7921
- console.log(`${import_chalk35.default.bold("Reputation")}: composite ${rep.scores.composite}/100${rep.computed ? "" : import_chalk35.default.dim(" (cold-start \u2014 no settled cycles yet)")}`);
7922
- console.log(`${import_chalk35.default.bold("Online")}: ${p.liveness.online ? import_chalk35.default.green("yes") : import_chalk35.default.dim("no")}`);
8229
+ console.log(`${import_chalk37.default.bold("Reputation")}: composite ${rep.scores.composite}/100${rep.computed ? "" : import_chalk37.default.dim(" (cold-start \u2014 no settled cycles yet)")}`);
8230
+ console.log(`${import_chalk37.default.bold("Online")}: ${p.liveness.online ? import_chalk37.default.green("yes") : import_chalk37.default.dim("no")}`);
7923
8231
  }
7924
8232
 
7925
8233
  // src/commands/work.ts
7926
8234
  var import_sdk31 = require("@heyanon-arp/sdk");
7927
- var import_chalk36 = __toESM(require("chalk"));
8235
+ var import_chalk38 = __toESM(require("chalk"));
7928
8236
  init_api();
7929
8237
  function registerWorkCommands(root) {
7930
8238
  const cmd = root.command("work").description("Work envelopes inside an ACCEPTED delegation: request / respond");
@@ -7965,11 +8273,11 @@ async function runRequest(recipientDid, delegationId, opts) {
7965
8273
  params
7966
8274
  };
7967
8275
  const body = { type: "work_request", content };
7968
- progress(opts.json, import_chalk36.default.dim(`Server: ${api.serverUrl}`));
7969
- progress(opts.json, import_chalk36.default.dim(`Sender: ${sender.did}`));
7970
- progress(opts.json, import_chalk36.default.dim(`Recipient: ${recipientDid}`));
7971
- progress(opts.json, import_chalk36.default.dim(`Delegation: ${delegationId}`));
7972
- progress(opts.json, import_chalk36.default.dim(`Request id: ${requestId}`));
8276
+ progress(opts.json, import_chalk38.default.dim(`Server: ${api.serverUrl}`));
8277
+ progress(opts.json, import_chalk38.default.dim(`Sender: ${sender.did}`));
8278
+ progress(opts.json, import_chalk38.default.dim(`Recipient: ${recipientDid}`));
8279
+ progress(opts.json, import_chalk38.default.dim(`Delegation: ${delegationId}`));
8280
+ progress(opts.json, import_chalk38.default.dim(`Request id: ${requestId}`));
7973
8281
  const result = await sendWorkEnvelope({ api, sender, recipientDid, body, ttlSeconds, verbose: opts.verbose, server: opts.server });
7974
8282
  if (opts.json) {
7975
8283
  jsonOut({
@@ -7986,10 +8294,10 @@ async function runRequest(recipientDid, delegationId, opts) {
7986
8294
  });
7987
8295
  } else {
7988
8296
  printIngestResult3(result);
7989
- console.log(import_chalk36.default.dim(`
8297
+ console.log(import_chalk38.default.dim(`
7990
8298
  The payee can reply with:`));
7991
- console.log(import_chalk36.default.dim(` heyarp work respond ${result.relationshipId} ${delegationId} ${requestId} --output '<json>'`));
7992
- console.log(import_chalk36.default.dim(` heyarp work respond ${result.relationshipId} ${delegationId} ${requestId} --error CODE:message`));
8299
+ console.log(import_chalk38.default.dim(` heyarp work respond ${result.relationshipId} ${delegationId} ${requestId} --output '<json>'`));
8300
+ console.log(import_chalk38.default.dim(` heyarp work respond ${result.relationshipId} ${delegationId} ${requestId} --error CODE:message`));
7993
8301
  }
7994
8302
  }
7995
8303
  function registerRespond(parent) {
@@ -8024,13 +8332,13 @@ async function runRespond(relationshipId, delegationId, requestId, opts) {
8024
8332
  ...responsePayload
8025
8333
  };
8026
8334
  const body = { type: "work_response", content };
8027
- progress(opts.json, import_chalk36.default.dim(`Server: ${api.serverUrl}`));
8028
- progress(opts.json, import_chalk36.default.dim(`Sender: ${sender.did}`));
8029
- progress(opts.json, import_chalk36.default.dim(`Recipient: ${recipientDid}`));
8030
- progress(opts.json, import_chalk36.default.dim(`Relationship: ${relationshipId}`));
8031
- progress(opts.json, import_chalk36.default.dim(`Delegation: ${delegationId}`));
8032
- progress(opts.json, import_chalk36.default.dim(`Request id: ${requestId}`));
8033
- progress(opts.json, import_chalk36.default.dim(`Outcome: ${responsePayload.output ? "success" : "error"}`));
8335
+ progress(opts.json, import_chalk38.default.dim(`Server: ${api.serverUrl}`));
8336
+ progress(opts.json, import_chalk38.default.dim(`Sender: ${sender.did}`));
8337
+ progress(opts.json, import_chalk38.default.dim(`Recipient: ${recipientDid}`));
8338
+ progress(opts.json, import_chalk38.default.dim(`Relationship: ${relationshipId}`));
8339
+ progress(opts.json, import_chalk38.default.dim(`Delegation: ${delegationId}`));
8340
+ progress(opts.json, import_chalk38.default.dim(`Request id: ${requestId}`));
8341
+ progress(opts.json, import_chalk38.default.dim(`Outcome: ${responsePayload.output ? "success" : "error"}`));
8034
8342
  const result = await sendWorkEnvelope({ api, sender, recipientDid, body, ttlSeconds, verbose: opts.verbose, server: opts.server });
8035
8343
  if (opts.json) {
8036
8344
  jsonOut({
@@ -8071,7 +8379,7 @@ async function sendWorkEnvelope(args) {
8071
8379
  identitySecretKey: signer.identitySecretKey
8072
8380
  });
8073
8381
  if (args.verbose) {
8074
- console.log(import_chalk36.default.bold("\nEnvelope (pre-send):"));
8382
+ console.log(import_chalk38.default.bold("\nEnvelope (pre-send):"));
8075
8383
  console.log(formatJson(envelope));
8076
8384
  }
8077
8385
  try {
@@ -8111,12 +8419,12 @@ async function resolveResponseRecipient(cmdName, api, signer, args) {
8111
8419
  );
8112
8420
  }
8113
8421
  function printIngestResult3(result) {
8114
- console.log(import_chalk36.default.green("\nDelivered."));
8115
- console.log(`${import_chalk36.default.bold("Event id")}: ${import_chalk36.default.cyan(result.eventId)}`);
8116
- console.log(`${import_chalk36.default.bold("Relationship id")}: ${import_chalk36.default.cyan(result.relationshipId)}`);
8117
- console.log(`${import_chalk36.default.bold("Chain index")}: ${import_chalk36.default.cyan(String(result.relationshipEventIndex))}`);
8118
- console.log(`${import_chalk36.default.bold("Server timestamp")}: ${import_chalk36.default.cyan(result.serverTimestamp)}`);
8119
- console.log(`${import_chalk36.default.bold("Server event hash")}: ${import_chalk36.default.cyan(result.serverEventHash)}`);
8422
+ console.log(import_chalk38.default.green("\nDelivered."));
8423
+ console.log(`${import_chalk38.default.bold("Event id")}: ${import_chalk38.default.cyan(result.eventId)}`);
8424
+ console.log(`${import_chalk38.default.bold("Relationship id")}: ${import_chalk38.default.cyan(result.relationshipId)}`);
8425
+ console.log(`${import_chalk38.default.bold("Chain index")}: ${import_chalk38.default.cyan(String(result.relationshipEventIndex))}`);
8426
+ console.log(`${import_chalk38.default.bold("Server timestamp")}: ${import_chalk38.default.cyan(result.serverTimestamp)}`);
8427
+ console.log(`${import_chalk38.default.bold("Server event hash")}: ${import_chalk38.default.cyan(result.serverEventHash)}`);
8120
8428
  }
8121
8429
  function parseJsonObject(cmdName, flagName, raw) {
8122
8430
  let parsed;
@@ -8154,8 +8462,8 @@ function parseParamsInput(cmdName, opts) {
8154
8462
  return parseJsonObject(cmdName, "--params", opts.params ?? "{}");
8155
8463
  }
8156
8464
  function readJsonObjectFile(cmdName, flagName, path) {
8157
- const { existsSync: existsSync7, readFileSync: readFileSync10 } = require("fs");
8158
- if (!existsSync7(path)) {
8465
+ const { existsSync: existsSync8, readFileSync: readFileSync10 } = require("fs");
8466
+ if (!existsSync8(path)) {
8159
8467
  throw new Error(`${cmdName}: ${flagName} file not found at ${path}`);
8160
8468
  }
8161
8469
  let raw;
@@ -8218,7 +8526,7 @@ function parseRequestId(cmdName, raw) {
8218
8526
 
8219
8527
  // src/commands/work-list.ts
8220
8528
  var import_sdk32 = require("@heyanon-arp/sdk");
8221
- var import_chalk37 = __toESM(require("chalk"));
8529
+ var import_chalk39 = __toESM(require("chalk"));
8222
8530
  init_api();
8223
8531
  var ALLOWED_STATES3 = new Set(import_sdk32.WORK_LOG_STATES);
8224
8532
  function registerWorkListCommand(root) {
@@ -8245,9 +8553,9 @@ async function runWorkList(relationshipId, opts) {
8245
8553
  const api = new ArpApiClient(opts.server);
8246
8554
  const sender = resolveSenderAgent("work-list", opts.server, opts.fromDid, opts.from);
8247
8555
  if (!opts.json) {
8248
- console.log(import_chalk37.default.dim(`Server: ${api.serverUrl}`));
8249
- console.log(import_chalk37.default.dim(`Signer: ${sender.did}`));
8250
- console.log(import_chalk37.default.dim(`Relationship: ${relationshipId}`));
8556
+ console.log(import_chalk39.default.dim(`Server: ${api.serverUrl}`));
8557
+ console.log(import_chalk39.default.dim(`Signer: ${sender.did}`));
8558
+ console.log(import_chalk39.default.dim(`Relationship: ${relationshipId}`));
8251
8559
  }
8252
8560
  const query = { limit };
8253
8561
  if (state) query.state = state;
@@ -8260,7 +8568,7 @@ async function runWorkList(relationshipId, opts) {
8260
8568
  return;
8261
8569
  }
8262
8570
  if (rows.length === 0) {
8263
- console.log(import_chalk37.default.dim("\n(no work-logs for this relationship)"));
8571
+ console.log(import_chalk39.default.dim("\n(no work-logs for this relationship)"));
8264
8572
  return;
8265
8573
  }
8266
8574
  console.log("");
@@ -8277,36 +8585,36 @@ async function runWorkList(relationshipId, opts) {
8277
8585
  }));
8278
8586
  }
8279
8587
  const lastId = rows[rows.length - 1].id;
8280
- console.log(import_chalk37.default.dim(`
8588
+ console.log(import_chalk39.default.dim(`
8281
8589
  ${rows.length} work-log row(s). Paginate with --after ${lastId}.`));
8282
8590
  }
8283
8591
  function formatWorkLogLine(w, selfDid, opts = {}) {
8284
8592
  const delegationPart = opts.fullIds ? w.delegationId : idHead3(w.delegationId);
8285
8593
  const requestPart = opts.fullIds ? w.requestId : truncate3(w.requestId, 16);
8286
- const id = import_chalk37.default.bold(`${delegationPart}/${requestPart}`);
8594
+ const id = import_chalk39.default.bold(`${delegationPart}/${requestPart}`);
8287
8595
  const state = colorState2(w.state).padEnd(stateColumnWidth2());
8288
8596
  const peerCallerHead = opts.fullIds ? w.callerDid : didHead5(w.callerDid);
8289
8597
  const peerPayeeHead = opts.fullIds ? w.payeeDid : didHead5(w.payeeDid);
8290
- const direction = w.callerDid === selfDid ? `${import_chalk37.default.bold("me")} \u2192 ${import_chalk37.default.dim(peerPayeeHead)}` : `${import_chalk37.default.dim(peerCallerHead)} \u2192 ${import_chalk37.default.bold("me")}`;
8598
+ const direction = w.callerDid === selfDid ? `${import_chalk39.default.bold("me")} \u2192 ${import_chalk39.default.dim(peerPayeeHead)}` : `${import_chalk39.default.dim(peerCallerHead)} \u2192 ${import_chalk39.default.bold("me")}`;
8291
8599
  const outcome = formatOutcome(w);
8292
8600
  return `${id} ${state} ${direction} ${outcome}`;
8293
8601
  }
8294
8602
  function colorState2(s) {
8295
8603
  switch (s) {
8296
8604
  case import_sdk32.WorkLogStates.REQUESTED:
8297
- return import_chalk37.default.yellow("requested");
8605
+ return import_chalk39.default.yellow("requested");
8298
8606
  case import_sdk32.WorkLogStates.RESPONDED:
8299
- return import_chalk37.default.green("responded");
8607
+ return import_chalk39.default.green("responded");
8300
8608
  }
8301
8609
  }
8302
8610
  function stateColumnWidth2() {
8303
8611
  return 9;
8304
8612
  }
8305
8613
  function formatOutcome(w) {
8306
- if (w.state === import_sdk32.WorkLogStates.REQUESTED) return import_chalk37.default.dim("(in flight)");
8307
- if (w.responseError) return import_chalk37.default.red(`error ${w.responseError.code}: ${truncate3(w.responseError.message, 32)}`);
8308
- if (w.responseOutput) return import_chalk37.default.cyan("ok");
8309
- return import_chalk37.default.dim("(empty response)");
8614
+ if (w.state === import_sdk32.WorkLogStates.REQUESTED) return import_chalk39.default.dim("(in flight)");
8615
+ if (w.responseError) return import_chalk39.default.red(`error ${w.responseError.code}: ${truncate3(w.responseError.message, 32)}`);
8616
+ if (w.responseOutput) return import_chalk39.default.cyan("ok");
8617
+ return import_chalk39.default.dim("(empty response)");
8310
8618
  }
8311
8619
  function idHead3(id) {
8312
8620
  if (id.length <= 12) return id;
@@ -8374,12 +8682,12 @@ function unknownOptionHint(program, err) {
8374
8682
  }
8375
8683
 
8376
8684
  // src/version-gate.ts
8377
- var import_node_fs10 = require("fs");
8378
- var import_node_path7 = require("path");
8685
+ var import_node_fs11 = require("fs");
8686
+ var import_node_path8 = require("path");
8379
8687
  init_paths();
8380
8688
  var CHECK_INTERVAL_MS = 60 * 60 * 1e3;
8381
8689
  var REGISTRY_TIMEOUT_MS = 1500;
8382
- var cacheFile = () => (0, import_node_path7.join)(arpHomeDir(), "update-check.json");
8690
+ var cacheFile = () => (0, import_node_path8.join)(arpHomeDir(), "update-check.json");
8383
8691
  function majorOf(version) {
8384
8692
  return Number.parseInt(version.split(".")[0] ?? "0", 10) || 0;
8385
8693
  }
@@ -8411,7 +8719,7 @@ async function fetchLatest(pkgName) {
8411
8719
  }
8412
8720
  async function resolveLatest(pkgName) {
8413
8721
  try {
8414
- const cached = JSON.parse((0, import_node_fs10.readFileSync)(cacheFile(), "utf8"));
8722
+ const cached = JSON.parse((0, import_node_fs11.readFileSync)(cacheFile(), "utf8"));
8415
8723
  if (typeof cached.latest === "string" && typeof cached.checkedAt === "number" && Date.now() - cached.checkedAt < CHECK_INTERVAL_MS) {
8416
8724
  return cached.latest;
8417
8725
  }
@@ -8421,8 +8729,8 @@ async function resolveLatest(pkgName) {
8421
8729
  if (!fresh) return null;
8422
8730
  try {
8423
8731
  const file = cacheFile();
8424
- (0, import_node_fs10.mkdirSync)((0, import_node_path7.dirname)(file), { recursive: true });
8425
- (0, import_node_fs10.writeFileSync)(file, JSON.stringify({ checkedAt: Date.now(), latest: fresh }));
8732
+ (0, import_node_fs11.mkdirSync)((0, import_node_path8.dirname)(file), { recursive: true });
8733
+ (0, import_node_fs11.writeFileSync)(file, JSON.stringify({ checkedAt: Date.now(), latest: fresh }));
8426
8734
  } catch {
8427
8735
  }
8428
8736
  return fresh;
@@ -8486,6 +8794,7 @@ async function main() {
8486
8794
  registerDidDocCommand(program);
8487
8795
  registerProfileCommand(program);
8488
8796
  registerDoctorCommand(program);
8797
+ registerSelftestCommand(program);
8489
8798
  registerAssetsCommand(program);
8490
8799
  registerEscrowCommands(program);
8491
8800
  registerWhoamiCommand(program);
@@ -8508,6 +8817,7 @@ async function main() {
8508
8817
  registerReceiptCommands(program);
8509
8818
  registerReceiptsCommand(program);
8510
8819
  registerReputationCommand(program);
8820
+ registerStatsCommand(program);
8511
8821
  registerWalletCommands(program);
8512
8822
  (0, import_shield3.installMiddleware)(program);
8513
8823
  try {