@heyanon-arp/cli 0.0.16 → 0.0.17
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 +480 -418
- package/dist/cli.js.map +1 -1
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -722,7 +722,7 @@ var import_simple_update_notifier = __toESM(require("simple-update-notifier"));
|
|
|
722
722
|
// package.json
|
|
723
723
|
var package_default = {
|
|
724
724
|
name: "@heyanon-arp/cli",
|
|
725
|
-
version: "0.0.
|
|
725
|
+
version: "0.0.17",
|
|
726
726
|
description: "Command-line client for the Agent Relationship Protocol \u2014 register agents, sign envelopes, run escrowed work cycles on Solana.",
|
|
727
727
|
license: "MIT",
|
|
728
728
|
keywords: ["arp", "agent-relationship-protocol", "did", "solana", "escrow", "ed25519", "agents", "a2a", "cli"],
|
|
@@ -804,6 +804,14 @@ function onboardingHelpFooter() {
|
|
|
804
804
|
`${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
805
|
].join("\n");
|
|
806
806
|
}
|
|
807
|
+
function optionPlacementHelpNote() {
|
|
808
|
+
return [
|
|
809
|
+
"",
|
|
810
|
+
`${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).`,
|
|
811
|
+
`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:`,
|
|
812
|
+
` ${import_chalk.default.cyan("heyarp <command> [options]")} ${import_chalk.default.dim("e.g. heyarp relationships --json --from-did did:arp:\u2026")}`
|
|
813
|
+
].join("\n");
|
|
814
|
+
}
|
|
807
815
|
function toCliErrorJson(err, includeStack = false) {
|
|
808
816
|
const { ApiError: ApiError2 } = (init_api(), __toCommonJS(api_exports));
|
|
809
817
|
if (err instanceof ApiError2) {
|
|
@@ -821,7 +829,9 @@ function toCliErrorJson(err, includeStack = false) {
|
|
|
821
829
|
}
|
|
822
830
|
function emitError(err, opts) {
|
|
823
831
|
if (opts.json) {
|
|
824
|
-
|
|
832
|
+
const obj = toCliErrorJson(err, opts.verbose);
|
|
833
|
+
if (opts.hint) obj.hint = opts.hint;
|
|
834
|
+
console.error(JSON.stringify(obj));
|
|
825
835
|
return;
|
|
826
836
|
}
|
|
827
837
|
const { ApiError: ApiError2 } = (init_api(), __toCommonJS(api_exports));
|
|
@@ -830,6 +840,7 @@ function emitError(err, opts) {
|
|
|
830
840
|
} else {
|
|
831
841
|
console.error(formatGenericError(err, opts.verbose));
|
|
832
842
|
}
|
|
843
|
+
if (opts.hint) console.error(`${import_chalk.default.yellow("hint")}: ${opts.hint}`);
|
|
833
844
|
}
|
|
834
845
|
function emitActionError(err, command) {
|
|
835
846
|
let root = command;
|
|
@@ -1162,19 +1173,28 @@ function listAgents() {
|
|
|
1162
1173
|
var import_chalk2 = __toESM(require("chalk"));
|
|
1163
1174
|
init_api();
|
|
1164
1175
|
function registerLifecycleCommands(root) {
|
|
1165
|
-
root.command("update").description("Update an agent profile (name / description / tags). At least one flag is required.").argument("
|
|
1176
|
+
root.command("update").description("Update an agent profile (name / description / tags). At least one flag is required.").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("--name <s>", "New display name").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
1177
|
async (did, opts) => {
|
|
1178
|
+
if (did !== void 0 && opts.fromDid !== void 0 && did !== opts.fromDid) {
|
|
1179
|
+
throw new Error(`update: positional <did> (${did}) and --from-did (${opts.fromDid}) disagree \u2014 pass only one`);
|
|
1180
|
+
}
|
|
1181
|
+
const explicitDid = did ?? opts.fromDid;
|
|
1182
|
+
const targetDid = (explicitDid !== void 0 ? loadAgentOrThrow(opts.server, explicitDid) : resolveSenderAgent("update", opts.server, void 0)).did;
|
|
1167
1183
|
const body = buildUpdateBody(opts);
|
|
1168
1184
|
if (Object.keys(body).length === 0) {
|
|
1169
1185
|
throw new Error("update: pass at least one of --name / --description / --tag / --clear-tags");
|
|
1170
1186
|
}
|
|
1171
|
-
const agent = await actSigned(
|
|
1172
|
-
updateAgentLocal(opts.server,
|
|
1187
|
+
const agent = await actSigned(targetDid, opts.server, opts.json, (api, signer) => api.updateAgent(targetDid, body, signer));
|
|
1188
|
+
updateAgentLocal(opts.server, targetDid, {
|
|
1173
1189
|
name: agent.name,
|
|
1174
1190
|
description: agent.description,
|
|
1175
1191
|
tags: agent.tags
|
|
1176
1192
|
});
|
|
1177
|
-
|
|
1193
|
+
if (opts.json) {
|
|
1194
|
+
jsonOut(agent);
|
|
1195
|
+
} else {
|
|
1196
|
+
printAgent("Updated", agent);
|
|
1197
|
+
}
|
|
1178
1198
|
}
|
|
1179
1199
|
);
|
|
1180
1200
|
}
|
|
@@ -1195,11 +1215,11 @@ function buildUpdateBody(opts) {
|
|
|
1195
1215
|
}
|
|
1196
1216
|
return body;
|
|
1197
1217
|
}
|
|
1198
|
-
async function actSigned(did, serverOverride, act) {
|
|
1218
|
+
async function actSigned(did, serverOverride, json, act) {
|
|
1199
1219
|
const local = loadAgentOrThrow(serverOverride, did);
|
|
1200
1220
|
const api = new ArpApiClient(serverOverride);
|
|
1201
|
-
|
|
1202
|
-
|
|
1221
|
+
progress(json, import_chalk2.default.dim(`Server: ${api.serverUrl}`));
|
|
1222
|
+
progress(json, import_chalk2.default.dim(`Signer: ${local.did}`));
|
|
1203
1223
|
const signer = makeSigner(local);
|
|
1204
1224
|
return act(api, signer);
|
|
1205
1225
|
}
|
|
@@ -1245,10 +1265,10 @@ function registerAgentsCommand(root) {
|
|
|
1245
1265
|
}
|
|
1246
1266
|
async function runAgents(opts) {
|
|
1247
1267
|
const limit = parseLimit(opts.limit);
|
|
1248
|
-
if (opts.sort && opts.sort !==
|
|
1268
|
+
if (opts.sort && opts.sort !== import_sdk2.DiscoverySorts.REPUTATION && opts.sort !== import_sdk2.DiscoverySorts.RECENT && opts.sort !== import_sdk2.DiscoverySorts.CREATED) {
|
|
1249
1269
|
throw new Error(`agents: --sort must be 'reputation', 'recent', or 'created' (got '${opts.sort}')`);
|
|
1250
1270
|
}
|
|
1251
|
-
const sort = opts.sort ===
|
|
1271
|
+
const sort = opts.sort === import_sdk2.DiscoverySorts.RECENT ? import_sdk2.DiscoverySorts.RECENT : opts.sort === import_sdk2.DiscoverySorts.CREATED ? import_sdk2.DiscoverySorts.CREATED : import_sdk2.DiscoverySorts.REPUTATION;
|
|
1252
1272
|
const api = new ArpApiClient(opts.server);
|
|
1253
1273
|
progress(opts.json, import_chalk3.default.dim(`Server: ${api.serverUrl}`));
|
|
1254
1274
|
const query = { limit, sort };
|
|
@@ -1257,7 +1277,7 @@ async function runAgents(opts) {
|
|
|
1257
1277
|
if (opts.accountId) query.accountId = opts.accountId;
|
|
1258
1278
|
if (opts.accepts) query.accepts = resolveAcceptsAsset(opts.accepts);
|
|
1259
1279
|
if (opts.online) query.online = true;
|
|
1260
|
-
if (sort ===
|
|
1280
|
+
if (sort === import_sdk2.DiscoverySorts.CREATED) {
|
|
1261
1281
|
if (opts.after) query.after = opts.after;
|
|
1262
1282
|
} else {
|
|
1263
1283
|
query.page = parsePage(opts.page);
|
|
@@ -1296,10 +1316,10 @@ ${rule}`);
|
|
|
1296
1316
|
`);
|
|
1297
1317
|
}
|
|
1298
1318
|
if (pagination.hasMore) {
|
|
1299
|
-
if (sort ===
|
|
1319
|
+
if (sort === import_sdk2.DiscoverySorts.CREATED && pagination.nextCursor) {
|
|
1300
1320
|
console.log(import_chalk3.default.dim(`
|
|
1301
1321
|
Next page: re-run with --after ${pagination.nextCursor}`));
|
|
1302
|
-
} else if (sort !==
|
|
1322
|
+
} else if (sort !== import_sdk2.DiscoverySorts.CREATED) {
|
|
1303
1323
|
console.log(import_chalk3.default.dim(`
|
|
1304
1324
|
Next page: re-run with --page ${parsePage(opts.page) + 1}`));
|
|
1305
1325
|
}
|
|
@@ -1495,13 +1515,14 @@ function registerAssetsCommand(root) {
|
|
|
1495
1515
|
}
|
|
1496
1516
|
|
|
1497
1517
|
// src/commands/block.ts
|
|
1518
|
+
var import_sdk4 = require("@heyanon-arp/sdk");
|
|
1498
1519
|
var import_chalk5 = __toESM(require("chalk"));
|
|
1499
1520
|
init_api();
|
|
1500
1521
|
function resolveSigningAgent(opts) {
|
|
1501
1522
|
return opts.fromDid !== void 0 ? loadAgentOrThrow(opts.server, opts.fromDid) : resolveSenderAgent("block", opts.server, void 0);
|
|
1502
1523
|
}
|
|
1503
1524
|
function formatBlockRow(b) {
|
|
1504
|
-
const scope = b.scope ===
|
|
1525
|
+
const scope = b.scope === import_sdk4.InboxBlockScopes.ACCOUNT ? import_chalk5.default.yellow("account") : import_chalk5.default.cyan("did");
|
|
1505
1526
|
const reason = b.reason ? import_chalk5.default.dim(` \u2014 ${b.reason}`) : "";
|
|
1506
1527
|
return `${scope.padEnd(7)} ${b.did}${reason} ${import_chalk5.default.dim(b.blockedAt)}`;
|
|
1507
1528
|
}
|
|
@@ -1526,7 +1547,7 @@ async function runAdd(did, opts) {
|
|
|
1526
1547
|
jsonOut(result);
|
|
1527
1548
|
return;
|
|
1528
1549
|
}
|
|
1529
|
-
const what = result.scope ===
|
|
1550
|
+
const what = result.scope === import_sdk4.InboxBlockScopes.ACCOUNT ? `the owner account of ${did} (all its agents)` : did;
|
|
1530
1551
|
console.log(import_chalk5.default.green(`\u2713 Blocked ${what}.`));
|
|
1531
1552
|
}
|
|
1532
1553
|
async function runRemove(did, opts) {
|
|
@@ -1642,14 +1663,15 @@ function unknownKey(key) {
|
|
|
1642
1663
|
|
|
1643
1664
|
// src/commands/delegation.ts
|
|
1644
1665
|
var import_node_fs4 = require("fs");
|
|
1645
|
-
var
|
|
1666
|
+
var import_sdk10 = require("@heyanon-arp/sdk");
|
|
1646
1667
|
var import_chalk8 = __toESM(require("chalk"));
|
|
1647
1668
|
init_api();
|
|
1648
1669
|
|
|
1649
1670
|
// src/id-format.ts
|
|
1671
|
+
var import_sdk5 = require("@heyanon-arp/sdk");
|
|
1650
1672
|
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
1673
|
var OBJECT_ID_24_HEX_RE = /^[0-9a-f]{24}$/;
|
|
1652
|
-
var SHA256_PREFIX_RE =
|
|
1674
|
+
var SHA256_PREFIX_RE = import_sdk5.SHA256_HEX_RE;
|
|
1653
1675
|
var UUID_NO_DASHES_RE = /^[a-fA-F0-9]{32}$/;
|
|
1654
1676
|
function describeNonUuidShape(raw) {
|
|
1655
1677
|
if (raw === "") return "empty string";
|
|
@@ -1681,7 +1703,7 @@ function requireUuid(cmdName, raw, label) {
|
|
|
1681
1703
|
}
|
|
1682
1704
|
|
|
1683
1705
|
// src/commands/status.ts
|
|
1684
|
-
var
|
|
1706
|
+
var import_sdk6 = require("@heyanon-arp/sdk");
|
|
1685
1707
|
var import_chalk7 = __toESM(require("chalk"));
|
|
1686
1708
|
init_api();
|
|
1687
1709
|
var UNTIL_PHASES = [
|
|
@@ -1782,13 +1804,13 @@ async function awaitFsmTransitionAfterAction(input) {
|
|
|
1782
1804
|
}
|
|
1783
1805
|
}
|
|
1784
1806
|
async function runWaitLoop(opts) {
|
|
1785
|
-
const isTerminal = (s) => s.cycleComplete || s.relationshipState ===
|
|
1807
|
+
const isTerminal = (s) => s.cycleComplete || s.relationshipState === import_sdk6.RelationshipStates.CLOSED || s.relationshipState === "not_found";
|
|
1786
1808
|
const isActionable = (s) => {
|
|
1787
1809
|
if (s.nextActionOwner === "me") {
|
|
1788
1810
|
if (s.relationshipState === "unknown") return false;
|
|
1789
1811
|
return true;
|
|
1790
1812
|
}
|
|
1791
|
-
if (s.nextActionOwner === "either" && s.relationshipState ===
|
|
1813
|
+
if (s.nextActionOwner === "either" && s.relationshipState === import_sdk6.RelationshipStates.ACTIVE) {
|
|
1792
1814
|
return true;
|
|
1793
1815
|
}
|
|
1794
1816
|
return false;
|
|
@@ -1924,41 +1946,41 @@ function parseUntilPhase(raw) {
|
|
|
1924
1946
|
function isPhaseTerminallyUnreachable(phase, s) {
|
|
1925
1947
|
if (untilPhaseMatched(phase, s)) return false;
|
|
1926
1948
|
if (s.relationshipState === "not_found") return true;
|
|
1927
|
-
if (s.relationshipState ===
|
|
1949
|
+
if (s.relationshipState === import_sdk6.RelationshipStates.CLOSED && phase !== "relationship.closed") return true;
|
|
1928
1950
|
return false;
|
|
1929
1951
|
}
|
|
1930
1952
|
function untilPhaseMatched(phase, s) {
|
|
1931
1953
|
switch (phase) {
|
|
1932
1954
|
case "delegation.offered":
|
|
1933
|
-
return s.latestDelegation?.state ===
|
|
1955
|
+
return s.latestDelegation?.state === import_sdk6.DelegationStates.OFFERED;
|
|
1934
1956
|
case "delegation.accepted":
|
|
1935
|
-
return s.latestDelegation?.state ===
|
|
1957
|
+
return s.latestDelegation?.state === import_sdk6.DelegationStates.ACCEPTED;
|
|
1936
1958
|
case "delegation.locked":
|
|
1937
|
-
return s.latestDelegation?.state ===
|
|
1959
|
+
return s.latestDelegation?.state === import_sdk6.DelegationStates.LOCKED;
|
|
1938
1960
|
case "delegation.disputing":
|
|
1939
|
-
return s.latestDelegation?.state ===
|
|
1961
|
+
return s.latestDelegation?.state === import_sdk6.DelegationStates.DISPUTING;
|
|
1940
1962
|
case "delegation.canceled":
|
|
1941
|
-
return s.latestDelegation?.state ===
|
|
1963
|
+
return s.latestDelegation?.state === import_sdk6.DelegationStates.CANCELED;
|
|
1942
1964
|
case "delegation.declined":
|
|
1943
|
-
return s.latestDelegation?.state ===
|
|
1965
|
+
return s.latestDelegation?.state === import_sdk6.DelegationStates.DECLINED;
|
|
1944
1966
|
case "work.requested":
|
|
1945
|
-
return s.latestWorkLog?.state ===
|
|
1967
|
+
return s.latestWorkLog?.state === import_sdk6.WorkLogStates.REQUESTED;
|
|
1946
1968
|
case "work.responded":
|
|
1947
|
-
return s.latestWorkLog?.state ===
|
|
1969
|
+
return s.latestWorkLog?.state === import_sdk6.WorkLogStates.RESPONDED;
|
|
1948
1970
|
case "receipt.proposed":
|
|
1949
1971
|
return s.latestReceipt != null;
|
|
1950
1972
|
case "relationship.pending":
|
|
1951
|
-
return s.relationshipState ===
|
|
1973
|
+
return s.relationshipState === import_sdk6.RelationshipStates.PENDING;
|
|
1952
1974
|
case "relationship.active":
|
|
1953
|
-
return s.relationshipState ===
|
|
1975
|
+
return s.relationshipState === import_sdk6.RelationshipStates.ACTIVE;
|
|
1954
1976
|
case "relationship.paused":
|
|
1955
|
-
return s.relationshipState ===
|
|
1977
|
+
return s.relationshipState === import_sdk6.RelationshipStates.PAUSED;
|
|
1956
1978
|
case "relationship.closed":
|
|
1957
|
-
return s.relationshipState ===
|
|
1979
|
+
return s.relationshipState === import_sdk6.RelationshipStates.CLOSED;
|
|
1958
1980
|
case "cycle.complete":
|
|
1959
1981
|
return s.cycleComplete;
|
|
1960
1982
|
case "cycle.released":
|
|
1961
|
-
return s.latestDelegation?.state ===
|
|
1983
|
+
return s.latestDelegation?.state === import_sdk6.DelegationStates.COMPLETED;
|
|
1962
1984
|
}
|
|
1963
1985
|
}
|
|
1964
1986
|
function parseWaitInterval(raw) {
|
|
@@ -2009,7 +2031,7 @@ async function composeStatus(api, signerDid, relationshipId, signer) {
|
|
|
2009
2031
|
const relationship = relationships.find((r) => r.relationshipId === relationshipId);
|
|
2010
2032
|
const counterpartyDid = relationship ? relationship.pairDidA === signerDid ? relationship.pairDidB : relationship.pairDidA : inferCounterpartyFromEntities(signerDid, allDelegations);
|
|
2011
2033
|
const delegations = allDelegations;
|
|
2012
|
-
const latestDelegation = pickLatestLive(delegations, [
|
|
2034
|
+
const latestDelegation = pickLatestLive(delegations, [...import_sdk6.DELEGATION_ACTIVE_STATES]);
|
|
2013
2035
|
const [workLogs, receipts] = await Promise.all([
|
|
2014
2036
|
latestDelegation ? fetchAllPages(
|
|
2015
2037
|
(after) => api.listWorkLogs(relationshipId, signer, { limit: 100, delegationId: latestDelegation.delegationId, ...after ? { after } : {} })
|
|
@@ -2073,8 +2095,8 @@ function findReceiptForWorkLog(receipts, workLog, allWorkLogs = [workLog]) {
|
|
|
2073
2095
|
};
|
|
2074
2096
|
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
2097
|
if (!responseBody) return null;
|
|
2076
|
-
const expectedRequestHash = (0,
|
|
2077
|
-
const expectedResponseHash = (0,
|
|
2098
|
+
const expectedRequestHash = (0, import_sdk6.canonicalSha256Hex)(requestBody);
|
|
2099
|
+
const expectedResponseHash = (0, import_sdk6.canonicalSha256Hex)(responseBody);
|
|
2078
2100
|
const matches = receipts.filter((r) => r.requestHash === expectedRequestHash && r.responseHash === expectedResponseHash);
|
|
2079
2101
|
if (matches.length > 0) return pickLatest(matches);
|
|
2080
2102
|
const respondedSiblings = allWorkLogs.filter((wl) => wl.delegationId === workLog.delegationId && (wl.responseOutput !== void 0 || wl.responseError !== void 0)).length;
|
|
@@ -2116,49 +2138,49 @@ function nextAction(input) {
|
|
|
2116
2138
|
complete: false
|
|
2117
2139
|
};
|
|
2118
2140
|
}
|
|
2119
|
-
if (relationship.state ===
|
|
2141
|
+
if (relationship.state === import_sdk6.RelationshipStates.PENDING) {
|
|
2120
2142
|
return {
|
|
2121
2143
|
hint: "Relationship is PENDING \u2014 one side owes `heyarp send-handshake-response <peer> --decision accept | decline`",
|
|
2122
2144
|
owner: "either",
|
|
2123
2145
|
complete: false
|
|
2124
2146
|
};
|
|
2125
2147
|
}
|
|
2126
|
-
if (relationship.state ===
|
|
2148
|
+
if (relationship.state === import_sdk6.RelationshipStates.PAUSED) {
|
|
2127
2149
|
return { hint: "Relationship is PAUSED \u2014 owner must `heyarp unpause` before any envelopes flow", owner: "either", complete: false };
|
|
2128
2150
|
}
|
|
2129
|
-
if (relationship.state ===
|
|
2151
|
+
if (relationship.state === import_sdk6.RelationshipStates.CLOSED) {
|
|
2130
2152
|
return { hint: "Relationship is CLOSED \u2014 terminal state, no further action possible. Start a fresh handshake to reopen.", owner: "none", complete: false };
|
|
2131
2153
|
}
|
|
2132
|
-
if (!latestDelegation || latestDelegation.state ===
|
|
2154
|
+
if (!latestDelegation || latestDelegation.state === import_sdk6.DelegationStates.DECLINED || latestDelegation.state === import_sdk6.DelegationStates.CANCELED) {
|
|
2133
2155
|
return {
|
|
2134
2156
|
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
2157
|
owner: "either",
|
|
2136
2158
|
complete: false
|
|
2137
2159
|
};
|
|
2138
2160
|
}
|
|
2139
|
-
if (latestDelegation.state ===
|
|
2161
|
+
if (latestDelegation.state === import_sdk6.DelegationStates.DISPUTING) {
|
|
2140
2162
|
return {
|
|
2141
2163
|
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
2164
|
owner: "none",
|
|
2143
2165
|
complete: false
|
|
2144
2166
|
};
|
|
2145
2167
|
}
|
|
2146
|
-
if (latestDelegation.state ===
|
|
2168
|
+
if (latestDelegation.state === import_sdk6.DelegationStates.COMPLETED) {
|
|
2147
2169
|
return {
|
|
2148
2170
|
hint: "Cycle COMPLETE \u2014 payment claimed on chain (lock paid; the receipt carries releaseStatus=paid)",
|
|
2149
2171
|
owner: "none",
|
|
2150
2172
|
complete: true
|
|
2151
2173
|
};
|
|
2152
2174
|
}
|
|
2153
|
-
if (latestDelegation.state ===
|
|
2175
|
+
if (latestDelegation.state === import_sdk6.DelegationStates.FAILED || latestDelegation.state === import_sdk6.DelegationStates.REFUNDED || latestDelegation.state === import_sdk6.DelegationStates.DISPUTE_RESOLVED) {
|
|
2154
2176
|
const stateLabel = latestDelegation.state.toUpperCase();
|
|
2155
|
-
const reason = latestDelegation.state ===
|
|
2177
|
+
const reason = latestDelegation.state === import_sdk6.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_sdk6.DelegationStates.REFUNDED ? (
|
|
2156
2178
|
// Keyed on the DELEGATION row's releaseStatus, not the
|
|
2157
2179
|
// receipt's: in the claim-expired path the worker never
|
|
2158
2180
|
// submitted anything, so no receipt row exists to carry
|
|
2159
2181
|
// the outcome — the delegation copy is always present
|
|
2160
2182
|
// on indexer-driven terminals.
|
|
2161
|
-
latestDelegation.releaseStatus ===
|
|
2183
|
+
latestDelegation.releaseStatus === import_sdk6.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_sdk6.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
2184
|
) : "admin closed the delegation via the dispute-resolution path";
|
|
2163
2185
|
return {
|
|
2164
2186
|
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 +2188,7 @@ function nextAction(input) {
|
|
|
2166
2188
|
complete: false
|
|
2167
2189
|
};
|
|
2168
2190
|
}
|
|
2169
|
-
if (latestDelegation.state ===
|
|
2191
|
+
if (latestDelegation.state === import_sdk6.DelegationStates.OFFERED) {
|
|
2170
2192
|
const iAmOfferer = latestDelegation.offererDid === signerDid;
|
|
2171
2193
|
const stateLabel = "OFFERED";
|
|
2172
2194
|
return {
|
|
@@ -2175,7 +2197,7 @@ function nextAction(input) {
|
|
|
2175
2197
|
complete: false
|
|
2176
2198
|
};
|
|
2177
2199
|
}
|
|
2178
|
-
if (latestDelegation.state ===
|
|
2200
|
+
if (latestDelegation.state === import_sdk6.DelegationStates.ACCEPTED && !latestWorkLog) {
|
|
2179
2201
|
const iAmOfferer = latestDelegation.offererDid === signerDid;
|
|
2180
2202
|
return {
|
|
2181
2203
|
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 +2205,7 @@ function nextAction(input) {
|
|
|
2183
2205
|
complete: false
|
|
2184
2206
|
};
|
|
2185
2207
|
}
|
|
2186
|
-
if (latestDelegation.state ===
|
|
2208
|
+
if (latestDelegation.state === import_sdk6.DelegationStates.PENDING_LOCK_FINALIZATION && !latestWorkLog) {
|
|
2187
2209
|
return {
|
|
2188
2210
|
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
2211
|
owner: "none",
|
|
@@ -2198,7 +2220,7 @@ function nextAction(input) {
|
|
|
2198
2220
|
complete: false
|
|
2199
2221
|
};
|
|
2200
2222
|
}
|
|
2201
|
-
if (latestWorkLog.state ===
|
|
2223
|
+
if (latestWorkLog.state === import_sdk6.WorkLogStates.REQUESTED) {
|
|
2202
2224
|
const iAmPayee = latestWorkLog.payeeDid === signerDid;
|
|
2203
2225
|
return {
|
|
2204
2226
|
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\``,
|
|
@@ -2294,13 +2316,13 @@ function cycleHeadline(s) {
|
|
|
2294
2316
|
return `${import_chalk7.default.bold("Cycle:")} ${import_chalk7.default.red.bold("NOT FOUND")} ${import_chalk7.default.dim("\u2014 relationship missing or signer is not a member")}`;
|
|
2295
2317
|
case "unknown":
|
|
2296
2318
|
return `${import_chalk7.default.bold("Cycle:")} ${import_chalk7.default.yellow.bold("UNKNOWN")} ${import_chalk7.default.dim("\u2014 state probe inconclusive; hint below is advisory")}`;
|
|
2297
|
-
case
|
|
2319
|
+
case import_sdk6.RelationshipStates.CLOSED:
|
|
2298
2320
|
return `${import_chalk7.default.bold("Cycle:")} ${import_chalk7.default.red.bold("CLOSED")} ${import_chalk7.default.dim("\u2014 relationship terminal, no further protocol action")}`;
|
|
2299
|
-
case
|
|
2321
|
+
case import_sdk6.RelationshipStates.PAUSED:
|
|
2300
2322
|
return `${import_chalk7.default.bold("Cycle:")} ${import_chalk7.default.yellow.bold("PAUSED")} ${import_chalk7.default.dim("\u2014 relationship soft-disabled, resume to continue")}`;
|
|
2301
|
-
case
|
|
2323
|
+
case import_sdk6.RelationshipStates.PENDING:
|
|
2302
2324
|
return `${import_chalk7.default.bold("Cycle:")} ${import_chalk7.default.yellow.bold("PENDING")} ${import_chalk7.default.dim("\u2014 awaiting handshake_response")}`;
|
|
2303
|
-
case
|
|
2325
|
+
case import_sdk6.RelationshipStates.ACTIVE:
|
|
2304
2326
|
default:
|
|
2305
2327
|
return `${import_chalk7.default.bold("Cycle:")} ${import_chalk7.default.cyan.bold("ACTIVE")} ${import_chalk7.default.dim('\u2014 work in progress; see "Next action" below')}`;
|
|
2306
2328
|
}
|
|
@@ -2315,41 +2337,41 @@ function stateColor(state) {
|
|
|
2315
2337
|
}
|
|
2316
2338
|
|
|
2317
2339
|
// src/commands/wallet.ts
|
|
2318
|
-
var
|
|
2340
|
+
var import_sdk9 = require("@heyanon-arp/sdk");
|
|
2319
2341
|
var import_utils = require("@noble/hashes/utils");
|
|
2320
2342
|
var import_web32 = require("@solana/web3.js");
|
|
2321
2343
|
init_api();
|
|
2322
2344
|
init_config();
|
|
2323
2345
|
|
|
2324
2346
|
// src/solana/escrow-ix.ts
|
|
2325
|
-
var
|
|
2347
|
+
var import_sdk7 = require("@heyanon-arp/sdk");
|
|
2326
2348
|
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(
|
|
2349
|
+
var SPL_TOKEN_PROGRAM_ID = new import_web3.PublicKey(import_sdk7.SPL_TOKEN_PROGRAM_ID_BASE58);
|
|
2350
|
+
var ASSOCIATED_TOKEN_PROGRAM_ID = new import_web3.PublicKey(import_sdk7.ASSOCIATED_TOKEN_PROGRAM_ID_BASE58);
|
|
2351
|
+
var NATIVE_SOL_MINT = new import_web3.PublicKey(import_sdk7.NATIVE_SOL_MINT_BASE58);
|
|
2330
2352
|
function deriveLockPda(programId, lockId) {
|
|
2331
|
-
return import_web3.PublicKey.findProgramAddressSync([Buffer.from(
|
|
2353
|
+
return import_web3.PublicKey.findProgramAddressSync([Buffer.from(import_sdk7.ESCROW_PDA_SEEDS.LOCK), Buffer.from(lockId)], programId)[0];
|
|
2332
2354
|
}
|
|
2333
2355
|
function deriveEscrowPda(programId, lockId) {
|
|
2334
|
-
return import_web3.PublicKey.findProgramAddressSync([Buffer.from(
|
|
2356
|
+
return import_web3.PublicKey.findProgramAddressSync([Buffer.from(import_sdk7.ESCROW_PDA_SEEDS.ESCROW), Buffer.from(lockId)], programId)[0];
|
|
2335
2357
|
}
|
|
2336
2358
|
function deriveConfigPda(programId) {
|
|
2337
|
-
return import_web3.PublicKey.findProgramAddressSync([Buffer.from(
|
|
2359
|
+
return import_web3.PublicKey.findProgramAddressSync([Buffer.from(import_sdk7.ESCROW_PDA_SEEDS.CONFIG)], programId)[0];
|
|
2338
2360
|
}
|
|
2339
2361
|
function deriveStakeVaultPda(programId) {
|
|
2340
|
-
return import_web3.PublicKey.findProgramAddressSync([Buffer.from(
|
|
2362
|
+
return import_web3.PublicKey.findProgramAddressSync([Buffer.from(import_sdk7.ESCROW_PDA_SEEDS.STAKE_VAULT)], programId)[0];
|
|
2341
2363
|
}
|
|
2342
2364
|
function deriveCollateralConfigPda(programId, mint) {
|
|
2343
|
-
return import_web3.PublicKey.findProgramAddressSync([Buffer.from(
|
|
2365
|
+
return import_web3.PublicKey.findProgramAddressSync([Buffer.from(import_sdk7.ESCROW_PDA_SEEDS.COLLATERAL), mint.toBuffer()], programId)[0];
|
|
2344
2366
|
}
|
|
2345
2367
|
function deriveDisputeResolutionPda(programId, lockId) {
|
|
2346
|
-
return import_web3.PublicKey.findProgramAddressSync([Buffer.from(
|
|
2368
|
+
return import_web3.PublicKey.findProgramAddressSync([Buffer.from(import_sdk7.ESCROW_PDA_SEEDS.DISPUTE_RESOLUTION), Buffer.from(lockId)], programId)[0];
|
|
2347
2369
|
}
|
|
2348
2370
|
function deriveOperatorAuthPda(programId, operator) {
|
|
2349
|
-
return import_web3.PublicKey.findProgramAddressSync([Buffer.from(
|
|
2371
|
+
return import_web3.PublicKey.findProgramAddressSync([Buffer.from(import_sdk7.ESCROW_PDA_SEEDS.OPERATOR_AUTH), operator.toBuffer()], programId)[0];
|
|
2350
2372
|
}
|
|
2351
2373
|
function deriveEventAuthorityPda(programId) {
|
|
2352
|
-
return import_web3.PublicKey.findProgramAddressSync([Buffer.from(
|
|
2374
|
+
return import_web3.PublicKey.findProgramAddressSync([Buffer.from(import_sdk7.ESCROW_PDA_SEEDS.EVENT_AUTHORITY)], programId)[0];
|
|
2353
2375
|
}
|
|
2354
2376
|
function deriveAta(owner, mint) {
|
|
2355
2377
|
return import_web3.PublicKey.findProgramAddressSync([owner.toBuffer(), SPL_TOKEN_PROGRAM_ID.toBuffer(), mint.toBuffer()], ASSOCIATED_TOKEN_PROGRAM_ID)[0];
|
|
@@ -2364,12 +2386,12 @@ function meta(pubkey, opts = {}) {
|
|
|
2364
2386
|
return { pubkey, isSigner: opts.signer === true, isWritable: opts.writable === true };
|
|
2365
2387
|
}
|
|
2366
2388
|
function noArgIx(programId, name, keys) {
|
|
2367
|
-
return new import_web3.TransactionInstruction({ programId, keys, data: Buffer.from((0,
|
|
2389
|
+
return new import_web3.TransactionInstruction({ programId, keys, data: Buffer.from((0, import_sdk7.buildLifecycleIxData)(name)) });
|
|
2368
2390
|
}
|
|
2369
2391
|
function buildCreateLockIx(input) {
|
|
2370
2392
|
const { programId, lockId } = input;
|
|
2371
2393
|
const native = input.mint === null;
|
|
2372
|
-
const data = Buffer.from((0,
|
|
2394
|
+
const data = Buffer.from((0, import_sdk7.buildCreateLockIxData)({ lockId, amount: input.amount, conditionHash: input.conditionHash }, { native }));
|
|
2373
2395
|
const head = [
|
|
2374
2396
|
meta(input.payer, { signer: true, writable: true }),
|
|
2375
2397
|
meta(input.payee),
|
|
@@ -2505,7 +2527,7 @@ function buildOpenDisputeIx(input) {
|
|
|
2505
2527
|
function buildResolveDisputeIx(input) {
|
|
2506
2528
|
const { programId, lockId } = input;
|
|
2507
2529
|
const native = input.mint === null;
|
|
2508
|
-
const data = Buffer.from((0,
|
|
2530
|
+
const data = Buffer.from((0, import_sdk7.buildResolveDisputeIxData)(input.args, { native }));
|
|
2509
2531
|
if (native) {
|
|
2510
2532
|
return new import_web3.TransactionInstruction({
|
|
2511
2533
|
programId,
|
|
@@ -2582,16 +2604,17 @@ function buildCloseDisputeIx(input) {
|
|
|
2582
2604
|
]);
|
|
2583
2605
|
}
|
|
2584
2606
|
async function fetchLockAccount(conn, programId, delegationId) {
|
|
2585
|
-
const lockId = (0,
|
|
2607
|
+
const lockId = (0, import_sdk7.deriveLockId)(delegationId);
|
|
2586
2608
|
const lockPda = deriveLockPda(programId, lockId);
|
|
2587
2609
|
const info = await conn.getAccountInfo(lockPda);
|
|
2588
2610
|
if (!info) return null;
|
|
2589
|
-
return { lockId, lockPda, lock: (0,
|
|
2611
|
+
return { lockId, lockPda, lock: (0, import_sdk7.decodeLockAccount)(Uint8Array.from(info.data)) };
|
|
2590
2612
|
}
|
|
2591
2613
|
|
|
2592
2614
|
// src/commands/token-amount.ts
|
|
2615
|
+
var import_sdk8 = require("@heyanon-arp/sdk");
|
|
2593
2616
|
function toBaseUnits(amountDecimal, decimals) {
|
|
2594
|
-
if (
|
|
2617
|
+
if (!(0, import_sdk8.isDecimalAmountString)(amountDecimal)) {
|
|
2595
2618
|
throw new Error(`amount '${amountDecimal}' is not a non-negative decimal number`);
|
|
2596
2619
|
}
|
|
2597
2620
|
if (!Number.isInteger(decimals) || decimals < 0 || decimals > 255) {
|
|
@@ -2620,8 +2643,8 @@ function normaliseDelegationId(raw) {
|
|
|
2620
2643
|
}
|
|
2621
2644
|
throw new Error(`wallet: --delegation-id must be either 'del_<uuid>' or a bare canonical-lowercase UUID (got '${raw}')`);
|
|
2622
2645
|
}
|
|
2623
|
-
var SPL_TOKEN_PROGRAM_ID2 = new import_web32.PublicKey(
|
|
2624
|
-
var ASSOCIATED_TOKEN_PROGRAM_ID2 = new import_web32.PublicKey(
|
|
2646
|
+
var SPL_TOKEN_PROGRAM_ID2 = new import_web32.PublicKey(import_sdk9.SPL_TOKEN_PROGRAM_ID_BASE58);
|
|
2647
|
+
var ASSOCIATED_TOKEN_PROGRAM_ID2 = new import_web32.PublicKey(import_sdk9.ASSOCIATED_TOKEN_PROGRAM_ID_BASE58);
|
|
2625
2648
|
var FALLBACK_RPC_URL = "https://api.mainnet-beta.solana.com";
|
|
2626
2649
|
function resolveRpcUrl(opts) {
|
|
2627
2650
|
if (opts.rpcUrl !== void 0 && opts.rpcUrl !== "") return opts.rpcUrl;
|
|
@@ -2641,7 +2664,7 @@ function redactRpcUrl(url) {
|
|
|
2641
2664
|
return "<redacted>";
|
|
2642
2665
|
}
|
|
2643
2666
|
}
|
|
2644
|
-
var FALLBACK_PROGRAM_ID =
|
|
2667
|
+
var FALLBACK_PROGRAM_ID = import_sdk9.ESCROW_PROGRAM_ID_BASE58;
|
|
2645
2668
|
async function resolveProgramIdWithSource(api, opts) {
|
|
2646
2669
|
if (opts.programId !== void 0 && opts.programId !== "") {
|
|
2647
2670
|
return { programId: opts.programId, source: "flag" };
|
|
@@ -2725,7 +2748,7 @@ async function derivePdasHandler(opts) {
|
|
|
2725
2748
|
const normalisedDelegationId = normaliseDelegationId(opts.delegationId);
|
|
2726
2749
|
const api = new ArpApiClient(opts.server);
|
|
2727
2750
|
const programId = new import_web32.PublicKey(await resolveProgramIdStrict(api, opts, "wallet derive-pdas"));
|
|
2728
|
-
const lockIdBytes = (0,
|
|
2751
|
+
const lockIdBytes = (0, import_sdk9.deriveLockId)(normalisedDelegationId);
|
|
2729
2752
|
const lockIdSeed = Buffer.from(lockIdBytes);
|
|
2730
2753
|
const lockIdHex = Buffer.from(lockIdBytes).toString("hex");
|
|
2731
2754
|
const [lockPda] = import_web32.PublicKey.findProgramAddressSync([Buffer.from("lock"), lockIdSeed], programId);
|
|
@@ -2744,11 +2767,11 @@ async function derivePdasHandler(opts) {
|
|
|
2744
2767
|
};
|
|
2745
2768
|
}
|
|
2746
2769
|
var TERMINAL_METHOD = {
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2770
|
+
[import_sdk9.LockStates.PAID]: "claim_work_payment",
|
|
2771
|
+
[import_sdk9.LockStates.CANCELED]: "cancel_lock",
|
|
2772
|
+
[import_sdk9.LockStates.REVOKED]: "claim_expired_work",
|
|
2773
|
+
[import_sdk9.LockStates.DISPUTE_RESOLVED]: "resolve_dispute",
|
|
2774
|
+
[import_sdk9.LockStates.DISPUTE_CLOSED]: "close_dispute"
|
|
2752
2775
|
};
|
|
2753
2776
|
function registerVerifyRelease(cmd) {
|
|
2754
2777
|
cmd.command("verify-release").description(
|
|
@@ -2794,7 +2817,7 @@ async function verifyReleaseHandler(opts) {
|
|
|
2794
2817
|
const rpcUrl = resolveRpcUrlStrict(opts);
|
|
2795
2818
|
const conn = new import_web32.Connection(rpcUrl, "confirmed");
|
|
2796
2819
|
const fetched = await fetchLockAccount(conn, programId, normalisedDelegationId);
|
|
2797
|
-
const lockId = (0,
|
|
2820
|
+
const lockId = (0, import_sdk9.deriveLockId)(normalisedDelegationId);
|
|
2798
2821
|
const lockPda = deriveLockPda(programId, lockId);
|
|
2799
2822
|
const escrowPda = deriveEscrowPda(programId, lockId);
|
|
2800
2823
|
if (!fetched) {
|
|
@@ -2815,7 +2838,7 @@ async function verifyReleaseHandler(opts) {
|
|
|
2815
2838
|
lock_pda: lockPda.toBase58(),
|
|
2816
2839
|
escrow_pda: escrowPda.toBase58(),
|
|
2817
2840
|
lock_account_exists: true,
|
|
2818
|
-
released: status ===
|
|
2841
|
+
released: status === import_sdk9.LockStates.PAID,
|
|
2819
2842
|
status,
|
|
2820
2843
|
...TERMINAL_METHOD[status] !== void 0 ? { release_method: TERMINAL_METHOD[status] } : {},
|
|
2821
2844
|
lock_state: lock.stateByte,
|
|
@@ -2825,23 +2848,23 @@ async function verifyReleaseHandler(opts) {
|
|
|
2825
2848
|
}
|
|
2826
2849
|
function renderStatusLine(status) {
|
|
2827
2850
|
switch (status) {
|
|
2828
|
-
case
|
|
2851
|
+
case import_sdk9.LockStates.PAID:
|
|
2829
2852
|
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
|
|
2853
|
+
case import_sdk9.LockStates.CREATED:
|
|
2831
2854
|
return "\u2717 created \u2014 funded, awaiting the worker accept_lock (stake) \u2014 or a buyer cancel";
|
|
2832
|
-
case
|
|
2855
|
+
case import_sdk9.LockStates.IN_PROGRESS:
|
|
2833
2856
|
return "\u2717 in_progress \u2014 worker accepted + staked; work window running";
|
|
2834
|
-
case
|
|
2857
|
+
case import_sdk9.LockStates.SUBMITTED:
|
|
2835
2858
|
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
|
|
2859
|
+
case import_sdk9.LockStates.DISPUTING:
|
|
2837
2860
|
return "\u2717 disputing \u2014 buyer disputed; operator has the dispute window to rule, after that either party can close";
|
|
2838
|
-
case
|
|
2861
|
+
case import_sdk9.LockStates.CANCELED:
|
|
2839
2862
|
return "\u2717 canceled \u2014 buyer canceled pre-accept; escrow returned";
|
|
2840
|
-
case
|
|
2863
|
+
case import_sdk9.LockStates.REVOKED:
|
|
2841
2864
|
return "\u2717 revoked \u2014 work window lapsed unsubmitted; buyer reclaimed the escrow + the worker stake";
|
|
2842
|
-
case
|
|
2865
|
+
case import_sdk9.LockStates.DISPUTE_RESOLVED:
|
|
2843
2866
|
return "\u2717 dispute_resolved \u2014 operator ruled; winner took the escrow per the on-chain split";
|
|
2844
|
-
case
|
|
2867
|
+
case import_sdk9.LockStates.DISPUTE_CLOSED:
|
|
2845
2868
|
return "\u2717 dispute_closed \u2014 dispute window lapsed unresolved; escrow returned to the buyer, stakes returned";
|
|
2846
2869
|
case "lock_never_created":
|
|
2847
2870
|
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 +3050,7 @@ async function createLockHandler(opts) {
|
|
|
3027
3050
|
if (clusterTag !== 0 && clusterTag !== 1) {
|
|
3028
3051
|
throw new Error(`--cluster-tag must be 0 (devnet) or 1 (mainnet) (got ${clusterTag})`);
|
|
3029
3052
|
}
|
|
3030
|
-
const clusterCaip2 = clusterTag === 1 ?
|
|
3053
|
+
const clusterCaip2 = clusterTag === 1 ? import_sdk9.SOLANA_CLUSTER_IDS["solana-mainnet"] : import_sdk9.SOLANA_CLUSTER_IDS["solana-devnet"];
|
|
3031
3054
|
const expectedLockAsset = typeof opts.mintPubkey === "string" && opts.mintPubkey !== "" ? { kind: "spl", mint: parsePubkey(opts.mintPubkey, "--mint-pubkey").toBase58(), cluster: clusterCaip2 } : { kind: "native" };
|
|
3032
3055
|
if (!offlineMode) {
|
|
3033
3056
|
await preflightLockCurrency(api, agent, normalisedDelegationId, expectedLockAsset);
|
|
@@ -3037,7 +3060,7 @@ async function createLockHandler(opts) {
|
|
|
3037
3060
|
const conn = new import_web32.Connection(rpcUrl, "confirmed");
|
|
3038
3061
|
const asset = await resolveCreateLockAsset(conn, opts, payerKp.publicKey, clusterCaip2);
|
|
3039
3062
|
const amount = asset.amount;
|
|
3040
|
-
const lockIdBytes = (0,
|
|
3063
|
+
const lockIdBytes = (0, import_sdk9.deriveLockId)(normalisedDelegationId);
|
|
3041
3064
|
const ix = buildCreateLockIx({
|
|
3042
3065
|
programId,
|
|
3043
3066
|
lockId: lockIdBytes,
|
|
@@ -3121,63 +3144,12 @@ function registerDelegationCommands(root) {
|
|
|
3121
3144
|
registerDecline(cmd);
|
|
3122
3145
|
registerCancel(cmd);
|
|
3123
3146
|
}
|
|
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
3147
|
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-did>", "Recipient agent 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 (${
|
|
3148
|
+
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-did>", "Recipient agent 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_sdk10.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_sdk10.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(
|
|
3149
|
+
"--json",
|
|
3150
|
+
'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.',
|
|
3151
|
+
false
|
|
3152
|
+
).option(
|
|
3181
3153
|
"--wait-until <phase>",
|
|
3182
3154
|
'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
3155
|
).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,6 +3255,11 @@ function assembleEscrowLockAttachment(opts) {
|
|
|
3283
3255
|
};
|
|
3284
3256
|
}
|
|
3285
3257
|
async function runOffer(recipientDid, opts) {
|
|
3258
|
+
if (opts.verbose && opts.json) {
|
|
3259
|
+
throw new Error(
|
|
3260
|
+
"delegation offer: --verbose and --json are mutually exclusive. --json emits the structured server response; --verbose adds dumps that would break `--json | jq`."
|
|
3261
|
+
);
|
|
3262
|
+
}
|
|
3286
3263
|
requireDid("delegation offer", recipientDid, "<recipient-did>");
|
|
3287
3264
|
const ttlSeconds = parseTtl("delegation offer", opts.ttl);
|
|
3288
3265
|
if (!opts.title || opts.title.length === 0) {
|
|
@@ -3290,7 +3267,7 @@ async function runOffer(recipientDid, opts) {
|
|
|
3290
3267
|
}
|
|
3291
3268
|
const terms = parseOfferTerms("delegation offer", opts);
|
|
3292
3269
|
const offeredAssetId = terms.currency?.asset_id;
|
|
3293
|
-
if (offeredAssetId && !(0,
|
|
3270
|
+
if (offeredAssetId && !(0, import_sdk10.isWhitelistedAssetId)(offeredAssetId)) {
|
|
3294
3271
|
console.error(
|
|
3295
3272
|
import_chalk8.default.yellow(
|
|
3296
3273
|
`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'.`
|
|
@@ -3311,21 +3288,21 @@ async function runOffer(recipientDid, opts) {
|
|
|
3311
3288
|
const api = new ArpApiClient(opts.server);
|
|
3312
3289
|
const sender = resolveSenderAgent("delegation offer", opts.server, opts.fromDid);
|
|
3313
3290
|
const content = {
|
|
3314
|
-
action:
|
|
3291
|
+
action: import_sdk10.DelegationActions.OFFER,
|
|
3315
3292
|
delegation_id: delegationId,
|
|
3316
3293
|
title: opts.title,
|
|
3317
3294
|
...terms
|
|
3318
3295
|
};
|
|
3319
3296
|
const body = { type: "delegation", content };
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3297
|
+
progress(opts.json, import_chalk8.default.dim(`Server: ${api.serverUrl}`));
|
|
3298
|
+
progress(opts.json, import_chalk8.default.dim(`Sender: ${sender.did}`));
|
|
3299
|
+
progress(opts.json, import_chalk8.default.dim(`Recipient: ${recipientDid}`));
|
|
3300
|
+
progress(opts.json, import_chalk8.default.dim(`Delegation: ${delegationId}`));
|
|
3324
3301
|
let result;
|
|
3325
3302
|
try {
|
|
3326
3303
|
result = await sendDelegationEnvelope({ api, sender, recipientDid, body, ttlSeconds, verbose: opts.verbose, server: opts.server });
|
|
3327
3304
|
} catch (err) {
|
|
3328
|
-
if (err instanceof ApiError && err.payload.code ===
|
|
3305
|
+
if (err instanceof ApiError && err.payload.code === import_sdk10.DelegationOfferRejectionCodes.ASSET_NOT_ALLOWED) {
|
|
3329
3306
|
const d = err.payload.details;
|
|
3330
3307
|
console.error(import_chalk8.default.yellow(`
|
|
3331
3308
|
The server's payment-asset whitelist rejected this currency.`));
|
|
@@ -3338,7 +3315,7 @@ See the whitelist (shorthand keys + canonical decimals):
|
|
|
3338
3315
|
heyarp assets
|
|
3339
3316
|
then re-offer with a whitelisted --currency.`));
|
|
3340
3317
|
}
|
|
3341
|
-
if (err instanceof ApiError && err.payload.code ===
|
|
3318
|
+
if (err instanceof ApiError && err.payload.code === import_sdk10.DelegationOfferRejectionCodes.PRICING_MISMATCH) {
|
|
3342
3319
|
const d = err.payload.details;
|
|
3343
3320
|
console.error(import_chalk8.default.yellow(`
|
|
3344
3321
|
The recipient's published accept-prefs rejected this offer${d?.reason ? ` (mismatch: ${d.reason})` : ""}.`));
|
|
@@ -3355,7 +3332,7 @@ then re-run with matching --currency / --amount.`
|
|
|
3355
3332
|
)
|
|
3356
3333
|
);
|
|
3357
3334
|
}
|
|
3358
|
-
if (err instanceof ApiError && err.payload.code ===
|
|
3335
|
+
if (err instanceof ApiError && err.payload.code === import_sdk10.DelegationOfferRejectionCodes.CAPACITY_EXCEEDED) {
|
|
3359
3336
|
const d = err.payload.details;
|
|
3360
3337
|
const cap = d?.maxActive === 0 ? "closed for new offers (busy)" : `at capacity (${d?.currentActive}/${d?.maxActive} active delegations)`;
|
|
3361
3338
|
console.error(import_chalk8.default.yellow(`
|
|
@@ -3364,17 +3341,31 @@ The recipient is ${cap}.`));
|
|
|
3364
3341
|
}
|
|
3365
3342
|
throw err;
|
|
3366
3343
|
}
|
|
3367
|
-
|
|
3368
|
-
|
|
3344
|
+
if (opts.json) {
|
|
3345
|
+
jsonOut({
|
|
3346
|
+
ok: true,
|
|
3347
|
+
action: "offer",
|
|
3348
|
+
delegationId,
|
|
3349
|
+
eventId: result.eventId,
|
|
3350
|
+
relationshipId: result.relationshipId,
|
|
3351
|
+
relationshipEventIndex: result.relationshipEventIndex,
|
|
3352
|
+
serverTimestamp: result.serverTimestamp,
|
|
3353
|
+
serverEventHash: result.serverEventHash,
|
|
3354
|
+
prevServerEventHash: result.prevServerEventHash ?? null
|
|
3355
|
+
});
|
|
3356
|
+
} else {
|
|
3357
|
+
printIngestResult(result);
|
|
3358
|
+
console.log(import_chalk8.default.dim(`
|
|
3369
3359
|
Reference this delegation on subsequent calls with:`));
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3360
|
+
console.log(import_chalk8.default.dim(` heyarp delegation accept ${result.relationshipId} ${delegationId}`));
|
|
3361
|
+
console.log(import_chalk8.default.dim(` heyarp delegation decline ${result.relationshipId} ${delegationId}`));
|
|
3362
|
+
console.log(import_chalk8.default.dim(` heyarp delegation cancel ${result.relationshipId} ${delegationId}`));
|
|
3363
|
+
console.log(import_chalk8.default.dim(`
|
|
3374
3364
|
After the worker accepts, fund the escrow lock:`));
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3365
|
+
console.log(import_chalk8.default.dim(` heyarp wallet create-lock --delegation-id ${delegationId} --condition-hash <hex> ... > lock.json`));
|
|
3366
|
+
console.log(import_chalk8.default.dim(` heyarp delegation fund ${delegationId} --escrow-lock-from-file lock.json`));
|
|
3367
|
+
}
|
|
3368
|
+
if (opts.waitUntil && !opts.json) {
|
|
3378
3369
|
const untilPhase = parseUntilPhase(opts.waitUntil);
|
|
3379
3370
|
if (untilPhase === void 0) {
|
|
3380
3371
|
throw new Error(`delegation offer: --wait-until requires a phase value (got ${JSON.stringify(opts.waitUntil)})`);
|
|
@@ -3394,7 +3385,7 @@ After the worker accepts, fund the escrow lock:`));
|
|
|
3394
3385
|
}
|
|
3395
3386
|
}
|
|
3396
3387
|
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>",
|
|
3388
|
+
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_sdk10.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
3389
|
"--json",
|
|
3399
3390
|
'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
3391
|
false
|
|
@@ -3458,7 +3449,7 @@ async function runFund(delegationId, opts) {
|
|
|
3458
3449
|
);
|
|
3459
3450
|
}
|
|
3460
3451
|
}
|
|
3461
|
-
const content = { action:
|
|
3452
|
+
const content = { action: import_sdk10.DelegationActions.FUND, delegation_id: delegationId };
|
|
3462
3453
|
const body = { type: "delegation", content };
|
|
3463
3454
|
const attachments = { escrow_lock: escrowResult.attachment };
|
|
3464
3455
|
progress(opts.json, import_chalk8.default.dim(`Server: ${api.serverUrl}`));
|
|
@@ -3559,8 +3550,12 @@ function registerDecline(parent) {
|
|
|
3559
3550
|
"--reason <code>",
|
|
3560
3551
|
// surface the closed enum at help time so operators
|
|
3561
3552
|
// 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(
|
|
3553
|
+
`Required: decline reason code (one of: ${import_sdk10.DECLINE_REASONS.join(", ")}). Carried in body.content.reason so the counterparty's reactor can branch on it.`
|
|
3554
|
+
).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(
|
|
3555
|
+
"--json",
|
|
3556
|
+
'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.',
|
|
3557
|
+
false
|
|
3558
|
+
).option(
|
|
3564
3559
|
"--no-wait-for-lock",
|
|
3565
3560
|
"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
3561
|
).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 +3563,11 @@ function registerDecline(parent) {
|
|
|
3568
3563
|
});
|
|
3569
3564
|
}
|
|
3570
3565
|
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(
|
|
3566
|
+
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(
|
|
3567
|
+
"--json",
|
|
3568
|
+
'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.',
|
|
3569
|
+
false
|
|
3570
|
+
).option(
|
|
3572
3571
|
"--no-wait-for-lock",
|
|
3573
3572
|
"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
3573
|
).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 +3587,7 @@ async function runFollowupAction(relationshipId, delegationId, action, opts) {
|
|
|
3588
3587
|
const lockWaitTimeoutSec = parseLockWaitTimeout(cmdName, opts.lockWaitTimeout);
|
|
3589
3588
|
const lockWaitIntervalSec = parseLockWaitInterval(cmdName, opts.lockWaitInterval);
|
|
3590
3589
|
let declinePayload = null;
|
|
3591
|
-
if (action ===
|
|
3590
|
+
if (action === import_sdk10.DelegationActions.DECLINE) {
|
|
3592
3591
|
const reason = parseDeclineReason(cmdName, opts.reason);
|
|
3593
3592
|
const validatedDetail = parseReasonDetail(cmdName, opts.reasonDetail);
|
|
3594
3593
|
declinePayload = validatedDetail ? { reason, reasonDetail: validatedDetail } : { reason };
|
|
@@ -3597,7 +3596,7 @@ async function runFollowupAction(relationshipId, delegationId, action, opts) {
|
|
|
3597
3596
|
const sender = resolveSenderAgent(cmdName, opts.server, opts.fromDid);
|
|
3598
3597
|
const signer = makeSigner(sender);
|
|
3599
3598
|
const resolved = await resolveDelegationRefs(cmdName, api, signer, { relationshipId, delegationId, action, selfDid: sender.did });
|
|
3600
|
-
if (resolved.state ===
|
|
3599
|
+
if (resolved.state === import_sdk10.DelegationStates.PENDING_LOCK_FINALIZATION && opts.waitForLock !== false) {
|
|
3601
3600
|
await awaitDelegationLockFinalized(cmdName, api, signer, {
|
|
3602
3601
|
relationshipId,
|
|
3603
3602
|
delegationId,
|
|
@@ -3622,7 +3621,7 @@ async function runFollowupAction(relationshipId, delegationId, action, opts) {
|
|
|
3622
3621
|
progress(opts.json, import_chalk8.default.dim(`Server: ${api.serverUrl}`));
|
|
3623
3622
|
progress(opts.json, import_chalk8.default.dim(`Sender: ${sender.did}`));
|
|
3624
3623
|
progress(opts.json, import_chalk8.default.dim(`Relationship: ${relationshipId}`));
|
|
3625
|
-
progress(opts.json, import_chalk8.default.dim(`Delegation: ${delegationId} (action=${action}${action ===
|
|
3624
|
+
progress(opts.json, import_chalk8.default.dim(`Delegation: ${delegationId} (action=${action}${action === import_sdk10.DelegationActions.DECLINE ? `, reason=${content.reason}` : ""})`));
|
|
3626
3625
|
const result = await sendDelegationEnvelope({
|
|
3627
3626
|
api,
|
|
3628
3627
|
sender,
|
|
@@ -3651,9 +3650,9 @@ async function runFollowupAction(relationshipId, delegationId, action, opts) {
|
|
|
3651
3650
|
async function sendDelegationEnvelope(args) {
|
|
3652
3651
|
const nextSequence = (args.sender.lastSenderSequence ?? 0) + 1;
|
|
3653
3652
|
const protectedBlock = {
|
|
3654
|
-
protocol_version:
|
|
3655
|
-
purpose:
|
|
3656
|
-
message_id: (0,
|
|
3653
|
+
protocol_version: import_sdk10.CURRENT_PROTOCOL_VERSION,
|
|
3654
|
+
purpose: import_sdk10.Purpose.ENVELOPE,
|
|
3655
|
+
message_id: (0, import_sdk10.uuidV4)(),
|
|
3657
3656
|
sender_did: args.sender.did,
|
|
3658
3657
|
recipient_did: args.recipientDid,
|
|
3659
3658
|
// `relationship_id: null` matches the handshake
|
|
@@ -3662,13 +3661,13 @@ async function sendDelegationEnvelope(args) {
|
|
|
3662
3661
|
// existing relationship row.
|
|
3663
3662
|
relationship_id: null,
|
|
3664
3663
|
sender_sequence: nextSequence,
|
|
3665
|
-
sender_nonce: (0,
|
|
3666
|
-
timestamp: (0,
|
|
3667
|
-
expires_at: (0,
|
|
3664
|
+
sender_nonce: (0, import_sdk10.senderNonce)(),
|
|
3665
|
+
timestamp: (0, import_sdk10.rfc3339)(),
|
|
3666
|
+
expires_at: (0, import_sdk10.expiresAt)(args.ttlSeconds),
|
|
3668
3667
|
delivery_id: null
|
|
3669
3668
|
};
|
|
3670
3669
|
const signer = makeSigner(args.sender);
|
|
3671
|
-
const envelope = (0,
|
|
3670
|
+
const envelope = (0, import_sdk10.signEnvelope)({
|
|
3672
3671
|
protected: protectedBlock,
|
|
3673
3672
|
body: args.body,
|
|
3674
3673
|
identitySecretKey: signer.identitySecretKey,
|
|
@@ -3683,7 +3682,7 @@ async function sendDelegationEnvelope(args) {
|
|
|
3683
3682
|
updateAgentLocal(args.server, args.sender.did, { lastSenderSequence: nextSequence });
|
|
3684
3683
|
return result;
|
|
3685
3684
|
} catch (err) {
|
|
3686
|
-
if (err instanceof ApiError && isPostCommitErrorCode(err.payload.code)) {
|
|
3685
|
+
if (err instanceof ApiError && (0, import_sdk10.isPostCommitErrorCode)(err.payload.code)) {
|
|
3687
3686
|
updateAgentLocal(args.server, args.sender.did, { lastSenderSequence: nextSequence });
|
|
3688
3687
|
}
|
|
3689
3688
|
throw err;
|
|
@@ -3705,7 +3704,7 @@ async function resolveDelegationRefs(cmdName, api, signer, args) {
|
|
|
3705
3704
|
);
|
|
3706
3705
|
}
|
|
3707
3706
|
let recipientDid;
|
|
3708
|
-
if (args.action ===
|
|
3707
|
+
if (args.action === import_sdk10.DelegationActions.CANCEL) {
|
|
3709
3708
|
const firstEvents = await api.listEvents(args.relationshipId, signer, { since: 0, limit: 1 });
|
|
3710
3709
|
const handshake = firstEvents[0];
|
|
3711
3710
|
if (!handshake) {
|
|
@@ -3745,7 +3744,7 @@ async function awaitDelegationLockFinalized(cmdName, api, signer, args) {
|
|
|
3745
3744
|
after = page[page.length - 1].id;
|
|
3746
3745
|
}
|
|
3747
3746
|
};
|
|
3748
|
-
const outcome = await (0,
|
|
3747
|
+
const outcome = await (0, import_sdk10.pollUntil)({
|
|
3749
3748
|
fetch: fetchRow,
|
|
3750
3749
|
// Match on either "row not found at all" OR "state moved
|
|
3751
3750
|
// past pending_lock_finalization". The post-poll branch
|
|
@@ -3755,7 +3754,7 @@ async function awaitDelegationLockFinalized(cmdName, api, signer, args) {
|
|
|
3755
3754
|
// rows return cleanly. Polling on null would loop pointlessly
|
|
3756
3755
|
// until the deadline fires and surface a misleading "timed
|
|
3757
3756
|
// out" message for what's actually a wrong-id problem.
|
|
3758
|
-
predicate: (row2) => row2 === null || row2.state !==
|
|
3757
|
+
predicate: (row2) => row2 === null || row2.state !== import_sdk10.DelegationStates.PENDING_LOCK_FINALIZATION,
|
|
3759
3758
|
intervalMs: args.intervalSec * 1e3,
|
|
3760
3759
|
timeoutMs: args.timeoutSec * 1e3,
|
|
3761
3760
|
// Swallow ONLY transient errors. A 4xx during the poll is a
|
|
@@ -3786,7 +3785,7 @@ async function awaitDelegationLockFinalized(cmdName, api, signer, args) {
|
|
|
3786
3785
|
`${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
3786
|
);
|
|
3788
3787
|
}
|
|
3789
|
-
if (row.state !==
|
|
3788
|
+
if (row.state !== import_sdk10.DelegationStates.OFFERED) {
|
|
3790
3789
|
throw new Error(
|
|
3791
3790
|
`${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
3791
|
);
|
|
@@ -3846,7 +3845,7 @@ function parseOfferTerms(cmdName, opts) {
|
|
|
3846
3845
|
if (opts.amount) {
|
|
3847
3846
|
out.amount = opts.amount;
|
|
3848
3847
|
if (!opts.currency) {
|
|
3849
|
-
throw new Error(`${cmdName}: --amount requires --currency. Shorthand: ${
|
|
3848
|
+
throw new Error(`${cmdName}: --amount requires --currency. Shorthand: ${import_sdk10.WELL_KNOWN_ASSET_KEYS.join(", ")}, or raw CAIP-19 + --currency-decimals.`);
|
|
3850
3849
|
}
|
|
3851
3850
|
out.currency = buildAssetIdentifier(cmdName, DELEGATION_CURRENCY_FLAGS, opts.currency, opts.currencyDecimals, opts.currencySymbol);
|
|
3852
3851
|
} else if (opts.currency) {
|
|
@@ -3869,7 +3868,7 @@ function resolveOfferDelegationId(rawCliId, escrow) {
|
|
|
3869
3868
|
cliId = rawCliId.toLowerCase();
|
|
3870
3869
|
}
|
|
3871
3870
|
if (escrow === void 0) {
|
|
3872
|
-
return cliId ?? (0,
|
|
3871
|
+
return cliId ?? (0, import_sdk10.uuidV4)();
|
|
3873
3872
|
}
|
|
3874
3873
|
if (escrow.delegationIdFromLock !== void 0) {
|
|
3875
3874
|
const fileId = escrow.delegationIdFromLock;
|
|
@@ -3904,10 +3903,10 @@ function collectRepeated(value, previous) {
|
|
|
3904
3903
|
}
|
|
3905
3904
|
function parseDeclineReason(cmdName, raw) {
|
|
3906
3905
|
if (raw === void 0 || raw === "") {
|
|
3907
|
-
throw new Error(`${cmdName}: --reason is required when declining (one of: ${
|
|
3906
|
+
throw new Error(`${cmdName}: --reason is required when declining (one of: ${import_sdk10.DECLINE_REASONS.join(", ")})`);
|
|
3908
3907
|
}
|
|
3909
|
-
if (!(0,
|
|
3910
|
-
throw new Error(`${cmdName}: --reason must be one of ${
|
|
3908
|
+
if (!(0, import_sdk10.isDeclineReason)(raw)) {
|
|
3909
|
+
throw new Error(`${cmdName}: --reason must be one of ${import_sdk10.DECLINE_REASONS.join(", ")} (got '${raw}')`);
|
|
3911
3910
|
}
|
|
3912
3911
|
return raw;
|
|
3913
3912
|
}
|
|
@@ -3922,10 +3921,10 @@ function parseReasonDetail(cmdName, raw) {
|
|
|
3922
3921
|
return raw;
|
|
3923
3922
|
}
|
|
3924
3923
|
function buildAssetIdentifier(cmdName, labels, rawCurrency, rawDecimals, rawSymbol) {
|
|
3925
|
-
const resolved = (0,
|
|
3924
|
+
const resolved = (0, import_sdk10.resolveAsset)(rawCurrency);
|
|
3926
3925
|
if (!resolved) {
|
|
3927
3926
|
throw new Error(
|
|
3928
|
-
`${cmdName}: ${labels.currencyFlag} '${rawCurrency}' is not a known shorthand or a valid CAIP-19 string. Shorthand: ${
|
|
3927
|
+
`${cmdName}: ${labels.currencyFlag} '${rawCurrency}' is not a known shorthand or a valid CAIP-19 string. Shorthand: ${import_sdk10.WELL_KNOWN_ASSET_KEYS.join(", ")}. Or pass a raw CAIP-19 id (e.g. "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/spl:EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v") with ${labels.decimalsFlag}.`
|
|
3929
3928
|
);
|
|
3930
3929
|
}
|
|
3931
3930
|
let decimals = resolved.decimals;
|
|
@@ -3934,20 +3933,20 @@ function buildAssetIdentifier(cmdName, labels, rawCurrency, rawDecimals, rawSymb
|
|
|
3934
3933
|
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
3934
|
}
|
|
3936
3935
|
const parsed = Number(rawDecimals);
|
|
3937
|
-
if (!Number.isInteger(parsed) || parsed <
|
|
3936
|
+
if (!Number.isInteger(parsed) || parsed < import_sdk10.ASSET_DECIMALS_MIN || parsed > import_sdk10.ASSET_DECIMALS_MAX) {
|
|
3938
3937
|
throw new Error(`${cmdName}: ${labels.decimalsFlag} must be an integer in [0, 18] (got '${rawDecimals}').`);
|
|
3939
3938
|
}
|
|
3940
3939
|
decimals = parsed;
|
|
3941
3940
|
} else if (rawDecimals !== void 0) {
|
|
3942
3941
|
const parsed = Number(rawDecimals);
|
|
3943
|
-
if (!Number.isInteger(parsed) || parsed <
|
|
3942
|
+
if (!Number.isInteger(parsed) || parsed < import_sdk10.ASSET_DECIMALS_MIN || parsed > import_sdk10.ASSET_DECIMALS_MAX) {
|
|
3944
3943
|
throw new Error(`${cmdName}: ${labels.decimalsFlag} must be an integer in [0, 18] (got '${rawDecimals}').`);
|
|
3945
3944
|
}
|
|
3946
3945
|
decimals = parsed;
|
|
3947
3946
|
}
|
|
3948
3947
|
let symbol = resolved.symbol;
|
|
3949
3948
|
if (rawSymbol !== void 0) {
|
|
3950
|
-
if (rawSymbol.length
|
|
3949
|
+
if (rawSymbol.length < import_sdk10.ASSET_SYMBOL_MIN_LEN || rawSymbol.length > import_sdk10.ASSET_SYMBOL_MAX_LEN) {
|
|
3951
3950
|
throw new Error(`${cmdName}: ${labels.symbolFlag} must be 1-16 chars (got length ${rawSymbol.length}).`);
|
|
3952
3951
|
}
|
|
3953
3952
|
symbol = rawSymbol;
|
|
@@ -3961,9 +3960,10 @@ var DELEGATION_CURRENCY_FLAGS = {
|
|
|
3961
3960
|
};
|
|
3962
3961
|
|
|
3963
3962
|
// src/commands/delegations.ts
|
|
3963
|
+
var import_sdk11 = require("@heyanon-arp/sdk");
|
|
3964
3964
|
var import_chalk9 = __toESM(require("chalk"));
|
|
3965
3965
|
init_api();
|
|
3966
|
-
var ALLOWED_STATES = /* @__PURE__ */ new Set([
|
|
3966
|
+
var ALLOWED_STATES = /* @__PURE__ */ new Set([import_sdk11.DelegationStates.OFFERED, import_sdk11.DelegationStates.ACCEPTED, import_sdk11.DelegationStates.DECLINED, import_sdk11.DelegationStates.CANCELED]);
|
|
3967
3967
|
function registerDelegationsCommand(root) {
|
|
3968
3968
|
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
3969
|
"--verbose",
|
|
@@ -4022,7 +4022,7 @@ function formatDelegationLine(d, selfDid, opts = {}) {
|
|
|
4022
4022
|
const amount = formatAmount(d);
|
|
4023
4023
|
const title = d.title ? import_chalk9.default.dim(`"${truncate2(d.title, 40)}"`) : import_chalk9.default.dim("(no title)");
|
|
4024
4024
|
let declineSuffix = "";
|
|
4025
|
-
if (d.state ===
|
|
4025
|
+
if (d.state === import_sdk11.DelegationStates.DECLINED && d.declineReason) {
|
|
4026
4026
|
const detail = d.declineReasonDetail ? `: ${truncate2(d.declineReasonDetail, 40)}` : "";
|
|
4027
4027
|
declineSuffix = ` ${import_chalk9.default.dim(`(reason: ${d.declineReason}${detail})`)}`;
|
|
4028
4028
|
}
|
|
@@ -4037,34 +4037,34 @@ function colorState(s) {
|
|
|
4037
4037
|
// returns `undefined` and `formatDelegationLine` crashes with
|
|
4038
4038
|
// `TypeError: Cannot read properties of undefined (reading
|
|
4039
4039
|
// 'padEnd')` on any listing containing such a row.
|
|
4040
|
-
case
|
|
4040
|
+
case import_sdk11.DelegationStates.OFFERED:
|
|
4041
4041
|
return import_chalk9.default.yellow("offered");
|
|
4042
|
-
case
|
|
4042
|
+
case import_sdk11.DelegationStates.PENDING_LOCK_FINALIZATION:
|
|
4043
4043
|
return import_chalk9.default.yellow("pending_lock");
|
|
4044
|
-
case
|
|
4044
|
+
case import_sdk11.DelegationStates.ACCEPTED:
|
|
4045
4045
|
return import_chalk9.default.green("accepted");
|
|
4046
4046
|
// The on-chain escrow lock is confirmed. Distinct branch so a
|
|
4047
4047
|
// LOCKED row renders without hitting the defensive fallback
|
|
4048
4048
|
// (which would otherwise echo the raw state).
|
|
4049
|
-
case
|
|
4049
|
+
case import_sdk11.DelegationStates.LOCKED:
|
|
4050
4050
|
return import_chalk9.default.green("locked");
|
|
4051
|
-
case
|
|
4051
|
+
case import_sdk11.DelegationStates.DECLINED:
|
|
4052
4052
|
return import_chalk9.default.red("declined");
|
|
4053
|
-
case
|
|
4053
|
+
case import_sdk11.DelegationStates.CANCELED:
|
|
4054
4054
|
return import_chalk9.default.dim("canceled");
|
|
4055
4055
|
// Terminal escrow outcomes: completed = payee paid;
|
|
4056
4056
|
// failed = create_lock never landed; refunded = funds returned
|
|
4057
4057
|
// to the buyer (work expired / dispute closed);
|
|
4058
4058
|
// dispute_resolved = operator ruled.
|
|
4059
|
-
case
|
|
4059
|
+
case import_sdk11.DelegationStates.COMPLETED:
|
|
4060
4060
|
return import_chalk9.default.green("completed");
|
|
4061
|
-
case
|
|
4061
|
+
case import_sdk11.DelegationStates.FAILED:
|
|
4062
4062
|
return import_chalk9.default.red("failed");
|
|
4063
|
-
case
|
|
4063
|
+
case import_sdk11.DelegationStates.REFUNDED:
|
|
4064
4064
|
return import_chalk9.default.red("refunded");
|
|
4065
|
-
case
|
|
4065
|
+
case import_sdk11.DelegationStates.DISPUTING:
|
|
4066
4066
|
return import_chalk9.default.yellow("disputing");
|
|
4067
|
-
case
|
|
4067
|
+
case import_sdk11.DelegationStates.DISPUTE_RESOLVED:
|
|
4068
4068
|
return import_chalk9.default.red("dispute_resolved");
|
|
4069
4069
|
default: {
|
|
4070
4070
|
const _exhaustive = s;
|
|
@@ -4110,7 +4110,7 @@ function parseLimit2(raw) {
|
|
|
4110
4110
|
}
|
|
4111
4111
|
|
|
4112
4112
|
// src/commands/did-doc.ts
|
|
4113
|
-
var
|
|
4113
|
+
var import_sdk12 = require("@heyanon-arp/sdk");
|
|
4114
4114
|
init_api();
|
|
4115
4115
|
function registerDidDocCommand(root) {
|
|
4116
4116
|
root.command("did-doc").description(
|
|
@@ -4119,7 +4119,7 @@ function registerDidDocCommand(root) {
|
|
|
4119
4119
|
"--field <path>",
|
|
4120
4120
|
"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
4121
|
).action(async (did, opts) => {
|
|
4122
|
-
if (!(0,
|
|
4122
|
+
if (!(0, import_sdk12.isValidDid)(did)) {
|
|
4123
4123
|
throw new Error(`'${did}' is not a syntactically valid did:arp identifier`);
|
|
4124
4124
|
}
|
|
4125
4125
|
if (opts.json && opts.field !== void 0) {
|
|
@@ -4231,7 +4231,7 @@ function describeShape(value) {
|
|
|
4231
4231
|
}
|
|
4232
4232
|
|
|
4233
4233
|
// src/commands/doctor.ts
|
|
4234
|
-
var
|
|
4234
|
+
var import_sdk13 = require("@heyanon-arp/sdk");
|
|
4235
4235
|
var import_chalk10 = __toESM(require("chalk"));
|
|
4236
4236
|
init_api();
|
|
4237
4237
|
function registerDoctorCommand(root) {
|
|
@@ -4241,7 +4241,7 @@ function registerDoctorCommand(root) {
|
|
|
4241
4241
|
}
|
|
4242
4242
|
var LISTENING_THRESHOLD_SECONDS = 15 * 60;
|
|
4243
4243
|
async function runDoctor(did, opts) {
|
|
4244
|
-
if (!(0,
|
|
4244
|
+
if (!(0, import_sdk13.isValidDid)(did)) {
|
|
4245
4245
|
throw new Error(`'${did}' is not a syntactically valid did:arp identifier`);
|
|
4246
4246
|
}
|
|
4247
4247
|
const api = new ArpApiClient(opts.server);
|
|
@@ -4394,14 +4394,14 @@ function formatHints(event) {
|
|
|
4394
4394
|
}
|
|
4395
4395
|
|
|
4396
4396
|
// src/commands/escrow.ts
|
|
4397
|
-
var
|
|
4397
|
+
var import_sdk15 = require("@heyanon-arp/sdk");
|
|
4398
4398
|
var import_utils2 = require("@noble/hashes/utils");
|
|
4399
4399
|
var import_chalk12 = __toESM(require("chalk"));
|
|
4400
4400
|
init_api();
|
|
4401
4401
|
|
|
4402
4402
|
// src/commands/escrow-actions.ts
|
|
4403
4403
|
var import_node_crypto = require("crypto");
|
|
4404
|
-
var
|
|
4404
|
+
var import_sdk14 = require("@heyanon-arp/sdk");
|
|
4405
4405
|
var import_web33 = require("@solana/web3.js");
|
|
4406
4406
|
init_api();
|
|
4407
4407
|
var FEE_BUFFER_LAMPORTS = 10000000n;
|
|
@@ -4415,7 +4415,7 @@ async function setup(cmd, delegationIdArg, opts) {
|
|
|
4415
4415
|
const delegationId = normaliseDelegationId(delegationIdArg);
|
|
4416
4416
|
const fetched = await fetchLockAccount(conn, programId, delegationId);
|
|
4417
4417
|
if (!fetched) {
|
|
4418
|
-
const lockPda = deriveLockPda(programId, (0,
|
|
4418
|
+
const lockPda = deriveLockPda(programId, (0, import_sdk14.deriveLockId)(delegationId)).toBase58();
|
|
4419
4419
|
throw new Error(
|
|
4420
4420
|
`${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
4421
|
);
|
|
@@ -4440,7 +4440,7 @@ function nowSecs() {
|
|
|
4440
4440
|
function deadlinePassed(ctx) {
|
|
4441
4441
|
return ctx.lock.expiry > 0n && nowSecs() >= ctx.lock.expiry;
|
|
4442
4442
|
}
|
|
4443
|
-
var SYSTEM_PROGRAM_B58 =
|
|
4443
|
+
var SYSTEM_PROGRAM_B58 = import_sdk14.SYSTEM_PROGRAM_ID_BASE58;
|
|
4444
4444
|
function effectiveFeeRecipient(lock) {
|
|
4445
4445
|
if (lock.feeRecipientAtLock !== SYSTEM_PROGRAM_B58) return new import_web33.PublicKey(lock.feeRecipientAtLock);
|
|
4446
4446
|
if (lock.treasuryAtLock && lock.treasuryAtLock !== SYSTEM_PROGRAM_B58) return new import_web33.PublicKey(lock.treasuryAtLock);
|
|
@@ -4502,7 +4502,7 @@ function emit(ctx, action, signature, extra = {}) {
|
|
|
4502
4502
|
}
|
|
4503
4503
|
async function acceptHandler(delegationId, opts) {
|
|
4504
4504
|
const ctx = await setup("escrow accept", delegationId, opts);
|
|
4505
|
-
requireState(ctx, [
|
|
4505
|
+
requireState(ctx, [import_sdk14.LockStates.CREATED], "Accept is only possible before any other transition; if it shows in_progress you already accepted.");
|
|
4506
4506
|
requireSigner(ctx, "payee", ctx.lock.payee);
|
|
4507
4507
|
const stake = ctx.lock.workerStakeAtLock;
|
|
4508
4508
|
await preflightLamports(ctx, stake, `the worker stake (${stake} lamports, returned when the lock settles in your favour)`);
|
|
@@ -4512,7 +4512,7 @@ async function acceptHandler(delegationId, opts) {
|
|
|
4512
4512
|
}
|
|
4513
4513
|
async function submitWorkHandler(delegationId, opts) {
|
|
4514
4514
|
const ctx = await setup("escrow submit-work", delegationId, opts);
|
|
4515
|
-
requireState(ctx, [
|
|
4515
|
+
requireState(ctx, [import_sdk14.LockStates.IN_PROGRESS], "Submit needs an accepted lock ('created' \u2192 run `heyarp escrow accept` first; terminal \u2192 the cycle already ended).");
|
|
4516
4516
|
requireSigner(ctx, "payee", ctx.lock.payee);
|
|
4517
4517
|
if (deadlinePassed(ctx)) {
|
|
4518
4518
|
throw new Error(
|
|
@@ -4523,7 +4523,7 @@ async function submitWorkHandler(delegationId, opts) {
|
|
|
4523
4523
|
let reviewDeadline = null;
|
|
4524
4524
|
try {
|
|
4525
4525
|
const fresh = await fetchLockAccount(ctx.conn, ctx.programId, ctx.delegationId);
|
|
4526
|
-
if (fresh && fresh.lock.state ===
|
|
4526
|
+
if (fresh && fresh.lock.state === import_sdk14.LockStates.SUBMITTED && fresh.lock.expiry > 0n) {
|
|
4527
4527
|
reviewDeadline = new Date(Number(fresh.lock.expiry) * 1e3).toISOString();
|
|
4528
4528
|
}
|
|
4529
4529
|
} catch {
|
|
@@ -4536,22 +4536,25 @@ async function submitWorkHandler(delegationId, opts) {
|
|
|
4536
4536
|
}
|
|
4537
4537
|
async function claimHandler(delegationId, opts) {
|
|
4538
4538
|
const ctx = await setup("escrow claim", delegationId, opts);
|
|
4539
|
-
requireState(ctx, [
|
|
4539
|
+
requireState(ctx, [import_sdk14.LockStates.SUBMITTED], "Claim needs submitted work ('in_progress' \u2192 the worker must `escrow submit-work` first; 'paid' \u2192 already claimed).");
|
|
4540
4540
|
const me = ctx.keypair.publicKey.toBase58();
|
|
4541
4541
|
let role;
|
|
4542
4542
|
if (me === ctx.lock.payer) {
|
|
4543
|
-
role =
|
|
4543
|
+
role = import_sdk14.EscrowReleaseMethods.BUYER_APPROVED;
|
|
4544
4544
|
} else if (me === ctx.lock.payee) {
|
|
4545
4545
|
if (!deadlinePassed(ctx)) {
|
|
4546
4546
|
throw new Error(
|
|
4547
4547
|
`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
4548
|
);
|
|
4549
4549
|
}
|
|
4550
|
-
role =
|
|
4550
|
+
role = import_sdk14.EscrowReleaseMethods.REVIEW_TIMEOUT;
|
|
4551
4551
|
} else {
|
|
4552
4552
|
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
4553
|
}
|
|
4554
|
-
progress(
|
|
4554
|
+
progress(
|
|
4555
|
+
ctx.opts.json,
|
|
4556
|
+
role === import_sdk14.EscrowReleaseMethods.BUYER_APPROVED ? "approving payment as the buyer \u2014 this RELEASES the escrow and is irreversible" : "self-claiming after review timeout"
|
|
4557
|
+
);
|
|
4555
4558
|
const sig = await sendIx(
|
|
4556
4559
|
ctx,
|
|
4557
4560
|
buildClaimWorkPaymentIx({
|
|
@@ -4568,7 +4571,7 @@ async function claimHandler(delegationId, opts) {
|
|
|
4568
4571
|
}
|
|
4569
4572
|
async function cancelHandler(delegationId, opts) {
|
|
4570
4573
|
const ctx = await setup("escrow cancel", delegationId, opts);
|
|
4571
|
-
requireState(ctx, [
|
|
4574
|
+
requireState(ctx, [import_sdk14.LockStates.CREATED], "Cancel is the pre-accept exit only \u2014 once the worker accepted ('in_progress') the windows model governs.");
|
|
4572
4575
|
requireSigner(ctx, "payer", ctx.lock.payer);
|
|
4573
4576
|
const sig = await sendIx(
|
|
4574
4577
|
ctx,
|
|
@@ -4583,7 +4586,7 @@ async function cancelHandler(delegationId, opts) {
|
|
|
4583
4586
|
}
|
|
4584
4587
|
async function claimExpiredHandler(delegationId, opts) {
|
|
4585
4588
|
const ctx = await setup("escrow claim-expired", delegationId, opts);
|
|
4586
|
-
requireState(ctx, [
|
|
4589
|
+
requireState(ctx, [import_sdk14.LockStates.IN_PROGRESS], "Claim-expired recovers an accepted-but-never-submitted lock; 'submitted' work goes through claim/dispute instead.");
|
|
4587
4590
|
requireSigner(ctx, "payer", ctx.lock.payer);
|
|
4588
4591
|
if (!deadlinePassed(ctx)) {
|
|
4589
4592
|
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 +4604,7 @@ async function claimExpiredHandler(delegationId, opts) {
|
|
|
4601
4604
|
}
|
|
4602
4605
|
async function disputeOpenHandler(delegationId, opts) {
|
|
4603
4606
|
const ctx = await setup("escrow dispute open", delegationId, opts);
|
|
4604
|
-
requireState(ctx, [
|
|
4607
|
+
requireState(ctx, [import_sdk14.LockStates.SUBMITTED], "Disputes open against SUBMITTED work, inside the review window.");
|
|
4605
4608
|
requireSigner(ctx, "payer", ctx.lock.payer);
|
|
4606
4609
|
if (deadlinePassed(ctx)) {
|
|
4607
4610
|
throw new Error(
|
|
@@ -4616,7 +4619,7 @@ async function disputeOpenHandler(delegationId, opts) {
|
|
|
4616
4619
|
}
|
|
4617
4620
|
async function disputeCloseHandler(delegationId, opts) {
|
|
4618
4621
|
const ctx = await setup("escrow dispute close", delegationId, opts);
|
|
4619
|
-
requireState(ctx, [
|
|
4622
|
+
requireState(ctx, [import_sdk14.LockStates.DISPUTING], "Close only applies to an OPEN dispute that the operator never resolved.");
|
|
4620
4623
|
const me = ctx.keypair.publicKey.toBase58();
|
|
4621
4624
|
if (me !== ctx.lock.payer && me !== ctx.lock.payee) {
|
|
4622
4625
|
throw new Error(`escrow dispute close: your settlement key ${me} is neither party of this lock.`);
|
|
@@ -4641,7 +4644,7 @@ async function disputeCloseHandler(delegationId, opts) {
|
|
|
4641
4644
|
}
|
|
4642
4645
|
async function disputeResolveHandler(delegationId, opts) {
|
|
4643
4646
|
const ctx = await setup("escrow dispute resolve", delegationId, opts);
|
|
4644
|
-
requireState(ctx, [
|
|
4647
|
+
requireState(ctx, [import_sdk14.LockStates.DISPUTING], "Resolve only applies to an OPEN dispute, inside the dispute window.");
|
|
4645
4648
|
if (deadlinePassed(ctx)) {
|
|
4646
4649
|
throw new Error(
|
|
4647
4650
|
`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 +4688,7 @@ async function showHandler(delegationId, opts) {
|
|
|
4685
4688
|
jsonOut({
|
|
4686
4689
|
delegation_id: normalised.slice("del_".length),
|
|
4687
4690
|
lock_exists: false,
|
|
4688
|
-
lock_pda: deriveLockPda(programId, (0,
|
|
4691
|
+
lock_pda: deriveLockPda(programId, (0, import_sdk14.deriveLockId)(normalised)).toBase58(),
|
|
4689
4692
|
rpc_url: redactRpcUrl(rpcUrl)
|
|
4690
4693
|
});
|
|
4691
4694
|
return;
|
|
@@ -4762,7 +4765,7 @@ function registerEscrowCommands(root) {
|
|
|
4762
4765
|
"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
4766
|
).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
4767
|
"--currency <s>",
|
|
4765
|
-
`Asset identifier bound into the hash: shorthand (${
|
|
4768
|
+
`Asset identifier bound into the hash: shorthand (${import_sdk15.WELL_KNOWN_ASSET_KEYS.join("|")}) OR raw CAIP-19 string. Optional but must match the offer's --currency.`
|
|
4766
4769
|
).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
4770
|
await runDeriveConditionHash(opts);
|
|
4768
4771
|
});
|
|
@@ -4841,7 +4844,7 @@ async function runDeriveConditionHash(opts) {
|
|
|
4841
4844
|
progress(opts.json, import_chalk12.default.dim(`Server: ${api.serverUrl}`));
|
|
4842
4845
|
progress(opts.json, import_chalk12.default.dim(`Signer: ${sender.did}`));
|
|
4843
4846
|
const subset = projectDelegationForHash(cmdName, opts, delegationId);
|
|
4844
|
-
const hashBytes = (0,
|
|
4847
|
+
const hashBytes = (0, import_sdk15.deriveDelegationConditionHash)(subset);
|
|
4845
4848
|
const hex = (0, import_utils2.bytesToHex)(hashBytes);
|
|
4846
4849
|
if (opts.json) {
|
|
4847
4850
|
jsonOut({
|
|
@@ -4923,6 +4926,7 @@ async function runRecoverSequence(opts) {
|
|
|
4923
4926
|
}
|
|
4924
4927
|
|
|
4925
4928
|
// src/commands/events.ts
|
|
4929
|
+
var import_sdk16 = require("@heyanon-arp/sdk");
|
|
4926
4930
|
var import_chalk13 = __toESM(require("chalk"));
|
|
4927
4931
|
init_api();
|
|
4928
4932
|
function registerEventsCommand(root) {
|
|
@@ -4973,8 +4977,8 @@ async function runEvents(relationshipId, opts) {
|
|
|
4973
4977
|
}
|
|
4974
4978
|
const query = { limit };
|
|
4975
4979
|
if (since !== void 0) query.since = since;
|
|
4976
|
-
if (opts.successOnly) query.readModelStatus =
|
|
4977
|
-
else if (opts.rejectedOnly) query.readModelStatus =
|
|
4980
|
+
if (opts.successOnly) query.readModelStatus = import_sdk16.ReadModelStatuses.MATERIALIZED;
|
|
4981
|
+
else if (opts.rejectedOnly) query.readModelStatus = import_sdk16.ReadModelStatuses.REJECTED;
|
|
4978
4982
|
const signer = makeSigner(sender);
|
|
4979
4983
|
const events = await api.listEvents(relationshipId, signer, query);
|
|
4980
4984
|
if (opts.json) {
|
|
@@ -5009,8 +5013,8 @@ function formatEventLine(ev, selfDid, opts = {}) {
|
|
|
5009
5013
|
const hash = opts.fullIds ? ev.serverEventHash : hashHead(ev.serverEventHash);
|
|
5010
5014
|
const extra = extraDetail(ev);
|
|
5011
5015
|
const tail = extra ? ` ${import_chalk13.default.dim(`(${extra})`)}` : "";
|
|
5012
|
-
const status = ev.readModelStatus ??
|
|
5013
|
-
const statusGlyph = status ===
|
|
5016
|
+
const status = ev.readModelStatus ?? import_sdk16.ReadModelStatuses.MATERIALIZED;
|
|
5017
|
+
const statusGlyph = status === import_sdk16.ReadModelStatuses.REJECTED ? `${import_chalk13.default.red("\u2717")} ` : " ";
|
|
5014
5018
|
return `${statusGlyph}${idx} ${import_chalk13.default.cyan(eventId)} ${type} ${direction} ${import_chalk13.default.cyan(hash)}${tail}`;
|
|
5015
5019
|
}
|
|
5016
5020
|
function eventIdHead(eventId) {
|
|
@@ -6185,7 +6189,7 @@ function parseLimit4(raw) {
|
|
|
6185
6189
|
// src/commands/keys.ts
|
|
6186
6190
|
var import_node_crypto2 = require("crypto");
|
|
6187
6191
|
var import_node_fs7 = require("fs");
|
|
6188
|
-
var
|
|
6192
|
+
var import_sdk17 = require("@heyanon-arp/sdk");
|
|
6189
6193
|
var import_chalk17 = __toESM(require("chalk"));
|
|
6190
6194
|
function writeSecretFile(path, body) {
|
|
6191
6195
|
const tmp = `${path}.tmp.${(0, import_node_crypto2.randomBytes)(8).toString("hex")}`;
|
|
@@ -6213,19 +6217,19 @@ function writeSecretFile(path, body) {
|
|
|
6213
6217
|
function registerKeysCommand(root) {
|
|
6214
6218
|
const keys = root.command("keys").description("Local key utilities");
|
|
6215
6219
|
keys.command("gen").description("Generate a fresh identity + settlement keypair (no save by default)").action(() => {
|
|
6216
|
-
const identity = (0,
|
|
6217
|
-
const settlement = (0,
|
|
6220
|
+
const identity = (0, import_sdk17.generateKeyPair)();
|
|
6221
|
+
const settlement = (0, import_sdk17.generateKeyPair)();
|
|
6218
6222
|
const out = [
|
|
6219
6223
|
import_chalk17.default.bold("Identity key (Ed25519)"),
|
|
6220
|
-
` public (base58btc): ${import_chalk17.default.cyan((0,
|
|
6224
|
+
` public (base58btc): ${import_chalk17.default.cyan((0, import_sdk17.base58btcEncode)(identity.publicKey))}`,
|
|
6221
6225
|
` secret (base64) : ${import_chalk17.default.yellow(Buffer.from(identity.secretKey).toString("base64"))}`,
|
|
6222
6226
|
"",
|
|
6223
6227
|
import_chalk17.default.bold("Settlement key (Ed25519)"),
|
|
6224
|
-
` public (base58btc): ${import_chalk17.default.cyan((0,
|
|
6228
|
+
` public (base58btc): ${import_chalk17.default.cyan((0, import_sdk17.base58btcEncode)(settlement.publicKey))}`,
|
|
6225
6229
|
` secret (base64) : ${import_chalk17.default.yellow(Buffer.from(settlement.secretKey).toString("base64"))}`,
|
|
6226
6230
|
"",
|
|
6227
6231
|
import_chalk17.default.bold("Resulting DID"),
|
|
6228
|
-
` ${import_chalk17.default.cyan((0,
|
|
6232
|
+
` ${import_chalk17.default.cyan((0, import_sdk17.formatDid)(identity.publicKey))}`
|
|
6229
6233
|
];
|
|
6230
6234
|
console.log(out.join("\n"));
|
|
6231
6235
|
});
|
|
@@ -6244,10 +6248,10 @@ function registerKeysCommand(root) {
|
|
|
6244
6248
|
});
|
|
6245
6249
|
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
6250
|
const seed = decodeSeed(secretKeyB64);
|
|
6247
|
-
const pub = (0,
|
|
6248
|
-
const did = (0,
|
|
6251
|
+
const pub = (0, import_sdk17.getPublicKey)(seed);
|
|
6252
|
+
const did = (0, import_sdk17.formatDid)(pub);
|
|
6249
6253
|
console.log(`${import_chalk17.default.bold("DID")}: ${import_chalk17.default.cyan(did)}`);
|
|
6250
|
-
console.log(`${import_chalk17.default.bold("Identity public key (base58btc)")}: ${import_chalk17.default.cyan((0,
|
|
6254
|
+
console.log(`${import_chalk17.default.bold("Identity public key (base58btc)")}: ${import_chalk17.default.cyan((0, import_sdk17.base58btcEncode)(pub))}`);
|
|
6251
6255
|
});
|
|
6252
6256
|
}
|
|
6253
6257
|
function decodeSeed(b64) {
|
|
@@ -6266,8 +6270,12 @@ function decodeSeed(b64) {
|
|
|
6266
6270
|
// src/commands/list.ts
|
|
6267
6271
|
var import_chalk18 = __toESM(require("chalk"));
|
|
6268
6272
|
function registerListCommand(root) {
|
|
6269
|
-
root.command("list").description("List agents registered locally (~/.heyarp/agents.json)").action(() => {
|
|
6273
|
+
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
6274
|
const rows = listAgents();
|
|
6275
|
+
if (opts.json) {
|
|
6276
|
+
jsonOut(rows.map(({ serverUrl, agent }) => ({ serverUrl, did: agent.did, name: agent.name ?? null, tags: agent.tags ?? [], registeredAt: agent.registeredAt })));
|
|
6277
|
+
return;
|
|
6278
|
+
}
|
|
6271
6279
|
if (rows.length === 0) {
|
|
6272
6280
|
console.log(import_chalk18.default.dim(`No local agents. State file: ${stateFilePath()}`));
|
|
6273
6281
|
return;
|
|
@@ -6406,12 +6414,12 @@ function registerLogoutCommand(root) {
|
|
|
6406
6414
|
}
|
|
6407
6415
|
|
|
6408
6416
|
// src/commands/profile.ts
|
|
6409
|
-
var
|
|
6417
|
+
var import_sdk18 = require("@heyanon-arp/sdk");
|
|
6410
6418
|
var import_chalk21 = __toESM(require("chalk"));
|
|
6411
6419
|
init_api();
|
|
6412
6420
|
function registerProfileCommand(root) {
|
|
6413
6421
|
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,
|
|
6422
|
+
if (!(0, import_sdk18.isValidDid)(did)) {
|
|
6415
6423
|
throw new Error(`'${did}' is not a syntactically valid did:arp identifier`);
|
|
6416
6424
|
}
|
|
6417
6425
|
const api = new ArpApiClient(opts.server);
|
|
@@ -6439,7 +6447,7 @@ function registerProfileCommand(root) {
|
|
|
6439
6447
|
}
|
|
6440
6448
|
|
|
6441
6449
|
// src/commands/receipt.ts
|
|
6442
|
-
var
|
|
6450
|
+
var import_sdk19 = require("@heyanon-arp/sdk");
|
|
6443
6451
|
var import_shield2 = require("@heyanon-arp/shield");
|
|
6444
6452
|
var import_chalk22 = __toESM(require("chalk"));
|
|
6445
6453
|
init_api();
|
|
@@ -6447,35 +6455,6 @@ function registerReceiptCommands(root) {
|
|
|
6447
6455
|
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
6456
|
registerPropose(cmd);
|
|
6449
6457
|
}
|
|
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
6458
|
function registerPropose(parent) {
|
|
6480
6459
|
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-did>", "Recipient agent 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
6460
|
"--auto-hashes",
|
|
@@ -6675,7 +6654,7 @@ async function computeWorkLogHashes(api, sender, relationshipId, delegationId, r
|
|
|
6675
6654
|
`receipt propose --auto-hashes: no work-log row found for (relationshipId=${relationshipId}, delegationId=${delegationId}, requestId=${requestId}). Did the work_request envelope land yet?`
|
|
6676
6655
|
);
|
|
6677
6656
|
}
|
|
6678
|
-
if (workLog.state !==
|
|
6657
|
+
if (workLog.state !== import_sdk19.WorkLogStates.RESPONDED) {
|
|
6679
6658
|
throw new Error(
|
|
6680
6659
|
`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
6660
|
);
|
|
@@ -6691,27 +6670,27 @@ async function computeWorkLogHashes(api, sender, relationshipId, delegationId, r
|
|
|
6691
6670
|
};
|
|
6692
6671
|
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
6672
|
return {
|
|
6694
|
-
requestHash: (0,
|
|
6695
|
-
responseHash: (0,
|
|
6673
|
+
requestHash: (0, import_sdk19.canonicalSha256Hex)(requestBody),
|
|
6674
|
+
responseHash: (0, import_sdk19.canonicalSha256Hex)(responseBody)
|
|
6696
6675
|
};
|
|
6697
6676
|
}
|
|
6698
6677
|
async function sendReceiptEnvelope(args) {
|
|
6699
6678
|
const nextSequence = (args.sender.lastSenderSequence ?? 0) + 1;
|
|
6700
6679
|
const protectedBlock = {
|
|
6701
|
-
protocol_version:
|
|
6702
|
-
purpose:
|
|
6703
|
-
message_id: (0,
|
|
6680
|
+
protocol_version: import_sdk19.CURRENT_PROTOCOL_VERSION,
|
|
6681
|
+
purpose: import_sdk19.Purpose.ENVELOPE,
|
|
6682
|
+
message_id: (0, import_sdk19.uuidV4)(),
|
|
6704
6683
|
sender_did: args.sender.did,
|
|
6705
6684
|
recipient_did: args.recipientDid,
|
|
6706
6685
|
relationship_id: null,
|
|
6707
6686
|
sender_sequence: nextSequence,
|
|
6708
|
-
sender_nonce: (0,
|
|
6709
|
-
timestamp: (0,
|
|
6710
|
-
expires_at: (0,
|
|
6687
|
+
sender_nonce: (0, import_sdk19.senderNonce)(),
|
|
6688
|
+
timestamp: (0, import_sdk19.rfc3339)(),
|
|
6689
|
+
expires_at: (0, import_sdk19.expiresAt)(args.ttlSeconds),
|
|
6711
6690
|
delivery_id: null
|
|
6712
6691
|
};
|
|
6713
6692
|
const signer = makeSigner(args.sender);
|
|
6714
|
-
const envelope = (0,
|
|
6693
|
+
const envelope = (0, import_sdk19.signEnvelope)({
|
|
6715
6694
|
protected: protectedBlock,
|
|
6716
6695
|
body: args.body,
|
|
6717
6696
|
identitySecretKey: signer.identitySecretKey,
|
|
@@ -6726,7 +6705,7 @@ async function sendReceiptEnvelope(args) {
|
|
|
6726
6705
|
updateAgentLocal(args.server, args.sender.did, { lastSenderSequence: nextSequence });
|
|
6727
6706
|
return result;
|
|
6728
6707
|
} catch (err) {
|
|
6729
|
-
if (err instanceof ApiError &&
|
|
6708
|
+
if (err instanceof ApiError && (0, import_sdk19.isPostCommitErrorCode)(err.payload.code)) {
|
|
6730
6709
|
updateAgentLocal(args.server, args.sender.did, { lastSenderSequence: nextSequence });
|
|
6731
6710
|
}
|
|
6732
6711
|
throw err;
|
|
@@ -6741,9 +6720,9 @@ function printIngestResult2(result) {
|
|
|
6741
6720
|
console.log(`${import_chalk22.default.bold("Server event hash")}: ${import_chalk22.default.cyan(result.serverEventHash)}`);
|
|
6742
6721
|
}
|
|
6743
6722
|
function parseVerdict(cmdName, raw) {
|
|
6744
|
-
if (raw === void 0 || raw === "") return
|
|
6745
|
-
if (!
|
|
6746
|
-
throw new Error(`${cmdName}: --verdict must be one of ${
|
|
6723
|
+
if (raw === void 0 || raw === "") return import_sdk19.ReceiptVerdicts.ACCEPTED;
|
|
6724
|
+
if (!import_sdk19.RECEIPT_VERDICTS.includes(raw)) {
|
|
6725
|
+
throw new Error(`${cmdName}: --verdict must be one of ${import_sdk19.RECEIPT_VERDICTS.join(" | ")} (got '${raw}')`);
|
|
6747
6726
|
}
|
|
6748
6727
|
return raw;
|
|
6749
6728
|
}
|
|
@@ -6780,7 +6759,7 @@ function requireUuid3(cmdName, raw, label) {
|
|
|
6780
6759
|
requireUuid(cmdName, raw, label);
|
|
6781
6760
|
}
|
|
6782
6761
|
function requireSha256(cmdName, raw, label) {
|
|
6783
|
-
if (!
|
|
6762
|
+
if (!(0, import_sdk19.isSha256Hex)(raw)) {
|
|
6784
6763
|
throw new Error(`${cmdName}: ${label} must match 'sha256:<64 lowercase hex>' (got '${raw}')`);
|
|
6785
6764
|
}
|
|
6786
6765
|
}
|
|
@@ -6791,6 +6770,7 @@ function requireDid2(cmdName, did, label) {
|
|
|
6791
6770
|
}
|
|
6792
6771
|
|
|
6793
6772
|
// src/commands/receipts.ts
|
|
6773
|
+
var import_sdk20 = require("@heyanon-arp/sdk");
|
|
6794
6774
|
var import_chalk23 = __toESM(require("chalk"));
|
|
6795
6775
|
init_api();
|
|
6796
6776
|
function registerReceiptsCommand(root) {
|
|
@@ -6862,11 +6842,11 @@ function formatReceiptLine(r, selfDid, opts = {}) {
|
|
|
6862
6842
|
}
|
|
6863
6843
|
function formatVerdict(r) {
|
|
6864
6844
|
switch (r.verdictProposed) {
|
|
6865
|
-
case
|
|
6845
|
+
case import_sdk20.ReceiptVerdicts.ACCEPTED:
|
|
6866
6846
|
return import_chalk23.default.green("accepted");
|
|
6867
|
-
case
|
|
6847
|
+
case import_sdk20.ReceiptVerdicts.ACCEPTED_WITH_NOTES:
|
|
6868
6848
|
return import_chalk23.default.yellow("accepted_with_notes");
|
|
6869
|
-
case
|
|
6849
|
+
case import_sdk20.ReceiptVerdicts.REJECTED:
|
|
6870
6850
|
return import_chalk23.default.red("rejected");
|
|
6871
6851
|
}
|
|
6872
6852
|
}
|
|
@@ -6893,7 +6873,7 @@ function parseLimit5(raw) {
|
|
|
6893
6873
|
|
|
6894
6874
|
// src/commands/recover.ts
|
|
6895
6875
|
var import_node_fs8 = require("fs");
|
|
6896
|
-
var
|
|
6876
|
+
var import_sdk21 = require("@heyanon-arp/sdk");
|
|
6897
6877
|
var import_chalk24 = __toESM(require("chalk"));
|
|
6898
6878
|
init_api();
|
|
6899
6879
|
function registerRecoverCommand(root) {
|
|
@@ -6914,18 +6894,18 @@ async function runRecover(opts) {
|
|
|
6914
6894
|
}
|
|
6915
6895
|
const bundle = validateKeyBundle(raw);
|
|
6916
6896
|
const identitySecret = new Uint8Array(Buffer.from(bundle.identitySecretKeyB64, "base64"));
|
|
6917
|
-
const identityPub = (0,
|
|
6918
|
-
const derivedDid = (0,
|
|
6897
|
+
const identityPub = (0, import_sdk21.base58btcDecode)(bundle.identityPublicKeyB58);
|
|
6898
|
+
const derivedDid = (0, import_sdk21.formatDid)(identityPub);
|
|
6919
6899
|
if (derivedDid !== bundle.did) {
|
|
6920
6900
|
throw new Error(`recover: key file is inconsistent \u2014 its DID (${bundle.did}) does not match its identity public key (${derivedDid})`);
|
|
6921
6901
|
}
|
|
6922
6902
|
const probe2 = new TextEncoder().encode("heyarp-recover-keycheck");
|
|
6923
|
-
if (!(0,
|
|
6903
|
+
if (!(0, import_sdk21.verify)((0, import_sdk21.sign)(probe2, identitySecret), probe2, identityPub)) {
|
|
6924
6904
|
throw new Error("recover: the identity secret key does not match the public key in this bundle");
|
|
6925
6905
|
}
|
|
6926
6906
|
const settlementSecret = new Uint8Array(Buffer.from(bundle.settlementSecretKeyB64, "base64"));
|
|
6927
|
-
const settlementPub = (0,
|
|
6928
|
-
if (!(0,
|
|
6907
|
+
const settlementPub = (0, import_sdk21.base58btcDecode)(bundle.settlementPublicKeyB58);
|
|
6908
|
+
if (!(0, import_sdk21.verify)((0, import_sdk21.sign)(probe2, settlementSecret), probe2, settlementPub)) {
|
|
6929
6909
|
throw new Error("recover: the settlement secret key does not match the settlement public key in this bundle");
|
|
6930
6910
|
}
|
|
6931
6911
|
if (bundle.ownerWallet && bundle.ownerWallet !== credential.wallet) {
|
|
@@ -6981,7 +6961,7 @@ async function runRecover(opts) {
|
|
|
6981
6961
|
// src/commands/register.ts
|
|
6982
6962
|
var import_node_crypto4 = require("crypto");
|
|
6983
6963
|
var import_node_fs9 = require("fs");
|
|
6984
|
-
var
|
|
6964
|
+
var import_sdk22 = require("@heyanon-arp/sdk");
|
|
6985
6965
|
var import_chalk25 = __toESM(require("chalk"));
|
|
6986
6966
|
var import_prompts2 = __toESM(require("prompts"));
|
|
6987
6967
|
init_api();
|
|
@@ -7043,37 +7023,37 @@ async function runRegister(opts, deps = defaultRegisterDeps) {
|
|
|
7043
7023
|
warnIfOrphanHomesPresent();
|
|
7044
7024
|
}
|
|
7045
7025
|
const keys = opts.fromKeys ? loadKeysFromFile(opts.fromKeys) : freshKeys();
|
|
7046
|
-
const did = (0,
|
|
7026
|
+
const did = (0, import_sdk22.formatDid)(keys.identityPublicKey);
|
|
7047
7027
|
if (!opts.json) console.log(import_chalk25.default.dim(`DID will be: ${did}`));
|
|
7048
7028
|
const answers = await mergeAnswers(opts);
|
|
7049
7029
|
const scryptSalt = (0, import_node_crypto4.randomBytes)(16);
|
|
7050
7030
|
if (!opts.json) console.log(import_chalk25.default.dim("Deriving scrypt key, this may take a moment..."));
|
|
7051
|
-
const scryptKey = (0,
|
|
7031
|
+
const scryptKey = (0, import_sdk22.deriveScryptKey)(answers.password, new Uint8Array(scryptSalt));
|
|
7052
7032
|
const challenge = await api.issueChallenge("register");
|
|
7053
7033
|
const challengeBytes = base64UrlNoPadDecode(challenge.challengeB64);
|
|
7054
7034
|
if (challengeBytes.length !== 32) {
|
|
7055
7035
|
throw new Error(`Server returned a ${challengeBytes.length}-byte challenge; expected 32`);
|
|
7056
7036
|
}
|
|
7057
|
-
const challengeSig = (0,
|
|
7058
|
-
const identityPublicKeyB58 = (0,
|
|
7037
|
+
const challengeSig = (0, import_sdk22.signChallenge)(challengeBytes, keys.identitySecretKey);
|
|
7038
|
+
const identityPublicKeyB58 = (0, import_sdk22.base58btcEncode)(keys.identityPublicKey);
|
|
7059
7039
|
await api.submitChallengeResponse({
|
|
7060
7040
|
challengeId: challenge.challengeId,
|
|
7061
7041
|
identityPublicKey: identityPublicKeyB58,
|
|
7062
7042
|
signature: Buffer.from(challengeSig).toString("base64")
|
|
7063
7043
|
});
|
|
7064
|
-
const settlementPublicKeyB58 = (0,
|
|
7065
|
-
const scryptSaltId = (0,
|
|
7044
|
+
const settlementPublicKeyB58 = (0, import_sdk22.base58btcEncode)(keys.settlementPublicKey);
|
|
7045
|
+
const scryptSaltId = (0, import_sdk22.uuidV4)();
|
|
7066
7046
|
const payload = {
|
|
7067
|
-
purpose:
|
|
7047
|
+
purpose: import_sdk22.Purpose.KEY_LINK,
|
|
7068
7048
|
agent_did: did,
|
|
7069
7049
|
identity_public_key: identityPublicKeyB58,
|
|
7070
7050
|
settlement_public_key: settlementPublicKeyB58,
|
|
7071
|
-
owner_signing_method:
|
|
7051
|
+
owner_signing_method: import_sdk22.OWNER_SIGNING_METHODS[0],
|
|
7072
7052
|
link_method: "manual",
|
|
7073
|
-
created_at: (0,
|
|
7074
|
-
nonce: (0,
|
|
7053
|
+
created_at: (0, import_sdk22.rfc3339)(),
|
|
7054
|
+
nonce: (0, import_sdk22.senderNonce)()
|
|
7075
7055
|
};
|
|
7076
|
-
const attestation = (0,
|
|
7056
|
+
const attestation = (0, import_sdk22.signKeyLinkAttestation)({ payload, scryptKey, scryptSaltId });
|
|
7077
7057
|
const body = {
|
|
7078
7058
|
challengeId: challenge.challengeId,
|
|
7079
7059
|
identityPublicKey: identityPublicKeyB58,
|
|
@@ -7116,7 +7096,7 @@ async function runRegister(opts, deps = defaultRegisterDeps) {
|
|
|
7116
7096
|
try {
|
|
7117
7097
|
result = await api.register(body, credential.token);
|
|
7118
7098
|
} catch (err) {
|
|
7119
|
-
if (err instanceof ApiError && (err.payload.code ===
|
|
7099
|
+
if (err instanceof ApiError && (err.payload.code === import_sdk22.CliAuthTokenErrorCodes.INVALID || err.payload.code === import_sdk22.CliAuthTokenErrorCodes.REQUIRED)) {
|
|
7120
7100
|
throw new Error(
|
|
7121
7101
|
`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
7102
|
);
|
|
@@ -7272,8 +7252,8 @@ function parseTagsCsv(raw) {
|
|
|
7272
7252
|
return raw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
7273
7253
|
}
|
|
7274
7254
|
function freshKeys() {
|
|
7275
|
-
const identity = (0,
|
|
7276
|
-
const settlement = (0,
|
|
7255
|
+
const identity = (0, import_sdk22.generateKeyPair)();
|
|
7256
|
+
const settlement = (0, import_sdk22.generateKeyPair)();
|
|
7277
7257
|
return {
|
|
7278
7258
|
identityPublicKey: identity.publicKey,
|
|
7279
7259
|
identitySecretKey: identity.secretKey,
|
|
@@ -7299,9 +7279,9 @@ function loadKeysFromFile(path) {
|
|
|
7299
7279
|
if (identitySecret.length !== 32) throw new Error("--from-keys: identitySecretKeyB64 is not a 32-byte Ed25519 seed");
|
|
7300
7280
|
if (settlementSecret.length !== 32) throw new Error("--from-keys: settlementSecretKeyB64 is not a 32-byte Ed25519 seed");
|
|
7301
7281
|
return {
|
|
7302
|
-
identityPublicKey: (0,
|
|
7282
|
+
identityPublicKey: (0, import_sdk22.getPublicKey)(identitySecret),
|
|
7303
7283
|
identitySecretKey: identitySecret,
|
|
7304
|
-
settlementPublicKey: (0,
|
|
7284
|
+
settlementPublicKey: (0, import_sdk22.getPublicKey)(settlementSecret),
|
|
7305
7285
|
settlementSecretKey: settlementSecret
|
|
7306
7286
|
};
|
|
7307
7287
|
}
|
|
@@ -7317,17 +7297,27 @@ function assertJsonRequiresYes(opts) {
|
|
|
7317
7297
|
}
|
|
7318
7298
|
|
|
7319
7299
|
// src/commands/relationships.ts
|
|
7300
|
+
var import_sdk23 = require("@heyanon-arp/sdk");
|
|
7320
7301
|
var import_chalk26 = __toESM(require("chalk"));
|
|
7321
7302
|
init_api();
|
|
7322
|
-
var ALLOWED_STATES2 =
|
|
7303
|
+
var ALLOWED_STATES2 = new Set(import_sdk23.RELATIONSHIP_STATE_NAMES);
|
|
7323
7304
|
function registerRelationshipsCommand(root) {
|
|
7324
7305
|
root.command("relationships").description(
|
|
7325
7306
|
"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
|
|
7307
|
+
).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(
|
|
7308
|
+
"--json",
|
|
7309
|
+
"Machine-readable mode \u2014 emit the relationships as a single JSON array on stdout (RelationshipPublic[]). Prelude + table move to stderr. Mutually exclusive with --verbose.",
|
|
7310
|
+
false
|
|
7311
|
+
).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
7312
|
await runRelationships(did, opts);
|
|
7328
7313
|
});
|
|
7329
7314
|
}
|
|
7330
7315
|
async function runRelationships(positionalDid, opts) {
|
|
7316
|
+
if (opts.verbose && opts.json) {
|
|
7317
|
+
throw new Error(
|
|
7318
|
+
"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`."
|
|
7319
|
+
);
|
|
7320
|
+
}
|
|
7331
7321
|
const limit = parseLimit6(opts.limit);
|
|
7332
7322
|
const state = parseState2(opts.state);
|
|
7333
7323
|
if (positionalDid !== void 0 && opts.fromDid !== void 0 && positionalDid !== opts.fromDid) {
|
|
@@ -7337,12 +7327,16 @@ async function runRelationships(positionalDid, opts) {
|
|
|
7337
7327
|
const local = explicitDid !== void 0 ? loadAgentOrThrow(opts.server, explicitDid) : resolveSenderAgent("relationships", opts.server, void 0);
|
|
7338
7328
|
const did = local.did;
|
|
7339
7329
|
const api = new ArpApiClient(opts.server);
|
|
7340
|
-
|
|
7341
|
-
|
|
7330
|
+
progress(opts.json, import_chalk26.default.dim(`Server: ${api.serverUrl}`));
|
|
7331
|
+
progress(opts.json, import_chalk26.default.dim(`Signer: ${local.did}`));
|
|
7342
7332
|
const query = { limit };
|
|
7343
7333
|
if (state) query.state = state;
|
|
7344
7334
|
const signer = makeSigner(local);
|
|
7345
7335
|
const rows = await api.listRelationships(did, signer, query);
|
|
7336
|
+
if (opts.json) {
|
|
7337
|
+
jsonOut(rows);
|
|
7338
|
+
return;
|
|
7339
|
+
}
|
|
7346
7340
|
if (rows.length === 0) {
|
|
7347
7341
|
console.log(import_chalk26.default.dim("\n(no relationships)"));
|
|
7348
7342
|
return;
|
|
@@ -7387,12 +7381,12 @@ function parseLimit6(raw) {
|
|
|
7387
7381
|
}
|
|
7388
7382
|
|
|
7389
7383
|
// src/commands/reputation.ts
|
|
7390
|
-
var
|
|
7384
|
+
var import_sdk24 = require("@heyanon-arp/sdk");
|
|
7391
7385
|
var import_chalk27 = __toESM(require("chalk"));
|
|
7392
7386
|
init_api();
|
|
7393
7387
|
function registerReputationCommand(root) {
|
|
7394
7388
|
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,
|
|
7389
|
+
if (!(0, import_sdk24.isValidDid)(did)) {
|
|
7396
7390
|
throw new Error(`'${did}' is not a syntactically valid did:arp identifier`);
|
|
7397
7391
|
}
|
|
7398
7392
|
const api = new ArpApiClient(opts.server);
|
|
@@ -7434,11 +7428,11 @@ function bar(score) {
|
|
|
7434
7428
|
}
|
|
7435
7429
|
|
|
7436
7430
|
// src/commands/send-handshake.ts
|
|
7437
|
-
var
|
|
7431
|
+
var import_sdk25 = require("@heyanon-arp/sdk");
|
|
7438
7432
|
var import_chalk28 = __toESM(require("chalk"));
|
|
7439
7433
|
init_api();
|
|
7440
7434
|
function registerSendHandshakeCommand(root) {
|
|
7441
|
-
root.command("send-handshake").description("Send a handshake envelope to <recipient-did>. Server creates the relationship row on first contact.").argument("<recipient-did>", "Recipient agent 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>",
|
|
7435
|
+
root.command("send-handshake").description("Send a handshake envelope to <recipient-did>. Server creates the relationship row on first contact.").argument("<recipient-did>", "Recipient agent 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_sdk25.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
7436
|
"--json",
|
|
7443
7437
|
"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
7438
|
false
|
|
@@ -7447,8 +7441,8 @@ function registerSendHandshakeCommand(root) {
|
|
|
7447
7441
|
});
|
|
7448
7442
|
}
|
|
7449
7443
|
async function runSendHandshake(recipientDid, opts) {
|
|
7450
|
-
if (!
|
|
7451
|
-
throw new Error(`send-handshake: <recipient-did> must
|
|
7444
|
+
if (!(0, import_sdk25.isValidDid)(recipientDid)) {
|
|
7445
|
+
throw new Error(`send-handshake: <recipient-did> must be a valid did:arp identifier (base58btc-encoded 32-byte Ed25519 pubkey) (got '${recipientDid}')`);
|
|
7452
7446
|
}
|
|
7453
7447
|
if (opts.verbose && opts.json) {
|
|
7454
7448
|
throw new Error(
|
|
@@ -7467,20 +7461,20 @@ async function runSendHandshake(recipientDid, opts) {
|
|
|
7467
7461
|
const body = { type: "handshake", content };
|
|
7468
7462
|
const nextSequence = (sender.lastSenderSequence ?? 0) + 1;
|
|
7469
7463
|
const protectedBlock = {
|
|
7470
|
-
protocol_version:
|
|
7471
|
-
purpose:
|
|
7472
|
-
message_id: (0,
|
|
7464
|
+
protocol_version: import_sdk25.CURRENT_PROTOCOL_VERSION,
|
|
7465
|
+
purpose: import_sdk25.Purpose.ENVELOPE,
|
|
7466
|
+
message_id: (0, import_sdk25.uuidV4)(),
|
|
7473
7467
|
sender_did: sender.did,
|
|
7474
7468
|
recipient_did: recipientDid,
|
|
7475
7469
|
relationship_id: null,
|
|
7476
7470
|
sender_sequence: nextSequence,
|
|
7477
|
-
sender_nonce: (0,
|
|
7478
|
-
timestamp: (0,
|
|
7479
|
-
expires_at: (0,
|
|
7471
|
+
sender_nonce: (0, import_sdk25.senderNonce)(),
|
|
7472
|
+
timestamp: (0, import_sdk25.rfc3339)(),
|
|
7473
|
+
expires_at: (0, import_sdk25.expiresAt)(ttlSeconds),
|
|
7480
7474
|
delivery_id: null
|
|
7481
7475
|
};
|
|
7482
7476
|
const signer = makeSigner(sender);
|
|
7483
|
-
const envelope = (0,
|
|
7477
|
+
const envelope = (0, import_sdk25.signEnvelope)({
|
|
7484
7478
|
protected: protectedBlock,
|
|
7485
7479
|
body,
|
|
7486
7480
|
identitySecretKey: signer.identitySecretKey
|
|
@@ -7494,6 +7488,7 @@ async function runSendHandshake(recipientDid, opts) {
|
|
|
7494
7488
|
if (opts.json) {
|
|
7495
7489
|
jsonOut({
|
|
7496
7490
|
ok: true,
|
|
7491
|
+
action: "handshake",
|
|
7497
7492
|
eventId: result.eventId,
|
|
7498
7493
|
relationshipId: result.relationshipId,
|
|
7499
7494
|
relationshipEventIndex: result.relationshipEventIndex,
|
|
@@ -7532,15 +7527,12 @@ function parseTtl3(raw) {
|
|
|
7532
7527
|
}
|
|
7533
7528
|
return n;
|
|
7534
7529
|
}
|
|
7535
|
-
function isDid(s) {
|
|
7536
|
-
return typeof s === "string" && s.startsWith("did:arp:") && s.length > "did:arp:".length;
|
|
7537
|
-
}
|
|
7538
7530
|
|
|
7539
7531
|
// src/commands/send-handshake-response.ts
|
|
7540
|
-
var
|
|
7532
|
+
var import_sdk26 = require("@heyanon-arp/sdk");
|
|
7541
7533
|
var import_chalk29 = __toESM(require("chalk"));
|
|
7542
7534
|
init_api();
|
|
7543
|
-
var ALLOWED_DECISIONS =
|
|
7535
|
+
var ALLOWED_DECISIONS = new Set(import_sdk26.HANDSHAKE_DECISIONS);
|
|
7544
7536
|
function registerSendHandshakeResponseCommand(root) {
|
|
7545
7537
|
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
7538
|
"--reason <code>",
|
|
@@ -7548,8 +7540,8 @@ function registerSendHandshakeResponseCommand(root) {
|
|
|
7548
7540
|
// We don't use commander's requiredOption because it
|
|
7549
7541
|
// would fire for the accept path too; validate manually
|
|
7550
7542
|
// 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>",
|
|
7543
|
+
`When --decision=decline: required reason code (one of: ${import_sdk26.DECLINE_REASONS.join(", ")}). Carried in body.content.reason.`
|
|
7544
|
+
).option("--reason-detail <s>", "Optional free-text elaboration alongside --reason (max 512 chars).").option("--ttl <seconds>", `Envelope TTL in seconds (max ${import_sdk26.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
7545
|
"--json",
|
|
7554
7546
|
"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
7547
|
false
|
|
@@ -7567,13 +7559,13 @@ async function runSendHandshakeResponse(recipientDid, opts) {
|
|
|
7567
7559
|
"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
7560
|
);
|
|
7569
7561
|
}
|
|
7570
|
-
if (!
|
|
7571
|
-
throw new Error(`send-handshake-response: <recipient-did> must
|
|
7562
|
+
if (!(0, import_sdk26.isValidDid)(recipientDid)) {
|
|
7563
|
+
throw new Error(`send-handshake-response: <recipient-did> must be a valid did:arp identifier (base58btc-encoded 32-byte Ed25519 pubkey) (got '${recipientDid}')`);
|
|
7572
7564
|
}
|
|
7573
7565
|
const decision = parseDecision(opts.decision);
|
|
7574
7566
|
const ttlSeconds = parseTtl4(opts.ttl);
|
|
7575
7567
|
let declinePayload = null;
|
|
7576
|
-
if (decision ===
|
|
7568
|
+
if (decision === import_sdk26.HandshakeDecisions.DECLINE) {
|
|
7577
7569
|
const reason = parseDeclineReason("send-handshake-response", opts.reason);
|
|
7578
7570
|
const detail = parseReasonDetail("send-handshake-response", opts.reasonDetail);
|
|
7579
7571
|
declinePayload = detail ? { reason, reasonDetail: detail } : { reason };
|
|
@@ -7599,6 +7591,7 @@ async function runSendHandshakeResponse(recipientDid, opts) {
|
|
|
7599
7591
|
if (opts.json) {
|
|
7600
7592
|
jsonOut({
|
|
7601
7593
|
ok: true,
|
|
7594
|
+
action: "handshake_response",
|
|
7602
7595
|
idempotent: true,
|
|
7603
7596
|
decision,
|
|
7604
7597
|
eventId: previousResponseFromMe.eventId,
|
|
@@ -7641,19 +7634,19 @@ async function runSendHandshakeResponse(recipientDid, opts) {
|
|
|
7641
7634
|
const body = { type: "handshake_response", content };
|
|
7642
7635
|
const nextSequence = (sender.lastSenderSequence ?? 0) + 1;
|
|
7643
7636
|
const protectedBlock = {
|
|
7644
|
-
protocol_version:
|
|
7645
|
-
purpose:
|
|
7646
|
-
message_id: (0,
|
|
7637
|
+
protocol_version: import_sdk26.CURRENT_PROTOCOL_VERSION,
|
|
7638
|
+
purpose: import_sdk26.Purpose.ENVELOPE,
|
|
7639
|
+
message_id: (0, import_sdk26.uuidV4)(),
|
|
7647
7640
|
sender_did: sender.did,
|
|
7648
7641
|
recipient_did: recipientDid,
|
|
7649
7642
|
relationship_id: null,
|
|
7650
7643
|
sender_sequence: nextSequence,
|
|
7651
|
-
sender_nonce: (0,
|
|
7652
|
-
timestamp: (0,
|
|
7653
|
-
expires_at: (0,
|
|
7644
|
+
sender_nonce: (0, import_sdk26.senderNonce)(),
|
|
7645
|
+
timestamp: (0, import_sdk26.rfc3339)(),
|
|
7646
|
+
expires_at: (0, import_sdk26.expiresAt)(ttlSeconds),
|
|
7654
7647
|
delivery_id: null
|
|
7655
7648
|
};
|
|
7656
|
-
const envelope = (0,
|
|
7649
|
+
const envelope = (0, import_sdk26.signEnvelope)({
|
|
7657
7650
|
protected: protectedBlock,
|
|
7658
7651
|
body,
|
|
7659
7652
|
identitySecretKey: signer.identitySecretKey
|
|
@@ -7667,6 +7660,7 @@ async function runSendHandshakeResponse(recipientDid, opts) {
|
|
|
7667
7660
|
if (opts.json) {
|
|
7668
7661
|
jsonOut({
|
|
7669
7662
|
ok: true,
|
|
7663
|
+
action: "handshake_response",
|
|
7670
7664
|
decision,
|
|
7671
7665
|
eventId: result.eventId,
|
|
7672
7666
|
relationshipId: result.relationshipId,
|
|
@@ -7715,13 +7709,10 @@ function parseTtl4(raw) {
|
|
|
7715
7709
|
}
|
|
7716
7710
|
return n;
|
|
7717
7711
|
}
|
|
7718
|
-
function isDid2(s) {
|
|
7719
|
-
return typeof s === "string" && s.startsWith("did:arp:") && s.length > "did:arp:".length;
|
|
7720
|
-
}
|
|
7721
7712
|
function classifyIdempotencyOutcome(decision, existing) {
|
|
7722
7713
|
if (!existing) return { kind: "proceed" };
|
|
7723
|
-
if (existing.state ===
|
|
7724
|
-
if (decision ===
|
|
7714
|
+
if (existing.state === import_sdk26.RelationshipStates.ACTIVE) {
|
|
7715
|
+
if (decision === import_sdk26.HandshakeDecisions.DECLINE) {
|
|
7725
7716
|
return {
|
|
7726
7717
|
kind: "error",
|
|
7727
7718
|
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 +7720,7 @@ function classifyIdempotencyOutcome(decision, existing) {
|
|
|
7729
7720
|
}
|
|
7730
7721
|
return { kind: "short-circuit" };
|
|
7731
7722
|
}
|
|
7732
|
-
if (existing.state ===
|
|
7723
|
+
if (existing.state === import_sdk26.RelationshipStates.CLOSED) {
|
|
7733
7724
|
return {
|
|
7734
7725
|
kind: "error",
|
|
7735
7726
|
message: `send-handshake-response: relationship ${existing.relationshipId} is CLOSED. Cannot respond to handshake on a terminated relationship \u2014 start a fresh handshake instead.`
|
|
@@ -7919,7 +7910,7 @@ function registerWhoamiCommand(root) {
|
|
|
7919
7910
|
}
|
|
7920
7911
|
|
|
7921
7912
|
// src/commands/work.ts
|
|
7922
|
-
var
|
|
7913
|
+
var import_sdk27 = require("@heyanon-arp/sdk");
|
|
7923
7914
|
var import_chalk32 = __toESM(require("chalk"));
|
|
7924
7915
|
init_api();
|
|
7925
7916
|
function registerWorkCommands(root) {
|
|
@@ -7927,25 +7918,6 @@ function registerWorkCommands(root) {
|
|
|
7927
7918
|
registerRequest(cmd);
|
|
7928
7919
|
registerRespond(cmd);
|
|
7929
7920
|
}
|
|
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
7921
|
function registerRequest(parent) {
|
|
7950
7922
|
parent.command("request").description("Send a work_request to <recipient-did> under <delegation-id> (must be ACCEPTED).").argument("<recipient-did>", "Recipient agent 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
7923
|
"--params <json>",
|
|
@@ -7953,11 +7925,20 @@ function registerRequest(parent) {
|
|
|
7953
7925
|
).option(
|
|
7954
7926
|
"--params-file <path>",
|
|
7955
7927
|
"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>",
|
|
7928
|
+
).option("--ttl <seconds>", `Envelope TTL in seconds (max ${import_sdk27.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(
|
|
7929
|
+
"--json",
|
|
7930
|
+
'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.',
|
|
7931
|
+
false
|
|
7932
|
+
).action(async (recipientDid, delegationId, opts) => {
|
|
7957
7933
|
await runRequest(recipientDid, delegationId, opts);
|
|
7958
7934
|
});
|
|
7959
7935
|
}
|
|
7960
7936
|
async function runRequest(recipientDid, delegationId, opts) {
|
|
7937
|
+
if (opts.verbose && opts.json) {
|
|
7938
|
+
throw new Error(
|
|
7939
|
+
"work request: --verbose and --json are mutually exclusive. --json emits the structured server response; --verbose adds dumps that would break `--json | jq`."
|
|
7940
|
+
);
|
|
7941
|
+
}
|
|
7961
7942
|
requireDid3("work request", recipientDid, "<recipient-did>");
|
|
7962
7943
|
delegationId = requireUuidNormalised3("work request", delegationId, "<delegation-id>");
|
|
7963
7944
|
const ttlSeconds = parseTtl5("work request", opts.ttl);
|
|
@@ -7971,27 +7952,51 @@ async function runRequest(recipientDid, delegationId, opts) {
|
|
|
7971
7952
|
params
|
|
7972
7953
|
};
|
|
7973
7954
|
const body = { type: "work_request", content };
|
|
7974
|
-
|
|
7975
|
-
|
|
7976
|
-
|
|
7977
|
-
|
|
7978
|
-
|
|
7955
|
+
progress(opts.json, import_chalk32.default.dim(`Server: ${api.serverUrl}`));
|
|
7956
|
+
progress(opts.json, import_chalk32.default.dim(`Sender: ${sender.did}`));
|
|
7957
|
+
progress(opts.json, import_chalk32.default.dim(`Recipient: ${recipientDid}`));
|
|
7958
|
+
progress(opts.json, import_chalk32.default.dim(`Delegation: ${delegationId}`));
|
|
7959
|
+
progress(opts.json, import_chalk32.default.dim(`Request id: ${requestId}`));
|
|
7979
7960
|
const result = await sendWorkEnvelope({ api, sender, recipientDid, body, ttlSeconds, verbose: opts.verbose, server: opts.server });
|
|
7980
|
-
|
|
7981
|
-
|
|
7961
|
+
if (opts.json) {
|
|
7962
|
+
jsonOut({
|
|
7963
|
+
ok: true,
|
|
7964
|
+
action: "work_request",
|
|
7965
|
+
requestId,
|
|
7966
|
+
delegationId,
|
|
7967
|
+
eventId: result.eventId,
|
|
7968
|
+
relationshipId: result.relationshipId,
|
|
7969
|
+
relationshipEventIndex: result.relationshipEventIndex,
|
|
7970
|
+
serverTimestamp: result.serverTimestamp,
|
|
7971
|
+
serverEventHash: result.serverEventHash,
|
|
7972
|
+
prevServerEventHash: result.prevServerEventHash ?? null
|
|
7973
|
+
});
|
|
7974
|
+
} else {
|
|
7975
|
+
printIngestResult3(result);
|
|
7976
|
+
console.log(import_chalk32.default.dim(`
|
|
7982
7977
|
The payee can reply with:`));
|
|
7983
|
-
|
|
7984
|
-
|
|
7978
|
+
console.log(import_chalk32.default.dim(` heyarp work respond ${result.relationshipId} ${delegationId} ${requestId} --output '<json>'`));
|
|
7979
|
+
console.log(import_chalk32.default.dim(` heyarp work respond ${result.relationshipId} ${delegationId} ${requestId} --error CODE:message`));
|
|
7980
|
+
}
|
|
7985
7981
|
}
|
|
7986
7982
|
function registerRespond(parent) {
|
|
7987
7983
|
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
7984
|
"--output-file <path>",
|
|
7989
7985
|
"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).
|
|
7986
|
+
).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(
|
|
7987
|
+
"--json",
|
|
7988
|
+
'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.',
|
|
7989
|
+
false
|
|
7990
|
+
).action(async (relationshipId, delegationId, requestId, opts) => {
|
|
7991
7991
|
await runRespond(relationshipId, delegationId, requestId, opts);
|
|
7992
7992
|
});
|
|
7993
7993
|
}
|
|
7994
7994
|
async function runRespond(relationshipId, delegationId, requestId, opts) {
|
|
7995
|
+
if (opts.verbose && opts.json) {
|
|
7996
|
+
throw new Error(
|
|
7997
|
+
"work respond: --verbose and --json are mutually exclusive. --json emits the structured server response; --verbose adds dumps that would break `--json | jq`."
|
|
7998
|
+
);
|
|
7999
|
+
}
|
|
7995
8000
|
relationshipId = requireUuidNormalised3("work respond", relationshipId, "<relationship-id>");
|
|
7996
8001
|
delegationId = requireUuidNormalised3("work respond", delegationId, "<delegation-id>");
|
|
7997
8002
|
const ttlSeconds = parseTtl5("work respond", opts.ttl);
|
|
@@ -8006,33 +8011,48 @@ async function runRespond(relationshipId, delegationId, requestId, opts) {
|
|
|
8006
8011
|
...responsePayload
|
|
8007
8012
|
};
|
|
8008
8013
|
const body = { type: "work_response", content };
|
|
8009
|
-
|
|
8010
|
-
|
|
8011
|
-
|
|
8012
|
-
|
|
8013
|
-
|
|
8014
|
-
|
|
8015
|
-
|
|
8014
|
+
progress(opts.json, import_chalk32.default.dim(`Server: ${api.serverUrl}`));
|
|
8015
|
+
progress(opts.json, import_chalk32.default.dim(`Sender: ${sender.did}`));
|
|
8016
|
+
progress(opts.json, import_chalk32.default.dim(`Recipient: ${recipientDid}`));
|
|
8017
|
+
progress(opts.json, import_chalk32.default.dim(`Relationship: ${relationshipId}`));
|
|
8018
|
+
progress(opts.json, import_chalk32.default.dim(`Delegation: ${delegationId}`));
|
|
8019
|
+
progress(opts.json, import_chalk32.default.dim(`Request id: ${requestId}`));
|
|
8020
|
+
progress(opts.json, import_chalk32.default.dim(`Outcome: ${responsePayload.output ? "success" : "error"}`));
|
|
8016
8021
|
const result = await sendWorkEnvelope({ api, sender, recipientDid, body, ttlSeconds, verbose: opts.verbose, server: opts.server });
|
|
8017
|
-
|
|
8022
|
+
if (opts.json) {
|
|
8023
|
+
jsonOut({
|
|
8024
|
+
ok: true,
|
|
8025
|
+
action: "work_response",
|
|
8026
|
+
requestId,
|
|
8027
|
+
delegationId,
|
|
8028
|
+
eventId: result.eventId,
|
|
8029
|
+
relationshipId: result.relationshipId,
|
|
8030
|
+
relationshipEventIndex: result.relationshipEventIndex,
|
|
8031
|
+
serverTimestamp: result.serverTimestamp,
|
|
8032
|
+
serverEventHash: result.serverEventHash,
|
|
8033
|
+
prevServerEventHash: result.prevServerEventHash ?? null
|
|
8034
|
+
});
|
|
8035
|
+
} else {
|
|
8036
|
+
printIngestResult3(result);
|
|
8037
|
+
}
|
|
8018
8038
|
}
|
|
8019
8039
|
async function sendWorkEnvelope(args) {
|
|
8020
8040
|
const nextSequence = (args.sender.lastSenderSequence ?? 0) + 1;
|
|
8021
8041
|
const protectedBlock = {
|
|
8022
|
-
protocol_version:
|
|
8023
|
-
purpose:
|
|
8024
|
-
message_id: (0,
|
|
8042
|
+
protocol_version: import_sdk27.CURRENT_PROTOCOL_VERSION,
|
|
8043
|
+
purpose: import_sdk27.Purpose.ENVELOPE,
|
|
8044
|
+
message_id: (0, import_sdk27.uuidV4)(),
|
|
8025
8045
|
sender_did: args.sender.did,
|
|
8026
8046
|
recipient_did: args.recipientDid,
|
|
8027
8047
|
relationship_id: null,
|
|
8028
8048
|
sender_sequence: nextSequence,
|
|
8029
|
-
sender_nonce: (0,
|
|
8030
|
-
timestamp: (0,
|
|
8031
|
-
expires_at: (0,
|
|
8049
|
+
sender_nonce: (0, import_sdk27.senderNonce)(),
|
|
8050
|
+
timestamp: (0, import_sdk27.rfc3339)(),
|
|
8051
|
+
expires_at: (0, import_sdk27.expiresAt)(args.ttlSeconds),
|
|
8032
8052
|
delivery_id: null
|
|
8033
8053
|
};
|
|
8034
8054
|
const signer = makeSigner(args.sender);
|
|
8035
|
-
const envelope = (0,
|
|
8055
|
+
const envelope = (0, import_sdk27.signEnvelope)({
|
|
8036
8056
|
protected: protectedBlock,
|
|
8037
8057
|
body: args.body,
|
|
8038
8058
|
identitySecretKey: signer.identitySecretKey
|
|
@@ -8046,7 +8066,7 @@ async function sendWorkEnvelope(args) {
|
|
|
8046
8066
|
updateAgentLocal(args.server, args.sender.did, { lastSenderSequence: nextSequence });
|
|
8047
8067
|
return result;
|
|
8048
8068
|
} catch (err) {
|
|
8049
|
-
if (err instanceof ApiError &&
|
|
8069
|
+
if (err instanceof ApiError && (0, import_sdk27.isPostCommitErrorCode)(err.payload.code)) {
|
|
8050
8070
|
updateAgentLocal(args.server, args.sender.did, { lastSenderSequence: nextSequence });
|
|
8051
8071
|
}
|
|
8052
8072
|
throw err;
|
|
@@ -8058,7 +8078,7 @@ async function resolveResponseRecipient(cmdName, api, signer, args) {
|
|
|
8058
8078
|
const page = await api.listWorkLogs(args.relationshipId, signer, { delegationId: args.delegationId, limit: 100, after });
|
|
8059
8079
|
const row = page.find((w) => w.requestId === args.requestId);
|
|
8060
8080
|
if (row) {
|
|
8061
|
-
if (row.state !==
|
|
8081
|
+
if (row.state !== import_sdk27.WorkLogStates.REQUESTED) {
|
|
8062
8082
|
throw new Error(
|
|
8063
8083
|
`${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
8084
|
);
|
|
@@ -8175,7 +8195,7 @@ function parseTtl5(cmdName, raw) {
|
|
|
8175
8195
|
}
|
|
8176
8196
|
function parseRequestId(cmdName, raw) {
|
|
8177
8197
|
if (raw === void 0 || raw === "") {
|
|
8178
|
-
return (0,
|
|
8198
|
+
return (0, import_sdk27.uuidV4)();
|
|
8179
8199
|
}
|
|
8180
8200
|
if (raw.length === 0) {
|
|
8181
8201
|
throw new Error(`${cmdName}: --request-id must be a non-empty string`);
|
|
@@ -8196,9 +8216,10 @@ function requireDid3(cmdName, did, label) {
|
|
|
8196
8216
|
}
|
|
8197
8217
|
|
|
8198
8218
|
// src/commands/work-list.ts
|
|
8219
|
+
var import_sdk28 = require("@heyanon-arp/sdk");
|
|
8199
8220
|
var import_chalk33 = __toESM(require("chalk"));
|
|
8200
8221
|
init_api();
|
|
8201
|
-
var ALLOWED_STATES3 =
|
|
8222
|
+
var ALLOWED_STATES3 = new Set(import_sdk28.WORK_LOG_STATES);
|
|
8202
8223
|
function registerWorkListCommand(root) {
|
|
8203
8224
|
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
8225
|
"--verbose",
|
|
@@ -8271,9 +8292,9 @@ function formatWorkLogLine(w, selfDid, opts = {}) {
|
|
|
8271
8292
|
}
|
|
8272
8293
|
function colorState2(s) {
|
|
8273
8294
|
switch (s) {
|
|
8274
|
-
case
|
|
8295
|
+
case import_sdk28.WorkLogStates.REQUESTED:
|
|
8275
8296
|
return import_chalk33.default.yellow("requested");
|
|
8276
|
-
case
|
|
8297
|
+
case import_sdk28.WorkLogStates.RESPONDED:
|
|
8277
8298
|
return import_chalk33.default.green("responded");
|
|
8278
8299
|
}
|
|
8279
8300
|
}
|
|
@@ -8281,7 +8302,7 @@ function stateColumnWidth2() {
|
|
|
8281
8302
|
return 9;
|
|
8282
8303
|
}
|
|
8283
8304
|
function formatOutcome(w) {
|
|
8284
|
-
if (w.state ===
|
|
8305
|
+
if (w.state === import_sdk28.WorkLogStates.REQUESTED) return import_chalk33.default.dim("(in flight)");
|
|
8285
8306
|
if (w.responseError) return import_chalk33.default.red(`error ${w.responseError.code}: ${truncate3(w.responseError.message, 32)}`);
|
|
8286
8307
|
if (w.responseOutput) return import_chalk33.default.cyan("ok");
|
|
8287
8308
|
return import_chalk33.default.dim("(empty response)");
|
|
@@ -8314,6 +8335,43 @@ function parseLimit7(raw) {
|
|
|
8314
8335
|
return n;
|
|
8315
8336
|
}
|
|
8316
8337
|
|
|
8338
|
+
// src/option-hint.ts
|
|
8339
|
+
function unknownOptionHint(program, err) {
|
|
8340
|
+
try {
|
|
8341
|
+
if (err.code !== "commander.unknownOption" || !err.message) return null;
|
|
8342
|
+
const m = /unknown option '([^']+)'/.exec(err.message);
|
|
8343
|
+
if (!m) return null;
|
|
8344
|
+
const raw = m[1];
|
|
8345
|
+
const flag = raw.split("=")[0];
|
|
8346
|
+
const owners = [];
|
|
8347
|
+
const walk = (cmd, path) => {
|
|
8348
|
+
for (const opt of cmd.options) {
|
|
8349
|
+
if (opt.long === flag || opt.short === flag) owners.push(path.join(" "));
|
|
8350
|
+
}
|
|
8351
|
+
for (const sub of cmd.commands) walk(sub, [...path, sub.name()]);
|
|
8352
|
+
};
|
|
8353
|
+
for (const sub of program.commands) walk(sub, [sub.name()]);
|
|
8354
|
+
if (owners.length === 0) return null;
|
|
8355
|
+
owners.sort((a, b) => a.split(" ").length - b.split(" ").length);
|
|
8356
|
+
const argv = process.argv.slice(2);
|
|
8357
|
+
const commandNames = /* @__PURE__ */ new Set();
|
|
8358
|
+
for (const c of program.commands) {
|
|
8359
|
+
commandNames.add(c.name());
|
|
8360
|
+
for (const a of c.aliases()) commandNames.add(a);
|
|
8361
|
+
}
|
|
8362
|
+
const flagIdx = argv.findIndex((t) => t === raw || t.split("=")[0] === flag);
|
|
8363
|
+
const cmdIdx = argv.findIndex((t) => commandNames.has(t));
|
|
8364
|
+
const placedBeforeCommand = cmdIdx === -1 || flagIdx !== -1 && flagIdx < cmdIdx;
|
|
8365
|
+
if (placedBeforeCommand) {
|
|
8366
|
+
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.`;
|
|
8367
|
+
}
|
|
8368
|
+
const list = owners.slice(0, 4).join(", ") + (owners.length > 4 ? ", \u2026" : "");
|
|
8369
|
+
return `'${flag}' isn't valid for that command \u2014 it's an option of: ${list}.`;
|
|
8370
|
+
} catch {
|
|
8371
|
+
return null;
|
|
8372
|
+
}
|
|
8373
|
+
}
|
|
8374
|
+
|
|
8317
8375
|
// src/cli.ts
|
|
8318
8376
|
async function checkForUpdates() {
|
|
8319
8377
|
if (package_default.private === true) return;
|
|
@@ -8328,7 +8386,7 @@ async function checkForUpdates() {
|
|
|
8328
8386
|
async function main() {
|
|
8329
8387
|
void checkForUpdates();
|
|
8330
8388
|
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);
|
|
8389
|
+
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
8390
|
program.exitOverride();
|
|
8333
8391
|
program.configureOutput({
|
|
8334
8392
|
writeErr: (str) => {
|
|
@@ -8336,6 +8394,7 @@ async function main() {
|
|
|
8336
8394
|
process.stderr.write(str);
|
|
8337
8395
|
}
|
|
8338
8396
|
});
|
|
8397
|
+
program.addHelpText("after", () => optionPlacementHelpNote());
|
|
8339
8398
|
program.addHelpText("after", () => onboardingHelpFooter());
|
|
8340
8399
|
registerConfigCommand(program);
|
|
8341
8400
|
registerGuideCommand(program);
|
|
@@ -8383,10 +8442,13 @@ async function main() {
|
|
|
8383
8442
|
const json = process.argv.includes("--json");
|
|
8384
8443
|
const verbose = process.argv.includes("--trace");
|
|
8385
8444
|
const exitCode = typeof cerr.exitCode === "number" && cerr.exitCode !== 0 ? cerr.exitCode : 1;
|
|
8445
|
+
const hint = unknownOptionHint(program, cerr);
|
|
8386
8446
|
if (isCommanderError && !json) {
|
|
8447
|
+
if (hint) process.stderr.write(`hint: ${hint}
|
|
8448
|
+
`);
|
|
8387
8449
|
process.exit(exitCode);
|
|
8388
8450
|
}
|
|
8389
|
-
emitError(err, { json, verbose });
|
|
8451
|
+
emitError(err, { json, verbose, hint: hint ?? void 0 });
|
|
8390
8452
|
process.exit(exitCode);
|
|
8391
8453
|
}
|
|
8392
8454
|
}
|