@heyanon-arp/cli 0.0.29 → 0.0.31

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
@@ -337,6 +337,11 @@ var init_api = __esm({
337
337
  if (query?.accountId !== void 0) params.set("accountId", query.accountId);
338
338
  if (query?.accepts !== void 0) params.set("accepts", query.accepts);
339
339
  if (query?.online) params.set("online", "true");
340
+ if (query?.trustedOnly) params.set("trustedOnly", "true");
341
+ if (query?.includeUnproven === false) params.set("includeUnproven", "false");
342
+ if (query?.minOnchainCycles !== void 0) params.set("minOnchainCycles", String(query.minOnchainCycles));
343
+ if (query?.minCompletedAsPayee !== void 0) params.set("minCompletedAsPayee", String(query.minCompletedAsPayee));
344
+ if (query?.minDistinctCounterparts !== void 0) params.set("minDistinctCounterparts", String(query.minDistinctCounterparts));
340
345
  if (query?.sort !== void 0) params.set("sort", query.sort);
341
346
  if (query?.page !== void 0) params.set("page", String(query.page));
342
347
  if (query?.after !== void 0) params.set("after", query.after);
@@ -736,7 +741,7 @@ var import_commander = require("commander");
736
741
  // package.json
737
742
  var package_default = {
738
743
  name: "@heyanon-arp/cli",
739
- version: "0.0.29",
744
+ version: "0.0.31",
740
745
  description: "Command-line client for the Agent Relationship Protocol \u2014 register agents, sign envelopes, run escrowed work cycles on Solana.",
741
746
  license: "MIT",
742
747
  keywords: ["arp", "agent-relationship-protocol", "did", "solana", "escrow", "ed25519", "agents", "a2a", "cli"],
@@ -1017,7 +1022,7 @@ function requireCredential(commandName, serverUrl) {
1017
1022
 
1018
1023
  // src/state.ts
1019
1024
  init_paths();
1020
- var STATE_WARNING = "DO NOT COMMIT \u2014 contains private keys (Ed25519 + derived scrypt).";
1025
+ var STATE_WARNING = "DO NOT COMMIT \u2014 contains private keys (Ed25519 identity + settlement).";
1021
1026
  function stateFilePath() {
1022
1027
  return (0, import_node_path4.join)(arpHomeDir(), "agents.json");
1023
1028
  }
@@ -1130,9 +1135,6 @@ function toKeyBundle(agent, exportedAt) {
1130
1135
  identitySecretKeyB64: agent.identitySecretKeyB64,
1131
1136
  settlementPublicKeyB58: agent.settlementPublicKeyB58,
1132
1137
  settlementSecretKeyB64: agent.settlementSecretKeyB64,
1133
- scryptKeyB64: agent.scryptKeyB64,
1134
- scryptSaltB64: agent.scryptSaltB64,
1135
- scryptSaltId: agent.scryptSaltId,
1136
1138
  ownerWallet: agent.ownerWallet,
1137
1139
  exportedAt
1138
1140
  };
@@ -1142,16 +1144,7 @@ function validateKeyBundle(raw) {
1142
1144
  throw new Error("recover: key file is not a JSON object");
1143
1145
  }
1144
1146
  const o = raw;
1145
- const required = [
1146
- "did",
1147
- "identityPublicKeyB58",
1148
- "identitySecretKeyB64",
1149
- "settlementPublicKeyB58",
1150
- "settlementSecretKeyB64",
1151
- "scryptKeyB64",
1152
- "scryptSaltB64",
1153
- "scryptSaltId"
1154
- ];
1147
+ const required = ["did", "identityPublicKeyB58", "identitySecretKeyB64", "settlementPublicKeyB58", "settlementSecretKeyB64"];
1155
1148
  for (const f of required) {
1156
1149
  if (typeof o[f] !== "string" || o[f].length === 0) {
1157
1150
  throw new Error(`recover: key file is missing or has an invalid '${f}' (expected a non-empty string) \u2014 is this a 'heyarp keys export' file?`);
@@ -1166,9 +1159,6 @@ function validateKeyBundle(raw) {
1166
1159
  identitySecretKeyB64: o.identitySecretKeyB64,
1167
1160
  settlementPublicKeyB58: o.settlementPublicKeyB58,
1168
1161
  settlementSecretKeyB64: o.settlementSecretKeyB64,
1169
- scryptKeyB64: o.scryptKeyB64,
1170
- scryptSaltB64: o.scryptSaltB64,
1171
- scryptSaltId: o.scryptSaltId,
1172
1162
  ownerWallet: o.ownerWallet,
1173
1163
  exportedAt: typeof o.exportedAt === "string" ? o.exportedAt : ""
1174
1164
  };
@@ -1309,7 +1299,7 @@ ${verb}.`));
1309
1299
  function registerAgentsCommand(root) {
1310
1300
  const agents = root.command("agents").description(
1311
1301
  "Search published agents (reputation-ranked) \u2014 ONLINE-only by default (seen within the liveness window); --all includes offline. Filter by tag / text / creator account / accepted asset."
1312
- ).option("--server <url>", "Override ARP server base URL").option("--tag <s>", "Filter by capability tag \u2014 repeatable; AND-semantics across tags", accumulate2, []).option("--query <s>", "Full-text search over name + description").option("--account-id <wallet>", "Filter to a creator account (owner wallet, base58)").option("--accepts <asset>", "Filter to agents that accept this asset \u2014 shorthand (SOL:solana-devnet) or CAIP-19. Matches accept-anything agents too.").option("--all", "Include offline agents too \u2014 by default only agents seen within the ~5-min liveness window are listed", false).option("--sort <mode>", "reputation (default) | recent | created", "reputation").option("--page <n>", "Zero-based page index (reputation/recent sorts)", "0").option("--after <id>", "Cursor for --sort created: the previous page's last `id`").option("--limit <n>", "Max rows to return (1..100)", "20").option(
1302
+ ).option("--server <url>", "Override ARP server base URL").option("--tag <s>", "Filter by capability tag \u2014 repeatable; AND-semantics across tags", accumulate2, []).option("--query <s>", "Full-text search over name + description").option("--account-id <wallet>", "Filter to a creator account (owner wallet, base58)").option("--accepts <asset>", "Filter to agents that accept this asset \u2014 shorthand (SOL:solana-devnet) or CAIP-19. Matches accept-anything agents too.").option("--all", "Include offline agents too \u2014 by default only agents seen within the ~5-min liveness window are listed", false).option("--trusted-only", "Return only platform-trusted agents (the manual allow-list flag \u2014 NOT earned reputation)", false).option("--proven", "Only agents with real settled on-chain history \u2014 hard-excludes cold-start (unproven) agents", false).option("--min-cycles <n>", "Hard filter: minimum settled on-chain cycles").option("--min-completed <n>", "Hard filter: minimum completed delegations AS THE PAYEE (paid work delivered)").option("--min-counterparts <n>", "Hard filter: minimum distinct (owner-resolved) counterparts \u2014 anti-wash").option("--sort <mode>", "reputation (default) | recent | created", "reputation").option("--page <n>", "Zero-based page index (reputation/recent sorts)", "0").option("--after <id>", "Cursor for --sort created: the previous page's last `id`").option("--limit <n>", "Max rows to return (1..100)", "20").option(
1313
1303
  "--verbose",
1314
1304
  '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)',
1315
1305
  false
@@ -1347,6 +1337,11 @@ async function runAgents(opts) {
1347
1337
  if (opts.accountId) query.accountId = opts.accountId;
1348
1338
  if (opts.accepts) query.accepts = resolveAcceptsAsset(opts.accepts);
1349
1339
  if (!opts.all) query.online = true;
1340
+ if (opts.trustedOnly) query.trustedOnly = true;
1341
+ if (opts.proven) query.includeUnproven = false;
1342
+ if (opts.minCycles !== void 0) query.minOnchainCycles = parseNonNegInt(opts.minCycles, "--min-cycles");
1343
+ if (opts.minCompleted !== void 0) query.minCompletedAsPayee = parseNonNegInt(opts.minCompleted, "--min-completed");
1344
+ if (opts.minCounterparts !== void 0) query.minDistinctCounterparts = parseNonNegInt(opts.minCounterparts, "--min-counterparts");
1350
1345
  if (sort === import_sdk3.DiscoverySorts.CREATED) {
1351
1346
  if (opts.after) query.after = opts.after;
1352
1347
  } else {
@@ -1402,7 +1397,21 @@ function formatAgentLine(a, opts = {}) {
1402
1397
  const description = a.description ? `\u2014 ${import_chalk3.default.dim(truncate(sanitizeForTerminal(a.description), 60))}` : "";
1403
1398
  const rep = `${import_chalk3.default.cyan(`rep${a.reputation.composite.toFixed(0)}`)}${a.reputation.computed ? "" : import_chalk3.default.dim("*")}`;
1404
1399
  const live = a.liveness.online ? import_chalk3.default.green("\u25CF") : import_chalk3.default.dim("\u25CB");
1405
- return `${import_chalk3.default.dim(idDisplay)} ${import_chalk3.default.cyan(a.did)} ${rep} ${live} ${import_chalk3.default.magenta(tags)} ${name} ${description}`.trim();
1400
+ const badge = formatBadge(a.badge);
1401
+ const trust = a.trusted ? ` ${import_chalk3.default.blue("\u2713trusted")}` : "";
1402
+ return `${import_chalk3.default.dim(idDisplay)} ${import_chalk3.default.cyan(a.did)} ${rep} ${badge} ${live} ${import_chalk3.default.magenta(tags)} ${name}${trust} ${description}`.trim();
1403
+ }
1404
+ function formatBadge(badge) {
1405
+ switch (badge) {
1406
+ case "proven":
1407
+ return import_chalk3.default.green("proven");
1408
+ case "limited":
1409
+ return import_chalk3.default.yellow("limited");
1410
+ case "flagged":
1411
+ return import_chalk3.default.red("flagged");
1412
+ default:
1413
+ return import_chalk3.default.dim("new");
1414
+ }
1406
1415
  }
1407
1416
  function truncate(s, max) {
1408
1417
  if (s.length <= max) return s;
@@ -1427,6 +1436,13 @@ function parsePage(raw) {
1427
1436
  }
1428
1437
  return n;
1429
1438
  }
1439
+ function parseNonNegInt(raw, flag) {
1440
+ const n = Number(raw);
1441
+ if (!Number.isFinite(n) || !Number.isInteger(n) || n < 0) {
1442
+ throw new Error(`agents: ${flag} must be a non-negative integer (got '${raw}')`);
1443
+ }
1444
+ return n;
1445
+ }
1430
1446
  function resolveAcceptsAsset(input) {
1431
1447
  const resolved = (0, import_sdk3.resolveAsset)(input);
1432
1448
  if (!resolved) {
@@ -6908,9 +6924,6 @@ async function runRecover(opts) {
6908
6924
  identitySecretKeyB64: bundle.identitySecretKeyB64,
6909
6925
  settlementPublicKeyB58: bundle.settlementPublicKeyB58,
6910
6926
  settlementSecretKeyB64: bundle.settlementSecretKeyB64,
6911
- scryptKeyB64: bundle.scryptKeyB64,
6912
- scryptSaltB64: bundle.scryptSaltB64,
6913
- scryptSaltId: bundle.scryptSaltId,
6914
6927
  currentAttestationId: row.currentAttestationId,
6915
6928
  name: row.name ?? void 0,
6916
6929
  description: row.description ?? void 0,
@@ -6928,7 +6941,6 @@ async function runRecover(opts) {
6928
6941
  }
6929
6942
 
6930
6943
  // src/commands/register.ts
6931
- var import_node_crypto4 = require("crypto");
6932
6944
  var import_node_fs9 = require("fs");
6933
6945
  var import_sdk25 = require("@heyanon-arp/sdk");
6934
6946
  var import_chalk28 = __toESM(require("chalk"));
@@ -6940,28 +6952,10 @@ function registerRegisterCommand(root) {
6940
6952
  [
6941
6953
  "Register a new ARP agent. Interactive by default; pass any of the profile flags below to skip the matching prompt.",
6942
6954
  "",
6943
- "`--password` is REQUIRED \u2014 must be at least 8 characters. In interactive mode (--yes omitted) the CLI prompts for it; with --yes it must be passed explicitly.",
6955
+ "No password \u2014 the agent identity key self-signs the owner key-link; ownership is your `heyarp login` wallet.",
6944
6956
  "`--yes` is the non-interactive switch \u2014 every required field must arrive via flags (no prompts). Use this for scripted setups."
6945
6957
  ].join("\n")
6946
- ).option("--server <url>", "Override ARP server base URL").option("--from-keys <file>", "Load identity + settlement keys from a JSON file instead of generating").option("--name <s>", "Unique handle \u2014 lowercase a-z0-9_, 3-32 chars, immutable (skips the name prompt)").option("--description <s>", "Description (skips the description prompt)").option("--tag <s>", "Capability tag \u2014 repeatable, e.g. --tag translation --tag fr", accumulate3, []).option(
6947
- "--password <s>",
6948
- // `--password` puts the secret in `argv` — visible via
6949
- // `ps aux` / kernel process table on shared hosts,
6950
- // recorded by `/proc/<pid>/cmdline`, and almost always
6951
- // logged by CI runners (e.g. GitHub Actions echoes the
6952
- // full command). Safer alternatives:
6953
- // • interactive prompt (default) — never written anywhere
6954
- // • `HEYARP_PASSWORD` env var (tracked) reads from env so
6955
- // the secret stays out of argv even in scripts
6956
- // Treat `--password <s>` as a one-off local-dev affordance;
6957
- // do NOT use it in CI pipelines without a secret-redacting
6958
- // runner.
6959
- "Owner password \u2014 MUST be at least 8 characters. REQUIRED when --yes is set; otherwise the CLI prompts for it. WARNING: --password puts the secret in process argv (visible in `ps`, /proc/<pid>/cmdline, and CI logs that echo commands). Prefer the interactive prompt unless your CI runner redacts secrets in command echoes. HEYARP_PASSWORD env var support is tracked."
6960
- ).option(
6961
- "--yes",
6962
- "Strict non-interactive: fail if any required field is still missing after merging flags. With --yes, --password must be supplied explicitly (>= 8 chars).",
6963
- false
6964
- ).option(
6958
+ ).option("--server <url>", "Override ARP server base URL").option("--from-keys <file>", "Load identity + settlement keys from a JSON file instead of generating").option("--name <s>", "Unique handle \u2014 lowercase a-z0-9_, 3-32 chars, immutable (skips the name prompt)").option("--description <s>", "Description (skips the description prompt)").option("--tag <s>", "Capability tag \u2014 repeatable, e.g. --tag translation --tag fr", accumulate3, []).option("--yes", "Strict non-interactive: fail if any required field (--name) is still missing after merging flags.", false).option(
6965
6959
  "--json",
6966
6960
  // Emit a single JSON object instead of human-friendly
6967
6961
  // success prints. Output shape:
@@ -6998,9 +6992,6 @@ async function runRegister(opts, deps = defaultRegisterDeps) {
6998
6992
  const did = (0, import_sdk25.formatDid)(keys.identityPublicKey);
6999
6993
  if (!opts.json) console.log(import_chalk28.default.dim(`DID will be: ${did}`));
7000
6994
  const answers = await mergeAnswers(opts);
7001
- const scryptSalt = (0, import_node_crypto4.randomBytes)(16);
7002
- if (!opts.json) console.log(import_chalk28.default.dim("Deriving scrypt key, this may take a moment..."));
7003
- const scryptKey = (0, import_sdk25.deriveScryptKey)(answers.password, new Uint8Array(scryptSalt));
7004
6995
  const challenge = await api.issueChallenge("register");
7005
6996
  const challengeBytes = base64UrlNoPadDecode(challenge.challengeB64);
7006
6997
  if (challengeBytes.length !== 32) {
@@ -7014,7 +7005,6 @@ async function runRegister(opts, deps = defaultRegisterDeps) {
7014
7005
  signature: Buffer.from(challengeSig).toString("base64")
7015
7006
  });
7016
7007
  const settlementPublicKeyB58 = (0, import_sdk25.base58btcEncode)(keys.settlementPublicKey);
7017
- const scryptSaltId = (0, import_sdk25.uuidV4)();
7018
7008
  const payload = {
7019
7009
  purpose: import_sdk25.Purpose.KEY_LINK,
7020
7010
  agent_did: did,
@@ -7025,18 +7015,15 @@ async function runRegister(opts, deps = defaultRegisterDeps) {
7025
7015
  created_at: (0, import_sdk25.rfc3339)(),
7026
7016
  nonce: (0, import_sdk25.senderNonce)()
7027
7017
  };
7028
- const attestation = (0, import_sdk25.signKeyLinkAttestation)({ payload, scryptKey, scryptSaltId });
7018
+ const attestation = (0, import_sdk25.signKeyLinkAttestation)({ payload, identitySecretKey: keys.identitySecretKey });
7029
7019
  const body = {
7030
7020
  challengeId: challenge.challengeId,
7031
7021
  identityPublicKey: identityPublicKeyB58,
7032
7022
  settlementPublicKey: settlementPublicKeyB58,
7033
7023
  ownerAttestation: {
7034
7024
  payload: attestation.payload,
7035
- sig: attestation.sig,
7036
- scrypt_salt_id: attestation.scrypt_salt_id
7025
+ sig: attestation.sig
7037
7026
  },
7038
- scryptKeyB64: Buffer.from(scryptKey).toString("base64"),
7039
- scryptSaltB64: Buffer.from(scryptSalt).toString("base64"),
7040
7027
  name: answers.name,
7041
7028
  description: answers.description ? answers.description : void 0,
7042
7029
  tags: answers.tags.length > 0 ? answers.tags : void 0
@@ -7047,9 +7034,6 @@ async function runRegister(opts, deps = defaultRegisterDeps) {
7047
7034
  identitySecretKeyB64: Buffer.from(keys.identitySecretKey).toString("base64"),
7048
7035
  settlementPublicKeyB58,
7049
7036
  settlementSecretKeyB64: Buffer.from(keys.settlementSecretKey).toString("base64"),
7050
- scryptKeyB64: Buffer.from(scryptKey).toString("base64"),
7051
- scryptSaltB64: Buffer.from(scryptSalt).toString("base64"),
7052
- scryptSaltId,
7053
7037
  // Placeholder until the server confirms registration and returns
7054
7038
  // the canonical attestation id (finalized in Step 8 below).
7055
7039
  currentAttestationId: "",
@@ -7128,32 +7112,15 @@ Local state saved to ${arpHomeDir()}/agents.json (mode 0600).`));
7128
7112
  }
7129
7113
  }
7130
7114
  async function mergeAnswers(opts) {
7131
- const need = opts.yes ? { password: false, name: false, description: false, tagsCsv: false } : {
7132
- password: opts.password === void 0,
7115
+ const need = opts.yes ? { name: false, description: false, tagsCsv: false } : {
7133
7116
  name: opts.name === void 0,
7134
7117
  description: opts.description === void 0,
7135
7118
  tagsCsv: opts.tag === void 0 || opts.tag.length === 0
7136
7119
  };
7137
- if (opts.yes) {
7138
- const missing = [];
7139
- if (opts.password === void 0) missing.push("--password");
7140
- if (opts.name === void 0) missing.push("--name");
7141
- if (missing.length > 0) {
7142
- throw new Error(`register --yes: missing required flag${missing.length > 1 ? "s" : ""}: ${missing.join(", ")}`);
7143
- }
7144
- }
7145
- if (opts.password !== void 0 && opts.password.length < 8) {
7146
- throw new Error("register --password: password must be at least 8 characters");
7120
+ if (opts.yes && opts.name === void 0) {
7121
+ throw new Error("register --yes: missing required flag: --name");
7147
7122
  }
7148
7123
  const promptDefs = [];
7149
- if (need.password) {
7150
- promptDefs.push({
7151
- type: "password",
7152
- name: "password",
7153
- message: "Owner password (used to derive the scrypt key)",
7154
- validate: (v) => v.length >= 8 ? true : "must be at least 8 characters"
7155
- });
7156
- }
7157
7124
  if (need.name) {
7158
7125
  promptDefs.push({
7159
7126
  type: "text",
@@ -7187,7 +7154,6 @@ async function mergeAnswers(opts) {
7187
7154
  const tags = (opts.tag && opts.tag.length > 0 ? opts.tag : parseTagsCsv(typeof prompted.tagsCsv === "string" ? prompted.tagsCsv : "")).map((t) => t.trim().toLowerCase()).filter((t) => t.length > 0);
7188
7155
  const name = normalizeAndValidateName(opts.name ?? prompted.name);
7189
7156
  return {
7190
- password: opts.password ?? prompted.password,
7191
7157
  name,
7192
7158
  description: opts.description ?? prompted.description ?? "",
7193
7159
  tags