@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 +43 -77
- package/dist/cli.js.map +1 -1
- package/package.json +2 -2
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.
|
|
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 +
|
|
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
|
-
|
|
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
|
-
"
|
|
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,
|
|
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 ? {
|
|
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
|
-
|
|
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
|