@heyanon-arp/cli 0.0.16 → 0.0.18
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 +1043 -847
- package/dist/cli.js.map +1 -1
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -345,6 +345,10 @@ var init_api = __esm({
|
|
|
345
345
|
async discoverProfile(did) {
|
|
346
346
|
return this.get(`/v1/discovery/agents/${encodeURIComponent(did)}/profile`);
|
|
347
347
|
}
|
|
348
|
+
/** Public `GET /v1/discovery/agents/by-name/:name`. Resolves a unique name → composed profile (incl. DID). 404 if unknown. */
|
|
349
|
+
async discoverByName(name) {
|
|
350
|
+
return this.get(`/v1/discovery/agents/by-name/${encodeURIComponent(name)}`);
|
|
351
|
+
}
|
|
348
352
|
/**
|
|
349
353
|
* Public `GET /v1/escrow/config`. Returns the live on-chain V2
|
|
350
354
|
* Config PDA (fees / pause / stakes / windows). No auth.
|
|
@@ -722,7 +726,7 @@ var import_simple_update_notifier = __toESM(require("simple-update-notifier"));
|
|
|
722
726
|
// package.json
|
|
723
727
|
var package_default = {
|
|
724
728
|
name: "@heyanon-arp/cli",
|
|
725
|
-
version: "0.0.
|
|
729
|
+
version: "0.0.18",
|
|
726
730
|
description: "Command-line client for the Agent Relationship Protocol \u2014 register agents, sign envelopes, run escrowed work cycles on Solana.",
|
|
727
731
|
license: "MIT",
|
|
728
732
|
keywords: ["arp", "agent-relationship-protocol", "did", "solana", "escrow", "ed25519", "agents", "a2a", "cli"],
|
|
@@ -767,7 +771,7 @@ var package_default = {
|
|
|
767
771
|
};
|
|
768
772
|
|
|
769
773
|
// src/commands/agents.ts
|
|
770
|
-
var
|
|
774
|
+
var import_sdk3 = require("@heyanon-arp/sdk");
|
|
771
775
|
var import_chalk3 = __toESM(require("chalk"));
|
|
772
776
|
init_api();
|
|
773
777
|
|
|
@@ -804,6 +808,14 @@ function onboardingHelpFooter() {
|
|
|
804
808
|
`${import_chalk.default.dim("Then:")} ${import_chalk.default.cyan("heyarp register")} ${import_chalk.default.dim("\u2192 handshake \u2192 delegation \u2192 work \u2192 receipt \u2192 on-chain claim.")}`
|
|
805
809
|
].join("\n");
|
|
806
810
|
}
|
|
811
|
+
function optionPlacementHelpNote() {
|
|
812
|
+
return [
|
|
813
|
+
"",
|
|
814
|
+
`${import_chalk.default.bold("Option placement:")} only ${import_chalk.default.cyan("--trace")}, ${import_chalk.default.cyan("--help")}, ${import_chalk.default.cyan("--version")} are global (before the command).`,
|
|
815
|
+
`Everything else \u2014 ${import_chalk.default.cyan("--json")}, ${import_chalk.default.cyan("--from-did")}, ${import_chalk.default.cyan("--verbose")}, ${import_chalk.default.cyan("--server")}, \u2026 \u2014 is a command option and goes AFTER the command:`,
|
|
816
|
+
` ${import_chalk.default.cyan("heyarp <command> [options]")} ${import_chalk.default.dim("e.g. heyarp relationships --json --from-did did:arp:\u2026")}`
|
|
817
|
+
].join("\n");
|
|
818
|
+
}
|
|
807
819
|
function toCliErrorJson(err, includeStack = false) {
|
|
808
820
|
const { ApiError: ApiError2 } = (init_api(), __toCommonJS(api_exports));
|
|
809
821
|
if (err instanceof ApiError2) {
|
|
@@ -821,7 +833,9 @@ function toCliErrorJson(err, includeStack = false) {
|
|
|
821
833
|
}
|
|
822
834
|
function emitError(err, opts) {
|
|
823
835
|
if (opts.json) {
|
|
824
|
-
|
|
836
|
+
const obj = toCliErrorJson(err, opts.verbose);
|
|
837
|
+
if (opts.hint) obj.hint = opts.hint;
|
|
838
|
+
console.error(JSON.stringify(obj));
|
|
825
839
|
return;
|
|
826
840
|
}
|
|
827
841
|
const { ApiError: ApiError2 } = (init_api(), __toCommonJS(api_exports));
|
|
@@ -830,6 +844,7 @@ function emitError(err, opts) {
|
|
|
830
844
|
} else {
|
|
831
845
|
console.error(formatGenericError(err, opts.verbose));
|
|
832
846
|
}
|
|
847
|
+
if (opts.hint) console.error(`${import_chalk.default.yellow("hint")}: ${opts.hint}`);
|
|
833
848
|
}
|
|
834
849
|
function emitActionError(err, command) {
|
|
835
850
|
let root = command;
|
|
@@ -901,6 +916,7 @@ function formatAgentsTable(rows) {
|
|
|
901
916
|
// src/state.ts
|
|
902
917
|
var import_node_fs3 = require("fs");
|
|
903
918
|
var import_node_path4 = require("path");
|
|
919
|
+
var import_sdk2 = require("@heyanon-arp/sdk");
|
|
904
920
|
init_api();
|
|
905
921
|
|
|
906
922
|
// src/credentials.ts
|
|
@@ -1129,9 +1145,25 @@ function warnIfForeignOwner(agent, serverUrl) {
|
|
|
1129
1145
|
function resolveSenderAgent(cmdName, serverOverride, explicitFromDid) {
|
|
1130
1146
|
const resolvedServerUrl = resolveServerUrl(serverOverride);
|
|
1131
1147
|
if (explicitFromDid) {
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1148
|
+
if (explicitFromDid.startsWith("did:arp:")) {
|
|
1149
|
+
const agent = loadAgentOrThrow(serverOverride, explicitFromDid);
|
|
1150
|
+
warnIfForeignOwner(agent, resolvedServerUrl);
|
|
1151
|
+
return agent;
|
|
1152
|
+
}
|
|
1153
|
+
const wanted = (0, import_sdk2.normalizeName)(explicitFromDid);
|
|
1154
|
+
const named = listAgents().filter((row) => row.serverUrl === resolvedServerUrl && row.agent.name === wanted);
|
|
1155
|
+
if (named.length === 1) {
|
|
1156
|
+
warnIfForeignOwner(named[0].agent, resolvedServerUrl);
|
|
1157
|
+
return named[0].agent;
|
|
1158
|
+
}
|
|
1159
|
+
if (named.length === 0) {
|
|
1160
|
+
throw new Error(`${cmdName}: no local agent named '${wanted}' for ${resolvedServerUrl}. Pass its did:arp: DID, or register/recover that agent locally first.`);
|
|
1161
|
+
}
|
|
1162
|
+
const dups = named.map((row) => ` ${row.agent.did}`).join("\n");
|
|
1163
|
+
throw new Error(
|
|
1164
|
+
`${cmdName}: ${named.length} local agents share the name '${wanted}' for ${resolvedServerUrl} \u2014 ambiguous. Pass the did:arp: DID instead. Candidates:
|
|
1165
|
+
${dups}`
|
|
1166
|
+
);
|
|
1135
1167
|
}
|
|
1136
1168
|
const onServer = listAgents().filter((row) => row.serverUrl === resolvedServerUrl);
|
|
1137
1169
|
if (onServer.length === 1) {
|
|
@@ -1162,19 +1194,28 @@ function listAgents() {
|
|
|
1162
1194
|
var import_chalk2 = __toESM(require("chalk"));
|
|
1163
1195
|
init_api();
|
|
1164
1196
|
function registerLifecycleCommands(root) {
|
|
1165
|
-
root.command("update").description("Update an agent profile (
|
|
1197
|
+
root.command("update").description("Update an agent profile (description / tags). At least one flag is required. The agent name is immutable and cannot be changed.").argument("[did]", "Agent DID (did:arp:...) \u2014 optional when --from-did is given OR exactly one agent is registered for the resolved server.").option("--server <url>", "Override ARP server base URL").option("--from-did <did>", "Alias for the positional <did> \u2014 accepted for consistency with other signed commands. Must match the positional if both are given.").option("--description <s>", "New description").option("--tag <s>", "Capability tag \u2014 REPLACES the existing list. Repeatable: --tag translation --tag fr", accumulate, []).option("--clear-tags", "Drop all tags (cannot be combined with --tag)", false).option("--json", "Machine-readable mode \u2014 emit the updated profile as a single JSON object on stdout (AgentPublic). Prelude moves to stderr. ", false).action(
|
|
1166
1198
|
async (did, opts) => {
|
|
1199
|
+
if (did !== void 0 && opts.fromDid !== void 0 && did !== opts.fromDid) {
|
|
1200
|
+
throw new Error(`update: positional <did> (${did}) and --from-did (${opts.fromDid}) disagree \u2014 pass only one`);
|
|
1201
|
+
}
|
|
1202
|
+
const explicitDid = did ?? opts.fromDid;
|
|
1203
|
+
const targetDid = (explicitDid !== void 0 ? loadAgentOrThrow(opts.server, explicitDid) : resolveSenderAgent("update", opts.server, void 0)).did;
|
|
1167
1204
|
const body = buildUpdateBody(opts);
|
|
1168
1205
|
if (Object.keys(body).length === 0) {
|
|
1169
|
-
throw new Error("update: pass at least one of --
|
|
1206
|
+
throw new Error("update: pass at least one of --description / --tag / --clear-tags");
|
|
1170
1207
|
}
|
|
1171
|
-
const agent = await actSigned(
|
|
1172
|
-
updateAgentLocal(opts.server,
|
|
1208
|
+
const agent = await actSigned(targetDid, opts.server, opts.json, (api, signer) => api.updateAgent(targetDid, body, signer));
|
|
1209
|
+
updateAgentLocal(opts.server, targetDid, {
|
|
1173
1210
|
name: agent.name,
|
|
1174
1211
|
description: agent.description,
|
|
1175
1212
|
tags: agent.tags
|
|
1176
1213
|
});
|
|
1177
|
-
|
|
1214
|
+
if (opts.json) {
|
|
1215
|
+
jsonOut(agent);
|
|
1216
|
+
} else {
|
|
1217
|
+
printAgent("Updated", agent);
|
|
1218
|
+
}
|
|
1178
1219
|
}
|
|
1179
1220
|
);
|
|
1180
1221
|
}
|
|
@@ -1186,7 +1227,6 @@ function buildUpdateBody(opts) {
|
|
|
1186
1227
|
throw new Error("update: --clear-tags cannot be combined with --tag");
|
|
1187
1228
|
}
|
|
1188
1229
|
const body = {};
|
|
1189
|
-
if (opts.name !== void 0) body.name = opts.name;
|
|
1190
1230
|
if (opts.description !== void 0) body.description = opts.description;
|
|
1191
1231
|
if (opts.clearTags) {
|
|
1192
1232
|
body.tags = [];
|
|
@@ -1195,11 +1235,11 @@ function buildUpdateBody(opts) {
|
|
|
1195
1235
|
}
|
|
1196
1236
|
return body;
|
|
1197
1237
|
}
|
|
1198
|
-
async function actSigned(did, serverOverride, act) {
|
|
1238
|
+
async function actSigned(did, serverOverride, json, act) {
|
|
1199
1239
|
const local = loadAgentOrThrow(serverOverride, did);
|
|
1200
1240
|
const api = new ArpApiClient(serverOverride);
|
|
1201
|
-
|
|
1202
|
-
|
|
1241
|
+
progress(json, import_chalk2.default.dim(`Server: ${api.serverUrl}`));
|
|
1242
|
+
progress(json, import_chalk2.default.dim(`Signer: ${local.did}`));
|
|
1203
1243
|
const signer = makeSigner(local);
|
|
1204
1244
|
return act(api, signer);
|
|
1205
1245
|
}
|
|
@@ -1245,10 +1285,10 @@ function registerAgentsCommand(root) {
|
|
|
1245
1285
|
}
|
|
1246
1286
|
async function runAgents(opts) {
|
|
1247
1287
|
const limit = parseLimit(opts.limit);
|
|
1248
|
-
if (opts.sort && opts.sort !==
|
|
1288
|
+
if (opts.sort && opts.sort !== import_sdk3.DiscoverySorts.REPUTATION && opts.sort !== import_sdk3.DiscoverySorts.RECENT && opts.sort !== import_sdk3.DiscoverySorts.CREATED) {
|
|
1249
1289
|
throw new Error(`agents: --sort must be 'reputation', 'recent', or 'created' (got '${opts.sort}')`);
|
|
1250
1290
|
}
|
|
1251
|
-
const sort = opts.sort ===
|
|
1291
|
+
const sort = opts.sort === import_sdk3.DiscoverySorts.RECENT ? import_sdk3.DiscoverySorts.RECENT : opts.sort === import_sdk3.DiscoverySorts.CREATED ? import_sdk3.DiscoverySorts.CREATED : import_sdk3.DiscoverySorts.REPUTATION;
|
|
1252
1292
|
const api = new ArpApiClient(opts.server);
|
|
1253
1293
|
progress(opts.json, import_chalk3.default.dim(`Server: ${api.serverUrl}`));
|
|
1254
1294
|
const query = { limit, sort };
|
|
@@ -1257,7 +1297,7 @@ async function runAgents(opts) {
|
|
|
1257
1297
|
if (opts.accountId) query.accountId = opts.accountId;
|
|
1258
1298
|
if (opts.accepts) query.accepts = resolveAcceptsAsset(opts.accepts);
|
|
1259
1299
|
if (opts.online) query.online = true;
|
|
1260
|
-
if (sort ===
|
|
1300
|
+
if (sort === import_sdk3.DiscoverySorts.CREATED) {
|
|
1261
1301
|
if (opts.after) query.after = opts.after;
|
|
1262
1302
|
} else {
|
|
1263
1303
|
query.page = parsePage(opts.page);
|
|
@@ -1296,10 +1336,10 @@ ${rule}`);
|
|
|
1296
1336
|
`);
|
|
1297
1337
|
}
|
|
1298
1338
|
if (pagination.hasMore) {
|
|
1299
|
-
if (sort ===
|
|
1339
|
+
if (sort === import_sdk3.DiscoverySorts.CREATED && pagination.nextCursor) {
|
|
1300
1340
|
console.log(import_chalk3.default.dim(`
|
|
1301
1341
|
Next page: re-run with --after ${pagination.nextCursor}`));
|
|
1302
|
-
} else if (sort !==
|
|
1342
|
+
} else if (sort !== import_sdk3.DiscoverySorts.CREATED) {
|
|
1303
1343
|
console.log(import_chalk3.default.dim(`
|
|
1304
1344
|
Next page: re-run with --page ${parsePage(opts.page) + 1}`));
|
|
1305
1345
|
}
|
|
@@ -1338,7 +1378,7 @@ function parsePage(raw) {
|
|
|
1338
1378
|
return n;
|
|
1339
1379
|
}
|
|
1340
1380
|
function resolveAcceptsAsset(input) {
|
|
1341
|
-
const resolved = (0,
|
|
1381
|
+
const resolved = (0, import_sdk3.resolveAsset)(input);
|
|
1342
1382
|
if (!resolved) {
|
|
1343
1383
|
throw new Error(`agents: --accepts '${input}' is not a known asset shorthand or a valid CAIP-19 id.`);
|
|
1344
1384
|
}
|
|
@@ -1467,11 +1507,11 @@ function printAcceptPrefs(prefs) {
|
|
|
1467
1507
|
}
|
|
1468
1508
|
|
|
1469
1509
|
// src/commands/assets.ts
|
|
1470
|
-
var
|
|
1510
|
+
var import_sdk4 = require("@heyanon-arp/sdk");
|
|
1471
1511
|
var import_chalk4 = __toESM(require("chalk"));
|
|
1472
1512
|
function renderAssetsText() {
|
|
1473
1513
|
const lines = [];
|
|
1474
|
-
for (const [cluster, assets] of Object.entries(
|
|
1514
|
+
for (const [cluster, assets] of Object.entries(import_sdk4.ASSET_WHITELIST)) {
|
|
1475
1515
|
lines.push(import_chalk4.default.bold(cluster));
|
|
1476
1516
|
for (const a of assets) {
|
|
1477
1517
|
const key = `${a.symbol}:${cluster}`;
|
|
@@ -1487,7 +1527,7 @@ function renderAssetsText() {
|
|
|
1487
1527
|
function registerAssetsCommand(root) {
|
|
1488
1528
|
root.command("assets").description("List the payment-asset whitelist (per cluster) \u2014 currencies the server accepts for delegations").option("--json", "machine-readable output (the per-cluster whitelist table)").action((opts) => {
|
|
1489
1529
|
if (opts.json) {
|
|
1490
|
-
console.log(formatJson(
|
|
1530
|
+
console.log(formatJson(import_sdk4.ASSET_WHITELIST));
|
|
1491
1531
|
return;
|
|
1492
1532
|
}
|
|
1493
1533
|
console.log(renderAssetsText());
|
|
@@ -1495,13 +1535,14 @@ function registerAssetsCommand(root) {
|
|
|
1495
1535
|
}
|
|
1496
1536
|
|
|
1497
1537
|
// src/commands/block.ts
|
|
1538
|
+
var import_sdk5 = require("@heyanon-arp/sdk");
|
|
1498
1539
|
var import_chalk5 = __toESM(require("chalk"));
|
|
1499
1540
|
init_api();
|
|
1500
1541
|
function resolveSigningAgent(opts) {
|
|
1501
1542
|
return opts.fromDid !== void 0 ? loadAgentOrThrow(opts.server, opts.fromDid) : resolveSenderAgent("block", opts.server, void 0);
|
|
1502
1543
|
}
|
|
1503
1544
|
function formatBlockRow(b) {
|
|
1504
|
-
const scope = b.scope ===
|
|
1545
|
+
const scope = b.scope === import_sdk5.InboxBlockScopes.ACCOUNT ? import_chalk5.default.yellow("account") : import_chalk5.default.cyan("did");
|
|
1505
1546
|
const reason = b.reason ? import_chalk5.default.dim(` \u2014 ${b.reason}`) : "";
|
|
1506
1547
|
return `${scope.padEnd(7)} ${b.did}${reason} ${import_chalk5.default.dim(b.blockedAt)}`;
|
|
1507
1548
|
}
|
|
@@ -1526,7 +1567,7 @@ async function runAdd(did, opts) {
|
|
|
1526
1567
|
jsonOut(result);
|
|
1527
1568
|
return;
|
|
1528
1569
|
}
|
|
1529
|
-
const what = result.scope ===
|
|
1570
|
+
const what = result.scope === import_sdk5.InboxBlockScopes.ACCOUNT ? `the owner account of ${did} (all its agents)` : did;
|
|
1530
1571
|
console.log(import_chalk5.default.green(`\u2713 Blocked ${what}.`));
|
|
1531
1572
|
}
|
|
1532
1573
|
async function runRemove(did, opts) {
|
|
@@ -1642,14 +1683,15 @@ function unknownKey(key) {
|
|
|
1642
1683
|
|
|
1643
1684
|
// src/commands/delegation.ts
|
|
1644
1685
|
var import_node_fs4 = require("fs");
|
|
1645
|
-
var
|
|
1646
|
-
var
|
|
1686
|
+
var import_sdk12 = require("@heyanon-arp/sdk");
|
|
1687
|
+
var import_chalk9 = __toESM(require("chalk"));
|
|
1647
1688
|
init_api();
|
|
1648
1689
|
|
|
1649
1690
|
// src/id-format.ts
|
|
1691
|
+
var import_sdk6 = require("@heyanon-arp/sdk");
|
|
1650
1692
|
var UUID_RE = /^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$/;
|
|
1651
1693
|
var OBJECT_ID_24_HEX_RE = /^[0-9a-f]{24}$/;
|
|
1652
|
-
var SHA256_PREFIX_RE =
|
|
1694
|
+
var SHA256_PREFIX_RE = import_sdk6.SHA256_HEX_RE;
|
|
1653
1695
|
var UUID_NO_DASHES_RE = /^[a-fA-F0-9]{32}$/;
|
|
1654
1696
|
function describeNonUuidShape(raw) {
|
|
1655
1697
|
if (raw === "") return "empty string";
|
|
@@ -1680,10 +1722,31 @@ function requireUuid(cmdName, raw, label) {
|
|
|
1680
1722
|
throw new Error(hint ? `${base} \u2014 ${hint}` : base);
|
|
1681
1723
|
}
|
|
1682
1724
|
|
|
1683
|
-
// src/
|
|
1684
|
-
var
|
|
1725
|
+
// src/resolve-recipient.ts
|
|
1726
|
+
var import_sdk7 = require("@heyanon-arp/sdk");
|
|
1685
1727
|
var import_chalk7 = __toESM(require("chalk"));
|
|
1686
1728
|
init_api();
|
|
1729
|
+
async function resolveRecipient(serverOverride, cmdName, input, opts = {}) {
|
|
1730
|
+
if (input.startsWith("did:arp:")) {
|
|
1731
|
+
if (!(0, import_sdk7.isValidDid)(input)) {
|
|
1732
|
+
throw new Error(`${cmdName}: '${input}' starts with did:arp: but is not a valid DID (base58btc-encoded 32-byte Ed25519 pubkey).`);
|
|
1733
|
+
}
|
|
1734
|
+
return input;
|
|
1735
|
+
}
|
|
1736
|
+
const name = (0, import_sdk7.normalizeName)(input);
|
|
1737
|
+
if (!(0, import_sdk7.isValidAgentName)(name)) {
|
|
1738
|
+
throw new Error(`${cmdName}: '${input}' is neither a DID (did:arp:...) nor a valid agent name (lowercase a-z0-9_, 3-32 chars).`);
|
|
1739
|
+
}
|
|
1740
|
+
const api = new ArpApiClient(serverOverride);
|
|
1741
|
+
const profile = await api.discoverByName(name);
|
|
1742
|
+
warn(opts.json, import_chalk7.default.dim(`Resolved ${import_chalk7.default.cyan(name)} \u2192 ${profile.did}${profile.description ? ` (${profile.description})` : ""}`));
|
|
1743
|
+
return profile.did;
|
|
1744
|
+
}
|
|
1745
|
+
|
|
1746
|
+
// src/commands/status.ts
|
|
1747
|
+
var import_sdk8 = require("@heyanon-arp/sdk");
|
|
1748
|
+
var import_chalk8 = __toESM(require("chalk"));
|
|
1749
|
+
init_api();
|
|
1687
1750
|
var UNTIL_PHASES = [
|
|
1688
1751
|
"delegation.offered",
|
|
1689
1752
|
"delegation.accepted",
|
|
@@ -1731,9 +1794,9 @@ async function runStatus(relationshipId, opts) {
|
|
|
1731
1794
|
const api = new ArpApiClient(opts.server);
|
|
1732
1795
|
const sender = resolveSenderAgent("status", opts.server, opts.fromDid);
|
|
1733
1796
|
if (!opts.json) {
|
|
1734
|
-
console.log(
|
|
1735
|
-
console.log(
|
|
1736
|
-
console.log(
|
|
1797
|
+
console.log(import_chalk8.default.dim(`Server: ${api.serverUrl}`));
|
|
1798
|
+
console.log(import_chalk8.default.dim(`Signer: ${sender.did}`));
|
|
1799
|
+
console.log(import_chalk8.default.dim(`Relationship: ${relationshipId}`));
|
|
1737
1800
|
}
|
|
1738
1801
|
const signer = makeSigner(sender);
|
|
1739
1802
|
if (!opts.wait) {
|
|
@@ -1765,7 +1828,7 @@ async function runStatus(relationshipId, opts) {
|
|
|
1765
1828
|
async function awaitFsmTransitionAfterAction(input) {
|
|
1766
1829
|
const { api, signerDid, signer, relationshipId, untilPhase, waitIntervalSec, waitTimeoutSec, waitVerbose, json } = input;
|
|
1767
1830
|
if (!json) {
|
|
1768
|
-
console.log(
|
|
1831
|
+
console.log(import_chalk8.default.dim(`
|
|
1769
1832
|
[--wait-until ${untilPhase}] polling relationship ${relationshipId} (interval=${waitIntervalSec}s timeout=${waitTimeoutSec}s)`));
|
|
1770
1833
|
}
|
|
1771
1834
|
const outcome = await runWaitLoop({
|
|
@@ -1782,13 +1845,13 @@ async function awaitFsmTransitionAfterAction(input) {
|
|
|
1782
1845
|
}
|
|
1783
1846
|
}
|
|
1784
1847
|
async function runWaitLoop(opts) {
|
|
1785
|
-
const isTerminal = (s) => s.cycleComplete || s.relationshipState ===
|
|
1848
|
+
const isTerminal = (s) => s.cycleComplete || s.relationshipState === import_sdk8.RelationshipStates.CLOSED || s.relationshipState === "not_found";
|
|
1786
1849
|
const isActionable = (s) => {
|
|
1787
1850
|
if (s.nextActionOwner === "me") {
|
|
1788
1851
|
if (s.relationshipState === "unknown") return false;
|
|
1789
1852
|
return true;
|
|
1790
1853
|
}
|
|
1791
|
-
if (s.nextActionOwner === "either" && s.relationshipState ===
|
|
1854
|
+
if (s.nextActionOwner === "either" && s.relationshipState === import_sdk8.RelationshipStates.ACTIVE) {
|
|
1792
1855
|
return true;
|
|
1793
1856
|
}
|
|
1794
1857
|
return false;
|
|
@@ -1804,7 +1867,7 @@ async function runWaitLoop(opts) {
|
|
|
1804
1867
|
}
|
|
1805
1868
|
if (isUntilReached !== null && isUntilReached(initial)) {
|
|
1806
1869
|
if (opts.json) opts.log(JSON.stringify(initial));
|
|
1807
|
-
else opts.log(
|
|
1870
|
+
else opts.log(import_chalk8.default.dim(`
|
|
1808
1871
|
[--wait] Phase '${opts.until}' already reached \u2014 exiting without polling.`));
|
|
1809
1872
|
return { timedOut: false, last: initial };
|
|
1810
1873
|
}
|
|
@@ -1815,13 +1878,13 @@ async function runWaitLoop(opts) {
|
|
|
1815
1878
|
else {
|
|
1816
1879
|
if (opts.until !== void 0) {
|
|
1817
1880
|
opts.log(
|
|
1818
|
-
|
|
1881
|
+
import_chalk8.default.yellow(
|
|
1819
1882
|
`
|
|
1820
1883
|
[--wait] Terminal state (${initial.relationshipState}, cycleComplete=${initial.cycleComplete}) reached before phase '${opts.until}' \u2014 exiting; phase unreachable.`
|
|
1821
1884
|
)
|
|
1822
1885
|
);
|
|
1823
1886
|
} else {
|
|
1824
|
-
opts.log(
|
|
1887
|
+
opts.log(import_chalk8.default.dim(`
|
|
1825
1888
|
[--wait] Already terminal \u2014 exiting.`));
|
|
1826
1889
|
}
|
|
1827
1890
|
}
|
|
@@ -1829,15 +1892,15 @@ async function runWaitLoop(opts) {
|
|
|
1829
1892
|
}
|
|
1830
1893
|
if (opts.until === void 0 && isActionable(initial)) {
|
|
1831
1894
|
if (opts.json) opts.log(JSON.stringify(initial));
|
|
1832
|
-
else opts.log(
|
|
1895
|
+
else opts.log(import_chalk8.default.dim(`
|
|
1833
1896
|
[--wait] Your turn already (nextActionOwner=${initial.nextActionOwner}) \u2014 exiting without polling.`));
|
|
1834
1897
|
return { timedOut: false, last: initial };
|
|
1835
1898
|
}
|
|
1836
1899
|
if (!opts.json) {
|
|
1837
1900
|
const blockerLabel = opts.until !== void 0 ? `Awaiting phase '${opts.until}'` : initial.nextActionOwner === "counterparty" ? "Counterparty owes the next move" : initial.nextActionOwner === "either" ? "Either side may act" : `Awaiting state change (currently ${initial.relationshipState}, nextActionOwner=${initial.nextActionOwner})`;
|
|
1838
|
-
opts.log(
|
|
1901
|
+
opts.log(import_chalk8.default.dim(`
|
|
1839
1902
|
[--wait] ${blockerLabel}. Polling every ${opts.waitIntervalSec}s, timeout ${opts.waitTimeoutSec}s.`));
|
|
1840
|
-
opts.log(
|
|
1903
|
+
opts.log(import_chalk8.default.dim(`[--wait] Initial hint: ${initial.nextActionHint}`));
|
|
1841
1904
|
}
|
|
1842
1905
|
const startedAt = localNow();
|
|
1843
1906
|
const deadline = startedAt + opts.waitTimeoutSec * 1e3;
|
|
@@ -1857,7 +1920,7 @@ async function runWaitLoop(opts) {
|
|
|
1857
1920
|
} else {
|
|
1858
1921
|
target = `nextActionOwner=${next.nextActionOwner}`;
|
|
1859
1922
|
}
|
|
1860
|
-
opts.log(
|
|
1923
|
+
opts.log(import_chalk8.default.dim(`[--wait tick ${tickIndex}/${maxTicks}] state=${next.relationshipState}, ${formatPhaseSnapshot(next)} (${target})`));
|
|
1861
1924
|
}
|
|
1862
1925
|
if (exitPredicate(next)) {
|
|
1863
1926
|
const phaseReached = isUntilReached !== null ? isUntilReached(next) : false;
|
|
@@ -1867,16 +1930,16 @@ async function runWaitLoop(opts) {
|
|
|
1867
1930
|
opts.log("");
|
|
1868
1931
|
if (opts.until !== void 0) {
|
|
1869
1932
|
if (phaseReached) {
|
|
1870
|
-
opts.log(
|
|
1933
|
+
opts.log(import_chalk8.default.green(`[--wait] Phase '${opts.until}' reached.`));
|
|
1871
1934
|
} else {
|
|
1872
1935
|
opts.log(
|
|
1873
|
-
|
|
1936
|
+
import_chalk8.default.yellow(
|
|
1874
1937
|
`[--wait] Terminal state (${next.relationshipState}, cycleComplete=${next.cycleComplete}) reached before phase '${opts.until}' \u2014 phase unreachable.`
|
|
1875
1938
|
)
|
|
1876
1939
|
);
|
|
1877
1940
|
}
|
|
1878
1941
|
} else {
|
|
1879
|
-
opts.log(
|
|
1942
|
+
opts.log(import_chalk8.default.green(`[--wait] ${isTerminal(next) ? "Cycle terminated" : `Your turn (owner=${next.nextActionOwner})`}.`));
|
|
1880
1943
|
}
|
|
1881
1944
|
opts.log(formatStatusReport(next));
|
|
1882
1945
|
}
|
|
@@ -1889,14 +1952,14 @@ async function runWaitLoop(opts) {
|
|
|
1889
1952
|
} else {
|
|
1890
1953
|
if (opts.until !== void 0) {
|
|
1891
1954
|
opts.log(
|
|
1892
|
-
|
|
1955
|
+
import_chalk8.default.yellow(
|
|
1893
1956
|
`
|
|
1894
1957
|
[--wait] Timed out after ${opts.waitTimeoutSec}s without reaching phase '${opts.until}' (latest state: ${last.relationshipState}, hint: ${last.nextActionHint}).`
|
|
1895
1958
|
)
|
|
1896
1959
|
);
|
|
1897
1960
|
} else {
|
|
1898
1961
|
opts.log(
|
|
1899
|
-
|
|
1962
|
+
import_chalk8.default.yellow(`
|
|
1900
1963
|
[--wait] Timed out after ${opts.waitTimeoutSec}s without an actionable or terminal transition (your turn never came, cycle still in flight).`)
|
|
1901
1964
|
);
|
|
1902
1965
|
}
|
|
@@ -1924,41 +1987,41 @@ function parseUntilPhase(raw) {
|
|
|
1924
1987
|
function isPhaseTerminallyUnreachable(phase, s) {
|
|
1925
1988
|
if (untilPhaseMatched(phase, s)) return false;
|
|
1926
1989
|
if (s.relationshipState === "not_found") return true;
|
|
1927
|
-
if (s.relationshipState ===
|
|
1990
|
+
if (s.relationshipState === import_sdk8.RelationshipStates.CLOSED && phase !== "relationship.closed") return true;
|
|
1928
1991
|
return false;
|
|
1929
1992
|
}
|
|
1930
1993
|
function untilPhaseMatched(phase, s) {
|
|
1931
1994
|
switch (phase) {
|
|
1932
1995
|
case "delegation.offered":
|
|
1933
|
-
return s.latestDelegation?.state ===
|
|
1996
|
+
return s.latestDelegation?.state === import_sdk8.DelegationStates.OFFERED;
|
|
1934
1997
|
case "delegation.accepted":
|
|
1935
|
-
return s.latestDelegation?.state ===
|
|
1998
|
+
return s.latestDelegation?.state === import_sdk8.DelegationStates.ACCEPTED;
|
|
1936
1999
|
case "delegation.locked":
|
|
1937
|
-
return s.latestDelegation?.state ===
|
|
2000
|
+
return s.latestDelegation?.state === import_sdk8.DelegationStates.LOCKED;
|
|
1938
2001
|
case "delegation.disputing":
|
|
1939
|
-
return s.latestDelegation?.state ===
|
|
2002
|
+
return s.latestDelegation?.state === import_sdk8.DelegationStates.DISPUTING;
|
|
1940
2003
|
case "delegation.canceled":
|
|
1941
|
-
return s.latestDelegation?.state ===
|
|
2004
|
+
return s.latestDelegation?.state === import_sdk8.DelegationStates.CANCELED;
|
|
1942
2005
|
case "delegation.declined":
|
|
1943
|
-
return s.latestDelegation?.state ===
|
|
2006
|
+
return s.latestDelegation?.state === import_sdk8.DelegationStates.DECLINED;
|
|
1944
2007
|
case "work.requested":
|
|
1945
|
-
return s.latestWorkLog?.state ===
|
|
2008
|
+
return s.latestWorkLog?.state === import_sdk8.WorkLogStates.REQUESTED;
|
|
1946
2009
|
case "work.responded":
|
|
1947
|
-
return s.latestWorkLog?.state ===
|
|
2010
|
+
return s.latestWorkLog?.state === import_sdk8.WorkLogStates.RESPONDED;
|
|
1948
2011
|
case "receipt.proposed":
|
|
1949
2012
|
return s.latestReceipt != null;
|
|
1950
2013
|
case "relationship.pending":
|
|
1951
|
-
return s.relationshipState ===
|
|
2014
|
+
return s.relationshipState === import_sdk8.RelationshipStates.PENDING;
|
|
1952
2015
|
case "relationship.active":
|
|
1953
|
-
return s.relationshipState ===
|
|
2016
|
+
return s.relationshipState === import_sdk8.RelationshipStates.ACTIVE;
|
|
1954
2017
|
case "relationship.paused":
|
|
1955
|
-
return s.relationshipState ===
|
|
2018
|
+
return s.relationshipState === import_sdk8.RelationshipStates.PAUSED;
|
|
1956
2019
|
case "relationship.closed":
|
|
1957
|
-
return s.relationshipState ===
|
|
2020
|
+
return s.relationshipState === import_sdk8.RelationshipStates.CLOSED;
|
|
1958
2021
|
case "cycle.complete":
|
|
1959
2022
|
return s.cycleComplete;
|
|
1960
2023
|
case "cycle.released":
|
|
1961
|
-
return s.latestDelegation?.state ===
|
|
2024
|
+
return s.latestDelegation?.state === import_sdk8.DelegationStates.COMPLETED;
|
|
1962
2025
|
}
|
|
1963
2026
|
}
|
|
1964
2027
|
function parseWaitInterval(raw) {
|
|
@@ -2009,7 +2072,7 @@ async function composeStatus(api, signerDid, relationshipId, signer) {
|
|
|
2009
2072
|
const relationship = relationships.find((r) => r.relationshipId === relationshipId);
|
|
2010
2073
|
const counterpartyDid = relationship ? relationship.pairDidA === signerDid ? relationship.pairDidB : relationship.pairDidA : inferCounterpartyFromEntities(signerDid, allDelegations);
|
|
2011
2074
|
const delegations = allDelegations;
|
|
2012
|
-
const latestDelegation = pickLatestLive(delegations, [
|
|
2075
|
+
const latestDelegation = pickLatestLive(delegations, [...import_sdk8.DELEGATION_ACTIVE_STATES]);
|
|
2013
2076
|
const [workLogs, receipts] = await Promise.all([
|
|
2014
2077
|
latestDelegation ? fetchAllPages(
|
|
2015
2078
|
(after) => api.listWorkLogs(relationshipId, signer, { limit: 100, delegationId: latestDelegation.delegationId, ...after ? { after } : {} })
|
|
@@ -2073,8 +2136,8 @@ function findReceiptForWorkLog(receipts, workLog, allWorkLogs = [workLog]) {
|
|
|
2073
2136
|
};
|
|
2074
2137
|
const responseBody = workLog.responseOutput !== void 0 ? { type: "work_response", content: { delegation_id: workLog.delegationId, request_id: workLog.requestId, output: workLog.responseOutput } } : workLog.responseError !== void 0 ? { type: "work_response", content: { delegation_id: workLog.delegationId, request_id: workLog.requestId, error: workLog.responseError } } : null;
|
|
2075
2138
|
if (!responseBody) return null;
|
|
2076
|
-
const expectedRequestHash = (0,
|
|
2077
|
-
const expectedResponseHash = (0,
|
|
2139
|
+
const expectedRequestHash = (0, import_sdk8.canonicalSha256Hex)(requestBody);
|
|
2140
|
+
const expectedResponseHash = (0, import_sdk8.canonicalSha256Hex)(responseBody);
|
|
2078
2141
|
const matches = receipts.filter((r) => r.requestHash === expectedRequestHash && r.responseHash === expectedResponseHash);
|
|
2079
2142
|
if (matches.length > 0) return pickLatest(matches);
|
|
2080
2143
|
const respondedSiblings = allWorkLogs.filter((wl) => wl.delegationId === workLog.delegationId && (wl.responseOutput !== void 0 || wl.responseError !== void 0)).length;
|
|
@@ -2116,49 +2179,49 @@ function nextAction(input) {
|
|
|
2116
2179
|
complete: false
|
|
2117
2180
|
};
|
|
2118
2181
|
}
|
|
2119
|
-
if (relationship.state ===
|
|
2182
|
+
if (relationship.state === import_sdk8.RelationshipStates.PENDING) {
|
|
2120
2183
|
return {
|
|
2121
2184
|
hint: "Relationship is PENDING \u2014 one side owes `heyarp send-handshake-response <peer> --decision accept | decline`",
|
|
2122
2185
|
owner: "either",
|
|
2123
2186
|
complete: false
|
|
2124
2187
|
};
|
|
2125
2188
|
}
|
|
2126
|
-
if (relationship.state ===
|
|
2189
|
+
if (relationship.state === import_sdk8.RelationshipStates.PAUSED) {
|
|
2127
2190
|
return { hint: "Relationship is PAUSED \u2014 owner must `heyarp unpause` before any envelopes flow", owner: "either", complete: false };
|
|
2128
2191
|
}
|
|
2129
|
-
if (relationship.state ===
|
|
2192
|
+
if (relationship.state === import_sdk8.RelationshipStates.CLOSED) {
|
|
2130
2193
|
return { hint: "Relationship is CLOSED \u2014 terminal state, no further action possible. Start a fresh handshake to reopen.", owner: "none", complete: false };
|
|
2131
2194
|
}
|
|
2132
|
-
if (!latestDelegation || latestDelegation.state ===
|
|
2195
|
+
if (!latestDelegation || latestDelegation.state === import_sdk8.DelegationStates.DECLINED || latestDelegation.state === import_sdk8.DelegationStates.CANCELED) {
|
|
2133
2196
|
return {
|
|
2134
2197
|
hint: "No live delegation \u2014 buyer offers (terms only, no lock) `heyarp delegation offer <peer> --delegation-id <new-uuid> --title \u2026 --scope \u2026 --amount \u2026 --currency SOL:solana-devnet --deadline \u2026`, then funds the escrow lock AFTER the worker accepts via `heyarp delegation fund <del-id> --escrow-lock-from-file <path>`",
|
|
2135
2198
|
owner: "either",
|
|
2136
2199
|
complete: false
|
|
2137
2200
|
};
|
|
2138
2201
|
}
|
|
2139
|
-
if (latestDelegation.state ===
|
|
2202
|
+
if (latestDelegation.state === import_sdk8.DelegationStates.DISPUTING) {
|
|
2140
2203
|
return {
|
|
2141
2204
|
hint: `Delegation ${latestDelegation.delegationId} is DISPUTING \u2014 the buyer opened an on-chain dispute (their stake is escrowed too). The operator may rule until the dispute window lapses; after that either party closes with \`heyarp escrow dispute close ${latestDelegation.delegationId}\` (escrow returns to the buyer, both stakes return). Deadline: \`heyarp escrow show ${latestDelegation.delegationId}\`. No envelopes to send meanwhile.`,
|
|
2142
2205
|
owner: "none",
|
|
2143
2206
|
complete: false
|
|
2144
2207
|
};
|
|
2145
2208
|
}
|
|
2146
|
-
if (latestDelegation.state ===
|
|
2209
|
+
if (latestDelegation.state === import_sdk8.DelegationStates.COMPLETED) {
|
|
2147
2210
|
return {
|
|
2148
2211
|
hint: "Cycle COMPLETE \u2014 payment claimed on chain (lock paid; the receipt carries releaseStatus=paid)",
|
|
2149
2212
|
owner: "none",
|
|
2150
2213
|
complete: true
|
|
2151
2214
|
};
|
|
2152
2215
|
}
|
|
2153
|
-
if (latestDelegation.state ===
|
|
2216
|
+
if (latestDelegation.state === import_sdk8.DelegationStates.FAILED || latestDelegation.state === import_sdk8.DelegationStates.REFUNDED || latestDelegation.state === import_sdk8.DelegationStates.DISPUTE_RESOLVED) {
|
|
2154
2217
|
const stateLabel = latestDelegation.state.toUpperCase();
|
|
2155
|
-
const reason = latestDelegation.state ===
|
|
2218
|
+
const reason = latestDelegation.state === import_sdk8.DelegationStates.FAILED ? "on-chain escrow lock failed to finalise (typical causes: insufficient payer funds, wrong program-id, ProgramState PDA uninitialised \u2014 check `heyarp delegations <rel-id> --json | jq .[].escrowError` for the worker-side reason)" : latestDelegation.state === import_sdk8.DelegationStates.REFUNDED ? (
|
|
2156
2219
|
// Keyed on the DELEGATION row's releaseStatus, not the
|
|
2157
2220
|
// receipt's: in the claim-expired path the worker never
|
|
2158
2221
|
// submitted anything, so no receipt row exists to carry
|
|
2159
2222
|
// the outcome — the delegation copy is always present
|
|
2160
2223
|
// on indexer-driven terminals.
|
|
2161
|
-
latestDelegation.releaseStatus ===
|
|
2224
|
+
latestDelegation.releaseStatus === import_sdk8.LockStates.DISPUTE_CLOSED ? "the dispute window lapsed without an operator ruling and the dispute was closed \u2014 escrow returned to the buyer, both stakes returned (work was delivered but not paid)" : latestDelegation.releaseStatus === import_sdk8.LockStates.REVOKED ? "the work window lapsed without an on-chain submit \u2014 the buyer reclaimed the escrow AND the worker stake (claim_expired_work)" : "lock was refunded after expiry \u2014 no work was delivered against this delegation"
|
|
2162
2225
|
) : "admin closed the delegation via the dispute-resolution path";
|
|
2163
2226
|
return {
|
|
2164
2227
|
hint: `Delegation ${latestDelegation.delegationId} is ${stateLabel} (terminal) \u2014 ${reason}. Issue a fresh \`heyarp delegation offer <peer> --delegation-id <new-uuid> \u2026\` to retry (FSM does not auto-retry).`,
|
|
@@ -2166,7 +2229,7 @@ function nextAction(input) {
|
|
|
2166
2229
|
complete: false
|
|
2167
2230
|
};
|
|
2168
2231
|
}
|
|
2169
|
-
if (latestDelegation.state ===
|
|
2232
|
+
if (latestDelegation.state === import_sdk8.DelegationStates.OFFERED) {
|
|
2170
2233
|
const iAmOfferer = latestDelegation.offererDid === signerDid;
|
|
2171
2234
|
const stateLabel = "OFFERED";
|
|
2172
2235
|
return {
|
|
@@ -2175,7 +2238,7 @@ function nextAction(input) {
|
|
|
2175
2238
|
complete: false
|
|
2176
2239
|
};
|
|
2177
2240
|
}
|
|
2178
|
-
if (latestDelegation.state ===
|
|
2241
|
+
if (latestDelegation.state === import_sdk8.DelegationStates.ACCEPTED && !latestWorkLog) {
|
|
2179
2242
|
const iAmOfferer = latestDelegation.offererDid === signerDid;
|
|
2180
2243
|
return {
|
|
2181
2244
|
hint: iAmOfferer ? `Delegation ${latestDelegation.delegationId} is ACCEPTED \u2014 you (buyer) owe \`heyarp wallet create-lock --delegation-id ${latestDelegation.delegationId} --condition-hash <hex> ... > lock.json\` then \`heyarp delegation fund ${latestDelegation.delegationId} --escrow-lock-from-file lock.json\` (fund the escrow lock; work begins once it is LOCKED on chain)` : `Delegation ${latestDelegation.delegationId} is ACCEPTED \u2014 counterparty (the buyer) owes \`heyarp delegation fund\` to lock the escrow; wait for the delegation to reach LOCKED before working`,
|
|
@@ -2183,7 +2246,7 @@ function nextAction(input) {
|
|
|
2183
2246
|
complete: false
|
|
2184
2247
|
};
|
|
2185
2248
|
}
|
|
2186
|
-
if (latestDelegation.state ===
|
|
2249
|
+
if (latestDelegation.state === import_sdk8.DelegationStates.PENDING_LOCK_FINALIZATION && !latestWorkLog) {
|
|
2187
2250
|
return {
|
|
2188
2251
|
hint: `Delegation ${latestDelegation.delegationId} is PENDING_LOCK_FINALIZATION \u2014 the escrow lock was funded and is awaiting on-chain confirmation; both sides wait (auto-advances to LOCKED). Poll with \`heyarp status ${relationship.relationshipId} --wait --until delegation.locked\`.`,
|
|
2189
2252
|
owner: "none",
|
|
@@ -2198,7 +2261,7 @@ function nextAction(input) {
|
|
|
2198
2261
|
complete: false
|
|
2199
2262
|
};
|
|
2200
2263
|
}
|
|
2201
|
-
if (latestWorkLog.state ===
|
|
2264
|
+
if (latestWorkLog.state === import_sdk8.WorkLogStates.REQUESTED) {
|
|
2202
2265
|
const iAmPayee = latestWorkLog.payeeDid === signerDid;
|
|
2203
2266
|
return {
|
|
2204
2267
|
hint: iAmPayee ? `work_request ${latestWorkLog.requestId} is REQUESTED \u2014 you owe \`heyarp work respond\` (output OR --error)` : `work_request ${latestWorkLog.requestId} is REQUESTED \u2014 counterparty (payee) owes \`heyarp work respond\``,
|
|
@@ -2250,106 +2313,106 @@ function formatStatusReport(s) {
|
|
|
2250
2313
|
const lines = [];
|
|
2251
2314
|
lines.push(cycleHeadline(s));
|
|
2252
2315
|
lines.push("");
|
|
2253
|
-
lines.push(
|
|
2316
|
+
lines.push(import_chalk8.default.bold("Relationship"));
|
|
2254
2317
|
lines.push(` state: ${stateColor(s.relationshipState)}`);
|
|
2255
|
-
if (s.counterpartyDid) lines.push(` counterparty: ${
|
|
2318
|
+
if (s.counterpartyDid) lines.push(` counterparty: ${import_chalk8.default.cyan(s.counterpartyDid)}`);
|
|
2256
2319
|
lines.push("");
|
|
2257
|
-
lines.push(
|
|
2320
|
+
lines.push(import_chalk8.default.bold("Latest delegation"));
|
|
2258
2321
|
if (s.latestDelegation) {
|
|
2259
2322
|
lines.push(` ${s.latestDelegation.delegationId} state=${stateColor(s.latestDelegation.state)}`);
|
|
2260
|
-
lines.push(` offerer: ${
|
|
2323
|
+
lines.push(` offerer: ${import_chalk8.default.cyan(s.latestDelegation.offererDid)}`);
|
|
2261
2324
|
if (s.latestDelegation.title) lines.push(` title: ${s.latestDelegation.title}`);
|
|
2262
2325
|
if (s.latestDelegation.scopeSummary) lines.push(` scope: ${s.latestDelegation.scopeSummary}`);
|
|
2263
2326
|
} else {
|
|
2264
|
-
lines.push(
|
|
2327
|
+
lines.push(import_chalk8.default.dim(" (none)"));
|
|
2265
2328
|
}
|
|
2266
2329
|
lines.push("");
|
|
2267
|
-
lines.push(
|
|
2330
|
+
lines.push(import_chalk8.default.bold("Latest work_log"));
|
|
2268
2331
|
if (s.latestWorkLog) {
|
|
2269
2332
|
lines.push(` request_id=${s.latestWorkLog.requestId} state=${stateColor(s.latestWorkLog.state)}`);
|
|
2270
2333
|
} else {
|
|
2271
|
-
lines.push(
|
|
2334
|
+
lines.push(import_chalk8.default.dim(" (none)"));
|
|
2272
2335
|
}
|
|
2273
2336
|
lines.push("");
|
|
2274
|
-
lines.push(
|
|
2337
|
+
lines.push(import_chalk8.default.bold("Latest receipt"));
|
|
2275
2338
|
if (s.latestReceipt) {
|
|
2276
2339
|
lines.push(` ${stateColor("proposed")} verdict=${s.latestReceipt.verdictProposed}`);
|
|
2277
2340
|
} else {
|
|
2278
|
-
lines.push(
|
|
2341
|
+
lines.push(import_chalk8.default.dim(" (none)"));
|
|
2279
2342
|
}
|
|
2280
2343
|
lines.push("");
|
|
2281
|
-
lines.push(
|
|
2282
|
-
const ownerLabel = s.nextActionOwner === "me" ?
|
|
2344
|
+
lines.push(import_chalk8.default.bold("Next action"));
|
|
2345
|
+
const ownerLabel = s.nextActionOwner === "me" ? import_chalk8.default.green("me") : s.nextActionOwner === "counterparty" ? import_chalk8.default.yellow("counterparty") : s.nextActionOwner === "either" ? import_chalk8.default.cyan("either side") : import_chalk8.default.dim("\u2014");
|
|
2283
2346
|
lines.push(` whose turn: ${ownerLabel}`);
|
|
2284
2347
|
lines.push(` hint: ${s.nextActionHint}`);
|
|
2285
|
-
if (s.cycleComplete) lines.push(` ${
|
|
2348
|
+
if (s.cycleComplete) lines.push(` ${import_chalk8.default.green("\u2713 Cycle complete.")}`);
|
|
2286
2349
|
return lines.join("\n");
|
|
2287
2350
|
}
|
|
2288
2351
|
function cycleHeadline(s) {
|
|
2289
2352
|
if (s.cycleComplete) {
|
|
2290
|
-
return `${
|
|
2353
|
+
return `${import_chalk8.default.bold("Cycle:")} ${import_chalk8.default.green.bold("COMPLETE")} ${import_chalk8.default.dim("\u2014 payment proven on chain")}`;
|
|
2291
2354
|
}
|
|
2292
2355
|
switch (s.relationshipState) {
|
|
2293
2356
|
case "not_found":
|
|
2294
|
-
return `${
|
|
2357
|
+
return `${import_chalk8.default.bold("Cycle:")} ${import_chalk8.default.red.bold("NOT FOUND")} ${import_chalk8.default.dim("\u2014 relationship missing or signer is not a member")}`;
|
|
2295
2358
|
case "unknown":
|
|
2296
|
-
return `${
|
|
2297
|
-
case
|
|
2298
|
-
return `${
|
|
2299
|
-
case
|
|
2300
|
-
return `${
|
|
2301
|
-
case
|
|
2302
|
-
return `${
|
|
2303
|
-
case
|
|
2359
|
+
return `${import_chalk8.default.bold("Cycle:")} ${import_chalk8.default.yellow.bold("UNKNOWN")} ${import_chalk8.default.dim("\u2014 state probe inconclusive; hint below is advisory")}`;
|
|
2360
|
+
case import_sdk8.RelationshipStates.CLOSED:
|
|
2361
|
+
return `${import_chalk8.default.bold("Cycle:")} ${import_chalk8.default.red.bold("CLOSED")} ${import_chalk8.default.dim("\u2014 relationship terminal, no further protocol action")}`;
|
|
2362
|
+
case import_sdk8.RelationshipStates.PAUSED:
|
|
2363
|
+
return `${import_chalk8.default.bold("Cycle:")} ${import_chalk8.default.yellow.bold("PAUSED")} ${import_chalk8.default.dim("\u2014 relationship soft-disabled, resume to continue")}`;
|
|
2364
|
+
case import_sdk8.RelationshipStates.PENDING:
|
|
2365
|
+
return `${import_chalk8.default.bold("Cycle:")} ${import_chalk8.default.yellow.bold("PENDING")} ${import_chalk8.default.dim("\u2014 awaiting handshake_response")}`;
|
|
2366
|
+
case import_sdk8.RelationshipStates.ACTIVE:
|
|
2304
2367
|
default:
|
|
2305
|
-
return `${
|
|
2368
|
+
return `${import_chalk8.default.bold("Cycle:")} ${import_chalk8.default.cyan.bold("ACTIVE")} ${import_chalk8.default.dim('\u2014 work in progress; see "Next action" below')}`;
|
|
2306
2369
|
}
|
|
2307
2370
|
}
|
|
2308
2371
|
function stateColor(state) {
|
|
2309
|
-
const c = state === "active" || state === "accepted" || state === "locked" || state === "responded" || state === "completed" ?
|
|
2372
|
+
const c = state === "active" || state === "accepted" || state === "locked" || state === "responded" || state === "completed" ? import_chalk8.default.green : state === "pending" || state === "requested" || state === "offered" || state === "pending_lock_finalization" ? import_chalk8.default.yellow : state === "closed" || state === "declined" || state === "canceled" || state === "replaced" || state === "not_found" || // Terminal failure states deserve the same red
|
|
2310
2373
|
// treatment as declined/canceled so an operator
|
|
2311
2374
|
// scanning `heyarp status` immediately sees
|
|
2312
2375
|
// "this is dead, don't follow the hint blindly".
|
|
2313
|
-
state === "failed" || state === "refunded" || state === "dispute_resolved" ?
|
|
2376
|
+
state === "failed" || state === "refunded" || state === "dispute_resolved" ? import_chalk8.default.red : import_chalk8.default.cyan;
|
|
2314
2377
|
return c(state);
|
|
2315
2378
|
}
|
|
2316
2379
|
|
|
2317
2380
|
// src/commands/wallet.ts
|
|
2318
|
-
var
|
|
2381
|
+
var import_sdk11 = require("@heyanon-arp/sdk");
|
|
2319
2382
|
var import_utils = require("@noble/hashes/utils");
|
|
2320
2383
|
var import_web32 = require("@solana/web3.js");
|
|
2321
2384
|
init_api();
|
|
2322
2385
|
init_config();
|
|
2323
2386
|
|
|
2324
2387
|
// src/solana/escrow-ix.ts
|
|
2325
|
-
var
|
|
2388
|
+
var import_sdk9 = require("@heyanon-arp/sdk");
|
|
2326
2389
|
var import_web3 = require("@solana/web3.js");
|
|
2327
|
-
var SPL_TOKEN_PROGRAM_ID = new import_web3.PublicKey(
|
|
2328
|
-
var ASSOCIATED_TOKEN_PROGRAM_ID = new import_web3.PublicKey(
|
|
2329
|
-
var NATIVE_SOL_MINT = new import_web3.PublicKey(
|
|
2390
|
+
var SPL_TOKEN_PROGRAM_ID = new import_web3.PublicKey(import_sdk9.SPL_TOKEN_PROGRAM_ID_BASE58);
|
|
2391
|
+
var ASSOCIATED_TOKEN_PROGRAM_ID = new import_web3.PublicKey(import_sdk9.ASSOCIATED_TOKEN_PROGRAM_ID_BASE58);
|
|
2392
|
+
var NATIVE_SOL_MINT = new import_web3.PublicKey(import_sdk9.NATIVE_SOL_MINT_BASE58);
|
|
2330
2393
|
function deriveLockPda(programId, lockId) {
|
|
2331
|
-
return import_web3.PublicKey.findProgramAddressSync([Buffer.from(
|
|
2394
|
+
return import_web3.PublicKey.findProgramAddressSync([Buffer.from(import_sdk9.ESCROW_PDA_SEEDS.LOCK), Buffer.from(lockId)], programId)[0];
|
|
2332
2395
|
}
|
|
2333
2396
|
function deriveEscrowPda(programId, lockId) {
|
|
2334
|
-
return import_web3.PublicKey.findProgramAddressSync([Buffer.from(
|
|
2397
|
+
return import_web3.PublicKey.findProgramAddressSync([Buffer.from(import_sdk9.ESCROW_PDA_SEEDS.ESCROW), Buffer.from(lockId)], programId)[0];
|
|
2335
2398
|
}
|
|
2336
2399
|
function deriveConfigPda(programId) {
|
|
2337
|
-
return import_web3.PublicKey.findProgramAddressSync([Buffer.from(
|
|
2400
|
+
return import_web3.PublicKey.findProgramAddressSync([Buffer.from(import_sdk9.ESCROW_PDA_SEEDS.CONFIG)], programId)[0];
|
|
2338
2401
|
}
|
|
2339
2402
|
function deriveStakeVaultPda(programId) {
|
|
2340
|
-
return import_web3.PublicKey.findProgramAddressSync([Buffer.from(
|
|
2403
|
+
return import_web3.PublicKey.findProgramAddressSync([Buffer.from(import_sdk9.ESCROW_PDA_SEEDS.STAKE_VAULT)], programId)[0];
|
|
2341
2404
|
}
|
|
2342
2405
|
function deriveCollateralConfigPda(programId, mint) {
|
|
2343
|
-
return import_web3.PublicKey.findProgramAddressSync([Buffer.from(
|
|
2406
|
+
return import_web3.PublicKey.findProgramAddressSync([Buffer.from(import_sdk9.ESCROW_PDA_SEEDS.COLLATERAL), mint.toBuffer()], programId)[0];
|
|
2344
2407
|
}
|
|
2345
2408
|
function deriveDisputeResolutionPda(programId, lockId) {
|
|
2346
|
-
return import_web3.PublicKey.findProgramAddressSync([Buffer.from(
|
|
2409
|
+
return import_web3.PublicKey.findProgramAddressSync([Buffer.from(import_sdk9.ESCROW_PDA_SEEDS.DISPUTE_RESOLUTION), Buffer.from(lockId)], programId)[0];
|
|
2347
2410
|
}
|
|
2348
2411
|
function deriveOperatorAuthPda(programId, operator) {
|
|
2349
|
-
return import_web3.PublicKey.findProgramAddressSync([Buffer.from(
|
|
2412
|
+
return import_web3.PublicKey.findProgramAddressSync([Buffer.from(import_sdk9.ESCROW_PDA_SEEDS.OPERATOR_AUTH), operator.toBuffer()], programId)[0];
|
|
2350
2413
|
}
|
|
2351
2414
|
function deriveEventAuthorityPda(programId) {
|
|
2352
|
-
return import_web3.PublicKey.findProgramAddressSync([Buffer.from(
|
|
2415
|
+
return import_web3.PublicKey.findProgramAddressSync([Buffer.from(import_sdk9.ESCROW_PDA_SEEDS.EVENT_AUTHORITY)], programId)[0];
|
|
2353
2416
|
}
|
|
2354
2417
|
function deriveAta(owner, mint) {
|
|
2355
2418
|
return import_web3.PublicKey.findProgramAddressSync([owner.toBuffer(), SPL_TOKEN_PROGRAM_ID.toBuffer(), mint.toBuffer()], ASSOCIATED_TOKEN_PROGRAM_ID)[0];
|
|
@@ -2364,12 +2427,12 @@ function meta(pubkey, opts = {}) {
|
|
|
2364
2427
|
return { pubkey, isSigner: opts.signer === true, isWritable: opts.writable === true };
|
|
2365
2428
|
}
|
|
2366
2429
|
function noArgIx(programId, name, keys) {
|
|
2367
|
-
return new import_web3.TransactionInstruction({ programId, keys, data: Buffer.from((0,
|
|
2430
|
+
return new import_web3.TransactionInstruction({ programId, keys, data: Buffer.from((0, import_sdk9.buildLifecycleIxData)(name)) });
|
|
2368
2431
|
}
|
|
2369
2432
|
function buildCreateLockIx(input) {
|
|
2370
2433
|
const { programId, lockId } = input;
|
|
2371
2434
|
const native = input.mint === null;
|
|
2372
|
-
const data = Buffer.from((0,
|
|
2435
|
+
const data = Buffer.from((0, import_sdk9.buildCreateLockIxData)({ lockId, amount: input.amount, conditionHash: input.conditionHash }, { native }));
|
|
2373
2436
|
const head = [
|
|
2374
2437
|
meta(input.payer, { signer: true, writable: true }),
|
|
2375
2438
|
meta(input.payee),
|
|
@@ -2505,7 +2568,7 @@ function buildOpenDisputeIx(input) {
|
|
|
2505
2568
|
function buildResolveDisputeIx(input) {
|
|
2506
2569
|
const { programId, lockId } = input;
|
|
2507
2570
|
const native = input.mint === null;
|
|
2508
|
-
const data = Buffer.from((0,
|
|
2571
|
+
const data = Buffer.from((0, import_sdk9.buildResolveDisputeIxData)(input.args, { native }));
|
|
2509
2572
|
if (native) {
|
|
2510
2573
|
return new import_web3.TransactionInstruction({
|
|
2511
2574
|
programId,
|
|
@@ -2582,16 +2645,17 @@ function buildCloseDisputeIx(input) {
|
|
|
2582
2645
|
]);
|
|
2583
2646
|
}
|
|
2584
2647
|
async function fetchLockAccount(conn, programId, delegationId) {
|
|
2585
|
-
const lockId = (0,
|
|
2648
|
+
const lockId = (0, import_sdk9.deriveLockId)(delegationId);
|
|
2586
2649
|
const lockPda = deriveLockPda(programId, lockId);
|
|
2587
2650
|
const info = await conn.getAccountInfo(lockPda);
|
|
2588
2651
|
if (!info) return null;
|
|
2589
|
-
return { lockId, lockPda, lock: (0,
|
|
2652
|
+
return { lockId, lockPda, lock: (0, import_sdk9.decodeLockAccount)(Uint8Array.from(info.data)) };
|
|
2590
2653
|
}
|
|
2591
2654
|
|
|
2592
2655
|
// src/commands/token-amount.ts
|
|
2656
|
+
var import_sdk10 = require("@heyanon-arp/sdk");
|
|
2593
2657
|
function toBaseUnits(amountDecimal, decimals) {
|
|
2594
|
-
if (
|
|
2658
|
+
if (!(0, import_sdk10.isDecimalAmountString)(amountDecimal)) {
|
|
2595
2659
|
throw new Error(`amount '${amountDecimal}' is not a non-negative decimal number`);
|
|
2596
2660
|
}
|
|
2597
2661
|
if (!Number.isInteger(decimals) || decimals < 0 || decimals > 255) {
|
|
@@ -2620,8 +2684,8 @@ function normaliseDelegationId(raw) {
|
|
|
2620
2684
|
}
|
|
2621
2685
|
throw new Error(`wallet: --delegation-id must be either 'del_<uuid>' or a bare canonical-lowercase UUID (got '${raw}')`);
|
|
2622
2686
|
}
|
|
2623
|
-
var SPL_TOKEN_PROGRAM_ID2 = new import_web32.PublicKey(
|
|
2624
|
-
var ASSOCIATED_TOKEN_PROGRAM_ID2 = new import_web32.PublicKey(
|
|
2687
|
+
var SPL_TOKEN_PROGRAM_ID2 = new import_web32.PublicKey(import_sdk11.SPL_TOKEN_PROGRAM_ID_BASE58);
|
|
2688
|
+
var ASSOCIATED_TOKEN_PROGRAM_ID2 = new import_web32.PublicKey(import_sdk11.ASSOCIATED_TOKEN_PROGRAM_ID_BASE58);
|
|
2625
2689
|
var FALLBACK_RPC_URL = "https://api.mainnet-beta.solana.com";
|
|
2626
2690
|
function resolveRpcUrl(opts) {
|
|
2627
2691
|
if (opts.rpcUrl !== void 0 && opts.rpcUrl !== "") return opts.rpcUrl;
|
|
@@ -2641,7 +2705,7 @@ function redactRpcUrl(url) {
|
|
|
2641
2705
|
return "<redacted>";
|
|
2642
2706
|
}
|
|
2643
2707
|
}
|
|
2644
|
-
var FALLBACK_PROGRAM_ID =
|
|
2708
|
+
var FALLBACK_PROGRAM_ID = import_sdk11.ESCROW_PROGRAM_ID_BASE58;
|
|
2645
2709
|
async function resolveProgramIdWithSource(api, opts) {
|
|
2646
2710
|
if (opts.programId !== void 0 && opts.programId !== "") {
|
|
2647
2711
|
return { programId: opts.programId, source: "flag" };
|
|
@@ -2725,7 +2789,7 @@ async function derivePdasHandler(opts) {
|
|
|
2725
2789
|
const normalisedDelegationId = normaliseDelegationId(opts.delegationId);
|
|
2726
2790
|
const api = new ArpApiClient(opts.server);
|
|
2727
2791
|
const programId = new import_web32.PublicKey(await resolveProgramIdStrict(api, opts, "wallet derive-pdas"));
|
|
2728
|
-
const lockIdBytes = (0,
|
|
2792
|
+
const lockIdBytes = (0, import_sdk11.deriveLockId)(normalisedDelegationId);
|
|
2729
2793
|
const lockIdSeed = Buffer.from(lockIdBytes);
|
|
2730
2794
|
const lockIdHex = Buffer.from(lockIdBytes).toString("hex");
|
|
2731
2795
|
const [lockPda] = import_web32.PublicKey.findProgramAddressSync([Buffer.from("lock"), lockIdSeed], programId);
|
|
@@ -2744,11 +2808,11 @@ async function derivePdasHandler(opts) {
|
|
|
2744
2808
|
};
|
|
2745
2809
|
}
|
|
2746
2810
|
var TERMINAL_METHOD = {
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2811
|
+
[import_sdk11.LockStates.PAID]: "claim_work_payment",
|
|
2812
|
+
[import_sdk11.LockStates.CANCELED]: "cancel_lock",
|
|
2813
|
+
[import_sdk11.LockStates.REVOKED]: "claim_expired_work",
|
|
2814
|
+
[import_sdk11.LockStates.DISPUTE_RESOLVED]: "resolve_dispute",
|
|
2815
|
+
[import_sdk11.LockStates.DISPUTE_CLOSED]: "close_dispute"
|
|
2752
2816
|
};
|
|
2753
2817
|
function registerVerifyRelease(cmd) {
|
|
2754
2818
|
cmd.command("verify-release").description(
|
|
@@ -2794,7 +2858,7 @@ async function verifyReleaseHandler(opts) {
|
|
|
2794
2858
|
const rpcUrl = resolveRpcUrlStrict(opts);
|
|
2795
2859
|
const conn = new import_web32.Connection(rpcUrl, "confirmed");
|
|
2796
2860
|
const fetched = await fetchLockAccount(conn, programId, normalisedDelegationId);
|
|
2797
|
-
const lockId = (0,
|
|
2861
|
+
const lockId = (0, import_sdk11.deriveLockId)(normalisedDelegationId);
|
|
2798
2862
|
const lockPda = deriveLockPda(programId, lockId);
|
|
2799
2863
|
const escrowPda = deriveEscrowPda(programId, lockId);
|
|
2800
2864
|
if (!fetched) {
|
|
@@ -2815,7 +2879,7 @@ async function verifyReleaseHandler(opts) {
|
|
|
2815
2879
|
lock_pda: lockPda.toBase58(),
|
|
2816
2880
|
escrow_pda: escrowPda.toBase58(),
|
|
2817
2881
|
lock_account_exists: true,
|
|
2818
|
-
released: status ===
|
|
2882
|
+
released: status === import_sdk11.LockStates.PAID,
|
|
2819
2883
|
status,
|
|
2820
2884
|
...TERMINAL_METHOD[status] !== void 0 ? { release_method: TERMINAL_METHOD[status] } : {},
|
|
2821
2885
|
lock_state: lock.stateByte,
|
|
@@ -2825,23 +2889,23 @@ async function verifyReleaseHandler(opts) {
|
|
|
2825
2889
|
}
|
|
2826
2890
|
function renderStatusLine(status) {
|
|
2827
2891
|
switch (status) {
|
|
2828
|
-
case
|
|
2892
|
+
case import_sdk11.LockStates.PAID:
|
|
2829
2893
|
return "\u2713 paid \u2014 claim_work_payment landed (buyer approval or post-review self-claim); the payee was paid net of any protocol fee";
|
|
2830
|
-
case
|
|
2894
|
+
case import_sdk11.LockStates.CREATED:
|
|
2831
2895
|
return "\u2717 created \u2014 funded, awaiting the worker accept_lock (stake) \u2014 or a buyer cancel";
|
|
2832
|
-
case
|
|
2896
|
+
case import_sdk11.LockStates.IN_PROGRESS:
|
|
2833
2897
|
return "\u2717 in_progress \u2014 worker accepted + staked; work window running";
|
|
2834
|
-
case
|
|
2898
|
+
case import_sdk11.LockStates.SUBMITTED:
|
|
2835
2899
|
return "\u2717 submitted \u2014 work delivered on-chain; review window running (buyer claims to approve, disputes to refuse; worker self-claims after expiry)";
|
|
2836
|
-
case
|
|
2900
|
+
case import_sdk11.LockStates.DISPUTING:
|
|
2837
2901
|
return "\u2717 disputing \u2014 buyer disputed; operator has the dispute window to rule, after that either party can close";
|
|
2838
|
-
case
|
|
2902
|
+
case import_sdk11.LockStates.CANCELED:
|
|
2839
2903
|
return "\u2717 canceled \u2014 buyer canceled pre-accept; escrow returned";
|
|
2840
|
-
case
|
|
2904
|
+
case import_sdk11.LockStates.REVOKED:
|
|
2841
2905
|
return "\u2717 revoked \u2014 work window lapsed unsubmitted; buyer reclaimed the escrow + the worker stake";
|
|
2842
|
-
case
|
|
2906
|
+
case import_sdk11.LockStates.DISPUTE_RESOLVED:
|
|
2843
2907
|
return "\u2717 dispute_resolved \u2014 operator ruled; winner took the escrow per the on-chain split";
|
|
2844
|
-
case
|
|
2908
|
+
case import_sdk11.LockStates.DISPUTE_CLOSED:
|
|
2845
2909
|
return "\u2717 dispute_closed \u2014 dispute window lapsed unresolved; escrow returned to the buyer, stakes returned";
|
|
2846
2910
|
case "lock_never_created":
|
|
2847
2911
|
return "\u2717 lock_never_created \u2014 no Lock PDA on this cluster/program; create_lock never fired (or wrong --rpc-url/--program-id)";
|
|
@@ -3027,7 +3091,7 @@ async function createLockHandler(opts) {
|
|
|
3027
3091
|
if (clusterTag !== 0 && clusterTag !== 1) {
|
|
3028
3092
|
throw new Error(`--cluster-tag must be 0 (devnet) or 1 (mainnet) (got ${clusterTag})`);
|
|
3029
3093
|
}
|
|
3030
|
-
const clusterCaip2 = clusterTag === 1 ?
|
|
3094
|
+
const clusterCaip2 = clusterTag === 1 ? import_sdk11.SOLANA_CLUSTER_IDS["solana-mainnet"] : import_sdk11.SOLANA_CLUSTER_IDS["solana-devnet"];
|
|
3031
3095
|
const expectedLockAsset = typeof opts.mintPubkey === "string" && opts.mintPubkey !== "" ? { kind: "spl", mint: parsePubkey(opts.mintPubkey, "--mint-pubkey").toBase58(), cluster: clusterCaip2 } : { kind: "native" };
|
|
3032
3096
|
if (!offlineMode) {
|
|
3033
3097
|
await preflightLockCurrency(api, agent, normalisedDelegationId, expectedLockAsset);
|
|
@@ -3037,7 +3101,7 @@ async function createLockHandler(opts) {
|
|
|
3037
3101
|
const conn = new import_web32.Connection(rpcUrl, "confirmed");
|
|
3038
3102
|
const asset = await resolveCreateLockAsset(conn, opts, payerKp.publicKey, clusterCaip2);
|
|
3039
3103
|
const amount = asset.amount;
|
|
3040
|
-
const lockIdBytes = (0,
|
|
3104
|
+
const lockIdBytes = (0, import_sdk11.deriveLockId)(normalisedDelegationId);
|
|
3041
3105
|
const ix = buildCreateLockIx({
|
|
3042
3106
|
programId,
|
|
3043
3107
|
lockId: lockIdBytes,
|
|
@@ -3121,63 +3185,12 @@ function registerDelegationCommands(root) {
|
|
|
3121
3185
|
registerDecline(cmd);
|
|
3122
3186
|
registerCancel(cmd);
|
|
3123
3187
|
}
|
|
3124
|
-
var POST_COMMIT_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
3125
|
-
"DELEGATION_ALREADY_EXISTS",
|
|
3126
|
-
"DELEGATION_INVALID_STATE",
|
|
3127
|
-
"DELEGATION_NOT_FOUND",
|
|
3128
|
-
"DELEGATION_RELATIONSHIP_MISMATCH",
|
|
3129
|
-
"DELEGATION_ACCEPTER_IS_OFFERER",
|
|
3130
|
-
"DELEGATION_DECLINER_IS_OFFERER",
|
|
3131
|
-
"DELEGATION_CANCELER_NOT_OFFERER",
|
|
3132
|
-
// PricingPolicy: the offer's terms fell outside the RECIPIENT's
|
|
3133
|
-
// published accept-prefs. Fires in `handleOffer` AFTER the event
|
|
3134
|
-
// row commit (pre-materialization on the server), so the sequence
|
|
3135
|
-
// was consumed — advance it or the corrected re-offer trips
|
|
3136
|
-
// ENV_SEQUENCE_BACKWARDS.
|
|
3137
|
-
// Asset whitelist gate: the offer currency is not a whitelisted
|
|
3138
|
-
// payment asset on this server (or its decimals diverge from the
|
|
3139
|
-
// canonical entry). Same lifecycle as the pricing gate — sequence
|
|
3140
|
-
// consumed. Fix the --currency and re-offer.
|
|
3141
|
-
"DELEGATION_ASSET_NOT_ALLOWED",
|
|
3142
|
-
"DELEGATION_PRICING_MISMATCH",
|
|
3143
|
-
// Capacity gate: the recipient is at its published
|
|
3144
|
-
// maxActiveDelegations cap (or closed with 0). Same lifecycle as
|
|
3145
|
-
// the pricing gate — sequence consumed. TRANSIENT: retry later.
|
|
3146
|
-
"DELEGATION_CAPACITY_EXCEEDED",
|
|
3147
|
-
// `DELEGATION_PENDING_LOCK` fires from the body handler's
|
|
3148
|
-
// `requireDelegationInState` AFTER the event row is persisted
|
|
3149
|
-
// (same code path as DELEGATION_INVALID_STATE), so an accept
|
|
3150
|
-
// against a PENDING_LOCK delegation consumes sender_sequence
|
|
3151
|
-
// even though it rejects.
|
|
3152
|
-
"DELEGATION_PENDING_LOCK",
|
|
3153
|
-
// The `fund` body handler (`handleFund`) emits
|
|
3154
|
-
// these AFTER the event row is committed (same lifecycle as
|
|
3155
|
-
// DELEGATION_INVALID_STATE). `DELEGATION_FUNDER_NOT_OFFERER` (403)
|
|
3156
|
-
// when a non-offerer attempts the fund; `DELEGATION_ALREADY_FUNDED`
|
|
3157
|
-
// (409) on a re-fund of a delegation that already moved into the
|
|
3158
|
-
// lock lifecycle (pending_lock_finalization / locked, or an
|
|
3159
|
-
// in-flight create_lock op). Both consume sender_sequence, so the
|
|
3160
|
-
// CLI must advance `lastSenderSequence` or a retry trips
|
|
3161
|
-
// `ENV_SEQUENCE_BACKWARDS`.
|
|
3162
|
-
"DELEGATION_FUNDER_NOT_OFFERER",
|
|
3163
|
-
"DELEGATION_ALREADY_FUNDED",
|
|
3164
|
-
// Lock-validator mint.owner pre-flight — kept here for
|
|
3165
|
-
// documentation, but the `isPostCommitErrorCode` helper below
|
|
3166
|
-
// also matches any `ESC_LOCK_*` prefix. The full lock-validator
|
|
3167
|
-
// cross-check set (ID_MISMATCH, CONDITION_HASH_MISMATCH,
|
|
3168
|
-
// AMOUNT_DELEGATION_MISMATCH, EXPIRY_TOO_*, PDA_*, etc.) ALSO
|
|
3169
|
-
// fires after the delegation event is committed; missing
|
|
3170
|
-
// entries here would leave `lastSenderSequence` stale and stall
|
|
3171
|
-
// retries on ENV_SEQUENCE_BACKWARDS.
|
|
3172
|
-
"ESC_LOCK_MINT_RPC_FAILED",
|
|
3173
|
-
"ESC_LOCK_MINT_NOT_FOUND",
|
|
3174
|
-
"ESC_LOCK_MINT_OWNER_MISMATCH"
|
|
3175
|
-
]);
|
|
3176
|
-
function isPostCommitErrorCode(code) {
|
|
3177
|
-
return POST_COMMIT_ERROR_CODES.has(code) || code.startsWith("ESC_LOCK_") || code.startsWith("SDK_");
|
|
3178
|
-
}
|
|
3179
3188
|
function registerOffer(parent) {
|
|
3180
|
-
parent.command("offer").description("Open a new delegation addressed to <recipient-did> with the agreed terms INLINE (no escrow lock \u2014 fund AFTER acceptance via `delegation fund`).").argument("<recipient
|
|
3189
|
+
parent.command("offer").description("Open a new delegation addressed to <recipient-did> with the agreed terms INLINE (no escrow lock \u2014 fund AFTER acceptance via `delegation fund`).").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("--delegation-id <uuid>", "Override the auto-generated delegation id (UUID). Reuse the SAME id at `heyarp delegation fund` time. Useful for replay / scripting.").option("--title <s>", "Required: human-readable title for the offer").option("--brief <json>", "Optional structured brief (JSON object)").option("--criterion <s>", "acceptance_criteria \u2014 repeatable; pass --criterion once per bullet", collectRepeated, []).option("--deadline <rfc3339>", 'Optional RFC 3339 deadline (e.g. "2026-12-31T23:59:59Z")').option("--scope <text>", "scope_summary \u2014 short prose describing the agreed work. Required.").option("--amount <s>", 'Optional decimal-as-string amount (e.g. "10.00"). REQUIRES --currency if set.').option("--currency <s>", `Asset identifier: shorthand (${import_sdk12.WELL_KNOWN_ASSET_KEYS.join("|")}) OR raw CAIP-19 string.`).option("--currency-decimals <n>", "Decimal places for base-unit conversion (0-18). Required only when --currency is raw CAIP-19.").option("--currency-symbol <s>", 'Optional UI hint ("USDC", "SOL"). Max 16 chars.').option("--ttl <seconds>", `Envelope TTL in seconds (max ${import_sdk12.MAX_ENVELOPE_TTL_SECONDS} = 24h)`, "3600").option("--verbose", "Print the full envelope before sending and the full server response. Mutually exclusive with --json.", false).option(
|
|
3190
|
+
"--json",
|
|
3191
|
+
'Machine-readable mode \u2014 emit a single JSON object on stdout ({ok, action:"offer", delegationId, eventId, relationshipId, relationshipEventIndex, serverTimestamp, serverEventHash}). Prelude + the "reference this delegation" hints move to stderr; on failure stderr carries `{code, message}`. Mutually exclusive with --verbose.',
|
|
3192
|
+
false
|
|
3193
|
+
).option(
|
|
3181
3194
|
"--wait-until <phase>",
|
|
3182
3195
|
'Block after delivery until the named FSM phase is reached (e.g. delegation.accepted). One of the UNTIL_PHASES from `heyarp status --help`. Exit code 124 on --wait-timeout. Recovers the "sub-agent exits before counterparty accepts" antipattern.'
|
|
3183
3196
|
).option("--wait-timeout <seconds>", "When --wait-until is set: max wall-clock wait (default 300). Exit code 124 on timeout.").option("--wait-interval <seconds>", "When --wait-until is set: poll cadence (default 3, bound [1, 60]).").option(
|
|
@@ -3283,16 +3296,21 @@ function assembleEscrowLockAttachment(opts) {
|
|
|
3283
3296
|
};
|
|
3284
3297
|
}
|
|
3285
3298
|
async function runOffer(recipientDid, opts) {
|
|
3286
|
-
|
|
3299
|
+
if (opts.verbose && opts.json) {
|
|
3300
|
+
throw new Error(
|
|
3301
|
+
"delegation offer: --verbose and --json are mutually exclusive. --json emits the structured server response; --verbose adds dumps that would break `--json | jq`."
|
|
3302
|
+
);
|
|
3303
|
+
}
|
|
3304
|
+
recipientDid = await resolveRecipient(opts.server, "delegation offer", recipientDid, { json: opts.json });
|
|
3287
3305
|
const ttlSeconds = parseTtl("delegation offer", opts.ttl);
|
|
3288
3306
|
if (!opts.title || opts.title.length === 0) {
|
|
3289
3307
|
throw new Error("delegation offer: --title is required (server-side validator rejects empty offers)");
|
|
3290
3308
|
}
|
|
3291
3309
|
const terms = parseOfferTerms("delegation offer", opts);
|
|
3292
3310
|
const offeredAssetId = terms.currency?.asset_id;
|
|
3293
|
-
if (offeredAssetId && !(0,
|
|
3311
|
+
if (offeredAssetId && !(0, import_sdk12.isWhitelistedAssetId)(offeredAssetId)) {
|
|
3294
3312
|
console.error(
|
|
3295
|
-
|
|
3313
|
+
import_chalk9.default.yellow(
|
|
3296
3314
|
`warning: currency '${offeredAssetId}' is not in the static payment whitelist \u2014 the server will reject the offer (DELEGATION_ASSET_NOT_ALLOWED) unless its deploy registers this asset. See 'heyarp assets'.`
|
|
3297
3315
|
)
|
|
3298
3316
|
);
|
|
@@ -3311,43 +3329,43 @@ async function runOffer(recipientDid, opts) {
|
|
|
3311
3329
|
const api = new ArpApiClient(opts.server);
|
|
3312
3330
|
const sender = resolveSenderAgent("delegation offer", opts.server, opts.fromDid);
|
|
3313
3331
|
const content = {
|
|
3314
|
-
action:
|
|
3332
|
+
action: import_sdk12.DelegationActions.OFFER,
|
|
3315
3333
|
delegation_id: delegationId,
|
|
3316
3334
|
title: opts.title,
|
|
3317
3335
|
...terms
|
|
3318
3336
|
};
|
|
3319
3337
|
const body = { type: "delegation", content };
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3338
|
+
progress(opts.json, import_chalk9.default.dim(`Server: ${api.serverUrl}`));
|
|
3339
|
+
progress(opts.json, import_chalk9.default.dim(`Sender: ${sender.did}`));
|
|
3340
|
+
progress(opts.json, import_chalk9.default.dim(`Recipient: ${recipientDid}`));
|
|
3341
|
+
progress(opts.json, import_chalk9.default.dim(`Delegation: ${delegationId}`));
|
|
3324
3342
|
let result;
|
|
3325
3343
|
try {
|
|
3326
3344
|
result = await sendDelegationEnvelope({ api, sender, recipientDid, body, ttlSeconds, verbose: opts.verbose, server: opts.server });
|
|
3327
3345
|
} catch (err) {
|
|
3328
|
-
if (err instanceof ApiError && err.payload.code ===
|
|
3346
|
+
if (err instanceof ApiError && err.payload.code === import_sdk12.DelegationOfferRejectionCodes.ASSET_NOT_ALLOWED) {
|
|
3329
3347
|
const d = err.payload.details;
|
|
3330
|
-
console.error(
|
|
3348
|
+
console.error(import_chalk9.default.yellow(`
|
|
3331
3349
|
The server's payment-asset whitelist rejected this currency.`));
|
|
3332
3350
|
if (d !== void 0) {
|
|
3333
|
-
console.error(
|
|
3334
|
-
console.error(
|
|
3351
|
+
console.error(import_chalk9.default.dim(` offered: ${JSON.stringify(d.offered)}`));
|
|
3352
|
+
console.error(import_chalk9.default.dim(` accepted: ${JSON.stringify(d.accepted)}`));
|
|
3335
3353
|
}
|
|
3336
|
-
console.error(
|
|
3354
|
+
console.error(import_chalk9.default.dim(`
|
|
3337
3355
|
See the whitelist (shorthand keys + canonical decimals):
|
|
3338
3356
|
heyarp assets
|
|
3339
3357
|
then re-offer with a whitelisted --currency.`));
|
|
3340
3358
|
}
|
|
3341
|
-
if (err instanceof ApiError && err.payload.code ===
|
|
3359
|
+
if (err instanceof ApiError && err.payload.code === import_sdk12.DelegationOfferRejectionCodes.PRICING_MISMATCH) {
|
|
3342
3360
|
const d = err.payload.details;
|
|
3343
|
-
console.error(
|
|
3361
|
+
console.error(import_chalk9.default.yellow(`
|
|
3344
3362
|
The recipient's published accept-prefs rejected this offer${d?.reason ? ` (mismatch: ${d.reason})` : ""}.`));
|
|
3345
3363
|
if (d !== void 0) {
|
|
3346
|
-
console.error(
|
|
3347
|
-
console.error(
|
|
3364
|
+
console.error(import_chalk9.default.dim(` accepted: ${JSON.stringify(d.accepted)}`));
|
|
3365
|
+
console.error(import_chalk9.default.dim(` offered: ${JSON.stringify(d.offered)}`));
|
|
3348
3366
|
}
|
|
3349
3367
|
console.error(
|
|
3350
|
-
|
|
3368
|
+
import_chalk9.default.dim(
|
|
3351
3369
|
`
|
|
3352
3370
|
Check what the recipient accepts BEFORE offering:
|
|
3353
3371
|
heyarp agents accept-prefs show ${recipientDid}
|
|
@@ -3355,26 +3373,40 @@ then re-run with matching --currency / --amount.`
|
|
|
3355
3373
|
)
|
|
3356
3374
|
);
|
|
3357
3375
|
}
|
|
3358
|
-
if (err instanceof ApiError && err.payload.code ===
|
|
3376
|
+
if (err instanceof ApiError && err.payload.code === import_sdk12.DelegationOfferRejectionCodes.CAPACITY_EXCEEDED) {
|
|
3359
3377
|
const d = err.payload.details;
|
|
3360
3378
|
const cap = d?.maxActive === 0 ? "closed for new offers (busy)" : `at capacity (${d?.currentActive}/${d?.maxActive} active delegations)`;
|
|
3361
|
-
console.error(
|
|
3379
|
+
console.error(import_chalk9.default.yellow(`
|
|
3362
3380
|
The recipient is ${cap}.`));
|
|
3363
|
-
console.error(
|
|
3381
|
+
console.error(import_chalk9.default.dim("\nThis is TRANSIENT \u2014 your terms are fine. Retry the same offer later, or pick another worker (`heyarp agents --tag \u2026`)."));
|
|
3364
3382
|
}
|
|
3365
3383
|
throw err;
|
|
3366
3384
|
}
|
|
3367
|
-
|
|
3368
|
-
|
|
3385
|
+
if (opts.json) {
|
|
3386
|
+
jsonOut({
|
|
3387
|
+
ok: true,
|
|
3388
|
+
action: "offer",
|
|
3389
|
+
delegationId,
|
|
3390
|
+
eventId: result.eventId,
|
|
3391
|
+
relationshipId: result.relationshipId,
|
|
3392
|
+
relationshipEventIndex: result.relationshipEventIndex,
|
|
3393
|
+
serverTimestamp: result.serverTimestamp,
|
|
3394
|
+
serverEventHash: result.serverEventHash,
|
|
3395
|
+
prevServerEventHash: result.prevServerEventHash ?? null
|
|
3396
|
+
});
|
|
3397
|
+
} else {
|
|
3398
|
+
printIngestResult(result);
|
|
3399
|
+
console.log(import_chalk9.default.dim(`
|
|
3369
3400
|
Reference this delegation on subsequent calls with:`));
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3401
|
+
console.log(import_chalk9.default.dim(` heyarp delegation accept ${result.relationshipId} ${delegationId}`));
|
|
3402
|
+
console.log(import_chalk9.default.dim(` heyarp delegation decline ${result.relationshipId} ${delegationId}`));
|
|
3403
|
+
console.log(import_chalk9.default.dim(` heyarp delegation cancel ${result.relationshipId} ${delegationId}`));
|
|
3404
|
+
console.log(import_chalk9.default.dim(`
|
|
3374
3405
|
After the worker accepts, fund the escrow lock:`));
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3406
|
+
console.log(import_chalk9.default.dim(` heyarp wallet create-lock --delegation-id ${delegationId} --condition-hash <hex> ... > lock.json`));
|
|
3407
|
+
console.log(import_chalk9.default.dim(` heyarp delegation fund ${delegationId} --escrow-lock-from-file lock.json`));
|
|
3408
|
+
}
|
|
3409
|
+
if (opts.waitUntil && !opts.json) {
|
|
3378
3410
|
const untilPhase = parseUntilPhase(opts.waitUntil);
|
|
3379
3411
|
if (untilPhase === void 0) {
|
|
3380
3412
|
throw new Error(`delegation offer: --wait-until requires a phase value (got ${JSON.stringify(opts.waitUntil)})`);
|
|
@@ -3394,7 +3426,7 @@ After the worker accepts, fund the escrow lock:`));
|
|
|
3394
3426
|
}
|
|
3395
3427
|
}
|
|
3396
3428
|
function registerFund(parent) {
|
|
3397
|
-
parent.command("fund").description("Fund an ACCEPTED delegation with the escrow lock (buyer-only). Run AFTER the worker accepts the offer.").argument("<delegation-id>", "Delegation UUID (the one you offered + the worker accepted)").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("--ttl <seconds>",
|
|
3429
|
+
parent.command("fund").description("Fund an ACCEPTED delegation with the escrow lock (buyer-only). Run AFTER the worker accepts the offer.").argument("<delegation-id>", "Delegation UUID (the one you offered + the worker accepted)").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("--ttl <seconds>", `Envelope TTL in seconds (max ${import_sdk12.MAX_ENVELOPE_TTL_SECONDS} = 24h)`, "3600").option("--verbose", "Print the full envelope before sending and the full server response. Mutually exclusive with --json.", false).option(
|
|
3398
3430
|
"--json",
|
|
3399
3431
|
'Machine-readable mode \u2014 emit a single JSON object on stdout ({ok, action:"fund", delegationId, eventId, relationshipId, relationshipEventIndex, serverTimestamp, serverEventHash}). Prelude moves off stdout; on failure stderr carries `{code, message}`. Mutually exclusive with --verbose.',
|
|
3400
3432
|
false
|
|
@@ -3452,23 +3484,23 @@ async function runFund(delegationId, opts) {
|
|
|
3452
3484
|
}
|
|
3453
3485
|
if (result2.kind === "skipped_no_expected_program_id") {
|
|
3454
3486
|
console.error(
|
|
3455
|
-
|
|
3487
|
+
import_chalk9.default.yellow(
|
|
3456
3488
|
"\u26A0 delegation fund: no authoritative expected program-id available (--program-id missing, ARP_ESCROW_PROGRAM_ID env unset, server protocol-fee unreachable). Pre-flight skipped; server-side ESC_LOCK_TX_PROGRAM_ID_MISMATCH check is the only backstop. Set ARP_ESCROW_PROGRAM_ID or pass --program-id to enable pre-flight."
|
|
3457
3489
|
)
|
|
3458
3490
|
);
|
|
3459
3491
|
}
|
|
3460
3492
|
}
|
|
3461
|
-
const content = { action:
|
|
3493
|
+
const content = { action: import_sdk12.DelegationActions.FUND, delegation_id: delegationId };
|
|
3462
3494
|
const body = { type: "delegation", content };
|
|
3463
3495
|
const attachments = { escrow_lock: escrowResult.attachment };
|
|
3464
|
-
progress(opts.json,
|
|
3465
|
-
progress(opts.json,
|
|
3466
|
-
progress(opts.json,
|
|
3467
|
-
progress(opts.json,
|
|
3468
|
-
progress(opts.json,
|
|
3496
|
+
progress(opts.json, import_chalk9.default.dim(`Server: ${api.serverUrl}`));
|
|
3497
|
+
progress(opts.json, import_chalk9.default.dim(`Sender: ${sender.did}`));
|
|
3498
|
+
progress(opts.json, import_chalk9.default.dim(`Recipient: ${resolved.recipientDid}`));
|
|
3499
|
+
progress(opts.json, import_chalk9.default.dim(`Relationship: ${resolved.relationshipId}`));
|
|
3500
|
+
progress(opts.json, import_chalk9.default.dim(`Delegation: ${delegationId} (action=fund)`));
|
|
3469
3501
|
{
|
|
3470
3502
|
const a = escrowResult.attachment;
|
|
3471
|
-
progress(opts.json,
|
|
3503
|
+
progress(opts.json, import_chalk9.default.dim(`Escrow lock attached: lock_id=${a.lock_id} amount=${a.amount} asset_id=${a.asset_id}`));
|
|
3472
3504
|
}
|
|
3473
3505
|
const result = await sendDelegationEnvelope({
|
|
3474
3506
|
api,
|
|
@@ -3494,7 +3526,7 @@ async function runFund(delegationId, opts) {
|
|
|
3494
3526
|
});
|
|
3495
3527
|
} else {
|
|
3496
3528
|
printIngestResult(result);
|
|
3497
|
-
console.log(
|
|
3529
|
+
console.log(import_chalk9.default.dim("\nThe worker waits for the on-chain lock to confirm (LOCKED), then begins work."));
|
|
3498
3530
|
}
|
|
3499
3531
|
if (opts.waitUntil && !opts.json) {
|
|
3500
3532
|
const untilPhase = parseUntilPhase(opts.waitUntil);
|
|
@@ -3559,8 +3591,12 @@ function registerDecline(parent) {
|
|
|
3559
3591
|
"--reason <code>",
|
|
3560
3592
|
// surface the closed enum at help time so operators
|
|
3561
3593
|
// don't have to read source to find acceptable values.
|
|
3562
|
-
`Required: decline reason code (one of: ${
|
|
3563
|
-
).option("--reason-detail <s>", 'Optional free-text elaboration alongside --reason (e.g. "rate floor 0.20 USDC"). Max 512 chars.').option("--verbose", "Print the full envelope before sending and the full server response", false).option(
|
|
3594
|
+
`Required: decline reason code (one of: ${import_sdk12.DECLINE_REASONS.join(", ")}). Carried in body.content.reason so the counterparty's reactor can branch on it.`
|
|
3595
|
+
).option("--reason-detail <s>", 'Optional free-text elaboration alongside --reason (e.g. "rate floor 0.20 USDC"). Max 512 chars.').option("--verbose", "Print the full envelope before sending and the full server response. Mutually exclusive with --json.", false).option(
|
|
3596
|
+
"--json",
|
|
3597
|
+
'Machine-readable mode \u2014 emit a single JSON object on stdout ({ok, action:"decline", delegationId, eventId, relationshipId, relationshipEventIndex, serverTimestamp, serverEventHash}). Prelude + pending-lock poll chatter move off stdout; on failure stderr carries `{code, message}`. Mutually exclusive with --verbose.',
|
|
3598
|
+
false
|
|
3599
|
+
).option(
|
|
3564
3600
|
"--no-wait-for-lock",
|
|
3565
3601
|
"Opt-out of the pending-lock pre-flight poll. Default is ON: when the resolved delegation is in `pending_lock_finalization`, the CLI polls until the on-chain lock is confirmed before signing the envelope (avoids the racy DELEGATION_PENDING_LOCK 409 that consumes sender_sequence)."
|
|
3566
3602
|
).option("--lock-wait-timeout <seconds>", "Max wall-clock seconds to wait for pending-lock pre-flight (default 300).", "300").option("--lock-wait-interval <seconds>", "Poll cadence for pending-lock pre-flight in seconds. Bound to [1, 60].", "3").action(async (relationshipId, delegationId, opts) => {
|
|
@@ -3568,7 +3604,11 @@ function registerDecline(parent) {
|
|
|
3568
3604
|
});
|
|
3569
3605
|
}
|
|
3570
3606
|
function registerCancel(parent) {
|
|
3571
|
-
parent.command("cancel").description("Cancel an OFFERED delegation \u2014 moves to CANCELED. Offerer-only (the OTHER side uses decline).").argument("<relationship-id>", "Relationship UUID").argument("<delegation-id>", "Delegation UUID").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("--ttl <seconds>", "Envelope TTL in seconds", "3600").option("--verbose", "Print the full envelope before sending and the full server response", false).option(
|
|
3607
|
+
parent.command("cancel").description("Cancel an OFFERED delegation \u2014 moves to CANCELED. Offerer-only (the OTHER side uses decline).").argument("<relationship-id>", "Relationship UUID").argument("<delegation-id>", "Delegation UUID").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("--ttl <seconds>", "Envelope TTL in seconds", "3600").option("--verbose", "Print the full envelope before sending and the full server response. Mutually exclusive with --json.", false).option(
|
|
3608
|
+
"--json",
|
|
3609
|
+
'Machine-readable mode \u2014 emit a single JSON object on stdout ({ok, action:"cancel", delegationId, eventId, relationshipId, relationshipEventIndex, serverTimestamp, serverEventHash}). Prelude + pending-lock poll chatter move off stdout; on failure stderr carries `{code, message}`. Mutually exclusive with --verbose.',
|
|
3610
|
+
false
|
|
3611
|
+
).option(
|
|
3572
3612
|
"--no-wait-for-lock",
|
|
3573
3613
|
"Opt-out of the pending-lock pre-flight poll. Default is ON: when the resolved delegation is in `pending_lock_finalization`, the CLI polls until the on-chain lock is confirmed before signing the envelope (avoids the racy DELEGATION_PENDING_LOCK 409 that consumes sender_sequence)."
|
|
3574
3614
|
).option("--lock-wait-timeout <seconds>", "Max wall-clock seconds to wait for pending-lock pre-flight (default 300).", "300").option("--lock-wait-interval <seconds>", "Poll cadence for pending-lock pre-flight in seconds. Bound to [1, 60].", "3").action(async (relationshipId, delegationId, opts) => {
|
|
@@ -3588,7 +3628,7 @@ async function runFollowupAction(relationshipId, delegationId, action, opts) {
|
|
|
3588
3628
|
const lockWaitTimeoutSec = parseLockWaitTimeout(cmdName, opts.lockWaitTimeout);
|
|
3589
3629
|
const lockWaitIntervalSec = parseLockWaitInterval(cmdName, opts.lockWaitInterval);
|
|
3590
3630
|
let declinePayload = null;
|
|
3591
|
-
if (action ===
|
|
3631
|
+
if (action === import_sdk12.DelegationActions.DECLINE) {
|
|
3592
3632
|
const reason = parseDeclineReason(cmdName, opts.reason);
|
|
3593
3633
|
const validatedDetail = parseReasonDetail(cmdName, opts.reasonDetail);
|
|
3594
3634
|
declinePayload = validatedDetail ? { reason, reasonDetail: validatedDetail } : { reason };
|
|
@@ -3597,7 +3637,7 @@ async function runFollowupAction(relationshipId, delegationId, action, opts) {
|
|
|
3597
3637
|
const sender = resolveSenderAgent(cmdName, opts.server, opts.fromDid);
|
|
3598
3638
|
const signer = makeSigner(sender);
|
|
3599
3639
|
const resolved = await resolveDelegationRefs(cmdName, api, signer, { relationshipId, delegationId, action, selfDid: sender.did });
|
|
3600
|
-
if (resolved.state ===
|
|
3640
|
+
if (resolved.state === import_sdk12.DelegationStates.PENDING_LOCK_FINALIZATION && opts.waitForLock !== false) {
|
|
3601
3641
|
await awaitDelegationLockFinalized(cmdName, api, signer, {
|
|
3602
3642
|
relationshipId,
|
|
3603
3643
|
delegationId,
|
|
@@ -3619,10 +3659,10 @@ async function runFollowupAction(relationshipId, delegationId, action, opts) {
|
|
|
3619
3659
|
if (declinePayload.reasonDetail) content.reason_detail = declinePayload.reasonDetail;
|
|
3620
3660
|
}
|
|
3621
3661
|
const body = { type: "delegation", content };
|
|
3622
|
-
progress(opts.json,
|
|
3623
|
-
progress(opts.json,
|
|
3624
|
-
progress(opts.json,
|
|
3625
|
-
progress(opts.json,
|
|
3662
|
+
progress(opts.json, import_chalk9.default.dim(`Server: ${api.serverUrl}`));
|
|
3663
|
+
progress(opts.json, import_chalk9.default.dim(`Sender: ${sender.did}`));
|
|
3664
|
+
progress(opts.json, import_chalk9.default.dim(`Relationship: ${relationshipId}`));
|
|
3665
|
+
progress(opts.json, import_chalk9.default.dim(`Delegation: ${delegationId} (action=${action}${action === import_sdk12.DelegationActions.DECLINE ? `, reason=${content.reason}` : ""})`));
|
|
3626
3666
|
const result = await sendDelegationEnvelope({
|
|
3627
3667
|
api,
|
|
3628
3668
|
sender,
|
|
@@ -3651,9 +3691,9 @@ async function runFollowupAction(relationshipId, delegationId, action, opts) {
|
|
|
3651
3691
|
async function sendDelegationEnvelope(args) {
|
|
3652
3692
|
const nextSequence = (args.sender.lastSenderSequence ?? 0) + 1;
|
|
3653
3693
|
const protectedBlock = {
|
|
3654
|
-
protocol_version:
|
|
3655
|
-
purpose:
|
|
3656
|
-
message_id: (0,
|
|
3694
|
+
protocol_version: import_sdk12.CURRENT_PROTOCOL_VERSION,
|
|
3695
|
+
purpose: import_sdk12.Purpose.ENVELOPE,
|
|
3696
|
+
message_id: (0, import_sdk12.uuidV4)(),
|
|
3657
3697
|
sender_did: args.sender.did,
|
|
3658
3698
|
recipient_did: args.recipientDid,
|
|
3659
3699
|
// `relationship_id: null` matches the handshake
|
|
@@ -3662,20 +3702,20 @@ async function sendDelegationEnvelope(args) {
|
|
|
3662
3702
|
// existing relationship row.
|
|
3663
3703
|
relationship_id: null,
|
|
3664
3704
|
sender_sequence: nextSequence,
|
|
3665
|
-
sender_nonce: (0,
|
|
3666
|
-
timestamp: (0,
|
|
3667
|
-
expires_at: (0,
|
|
3705
|
+
sender_nonce: (0, import_sdk12.senderNonce)(),
|
|
3706
|
+
timestamp: (0, import_sdk12.rfc3339)(),
|
|
3707
|
+
expires_at: (0, import_sdk12.expiresAt)(args.ttlSeconds),
|
|
3668
3708
|
delivery_id: null
|
|
3669
3709
|
};
|
|
3670
3710
|
const signer = makeSigner(args.sender);
|
|
3671
|
-
const envelope = (0,
|
|
3711
|
+
const envelope = (0, import_sdk12.signEnvelope)({
|
|
3672
3712
|
protected: protectedBlock,
|
|
3673
3713
|
body: args.body,
|
|
3674
3714
|
identitySecretKey: signer.identitySecretKey,
|
|
3675
3715
|
attachments: args.attachments
|
|
3676
3716
|
});
|
|
3677
3717
|
if (args.verbose) {
|
|
3678
|
-
console.log(
|
|
3718
|
+
console.log(import_chalk9.default.bold("\nEnvelope (pre-send):"));
|
|
3679
3719
|
console.log(formatJson(envelope));
|
|
3680
3720
|
}
|
|
3681
3721
|
try {
|
|
@@ -3683,7 +3723,7 @@ async function sendDelegationEnvelope(args) {
|
|
|
3683
3723
|
updateAgentLocal(args.server, args.sender.did, { lastSenderSequence: nextSequence });
|
|
3684
3724
|
return result;
|
|
3685
3725
|
} catch (err) {
|
|
3686
|
-
if (err instanceof ApiError && isPostCommitErrorCode(err.payload.code)) {
|
|
3726
|
+
if (err instanceof ApiError && (0, import_sdk12.isPostCommitErrorCode)(err.payload.code)) {
|
|
3687
3727
|
updateAgentLocal(args.server, args.sender.did, { lastSenderSequence: nextSequence });
|
|
3688
3728
|
}
|
|
3689
3729
|
throw err;
|
|
@@ -3705,7 +3745,7 @@ async function resolveDelegationRefs(cmdName, api, signer, args) {
|
|
|
3705
3745
|
);
|
|
3706
3746
|
}
|
|
3707
3747
|
let recipientDid;
|
|
3708
|
-
if (args.action ===
|
|
3748
|
+
if (args.action === import_sdk12.DelegationActions.CANCEL) {
|
|
3709
3749
|
const firstEvents = await api.listEvents(args.relationshipId, signer, { since: 0, limit: 1 });
|
|
3710
3750
|
const handshake = firstEvents[0];
|
|
3711
3751
|
if (!handshake) {
|
|
@@ -3730,7 +3770,7 @@ async function resolveDelegationRefs(cmdName, api, signer, args) {
|
|
|
3730
3770
|
async function awaitDelegationLockFinalized(cmdName, api, signer, args) {
|
|
3731
3771
|
const log = args.log ?? ((line) => console.log(line));
|
|
3732
3772
|
log(
|
|
3733
|
-
|
|
3773
|
+
import_chalk9.default.dim(
|
|
3734
3774
|
`
|
|
3735
3775
|
[--wait-for-lock] delegation ${args.delegationId} is awaiting on-chain lock confirmation; polling until ready (interval=${args.intervalSec}s timeout=${args.timeoutSec}s)`
|
|
3736
3776
|
)
|
|
@@ -3745,7 +3785,7 @@ async function awaitDelegationLockFinalized(cmdName, api, signer, args) {
|
|
|
3745
3785
|
after = page[page.length - 1].id;
|
|
3746
3786
|
}
|
|
3747
3787
|
};
|
|
3748
|
-
const outcome = await (0,
|
|
3788
|
+
const outcome = await (0, import_sdk12.pollUntil)({
|
|
3749
3789
|
fetch: fetchRow,
|
|
3750
3790
|
// Match on either "row not found at all" OR "state moved
|
|
3751
3791
|
// past pending_lock_finalization". The post-poll branch
|
|
@@ -3755,7 +3795,7 @@ async function awaitDelegationLockFinalized(cmdName, api, signer, args) {
|
|
|
3755
3795
|
// rows return cleanly. Polling on null would loop pointlessly
|
|
3756
3796
|
// until the deadline fires and surface a misleading "timed
|
|
3757
3797
|
// out" message for what's actually a wrong-id problem.
|
|
3758
|
-
predicate: (row2) => row2 === null || row2.state !==
|
|
3798
|
+
predicate: (row2) => row2 === null || row2.state !== import_sdk12.DelegationStates.PENDING_LOCK_FINALIZATION,
|
|
3759
3799
|
intervalMs: args.intervalSec * 1e3,
|
|
3760
3800
|
timeoutMs: args.timeoutSec * 1e3,
|
|
3761
3801
|
// Swallow ONLY transient errors. A 4xx during the poll is a
|
|
@@ -3769,7 +3809,7 @@ async function awaitDelegationLockFinalized(cmdName, api, signer, args) {
|
|
|
3769
3809
|
if (err instanceof ApiError && err.status >= 400 && err.status < 500) {
|
|
3770
3810
|
throw err;
|
|
3771
3811
|
}
|
|
3772
|
-
log(
|
|
3812
|
+
log(import_chalk9.default.dim(` poll: transient fetch error (${err instanceof Error ? err.message : String(err)})`));
|
|
3773
3813
|
}
|
|
3774
3814
|
});
|
|
3775
3815
|
if (outcome.kind === "timeout") {
|
|
@@ -3786,12 +3826,12 @@ async function awaitDelegationLockFinalized(cmdName, api, signer, args) {
|
|
|
3786
3826
|
`${cmdName}: delegation ${args.delegationId} disappeared from relationship ${args.relationshipId} during --wait-for-lock pre-flight. Re-check the delegation id with \`heyarp delegations ${args.relationshipId}\`.`
|
|
3787
3827
|
);
|
|
3788
3828
|
}
|
|
3789
|
-
if (row.state !==
|
|
3829
|
+
if (row.state !== import_sdk12.DelegationStates.OFFERED) {
|
|
3790
3830
|
throw new Error(
|
|
3791
3831
|
`${cmdName}: delegation ${args.delegationId} transitioned to '${row.state}' while waiting for on-chain lock confirmation; cannot ${args.action}. Re-read the delegation timeline with \`heyarp delegations ${args.relationshipId}\` to see the latest state.`
|
|
3792
3832
|
);
|
|
3793
3833
|
}
|
|
3794
|
-
log(
|
|
3834
|
+
log(import_chalk9.default.dim(`[--wait-for-lock] delegation ${args.delegationId} ready (state=${row.state}); proceeding with ${args.action}.`));
|
|
3795
3835
|
return row;
|
|
3796
3836
|
}
|
|
3797
3837
|
function parseLockWaitTimeout(cmdName, raw) {
|
|
@@ -3817,12 +3857,12 @@ function parseLockWaitInterval(cmdName, raw) {
|
|
|
3817
3857
|
return n;
|
|
3818
3858
|
}
|
|
3819
3859
|
function printIngestResult(result) {
|
|
3820
|
-
console.log(
|
|
3821
|
-
console.log(`${
|
|
3822
|
-
console.log(`${
|
|
3823
|
-
console.log(`${
|
|
3824
|
-
console.log(`${
|
|
3825
|
-
console.log(`${
|
|
3860
|
+
console.log(import_chalk9.default.green("\nDelivered."));
|
|
3861
|
+
console.log(`${import_chalk9.default.bold("Event id")}: ${import_chalk9.default.cyan(result.eventId)}`);
|
|
3862
|
+
console.log(`${import_chalk9.default.bold("Relationship id")}: ${import_chalk9.default.cyan(result.relationshipId)}`);
|
|
3863
|
+
console.log(`${import_chalk9.default.bold("Chain index")}: ${import_chalk9.default.cyan(String(result.relationshipEventIndex))}`);
|
|
3864
|
+
console.log(`${import_chalk9.default.bold("Server timestamp")}: ${import_chalk9.default.cyan(result.serverTimestamp)}`);
|
|
3865
|
+
console.log(`${import_chalk9.default.bold("Server event hash")}: ${import_chalk9.default.cyan(result.serverEventHash)}`);
|
|
3826
3866
|
}
|
|
3827
3867
|
function parseOfferTerms(cmdName, opts) {
|
|
3828
3868
|
const out = {};
|
|
@@ -3846,7 +3886,7 @@ function parseOfferTerms(cmdName, opts) {
|
|
|
3846
3886
|
if (opts.amount) {
|
|
3847
3887
|
out.amount = opts.amount;
|
|
3848
3888
|
if (!opts.currency) {
|
|
3849
|
-
throw new Error(`${cmdName}: --amount requires --currency. Shorthand: ${
|
|
3889
|
+
throw new Error(`${cmdName}: --amount requires --currency. Shorthand: ${import_sdk12.WELL_KNOWN_ASSET_KEYS.join(", ")}, or raw CAIP-19 + --currency-decimals.`);
|
|
3850
3890
|
}
|
|
3851
3891
|
out.currency = buildAssetIdentifier(cmdName, DELEGATION_CURRENCY_FLAGS, opts.currency, opts.currencyDecimals, opts.currencySymbol);
|
|
3852
3892
|
} else if (opts.currency) {
|
|
@@ -3869,7 +3909,7 @@ function resolveOfferDelegationId(rawCliId, escrow) {
|
|
|
3869
3909
|
cliId = rawCliId.toLowerCase();
|
|
3870
3910
|
}
|
|
3871
3911
|
if (escrow === void 0) {
|
|
3872
|
-
return cliId ?? (0,
|
|
3912
|
+
return cliId ?? (0, import_sdk12.uuidV4)();
|
|
3873
3913
|
}
|
|
3874
3914
|
if (escrow.delegationIdFromLock !== void 0) {
|
|
3875
3915
|
const fileId = escrow.delegationIdFromLock;
|
|
@@ -3894,20 +3934,15 @@ function requireUuidNormalised(cmdName, raw, label) {
|
|
|
3894
3934
|
requireUuid2(cmdName, raw, label);
|
|
3895
3935
|
return raw.toLowerCase();
|
|
3896
3936
|
}
|
|
3897
|
-
function requireDid(cmdName, did, label) {
|
|
3898
|
-
if (typeof did !== "string" || !did.startsWith("did:arp:") || did.length <= "did:arp:".length) {
|
|
3899
|
-
throw new Error(`${cmdName}: ${label} must look like 'did:arp:...' (got '${did}')`);
|
|
3900
|
-
}
|
|
3901
|
-
}
|
|
3902
3937
|
function collectRepeated(value, previous) {
|
|
3903
3938
|
return [...previous, value];
|
|
3904
3939
|
}
|
|
3905
3940
|
function parseDeclineReason(cmdName, raw) {
|
|
3906
3941
|
if (raw === void 0 || raw === "") {
|
|
3907
|
-
throw new Error(`${cmdName}: --reason is required when declining (one of: ${
|
|
3942
|
+
throw new Error(`${cmdName}: --reason is required when declining (one of: ${import_sdk12.DECLINE_REASONS.join(", ")})`);
|
|
3908
3943
|
}
|
|
3909
|
-
if (!(0,
|
|
3910
|
-
throw new Error(`${cmdName}: --reason must be one of ${
|
|
3944
|
+
if (!(0, import_sdk12.isDeclineReason)(raw)) {
|
|
3945
|
+
throw new Error(`${cmdName}: --reason must be one of ${import_sdk12.DECLINE_REASONS.join(", ")} (got '${raw}')`);
|
|
3911
3946
|
}
|
|
3912
3947
|
return raw;
|
|
3913
3948
|
}
|
|
@@ -3922,10 +3957,10 @@ function parseReasonDetail(cmdName, raw) {
|
|
|
3922
3957
|
return raw;
|
|
3923
3958
|
}
|
|
3924
3959
|
function buildAssetIdentifier(cmdName, labels, rawCurrency, rawDecimals, rawSymbol) {
|
|
3925
|
-
const resolved = (0,
|
|
3960
|
+
const resolved = (0, import_sdk12.resolveAsset)(rawCurrency);
|
|
3926
3961
|
if (!resolved) {
|
|
3927
3962
|
throw new Error(
|
|
3928
|
-
`${cmdName}: ${labels.currencyFlag} '${rawCurrency}' is not a known shorthand or a valid CAIP-19 string. Shorthand: ${
|
|
3963
|
+
`${cmdName}: ${labels.currencyFlag} '${rawCurrency}' is not a known shorthand or a valid CAIP-19 string. Shorthand: ${import_sdk12.WELL_KNOWN_ASSET_KEYS.join(", ")}. Or pass a raw CAIP-19 id (e.g. "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/spl:EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v") with ${labels.decimalsFlag}.`
|
|
3929
3964
|
);
|
|
3930
3965
|
}
|
|
3931
3966
|
let decimals = resolved.decimals;
|
|
@@ -3934,20 +3969,20 @@ function buildAssetIdentifier(cmdName, labels, rawCurrency, rawDecimals, rawSymb
|
|
|
3934
3969
|
throw new Error(`${cmdName}: ${labels.currencyFlag} is a raw CAIP-19 string; ${labels.decimalsFlag} (0-18) is required to convert amounts to base units.`);
|
|
3935
3970
|
}
|
|
3936
3971
|
const parsed = Number(rawDecimals);
|
|
3937
|
-
if (!Number.isInteger(parsed) || parsed <
|
|
3972
|
+
if (!Number.isInteger(parsed) || parsed < import_sdk12.ASSET_DECIMALS_MIN || parsed > import_sdk12.ASSET_DECIMALS_MAX) {
|
|
3938
3973
|
throw new Error(`${cmdName}: ${labels.decimalsFlag} must be an integer in [0, 18] (got '${rawDecimals}').`);
|
|
3939
3974
|
}
|
|
3940
3975
|
decimals = parsed;
|
|
3941
3976
|
} else if (rawDecimals !== void 0) {
|
|
3942
3977
|
const parsed = Number(rawDecimals);
|
|
3943
|
-
if (!Number.isInteger(parsed) || parsed <
|
|
3978
|
+
if (!Number.isInteger(parsed) || parsed < import_sdk12.ASSET_DECIMALS_MIN || parsed > import_sdk12.ASSET_DECIMALS_MAX) {
|
|
3944
3979
|
throw new Error(`${cmdName}: ${labels.decimalsFlag} must be an integer in [0, 18] (got '${rawDecimals}').`);
|
|
3945
3980
|
}
|
|
3946
3981
|
decimals = parsed;
|
|
3947
3982
|
}
|
|
3948
3983
|
let symbol = resolved.symbol;
|
|
3949
3984
|
if (rawSymbol !== void 0) {
|
|
3950
|
-
if (rawSymbol.length
|
|
3985
|
+
if (rawSymbol.length < import_sdk12.ASSET_SYMBOL_MIN_LEN || rawSymbol.length > import_sdk12.ASSET_SYMBOL_MAX_LEN) {
|
|
3951
3986
|
throw new Error(`${cmdName}: ${labels.symbolFlag} must be 1-16 chars (got length ${rawSymbol.length}).`);
|
|
3952
3987
|
}
|
|
3953
3988
|
symbol = rawSymbol;
|
|
@@ -3961,9 +3996,10 @@ var DELEGATION_CURRENCY_FLAGS = {
|
|
|
3961
3996
|
};
|
|
3962
3997
|
|
|
3963
3998
|
// src/commands/delegations.ts
|
|
3964
|
-
var
|
|
3999
|
+
var import_sdk13 = require("@heyanon-arp/sdk");
|
|
4000
|
+
var import_chalk10 = __toESM(require("chalk"));
|
|
3965
4001
|
init_api();
|
|
3966
|
-
var ALLOWED_STATES = /* @__PURE__ */ new Set([
|
|
4002
|
+
var ALLOWED_STATES = /* @__PURE__ */ new Set([import_sdk13.DelegationStates.OFFERED, import_sdk13.DelegationStates.ACCEPTED, import_sdk13.DelegationStates.DECLINED, import_sdk13.DelegationStates.CANCELED]);
|
|
3967
4003
|
function registerDelegationsCommand(root) {
|
|
3968
4004
|
root.command("delegations").description("List delegations for a relationship (one row per delegationId, oldest-first)").argument("<relationship-id>", "Relationship UUID").option("--server <url>", "Override ARP server base URL").option("--state <s>", "Filter by exact state (offered|accepted|declined|canceled)").option("--after <id>", "Cursor: pass the previous page's last `id` to fetch the next page").option("--limit <n>", "Max rows to return (1..100)", "20").option("--from-did <did>", "Signer DID \u2014 required only if multiple agents are registered against this server").option(
|
|
3969
4005
|
"--verbose",
|
|
@@ -3983,9 +4019,9 @@ async function runDelegations(relationshipId, opts) {
|
|
|
3983
4019
|
const state = parseState(opts.state);
|
|
3984
4020
|
const api = new ArpApiClient(opts.server);
|
|
3985
4021
|
const sender = resolveSenderAgent("delegations", opts.server, opts.fromDid);
|
|
3986
|
-
progress(opts.json,
|
|
3987
|
-
progress(opts.json,
|
|
3988
|
-
progress(opts.json,
|
|
4022
|
+
progress(opts.json, import_chalk10.default.dim(`Server: ${api.serverUrl}`));
|
|
4023
|
+
progress(opts.json, import_chalk10.default.dim(`Signer: ${sender.did}`));
|
|
4024
|
+
progress(opts.json, import_chalk10.default.dim(`Relationship: ${relationshipId}`));
|
|
3989
4025
|
const query = { limit };
|
|
3990
4026
|
if (state) query.state = state;
|
|
3991
4027
|
if (opts.after) query.after = opts.after;
|
|
@@ -3996,7 +4032,7 @@ async function runDelegations(relationshipId, opts) {
|
|
|
3996
4032
|
return;
|
|
3997
4033
|
}
|
|
3998
4034
|
if (rows.length === 0) {
|
|
3999
|
-
console.log(
|
|
4035
|
+
console.log(import_chalk10.default.dim("\n(no delegations for this relationship)"));
|
|
4000
4036
|
return;
|
|
4001
4037
|
}
|
|
4002
4038
|
console.log("");
|
|
@@ -4012,19 +4048,19 @@ async function runDelegations(relationshipId, opts) {
|
|
|
4012
4048
|
}));
|
|
4013
4049
|
}
|
|
4014
4050
|
const lastId = rows[rows.length - 1].id;
|
|
4015
|
-
console.log(
|
|
4051
|
+
console.log(import_chalk10.default.dim(`
|
|
4016
4052
|
${rows.length} delegation row(s). Paginate with --after ${lastId}.`));
|
|
4017
4053
|
}
|
|
4018
4054
|
function formatDelegationLine(d, selfDid, opts = {}) {
|
|
4019
|
-
const idHead_ =
|
|
4055
|
+
const idHead_ = import_chalk10.default.bold(opts.fullIds ? d.delegationId : idHead(d.delegationId));
|
|
4020
4056
|
const state = colorState(d.state).padEnd(stateColumnWidth());
|
|
4021
|
-
const offerer = d.offererDid === selfDid ?
|
|
4057
|
+
const offerer = d.offererDid === selfDid ? import_chalk10.default.bold("me") : import_chalk10.default.dim(opts.fullIds ? d.offererDid : didHead(d.offererDid));
|
|
4022
4058
|
const amount = formatAmount(d);
|
|
4023
|
-
const title = d.title ?
|
|
4059
|
+
const title = d.title ? import_chalk10.default.dim(`"${truncate2(d.title, 40)}"`) : import_chalk10.default.dim("(no title)");
|
|
4024
4060
|
let declineSuffix = "";
|
|
4025
|
-
if (d.state ===
|
|
4061
|
+
if (d.state === import_sdk13.DelegationStates.DECLINED && d.declineReason) {
|
|
4026
4062
|
const detail = d.declineReasonDetail ? `: ${truncate2(d.declineReasonDetail, 40)}` : "";
|
|
4027
|
-
declineSuffix = ` ${
|
|
4063
|
+
declineSuffix = ` ${import_chalk10.default.dim(`(reason: ${d.declineReason}${detail})`)}`;
|
|
4028
4064
|
}
|
|
4029
4065
|
return `${idHead_} ${state} ${offerer} ${amount} ${title}${declineSuffix}`;
|
|
4030
4066
|
}
|
|
@@ -4037,35 +4073,35 @@ function colorState(s) {
|
|
|
4037
4073
|
// returns `undefined` and `formatDelegationLine` crashes with
|
|
4038
4074
|
// `TypeError: Cannot read properties of undefined (reading
|
|
4039
4075
|
// 'padEnd')` on any listing containing such a row.
|
|
4040
|
-
case
|
|
4041
|
-
return
|
|
4042
|
-
case
|
|
4043
|
-
return
|
|
4044
|
-
case
|
|
4045
|
-
return
|
|
4076
|
+
case import_sdk13.DelegationStates.OFFERED:
|
|
4077
|
+
return import_chalk10.default.yellow("offered");
|
|
4078
|
+
case import_sdk13.DelegationStates.PENDING_LOCK_FINALIZATION:
|
|
4079
|
+
return import_chalk10.default.yellow("pending_lock");
|
|
4080
|
+
case import_sdk13.DelegationStates.ACCEPTED:
|
|
4081
|
+
return import_chalk10.default.green("accepted");
|
|
4046
4082
|
// The on-chain escrow lock is confirmed. Distinct branch so a
|
|
4047
4083
|
// LOCKED row renders without hitting the defensive fallback
|
|
4048
4084
|
// (which would otherwise echo the raw state).
|
|
4049
|
-
case
|
|
4050
|
-
return
|
|
4051
|
-
case
|
|
4052
|
-
return
|
|
4053
|
-
case
|
|
4054
|
-
return
|
|
4085
|
+
case import_sdk13.DelegationStates.LOCKED:
|
|
4086
|
+
return import_chalk10.default.green("locked");
|
|
4087
|
+
case import_sdk13.DelegationStates.DECLINED:
|
|
4088
|
+
return import_chalk10.default.red("declined");
|
|
4089
|
+
case import_sdk13.DelegationStates.CANCELED:
|
|
4090
|
+
return import_chalk10.default.dim("canceled");
|
|
4055
4091
|
// Terminal escrow outcomes: completed = payee paid;
|
|
4056
4092
|
// failed = create_lock never landed; refunded = funds returned
|
|
4057
4093
|
// to the buyer (work expired / dispute closed);
|
|
4058
4094
|
// dispute_resolved = operator ruled.
|
|
4059
|
-
case
|
|
4060
|
-
return
|
|
4061
|
-
case
|
|
4062
|
-
return
|
|
4063
|
-
case
|
|
4064
|
-
return
|
|
4065
|
-
case
|
|
4066
|
-
return
|
|
4067
|
-
case
|
|
4068
|
-
return
|
|
4095
|
+
case import_sdk13.DelegationStates.COMPLETED:
|
|
4096
|
+
return import_chalk10.default.green("completed");
|
|
4097
|
+
case import_sdk13.DelegationStates.FAILED:
|
|
4098
|
+
return import_chalk10.default.red("failed");
|
|
4099
|
+
case import_sdk13.DelegationStates.REFUNDED:
|
|
4100
|
+
return import_chalk10.default.red("refunded");
|
|
4101
|
+
case import_sdk13.DelegationStates.DISPUTING:
|
|
4102
|
+
return import_chalk10.default.yellow("disputing");
|
|
4103
|
+
case import_sdk13.DelegationStates.DISPUTE_RESOLVED:
|
|
4104
|
+
return import_chalk10.default.red("dispute_resolved");
|
|
4069
4105
|
default: {
|
|
4070
4106
|
const _exhaustive = s;
|
|
4071
4107
|
void _exhaustive;
|
|
@@ -4077,9 +4113,9 @@ function stateColumnWidth() {
|
|
|
4077
4113
|
return 12;
|
|
4078
4114
|
}
|
|
4079
4115
|
function formatAmount(d) {
|
|
4080
|
-
if (!d.amount) return
|
|
4116
|
+
if (!d.amount) return import_chalk10.default.dim("(no amount)");
|
|
4081
4117
|
const currency = d.currency ? d.currency.symbol ?? d.currency.assetId : "?";
|
|
4082
|
-
return
|
|
4118
|
+
return import_chalk10.default.cyan(`${d.amount} ${currency}`);
|
|
4083
4119
|
}
|
|
4084
4120
|
function idHead(id) {
|
|
4085
4121
|
if (id.length <= 12) return id;
|
|
@@ -4110,7 +4146,7 @@ function parseLimit2(raw) {
|
|
|
4110
4146
|
}
|
|
4111
4147
|
|
|
4112
4148
|
// src/commands/did-doc.ts
|
|
4113
|
-
var
|
|
4149
|
+
var import_sdk14 = require("@heyanon-arp/sdk");
|
|
4114
4150
|
init_api();
|
|
4115
4151
|
function registerDidDocCommand(root) {
|
|
4116
4152
|
root.command("did-doc").description(
|
|
@@ -4119,7 +4155,7 @@ function registerDidDocCommand(root) {
|
|
|
4119
4155
|
"--field <path>",
|
|
4120
4156
|
"Extract a single value via a dotted path. Supports object property access (`id`), numeric array indexes (`verificationMethod.0`), and `#fragment` array selectors that match a verification-method or service entry by its `id` suffix (`verificationMethod.#settlement.publicKeyMultibase`). Two well-known shortcuts skip the path entirely AND strip the multibase prefix: `settlementPublicKey` / `identityPublicKey` emit the raw base58 pubkey ready for flags like `--recipient-pubkey`. Scalar values (string / number / boolean) emit raw to stdout for shell composition (`KEY=$(heyarp did-doc ... --field ...)`); objects / arrays emit as pretty-printed JSON. Mutually exclusive with `--json` since `--field` already controls the shape."
|
|
4121
4157
|
).action(async (did, opts) => {
|
|
4122
|
-
if (!(0,
|
|
4158
|
+
if (!(0, import_sdk14.isValidDid)(did)) {
|
|
4123
4159
|
throw new Error(`'${did}' is not a syntactically valid did:arp identifier`);
|
|
4124
4160
|
}
|
|
4125
4161
|
if (opts.json && opts.field !== void 0) {
|
|
@@ -4231,8 +4267,8 @@ function describeShape(value) {
|
|
|
4231
4267
|
}
|
|
4232
4268
|
|
|
4233
4269
|
// src/commands/doctor.ts
|
|
4234
|
-
var
|
|
4235
|
-
var
|
|
4270
|
+
var import_sdk15 = require("@heyanon-arp/sdk");
|
|
4271
|
+
var import_chalk11 = __toESM(require("chalk"));
|
|
4236
4272
|
init_api();
|
|
4237
4273
|
function registerDoctorCommand(root) {
|
|
4238
4274
|
root.command("doctor").description("Liveness probe for a counterparty: resolve DID document + read protocol activity. No auth.").argument("<did>", "did:arp:<base58btc> of the agent to probe").option("--server <url>", "Override ARP server base URL").option("--json", "Machine-readable: single JSON object on stdout. Pipe-safe.", false).action(async (did, opts) => {
|
|
@@ -4241,7 +4277,7 @@ function registerDoctorCommand(root) {
|
|
|
4241
4277
|
}
|
|
4242
4278
|
var LISTENING_THRESHOLD_SECONDS = 15 * 60;
|
|
4243
4279
|
async function runDoctor(did, opts) {
|
|
4244
|
-
if (!(0,
|
|
4280
|
+
if (!(0, import_sdk15.isValidDid)(did)) {
|
|
4245
4281
|
throw new Error(`'${did}' is not a syntactically valid did:arp identifier`);
|
|
4246
4282
|
}
|
|
4247
4283
|
const api = new ArpApiClient(opts.server);
|
|
@@ -4325,39 +4361,39 @@ async function probe(api, did) {
|
|
|
4325
4361
|
}
|
|
4326
4362
|
function formatDoctorReport(r) {
|
|
4327
4363
|
const lines = [];
|
|
4328
|
-
lines.push(`${
|
|
4329
|
-
lines.push(`${
|
|
4364
|
+
lines.push(`${import_chalk11.default.dim("Server:")} ${r.server}`);
|
|
4365
|
+
lines.push(`${import_chalk11.default.dim("Target DID:")} ${r.did}`);
|
|
4330
4366
|
if (!r.didDocument.found) {
|
|
4331
|
-
lines.push(`${
|
|
4367
|
+
lines.push(`${import_chalk11.default.dim("DID doc:")} ${import_chalk11.default.red("\u2717")} not found`);
|
|
4332
4368
|
} else {
|
|
4333
4369
|
const registered = r.didDocument.registeredAt ? ` (registered ${r.didDocument.registeredAt})` : "";
|
|
4334
|
-
lines.push(`${
|
|
4370
|
+
lines.push(`${import_chalk11.default.dim("DID doc:")} ${import_chalk11.default.green("\u2713")} resolved${registered}`);
|
|
4335
4371
|
}
|
|
4336
4372
|
if (r.activity) {
|
|
4337
4373
|
if (r.activity.lastEventAt === null) {
|
|
4338
|
-
lines.push(`${
|
|
4374
|
+
lines.push(`${import_chalk11.default.dim("Activity:")} ${import_chalk11.default.dim("(no events ever \u2014 fresh agent)")}`);
|
|
4339
4375
|
} else {
|
|
4340
4376
|
const ageMin = r.activity.ageSeconds !== null ? Math.floor(r.activity.ageSeconds / 60) : null;
|
|
4341
4377
|
const ageStr = ageMin !== null && ageMin > 0 ? `${ageMin}m ago` : `${r.activity.ageSeconds}s ago`;
|
|
4342
|
-
lines.push(`${
|
|
4378
|
+
lines.push(`${import_chalk11.default.dim("Activity:")} last event ${ageStr} (${r.activity.lastEventAt})`);
|
|
4343
4379
|
}
|
|
4344
4380
|
if (r.activity.lastSeenAt !== null && r.activity.lastSeenAt !== void 0) {
|
|
4345
4381
|
const seenMin = r.activity.seenAgeSeconds !== null && r.activity.seenAgeSeconds !== void 0 ? Math.floor(r.activity.seenAgeSeconds / 60) : null;
|
|
4346
4382
|
const seenStr = seenMin !== null && seenMin > 0 ? `${seenMin}m ago` : `${r.activity.seenAgeSeconds}s ago`;
|
|
4347
|
-
lines.push(`${
|
|
4383
|
+
lines.push(`${import_chalk11.default.dim("Last seen:")} signed request ${seenStr} (${r.activity.lastSeenAt})`);
|
|
4348
4384
|
}
|
|
4349
4385
|
if (r.activity.inboxStreamActive === true) {
|
|
4350
|
-
lines.push(`${
|
|
4386
|
+
lines.push(`${import_chalk11.default.dim("Inbox SSE:")} ${import_chalk11.default.green("\u2713")} active subscription on the central server`);
|
|
4351
4387
|
}
|
|
4352
4388
|
}
|
|
4353
|
-
const verdictColor = r.verdict === "LISTENING" ?
|
|
4389
|
+
const verdictColor = r.verdict === "LISTENING" ? import_chalk11.default.green : r.verdict === "DORMANT" ? import_chalk11.default.red : import_chalk11.default.yellow;
|
|
4354
4390
|
lines.push("");
|
|
4355
|
-
lines.push(`${
|
|
4391
|
+
lines.push(`${import_chalk11.default.bold("Verdict:")} ${verdictColor(r.verdict)} \u2014 ${r.reason}`);
|
|
4356
4392
|
return lines.join("\n");
|
|
4357
4393
|
}
|
|
4358
4394
|
|
|
4359
4395
|
// src/commands/envelope.ts
|
|
4360
|
-
var
|
|
4396
|
+
var import_chalk12 = __toESM(require("chalk"));
|
|
4361
4397
|
init_api();
|
|
4362
4398
|
function registerEnvelopeCommand(root) {
|
|
4363
4399
|
root.command("envelope").description("Fetch one canonical envelope by eventId \u2014 full body for inspection (signed read)").argument("<event-id>", "Event UUID \u2014 copy from `heyarp inbox`, `heyarp events`, or a counterparty citation").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("--json", "Machine-readable: emit only the envelope JSON object on stdout (no prelude, no chalk). Pipe-safe.", false).action(async (eventId, opts) => {
|
|
@@ -4368,9 +4404,9 @@ async function runEnvelope(eventId, opts) {
|
|
|
4368
4404
|
const api = new ArpApiClient(opts.server);
|
|
4369
4405
|
const sender = resolveSenderAgent("envelope", opts.server, opts.fromDid);
|
|
4370
4406
|
if (!opts.json) {
|
|
4371
|
-
console.log(
|
|
4372
|
-
console.log(
|
|
4373
|
-
console.log(
|
|
4407
|
+
console.log(import_chalk12.default.dim(`Server: ${api.serverUrl}`));
|
|
4408
|
+
console.log(import_chalk12.default.dim(`Signer: ${sender.did}`));
|
|
4409
|
+
console.log(import_chalk12.default.dim(`Event: ${eventId}`));
|
|
4374
4410
|
}
|
|
4375
4411
|
const signer = makeSigner(sender);
|
|
4376
4412
|
const event = await api.getEvent(sender.did, eventId, signer);
|
|
@@ -4379,29 +4415,29 @@ async function runEnvelope(eventId, opts) {
|
|
|
4379
4415
|
return;
|
|
4380
4416
|
}
|
|
4381
4417
|
console.log("");
|
|
4382
|
-
console.log(
|
|
4418
|
+
console.log(import_chalk12.default.bold("Envelope:"));
|
|
4383
4419
|
console.log(formatJson(event));
|
|
4384
4420
|
console.log("");
|
|
4385
4421
|
console.log(formatHints(event));
|
|
4386
4422
|
}
|
|
4387
4423
|
function formatHints(event) {
|
|
4388
4424
|
const lines = [];
|
|
4389
|
-
lines.push(`${
|
|
4390
|
-
lines.push(`${
|
|
4391
|
-
lines.push(`${
|
|
4392
|
-
lines.push(`${
|
|
4425
|
+
lines.push(`${import_chalk12.default.dim("relationshipId:")} ${import_chalk12.default.cyan(event.relationshipId)}`);
|
|
4426
|
+
lines.push(`${import_chalk12.default.dim("serverEventHash:")} ${import_chalk12.default.cyan(event.serverEventHash)}`);
|
|
4427
|
+
lines.push(`${import_chalk12.default.dim("eventId:")} ${import_chalk12.default.cyan(event.eventId)}`);
|
|
4428
|
+
lines.push(`${import_chalk12.default.dim("relationshipEventIndex:")} ${import_chalk12.default.cyan(String(event.relationshipEventIndex))}`);
|
|
4393
4429
|
return lines.join("\n");
|
|
4394
4430
|
}
|
|
4395
4431
|
|
|
4396
4432
|
// src/commands/escrow.ts
|
|
4397
|
-
var
|
|
4433
|
+
var import_sdk17 = require("@heyanon-arp/sdk");
|
|
4398
4434
|
var import_utils2 = require("@noble/hashes/utils");
|
|
4399
|
-
var
|
|
4435
|
+
var import_chalk13 = __toESM(require("chalk"));
|
|
4400
4436
|
init_api();
|
|
4401
4437
|
|
|
4402
4438
|
// src/commands/escrow-actions.ts
|
|
4403
4439
|
var import_node_crypto = require("crypto");
|
|
4404
|
-
var
|
|
4440
|
+
var import_sdk16 = require("@heyanon-arp/sdk");
|
|
4405
4441
|
var import_web33 = require("@solana/web3.js");
|
|
4406
4442
|
init_api();
|
|
4407
4443
|
var FEE_BUFFER_LAMPORTS = 10000000n;
|
|
@@ -4415,7 +4451,7 @@ async function setup(cmd, delegationIdArg, opts) {
|
|
|
4415
4451
|
const delegationId = normaliseDelegationId(delegationIdArg);
|
|
4416
4452
|
const fetched = await fetchLockAccount(conn, programId, delegationId);
|
|
4417
4453
|
if (!fetched) {
|
|
4418
|
-
const lockPda = deriveLockPda(programId, (0,
|
|
4454
|
+
const lockPda = deriveLockPda(programId, (0, import_sdk16.deriveLockId)(delegationId)).toBase58();
|
|
4419
4455
|
throw new Error(
|
|
4420
4456
|
`${cmd}: no on-chain Lock for delegation ${delegationId} (PDA ${lockPda} not found on ${rpcUrl}). Either the buyer hasn't funded yet (delegation fund \u2192 server relays create_lock), or you're pointing at the wrong cluster/program.`
|
|
4421
4457
|
);
|
|
@@ -4440,7 +4476,7 @@ function nowSecs() {
|
|
|
4440
4476
|
function deadlinePassed(ctx) {
|
|
4441
4477
|
return ctx.lock.expiry > 0n && nowSecs() >= ctx.lock.expiry;
|
|
4442
4478
|
}
|
|
4443
|
-
var SYSTEM_PROGRAM_B58 =
|
|
4479
|
+
var SYSTEM_PROGRAM_B58 = import_sdk16.SYSTEM_PROGRAM_ID_BASE58;
|
|
4444
4480
|
function effectiveFeeRecipient(lock) {
|
|
4445
4481
|
if (lock.feeRecipientAtLock !== SYSTEM_PROGRAM_B58) return new import_web33.PublicKey(lock.feeRecipientAtLock);
|
|
4446
4482
|
if (lock.treasuryAtLock && lock.treasuryAtLock !== SYSTEM_PROGRAM_B58) return new import_web33.PublicKey(lock.treasuryAtLock);
|
|
@@ -4502,7 +4538,7 @@ function emit(ctx, action, signature, extra = {}) {
|
|
|
4502
4538
|
}
|
|
4503
4539
|
async function acceptHandler(delegationId, opts) {
|
|
4504
4540
|
const ctx = await setup("escrow accept", delegationId, opts);
|
|
4505
|
-
requireState(ctx, [
|
|
4541
|
+
requireState(ctx, [import_sdk16.LockStates.CREATED], "Accept is only possible before any other transition; if it shows in_progress you already accepted.");
|
|
4506
4542
|
requireSigner(ctx, "payee", ctx.lock.payee);
|
|
4507
4543
|
const stake = ctx.lock.workerStakeAtLock;
|
|
4508
4544
|
await preflightLamports(ctx, stake, `the worker stake (${stake} lamports, returned when the lock settles in your favour)`);
|
|
@@ -4512,7 +4548,7 @@ async function acceptHandler(delegationId, opts) {
|
|
|
4512
4548
|
}
|
|
4513
4549
|
async function submitWorkHandler(delegationId, opts) {
|
|
4514
4550
|
const ctx = await setup("escrow submit-work", delegationId, opts);
|
|
4515
|
-
requireState(ctx, [
|
|
4551
|
+
requireState(ctx, [import_sdk16.LockStates.IN_PROGRESS], "Submit needs an accepted lock ('created' \u2192 run `heyarp escrow accept` first; terminal \u2192 the cycle already ended).");
|
|
4516
4552
|
requireSigner(ctx, "payee", ctx.lock.payee);
|
|
4517
4553
|
if (deadlinePassed(ctx)) {
|
|
4518
4554
|
throw new Error(
|
|
@@ -4523,7 +4559,7 @@ async function submitWorkHandler(delegationId, opts) {
|
|
|
4523
4559
|
let reviewDeadline = null;
|
|
4524
4560
|
try {
|
|
4525
4561
|
const fresh = await fetchLockAccount(ctx.conn, ctx.programId, ctx.delegationId);
|
|
4526
|
-
if (fresh && fresh.lock.state ===
|
|
4562
|
+
if (fresh && fresh.lock.state === import_sdk16.LockStates.SUBMITTED && fresh.lock.expiry > 0n) {
|
|
4527
4563
|
reviewDeadline = new Date(Number(fresh.lock.expiry) * 1e3).toISOString();
|
|
4528
4564
|
}
|
|
4529
4565
|
} catch {
|
|
@@ -4536,22 +4572,25 @@ async function submitWorkHandler(delegationId, opts) {
|
|
|
4536
4572
|
}
|
|
4537
4573
|
async function claimHandler(delegationId, opts) {
|
|
4538
4574
|
const ctx = await setup("escrow claim", delegationId, opts);
|
|
4539
|
-
requireState(ctx, [
|
|
4575
|
+
requireState(ctx, [import_sdk16.LockStates.SUBMITTED], "Claim needs submitted work ('in_progress' \u2192 the worker must `escrow submit-work` first; 'paid' \u2192 already claimed).");
|
|
4540
4576
|
const me = ctx.keypair.publicKey.toBase58();
|
|
4541
4577
|
let role;
|
|
4542
4578
|
if (me === ctx.lock.payer) {
|
|
4543
|
-
role =
|
|
4579
|
+
role = import_sdk16.EscrowReleaseMethods.BUYER_APPROVED;
|
|
4544
4580
|
} else if (me === ctx.lock.payee) {
|
|
4545
4581
|
if (!deadlinePassed(ctx)) {
|
|
4546
4582
|
throw new Error(
|
|
4547
4583
|
`escrow claim: the review window is still open (until ${expiryIso(ctx)}). As the worker you can self-claim only AFTER it lapses; before that the buyer must approve (or dispute).`
|
|
4548
4584
|
);
|
|
4549
4585
|
}
|
|
4550
|
-
role =
|
|
4586
|
+
role = import_sdk16.EscrowReleaseMethods.REVIEW_TIMEOUT;
|
|
4551
4587
|
} else {
|
|
4552
4588
|
throw new Error(`escrow claim: your settlement key ${me} is neither the payer (${ctx.lock.payer}) nor the payee (${ctx.lock.payee}) of this lock.`);
|
|
4553
4589
|
}
|
|
4554
|
-
progress(
|
|
4590
|
+
progress(
|
|
4591
|
+
ctx.opts.json,
|
|
4592
|
+
role === import_sdk16.EscrowReleaseMethods.BUYER_APPROVED ? "approving payment as the buyer \u2014 this RELEASES the escrow and is irreversible" : "self-claiming after review timeout"
|
|
4593
|
+
);
|
|
4555
4594
|
const sig = await sendIx(
|
|
4556
4595
|
ctx,
|
|
4557
4596
|
buildClaimWorkPaymentIx({
|
|
@@ -4568,7 +4607,7 @@ async function claimHandler(delegationId, opts) {
|
|
|
4568
4607
|
}
|
|
4569
4608
|
async function cancelHandler(delegationId, opts) {
|
|
4570
4609
|
const ctx = await setup("escrow cancel", delegationId, opts);
|
|
4571
|
-
requireState(ctx, [
|
|
4610
|
+
requireState(ctx, [import_sdk16.LockStates.CREATED], "Cancel is the pre-accept exit only \u2014 once the worker accepted ('in_progress') the windows model governs.");
|
|
4572
4611
|
requireSigner(ctx, "payer", ctx.lock.payer);
|
|
4573
4612
|
const sig = await sendIx(
|
|
4574
4613
|
ctx,
|
|
@@ -4583,7 +4622,7 @@ async function cancelHandler(delegationId, opts) {
|
|
|
4583
4622
|
}
|
|
4584
4623
|
async function claimExpiredHandler(delegationId, opts) {
|
|
4585
4624
|
const ctx = await setup("escrow claim-expired", delegationId, opts);
|
|
4586
|
-
requireState(ctx, [
|
|
4625
|
+
requireState(ctx, [import_sdk16.LockStates.IN_PROGRESS], "Claim-expired recovers an accepted-but-never-submitted lock; 'submitted' work goes through claim/dispute instead.");
|
|
4587
4626
|
requireSigner(ctx, "payer", ctx.lock.payer);
|
|
4588
4627
|
if (!deadlinePassed(ctx)) {
|
|
4589
4628
|
throw new Error(`escrow claim-expired: the work window is still open (until ${expiryIso(ctx)}). The worker can still submit; the chain will reject this claim until then.`);
|
|
@@ -4601,7 +4640,7 @@ async function claimExpiredHandler(delegationId, opts) {
|
|
|
4601
4640
|
}
|
|
4602
4641
|
async function disputeOpenHandler(delegationId, opts) {
|
|
4603
4642
|
const ctx = await setup("escrow dispute open", delegationId, opts);
|
|
4604
|
-
requireState(ctx, [
|
|
4643
|
+
requireState(ctx, [import_sdk16.LockStates.SUBMITTED], "Disputes open against SUBMITTED work, inside the review window.");
|
|
4605
4644
|
requireSigner(ctx, "payer", ctx.lock.payer);
|
|
4606
4645
|
if (deadlinePassed(ctx)) {
|
|
4607
4646
|
throw new Error(
|
|
@@ -4616,7 +4655,7 @@ async function disputeOpenHandler(delegationId, opts) {
|
|
|
4616
4655
|
}
|
|
4617
4656
|
async function disputeCloseHandler(delegationId, opts) {
|
|
4618
4657
|
const ctx = await setup("escrow dispute close", delegationId, opts);
|
|
4619
|
-
requireState(ctx, [
|
|
4658
|
+
requireState(ctx, [import_sdk16.LockStates.DISPUTING], "Close only applies to an OPEN dispute that the operator never resolved.");
|
|
4620
4659
|
const me = ctx.keypair.publicKey.toBase58();
|
|
4621
4660
|
if (me !== ctx.lock.payer && me !== ctx.lock.payee) {
|
|
4622
4661
|
throw new Error(`escrow dispute close: your settlement key ${me} is neither party of this lock.`);
|
|
@@ -4641,7 +4680,7 @@ async function disputeCloseHandler(delegationId, opts) {
|
|
|
4641
4680
|
}
|
|
4642
4681
|
async function disputeResolveHandler(delegationId, opts) {
|
|
4643
4682
|
const ctx = await setup("escrow dispute resolve", delegationId, opts);
|
|
4644
|
-
requireState(ctx, [
|
|
4683
|
+
requireState(ctx, [import_sdk16.LockStates.DISPUTING], "Resolve only applies to an OPEN dispute, inside the dispute window.");
|
|
4645
4684
|
if (deadlinePassed(ctx)) {
|
|
4646
4685
|
throw new Error(
|
|
4647
4686
|
`escrow dispute resolve: the dispute window lapsed at ${expiryIso(ctx)} \u2014 the chain rejects late rulings (LockExpired); either party can now \`escrow dispute close\` instead.`
|
|
@@ -4685,7 +4724,7 @@ async function showHandler(delegationId, opts) {
|
|
|
4685
4724
|
jsonOut({
|
|
4686
4725
|
delegation_id: normalised.slice("del_".length),
|
|
4687
4726
|
lock_exists: false,
|
|
4688
|
-
lock_pda: deriveLockPda(programId, (0,
|
|
4727
|
+
lock_pda: deriveLockPda(programId, (0, import_sdk16.deriveLockId)(normalised)).toBase58(),
|
|
4689
4728
|
rpc_url: redactRpcUrl(rpcUrl)
|
|
4690
4729
|
});
|
|
4691
4730
|
return;
|
|
@@ -4762,7 +4801,7 @@ function registerEscrowCommands(root) {
|
|
|
4762
4801
|
"Compute canonical condition_hash (32-byte hex) for `heyarp wallet create-lock --condition-hash <hex>` from the DELEGATION terms. Projects the flags to the canonical subset and hashes via SDK deriveDelegationConditionHash \u2014 no server fetch. The SAME terms MUST go into `delegation offer` or the server rejects the lock (ESC_LOCK_CONDITION_HASH_MISMATCH)."
|
|
4763
4802
|
).requiredOption("--delegation-id <id>", "Delegation UUID this lock binds (drives the on-chain lock_id + the condition_hash identity binding)").requiredOption("--scope <text>", "scope_summary \u2014 short prose describing the agreed work").option(
|
|
4764
4803
|
"--currency <s>",
|
|
4765
|
-
`Asset identifier bound into the hash: shorthand (${
|
|
4804
|
+
`Asset identifier bound into the hash: shorthand (${import_sdk17.WELL_KNOWN_ASSET_KEYS.join("|")}) OR raw CAIP-19 string. Optional but must match the offer's --currency.`
|
|
4766
4805
|
).option("--currency-decimals <n>", "Decimal places (0-18). Required only when --currency is raw CAIP-19.").option("--currency-symbol <s>", 'Optional UI hint ("USDC", "SOL"). Max 16 chars.').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("--json", "Machine-readable JSON: {delegation_id, condition_hash_hex, projected_subset}", false).action(async (opts) => {
|
|
4767
4806
|
await runDeriveConditionHash(opts);
|
|
4768
4807
|
});
|
|
@@ -4776,7 +4815,7 @@ async function runEscrowInfo(opts) {
|
|
|
4776
4815
|
const api = new ArpApiClient(opts.server);
|
|
4777
4816
|
const status = await api.getEscrowConfig();
|
|
4778
4817
|
if (opts.json) {
|
|
4779
|
-
progress(true,
|
|
4818
|
+
progress(true, import_chalk13.default.dim(`Server: ${api.serverUrl}`));
|
|
4780
4819
|
jsonOut(status);
|
|
4781
4820
|
} else {
|
|
4782
4821
|
console.log(formatEscrowConfigStatus(api.serverUrl, status));
|
|
@@ -4785,35 +4824,35 @@ async function runEscrowInfo(opts) {
|
|
|
4785
4824
|
function formatEscrowConfigStatus(serverUrl, s) {
|
|
4786
4825
|
const lines = [];
|
|
4787
4826
|
const win = (secs) => secs % 3600 === 0 ? `${secs / 3600}h` : secs % 60 === 0 ? `${secs / 60}m` : `${secs}s`;
|
|
4788
|
-
lines.push(`${
|
|
4789
|
-
lines.push(`${
|
|
4790
|
-
lines.push(`${
|
|
4791
|
-
lines.push(`${
|
|
4792
|
-
lines.push(`${
|
|
4827
|
+
lines.push(`${import_chalk13.default.dim("Server:")} ${serverUrl}`);
|
|
4828
|
+
lines.push(`${import_chalk13.default.dim("Program ID:")} ${s.programId}`);
|
|
4829
|
+
lines.push(`${import_chalk13.default.dim("Admin:")} ${s.admin}`);
|
|
4830
|
+
lines.push(`${import_chalk13.default.dim("Treasury:")} ${s.treasury}`);
|
|
4831
|
+
lines.push(`${import_chalk13.default.dim("Paused:")} ${s.paused ? import_chalk13.default.yellow("YES (new locks rejected)") : import_chalk13.default.green("no")}`);
|
|
4793
4832
|
lines.push("");
|
|
4794
|
-
lines.push(
|
|
4795
|
-
lines.push(` ${
|
|
4796
|
-
lines.push(` ${
|
|
4797
|
-
lines.push(` ${
|
|
4833
|
+
lines.push(import_chalk13.default.bold("Windows (rolling deadlines):"));
|
|
4834
|
+
lines.push(` ${import_chalk13.default.dim("work:")} ${win(s.workWindowSecs)} ${import_chalk13.default.dim("(accept \u2192 submit_work)")}`);
|
|
4835
|
+
lines.push(` ${import_chalk13.default.dim("review:")} ${win(s.reviewWindowSecs)} ${import_chalk13.default.dim("(submit_work \u2192 buyer approve / worker self-claim)")}`);
|
|
4836
|
+
lines.push(` ${import_chalk13.default.dim("dispute:")} ${win(s.disputeWindowSecs)} ${import_chalk13.default.dim("(open_dispute \u2192 operator resolve / timeout close)")}`);
|
|
4798
4837
|
lines.push("");
|
|
4799
|
-
lines.push(
|
|
4800
|
-
lines.push(` ${
|
|
4801
|
-
lines.push(` ${
|
|
4838
|
+
lines.push(import_chalk13.default.bold("Stakes:"));
|
|
4839
|
+
lines.push(` ${import_chalk13.default.dim("worker stake:")} ${s.workerStakeLamports} lamports ${import_chalk13.default.dim("(escrowed at accept_lock, returned on completion)")}`);
|
|
4840
|
+
lines.push(` ${import_chalk13.default.dim("operator dispute fee:")} ${s.operatorDisputeFeeLamports} lamports`);
|
|
4802
4841
|
lines.push("");
|
|
4803
|
-
lines.push(
|
|
4842
|
+
lines.push(import_chalk13.default.bold("Protocol fee:"));
|
|
4804
4843
|
if (!s.feeEnabled || s.feeBps === 0) {
|
|
4805
|
-
lines.push(` ${
|
|
4806
|
-
lines.push(` ${
|
|
4807
|
-
lines.push(` ${
|
|
4844
|
+
lines.push(` ${import_chalk13.default.green("DISABLED")}`);
|
|
4845
|
+
lines.push(` ${import_chalk13.default.dim("fee_bps:")} ${s.feeBps}`);
|
|
4846
|
+
lines.push(` ${import_chalk13.default.dim("fee_recipient:")} ${s.feeRecipient}`);
|
|
4808
4847
|
lines.push("");
|
|
4809
|
-
lines.push(
|
|
4848
|
+
lines.push(import_chalk13.default.dim(` New locks will snapshot fee_bps=0 \u2014 payee receives 100% on claim.`));
|
|
4810
4849
|
} else {
|
|
4811
4850
|
const pct = (s.feeBps / 100).toFixed(2);
|
|
4812
|
-
lines.push(` ${
|
|
4813
|
-
lines.push(` ${
|
|
4851
|
+
lines.push(` ${import_chalk13.default.yellow("ENABLED")} \u2014 ${pct}% of payee slice (${s.feeBps} bps)`);
|
|
4852
|
+
lines.push(` ${import_chalk13.default.dim("fee_recipient:")} ${s.feeRecipient}`);
|
|
4814
4853
|
lines.push("");
|
|
4815
|
-
lines.push(
|
|
4816
|
-
lines.push(
|
|
4854
|
+
lines.push(import_chalk13.default.dim(` New locks will snapshot fee_bps=${s.feeBps} onto themselves.`));
|
|
4855
|
+
lines.push(import_chalk13.default.dim(` Existing locks keep their lock-time snapshot \u2014 no retroactive change.`));
|
|
4817
4856
|
}
|
|
4818
4857
|
return lines.join("\n");
|
|
4819
4858
|
}
|
|
@@ -4838,10 +4877,10 @@ async function runDeriveConditionHash(opts) {
|
|
|
4838
4877
|
}
|
|
4839
4878
|
const api = new ArpApiClient(opts.server);
|
|
4840
4879
|
const sender = resolveSenderAgent(cmdName, opts.server, opts.fromDid);
|
|
4841
|
-
progress(opts.json,
|
|
4842
|
-
progress(opts.json,
|
|
4880
|
+
progress(opts.json, import_chalk13.default.dim(`Server: ${api.serverUrl}`));
|
|
4881
|
+
progress(opts.json, import_chalk13.default.dim(`Signer: ${sender.did}`));
|
|
4843
4882
|
const subset = projectDelegationForHash(cmdName, opts, delegationId);
|
|
4844
|
-
const hashBytes = (0,
|
|
4883
|
+
const hashBytes = (0, import_sdk17.deriveDelegationConditionHash)(subset);
|
|
4845
4884
|
const hex = (0, import_utils2.bytesToHex)(hashBytes);
|
|
4846
4885
|
if (opts.json) {
|
|
4847
4886
|
jsonOut({
|
|
@@ -4851,14 +4890,14 @@ async function runDeriveConditionHash(opts) {
|
|
|
4851
4890
|
});
|
|
4852
4891
|
return;
|
|
4853
4892
|
}
|
|
4854
|
-
console.log(
|
|
4855
|
-
console.log(
|
|
4856
|
-
console.log(
|
|
4857
|
-
if (subset.currency !== void 0) console.log(
|
|
4893
|
+
console.log(import_chalk13.default.dim(`Delegation: ${delegationId}`));
|
|
4894
|
+
console.log(import_chalk13.default.dim("Subset hashed:"));
|
|
4895
|
+
console.log(import_chalk13.default.dim(` scopeSummary: ${subset.scopeSummary ?? "(unset)"}`));
|
|
4896
|
+
if (subset.currency !== void 0) console.log(import_chalk13.default.dim(` currency.asset_id: ${subset.currency.asset_id}`));
|
|
4858
4897
|
console.log("");
|
|
4859
|
-
console.log(`${
|
|
4898
|
+
console.log(`${import_chalk13.default.bold("condition_hash:")} ${hex}`);
|
|
4860
4899
|
console.log("");
|
|
4861
|
-
console.log(
|
|
4900
|
+
console.log(import_chalk13.default.dim(`Pass to: heyarp wallet create-lock --delegation-id ${delegationId} --condition-hash ${hex} ...`));
|
|
4862
4901
|
}
|
|
4863
4902
|
function classifyRecoverOutcome(local, server) {
|
|
4864
4903
|
if (local === server) return { kind: "in-sync", value: local };
|
|
@@ -4891,39 +4930,40 @@ async function runRecoverSequence(opts) {
|
|
|
4891
4930
|
applied: opts.apply === true && outcome.kind === "behind"
|
|
4892
4931
|
});
|
|
4893
4932
|
} else {
|
|
4894
|
-
console.log(
|
|
4895
|
-
console.log(
|
|
4933
|
+
console.log(import_chalk13.default.dim(`DID: ${sender.did}`));
|
|
4934
|
+
console.log(import_chalk13.default.dim(`Server: ${api.serverUrl}`));
|
|
4896
4935
|
console.log("");
|
|
4897
|
-
console.log(`${
|
|
4898
|
-
console.log(`${
|
|
4936
|
+
console.log(`${import_chalk13.default.bold("Local lastSenderSequence:")} ${local}`);
|
|
4937
|
+
console.log(`${import_chalk13.default.bold("Server lastSenderSequence:")} ${server}`);
|
|
4899
4938
|
console.log("");
|
|
4900
4939
|
if (outcome.kind === "in-sync") {
|
|
4901
|
-
console.log(
|
|
4940
|
+
console.log(import_chalk13.default.green("\u2713 In sync \u2014 no recovery needed."));
|
|
4902
4941
|
} else if (outcome.kind === "behind") {
|
|
4903
|
-
console.log(
|
|
4942
|
+
console.log(import_chalk13.default.yellow(`\u26A0 Local is BEHIND by ${outcome.drift}. Server has accepted envelopes the CLI didn't classify as post-commit.`));
|
|
4904
4943
|
if (opts.apply) {
|
|
4905
|
-
console.log(
|
|
4944
|
+
console.log(import_chalk13.default.dim("Writing server value to local state..."));
|
|
4906
4945
|
} else {
|
|
4907
|
-
console.log(
|
|
4946
|
+
console.log(import_chalk13.default.dim("Dry-run. Pass --apply to update local state to match server."));
|
|
4908
4947
|
}
|
|
4909
4948
|
} else {
|
|
4910
|
-
console.log(
|
|
4911
|
-
console.log(
|
|
4912
|
-
console.log(
|
|
4913
|
-
console.log(
|
|
4914
|
-
console.log(
|
|
4949
|
+
console.log(import_chalk13.default.red(`\u2717 Local is AHEAD of server by ${outcome.drift}. This should not happen under normal protocol flow.`));
|
|
4950
|
+
console.log(import_chalk13.default.dim("NOT applying \u2014 manual investigation needed. Possible causes:"));
|
|
4951
|
+
console.log(import_chalk13.default.dim(" - Local agents.json edited by hand to a wrong value"));
|
|
4952
|
+
console.log(import_chalk13.default.dim(" - Server data lost / rolled back"));
|
|
4953
|
+
console.log(import_chalk13.default.dim(" - HEYARP_HOME pointed at a wrong account"));
|
|
4915
4954
|
}
|
|
4916
4955
|
}
|
|
4917
4956
|
if (outcome.kind === "behind" && opts.apply) {
|
|
4918
4957
|
updateAgentLocal(opts.server, sender.did, { lastSenderSequence: outcome.server });
|
|
4919
|
-
if (!opts.json) console.log(
|
|
4958
|
+
if (!opts.json) console.log(import_chalk13.default.green(`\u2713 Local lastSenderSequence updated: ${local} \u2192 ${outcome.server}`));
|
|
4920
4959
|
}
|
|
4921
4960
|
if (outcome.kind === "behind" && !opts.apply) process.exitCode = 1;
|
|
4922
4961
|
if (outcome.kind === "ahead") process.exitCode = 2;
|
|
4923
4962
|
}
|
|
4924
4963
|
|
|
4925
4964
|
// src/commands/events.ts
|
|
4926
|
-
var
|
|
4965
|
+
var import_sdk18 = require("@heyanon-arp/sdk");
|
|
4966
|
+
var import_chalk14 = __toESM(require("chalk"));
|
|
4927
4967
|
init_api();
|
|
4928
4968
|
function registerEventsCommand(root) {
|
|
4929
4969
|
root.command("events").description("List events for a relationship (chain order, ascending index)").argument("<relationship-id>", "Relationship UUID").option("--server <url>", "Override ARP server base URL").option("--since <n>", "Cursor: only events with relationshipEventIndex >= since").option("--limit <n>", "Max events to return (1..100)", "20").option("--from-did <did>", "Signer DID \u2014 required only if multiple agents are registered against this server").option(
|
|
@@ -4967,14 +5007,14 @@ async function runEvents(relationshipId, opts) {
|
|
|
4967
5007
|
const api = new ArpApiClient(opts.server);
|
|
4968
5008
|
const sender = resolveSenderAgent("events", opts.server, opts.fromDid);
|
|
4969
5009
|
if (!opts.json) {
|
|
4970
|
-
console.log(
|
|
4971
|
-
console.log(
|
|
4972
|
-
console.log(
|
|
5010
|
+
console.log(import_chalk14.default.dim(`Server: ${api.serverUrl}`));
|
|
5011
|
+
console.log(import_chalk14.default.dim(`Signer: ${sender.did}`));
|
|
5012
|
+
console.log(import_chalk14.default.dim(`Relationship: ${relationshipId}`));
|
|
4973
5013
|
}
|
|
4974
5014
|
const query = { limit };
|
|
4975
5015
|
if (since !== void 0) query.since = since;
|
|
4976
|
-
if (opts.successOnly) query.readModelStatus =
|
|
4977
|
-
else if (opts.rejectedOnly) query.readModelStatus =
|
|
5016
|
+
if (opts.successOnly) query.readModelStatus = import_sdk18.ReadModelStatuses.MATERIALIZED;
|
|
5017
|
+
else if (opts.rejectedOnly) query.readModelStatus = import_sdk18.ReadModelStatuses.REJECTED;
|
|
4978
5018
|
const signer = makeSigner(sender);
|
|
4979
5019
|
const events = await api.listEvents(relationshipId, signer, query);
|
|
4980
5020
|
if (opts.json) {
|
|
@@ -4982,7 +5022,7 @@ async function runEvents(relationshipId, opts) {
|
|
|
4982
5022
|
return;
|
|
4983
5023
|
}
|
|
4984
5024
|
if (events.length === 0) {
|
|
4985
|
-
console.log(
|
|
5025
|
+
console.log(import_chalk14.default.dim("\n(no events for this relationship)"));
|
|
4986
5026
|
return;
|
|
4987
5027
|
}
|
|
4988
5028
|
console.log("");
|
|
@@ -4998,20 +5038,20 @@ async function runEvents(relationshipId, opts) {
|
|
|
4998
5038
|
}));
|
|
4999
5039
|
}
|
|
5000
5040
|
const lastIndex = events[events.length - 1].relationshipEventIndex;
|
|
5001
|
-
console.log(
|
|
5041
|
+
console.log(import_chalk14.default.dim(`
|
|
5002
5042
|
${events.length} event(s). Paginate with --since ${lastIndex + 1}.`));
|
|
5003
5043
|
}
|
|
5004
5044
|
function formatEventLine(ev, selfDid, opts = {}) {
|
|
5005
|
-
const idx =
|
|
5045
|
+
const idx = import_chalk14.default.bold(`#${ev.relationshipEventIndex}`);
|
|
5006
5046
|
const eventId = opts.fullIds ? ev.eventId : eventIdHead(ev.eventId);
|
|
5007
5047
|
const type = ev.type.padEnd(20);
|
|
5008
5048
|
const direction = directionLabel(ev, selfDid, opts);
|
|
5009
5049
|
const hash = opts.fullIds ? ev.serverEventHash : hashHead(ev.serverEventHash);
|
|
5010
5050
|
const extra = extraDetail(ev);
|
|
5011
|
-
const tail = extra ? ` ${
|
|
5012
|
-
const status = ev.readModelStatus ??
|
|
5013
|
-
const statusGlyph = status ===
|
|
5014
|
-
return `${statusGlyph}${idx} ${
|
|
5051
|
+
const tail = extra ? ` ${import_chalk14.default.dim(`(${extra})`)}` : "";
|
|
5052
|
+
const status = ev.readModelStatus ?? import_sdk18.ReadModelStatuses.MATERIALIZED;
|
|
5053
|
+
const statusGlyph = status === import_sdk18.ReadModelStatuses.REJECTED ? `${import_chalk14.default.red("\u2717")} ` : " ";
|
|
5054
|
+
return `${statusGlyph}${idx} ${import_chalk14.default.cyan(eventId)} ${type} ${direction} ${import_chalk14.default.cyan(hash)}${tail}`;
|
|
5015
5055
|
}
|
|
5016
5056
|
function eventIdHead(eventId) {
|
|
5017
5057
|
if (eventId.length <= 20) return eventId;
|
|
@@ -5020,9 +5060,9 @@ function eventIdHead(eventId) {
|
|
|
5020
5060
|
function directionLabel(ev, selfDid, opts = {}) {
|
|
5021
5061
|
const senderHead = opts.fullIds ? ev.senderDid : didHead2(ev.senderDid);
|
|
5022
5062
|
const recipientHead = opts.fullIds ? ev.recipientDid : didHead2(ev.recipientDid);
|
|
5023
|
-
if (ev.senderDid === selfDid) return `${
|
|
5024
|
-
if (ev.recipientDid === selfDid) return `${
|
|
5025
|
-
return `${
|
|
5063
|
+
if (ev.senderDid === selfDid) return `${import_chalk14.default.bold("me")} \u2192 ${import_chalk14.default.dim(recipientHead)}`;
|
|
5064
|
+
if (ev.recipientDid === selfDid) return `${import_chalk14.default.dim(senderHead)} \u2192 ${import_chalk14.default.bold("me")}`;
|
|
5065
|
+
return `${import_chalk14.default.dim(senderHead)} \u2192 ${import_chalk14.default.dim(recipientHead)}`;
|
|
5026
5066
|
}
|
|
5027
5067
|
function extraDetail(ev) {
|
|
5028
5068
|
if (ev.type === "handshake_response") {
|
|
@@ -5059,7 +5099,7 @@ function parseSince(raw) {
|
|
|
5059
5099
|
}
|
|
5060
5100
|
|
|
5061
5101
|
// src/commands/guide.ts
|
|
5062
|
-
var
|
|
5102
|
+
var import_chalk15 = __toESM(require("chalk"));
|
|
5063
5103
|
|
|
5064
5104
|
// src/guide/source.ts
|
|
5065
5105
|
var GUIDE_TITLE = "HeyARP CLI \u2014 agent guide";
|
|
@@ -5593,7 +5633,7 @@ var GUIDE_SECTIONS = [
|
|
|
5593
5633
|
" 1. heyarp login link this CLI to your Solana wallet \u2014 hand the",
|
|
5594
5634
|
" printed URL to your HUMAN operator (browser",
|
|
5595
5635
|
" approval; registration REQUIRES it)",
|
|
5596
|
-
" 2. heyarp register
|
|
5636
|
+
" 2. heyarp register --name <handle> create your DID + Ed25519 keys (handle: unique, lowercase a-z0-9_ 3-32, immutable \u2014 others can address you by it instead of your DID, e.g. `send-handshake <handle>`; `heyarp whois <handle>` resolves it)",
|
|
5597
5637
|
" 3. heyarp whoami confirm your DID + login account are set",
|
|
5598
5638
|
" 4. role for THIS deal: you SEND the offer \u2192 buyer; an offer ARRIVES \u2192 worker",
|
|
5599
5639
|
" 5. BUYER only \u2014 fund your settlement wallet: `whoami --local` \u2192",
|
|
@@ -5700,7 +5740,7 @@ function renderCommand(c) {
|
|
|
5700
5740
|
${c.description}`;
|
|
5701
5741
|
}
|
|
5702
5742
|
function renderSection(s) {
|
|
5703
|
-
const lines = [
|
|
5743
|
+
const lines = [import_chalk15.default.bold(s.title)];
|
|
5704
5744
|
if (s.body && s.body.length > 0) lines.push(...s.body);
|
|
5705
5745
|
if (s.nextActions && s.nextActions.length > 0) {
|
|
5706
5746
|
lines.push(" Commands:");
|
|
@@ -5727,21 +5767,21 @@ function modeHeader(mode) {
|
|
|
5727
5767
|
""
|
|
5728
5768
|
];
|
|
5729
5769
|
case "role":
|
|
5730
|
-
return [
|
|
5770
|
+
return [import_chalk15.default.dim(`(${mode.role} guide \u2014 your slice only; run \`heyarp guide\` for the overview)`), ""];
|
|
5731
5771
|
case "setup":
|
|
5732
|
-
return [
|
|
5772
|
+
return [import_chalk15.default.dim("(setup \u2014 role-agnostic; run `heyarp guide` for the overview)"), ""];
|
|
5733
5773
|
case "troubleshoot":
|
|
5734
|
-
return [
|
|
5774
|
+
return [import_chalk15.default.dim("(troubleshooting \u2014 role-agnostic)"), ""];
|
|
5735
5775
|
}
|
|
5736
5776
|
}
|
|
5737
5777
|
function modeFooter(mode) {
|
|
5738
5778
|
if (mode.kind === "overview") {
|
|
5739
|
-
return ["",
|
|
5779
|
+
return ["", import_chalk15.default.dim("Full reference per role: `heyarp guide --role worker|buyer`. Docs: https://www.npmjs.com/package/@heyanon-arp/cli")];
|
|
5740
5780
|
}
|
|
5741
5781
|
return [];
|
|
5742
5782
|
}
|
|
5743
5783
|
function renderGuide(mode = { kind: "overview" }) {
|
|
5744
|
-
const blocks = [
|
|
5784
|
+
const blocks = [import_chalk15.default.bold(GUIDE_TITLE), "", ...modeHeader(mode)];
|
|
5745
5785
|
for (const s of selectSections(mode)) {
|
|
5746
5786
|
blocks.push(renderSection(s), "");
|
|
5747
5787
|
}
|
|
@@ -5791,7 +5831,7 @@ function renderPrompt(mode, opts = { concise: false }) {
|
|
|
5791
5831
|
// src/commands/homes.ts
|
|
5792
5832
|
var import_node_fs6 = require("fs");
|
|
5793
5833
|
var import_node_path6 = require("path");
|
|
5794
|
-
var
|
|
5834
|
+
var import_chalk16 = __toESM(require("chalk"));
|
|
5795
5835
|
var import_prompts = __toESM(require("prompts"));
|
|
5796
5836
|
|
|
5797
5837
|
// src/homes.ts
|
|
@@ -5885,27 +5925,27 @@ function runHomes(opts) {
|
|
|
5885
5925
|
return;
|
|
5886
5926
|
}
|
|
5887
5927
|
if (rows.length === 0) {
|
|
5888
|
-
console.log(
|
|
5889
|
-
console.log(
|
|
5928
|
+
console.log(import_chalk16.default.dim("(no HEYARP_HOME directories registered yet \u2014 run `heyarp register` once and the registry populates itself)"));
|
|
5929
|
+
console.log(import_chalk16.default.dim(` registry path: ${homesRegistryPath()}`));
|
|
5890
5930
|
return;
|
|
5891
5931
|
}
|
|
5892
5932
|
const header = ["Path", "Agents", "Last seen", "Status"];
|
|
5893
5933
|
const data = rows.map((r) => [
|
|
5894
|
-
r.path + (r.isCurrent ?
|
|
5934
|
+
r.path + (r.isCurrent ? import_chalk16.default.green(" (current)") : ""),
|
|
5895
5935
|
String(r.agentCount),
|
|
5896
5936
|
formatRelativeTime(r.lastSeenAt),
|
|
5897
|
-
r.exists ?
|
|
5937
|
+
r.exists ? import_chalk16.default.green("ok") : import_chalk16.default.red("missing")
|
|
5898
5938
|
]);
|
|
5899
5939
|
console.log("");
|
|
5900
5940
|
console.log(formatTable(header, data));
|
|
5901
|
-
console.log(
|
|
5941
|
+
console.log(import_chalk16.default.dim(`
|
|
5902
5942
|
Registry path: ${homesRegistryPath()}`));
|
|
5903
|
-
console.log(
|
|
5943
|
+
console.log(import_chalk16.default.dim(`Set HEYARP_HOME=<path> in a shell to switch between homes; run \`heyarp homes forget <path>\` to drop a stale entry.`));
|
|
5904
5944
|
}
|
|
5905
5945
|
async function runForget(path, opts) {
|
|
5906
5946
|
if (!opts.yes) {
|
|
5907
|
-
console.log(
|
|
5908
|
-
console.log(
|
|
5947
|
+
console.log(import_chalk16.default.yellow(`About to remove '${path}' from the homes registry.`));
|
|
5948
|
+
console.log(import_chalk16.default.dim(" Note: this only forgets the registry entry; the directory + its agents.json are NOT touched."));
|
|
5909
5949
|
const answer = await (0, import_prompts.default)(
|
|
5910
5950
|
{
|
|
5911
5951
|
type: "confirm",
|
|
@@ -5915,21 +5955,21 @@ async function runForget(path, opts) {
|
|
|
5915
5955
|
},
|
|
5916
5956
|
{
|
|
5917
5957
|
onCancel: () => {
|
|
5918
|
-
console.log(
|
|
5958
|
+
console.log(import_chalk16.default.yellow("Aborted."));
|
|
5919
5959
|
process.exit(130);
|
|
5920
5960
|
}
|
|
5921
5961
|
}
|
|
5922
5962
|
);
|
|
5923
5963
|
if (!answer.confirm) {
|
|
5924
|
-
console.log(
|
|
5964
|
+
console.log(import_chalk16.default.dim("Aborted (no changes)."));
|
|
5925
5965
|
return;
|
|
5926
5966
|
}
|
|
5927
5967
|
}
|
|
5928
5968
|
const removed = forgetHome(path);
|
|
5929
5969
|
if (removed) {
|
|
5930
|
-
console.log(
|
|
5970
|
+
console.log(import_chalk16.default.green(`\u2713 forgot ${path}`));
|
|
5931
5971
|
} else {
|
|
5932
|
-
console.log(
|
|
5972
|
+
console.log(import_chalk16.default.dim(`(no entry for ${path} in the registry \u2014 already absent)`));
|
|
5933
5973
|
}
|
|
5934
5974
|
}
|
|
5935
5975
|
function countAgents(homePath) {
|
|
@@ -5954,13 +5994,13 @@ function formatTable(header, data) {
|
|
|
5954
5994
|
const padding = " ".repeat(Math.max(0, widths[i] - lengths[i]));
|
|
5955
5995
|
return cell + padding;
|
|
5956
5996
|
}).join(" ");
|
|
5957
|
-
const headerLine =
|
|
5997
|
+
const headerLine = import_chalk16.default.bold(
|
|
5958
5998
|
pad(
|
|
5959
5999
|
header,
|
|
5960
6000
|
header.map((s) => s.length)
|
|
5961
6001
|
)
|
|
5962
6002
|
);
|
|
5963
|
-
const sepLine =
|
|
6003
|
+
const sepLine = import_chalk16.default.dim(
|
|
5964
6004
|
pad(
|
|
5965
6005
|
widths.map((w) => "-".repeat(w)),
|
|
5966
6006
|
widths
|
|
@@ -5987,7 +6027,7 @@ function formatRelativeTime(iso) {
|
|
|
5987
6027
|
}
|
|
5988
6028
|
|
|
5989
6029
|
// src/commands/inbox.ts
|
|
5990
|
-
var
|
|
6030
|
+
var import_chalk17 = __toESM(require("chalk"));
|
|
5991
6031
|
init_api();
|
|
5992
6032
|
function formatTailStartedPing(input) {
|
|
5993
6033
|
const ping = {
|
|
@@ -6034,8 +6074,8 @@ async function runInbox(positionalDid, opts) {
|
|
|
6034
6074
|
}
|
|
6035
6075
|
const api = new ArpApiClient(opts.server);
|
|
6036
6076
|
if (!opts.json) {
|
|
6037
|
-
console.log(
|
|
6038
|
-
console.log(
|
|
6077
|
+
console.log(import_chalk17.default.dim(`Server: ${api.serverUrl}`));
|
|
6078
|
+
console.log(import_chalk17.default.dim(`Signer: ${local.did}`));
|
|
6039
6079
|
}
|
|
6040
6080
|
const query = { limit };
|
|
6041
6081
|
if (opts.before) query.before = opts.before;
|
|
@@ -6049,7 +6089,7 @@ async function runInbox(positionalDid, opts) {
|
|
|
6049
6089
|
return;
|
|
6050
6090
|
}
|
|
6051
6091
|
if (events.length === 0) {
|
|
6052
|
-
console.log(
|
|
6092
|
+
console.log(import_chalk17.default.dim("\n(no events addressed to me \u2014 `heyarp events <relationship-id>` shows the chain-wide listing)"));
|
|
6053
6093
|
return;
|
|
6054
6094
|
}
|
|
6055
6095
|
console.log("");
|
|
@@ -6064,16 +6104,16 @@ async function runInbox(positionalDid, opts) {
|
|
|
6064
6104
|
secondary: `eventId=${ev.eventId} serverEventHash=${ev.serverEventHash}`
|
|
6065
6105
|
}));
|
|
6066
6106
|
}
|
|
6067
|
-
const addressedToMeHint =
|
|
6107
|
+
const addressedToMeHint = import_chalk17.default.dim(" (envelopes addressed to me \u2014 for the full chain see `heyarp events <relationship-id>`)");
|
|
6068
6108
|
if (opts.since && !opts.before) {
|
|
6069
6109
|
console.log(
|
|
6070
|
-
|
|
6110
|
+
import_chalk17.default.dim(
|
|
6071
6111
|
`
|
|
6072
6112
|
${events.length} event(s) (oldest-first).${addressedToMeHint} Advance the forward cursor with --since <serverTimestamp> --since-event-id <eventId> using the LAST row above.`
|
|
6073
6113
|
)
|
|
6074
6114
|
);
|
|
6075
6115
|
} else {
|
|
6076
|
-
console.log(
|
|
6116
|
+
console.log(import_chalk17.default.dim(`
|
|
6077
6117
|
${events.length} event(s).${addressedToMeHint} Paginate with --before <serverTimestamp> --before-event-id <eventId> using the LAST row above.`));
|
|
6078
6118
|
}
|
|
6079
6119
|
}
|
|
@@ -6088,7 +6128,7 @@ async function runInboxTail(did, local, opts) {
|
|
|
6088
6128
|
} else {
|
|
6089
6129
|
warn(
|
|
6090
6130
|
opts.json,
|
|
6091
|
-
|
|
6131
|
+
import_chalk17.default.yellow(
|
|
6092
6132
|
"\u26A0 inbox --tail: stdout is piped but `process.stdout._handle.setBlocking` is unavailable in this Node runtime. Buffered writes may delay event delivery. Fall back to polling (`heyarp inbox --json`) if events stop arriving."
|
|
6093
6133
|
)
|
|
6094
6134
|
);
|
|
@@ -6098,9 +6138,9 @@ async function runInboxTail(did, local, opts) {
|
|
|
6098
6138
|
if (opts.json) {
|
|
6099
6139
|
console.log(formatTailStartedPing({ server: api.serverUrl, signer: local.did, stdoutBlockingApplied }));
|
|
6100
6140
|
} else {
|
|
6101
|
-
console.log(
|
|
6102
|
-
console.log(
|
|
6103
|
-
console.log(
|
|
6141
|
+
console.log(import_chalk17.default.dim(`Server: ${api.serverUrl}`));
|
|
6142
|
+
console.log(import_chalk17.default.dim(`Signer: ${local.did}`));
|
|
6143
|
+
console.log(import_chalk17.default.dim("Mode: --tail (live SSE, Ctrl-C to stop)"));
|
|
6104
6144
|
}
|
|
6105
6145
|
const controller = new AbortController();
|
|
6106
6146
|
let userAborted = false;
|
|
@@ -6119,7 +6159,7 @@ async function runInboxTail(did, local, opts) {
|
|
|
6119
6159
|
}
|
|
6120
6160
|
if (event.type === "heartbeat") continue;
|
|
6121
6161
|
if (event.type === "connected") {
|
|
6122
|
-
console.log(
|
|
6162
|
+
console.log(import_chalk17.default.green("\u25CF stream open \u2014 listening for envelopes..."));
|
|
6123
6163
|
continue;
|
|
6124
6164
|
}
|
|
6125
6165
|
if (event.type === "envelope") {
|
|
@@ -6133,7 +6173,7 @@ async function runInboxTail(did, local, opts) {
|
|
|
6133
6173
|
}
|
|
6134
6174
|
continue;
|
|
6135
6175
|
}
|
|
6136
|
-
console.log(
|
|
6176
|
+
console.log(import_chalk17.default.dim(`(unknown event: ${event.type})`));
|
|
6137
6177
|
}
|
|
6138
6178
|
if (!userAborted) {
|
|
6139
6179
|
throw new Error("inbox --tail: stream ended unexpectedly (server may have restarted, or change stream errored). Re-run to reconnect.");
|
|
@@ -6141,7 +6181,7 @@ async function runInboxTail(did, local, opts) {
|
|
|
6141
6181
|
} catch (err) {
|
|
6142
6182
|
const name = err.name;
|
|
6143
6183
|
if (name === "AbortError" || userAborted) {
|
|
6144
|
-
if (!opts.json) console.log(
|
|
6184
|
+
if (!opts.json) console.log(import_chalk17.default.dim("\nstream closed."));
|
|
6145
6185
|
return;
|
|
6146
6186
|
}
|
|
6147
6187
|
throw err;
|
|
@@ -6161,15 +6201,15 @@ function formatInboxTable(events, opts = {}) {
|
|
|
6161
6201
|
]);
|
|
6162
6202
|
const widths = header.map((h, i) => Math.max(h.length, ...data.map((row) => row[i].length)));
|
|
6163
6203
|
const pad = (cells) => cells.map((c, i) => c.padEnd(widths[i])).join(" ");
|
|
6164
|
-
const lines = [
|
|
6165
|
-
const detail = events.map((ev) => ` ${
|
|
6204
|
+
const lines = [import_chalk17.default.bold(pad(header)), import_chalk17.default.dim(pad(widths.map((w) => "-".repeat(w)))), ...data.map((row) => pad(row))];
|
|
6205
|
+
const detail = events.map((ev) => ` ${import_chalk17.default.dim("eventId:")} ${import_chalk17.default.cyan(ev.eventId)} ${import_chalk17.default.dim("serverTimestamp:")} ${import_chalk17.default.cyan(ev.serverTimestamp)}`).join("\n");
|
|
6166
6206
|
return `${lines.join("\n")}
|
|
6167
6207
|
|
|
6168
|
-
${
|
|
6208
|
+
${import_chalk17.default.bold("Pagination cursors")} (last \u2192 first):
|
|
6169
6209
|
${detail}`;
|
|
6170
6210
|
}
|
|
6171
6211
|
function hashHead2(hash) {
|
|
6172
|
-
if (!hash) return
|
|
6212
|
+
if (!hash) return import_chalk17.default.dim("(none)");
|
|
6173
6213
|
if (hash.length <= 14) return hash;
|
|
6174
6214
|
return `${hash.slice(0, 14)}...`;
|
|
6175
6215
|
}
|
|
@@ -6185,8 +6225,8 @@ function parseLimit4(raw) {
|
|
|
6185
6225
|
// src/commands/keys.ts
|
|
6186
6226
|
var import_node_crypto2 = require("crypto");
|
|
6187
6227
|
var import_node_fs7 = require("fs");
|
|
6188
|
-
var
|
|
6189
|
-
var
|
|
6228
|
+
var import_sdk19 = require("@heyanon-arp/sdk");
|
|
6229
|
+
var import_chalk18 = __toESM(require("chalk"));
|
|
6190
6230
|
function writeSecretFile(path, body) {
|
|
6191
6231
|
const tmp = `${path}.tmp.${(0, import_node_crypto2.randomBytes)(8).toString("hex")}`;
|
|
6192
6232
|
const fd = (0, import_node_fs7.openSync)(tmp, "wx", 384);
|
|
@@ -6213,19 +6253,19 @@ function writeSecretFile(path, body) {
|
|
|
6213
6253
|
function registerKeysCommand(root) {
|
|
6214
6254
|
const keys = root.command("keys").description("Local key utilities");
|
|
6215
6255
|
keys.command("gen").description("Generate a fresh identity + settlement keypair (no save by default)").action(() => {
|
|
6216
|
-
const identity = (0,
|
|
6217
|
-
const settlement = (0,
|
|
6256
|
+
const identity = (0, import_sdk19.generateKeyPair)();
|
|
6257
|
+
const settlement = (0, import_sdk19.generateKeyPair)();
|
|
6218
6258
|
const out = [
|
|
6219
|
-
|
|
6220
|
-
` public (base58btc): ${
|
|
6221
|
-
` secret (base64) : ${
|
|
6259
|
+
import_chalk18.default.bold("Identity key (Ed25519)"),
|
|
6260
|
+
` public (base58btc): ${import_chalk18.default.cyan((0, import_sdk19.base58btcEncode)(identity.publicKey))}`,
|
|
6261
|
+
` secret (base64) : ${import_chalk18.default.yellow(Buffer.from(identity.secretKey).toString("base64"))}`,
|
|
6222
6262
|
"",
|
|
6223
|
-
|
|
6224
|
-
` public (base58btc): ${
|
|
6225
|
-
` secret (base64) : ${
|
|
6263
|
+
import_chalk18.default.bold("Settlement key (Ed25519)"),
|
|
6264
|
+
` public (base58btc): ${import_chalk18.default.cyan((0, import_sdk19.base58btcEncode)(settlement.publicKey))}`,
|
|
6265
|
+
` secret (base64) : ${import_chalk18.default.yellow(Buffer.from(settlement.secretKey).toString("base64"))}`,
|
|
6226
6266
|
"",
|
|
6227
|
-
|
|
6228
|
-
` ${
|
|
6267
|
+
import_chalk18.default.bold("Resulting DID"),
|
|
6268
|
+
` ${import_chalk18.default.cyan((0, import_sdk19.formatDid)(identity.publicKey))}`
|
|
6229
6269
|
];
|
|
6230
6270
|
console.log(out.join("\n"));
|
|
6231
6271
|
});
|
|
@@ -6234,20 +6274,20 @@ function registerKeysCommand(root) {
|
|
|
6234
6274
|
const json = JSON.stringify(toKeyBundle(agent, (/* @__PURE__ */ new Date()).toISOString()), null, 2);
|
|
6235
6275
|
if (opts.out) {
|
|
6236
6276
|
writeSecretFile(opts.out, json);
|
|
6237
|
-
process.stderr.write(
|
|
6277
|
+
process.stderr.write(import_chalk18.default.yellow(`\u26A0 wrote SECRET key bundle to ${opts.out} (mode 0600) \u2014 keep it offline; anyone with this file can operate ${did}.
|
|
6238
6278
|
`));
|
|
6239
6279
|
console.log(opts.out);
|
|
6240
6280
|
} else {
|
|
6241
|
-
process.stderr.write(
|
|
6281
|
+
process.stderr.write(import_chalk18.default.yellow("\u26A0 this is a SECRET key bundle \u2014 redirect to a file and keep it offline.\n"));
|
|
6242
6282
|
console.log(json);
|
|
6243
6283
|
}
|
|
6244
6284
|
});
|
|
6245
6285
|
keys.command("whoami").description("Print the DID derived from a base64-encoded identity secret key").argument("<secret-key-b64>", "32-byte Ed25519 seed, base64").action((secretKeyB64) => {
|
|
6246
6286
|
const seed = decodeSeed(secretKeyB64);
|
|
6247
|
-
const pub = (0,
|
|
6248
|
-
const did = (0,
|
|
6249
|
-
console.log(`${
|
|
6250
|
-
console.log(`${
|
|
6287
|
+
const pub = (0, import_sdk19.getPublicKey)(seed);
|
|
6288
|
+
const did = (0, import_sdk19.formatDid)(pub);
|
|
6289
|
+
console.log(`${import_chalk18.default.bold("DID")}: ${import_chalk18.default.cyan(did)}`);
|
|
6290
|
+
console.log(`${import_chalk18.default.bold("Identity public key (base58btc)")}: ${import_chalk18.default.cyan((0, import_sdk19.base58btcEncode)(pub))}`);
|
|
6251
6291
|
});
|
|
6252
6292
|
}
|
|
6253
6293
|
function decodeSeed(b64) {
|
|
@@ -6264,12 +6304,16 @@ function decodeSeed(b64) {
|
|
|
6264
6304
|
}
|
|
6265
6305
|
|
|
6266
6306
|
// src/commands/list.ts
|
|
6267
|
-
var
|
|
6307
|
+
var import_chalk19 = __toESM(require("chalk"));
|
|
6268
6308
|
function registerListCommand(root) {
|
|
6269
|
-
root.command("list").description("List agents registered locally (~/.heyarp/agents.json)").action(() => {
|
|
6309
|
+
root.command("list").description("List agents registered locally (~/.heyarp/agents.json)").option("--json", "Machine-readable mode \u2014 emit the local agents as a single JSON array on stdout ({serverUrl, did, name, tags, registeredAt}[]).", false).action((opts) => {
|
|
6270
6310
|
const rows = listAgents();
|
|
6311
|
+
if (opts.json) {
|
|
6312
|
+
jsonOut(rows.map(({ serverUrl, agent }) => ({ serverUrl, did: agent.did, name: agent.name ?? null, tags: agent.tags ?? [], registeredAt: agent.registeredAt })));
|
|
6313
|
+
return;
|
|
6314
|
+
}
|
|
6271
6315
|
if (rows.length === 0) {
|
|
6272
|
-
console.log(
|
|
6316
|
+
console.log(import_chalk19.default.dim(`No local agents. State file: ${stateFilePath()}`));
|
|
6273
6317
|
return;
|
|
6274
6318
|
}
|
|
6275
6319
|
const grouped = /* @__PURE__ */ new Map();
|
|
@@ -6281,7 +6325,7 @@ function registerListCommand(root) {
|
|
|
6281
6325
|
for (const [serverUrl, group] of grouped) {
|
|
6282
6326
|
if (!first) console.log("");
|
|
6283
6327
|
first = false;
|
|
6284
|
-
console.log(
|
|
6328
|
+
console.log(import_chalk19.default.bold(`Server: ${serverUrl}`));
|
|
6285
6329
|
console.log(formatAgentsTable(group.map(({ agent }) => ({ did: agent.did, name: agent.name, tags: agent.tags, registeredAt: agent.registeredAt }))));
|
|
6286
6330
|
}
|
|
6287
6331
|
});
|
|
@@ -6289,7 +6333,7 @@ function registerListCommand(root) {
|
|
|
6289
6333
|
|
|
6290
6334
|
// src/commands/login.ts
|
|
6291
6335
|
var import_node_crypto3 = require("crypto");
|
|
6292
|
-
var
|
|
6336
|
+
var import_chalk20 = __toESM(require("chalk"));
|
|
6293
6337
|
init_api();
|
|
6294
6338
|
var POLL_INTERVAL_MS = 2e3;
|
|
6295
6339
|
var POLL_TIMEOUT_MS = 11 * 6e4;
|
|
@@ -6359,9 +6403,9 @@ function registerLoginCommand(root) {
|
|
|
6359
6403
|
jsonOut({ serverUrl: result.serverUrl, wallet: result.wallet, credentialsPath: credentialsFilePath() });
|
|
6360
6404
|
} else {
|
|
6361
6405
|
console.log("");
|
|
6362
|
-
console.log(`${
|
|
6363
|
-
console.log(
|
|
6364
|
-
console.log(
|
|
6406
|
+
console.log(`${import_chalk20.default.green("Logged in as")} ${import_chalk20.default.cyan(result.wallet)}`);
|
|
6407
|
+
console.log(import_chalk20.default.dim(`If that is not the wallet you approved with, run heyarp logout immediately.`));
|
|
6408
|
+
console.log(import_chalk20.default.dim(`Credential saved to ${credentialsFilePath()} (mode 0600).`));
|
|
6365
6409
|
}
|
|
6366
6410
|
} catch (err) {
|
|
6367
6411
|
emitActionError(err, cmd);
|
|
@@ -6371,7 +6415,7 @@ function registerLoginCommand(root) {
|
|
|
6371
6415
|
}
|
|
6372
6416
|
|
|
6373
6417
|
// src/commands/logout.ts
|
|
6374
|
-
var
|
|
6418
|
+
var import_chalk21 = __toESM(require("chalk"));
|
|
6375
6419
|
init_api();
|
|
6376
6420
|
function registerLogoutCommand(root) {
|
|
6377
6421
|
root.command("logout").description("Log out of the ARP server: revoke the stored CLI auth token (best-effort) and delete the local credential for this server.").option("--server <url>", "Override ARP server base URL").option("--json", "machine-readable output ({ serverUrl, loggedOut, wallet? })", false).action(async (opts, cmd) => {
|
|
@@ -6396,7 +6440,7 @@ function registerLogoutCommand(root) {
|
|
|
6396
6440
|
if (opts.json) {
|
|
6397
6441
|
jsonOut({ serverUrl: api.serverUrl, loggedOut: true, wallet: credential.wallet });
|
|
6398
6442
|
} else {
|
|
6399
|
-
console.log(`${
|
|
6443
|
+
console.log(`${import_chalk21.default.green("Logged out of")} ${api.serverUrl} ${import_chalk21.default.dim(`(was ${credential.wallet})`)}`);
|
|
6400
6444
|
}
|
|
6401
6445
|
} catch (err) {
|
|
6402
6446
|
emitActionError(err, cmd);
|
|
@@ -6405,13 +6449,65 @@ function registerLogoutCommand(root) {
|
|
|
6405
6449
|
});
|
|
6406
6450
|
}
|
|
6407
6451
|
|
|
6452
|
+
// src/commands/name.ts
|
|
6453
|
+
var import_sdk20 = require("@heyanon-arp/sdk");
|
|
6454
|
+
var import_chalk22 = __toESM(require("chalk"));
|
|
6455
|
+
init_api();
|
|
6456
|
+
function registerNameCommand(root) {
|
|
6457
|
+
const name = root.command("name").description("Agent name (handle) utilities.");
|
|
6458
|
+
name.command("check").description("Check whether an agent name (handle) can be registered \u2014 reports invalid / reserved / taken / available without registering.").argument("<name>", "Candidate handle (lowercase a-z0-9_, 3-32 chars)").option("--server <url>", "Override ARP server base URL").option("--json", "Emit {name, available, reason, did?} as a single JSON object on stdout.", false).action(async (input, opts) => {
|
|
6459
|
+
const result = await runNameCheck(input, opts);
|
|
6460
|
+
if (opts.json) {
|
|
6461
|
+
jsonOut(result);
|
|
6462
|
+
} else {
|
|
6463
|
+
printNameCheck(input, result);
|
|
6464
|
+
}
|
|
6465
|
+
if (!result.available) process.exitCode = 1;
|
|
6466
|
+
});
|
|
6467
|
+
}
|
|
6468
|
+
async function runNameCheck(input, opts) {
|
|
6469
|
+
const name = (0, import_sdk20.normalizeName)(input);
|
|
6470
|
+
if (!(0, import_sdk20.isValidAgentName)(name)) {
|
|
6471
|
+
return { name, available: false, reason: "invalid" };
|
|
6472
|
+
}
|
|
6473
|
+
if ((0, import_sdk20.isReservedName)(name)) {
|
|
6474
|
+
return { name, available: false, reason: "reserved" };
|
|
6475
|
+
}
|
|
6476
|
+
const api = new ArpApiClient(opts.server);
|
|
6477
|
+
progress(opts.json, import_chalk22.default.dim(`Server: ${api.serverUrl}`));
|
|
6478
|
+
try {
|
|
6479
|
+
const profile = await api.discoverByName(name);
|
|
6480
|
+
return { name, available: false, reason: "taken", did: profile.did };
|
|
6481
|
+
} catch (err) {
|
|
6482
|
+
if (err instanceof ApiError && err.payload.code === "AGENT_NOT_FOUND") {
|
|
6483
|
+
return { name, available: true, reason: null };
|
|
6484
|
+
}
|
|
6485
|
+
throw err;
|
|
6486
|
+
}
|
|
6487
|
+
}
|
|
6488
|
+
function printNameCheck(input, r) {
|
|
6489
|
+
switch (r.reason) {
|
|
6490
|
+
case "invalid":
|
|
6491
|
+
console.log(`${import_chalk22.default.red("\u2717")} '${input}' is not a valid handle \u2014 must be lowercase a-z0-9_, 3-32 chars.`);
|
|
6492
|
+
break;
|
|
6493
|
+
case "reserved":
|
|
6494
|
+
console.log(`${import_chalk22.default.red("\u2717")} '${r.name}' is reserved and cannot be registered.`);
|
|
6495
|
+
break;
|
|
6496
|
+
case "taken":
|
|
6497
|
+
console.log(`${import_chalk22.default.yellow("\u2717")} '${r.name}' is taken \u2192 ${import_chalk22.default.cyan(r.did ?? "(unknown DID)")}`);
|
|
6498
|
+
break;
|
|
6499
|
+
default:
|
|
6500
|
+
console.log(`${import_chalk22.default.green("\u2713")} '${r.name}' is available.`);
|
|
6501
|
+
}
|
|
6502
|
+
}
|
|
6503
|
+
|
|
6408
6504
|
// src/commands/profile.ts
|
|
6409
|
-
var
|
|
6410
|
-
var
|
|
6505
|
+
var import_sdk21 = require("@heyanon-arp/sdk");
|
|
6506
|
+
var import_chalk23 = __toESM(require("chalk"));
|
|
6411
6507
|
init_api();
|
|
6412
6508
|
function registerProfileCommand(root) {
|
|
6413
6509
|
root.command("profile").description("Composed agent profile: public fields + reputation + liveness, in one read.").argument("<did>", "did:arp:<base58btc> identifier").option("--server <url>", "Override ARP server base URL").option("--json", "Emit the profile as JSON on stdout.", false).action(async (did, opts) => {
|
|
6414
|
-
if (!(0,
|
|
6510
|
+
if (!(0, import_sdk21.isValidDid)(did)) {
|
|
6415
6511
|
throw new Error(`'${did}' is not a syntactically valid did:arp identifier`);
|
|
6416
6512
|
}
|
|
6417
6513
|
const api = new ArpApiClient(opts.server);
|
|
@@ -6422,62 +6518,33 @@ function registerProfileCommand(root) {
|
|
|
6422
6518
|
}
|
|
6423
6519
|
const j = false;
|
|
6424
6520
|
const s = p.reputation.scores;
|
|
6425
|
-
const live = p.liveness.online ?
|
|
6521
|
+
const live = p.liveness.online ? import_chalk23.default.green("\u25CF online") : import_chalk23.default.dim("\u25CB offline");
|
|
6426
6522
|
const tags = p.tags.map(sanitizeForTerminal).filter((t) => t.length > 0);
|
|
6427
|
-
progress(j,
|
|
6428
|
-
if (p.description) progress(j,
|
|
6429
|
-
progress(j, ` ${live}${p.liveness.inboxStreamActive ?
|
|
6430
|
-
progress(j, ` tags: ${tags.length ? tags.join(", ") :
|
|
6523
|
+
progress(j, import_chalk23.default.bold(`${p.name ? sanitizeForTerminal(p.name) : "(unnamed)"} ${import_chalk23.default.dim(p.did)}`));
|
|
6524
|
+
if (p.description) progress(j, import_chalk23.default.dim(` ${sanitizeForTerminal(p.description)}`));
|
|
6525
|
+
progress(j, ` ${live}${p.liveness.inboxStreamActive ? import_chalk23.default.green(" \xB7 stream attached") : ""} \xB7 last seen ${p.liveness.lastSeenAt ?? "\u2014"}`);
|
|
6526
|
+
progress(j, ` tags: ${tags.length ? tags.join(", ") : import_chalk23.default.dim("none")}`);
|
|
6431
6527
|
progress(j, "");
|
|
6432
|
-
progress(j,
|
|
6528
|
+
progress(j, import_chalk23.default.bold(" Reputation") + import_chalk23.default.dim(" (informational)"));
|
|
6433
6529
|
progress(
|
|
6434
6530
|
j,
|
|
6435
6531
|
` composite ${s.composite.toFixed(2)} \xB7 reliability ${s.reliability.toFixed(2)} \xB7 settlement ${s.settlement.toFixed(2)} \xB7 dispute-health ${s.disputeHealth.toFixed(2)}`
|
|
6436
6532
|
);
|
|
6437
|
-
progress(j,
|
|
6533
|
+
progress(j, import_chalk23.default.dim(` ${p.reputation.computed ? `computed ${p.reputation.lastComputedAt}` : "never computed (neutral cold-start)"}`));
|
|
6438
6534
|
});
|
|
6439
6535
|
}
|
|
6440
6536
|
|
|
6441
6537
|
// src/commands/receipt.ts
|
|
6442
|
-
var
|
|
6538
|
+
var import_sdk22 = require("@heyanon-arp/sdk");
|
|
6443
6539
|
var import_shield2 = require("@heyanon-arp/shield");
|
|
6444
|
-
var
|
|
6540
|
+
var import_chalk24 = __toESM(require("chalk"));
|
|
6445
6541
|
init_api();
|
|
6446
6542
|
function registerReceiptCommands(root) {
|
|
6447
6543
|
const cmd = root.command("receipt").description("Receipt envelopes \u2014 the payee proposes a delivery record (payment consent is on-chain via claim_work_payment)");
|
|
6448
6544
|
registerPropose(cmd);
|
|
6449
6545
|
}
|
|
6450
|
-
var POST_COMMIT_ERROR_CODES2 = /* @__PURE__ */ new Set([
|
|
6451
|
-
"RECEIPT_ALREADY_EXISTS",
|
|
6452
|
-
"RECEIPT_DELEGATION_NOT_FOUND",
|
|
6453
|
-
"RECEIPT_DELEGATION_NOT_ACTIVE",
|
|
6454
|
-
"RECEIPT_RELATIONSHIP_MISMATCH",
|
|
6455
|
-
"RECEIPT_ISSUER_IS_CALLER",
|
|
6456
|
-
"RECEIPT_NOT_FOUND",
|
|
6457
|
-
"RECEIPT_INVALID_STATE",
|
|
6458
|
-
// The receipt-propose handler's LOCKED gate emits
|
|
6459
|
-
// `DELEGATION_PENDING_LOCK` (409) when the delegation is funded but
|
|
6460
|
-
// the on-chain lock isn't confirmed yet (state
|
|
6461
|
-
// `pending_lock_finalization`). It fires from the body handler AFTER
|
|
6462
|
-
// the event row is committed — same lifecycle as
|
|
6463
|
-
// `RECEIPT_DELEGATION_NOT_ACTIVE` — so the CLI must advance
|
|
6464
|
-
// `lastSenderSequence`, otherwise a retry once the lock confirms
|
|
6465
|
-
// reuses the consumed sequence and trips `ENV_SEQUENCE_BACKWARDS`.
|
|
6466
|
-
"DELEGATION_PENDING_LOCK",
|
|
6467
|
-
// response_hash / request_hash / deliverable_hash content
|
|
6468
|
-
// verification. Server commits the receipt envelope row BEFORE
|
|
6469
|
-
// running the canonical-hash lookup, so a rejection here still
|
|
6470
|
-
// consumes the sender sequence — must be in the allowlist or
|
|
6471
|
-
// a retry after fixing the hashes would trip
|
|
6472
|
-
// `ENV_SEQUENCE_BACKWARDS`.
|
|
6473
|
-
"RECEIPT_RESPONSE_HASH_NOT_FOUND",
|
|
6474
|
-
"RECEIPT_REQUEST_HASH_NOT_FOUND",
|
|
6475
|
-
"RECEIPT_DELIVERABLE_HASH_MISMATCH"
|
|
6476
|
-
]);
|
|
6477
|
-
var VERDICT_VALUES = ["accepted", "accepted_with_notes", "rejected"];
|
|
6478
|
-
var SHA256_RE = /^sha256:[0-9a-f]{64}$/;
|
|
6479
6546
|
function registerPropose(parent) {
|
|
6480
|
-
parent.command("propose").description("Send a receipt envelope as the PAYEE. Row lands PROPOSED; the buyer approves payment on-chain via claim_work_payment.").argument("<recipient
|
|
6547
|
+
parent.command("propose").description("Send a receipt envelope as the PAYEE. Row lands PROPOSED; the buyer approves payment on-chain via claim_work_payment.").argument("<recipient>", "Recipient \u2014 agent name (handle) or DID (= caller / offerer of the parent delegation)").argument("<delegation-id>", "Parent delegation id (UUID, must be ACCEPTED)").argument("[request-hash]", "sha256:<64 hex> \u2014 SHA-256 of the work_request payload being settled. Omit when --auto-hashes is set.").argument("[response-hash]", "sha256:<64 hex> \u2014 SHA-256 of the work_response payload being settled. Omit when --auto-hashes is set.").option("--server <url>", "Override ARP server base URL").option("--from-did <did>", "Sender DID \u2014 required only if multiple agents are registered against this server").option("--verdict <s>", "verdict_proposed (accepted | accepted_with_notes | rejected)", "accepted").option("--notes-hash <sha256>", "Optional sha256:<64 hex> notes hash").option("--deliverable-hash <sha256>", "Optional sha256:<64 hex> deliverable hash").option("--input-tokens <n>", "Optional usage.input_tokens").option("--output-tokens <n>", "Optional usage.output_tokens").option("--latency-ms <n>", "Optional usage.latency_ms").option("--model <name>", "Optional usage.model").option("--computed-amount <s>", "Optional usage.computed_amount").option("--ttl <seconds>", "Envelope TTL in seconds", "3600").option(
|
|
6481
6548
|
"--auto-hashes",
|
|
6482
6549
|
"Compute request_hash + response_hash automatically from the work-log row at (--rel-id, <delegation-id>, --request-id). Positional <request-hash>/<response-hash> become optional; if supplied they must match the computed values (consistency check). --rel-id and --request-id auto-resolve from local state when unambiguous \u2014 pass them explicitly only if the lookup finds multiple candidates.",
|
|
6483
6550
|
false
|
|
@@ -6497,7 +6564,7 @@ function registerPropose(parent) {
|
|
|
6497
6564
|
} catch (err) {
|
|
6498
6565
|
emitActionError(err, cmd);
|
|
6499
6566
|
if (!opts.json && err instanceof ApiError && err.payload.code === "RECEIPT_ALREADY_EXISTS") {
|
|
6500
|
-
console.error(
|
|
6567
|
+
console.error(import_chalk24.default.dim(" This receipt already exists (a prior propose committed it). Do NOT re-propose \u2014 payment consent is on-chain (claim_work_payment)."));
|
|
6501
6568
|
}
|
|
6502
6569
|
process.exitCode = 1;
|
|
6503
6570
|
}
|
|
@@ -6509,7 +6576,7 @@ async function runPropose(recipientDid, delegationId, requestHashArg, responseHa
|
|
|
6509
6576
|
"receipt propose: --verbose and --json are mutually exclusive. --json already emits the full server response as a structured payload; --verbose adds an envelope + response dump on top that would break `--json | jq`."
|
|
6510
6577
|
);
|
|
6511
6578
|
}
|
|
6512
|
-
|
|
6579
|
+
recipientDid = await resolveRecipient(opts.server, "receipt propose", recipientDid, { json: opts.json });
|
|
6513
6580
|
delegationId = requireUuidNormalised2("receipt propose", delegationId, "<delegation-id>");
|
|
6514
6581
|
if (opts.relId) opts.relId = requireUuidNormalised2("receipt propose", opts.relId, "--rel-id");
|
|
6515
6582
|
const verdict = parseVerdict("receipt propose", opts.verdict);
|
|
@@ -6523,7 +6590,7 @@ async function runPropose(recipientDid, delegationId, requestHashArg, responseHa
|
|
|
6523
6590
|
opts.relId = await resolveAutoRelId(api, sender, delegationId);
|
|
6524
6591
|
progress(
|
|
6525
6592
|
opts.json,
|
|
6526
|
-
|
|
6593
|
+
import_chalk24.default.dim(`[auto-rel-id] resolved --rel-id=${opts.relId} (delegation found in exactly one of your relationships; pass --rel-id explicitly to override)`)
|
|
6527
6594
|
);
|
|
6528
6595
|
}
|
|
6529
6596
|
if (opts.relId) {
|
|
@@ -6539,7 +6606,7 @@ async function runPropose(recipientDid, delegationId, requestHashArg, responseHa
|
|
|
6539
6606
|
opts.requestId = await resolveAutoRequestId(api, sender, opts.relId, delegationId);
|
|
6540
6607
|
progress(
|
|
6541
6608
|
opts.json,
|
|
6542
|
-
|
|
6609
|
+
import_chalk24.default.dim(
|
|
6543
6610
|
`[auto-request-id] resolved --request-id=${opts.requestId} (unique 'responded' work_log under this delegation; pass --request-id explicitly to override)`
|
|
6544
6611
|
)
|
|
6545
6612
|
);
|
|
@@ -6558,8 +6625,8 @@ async function runPropose(recipientDid, delegationId, requestHashArg, responseHa
|
|
|
6558
6625
|
}
|
|
6559
6626
|
requestHash = computed.requestHash;
|
|
6560
6627
|
responseHash = computed.responseHash;
|
|
6561
|
-
progress(opts.json,
|
|
6562
|
-
progress(opts.json,
|
|
6628
|
+
progress(opts.json, import_chalk24.default.dim(`[auto-hashes] request_hash: ${requestHash} (from work-log ${opts.relId}/${delegationId}/${opts.requestId})`));
|
|
6629
|
+
progress(opts.json, import_chalk24.default.dim(`[auto-hashes] response_hash: ${responseHash}`));
|
|
6563
6630
|
} else {
|
|
6564
6631
|
if (requestHashArg === void 0 || responseHashArg === void 0) {
|
|
6565
6632
|
throw new Error("receipt propose: <request-hash> and <response-hash> are required (or pass --auto-hashes + --rel-id + --request-id to derive them from the work-log)");
|
|
@@ -6579,11 +6646,11 @@ async function runPropose(recipientDid, delegationId, requestHashArg, responseHa
|
|
|
6579
6646
|
if (opts.deliverableHash) content.deliverable_hash = opts.deliverableHash;
|
|
6580
6647
|
if (usage) content.usage = usage;
|
|
6581
6648
|
const body = { type: "receipt", content };
|
|
6582
|
-
progress(opts.json,
|
|
6583
|
-
progress(opts.json,
|
|
6584
|
-
progress(opts.json,
|
|
6585
|
-
progress(opts.json,
|
|
6586
|
-
progress(opts.json,
|
|
6649
|
+
progress(opts.json, import_chalk24.default.dim(`Server: ${api.serverUrl}`));
|
|
6650
|
+
progress(opts.json, import_chalk24.default.dim(`Sender (payee): ${sender.did}`));
|
|
6651
|
+
progress(opts.json, import_chalk24.default.dim(`Recipient (caller): ${recipientDid}`));
|
|
6652
|
+
progress(opts.json, import_chalk24.default.dim(`Delegation: ${delegationId}`));
|
|
6653
|
+
progress(opts.json, import_chalk24.default.dim(`Verdict (proposed): ${verdict}`));
|
|
6587
6654
|
const result = await sendReceiptEnvelope({ api, sender, recipientDid, body, attachments: void 0, ttlSeconds, verbose: opts.verbose, server: opts.server });
|
|
6588
6655
|
if (opts.json) {
|
|
6589
6656
|
const json = {
|
|
@@ -6604,10 +6671,10 @@ async function runPropose(recipientDid, delegationId, requestHashArg, responseHa
|
|
|
6604
6671
|
return;
|
|
6605
6672
|
}
|
|
6606
6673
|
printIngestResult2(result);
|
|
6607
|
-
console.log(
|
|
6608
|
-
Receipt event hash: ${
|
|
6609
|
-
console.log(
|
|
6610
|
-
console.log(
|
|
6674
|
+
console.log(import_chalk24.default.dim(`
|
|
6675
|
+
Receipt event hash: ${import_chalk24.default.cyan(result.serverEventHash)}`));
|
|
6676
|
+
console.log(import_chalk24.default.dim("Receipt recorded. Payment consent is ON-CHAIN now: the buyer approves by"));
|
|
6677
|
+
console.log(import_chalk24.default.dim("sending claim_work_payment (or you self-claim after the review window)."));
|
|
6611
6678
|
}
|
|
6612
6679
|
async function assertSenderIsReceiptPayee(api, sender, relationshipId, delegationId) {
|
|
6613
6680
|
const signer = makeSigner(sender);
|
|
@@ -6675,7 +6742,7 @@ async function computeWorkLogHashes(api, sender, relationshipId, delegationId, r
|
|
|
6675
6742
|
`receipt propose --auto-hashes: no work-log row found for (relationshipId=${relationshipId}, delegationId=${delegationId}, requestId=${requestId}). Did the work_request envelope land yet?`
|
|
6676
6743
|
);
|
|
6677
6744
|
}
|
|
6678
|
-
if (workLog.state !==
|
|
6745
|
+
if (workLog.state !== import_sdk22.WorkLogStates.RESPONDED) {
|
|
6679
6746
|
throw new Error(
|
|
6680
6747
|
`receipt propose --auto-hashes: work-log row ${requestId} is in state '${workLog.state}', not 'responded'. The payee must \`work respond\` before a receipt can be proposed.`
|
|
6681
6748
|
);
|
|
@@ -6691,34 +6758,34 @@ async function computeWorkLogHashes(api, sender, relationshipId, delegationId, r
|
|
|
6691
6758
|
};
|
|
6692
6759
|
const responseBody = workLog.responseOutput !== void 0 ? { type: "work_response", content: { delegation_id: workLog.delegationId, request_id: workLog.requestId, output: workLog.responseOutput } } : { type: "work_response", content: { delegation_id: workLog.delegationId, request_id: workLog.requestId, error: workLog.responseError } };
|
|
6693
6760
|
return {
|
|
6694
|
-
requestHash: (0,
|
|
6695
|
-
responseHash: (0,
|
|
6761
|
+
requestHash: (0, import_sdk22.canonicalSha256Hex)(requestBody),
|
|
6762
|
+
responseHash: (0, import_sdk22.canonicalSha256Hex)(responseBody)
|
|
6696
6763
|
};
|
|
6697
6764
|
}
|
|
6698
6765
|
async function sendReceiptEnvelope(args) {
|
|
6699
6766
|
const nextSequence = (args.sender.lastSenderSequence ?? 0) + 1;
|
|
6700
6767
|
const protectedBlock = {
|
|
6701
|
-
protocol_version:
|
|
6702
|
-
purpose:
|
|
6703
|
-
message_id: (0,
|
|
6768
|
+
protocol_version: import_sdk22.CURRENT_PROTOCOL_VERSION,
|
|
6769
|
+
purpose: import_sdk22.Purpose.ENVELOPE,
|
|
6770
|
+
message_id: (0, import_sdk22.uuidV4)(),
|
|
6704
6771
|
sender_did: args.sender.did,
|
|
6705
6772
|
recipient_did: args.recipientDid,
|
|
6706
6773
|
relationship_id: null,
|
|
6707
6774
|
sender_sequence: nextSequence,
|
|
6708
|
-
sender_nonce: (0,
|
|
6709
|
-
timestamp: (0,
|
|
6710
|
-
expires_at: (0,
|
|
6775
|
+
sender_nonce: (0, import_sdk22.senderNonce)(),
|
|
6776
|
+
timestamp: (0, import_sdk22.rfc3339)(),
|
|
6777
|
+
expires_at: (0, import_sdk22.expiresAt)(args.ttlSeconds),
|
|
6711
6778
|
delivery_id: null
|
|
6712
6779
|
};
|
|
6713
6780
|
const signer = makeSigner(args.sender);
|
|
6714
|
-
const envelope = (0,
|
|
6781
|
+
const envelope = (0, import_sdk22.signEnvelope)({
|
|
6715
6782
|
protected: protectedBlock,
|
|
6716
6783
|
body: args.body,
|
|
6717
6784
|
identitySecretKey: signer.identitySecretKey,
|
|
6718
6785
|
attachments: args.attachments
|
|
6719
6786
|
});
|
|
6720
6787
|
if (args.verbose) {
|
|
6721
|
-
console.log(
|
|
6788
|
+
console.log(import_chalk24.default.bold("\nEnvelope (pre-send):"));
|
|
6722
6789
|
console.log(formatJson(envelope));
|
|
6723
6790
|
}
|
|
6724
6791
|
try {
|
|
@@ -6726,24 +6793,24 @@ async function sendReceiptEnvelope(args) {
|
|
|
6726
6793
|
updateAgentLocal(args.server, args.sender.did, { lastSenderSequence: nextSequence });
|
|
6727
6794
|
return result;
|
|
6728
6795
|
} catch (err) {
|
|
6729
|
-
if (err instanceof ApiError &&
|
|
6796
|
+
if (err instanceof ApiError && (0, import_sdk22.isPostCommitErrorCode)(err.payload.code)) {
|
|
6730
6797
|
updateAgentLocal(args.server, args.sender.did, { lastSenderSequence: nextSequence });
|
|
6731
6798
|
}
|
|
6732
6799
|
throw err;
|
|
6733
6800
|
}
|
|
6734
6801
|
}
|
|
6735
6802
|
function printIngestResult2(result) {
|
|
6736
|
-
console.log(
|
|
6737
|
-
console.log(`${
|
|
6738
|
-
console.log(`${
|
|
6739
|
-
console.log(`${
|
|
6740
|
-
console.log(`${
|
|
6741
|
-
console.log(`${
|
|
6803
|
+
console.log(import_chalk24.default.green("\nDelivered."));
|
|
6804
|
+
console.log(`${import_chalk24.default.bold("Event id")}: ${import_chalk24.default.cyan(result.eventId)}`);
|
|
6805
|
+
console.log(`${import_chalk24.default.bold("Relationship id")}: ${import_chalk24.default.cyan(result.relationshipId)}`);
|
|
6806
|
+
console.log(`${import_chalk24.default.bold("Chain index")}: ${import_chalk24.default.cyan(String(result.relationshipEventIndex))}`);
|
|
6807
|
+
console.log(`${import_chalk24.default.bold("Server timestamp")}: ${import_chalk24.default.cyan(result.serverTimestamp)}`);
|
|
6808
|
+
console.log(`${import_chalk24.default.bold("Server event hash")}: ${import_chalk24.default.cyan(result.serverEventHash)}`);
|
|
6742
6809
|
}
|
|
6743
6810
|
function parseVerdict(cmdName, raw) {
|
|
6744
|
-
if (raw === void 0 || raw === "") return
|
|
6745
|
-
if (!
|
|
6746
|
-
throw new Error(`${cmdName}: --verdict must be one of ${
|
|
6811
|
+
if (raw === void 0 || raw === "") return import_sdk22.ReceiptVerdicts.ACCEPTED;
|
|
6812
|
+
if (!import_sdk22.RECEIPT_VERDICTS.includes(raw)) {
|
|
6813
|
+
throw new Error(`${cmdName}: --verdict must be one of ${import_sdk22.RECEIPT_VERDICTS.join(" | ")} (got '${raw}')`);
|
|
6747
6814
|
}
|
|
6748
6815
|
return raw;
|
|
6749
6816
|
}
|
|
@@ -6780,18 +6847,14 @@ function requireUuid3(cmdName, raw, label) {
|
|
|
6780
6847
|
requireUuid(cmdName, raw, label);
|
|
6781
6848
|
}
|
|
6782
6849
|
function requireSha256(cmdName, raw, label) {
|
|
6783
|
-
if (!
|
|
6850
|
+
if (!(0, import_sdk22.isSha256Hex)(raw)) {
|
|
6784
6851
|
throw new Error(`${cmdName}: ${label} must match 'sha256:<64 lowercase hex>' (got '${raw}')`);
|
|
6785
6852
|
}
|
|
6786
6853
|
}
|
|
6787
|
-
function requireDid2(cmdName, did, label) {
|
|
6788
|
-
if (typeof did !== "string" || !did.startsWith("did:arp:") || did.length <= "did:arp:".length) {
|
|
6789
|
-
throw new Error(`${cmdName}: ${label} must look like 'did:arp:...' (got '${did}')`);
|
|
6790
|
-
}
|
|
6791
|
-
}
|
|
6792
6854
|
|
|
6793
6855
|
// src/commands/receipts.ts
|
|
6794
|
-
var
|
|
6856
|
+
var import_sdk23 = require("@heyanon-arp/sdk");
|
|
6857
|
+
var import_chalk25 = __toESM(require("chalk"));
|
|
6795
6858
|
init_api();
|
|
6796
6859
|
function registerReceiptsCommand(root) {
|
|
6797
6860
|
root.command("receipts").description(
|
|
@@ -6814,9 +6877,9 @@ async function runReceipts(relationshipId, opts) {
|
|
|
6814
6877
|
const api = new ArpApiClient(opts.server);
|
|
6815
6878
|
const sender = resolveSenderAgent("receipts", opts.server, opts.fromDid);
|
|
6816
6879
|
if (!opts.json) {
|
|
6817
|
-
console.log(
|
|
6818
|
-
console.log(
|
|
6819
|
-
console.log(
|
|
6880
|
+
console.log(import_chalk25.default.dim(`Server: ${api.serverUrl}`));
|
|
6881
|
+
console.log(import_chalk25.default.dim(`Signer: ${sender.did}`));
|
|
6882
|
+
console.log(import_chalk25.default.dim(`Relationship: ${relationshipId}`));
|
|
6820
6883
|
}
|
|
6821
6884
|
const query = { limit };
|
|
6822
6885
|
if (opts.delegationId) query.delegationId = opts.delegationId;
|
|
@@ -6828,7 +6891,7 @@ async function runReceipts(relationshipId, opts) {
|
|
|
6828
6891
|
return;
|
|
6829
6892
|
}
|
|
6830
6893
|
if (rows.length === 0) {
|
|
6831
|
-
console.log(
|
|
6894
|
+
console.log(import_chalk25.default.dim("\n(no receipts for this relationship)"));
|
|
6832
6895
|
return;
|
|
6833
6896
|
}
|
|
6834
6897
|
console.log("");
|
|
@@ -6845,29 +6908,29 @@ async function runReceipts(relationshipId, opts) {
|
|
|
6845
6908
|
}));
|
|
6846
6909
|
}
|
|
6847
6910
|
const lastId = rows[rows.length - 1].id;
|
|
6848
|
-
console.log(
|
|
6911
|
+
console.log(import_chalk25.default.dim(`
|
|
6849
6912
|
${rows.length} receipt row(s). Paginate with --after ${lastId}.`));
|
|
6850
6913
|
}
|
|
6851
6914
|
function formatReceiptLine(r, selfDid, opts = {}) {
|
|
6852
6915
|
const delegationPart = opts.fullIds ? r.delegationId : idHead2(r.delegationId);
|
|
6853
6916
|
const requestHashPart = opts.fullIds ? r.requestHash : hashHead3(r.requestHash);
|
|
6854
|
-
const id =
|
|
6917
|
+
const id = import_chalk25.default.bold(`${delegationPart}/${requestHashPart}`);
|
|
6855
6918
|
const callerHead = opts.fullIds ? r.callerDid : didHead3(r.callerDid);
|
|
6856
6919
|
const payeeHead = opts.fullIds ? r.payeeDid : didHead3(r.payeeDid);
|
|
6857
|
-
const direction = r.payeeDid === selfDid ? `${
|
|
6920
|
+
const direction = r.payeeDid === selfDid ? `${import_chalk25.default.bold("me")}(payee) \u2192 ${import_chalk25.default.dim(callerHead)}` : `${import_chalk25.default.dim(payeeHead)}(payee) \u2192 ${import_chalk25.default.bold("me")}`;
|
|
6858
6921
|
const verdict = formatVerdict(r);
|
|
6859
6922
|
const responseTail = opts.fullIds ? `
|
|
6860
|
-
${
|
|
6923
|
+
${import_chalk25.default.dim("responseHash:")} ${import_chalk25.default.cyan(r.responseHash)}` : "";
|
|
6861
6924
|
return `${id} ${direction} ${verdict}${responseTail}`;
|
|
6862
6925
|
}
|
|
6863
6926
|
function formatVerdict(r) {
|
|
6864
6927
|
switch (r.verdictProposed) {
|
|
6865
|
-
case
|
|
6866
|
-
return
|
|
6867
|
-
case
|
|
6868
|
-
return
|
|
6869
|
-
case
|
|
6870
|
-
return
|
|
6928
|
+
case import_sdk23.ReceiptVerdicts.ACCEPTED:
|
|
6929
|
+
return import_chalk25.default.green("accepted");
|
|
6930
|
+
case import_sdk23.ReceiptVerdicts.ACCEPTED_WITH_NOTES:
|
|
6931
|
+
return import_chalk25.default.yellow("accepted_with_notes");
|
|
6932
|
+
case import_sdk23.ReceiptVerdicts.REJECTED:
|
|
6933
|
+
return import_chalk25.default.red("rejected");
|
|
6871
6934
|
}
|
|
6872
6935
|
}
|
|
6873
6936
|
function idHead2(id) {
|
|
@@ -6893,8 +6956,8 @@ function parseLimit5(raw) {
|
|
|
6893
6956
|
|
|
6894
6957
|
// src/commands/recover.ts
|
|
6895
6958
|
var import_node_fs8 = require("fs");
|
|
6896
|
-
var
|
|
6897
|
-
var
|
|
6959
|
+
var import_sdk24 = require("@heyanon-arp/sdk");
|
|
6960
|
+
var import_chalk26 = __toESM(require("chalk"));
|
|
6898
6961
|
init_api();
|
|
6899
6962
|
function registerRecoverCommand(root) {
|
|
6900
6963
|
root.command("recover").description(
|
|
@@ -6914,23 +6977,23 @@ async function runRecover(opts) {
|
|
|
6914
6977
|
}
|
|
6915
6978
|
const bundle = validateKeyBundle(raw);
|
|
6916
6979
|
const identitySecret = new Uint8Array(Buffer.from(bundle.identitySecretKeyB64, "base64"));
|
|
6917
|
-
const identityPub = (0,
|
|
6918
|
-
const derivedDid = (0,
|
|
6980
|
+
const identityPub = (0, import_sdk24.base58btcDecode)(bundle.identityPublicKeyB58);
|
|
6981
|
+
const derivedDid = (0, import_sdk24.formatDid)(identityPub);
|
|
6919
6982
|
if (derivedDid !== bundle.did) {
|
|
6920
6983
|
throw new Error(`recover: key file is inconsistent \u2014 its DID (${bundle.did}) does not match its identity public key (${derivedDid})`);
|
|
6921
6984
|
}
|
|
6922
6985
|
const probe2 = new TextEncoder().encode("heyarp-recover-keycheck");
|
|
6923
|
-
if (!(0,
|
|
6986
|
+
if (!(0, import_sdk24.verify)((0, import_sdk24.sign)(probe2, identitySecret), probe2, identityPub)) {
|
|
6924
6987
|
throw new Error("recover: the identity secret key does not match the public key in this bundle");
|
|
6925
6988
|
}
|
|
6926
6989
|
const settlementSecret = new Uint8Array(Buffer.from(bundle.settlementSecretKeyB64, "base64"));
|
|
6927
|
-
const settlementPub = (0,
|
|
6928
|
-
if (!(0,
|
|
6990
|
+
const settlementPub = (0, import_sdk24.base58btcDecode)(bundle.settlementPublicKeyB58);
|
|
6991
|
+
if (!(0, import_sdk24.verify)((0, import_sdk24.sign)(probe2, settlementSecret), probe2, settlementPub)) {
|
|
6929
6992
|
throw new Error("recover: the settlement secret key does not match the settlement public key in this bundle");
|
|
6930
6993
|
}
|
|
6931
6994
|
if (bundle.ownerWallet && bundle.ownerWallet !== credential.wallet) {
|
|
6932
6995
|
process.stderr.write(
|
|
6933
|
-
|
|
6996
|
+
import_chalk26.default.yellow(
|
|
6934
6997
|
`\u26A0 this bundle was exported under wallet ${bundle.ownerWallet}, but you are logged in as ${credential.wallet}. The server will reject the recover unless the agent is yours.
|
|
6935
6998
|
`
|
|
6936
6999
|
)
|
|
@@ -6947,7 +7010,7 @@ async function runRecover(opts) {
|
|
|
6947
7010
|
lastSenderSequence = seq.lastSenderSequence;
|
|
6948
7011
|
} catch (err) {
|
|
6949
7012
|
process.stderr.write(
|
|
6950
|
-
|
|
7013
|
+
import_chalk26.default.yellow(
|
|
6951
7014
|
`\u26A0 could not read the sender sequence from the server (${err.message}). If sends are rejected as backwards, run \`heyarp escrow recover-sequence --apply\`.
|
|
6952
7015
|
`
|
|
6953
7016
|
)
|
|
@@ -6975,14 +7038,14 @@ async function runRecover(opts) {
|
|
|
6975
7038
|
jsonOut({ recovered: true, did: derivedDid, name: row.name });
|
|
6976
7039
|
return;
|
|
6977
7040
|
}
|
|
6978
|
-
console.log(
|
|
7041
|
+
console.log(import_chalk26.default.green(`\u2713 Recovered ${row.name ? `${row.name} ` : ""}${derivedDid} into local state \u2014 you can operate it now.`));
|
|
6979
7042
|
}
|
|
6980
7043
|
|
|
6981
7044
|
// src/commands/register.ts
|
|
6982
7045
|
var import_node_crypto4 = require("crypto");
|
|
6983
7046
|
var import_node_fs9 = require("fs");
|
|
6984
|
-
var
|
|
6985
|
-
var
|
|
7047
|
+
var import_sdk25 = require("@heyanon-arp/sdk");
|
|
7048
|
+
var import_chalk27 = __toESM(require("chalk"));
|
|
6986
7049
|
var import_prompts2 = __toESM(require("prompts"));
|
|
6987
7050
|
init_api();
|
|
6988
7051
|
init_paths();
|
|
@@ -6994,7 +7057,7 @@ function registerRegisterCommand(root) {
|
|
|
6994
7057
|
"`--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.",
|
|
6995
7058
|
"`--yes` is the non-interactive switch \u2014 every required field must arrive via flags (no prompts). Use this for scripted setups."
|
|
6996
7059
|
].join("\n")
|
|
6997
|
-
).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>", "
|
|
7060
|
+
).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(
|
|
6998
7061
|
"--password <s>",
|
|
6999
7062
|
// `--password` puts the secret in `argv` — visible via
|
|
7000
7063
|
// `ps aux` / kernel process table on shared hosts,
|
|
@@ -7036,44 +7099,44 @@ var defaultRegisterDeps = {
|
|
|
7036
7099
|
async function runRegister(opts, deps = defaultRegisterDeps) {
|
|
7037
7100
|
assertJsonRequiresYes(opts);
|
|
7038
7101
|
const api = deps.makeApi(opts.server);
|
|
7039
|
-
if (!opts.json) console.log(
|
|
7102
|
+
if (!opts.json) console.log(import_chalk27.default.dim(`Server: ${api.serverUrl}`));
|
|
7040
7103
|
const credential = requireCredential("register", api.serverUrl);
|
|
7041
7104
|
if (!opts.json) {
|
|
7042
7105
|
warnIfAgentsAlreadyRegistered(opts.server);
|
|
7043
7106
|
warnIfOrphanHomesPresent();
|
|
7044
7107
|
}
|
|
7045
7108
|
const keys = opts.fromKeys ? loadKeysFromFile(opts.fromKeys) : freshKeys();
|
|
7046
|
-
const did = (0,
|
|
7047
|
-
if (!opts.json) console.log(
|
|
7109
|
+
const did = (0, import_sdk25.formatDid)(keys.identityPublicKey);
|
|
7110
|
+
if (!opts.json) console.log(import_chalk27.default.dim(`DID will be: ${did}`));
|
|
7048
7111
|
const answers = await mergeAnswers(opts);
|
|
7049
7112
|
const scryptSalt = (0, import_node_crypto4.randomBytes)(16);
|
|
7050
|
-
if (!opts.json) console.log(
|
|
7051
|
-
const scryptKey = (0,
|
|
7113
|
+
if (!opts.json) console.log(import_chalk27.default.dim("Deriving scrypt key, this may take a moment..."));
|
|
7114
|
+
const scryptKey = (0, import_sdk25.deriveScryptKey)(answers.password, new Uint8Array(scryptSalt));
|
|
7052
7115
|
const challenge = await api.issueChallenge("register");
|
|
7053
7116
|
const challengeBytes = base64UrlNoPadDecode(challenge.challengeB64);
|
|
7054
7117
|
if (challengeBytes.length !== 32) {
|
|
7055
7118
|
throw new Error(`Server returned a ${challengeBytes.length}-byte challenge; expected 32`);
|
|
7056
7119
|
}
|
|
7057
|
-
const challengeSig = (0,
|
|
7058
|
-
const identityPublicKeyB58 = (0,
|
|
7120
|
+
const challengeSig = (0, import_sdk25.signChallenge)(challengeBytes, keys.identitySecretKey);
|
|
7121
|
+
const identityPublicKeyB58 = (0, import_sdk25.base58btcEncode)(keys.identityPublicKey);
|
|
7059
7122
|
await api.submitChallengeResponse({
|
|
7060
7123
|
challengeId: challenge.challengeId,
|
|
7061
7124
|
identityPublicKey: identityPublicKeyB58,
|
|
7062
7125
|
signature: Buffer.from(challengeSig).toString("base64")
|
|
7063
7126
|
});
|
|
7064
|
-
const settlementPublicKeyB58 = (0,
|
|
7065
|
-
const scryptSaltId = (0,
|
|
7127
|
+
const settlementPublicKeyB58 = (0, import_sdk25.base58btcEncode)(keys.settlementPublicKey);
|
|
7128
|
+
const scryptSaltId = (0, import_sdk25.uuidV4)();
|
|
7066
7129
|
const payload = {
|
|
7067
|
-
purpose:
|
|
7130
|
+
purpose: import_sdk25.Purpose.KEY_LINK,
|
|
7068
7131
|
agent_did: did,
|
|
7069
7132
|
identity_public_key: identityPublicKeyB58,
|
|
7070
7133
|
settlement_public_key: settlementPublicKeyB58,
|
|
7071
|
-
owner_signing_method:
|
|
7134
|
+
owner_signing_method: import_sdk25.OWNER_SIGNING_METHODS[0],
|
|
7072
7135
|
link_method: "manual",
|
|
7073
|
-
created_at: (0,
|
|
7074
|
-
nonce: (0,
|
|
7136
|
+
created_at: (0, import_sdk25.rfc3339)(),
|
|
7137
|
+
nonce: (0, import_sdk25.senderNonce)()
|
|
7075
7138
|
};
|
|
7076
|
-
const attestation = (0,
|
|
7139
|
+
const attestation = (0, import_sdk25.signKeyLinkAttestation)({ payload, scryptKey, scryptSaltId });
|
|
7077
7140
|
const body = {
|
|
7078
7141
|
challengeId: challenge.challengeId,
|
|
7079
7142
|
identityPublicKey: identityPublicKeyB58,
|
|
@@ -7116,7 +7179,7 @@ async function runRegister(opts, deps = defaultRegisterDeps) {
|
|
|
7116
7179
|
try {
|
|
7117
7180
|
result = await api.register(body, credential.token);
|
|
7118
7181
|
} catch (err) {
|
|
7119
|
-
if (err instanceof ApiError && (err.payload.code ===
|
|
7182
|
+
if (err instanceof ApiError && (err.payload.code === import_sdk25.CliAuthTokenErrorCodes.INVALID || err.payload.code === import_sdk25.CliAuthTokenErrorCodes.REQUIRED)) {
|
|
7120
7183
|
throw new Error(
|
|
7121
7184
|
`register: the stored login token for ${api.serverUrl} was rejected (${err.payload.message}) \u2014 run 'heyarp login' again. Your keys are saved locally; re-running register with --from-keys is safe.`
|
|
7122
7185
|
);
|
|
@@ -7135,19 +7198,19 @@ async function runRegister(opts, deps = defaultRegisterDeps) {
|
|
|
7135
7198
|
try {
|
|
7136
7199
|
recordHome(arpHomeDir());
|
|
7137
7200
|
} catch (registryErr) {
|
|
7138
|
-
if (!opts.json) console.log(
|
|
7201
|
+
if (!opts.json) console.log(import_chalk27.default.dim(`(homes registry write failed: ${registryErr.message})`));
|
|
7139
7202
|
}
|
|
7140
7203
|
if (!opts.json) {
|
|
7141
|
-
console.log(
|
|
7142
|
-
console.log(`${
|
|
7143
|
-
console.log(`${
|
|
7144
|
-
console.log(`${
|
|
7145
|
-
console.log(
|
|
7204
|
+
console.log(import_chalk27.default.green("\nRegistered."));
|
|
7205
|
+
console.log(`${import_chalk27.default.bold("DID")}: ${import_chalk27.default.cyan(result.did)}`);
|
|
7206
|
+
console.log(`${import_chalk27.default.bold("Settlement pubkey")} ${import_chalk27.default.dim("(fund with SOL)")}: ${import_chalk27.default.cyan(settlementPublicKeyB58)}`);
|
|
7207
|
+
console.log(`${import_chalk27.default.bold("Owner account")}: ${import_chalk27.default.cyan(credential.wallet)}`);
|
|
7208
|
+
console.log(import_chalk27.default.bold("DID document:"));
|
|
7146
7209
|
console.log(formatJson(result.didDocument));
|
|
7147
7210
|
}
|
|
7148
|
-
if (!opts.json) console.log(
|
|
7211
|
+
if (!opts.json) console.log(import_chalk27.default.green(`
|
|
7149
7212
|
\u2713 Discoverable now via \`heyarp agents\`.`));
|
|
7150
|
-
if (!opts.json) console.log(
|
|
7213
|
+
if (!opts.json) console.log(import_chalk27.default.dim(`
|
|
7151
7214
|
Local state saved to ${arpHomeDir()}/agents.json (mode 0600).`));
|
|
7152
7215
|
if (opts.json) {
|
|
7153
7216
|
console.log(
|
|
@@ -7198,8 +7261,13 @@ async function mergeAnswers(opts) {
|
|
|
7198
7261
|
promptDefs.push({
|
|
7199
7262
|
type: "text",
|
|
7200
7263
|
name: "name",
|
|
7201
|
-
message: "Agent name (
|
|
7202
|
-
validate: (v) =>
|
|
7264
|
+
message: "Agent name \u2014 unique handle (lowercase a-z0-9_, 3-32 chars, immutable; addressable instead of the DID)",
|
|
7265
|
+
validate: (v) => {
|
|
7266
|
+
const n = (0, import_sdk25.normalizeName)(v);
|
|
7267
|
+
if (!(0, import_sdk25.isValidAgentName)(n)) return "must be lowercase a-z0-9_, 3-32 chars";
|
|
7268
|
+
if ((0, import_sdk25.isReservedName)(n)) return `'${n}' is reserved`;
|
|
7269
|
+
return true;
|
|
7270
|
+
}
|
|
7203
7271
|
});
|
|
7204
7272
|
}
|
|
7205
7273
|
if (need.description) {
|
|
@@ -7215,18 +7283,29 @@ async function mergeAnswers(opts) {
|
|
|
7215
7283
|
}
|
|
7216
7284
|
const prompted = promptDefs.length > 0 ? await (0, import_prompts2.default)(promptDefs, {
|
|
7217
7285
|
onCancel: () => {
|
|
7218
|
-
console.log(
|
|
7286
|
+
console.log(import_chalk27.default.yellow("\nAborted."));
|
|
7219
7287
|
process.exit(130);
|
|
7220
7288
|
}
|
|
7221
7289
|
}) : {};
|
|
7222
7290
|
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);
|
|
7291
|
+
const name = normalizeAndValidateName(opts.name ?? prompted.name);
|
|
7223
7292
|
return {
|
|
7224
7293
|
password: opts.password ?? prompted.password,
|
|
7225
|
-
name
|
|
7294
|
+
name,
|
|
7226
7295
|
description: opts.description ?? prompted.description ?? "",
|
|
7227
7296
|
tags
|
|
7228
7297
|
};
|
|
7229
7298
|
}
|
|
7299
|
+
function normalizeAndValidateName(raw) {
|
|
7300
|
+
const name = (0, import_sdk25.normalizeName)(raw);
|
|
7301
|
+
if (!(0, import_sdk25.isValidAgentName)(name)) {
|
|
7302
|
+
throw new Error(`register: name '${raw}' must be a lowercase handle \u2014 a-z0-9_, 3-32 chars`);
|
|
7303
|
+
}
|
|
7304
|
+
if ((0, import_sdk25.isReservedName)(name)) {
|
|
7305
|
+
throw new Error(`register: name '${name}' is reserved and cannot be registered`);
|
|
7306
|
+
}
|
|
7307
|
+
return name;
|
|
7308
|
+
}
|
|
7230
7309
|
function warnIfOrphanHomesPresent() {
|
|
7231
7310
|
if (process.env.HEYARP_HOME && process.env.HEYARP_HOME.length > 0) {
|
|
7232
7311
|
return;
|
|
@@ -7236,16 +7315,16 @@ function warnIfOrphanHomesPresent() {
|
|
|
7236
7315
|
try {
|
|
7237
7316
|
others = listHomes().filter((h) => h.path !== current);
|
|
7238
7317
|
} catch (registryErr) {
|
|
7239
|
-
console.log(
|
|
7318
|
+
console.log(import_chalk27.default.dim(`(homes registry unreadable, skipping orphan-home check: ${registryErr.message})`));
|
|
7240
7319
|
return;
|
|
7241
7320
|
}
|
|
7242
7321
|
if (others.length === 0) return;
|
|
7243
|
-
const list = others.map((h) => ` \u2022 ${
|
|
7244
|
-
console.log(
|
|
7322
|
+
const list = others.map((h) => ` \u2022 ${import_chalk27.default.cyan(h.path)} ${import_chalk27.default.dim(`(last seen ${h.lastSeenAt})`)}`).join("\n");
|
|
7323
|
+
console.log(import_chalk27.default.yellow(`
|
|
7245
7324
|
\u26A0 HEYARP_HOME is unset, but other agent homes are registered on this machine:`));
|
|
7246
7325
|
console.log(list);
|
|
7247
7326
|
console.log(
|
|
7248
|
-
|
|
7327
|
+
import_chalk27.default.dim(
|
|
7249
7328
|
` Registering will create a NEW agent under ${current}.
|
|
7250
7329
|
If you meant to add to an existing home, abort (Ctrl-C) and re-run with:
|
|
7251
7330
|
HEYARP_HOME=<path> heyarp register \u2026
|
|
@@ -7258,11 +7337,11 @@ function warnIfAgentsAlreadyRegistered(serverOverride) {
|
|
|
7258
7337
|
const targetServer = resolveServerUrl(serverOverride);
|
|
7259
7338
|
const existing = listAgents().filter((row) => row.serverUrl === targetServer);
|
|
7260
7339
|
if (existing.length === 0) return;
|
|
7261
|
-
const list = existing.map((row) => ` \u2022 ${
|
|
7262
|
-
console.log(
|
|
7340
|
+
const list = existing.map((row) => ` \u2022 ${import_chalk27.default.cyan(row.agent.did)}${row.agent.name ? import_chalk27.default.dim(` (${row.agent.name})`) : ""}`).join("\n");
|
|
7341
|
+
console.log(import_chalk27.default.yellow("\n\u26A0 ~/.heyarp/agents.json already has agent(s) for this server:"));
|
|
7263
7342
|
console.log(list);
|
|
7264
7343
|
console.log(
|
|
7265
|
-
|
|
7344
|
+
import_chalk27.default.dim(
|
|
7266
7345
|
" After this register completes, you will have multiple local DIDs sharing one state file.\n To keep their state isolated, run with HEYARP_HOME pointing at a per-agent dir, e.g.\n HEYARP_HOME=/tmp/agent-alice heyarp register \u2026\n Otherwise, pass --from-did <did> explicitly on every signed command.\n"
|
|
7267
7346
|
)
|
|
7268
7347
|
);
|
|
@@ -7272,8 +7351,8 @@ function parseTagsCsv(raw) {
|
|
|
7272
7351
|
return raw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
7273
7352
|
}
|
|
7274
7353
|
function freshKeys() {
|
|
7275
|
-
const identity = (0,
|
|
7276
|
-
const settlement = (0,
|
|
7354
|
+
const identity = (0, import_sdk25.generateKeyPair)();
|
|
7355
|
+
const settlement = (0, import_sdk25.generateKeyPair)();
|
|
7277
7356
|
return {
|
|
7278
7357
|
identityPublicKey: identity.publicKey,
|
|
7279
7358
|
identitySecretKey: identity.secretKey,
|
|
@@ -7299,9 +7378,9 @@ function loadKeysFromFile(path) {
|
|
|
7299
7378
|
if (identitySecret.length !== 32) throw new Error("--from-keys: identitySecretKeyB64 is not a 32-byte Ed25519 seed");
|
|
7300
7379
|
if (settlementSecret.length !== 32) throw new Error("--from-keys: settlementSecretKeyB64 is not a 32-byte Ed25519 seed");
|
|
7301
7380
|
return {
|
|
7302
|
-
identityPublicKey: (0,
|
|
7381
|
+
identityPublicKey: (0, import_sdk25.getPublicKey)(identitySecret),
|
|
7303
7382
|
identitySecretKey: identitySecret,
|
|
7304
|
-
settlementPublicKey: (0,
|
|
7383
|
+
settlementPublicKey: (0, import_sdk25.getPublicKey)(settlementSecret),
|
|
7305
7384
|
settlementSecretKey: settlementSecret
|
|
7306
7385
|
};
|
|
7307
7386
|
}
|
|
@@ -7317,17 +7396,27 @@ function assertJsonRequiresYes(opts) {
|
|
|
7317
7396
|
}
|
|
7318
7397
|
|
|
7319
7398
|
// src/commands/relationships.ts
|
|
7320
|
-
var
|
|
7399
|
+
var import_sdk26 = require("@heyanon-arp/sdk");
|
|
7400
|
+
var import_chalk28 = __toESM(require("chalk"));
|
|
7321
7401
|
init_api();
|
|
7322
|
-
var ALLOWED_STATES2 =
|
|
7402
|
+
var ALLOWED_STATES2 = new Set(import_sdk26.RELATIONSHIP_STATE_NAMES);
|
|
7323
7403
|
function registerRelationshipsCommand(root) {
|
|
7324
7404
|
root.command("relationships").description(
|
|
7325
7405
|
"List relationships <did> belongs to (live + closed pairs, ordered by lastEventAt desc). DID can be passed positionally OR via --from-did; if both are omitted the resolver picks the sole local agent for the server (see `heyarp config set server` + multi-DID disambiguation rules)."
|
|
7326
|
-
).argument("[did]", "Agent DID (did:arp:...) \u2014 must have local state. Optional when --from-did is given OR exactly one agent is registered for the resolved server.").option("--server <url>", "Override ARP server base URL").option("--state <s>", "Filter by relationship state (pending|active|paused|closed)").option("--limit <n>", "Max relationships to return (1..100)", "20").option("--verbose", "Print the full JSON for each relationship in addition to the table
|
|
7406
|
+
).argument("[did]", "Agent DID (did:arp:...) \u2014 must have local state. Optional when --from-did is given OR exactly one agent is registered for the resolved server.").option("--server <url>", "Override ARP server base URL").option("--state <s>", "Filter by relationship state (pending|active|paused|closed)").option("--limit <n>", "Max relationships to return (1..100)", "20").option("--verbose", "Print the full JSON for each relationship in addition to the table. Mutually exclusive with --json.", false).option(
|
|
7407
|
+
"--json",
|
|
7408
|
+
"Machine-readable mode \u2014 emit the relationships as a single JSON array on stdout (RelationshipPublic[]). Prelude + table move to stderr. Mutually exclusive with --verbose.",
|
|
7409
|
+
false
|
|
7410
|
+
).option("--from-did <did>", "Alias for the positional <did> argument \u2014 accepted for consistency with other signed commands. Must match the positional if both are given.").action(async (did, opts) => {
|
|
7327
7411
|
await runRelationships(did, opts);
|
|
7328
7412
|
});
|
|
7329
7413
|
}
|
|
7330
7414
|
async function runRelationships(positionalDid, opts) {
|
|
7415
|
+
if (opts.verbose && opts.json) {
|
|
7416
|
+
throw new Error(
|
|
7417
|
+
"relationships: --verbose and --json are mutually exclusive. --json emits the rows as a clean array; --verbose adds per-row dumps that would break `--json | jq`."
|
|
7418
|
+
);
|
|
7419
|
+
}
|
|
7331
7420
|
const limit = parseLimit6(opts.limit);
|
|
7332
7421
|
const state = parseState2(opts.state);
|
|
7333
7422
|
if (positionalDid !== void 0 && opts.fromDid !== void 0 && positionalDid !== opts.fromDid) {
|
|
@@ -7337,25 +7426,29 @@ async function runRelationships(positionalDid, opts) {
|
|
|
7337
7426
|
const local = explicitDid !== void 0 ? loadAgentOrThrow(opts.server, explicitDid) : resolveSenderAgent("relationships", opts.server, void 0);
|
|
7338
7427
|
const did = local.did;
|
|
7339
7428
|
const api = new ArpApiClient(opts.server);
|
|
7340
|
-
|
|
7341
|
-
|
|
7429
|
+
progress(opts.json, import_chalk28.default.dim(`Server: ${api.serverUrl}`));
|
|
7430
|
+
progress(opts.json, import_chalk28.default.dim(`Signer: ${local.did}`));
|
|
7342
7431
|
const query = { limit };
|
|
7343
7432
|
if (state) query.state = state;
|
|
7344
7433
|
const signer = makeSigner(local);
|
|
7345
7434
|
const rows = await api.listRelationships(did, signer, query);
|
|
7435
|
+
if (opts.json) {
|
|
7436
|
+
jsonOut(rows);
|
|
7437
|
+
return;
|
|
7438
|
+
}
|
|
7346
7439
|
if (rows.length === 0) {
|
|
7347
|
-
console.log(
|
|
7440
|
+
console.log(import_chalk28.default.dim("\n(no relationships)"));
|
|
7348
7441
|
return;
|
|
7349
7442
|
}
|
|
7350
7443
|
console.log("");
|
|
7351
7444
|
console.log(formatRelationshipsTable(rows, did));
|
|
7352
7445
|
if (opts.verbose) {
|
|
7353
|
-
console.log(
|
|
7446
|
+
console.log(import_chalk28.default.bold("\nFull relationships:"));
|
|
7354
7447
|
for (const r of rows) {
|
|
7355
7448
|
console.log(formatJson(r));
|
|
7356
7449
|
}
|
|
7357
7450
|
}
|
|
7358
|
-
console.log(
|
|
7451
|
+
console.log(import_chalk28.default.dim(`
|
|
7359
7452
|
${rows.length} relationship(s).`));
|
|
7360
7453
|
}
|
|
7361
7454
|
function formatRelationshipsTable(rows, selfDid) {
|
|
@@ -7363,7 +7456,7 @@ function formatRelationshipsTable(rows, selfDid) {
|
|
|
7363
7456
|
const data = rows.map((r) => [r.relationshipId, otherPair(r, selfDid), r.state, r.lastEventAt ?? "(none)", String(r.lastEventIndex)]);
|
|
7364
7457
|
const widths = header.map((h, i) => Math.max(h.length, ...data.map((row) => row[i].length)));
|
|
7365
7458
|
const pad = (cells) => cells.map((c, i) => c.padEnd(widths[i])).join(" ");
|
|
7366
|
-
return [
|
|
7459
|
+
return [import_chalk28.default.bold(pad(header)), import_chalk28.default.dim(pad(widths.map((w) => "-".repeat(w)))), ...data.map((row) => pad(row))].join("\n");
|
|
7367
7460
|
}
|
|
7368
7461
|
function otherPair(r, selfDid) {
|
|
7369
7462
|
if (r.pairDidA === selfDid) return r.pairDidB;
|
|
@@ -7387,12 +7480,12 @@ function parseLimit6(raw) {
|
|
|
7387
7480
|
}
|
|
7388
7481
|
|
|
7389
7482
|
// src/commands/reputation.ts
|
|
7390
|
-
var
|
|
7391
|
-
var
|
|
7483
|
+
var import_sdk27 = require("@heyanon-arp/sdk");
|
|
7484
|
+
var import_chalk29 = __toESM(require("chalk"));
|
|
7392
7485
|
init_api();
|
|
7393
7486
|
function registerReputationCommand(root) {
|
|
7394
7487
|
root.command("reputation").description("Show an agent's informational reputation (composite + component scores + raw counters). Public, no auth. NOT a money/eligibility gate.").argument("<did>", "did:arp:<base58btc> identifier").option("--server <url>", "Override ARP server base URL").option("--json", "Emit the reputation as JSON on stdout.", false).action(async (did, opts) => {
|
|
7395
|
-
if (!(0,
|
|
7488
|
+
if (!(0, import_sdk27.isValidDid)(did)) {
|
|
7396
7489
|
throw new Error(`'${did}' is not a syntactically valid did:arp identifier`);
|
|
7397
7490
|
}
|
|
7398
7491
|
const api = new ArpApiClient(opts.server);
|
|
@@ -7404,10 +7497,10 @@ function registerReputationCommand(root) {
|
|
|
7404
7497
|
const s = rep.scores;
|
|
7405
7498
|
const c = rep.counters;
|
|
7406
7499
|
const j = false;
|
|
7407
|
-
progress(j,
|
|
7500
|
+
progress(j, import_chalk29.default.bold(`Reputation \u2014 ${did}`));
|
|
7408
7501
|
progress(
|
|
7409
7502
|
j,
|
|
7410
|
-
|
|
7503
|
+
import_chalk29.default.dim(` ${rep.informational ? "INFORMATIONAL" : "GATING"} \xB7 ${rep.computed ? `computed ${rep.lastComputedAt}` : "never computed (neutral cold-start)"}`)
|
|
7411
7504
|
);
|
|
7412
7505
|
progress(j, "");
|
|
7413
7506
|
progress(j, ` composite ${bar(s.composite)} ${s.composite.toFixed(2)}`);
|
|
@@ -7415,17 +7508,17 @@ function registerReputationCommand(root) {
|
|
|
7415
7508
|
progress(j, ` settlement ${bar(s.settlement)} ${s.settlement.toFixed(2)}`);
|
|
7416
7509
|
progress(j, ` dispute health ${bar(s.disputeHealth)} ${s.disputeHealth.toFixed(2)}`);
|
|
7417
7510
|
progress(j, "");
|
|
7418
|
-
progress(j,
|
|
7511
|
+
progress(j, import_chalk29.default.dim(" evidence:"));
|
|
7419
7512
|
progress(
|
|
7420
7513
|
j,
|
|
7421
|
-
|
|
7514
|
+
import_chalk29.default.dim(
|
|
7422
7515
|
` on-chain cycles ${c.onchainCycles} \xB7 completed ${c.completedDelegations} (payer ${c.completedAsPayer} / payee ${c.completedAsPayee}) \xB7 failed ${c.failedDelegations}`
|
|
7423
7516
|
)
|
|
7424
7517
|
);
|
|
7425
|
-
progress(j,
|
|
7426
|
-
progress(j,
|
|
7518
|
+
progress(j, import_chalk29.default.dim(` escrows settled ${c.settledEscrows} / refunded ${c.refundedEscrows} \xB7 disputed ${c.disputedEscrows} (adverse ${c.disputesAdverse})`));
|
|
7519
|
+
progress(j, import_chalk29.default.dim(` distinct counterparts ${c.distinctCounterparts} \xB7 active relationships ${c.activeRelationships}`));
|
|
7427
7520
|
progress(j, "");
|
|
7428
|
-
progress(j,
|
|
7521
|
+
progress(j, import_chalk29.default.dim(" Informational only \u2014 a discovery-sort signal, not a money or eligibility gate."));
|
|
7429
7522
|
});
|
|
7430
7523
|
}
|
|
7431
7524
|
function bar(score) {
|
|
@@ -7434,11 +7527,11 @@ function bar(score) {
|
|
|
7434
7527
|
}
|
|
7435
7528
|
|
|
7436
7529
|
// src/commands/send-handshake.ts
|
|
7437
|
-
var
|
|
7438
|
-
var
|
|
7530
|
+
var import_sdk28 = require("@heyanon-arp/sdk");
|
|
7531
|
+
var import_chalk30 = __toESM(require("chalk"));
|
|
7439
7532
|
init_api();
|
|
7440
7533
|
function registerSendHandshakeCommand(root) {
|
|
7441
|
-
root.command("send-handshake").description("Send a handshake envelope to
|
|
7534
|
+
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("--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("--verbose", "Print the full envelope before sending and the full server response. Mutually exclusive with --json.", false).option(
|
|
7442
7535
|
"--json",
|
|
7443
7536
|
"Machine-readable mode \u2014 emit a single JSON object on stdout ({ok, eventId, relationshipId, relationshipEventIndex, serverTimestamp, signedMessageHash, serverEventHash, prevServerEventHash, senderSequence}). The Server/Sender/Recipient prelude moves to stderr so `--json | jq` stays byte-pure. Mutually exclusive with --verbose.",
|
|
7444
7537
|
false
|
|
@@ -7447,46 +7540,44 @@ function registerSendHandshakeCommand(root) {
|
|
|
7447
7540
|
});
|
|
7448
7541
|
}
|
|
7449
7542
|
async function runSendHandshake(recipientDid, opts) {
|
|
7450
|
-
if (!isDid(recipientDid)) {
|
|
7451
|
-
throw new Error(`send-handshake: <recipient-did> must look like 'did:arp:...' (got '${recipientDid}')`);
|
|
7452
|
-
}
|
|
7453
7543
|
if (opts.verbose && opts.json) {
|
|
7454
7544
|
throw new Error(
|
|
7455
7545
|
"send-handshake: --verbose and --json are mutually exclusive. --json emits the structured server response; --verbose adds envelope + response dumps that would break `--json | jq`."
|
|
7456
7546
|
);
|
|
7457
7547
|
}
|
|
7548
|
+
recipientDid = await resolveRecipient(opts.server, "send-handshake", recipientDid, { json: opts.json });
|
|
7458
7549
|
const ttlSeconds = parseTtl3(opts.ttl);
|
|
7459
7550
|
const api = new ArpApiClient(opts.server);
|
|
7460
|
-
progress(opts.json,
|
|
7551
|
+
progress(opts.json, import_chalk30.default.dim(`Server: ${api.serverUrl}`));
|
|
7461
7552
|
const sender = resolveSenderAgent("send-handshake", opts.server, opts.fromDid);
|
|
7462
|
-
progress(opts.json,
|
|
7463
|
-
progress(opts.json,
|
|
7553
|
+
progress(opts.json, import_chalk30.default.dim(`Sender: ${sender.did}`));
|
|
7554
|
+
progress(opts.json, import_chalk30.default.dim(`Recipient: ${recipientDid}`));
|
|
7464
7555
|
const content = {};
|
|
7465
7556
|
if (opts.greeting) content.greeting = opts.greeting;
|
|
7466
7557
|
if (opts.intent) content.intent = opts.intent;
|
|
7467
7558
|
const body = { type: "handshake", content };
|
|
7468
7559
|
const nextSequence = (sender.lastSenderSequence ?? 0) + 1;
|
|
7469
7560
|
const protectedBlock = {
|
|
7470
|
-
protocol_version:
|
|
7471
|
-
purpose:
|
|
7472
|
-
message_id: (0,
|
|
7561
|
+
protocol_version: import_sdk28.CURRENT_PROTOCOL_VERSION,
|
|
7562
|
+
purpose: import_sdk28.Purpose.ENVELOPE,
|
|
7563
|
+
message_id: (0, import_sdk28.uuidV4)(),
|
|
7473
7564
|
sender_did: sender.did,
|
|
7474
7565
|
recipient_did: recipientDid,
|
|
7475
7566
|
relationship_id: null,
|
|
7476
7567
|
sender_sequence: nextSequence,
|
|
7477
|
-
sender_nonce: (0,
|
|
7478
|
-
timestamp: (0,
|
|
7479
|
-
expires_at: (0,
|
|
7568
|
+
sender_nonce: (0, import_sdk28.senderNonce)(),
|
|
7569
|
+
timestamp: (0, import_sdk28.rfc3339)(),
|
|
7570
|
+
expires_at: (0, import_sdk28.expiresAt)(ttlSeconds),
|
|
7480
7571
|
delivery_id: null
|
|
7481
7572
|
};
|
|
7482
7573
|
const signer = makeSigner(sender);
|
|
7483
|
-
const envelope = (0,
|
|
7574
|
+
const envelope = (0, import_sdk28.signEnvelope)({
|
|
7484
7575
|
protected: protectedBlock,
|
|
7485
7576
|
body,
|
|
7486
7577
|
identitySecretKey: signer.identitySecretKey
|
|
7487
7578
|
});
|
|
7488
7579
|
if (opts.verbose) {
|
|
7489
|
-
console.log(
|
|
7580
|
+
console.log(import_chalk30.default.bold("\nEnvelope (pre-send):"));
|
|
7490
7581
|
console.log(formatJson(envelope));
|
|
7491
7582
|
}
|
|
7492
7583
|
const result = await api.ingest(envelope);
|
|
@@ -7494,6 +7585,7 @@ async function runSendHandshake(recipientDid, opts) {
|
|
|
7494
7585
|
if (opts.json) {
|
|
7495
7586
|
jsonOut({
|
|
7496
7587
|
ok: true,
|
|
7588
|
+
action: "handshake",
|
|
7497
7589
|
eventId: result.eventId,
|
|
7498
7590
|
relationshipId: result.relationshipId,
|
|
7499
7591
|
relationshipEventIndex: result.relationshipEventIndex,
|
|
@@ -7505,23 +7597,23 @@ async function runSendHandshake(recipientDid, opts) {
|
|
|
7505
7597
|
});
|
|
7506
7598
|
return;
|
|
7507
7599
|
}
|
|
7508
|
-
console.log(
|
|
7509
|
-
console.log(`${
|
|
7510
|
-
console.log(`${
|
|
7511
|
-
console.log(`${
|
|
7512
|
-
console.log(`${
|
|
7513
|
-
console.log(`${
|
|
7514
|
-
console.log(`${
|
|
7600
|
+
console.log(import_chalk30.default.green("\nDelivered."));
|
|
7601
|
+
console.log(`${import_chalk30.default.bold("Event id")}: ${import_chalk30.default.cyan(result.eventId)}`);
|
|
7602
|
+
console.log(`${import_chalk30.default.bold("Relationship id")}: ${import_chalk30.default.cyan(result.relationshipId)}`);
|
|
7603
|
+
console.log(`${import_chalk30.default.bold("Chain index")}: ${import_chalk30.default.cyan(String(result.relationshipEventIndex))}`);
|
|
7604
|
+
console.log(`${import_chalk30.default.bold("Server timestamp")}: ${import_chalk30.default.cyan(result.serverTimestamp)}`);
|
|
7605
|
+
console.log(`${import_chalk30.default.bold("Signed message hash")}: ${import_chalk30.default.cyan(result.signedMessageHash)}`);
|
|
7606
|
+
console.log(`${import_chalk30.default.bold("Server event hash")}: ${import_chalk30.default.cyan(result.serverEventHash)}`);
|
|
7515
7607
|
if (result.prevServerEventHash) {
|
|
7516
|
-
console.log(`${
|
|
7608
|
+
console.log(`${import_chalk30.default.bold("Prev server event hash")}: ${import_chalk30.default.cyan(result.prevServerEventHash)}`);
|
|
7517
7609
|
} else {
|
|
7518
|
-
console.log(`${
|
|
7610
|
+
console.log(`${import_chalk30.default.bold("Prev server event hash")}: ${import_chalk30.default.dim("(null \u2014 first event of this relationship)")}`);
|
|
7519
7611
|
}
|
|
7520
7612
|
if (opts.verbose) {
|
|
7521
|
-
console.log(
|
|
7613
|
+
console.log(import_chalk30.default.bold("\nFull server response:"));
|
|
7522
7614
|
console.log(formatJson(result));
|
|
7523
7615
|
}
|
|
7524
|
-
console.log(
|
|
7616
|
+
console.log(import_chalk30.default.dim(`
|
|
7525
7617
|
Local sender_sequence advanced to ${nextSequence}.`));
|
|
7526
7618
|
}
|
|
7527
7619
|
function parseTtl3(raw) {
|
|
@@ -7532,15 +7624,12 @@ function parseTtl3(raw) {
|
|
|
7532
7624
|
}
|
|
7533
7625
|
return n;
|
|
7534
7626
|
}
|
|
7535
|
-
function isDid(s) {
|
|
7536
|
-
return typeof s === "string" && s.startsWith("did:arp:") && s.length > "did:arp:".length;
|
|
7537
|
-
}
|
|
7538
7627
|
|
|
7539
7628
|
// src/commands/send-handshake-response.ts
|
|
7540
|
-
var
|
|
7541
|
-
var
|
|
7629
|
+
var import_sdk29 = require("@heyanon-arp/sdk");
|
|
7630
|
+
var import_chalk31 = __toESM(require("chalk"));
|
|
7542
7631
|
init_api();
|
|
7543
|
-
var ALLOWED_DECISIONS =
|
|
7632
|
+
var ALLOWED_DECISIONS = new Set(import_sdk29.HANDSHAKE_DECISIONS);
|
|
7544
7633
|
function registerSendHandshakeResponseCommand(root) {
|
|
7545
7634
|
root.command("send-handshake-response").description("Accept or decline an inbound handshake from <recipient-did>. Server reuses the existing relationship row.").argument("<recipient-did>", "Recipient agent DID (did:arp:...) \u2014 the original handshake sender").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("--decision <s>", "REQUIRED: accept or decline").option("--notes <s>", "Optional notes included in body.content").option(
|
|
7546
7635
|
"--reason <code>",
|
|
@@ -7548,8 +7637,8 @@ function registerSendHandshakeResponseCommand(root) {
|
|
|
7548
7637
|
// We don't use commander's requiredOption because it
|
|
7549
7638
|
// would fire for the accept path too; validate manually
|
|
7550
7639
|
// after decision is parsed.
|
|
7551
|
-
`When --decision=decline: required reason code (one of: ${
|
|
7552
|
-
).option("--reason-detail <s>", "Optional free-text elaboration alongside --reason (max 512 chars).").option("--ttl <seconds>",
|
|
7640
|
+
`When --decision=decline: required reason code (one of: ${import_sdk29.DECLINE_REASONS.join(", ")}). Carried in body.content.reason.`
|
|
7641
|
+
).option("--reason-detail <s>", "Optional free-text elaboration alongside --reason (max 512 chars).").option("--ttl <seconds>", `Envelope TTL in seconds (max ${import_sdk29.MAX_ENVELOPE_TTL_SECONDS} = 24h)`, "3600").option("--verbose", "Print the full envelope before sending and the full server response. Mutually exclusive with --json.", false).option(
|
|
7553
7642
|
"--json",
|
|
7554
7643
|
"Machine-readable mode \u2014 emit a single JSON object on stdout ({ok, decision, eventId, relationshipId, relationshipEventIndex, serverTimestamp, serverEventHash, prevServerEventHash}; idempotent short-circuit adds {idempotent:true}). Prelude + banners move off stdout; on failure stderr carries `{code, message}`. Mutually exclusive with --verbose.",
|
|
7555
7644
|
false
|
|
@@ -7567,23 +7656,23 @@ async function runSendHandshakeResponse(recipientDid, opts) {
|
|
|
7567
7656
|
"send-handshake-response: --verbose and --json are mutually exclusive. --json emits the structured server response; --verbose adds envelope + response dumps that would break `--json | jq`."
|
|
7568
7657
|
);
|
|
7569
7658
|
}
|
|
7570
|
-
if (!
|
|
7571
|
-
throw new Error(`send-handshake-response: <recipient-did> must
|
|
7659
|
+
if (!(0, import_sdk29.isValidDid)(recipientDid)) {
|
|
7660
|
+
throw new Error(`send-handshake-response: <recipient-did> must be a valid did:arp identifier (base58btc-encoded 32-byte Ed25519 pubkey) (got '${recipientDid}')`);
|
|
7572
7661
|
}
|
|
7573
7662
|
const decision = parseDecision(opts.decision);
|
|
7574
7663
|
const ttlSeconds = parseTtl4(opts.ttl);
|
|
7575
7664
|
let declinePayload = null;
|
|
7576
|
-
if (decision ===
|
|
7665
|
+
if (decision === import_sdk29.HandshakeDecisions.DECLINE) {
|
|
7577
7666
|
const reason = parseDeclineReason("send-handshake-response", opts.reason);
|
|
7578
7667
|
const detail = parseReasonDetail("send-handshake-response", opts.reasonDetail);
|
|
7579
7668
|
declinePayload = detail ? { reason, reasonDetail: detail } : { reason };
|
|
7580
7669
|
}
|
|
7581
7670
|
const api = new ArpApiClient(opts.server);
|
|
7582
|
-
progress(opts.json,
|
|
7671
|
+
progress(opts.json, import_chalk31.default.dim(`Server: ${api.serverUrl}`));
|
|
7583
7672
|
const sender = resolveSenderAgent("send-handshake-response", opts.server, opts.fromDid);
|
|
7584
|
-
progress(opts.json,
|
|
7585
|
-
progress(opts.json,
|
|
7586
|
-
progress(opts.json,
|
|
7673
|
+
progress(opts.json, import_chalk31.default.dim(`Sender: ${sender.did}`));
|
|
7674
|
+
progress(opts.json, import_chalk31.default.dim(`Recipient: ${recipientDid}`));
|
|
7675
|
+
progress(opts.json, import_chalk31.default.dim(`Decision: ${decision}`));
|
|
7587
7676
|
const signer = makeSigner(sender);
|
|
7588
7677
|
if (!opts.force) {
|
|
7589
7678
|
try {
|
|
@@ -7599,6 +7688,7 @@ async function runSendHandshakeResponse(recipientDid, opts) {
|
|
|
7599
7688
|
if (opts.json) {
|
|
7600
7689
|
jsonOut({
|
|
7601
7690
|
ok: true,
|
|
7691
|
+
action: "handshake_response",
|
|
7602
7692
|
idempotent: true,
|
|
7603
7693
|
decision,
|
|
7604
7694
|
eventId: previousResponseFromMe.eventId,
|
|
@@ -7612,13 +7702,13 @@ async function runSendHandshakeResponse(recipientDid, opts) {
|
|
|
7612
7702
|
});
|
|
7613
7703
|
return;
|
|
7614
7704
|
}
|
|
7615
|
-
progress(opts.json,
|
|
7705
|
+
progress(opts.json, import_chalk31.default.yellow(`
|
|
7616
7706
|
[--idempotency] Relationship ${existing.relationshipId} with ${recipientDid} is already 'active'.`));
|
|
7617
7707
|
progress(
|
|
7618
7708
|
opts.json,
|
|
7619
|
-
|
|
7709
|
+
import_chalk31.default.dim(`A previous accept from this signer (event ${previousResponseFromMe.eventId}) landed successfully. Skipping re-send (use --force to override).`)
|
|
7620
7710
|
);
|
|
7621
|
-
progress(opts.json,
|
|
7711
|
+
progress(opts.json, import_chalk31.default.dim(`Last event index: ${existing.lastEventIndex}, last server event hash: ${existing.lastServerEventHash ?? "(none)"}`));
|
|
7622
7712
|
return;
|
|
7623
7713
|
}
|
|
7624
7714
|
throw new Error(
|
|
@@ -7629,7 +7719,7 @@ async function runSendHandshakeResponse(recipientDid, opts) {
|
|
|
7629
7719
|
if (probeErr instanceof Error && /CLOSED|terminated|already 'active' from a previous ACCEPT|original initiator/i.test(probeErr.message)) {
|
|
7630
7720
|
throw probeErr;
|
|
7631
7721
|
}
|
|
7632
|
-
progress(opts.json,
|
|
7722
|
+
progress(opts.json, import_chalk31.default.dim(`(idempotency probe failed; proceeding anyway: ${probeErr.message})`));
|
|
7633
7723
|
}
|
|
7634
7724
|
}
|
|
7635
7725
|
const content = { decision };
|
|
@@ -7641,25 +7731,25 @@ async function runSendHandshakeResponse(recipientDid, opts) {
|
|
|
7641
7731
|
const body = { type: "handshake_response", content };
|
|
7642
7732
|
const nextSequence = (sender.lastSenderSequence ?? 0) + 1;
|
|
7643
7733
|
const protectedBlock = {
|
|
7644
|
-
protocol_version:
|
|
7645
|
-
purpose:
|
|
7646
|
-
message_id: (0,
|
|
7734
|
+
protocol_version: import_sdk29.CURRENT_PROTOCOL_VERSION,
|
|
7735
|
+
purpose: import_sdk29.Purpose.ENVELOPE,
|
|
7736
|
+
message_id: (0, import_sdk29.uuidV4)(),
|
|
7647
7737
|
sender_did: sender.did,
|
|
7648
7738
|
recipient_did: recipientDid,
|
|
7649
7739
|
relationship_id: null,
|
|
7650
7740
|
sender_sequence: nextSequence,
|
|
7651
|
-
sender_nonce: (0,
|
|
7652
|
-
timestamp: (0,
|
|
7653
|
-
expires_at: (0,
|
|
7741
|
+
sender_nonce: (0, import_sdk29.senderNonce)(),
|
|
7742
|
+
timestamp: (0, import_sdk29.rfc3339)(),
|
|
7743
|
+
expires_at: (0, import_sdk29.expiresAt)(ttlSeconds),
|
|
7654
7744
|
delivery_id: null
|
|
7655
7745
|
};
|
|
7656
|
-
const envelope = (0,
|
|
7746
|
+
const envelope = (0, import_sdk29.signEnvelope)({
|
|
7657
7747
|
protected: protectedBlock,
|
|
7658
7748
|
body,
|
|
7659
7749
|
identitySecretKey: signer.identitySecretKey
|
|
7660
7750
|
});
|
|
7661
7751
|
if (opts.verbose) {
|
|
7662
|
-
console.log(
|
|
7752
|
+
console.log(import_chalk31.default.bold("\nEnvelope (pre-send):"));
|
|
7663
7753
|
console.log(formatJson(envelope));
|
|
7664
7754
|
}
|
|
7665
7755
|
const result = await api.ingest(envelope);
|
|
@@ -7667,6 +7757,7 @@ async function runSendHandshakeResponse(recipientDid, opts) {
|
|
|
7667
7757
|
if (opts.json) {
|
|
7668
7758
|
jsonOut({
|
|
7669
7759
|
ok: true,
|
|
7760
|
+
action: "handshake_response",
|
|
7670
7761
|
decision,
|
|
7671
7762
|
eventId: result.eventId,
|
|
7672
7763
|
relationshipId: result.relationshipId,
|
|
@@ -7679,23 +7770,23 @@ async function runSendHandshakeResponse(recipientDid, opts) {
|
|
|
7679
7770
|
});
|
|
7680
7771
|
return;
|
|
7681
7772
|
}
|
|
7682
|
-
console.log(
|
|
7683
|
-
console.log(`${
|
|
7684
|
-
console.log(`${
|
|
7685
|
-
console.log(`${
|
|
7686
|
-
console.log(`${
|
|
7687
|
-
console.log(`${
|
|
7688
|
-
console.log(`${
|
|
7773
|
+
console.log(import_chalk31.default.green("\nDelivered."));
|
|
7774
|
+
console.log(`${import_chalk31.default.bold("Event id")}: ${import_chalk31.default.cyan(result.eventId)}`);
|
|
7775
|
+
console.log(`${import_chalk31.default.bold("Relationship id")}: ${import_chalk31.default.cyan(result.relationshipId)}`);
|
|
7776
|
+
console.log(`${import_chalk31.default.bold("Chain index")}: ${import_chalk31.default.cyan(String(result.relationshipEventIndex))}`);
|
|
7777
|
+
console.log(`${import_chalk31.default.bold("Server timestamp")}: ${import_chalk31.default.cyan(result.serverTimestamp)}`);
|
|
7778
|
+
console.log(`${import_chalk31.default.bold("Signed message hash")}: ${import_chalk31.default.cyan(result.signedMessageHash)}`);
|
|
7779
|
+
console.log(`${import_chalk31.default.bold("Server event hash")}: ${import_chalk31.default.cyan(result.serverEventHash)}`);
|
|
7689
7780
|
if (result.prevServerEventHash) {
|
|
7690
|
-
console.log(`${
|
|
7781
|
+
console.log(`${import_chalk31.default.bold("Prev server event hash")}: ${import_chalk31.default.cyan(result.prevServerEventHash)}`);
|
|
7691
7782
|
} else {
|
|
7692
|
-
console.log(`${
|
|
7783
|
+
console.log(`${import_chalk31.default.bold("Prev server event hash")}: ${import_chalk31.default.dim("(null \u2014 first event of this relationship)")}`);
|
|
7693
7784
|
}
|
|
7694
7785
|
if (opts.verbose) {
|
|
7695
|
-
console.log(
|
|
7786
|
+
console.log(import_chalk31.default.bold("\nFull server response:"));
|
|
7696
7787
|
console.log(formatJson(result));
|
|
7697
7788
|
}
|
|
7698
|
-
console.log(
|
|
7789
|
+
console.log(import_chalk31.default.dim(`
|
|
7699
7790
|
Local sender_sequence advanced to ${nextSequence}.`));
|
|
7700
7791
|
}
|
|
7701
7792
|
function parseDecision(raw) {
|
|
@@ -7715,13 +7806,10 @@ function parseTtl4(raw) {
|
|
|
7715
7806
|
}
|
|
7716
7807
|
return n;
|
|
7717
7808
|
}
|
|
7718
|
-
function isDid2(s) {
|
|
7719
|
-
return typeof s === "string" && s.startsWith("did:arp:") && s.length > "did:arp:".length;
|
|
7720
|
-
}
|
|
7721
7809
|
function classifyIdempotencyOutcome(decision, existing) {
|
|
7722
7810
|
if (!existing) return { kind: "proceed" };
|
|
7723
|
-
if (existing.state ===
|
|
7724
|
-
if (decision ===
|
|
7811
|
+
if (existing.state === import_sdk29.RelationshipStates.ACTIVE) {
|
|
7812
|
+
if (decision === import_sdk29.HandshakeDecisions.DECLINE) {
|
|
7725
7813
|
return {
|
|
7726
7814
|
kind: "error",
|
|
7727
7815
|
message: `send-handshake-response: relationship ${existing.relationshipId} is already 'active' from a previous ACCEPT. A decline cannot reverse that \u2014 the active relationship is now under FSM control. If you want to terminate, close the relationship explicitly; pass --force to ignore this check and send the decline (which the server will reject with DOM_INVALID_TRANSITION).`
|
|
@@ -7729,7 +7817,7 @@ function classifyIdempotencyOutcome(decision, existing) {
|
|
|
7729
7817
|
}
|
|
7730
7818
|
return { kind: "short-circuit" };
|
|
7731
7819
|
}
|
|
7732
|
-
if (existing.state ===
|
|
7820
|
+
if (existing.state === import_sdk29.RelationshipStates.CLOSED) {
|
|
7733
7821
|
return {
|
|
7734
7822
|
kind: "error",
|
|
7735
7823
|
message: `send-handshake-response: relationship ${existing.relationshipId} is CLOSED. Cannot respond to handshake on a terminated relationship \u2014 start a fresh handshake instead.`
|
|
@@ -7749,7 +7837,7 @@ async function findExistingRelationship(api, signer, senderDid, recipientDid) {
|
|
|
7749
7837
|
}
|
|
7750
7838
|
|
|
7751
7839
|
// src/commands/watch.ts
|
|
7752
|
-
var
|
|
7840
|
+
var import_chalk32 = __toESM(require("chalk"));
|
|
7753
7841
|
init_api();
|
|
7754
7842
|
function registerWatchCommand(root) {
|
|
7755
7843
|
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("--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) => {
|
|
@@ -7760,9 +7848,9 @@ async function runWatch(relationshipId, opts) {
|
|
|
7760
7848
|
const local = resolveSenderAgent("watch", opts.server, opts.fromDid);
|
|
7761
7849
|
const api = new ArpApiClient(opts.server);
|
|
7762
7850
|
if (!opts.json) {
|
|
7763
|
-
console.log(
|
|
7764
|
-
console.log(
|
|
7765
|
-
console.log(
|
|
7851
|
+
console.log(import_chalk32.default.dim(`Server: ${api.serverUrl}`));
|
|
7852
|
+
console.log(import_chalk32.default.dim(`Signer: ${local.did}`));
|
|
7853
|
+
console.log(import_chalk32.default.dim(`Watching: ${relationshipId}`));
|
|
7766
7854
|
}
|
|
7767
7855
|
const controller = new AbortController();
|
|
7768
7856
|
let userAborted = false;
|
|
@@ -7781,7 +7869,7 @@ async function runWatch(relationshipId, opts) {
|
|
|
7781
7869
|
}
|
|
7782
7870
|
if (event.type === "heartbeat") continue;
|
|
7783
7871
|
if (event.type === "connected") {
|
|
7784
|
-
console.log(
|
|
7872
|
+
console.log(import_chalk32.default.green(`\u25CF stream open \u2014 watching ${relationshipId}`));
|
|
7785
7873
|
continue;
|
|
7786
7874
|
}
|
|
7787
7875
|
if (event.type === "envelope") {
|
|
@@ -7795,7 +7883,7 @@ async function runWatch(relationshipId, opts) {
|
|
|
7795
7883
|
}
|
|
7796
7884
|
continue;
|
|
7797
7885
|
}
|
|
7798
|
-
console.log(
|
|
7886
|
+
console.log(import_chalk32.default.dim(`(unknown event: ${event.type})`));
|
|
7799
7887
|
}
|
|
7800
7888
|
if (!userAborted) {
|
|
7801
7889
|
throw new Error(`watch ${relationshipId}: stream ended unexpectedly (server may have restarted, or the change stream errored). Re-run to reconnect.`);
|
|
@@ -7803,7 +7891,7 @@ async function runWatch(relationshipId, opts) {
|
|
|
7803
7891
|
} catch (err) {
|
|
7804
7892
|
const name = err.name;
|
|
7805
7893
|
if (name === "AbortError" || userAborted) {
|
|
7806
|
-
if (!opts.json) console.log(
|
|
7894
|
+
if (!opts.json) console.log(import_chalk32.default.dim("\nstream closed."));
|
|
7807
7895
|
return;
|
|
7808
7896
|
}
|
|
7809
7897
|
throw err;
|
|
@@ -7817,21 +7905,21 @@ function formatWatchLine(ev, selfDid, opts = {}) {
|
|
|
7817
7905
|
const type = ev.type.padEnd(20);
|
|
7818
7906
|
const direction = directionLabel2(ev, selfDid, opts);
|
|
7819
7907
|
const hash = opts.fullIds ? ev.serverEventHash : hashHead4(ev.serverEventHash);
|
|
7820
|
-
return `${
|
|
7908
|
+
return `${import_chalk32.default.dim(`[${ts}]`)} ${type} ${direction} ${import_chalk32.default.cyan(hash)}`;
|
|
7821
7909
|
}
|
|
7822
7910
|
function directionLabel2(ev, selfDid, opts = {}) {
|
|
7823
7911
|
const senderHead = opts.fullIds ? ev.senderDid : didHead4(ev.senderDid);
|
|
7824
7912
|
const recipientHead = opts.fullIds ? ev.recipientDid : didHead4(ev.recipientDid);
|
|
7825
|
-
if (ev.senderDid === selfDid) return `${
|
|
7826
|
-
if (ev.recipientDid === selfDid) return `${
|
|
7827
|
-
return `${
|
|
7913
|
+
if (ev.senderDid === selfDid) return `${import_chalk32.default.bold("me")} \u2192 ${import_chalk32.default.dim(recipientHead)}`;
|
|
7914
|
+
if (ev.recipientDid === selfDid) return `${import_chalk32.default.dim(senderHead)} \u2192 ${import_chalk32.default.bold("me")}`;
|
|
7915
|
+
return `${import_chalk32.default.dim(senderHead)} \u2192 ${import_chalk32.default.dim(recipientHead)}`;
|
|
7828
7916
|
}
|
|
7829
7917
|
function didHead4(did) {
|
|
7830
7918
|
if (did.length <= 20) return did;
|
|
7831
7919
|
return `${did.slice(0, 20)}...`;
|
|
7832
7920
|
}
|
|
7833
7921
|
function hashHead4(hash) {
|
|
7834
|
-
if (!hash) return
|
|
7922
|
+
if (!hash) return import_chalk32.default.dim("(none)");
|
|
7835
7923
|
if (hash.length <= 14) return hash;
|
|
7836
7924
|
return `${hash.slice(0, 14)}...`;
|
|
7837
7925
|
}
|
|
@@ -7843,7 +7931,7 @@ function formatClock(iso) {
|
|
|
7843
7931
|
}
|
|
7844
7932
|
|
|
7845
7933
|
// src/commands/whoami.ts
|
|
7846
|
-
var
|
|
7934
|
+
var import_chalk33 = __toESM(require("chalk"));
|
|
7847
7935
|
init_api();
|
|
7848
7936
|
function registerWhoamiCommand(root) {
|
|
7849
7937
|
root.command("whoami").description(
|
|
@@ -7873,12 +7961,12 @@ function registerWhoamiCommand(root) {
|
|
|
7873
7961
|
if (opts.json) {
|
|
7874
7962
|
console.log(formatJson({ ...localJson, account: credential ? { wallet: credential.wallet } : null }));
|
|
7875
7963
|
} else {
|
|
7876
|
-
console.log(
|
|
7877
|
-
console.log(` DID: ${
|
|
7878
|
-
console.log(` Settlement pubkey: ${
|
|
7879
|
-
console.log(` Identity pubkey: ${
|
|
7964
|
+
console.log(import_chalk33.default.bold("Local agent:"));
|
|
7965
|
+
console.log(` DID: ${import_chalk33.default.cyan(local.did)}`);
|
|
7966
|
+
console.log(` Settlement pubkey: ${import_chalk33.default.cyan(local.settlementPublicKeyB58)}`);
|
|
7967
|
+
console.log(` Identity pubkey: ${import_chalk33.default.cyan(local.identityPublicKeyB58)}`);
|
|
7880
7968
|
if (local.name) console.log(` Name: ${local.name}`);
|
|
7881
|
-
console.log(` Account: ${credential ?
|
|
7969
|
+
console.log(` Account: ${credential ? import_chalk33.default.cyan(credential.wallet) : import_chalk33.default.dim("not logged in (heyarp login)")}`);
|
|
7882
7970
|
}
|
|
7883
7971
|
return;
|
|
7884
7972
|
}
|
|
@@ -7896,19 +7984,19 @@ function registerWhoamiCommand(root) {
|
|
|
7896
7984
|
if (opts.json) {
|
|
7897
7985
|
console.log(formatJson({ local: localJson, account, server: agent }));
|
|
7898
7986
|
} else {
|
|
7899
|
-
console.log(
|
|
7900
|
-
console.log(
|
|
7901
|
-
console.log(` DID: ${
|
|
7902
|
-
console.log(` Settlement pubkey: ${
|
|
7903
|
-
console.log(` Identity pubkey: ${
|
|
7904
|
-
console.log(
|
|
7987
|
+
console.log(import_chalk33.default.dim(`Server: ${api.serverUrl}`));
|
|
7988
|
+
console.log(import_chalk33.default.bold("\nLocal agent:"));
|
|
7989
|
+
console.log(` DID: ${import_chalk33.default.cyan(local.did)}`);
|
|
7990
|
+
console.log(` Settlement pubkey: ${import_chalk33.default.cyan(local.settlementPublicKeyB58)}`);
|
|
7991
|
+
console.log(` Identity pubkey: ${import_chalk33.default.cyan(local.identityPublicKeyB58)}`);
|
|
7992
|
+
console.log(import_chalk33.default.bold("\nAccount:"));
|
|
7905
7993
|
if (account) {
|
|
7906
|
-
console.log(` Wallet: ${
|
|
7994
|
+
console.log(` Wallet: ${import_chalk33.default.cyan(account.wallet)}`);
|
|
7907
7995
|
console.log(` Agents registered: ${account.agentCount}`);
|
|
7908
7996
|
} else {
|
|
7909
|
-
console.log(` ${
|
|
7997
|
+
console.log(` ${import_chalk33.default.dim("not logged in (heyarp login)")}`);
|
|
7910
7998
|
}
|
|
7911
|
-
console.log(
|
|
7999
|
+
console.log(import_chalk33.default.bold("\nServer profile:"));
|
|
7912
8000
|
console.log(formatJson(agent));
|
|
7913
8001
|
}
|
|
7914
8002
|
} catch (err) {
|
|
@@ -7918,47 +8006,77 @@ function registerWhoamiCommand(root) {
|
|
|
7918
8006
|
});
|
|
7919
8007
|
}
|
|
7920
8008
|
|
|
8009
|
+
// src/commands/whois.ts
|
|
8010
|
+
var import_sdk30 = require("@heyanon-arp/sdk");
|
|
8011
|
+
var import_chalk34 = __toESM(require("chalk"));
|
|
8012
|
+
init_api();
|
|
8013
|
+
function registerWhoisCommand(root) {
|
|
8014
|
+
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) => {
|
|
8015
|
+
const api = new ArpApiClient(opts.server);
|
|
8016
|
+
progress(opts.json, import_chalk34.default.dim(`Server: ${api.serverUrl}`));
|
|
8017
|
+
const profile = await resolveProfile(api, input);
|
|
8018
|
+
if (opts.json) {
|
|
8019
|
+
jsonOut(profile);
|
|
8020
|
+
return;
|
|
8021
|
+
}
|
|
8022
|
+
printProfile(profile);
|
|
8023
|
+
});
|
|
8024
|
+
}
|
|
8025
|
+
async function resolveProfile(api, input) {
|
|
8026
|
+
if (input.startsWith("did:arp:")) {
|
|
8027
|
+
if (!(0, import_sdk30.isValidDid)(input)) {
|
|
8028
|
+
throw new Error(`whois: '${input}' starts with did:arp: but is not a valid DID (base58btc-encoded 32-byte Ed25519 pubkey).`);
|
|
8029
|
+
}
|
|
8030
|
+
return api.discoverProfile(input);
|
|
8031
|
+
}
|
|
8032
|
+
const name = (0, import_sdk30.normalizeName)(input);
|
|
8033
|
+
if (!(0, import_sdk30.isValidAgentName)(name)) {
|
|
8034
|
+
throw new Error(`whois: '${input}' is neither a DID (did:arp:...) nor a valid agent name (lowercase a-z0-9_, 3-32 chars).`);
|
|
8035
|
+
}
|
|
8036
|
+
return api.discoverByName(name);
|
|
8037
|
+
}
|
|
8038
|
+
function printProfile(p) {
|
|
8039
|
+
console.log(`${import_chalk34.default.bold("Name")}: ${import_chalk34.default.cyan(p.name ?? "(unnamed)")}`);
|
|
8040
|
+
console.log(`${import_chalk34.default.bold("DID")}: ${import_chalk34.default.cyan(p.did)}`);
|
|
8041
|
+
if (p.description) console.log(`${import_chalk34.default.bold("Description")}: ${p.description}`);
|
|
8042
|
+
if (p.tags.length > 0) console.log(`${import_chalk34.default.bold("Tags")}: ${p.tags.join(", ")}`);
|
|
8043
|
+
console.log(`${import_chalk34.default.bold("Registered")}: ${p.registeredAt}`);
|
|
8044
|
+
const rep = p.reputation;
|
|
8045
|
+
console.log(`${import_chalk34.default.bold("Reputation")}: composite ${rep.scores.composite}/100${rep.computed ? "" : import_chalk34.default.dim(" (cold-start \u2014 no settled cycles yet)")}`);
|
|
8046
|
+
console.log(`${import_chalk34.default.bold("Online")}: ${p.liveness.online ? import_chalk34.default.green("yes") : import_chalk34.default.dim("no")}`);
|
|
8047
|
+
}
|
|
8048
|
+
|
|
7921
8049
|
// src/commands/work.ts
|
|
7922
|
-
var
|
|
7923
|
-
var
|
|
8050
|
+
var import_sdk31 = require("@heyanon-arp/sdk");
|
|
8051
|
+
var import_chalk35 = __toESM(require("chalk"));
|
|
7924
8052
|
init_api();
|
|
7925
8053
|
function registerWorkCommands(root) {
|
|
7926
8054
|
const cmd = root.command("work").description("Work envelopes inside an ACCEPTED delegation: request / respond");
|
|
7927
8055
|
registerRequest(cmd);
|
|
7928
8056
|
registerRespond(cmd);
|
|
7929
8057
|
}
|
|
7930
|
-
var POST_COMMIT_ERROR_CODES3 = /* @__PURE__ */ new Set([
|
|
7931
|
-
"WORK_DELEGATION_NOT_FOUND",
|
|
7932
|
-
"WORK_DELEGATION_NOT_ACTIVE",
|
|
7933
|
-
"WORK_RELATIONSHIP_MISMATCH",
|
|
7934
|
-
"WORK_REQUESTER_NOT_OFFERER",
|
|
7935
|
-
"WORK_REQUEST_ALREADY_EXISTS",
|
|
7936
|
-
"WORK_REQUEST_NOT_FOUND",
|
|
7937
|
-
"WORK_RESPONDER_IS_CALLER",
|
|
7938
|
-
"WORK_INVALID_STATE",
|
|
7939
|
-
// The work handler's LOCKED gate emits
|
|
7940
|
-
// `DELEGATION_PENDING_LOCK` (409) when the delegation is funded but
|
|
7941
|
-
// the on-chain lock isn't confirmed yet (state
|
|
7942
|
-
// `pending_lock_finalization`). It fires from the body handler AFTER
|
|
7943
|
-
// the event row is committed — same lifecycle as
|
|
7944
|
-
// `WORK_DELEGATION_NOT_ACTIVE` — so the CLI must advance
|
|
7945
|
-
// `lastSenderSequence`, otherwise a retry once the lock confirms
|
|
7946
|
-
// reuses the consumed sequence and trips `ENV_SEQUENCE_BACKWARDS`.
|
|
7947
|
-
"DELEGATION_PENDING_LOCK"
|
|
7948
|
-
]);
|
|
7949
8058
|
function registerRequest(parent) {
|
|
7950
|
-
parent.command("request").description("Send a work_request to <recipient-did> under <delegation-id> (must be ACCEPTED).").argument("<recipient
|
|
8059
|
+
parent.command("request").description("Send a work_request to <recipient-did> under <delegation-id> (must be ACCEPTED).").argument("<recipient>", "Recipient \u2014 agent name (handle) or DID (the payee \u2014 the OTHER side of the delegation pair)").argument("<delegation-id>", "Parent delegation id (UUID, must be ACCEPTED)").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("--request-id <id>", "Override the auto-generated request id (must be unique within the delegation)").option(
|
|
7951
8060
|
"--params <json>",
|
|
7952
8061
|
"JSON object payload as a literal string. Defaults to {}. Mutually exclusive with --params-file. Brittle against shell quoting \u2014 prefer --params-file for non-trivial bodies."
|
|
7953
8062
|
).option(
|
|
7954
8063
|
"--params-file <path>",
|
|
7955
8064
|
"Read the JSON payload from a file. Mutually exclusive with --params. Use this for any payload large or quote-heavy enough that `--params '{...}'` would fight your shell."
|
|
7956
|
-
).option("--ttl <seconds>",
|
|
8065
|
+
).option("--ttl <seconds>", `Envelope TTL in seconds (max ${import_sdk31.MAX_ENVELOPE_TTL_SECONDS} = 24h)`, "3600").option("--verbose", "Print the full envelope before sending and the full server response. Mutually exclusive with --json.", false).option(
|
|
8066
|
+
"--json",
|
|
8067
|
+
'Machine-readable mode \u2014 emit a single JSON object on stdout ({ok, action:"work_request", requestId, delegationId, eventId, relationshipId, relationshipEventIndex, serverTimestamp, serverEventHash}). Prelude + reply hints move to stderr; on failure stderr carries `{code, message}`. Mutually exclusive with --verbose.',
|
|
8068
|
+
false
|
|
8069
|
+
).action(async (recipientDid, delegationId, opts) => {
|
|
7957
8070
|
await runRequest(recipientDid, delegationId, opts);
|
|
7958
8071
|
});
|
|
7959
8072
|
}
|
|
7960
8073
|
async function runRequest(recipientDid, delegationId, opts) {
|
|
7961
|
-
|
|
8074
|
+
if (opts.verbose && opts.json) {
|
|
8075
|
+
throw new Error(
|
|
8076
|
+
"work request: --verbose and --json are mutually exclusive. --json emits the structured server response; --verbose adds dumps that would break `--json | jq`."
|
|
8077
|
+
);
|
|
8078
|
+
}
|
|
8079
|
+
recipientDid = await resolveRecipient(opts.server, "work request", recipientDid, { json: opts.json });
|
|
7962
8080
|
delegationId = requireUuidNormalised3("work request", delegationId, "<delegation-id>");
|
|
7963
8081
|
const ttlSeconds = parseTtl5("work request", opts.ttl);
|
|
7964
8082
|
const params = parseParamsInput("work request", opts);
|
|
@@ -7971,27 +8089,51 @@ async function runRequest(recipientDid, delegationId, opts) {
|
|
|
7971
8089
|
params
|
|
7972
8090
|
};
|
|
7973
8091
|
const body = { type: "work_request", content };
|
|
7974
|
-
|
|
7975
|
-
|
|
7976
|
-
|
|
7977
|
-
|
|
7978
|
-
|
|
8092
|
+
progress(opts.json, import_chalk35.default.dim(`Server: ${api.serverUrl}`));
|
|
8093
|
+
progress(opts.json, import_chalk35.default.dim(`Sender: ${sender.did}`));
|
|
8094
|
+
progress(opts.json, import_chalk35.default.dim(`Recipient: ${recipientDid}`));
|
|
8095
|
+
progress(opts.json, import_chalk35.default.dim(`Delegation: ${delegationId}`));
|
|
8096
|
+
progress(opts.json, import_chalk35.default.dim(`Request id: ${requestId}`));
|
|
7979
8097
|
const result = await sendWorkEnvelope({ api, sender, recipientDid, body, ttlSeconds, verbose: opts.verbose, server: opts.server });
|
|
7980
|
-
|
|
7981
|
-
|
|
8098
|
+
if (opts.json) {
|
|
8099
|
+
jsonOut({
|
|
8100
|
+
ok: true,
|
|
8101
|
+
action: "work_request",
|
|
8102
|
+
requestId,
|
|
8103
|
+
delegationId,
|
|
8104
|
+
eventId: result.eventId,
|
|
8105
|
+
relationshipId: result.relationshipId,
|
|
8106
|
+
relationshipEventIndex: result.relationshipEventIndex,
|
|
8107
|
+
serverTimestamp: result.serverTimestamp,
|
|
8108
|
+
serverEventHash: result.serverEventHash,
|
|
8109
|
+
prevServerEventHash: result.prevServerEventHash ?? null
|
|
8110
|
+
});
|
|
8111
|
+
} else {
|
|
8112
|
+
printIngestResult3(result);
|
|
8113
|
+
console.log(import_chalk35.default.dim(`
|
|
7982
8114
|
The payee can reply with:`));
|
|
7983
|
-
|
|
7984
|
-
|
|
8115
|
+
console.log(import_chalk35.default.dim(` heyarp work respond ${result.relationshipId} ${delegationId} ${requestId} --output '<json>'`));
|
|
8116
|
+
console.log(import_chalk35.default.dim(` heyarp work respond ${result.relationshipId} ${delegationId} ${requestId} --error CODE:message`));
|
|
8117
|
+
}
|
|
7985
8118
|
}
|
|
7986
8119
|
function registerRespond(parent) {
|
|
7987
8120
|
parent.command("respond").description("Send a work_response under <relationship-id> for <delegation-id> / <request-id>. Payee-only.").argument("<relationship-id>", "Relationship UUID").argument("<delegation-id>", "Parent delegation id (UUID)").argument("<request-id>", "Request id supplied on the work_request").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("--output <json>", "Success payload as a JSON object literal. Mutually exclusive with --error and --output-file.").option(
|
|
7988
8121
|
"--output-file <path>",
|
|
7989
8122
|
"Read the success payload from a file. Mutually exclusive with --output and --error. Use this for any payload large or quote-heavy enough to fight your shell."
|
|
7990
|
-
).option("--error <code:message>", "Failure payload as `CODE:message`. Mutually exclusive with --output / --output-file.").option("--ttl <seconds>", "Envelope TTL in seconds", "3600").option("--verbose", "Print the full envelope before sending and the full server response", false).
|
|
8123
|
+
).option("--error <code:message>", "Failure payload as `CODE:message`. Mutually exclusive with --output / --output-file.").option("--ttl <seconds>", "Envelope TTL in seconds", "3600").option("--verbose", "Print the full envelope before sending and the full server response. Mutually exclusive with --json.", false).option(
|
|
8124
|
+
"--json",
|
|
8125
|
+
'Machine-readable mode \u2014 emit a single JSON object on stdout ({ok, action:"work_response", requestId, delegationId, eventId, relationshipId, relationshipEventIndex, serverTimestamp, serverEventHash}). Prelude moves to stderr; on failure stderr carries `{code, message}`. Mutually exclusive with --verbose.',
|
|
8126
|
+
false
|
|
8127
|
+
).action(async (relationshipId, delegationId, requestId, opts) => {
|
|
7991
8128
|
await runRespond(relationshipId, delegationId, requestId, opts);
|
|
7992
8129
|
});
|
|
7993
8130
|
}
|
|
7994
8131
|
async function runRespond(relationshipId, delegationId, requestId, opts) {
|
|
8132
|
+
if (opts.verbose && opts.json) {
|
|
8133
|
+
throw new Error(
|
|
8134
|
+
"work respond: --verbose and --json are mutually exclusive. --json emits the structured server response; --verbose adds dumps that would break `--json | jq`."
|
|
8135
|
+
);
|
|
8136
|
+
}
|
|
7995
8137
|
relationshipId = requireUuidNormalised3("work respond", relationshipId, "<relationship-id>");
|
|
7996
8138
|
delegationId = requireUuidNormalised3("work respond", delegationId, "<delegation-id>");
|
|
7997
8139
|
const ttlSeconds = parseTtl5("work respond", opts.ttl);
|
|
@@ -8006,39 +8148,54 @@ async function runRespond(relationshipId, delegationId, requestId, opts) {
|
|
|
8006
8148
|
...responsePayload
|
|
8007
8149
|
};
|
|
8008
8150
|
const body = { type: "work_response", content };
|
|
8009
|
-
|
|
8010
|
-
|
|
8011
|
-
|
|
8012
|
-
|
|
8013
|
-
|
|
8014
|
-
|
|
8015
|
-
|
|
8151
|
+
progress(opts.json, import_chalk35.default.dim(`Server: ${api.serverUrl}`));
|
|
8152
|
+
progress(opts.json, import_chalk35.default.dim(`Sender: ${sender.did}`));
|
|
8153
|
+
progress(opts.json, import_chalk35.default.dim(`Recipient: ${recipientDid}`));
|
|
8154
|
+
progress(opts.json, import_chalk35.default.dim(`Relationship: ${relationshipId}`));
|
|
8155
|
+
progress(opts.json, import_chalk35.default.dim(`Delegation: ${delegationId}`));
|
|
8156
|
+
progress(opts.json, import_chalk35.default.dim(`Request id: ${requestId}`));
|
|
8157
|
+
progress(opts.json, import_chalk35.default.dim(`Outcome: ${responsePayload.output ? "success" : "error"}`));
|
|
8016
8158
|
const result = await sendWorkEnvelope({ api, sender, recipientDid, body, ttlSeconds, verbose: opts.verbose, server: opts.server });
|
|
8017
|
-
|
|
8159
|
+
if (opts.json) {
|
|
8160
|
+
jsonOut({
|
|
8161
|
+
ok: true,
|
|
8162
|
+
action: "work_response",
|
|
8163
|
+
requestId,
|
|
8164
|
+
delegationId,
|
|
8165
|
+
eventId: result.eventId,
|
|
8166
|
+
relationshipId: result.relationshipId,
|
|
8167
|
+
relationshipEventIndex: result.relationshipEventIndex,
|
|
8168
|
+
serverTimestamp: result.serverTimestamp,
|
|
8169
|
+
serverEventHash: result.serverEventHash,
|
|
8170
|
+
prevServerEventHash: result.prevServerEventHash ?? null
|
|
8171
|
+
});
|
|
8172
|
+
} else {
|
|
8173
|
+
printIngestResult3(result);
|
|
8174
|
+
}
|
|
8018
8175
|
}
|
|
8019
8176
|
async function sendWorkEnvelope(args) {
|
|
8020
8177
|
const nextSequence = (args.sender.lastSenderSequence ?? 0) + 1;
|
|
8021
8178
|
const protectedBlock = {
|
|
8022
|
-
protocol_version:
|
|
8023
|
-
purpose:
|
|
8024
|
-
message_id: (0,
|
|
8179
|
+
protocol_version: import_sdk31.CURRENT_PROTOCOL_VERSION,
|
|
8180
|
+
purpose: import_sdk31.Purpose.ENVELOPE,
|
|
8181
|
+
message_id: (0, import_sdk31.uuidV4)(),
|
|
8025
8182
|
sender_did: args.sender.did,
|
|
8026
8183
|
recipient_did: args.recipientDid,
|
|
8027
8184
|
relationship_id: null,
|
|
8028
8185
|
sender_sequence: nextSequence,
|
|
8029
|
-
sender_nonce: (0,
|
|
8030
|
-
timestamp: (0,
|
|
8031
|
-
expires_at: (0,
|
|
8186
|
+
sender_nonce: (0, import_sdk31.senderNonce)(),
|
|
8187
|
+
timestamp: (0, import_sdk31.rfc3339)(),
|
|
8188
|
+
expires_at: (0, import_sdk31.expiresAt)(args.ttlSeconds),
|
|
8032
8189
|
delivery_id: null
|
|
8033
8190
|
};
|
|
8034
8191
|
const signer = makeSigner(args.sender);
|
|
8035
|
-
const envelope = (0,
|
|
8192
|
+
const envelope = (0, import_sdk31.signEnvelope)({
|
|
8036
8193
|
protected: protectedBlock,
|
|
8037
8194
|
body: args.body,
|
|
8038
8195
|
identitySecretKey: signer.identitySecretKey
|
|
8039
8196
|
});
|
|
8040
8197
|
if (args.verbose) {
|
|
8041
|
-
console.log(
|
|
8198
|
+
console.log(import_chalk35.default.bold("\nEnvelope (pre-send):"));
|
|
8042
8199
|
console.log(formatJson(envelope));
|
|
8043
8200
|
}
|
|
8044
8201
|
try {
|
|
@@ -8046,7 +8203,7 @@ async function sendWorkEnvelope(args) {
|
|
|
8046
8203
|
updateAgentLocal(args.server, args.sender.did, { lastSenderSequence: nextSequence });
|
|
8047
8204
|
return result;
|
|
8048
8205
|
} catch (err) {
|
|
8049
|
-
if (err instanceof ApiError &&
|
|
8206
|
+
if (err instanceof ApiError && (0, import_sdk31.isPostCommitErrorCode)(err.payload.code)) {
|
|
8050
8207
|
updateAgentLocal(args.server, args.sender.did, { lastSenderSequence: nextSequence });
|
|
8051
8208
|
}
|
|
8052
8209
|
throw err;
|
|
@@ -8058,7 +8215,7 @@ async function resolveResponseRecipient(cmdName, api, signer, args) {
|
|
|
8058
8215
|
const page = await api.listWorkLogs(args.relationshipId, signer, { delegationId: args.delegationId, limit: 100, after });
|
|
8059
8216
|
const row = page.find((w) => w.requestId === args.requestId);
|
|
8060
8217
|
if (row) {
|
|
8061
|
-
if (row.state !==
|
|
8218
|
+
if (row.state !== import_sdk31.WorkLogStates.REQUESTED) {
|
|
8062
8219
|
throw new Error(
|
|
8063
8220
|
`${cmdName}: work_request ${args.requestId} for delegation ${args.delegationId} is already in state '${row.state}' \u2014 only requests in state 'requested' can be responded to.`
|
|
8064
8221
|
);
|
|
@@ -8078,12 +8235,12 @@ async function resolveResponseRecipient(cmdName, api, signer, args) {
|
|
|
8078
8235
|
);
|
|
8079
8236
|
}
|
|
8080
8237
|
function printIngestResult3(result) {
|
|
8081
|
-
console.log(
|
|
8082
|
-
console.log(`${
|
|
8083
|
-
console.log(`${
|
|
8084
|
-
console.log(`${
|
|
8085
|
-
console.log(`${
|
|
8086
|
-
console.log(`${
|
|
8238
|
+
console.log(import_chalk35.default.green("\nDelivered."));
|
|
8239
|
+
console.log(`${import_chalk35.default.bold("Event id")}: ${import_chalk35.default.cyan(result.eventId)}`);
|
|
8240
|
+
console.log(`${import_chalk35.default.bold("Relationship id")}: ${import_chalk35.default.cyan(result.relationshipId)}`);
|
|
8241
|
+
console.log(`${import_chalk35.default.bold("Chain index")}: ${import_chalk35.default.cyan(String(result.relationshipEventIndex))}`);
|
|
8242
|
+
console.log(`${import_chalk35.default.bold("Server timestamp")}: ${import_chalk35.default.cyan(result.serverTimestamp)}`);
|
|
8243
|
+
console.log(`${import_chalk35.default.bold("Server event hash")}: ${import_chalk35.default.cyan(result.serverEventHash)}`);
|
|
8087
8244
|
}
|
|
8088
8245
|
function parseJsonObject(cmdName, flagName, raw) {
|
|
8089
8246
|
let parsed;
|
|
@@ -8175,7 +8332,7 @@ function parseTtl5(cmdName, raw) {
|
|
|
8175
8332
|
}
|
|
8176
8333
|
function parseRequestId(cmdName, raw) {
|
|
8177
8334
|
if (raw === void 0 || raw === "") {
|
|
8178
|
-
return (0,
|
|
8335
|
+
return (0, import_sdk31.uuidV4)();
|
|
8179
8336
|
}
|
|
8180
8337
|
if (raw.length === 0) {
|
|
8181
8338
|
throw new Error(`${cmdName}: --request-id must be a non-empty string`);
|
|
@@ -8189,16 +8346,12 @@ function requireUuidNormalised3(cmdName, raw, label) {
|
|
|
8189
8346
|
function requireUuid4(cmdName, raw, label) {
|
|
8190
8347
|
requireUuid(cmdName, raw, label);
|
|
8191
8348
|
}
|
|
8192
|
-
function requireDid3(cmdName, did, label) {
|
|
8193
|
-
if (typeof did !== "string" || !did.startsWith("did:arp:") || did.length <= "did:arp:".length) {
|
|
8194
|
-
throw new Error(`${cmdName}: ${label} must look like 'did:arp:...' (got '${did}')`);
|
|
8195
|
-
}
|
|
8196
|
-
}
|
|
8197
8349
|
|
|
8198
8350
|
// src/commands/work-list.ts
|
|
8199
|
-
var
|
|
8351
|
+
var import_sdk32 = require("@heyanon-arp/sdk");
|
|
8352
|
+
var import_chalk36 = __toESM(require("chalk"));
|
|
8200
8353
|
init_api();
|
|
8201
|
-
var ALLOWED_STATES3 =
|
|
8354
|
+
var ALLOWED_STATES3 = new Set(import_sdk32.WORK_LOG_STATES);
|
|
8202
8355
|
function registerWorkListCommand(root) {
|
|
8203
8356
|
root.command("work-list").description("List work-log rows for a relationship (one row per (delegationId, requestId), oldest-first)").argument("<relationship-id>", "Relationship UUID").option("--server <url>", "Override ARP server base URL").option("--state <s>", "Filter by exact state (requested|responded)").option("--delegation-id <uuid>", "Narrow to work-logs operating under a specific delegation id").option("--after <id>", "Cursor: pass the previous page's last `id` to fetch the next page").option("--limit <n>", "Max rows to return (1..100)", "20").option("--from-did <did>", "Signer DID \u2014 required only if multiple agents are registered against this server").option(
|
|
8204
8357
|
"--verbose",
|
|
@@ -8223,9 +8376,9 @@ async function runWorkList(relationshipId, opts) {
|
|
|
8223
8376
|
const api = new ArpApiClient(opts.server);
|
|
8224
8377
|
const sender = resolveSenderAgent("work-list", opts.server, opts.fromDid);
|
|
8225
8378
|
if (!opts.json) {
|
|
8226
|
-
console.log(
|
|
8227
|
-
console.log(
|
|
8228
|
-
console.log(
|
|
8379
|
+
console.log(import_chalk36.default.dim(`Server: ${api.serverUrl}`));
|
|
8380
|
+
console.log(import_chalk36.default.dim(`Signer: ${sender.did}`));
|
|
8381
|
+
console.log(import_chalk36.default.dim(`Relationship: ${relationshipId}`));
|
|
8229
8382
|
}
|
|
8230
8383
|
const query = { limit };
|
|
8231
8384
|
if (state) query.state = state;
|
|
@@ -8238,7 +8391,7 @@ async function runWorkList(relationshipId, opts) {
|
|
|
8238
8391
|
return;
|
|
8239
8392
|
}
|
|
8240
8393
|
if (rows.length === 0) {
|
|
8241
|
-
console.log(
|
|
8394
|
+
console.log(import_chalk36.default.dim("\n(no work-logs for this relationship)"));
|
|
8242
8395
|
return;
|
|
8243
8396
|
}
|
|
8244
8397
|
console.log("");
|
|
@@ -8255,36 +8408,36 @@ async function runWorkList(relationshipId, opts) {
|
|
|
8255
8408
|
}));
|
|
8256
8409
|
}
|
|
8257
8410
|
const lastId = rows[rows.length - 1].id;
|
|
8258
|
-
console.log(
|
|
8411
|
+
console.log(import_chalk36.default.dim(`
|
|
8259
8412
|
${rows.length} work-log row(s). Paginate with --after ${lastId}.`));
|
|
8260
8413
|
}
|
|
8261
8414
|
function formatWorkLogLine(w, selfDid, opts = {}) {
|
|
8262
8415
|
const delegationPart = opts.fullIds ? w.delegationId : idHead3(w.delegationId);
|
|
8263
8416
|
const requestPart = opts.fullIds ? w.requestId : truncate3(w.requestId, 16);
|
|
8264
|
-
const id =
|
|
8417
|
+
const id = import_chalk36.default.bold(`${delegationPart}/${requestPart}`);
|
|
8265
8418
|
const state = colorState2(w.state).padEnd(stateColumnWidth2());
|
|
8266
8419
|
const peerCallerHead = opts.fullIds ? w.callerDid : didHead5(w.callerDid);
|
|
8267
8420
|
const peerPayeeHead = opts.fullIds ? w.payeeDid : didHead5(w.payeeDid);
|
|
8268
|
-
const direction = w.callerDid === selfDid ? `${
|
|
8421
|
+
const direction = w.callerDid === selfDid ? `${import_chalk36.default.bold("me")} \u2192 ${import_chalk36.default.dim(peerPayeeHead)}` : `${import_chalk36.default.dim(peerCallerHead)} \u2192 ${import_chalk36.default.bold("me")}`;
|
|
8269
8422
|
const outcome = formatOutcome(w);
|
|
8270
8423
|
return `${id} ${state} ${direction} ${outcome}`;
|
|
8271
8424
|
}
|
|
8272
8425
|
function colorState2(s) {
|
|
8273
8426
|
switch (s) {
|
|
8274
|
-
case
|
|
8275
|
-
return
|
|
8276
|
-
case
|
|
8277
|
-
return
|
|
8427
|
+
case import_sdk32.WorkLogStates.REQUESTED:
|
|
8428
|
+
return import_chalk36.default.yellow("requested");
|
|
8429
|
+
case import_sdk32.WorkLogStates.RESPONDED:
|
|
8430
|
+
return import_chalk36.default.green("responded");
|
|
8278
8431
|
}
|
|
8279
8432
|
}
|
|
8280
8433
|
function stateColumnWidth2() {
|
|
8281
8434
|
return 9;
|
|
8282
8435
|
}
|
|
8283
8436
|
function formatOutcome(w) {
|
|
8284
|
-
if (w.state ===
|
|
8285
|
-
if (w.responseError) return
|
|
8286
|
-
if (w.responseOutput) return
|
|
8287
|
-
return
|
|
8437
|
+
if (w.state === import_sdk32.WorkLogStates.REQUESTED) return import_chalk36.default.dim("(in flight)");
|
|
8438
|
+
if (w.responseError) return import_chalk36.default.red(`error ${w.responseError.code}: ${truncate3(w.responseError.message, 32)}`);
|
|
8439
|
+
if (w.responseOutput) return import_chalk36.default.cyan("ok");
|
|
8440
|
+
return import_chalk36.default.dim("(empty response)");
|
|
8288
8441
|
}
|
|
8289
8442
|
function idHead3(id) {
|
|
8290
8443
|
if (id.length <= 12) return id;
|
|
@@ -8314,6 +8467,43 @@ function parseLimit7(raw) {
|
|
|
8314
8467
|
return n;
|
|
8315
8468
|
}
|
|
8316
8469
|
|
|
8470
|
+
// src/option-hint.ts
|
|
8471
|
+
function unknownOptionHint(program, err) {
|
|
8472
|
+
try {
|
|
8473
|
+
if (err.code !== "commander.unknownOption" || !err.message) return null;
|
|
8474
|
+
const m = /unknown option '([^']+)'/.exec(err.message);
|
|
8475
|
+
if (!m) return null;
|
|
8476
|
+
const raw = m[1];
|
|
8477
|
+
const flag = raw.split("=")[0];
|
|
8478
|
+
const owners = [];
|
|
8479
|
+
const walk = (cmd, path) => {
|
|
8480
|
+
for (const opt of cmd.options) {
|
|
8481
|
+
if (opt.long === flag || opt.short === flag) owners.push(path.join(" "));
|
|
8482
|
+
}
|
|
8483
|
+
for (const sub of cmd.commands) walk(sub, [...path, sub.name()]);
|
|
8484
|
+
};
|
|
8485
|
+
for (const sub of program.commands) walk(sub, [sub.name()]);
|
|
8486
|
+
if (owners.length === 0) return null;
|
|
8487
|
+
owners.sort((a, b) => a.split(" ").length - b.split(" ").length);
|
|
8488
|
+
const argv = process.argv.slice(2);
|
|
8489
|
+
const commandNames = /* @__PURE__ */ new Set();
|
|
8490
|
+
for (const c of program.commands) {
|
|
8491
|
+
commandNames.add(c.name());
|
|
8492
|
+
for (const a of c.aliases()) commandNames.add(a);
|
|
8493
|
+
}
|
|
8494
|
+
const flagIdx = argv.findIndex((t) => t === raw || t.split("=")[0] === flag);
|
|
8495
|
+
const cmdIdx = argv.findIndex((t) => commandNames.has(t));
|
|
8496
|
+
const placedBeforeCommand = cmdIdx === -1 || flagIdx !== -1 && flagIdx < cmdIdx;
|
|
8497
|
+
if (placedBeforeCommand) {
|
|
8498
|
+
return `'${flag}' is a command option, not a global one \u2014 put it AFTER the command (e.g. \`heyarp ${owners[0]} ${flag} \u2026\`), not before it.`;
|
|
8499
|
+
}
|
|
8500
|
+
const list = owners.slice(0, 4).join(", ") + (owners.length > 4 ? ", \u2026" : "");
|
|
8501
|
+
return `'${flag}' isn't valid for that command \u2014 it's an option of: ${list}.`;
|
|
8502
|
+
} catch {
|
|
8503
|
+
return null;
|
|
8504
|
+
}
|
|
8505
|
+
}
|
|
8506
|
+
|
|
8317
8507
|
// src/cli.ts
|
|
8318
8508
|
async function checkForUpdates() {
|
|
8319
8509
|
if (package_default.private === true) return;
|
|
@@ -8328,7 +8518,7 @@ async function checkForUpdates() {
|
|
|
8328
8518
|
async function main() {
|
|
8329
8519
|
void checkForUpdates();
|
|
8330
8520
|
const program = new import_commander.Command();
|
|
8331
|
-
program.name("heyarp").description("ARP \u2014 Agent Relationship Protocol CLI (talks to apps/arp-server)").version(package_default.version).option("--trace", "Surface stack traces and error details on failure.", false);
|
|
8521
|
+
program.name("heyarp").description("ARP \u2014 Agent Relationship Protocol CLI (talks to apps/arp-server)").version(package_default.version).usage("[global-options] <command> [options]").option("--trace", "Surface stack traces and error details on failure.", false);
|
|
8332
8522
|
program.exitOverride();
|
|
8333
8523
|
program.configureOutput({
|
|
8334
8524
|
writeErr: (str) => {
|
|
@@ -8336,6 +8526,7 @@ async function main() {
|
|
|
8336
8526
|
process.stderr.write(str);
|
|
8337
8527
|
}
|
|
8338
8528
|
});
|
|
8529
|
+
program.addHelpText("after", () => optionPlacementHelpNote());
|
|
8339
8530
|
program.addHelpText("after", () => onboardingHelpFooter());
|
|
8340
8531
|
registerConfigCommand(program);
|
|
8341
8532
|
registerGuideCommand(program);
|
|
@@ -8353,6 +8544,8 @@ async function main() {
|
|
|
8353
8544
|
registerAssetsCommand(program);
|
|
8354
8545
|
registerEscrowCommands(program);
|
|
8355
8546
|
registerWhoamiCommand(program);
|
|
8547
|
+
registerWhoisCommand(program);
|
|
8548
|
+
registerNameCommand(program);
|
|
8356
8549
|
registerLifecycleCommands(program);
|
|
8357
8550
|
registerSendHandshakeCommand(program);
|
|
8358
8551
|
registerSendHandshakeResponseCommand(program);
|
|
@@ -8383,10 +8576,13 @@ async function main() {
|
|
|
8383
8576
|
const json = process.argv.includes("--json");
|
|
8384
8577
|
const verbose = process.argv.includes("--trace");
|
|
8385
8578
|
const exitCode = typeof cerr.exitCode === "number" && cerr.exitCode !== 0 ? cerr.exitCode : 1;
|
|
8579
|
+
const hint = unknownOptionHint(program, cerr);
|
|
8386
8580
|
if (isCommanderError && !json) {
|
|
8581
|
+
if (hint) process.stderr.write(`hint: ${hint}
|
|
8582
|
+
`);
|
|
8387
8583
|
process.exit(exitCode);
|
|
8388
8584
|
}
|
|
8389
|
-
emitError(err, { json, verbose });
|
|
8585
|
+
emitError(err, { json, verbose, hint: hint ?? void 0 });
|
|
8390
8586
|
process.exit(exitCode);
|
|
8391
8587
|
}
|
|
8392
8588
|
}
|