@heyanon-arp/cli 0.0.21 → 0.0.23
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 +157 -46
- package/dist/cli.js.map +1 -1
- package/package.json +3 -4
package/dist/cli.js
CHANGED
|
@@ -729,12 +729,11 @@ var init_api = __esm({
|
|
|
729
729
|
// src/cli.ts
|
|
730
730
|
var import_shield3 = require("@heyanon-arp/shield");
|
|
731
731
|
var import_commander = require("commander");
|
|
732
|
-
var import_simple_update_notifier = __toESM(require("simple-update-notifier"));
|
|
733
732
|
|
|
734
733
|
// package.json
|
|
735
734
|
var package_default = {
|
|
736
735
|
name: "@heyanon-arp/cli",
|
|
737
|
-
version: "0.0.
|
|
736
|
+
version: "0.0.23",
|
|
738
737
|
description: "Command-line client for the Agent Relationship Protocol \u2014 register agents, sign envelopes, run escrowed work cycles on Solana.",
|
|
739
738
|
license: "MIT",
|
|
740
739
|
keywords: ["arp", "agent-relationship-protocol", "did", "solana", "escrow", "ed25519", "agents", "a2a", "cli"],
|
|
@@ -763,8 +762,7 @@ var package_default = {
|
|
|
763
762
|
"@solana/web3.js": "^1.98.4",
|
|
764
763
|
chalk: "^4.1.2",
|
|
765
764
|
commander: "^12.1.0",
|
|
766
|
-
prompts: "^2.4.2"
|
|
767
|
-
"simple-update-notifier": "^2.0.0"
|
|
765
|
+
prompts: "^2.4.2"
|
|
768
766
|
},
|
|
769
767
|
devDependencies: {
|
|
770
768
|
"@types/jest": "^29.5.2",
|
|
@@ -1790,6 +1788,10 @@ var UNTIL_PHASES = [
|
|
|
1790
1788
|
];
|
|
1791
1789
|
var WAIT_DEFAULT_INTERVAL_SEC = 3;
|
|
1792
1790
|
var WAIT_DEFAULT_TIMEOUT_SEC = 300;
|
|
1791
|
+
var WAIT_ABS_MAX_SEC = 7 * 86400;
|
|
1792
|
+
var WAIT_CONTRACT_LAG_MARGIN_SEC = 300;
|
|
1793
|
+
var WAIT_CONTRACT_CAP_FALLBACK_SEC = 3600;
|
|
1794
|
+
var WAIT_LOCK_FINALIZATION_DEFAULT_SEC = 1200;
|
|
1793
1795
|
function registerStatusCommand(root) {
|
|
1794
1796
|
root.command("status").description("Where am I in the work cycle? FSM state + next-action hint for ONE relationship (signed reads)").argument("<relationship-id>", "Relationship UUID").option("--server <url>", "Override ARP server base URL").option("--from-did <did>", "Signer DID \u2014 required only if multiple agents are registered against this server").option("--from <name>", "Signer agent NAME (handle) \u2014 alternative to --from-did, resolved against your local agents").option("--json", "Machine-readable: single JSON object with the composed summary. Pipe-safe.", false).option(
|
|
1795
1797
|
"--wait",
|
|
@@ -1797,8 +1799,10 @@ function registerStatusCommand(root) {
|
|
|
1797
1799
|
false
|
|
1798
1800
|
).option(
|
|
1799
1801
|
"--wait-timeout <seconds>",
|
|
1800
|
-
`Max wall-clock seconds to wait when --wait is set
|
|
1801
|
-
|
|
1802
|
+
`Max wall-clock seconds to wait when --wait is set. Default ${WAIT_DEFAULT_TIMEOUT_SEC}s, with two phase-aware exceptions when --until is set: (1) delegation.locked uses a generous lock-finalization default (on-chain confirmation + indexer projection latency, not the lifecycle windows); (2) a lifecycle phase (work/review/dispute-governed, e.g. work.responded) auto-sizes to the live on-chain budget (work+review+dispute windows + margin, read from the contract) so it tracks the windows. An explicit value is always honored as-is (it may legitimately exceed the budget \u2014 a wait can span pre-lock acceptance/funding too); only a generous 7-day wait-loop safety cap is enforced. Exit code 124 on timeout (unix \`timeout\` convention).`
|
|
1803
|
+
// NB: no Commander default — an omitted value must reach resolveWaitTimeoutSec
|
|
1804
|
+
// as `undefined` so it can phase-size the default (a literal '300' here would
|
|
1805
|
+
// mask the contract-budget auto-sizing for --until waits).
|
|
1802
1806
|
).option(
|
|
1803
1807
|
"--wait-interval <seconds>",
|
|
1804
1808
|
`Seconds between polls when --wait is set (default ${WAIT_DEFAULT_INTERVAL_SEC}). Bound to [1, 60].`,
|
|
@@ -1833,9 +1837,9 @@ async function runStatus(relationshipId, opts) {
|
|
|
1833
1837
|
console.log(formatStatusReport(summary));
|
|
1834
1838
|
return;
|
|
1835
1839
|
}
|
|
1836
|
-
const waitTimeout = parseWaitTimeout(opts.waitTimeout);
|
|
1837
|
-
const waitInterval = parseWaitInterval(opts.waitInterval);
|
|
1838
1840
|
const until = parseUntilPhase(opts.until);
|
|
1841
|
+
const waitInterval = parseWaitInterval(opts.waitInterval);
|
|
1842
|
+
const waitTimeout = await resolveWaitTimeoutSec(api, opts.waitTimeout, { untilPhase: until });
|
|
1839
1843
|
const outcome = await runWaitLoop({
|
|
1840
1844
|
fetchSummary: () => composeStatus(api, sender.did, relationshipId, signer),
|
|
1841
1845
|
waitIntervalSec: waitInterval,
|
|
@@ -1996,11 +2000,38 @@ function parseWaitTimeout(raw) {
|
|
|
1996
2000
|
if (!Number.isFinite(n) || !Number.isInteger(n) || n <= 0) {
|
|
1997
2001
|
throw new Error(`status: --wait-timeout must be a positive integer number of seconds (got '${raw}')`);
|
|
1998
2002
|
}
|
|
1999
|
-
if (n >
|
|
2000
|
-
throw new Error(`status: --wait-timeout must be <=
|
|
2003
|
+
if (n > WAIT_ABS_MAX_SEC) {
|
|
2004
|
+
throw new Error(`status: --wait-timeout must be <= ${WAIT_ABS_MAX_SEC} seconds (the 7-day wait-loop safety cap). Got ${n}.`);
|
|
2001
2005
|
}
|
|
2002
2006
|
return n;
|
|
2003
2007
|
}
|
|
2008
|
+
function contractWaitCapSec(cfg) {
|
|
2009
|
+
const w = Number(cfg?.workWindowSecs);
|
|
2010
|
+
const r = Number(cfg?.reviewWindowSecs);
|
|
2011
|
+
const d = Number(cfg?.disputeWindowSecs);
|
|
2012
|
+
if (![w, r, d].every((n) => Number.isFinite(n) && n > 0)) return WAIT_CONTRACT_CAP_FALLBACK_SEC;
|
|
2013
|
+
return Math.min(WAIT_ABS_MAX_SEC, w + r + d + WAIT_CONTRACT_LAG_MARGIN_SEC);
|
|
2014
|
+
}
|
|
2015
|
+
var LOCK_FINALIZATION_PHASES = /* @__PURE__ */ new Set(["delegation.locked"]);
|
|
2016
|
+
var CONTRACT_BUDGETED_PHASES = /* @__PURE__ */ new Set([
|
|
2017
|
+
"delegation.disputing",
|
|
2018
|
+
"work.requested",
|
|
2019
|
+
"work.responded",
|
|
2020
|
+
"receipt.proposed",
|
|
2021
|
+
"cycle.released",
|
|
2022
|
+
"cycle.complete"
|
|
2023
|
+
]);
|
|
2024
|
+
async function resolveWaitTimeoutSec(api, raw, opts) {
|
|
2025
|
+
if (raw !== void 0) return parseWaitTimeout(raw);
|
|
2026
|
+
if (opts.untilPhase !== void 0 && LOCK_FINALIZATION_PHASES.has(opts.untilPhase)) return WAIT_LOCK_FINALIZATION_DEFAULT_SEC;
|
|
2027
|
+
const contractBudgeted = opts.untilPhase !== void 0 && CONTRACT_BUDGETED_PHASES.has(opts.untilPhase);
|
|
2028
|
+
if (!contractBudgeted) return WAIT_DEFAULT_TIMEOUT_SEC;
|
|
2029
|
+
try {
|
|
2030
|
+
return contractWaitCapSec(await api.getEscrowConfig());
|
|
2031
|
+
} catch {
|
|
2032
|
+
return WAIT_CONTRACT_CAP_FALLBACK_SEC;
|
|
2033
|
+
}
|
|
2034
|
+
}
|
|
2004
2035
|
function parseUntilPhase(raw) {
|
|
2005
2036
|
if (raw === void 0 || raw === "") return void 0;
|
|
2006
2037
|
if (!UNTIL_PHASES.includes(raw)) {
|
|
@@ -2318,9 +2349,8 @@ function nextAction(input) {
|
|
|
2318
2349
|
}
|
|
2319
2350
|
const iAmCaller = latestReceipt.callerDid === signerDid;
|
|
2320
2351
|
return {
|
|
2321
|
-
//
|
|
2322
|
-
//
|
|
2323
|
-
// review-window self-claim.
|
|
2352
|
+
// Consent is the on-chain claim_work_payment tx (the buyer's), and
|
|
2353
|
+
// worker recourse is the review-window self-claim.
|
|
2324
2354
|
hint: iAmCaller ? `Receipt PROPOSED \u2014 you (caller): review the deliverable and approve payment ON-CHAIN with \`heyarp escrow claim ${latestReceipt.delegationId}\` (irreversible release; \`heyarp escrow dispute open ${latestReceipt.delegationId}\` within the review window if the work is unacceptable)` : `Receipt PROPOSED \u2014 counterparty (the buyer) owes the on-chain approval (\`heyarp escrow claim\`); once the review window lapses you may self-claim with \`heyarp escrow claim ${latestReceipt.delegationId}\``,
|
|
2325
2355
|
owner: iAmCaller ? "me" : "counterparty",
|
|
2326
2356
|
complete: false
|
|
@@ -2959,7 +2989,10 @@ function registerOffer(parent) {
|
|
|
2959
2989
|
).option(
|
|
2960
2990
|
"--wait-until <phase>",
|
|
2961
2991
|
'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.'
|
|
2962
|
-
).option(
|
|
2992
|
+
).option(
|
|
2993
|
+
"--wait-timeout <seconds>",
|
|
2994
|
+
"When --wait-until is set: max wall-clock wait. Omitted \u2192 delegation.locked uses a generous lock-finalization default (on-chain confirmation + indexer projection); later lifecycle phases (work/review/dispute-governed) auto-size to the live on-chain budget (read from the contract); other phases default to 300s. An explicit value is always honored as-is (a wait may span pre-lock acceptance/funding, so it can exceed the budget), bounded only by a generous 7-day wait-loop safety cap. Exit code 124 on timeout."
|
|
2995
|
+
).option("--wait-interval <seconds>", "When --wait-until is set: poll cadence (default 3, bound [1, 60]).").option(
|
|
2963
2996
|
"--wait-verbose",
|
|
2964
2997
|
'When --wait-until is set: emit one dim line per poll tick showing the current FSM state. Useful for "is it alive or stuck?" diagnosis on long blocks.',
|
|
2965
2998
|
false
|
|
@@ -3184,7 +3217,8 @@ After the worker accepts, fund the escrow lock:`));
|
|
|
3184
3217
|
relationshipId: result.relationshipId,
|
|
3185
3218
|
untilPhase,
|
|
3186
3219
|
waitIntervalSec: parseWaitInterval(opts.waitInterval),
|
|
3187
|
-
|
|
3220
|
+
// Cap/default the wait against the live on-chain windows (work+review+dispute).
|
|
3221
|
+
waitTimeoutSec: await resolveWaitTimeoutSec(api, opts.waitTimeout, { untilPhase }),
|
|
3188
3222
|
waitVerbose: !!opts.waitVerbose,
|
|
3189
3223
|
json: false
|
|
3190
3224
|
// delegation offer is a human-text command (printIngestResult is human-text); JSON mode would be a follow-up.
|
|
@@ -3208,7 +3242,10 @@ function registerFund(parent) {
|
|
|
3208
3242
|
).option(
|
|
3209
3243
|
"--wait-until <phase>",
|
|
3210
3244
|
"Block after delivery until the named FSM phase is reached (typically delegation.locked \u2014 resolves once the escrow lock confirms on chain). One of the UNTIL_PHASES from `heyarp status --help`. Exit code 124 on --wait-timeout."
|
|
3211
|
-
).option(
|
|
3245
|
+
).option(
|
|
3246
|
+
"--wait-timeout <seconds>",
|
|
3247
|
+
"When --wait-until is set: max wall-clock wait. Omitted \u2192 delegation.locked uses a generous lock-finalization default (on-chain confirmation + indexer projection); later lifecycle phases (work/review/dispute-governed) auto-size to the live on-chain budget (read from the contract); other phases default to 300s. An explicit value is always honored as-is (a wait may span pre-lock acceptance/funding, so it can exceed the budget), bounded only by a generous 7-day wait-loop safety cap. Exit code 124 on timeout."
|
|
3248
|
+
).option("--wait-interval <seconds>", "When --wait-until is set: poll cadence (default 3, bound [1, 60]).").option("--wait-verbose", "When --wait-until is set: emit one dim line per poll tick showing the current FSM state.", false).action(async (delegationId, opts) => {
|
|
3212
3249
|
await runFund(delegationId, opts);
|
|
3213
3250
|
});
|
|
3214
3251
|
}
|
|
@@ -3306,11 +3343,11 @@ async function runFund(delegationId, opts) {
|
|
|
3306
3343
|
relationshipId: result.relationshipId,
|
|
3307
3344
|
untilPhase,
|
|
3308
3345
|
waitIntervalSec: parseWaitInterval(opts.waitInterval),
|
|
3309
|
-
// Lock finalization
|
|
3310
|
-
//
|
|
3311
|
-
//
|
|
3312
|
-
// almost never a failure, just a slow chain.
|
|
3313
|
-
waitTimeoutSec:
|
|
3346
|
+
// Lock finalization (submit → confirm → indexer projection) is
|
|
3347
|
+
// slow, so an omitted timeout auto-sizes to the live on-chain
|
|
3348
|
+
// budget (work+review+dispute + margin) — generous by design;
|
|
3349
|
+
// a timeout here is almost never a failure, just a slow chain.
|
|
3350
|
+
waitTimeoutSec: await resolveWaitTimeoutSec(api, opts.waitTimeout, { untilPhase }),
|
|
3314
3351
|
waitVerbose: !!opts.waitVerbose,
|
|
3315
3352
|
json: false
|
|
3316
3353
|
});
|
|
@@ -6373,8 +6410,8 @@ async function runPropose(recipientDid, delegationId, requestHashArg, responseHa
|
|
|
6373
6410
|
);
|
|
6374
6411
|
}
|
|
6375
6412
|
recipientDid = await resolveRecipient(opts.server, "receipt propose", recipientDid, { json: opts.json });
|
|
6376
|
-
delegationId =
|
|
6377
|
-
if (opts.relId) opts.relId =
|
|
6413
|
+
delegationId = requireUuidNormalised("receipt propose", delegationId, "<delegation-id>");
|
|
6414
|
+
if (opts.relId) opts.relId = requireUuidNormalised("receipt propose", opts.relId, "--rel-id");
|
|
6378
6415
|
const verdict = parseVerdict("receipt propose", opts.verdict);
|
|
6379
6416
|
const ttlSeconds = parseTtl2("receipt propose", opts.ttl);
|
|
6380
6417
|
if (opts.notesHash) requireSha256("receipt propose", opts.notesHash, "--notes-hash");
|
|
@@ -6635,10 +6672,6 @@ function parseInteger(cmdName, flag, raw) {
|
|
|
6635
6672
|
}
|
|
6636
6673
|
return n;
|
|
6637
6674
|
}
|
|
6638
|
-
function requireUuidNormalised2(cmdName, raw, label) {
|
|
6639
|
-
requireUuid3(cmdName, raw, label);
|
|
6640
|
-
return raw.toLowerCase();
|
|
6641
|
-
}
|
|
6642
6675
|
function requireUuid3(cmdName, raw, label) {
|
|
6643
6676
|
requireUuid(cmdName, raw, label);
|
|
6644
6677
|
}
|
|
@@ -7874,7 +7907,7 @@ async function runRequest(recipientDid, delegationId, opts) {
|
|
|
7874
7907
|
);
|
|
7875
7908
|
}
|
|
7876
7909
|
recipientDid = await resolveRecipient(opts.server, "work request", recipientDid, { json: opts.json });
|
|
7877
|
-
delegationId =
|
|
7910
|
+
delegationId = requireUuidNormalised("work request", delegationId, "<delegation-id>");
|
|
7878
7911
|
const ttlSeconds = parseTtl5("work request", opts.ttl);
|
|
7879
7912
|
const params = parseParamsInput("work request", opts);
|
|
7880
7913
|
const requestId = parseRequestId("work request", opts.requestId);
|
|
@@ -7931,8 +7964,8 @@ async function runRespond(relationshipId, delegationId, requestId, opts) {
|
|
|
7931
7964
|
"work respond: --verbose and --json are mutually exclusive. --json emits the structured server response; --verbose adds dumps that would break `--json | jq`."
|
|
7932
7965
|
);
|
|
7933
7966
|
}
|
|
7934
|
-
relationshipId =
|
|
7935
|
-
delegationId =
|
|
7967
|
+
relationshipId = requireUuidNormalised("work respond", relationshipId, "<relationship-id>");
|
|
7968
|
+
delegationId = requireUuidNormalised("work respond", delegationId, "<delegation-id>");
|
|
7936
7969
|
const ttlSeconds = parseTtl5("work respond", opts.ttl);
|
|
7937
7970
|
const responsePayload = parseResponsePayload("work respond", opts);
|
|
7938
7971
|
const api = new ArpApiClient(opts.server);
|
|
@@ -8075,13 +8108,13 @@ function parseParamsInput(cmdName, opts) {
|
|
|
8075
8108
|
return parseJsonObject(cmdName, "--params", opts.params ?? "{}");
|
|
8076
8109
|
}
|
|
8077
8110
|
function readJsonObjectFile(cmdName, flagName, path) {
|
|
8078
|
-
const { existsSync: existsSync7, readFileSync:
|
|
8111
|
+
const { existsSync: existsSync7, readFileSync: readFileSync10 } = require("fs");
|
|
8079
8112
|
if (!existsSync7(path)) {
|
|
8080
8113
|
throw new Error(`${cmdName}: ${flagName} file not found at ${path}`);
|
|
8081
8114
|
}
|
|
8082
8115
|
let raw;
|
|
8083
8116
|
try {
|
|
8084
|
-
raw =
|
|
8117
|
+
raw = readFileSync10(path, "utf8");
|
|
8085
8118
|
} catch (err) {
|
|
8086
8119
|
const detail = err instanceof Error ? err.message : String(err);
|
|
8087
8120
|
throw new Error(`${cmdName}: failed to read ${flagName} (${path}): ${detail}`);
|
|
@@ -8136,13 +8169,6 @@ function parseRequestId(cmdName, raw) {
|
|
|
8136
8169
|
}
|
|
8137
8170
|
return raw;
|
|
8138
8171
|
}
|
|
8139
|
-
function requireUuidNormalised3(cmdName, raw, label) {
|
|
8140
|
-
requireUuid4(cmdName, raw, label);
|
|
8141
|
-
return raw.toLowerCase();
|
|
8142
|
-
}
|
|
8143
|
-
function requireUuid4(cmdName, raw, label) {
|
|
8144
|
-
requireUuid(cmdName, raw, label);
|
|
8145
|
-
}
|
|
8146
8172
|
|
|
8147
8173
|
// src/commands/work-list.ts
|
|
8148
8174
|
var import_sdk32 = require("@heyanon-arp/sdk");
|
|
@@ -8301,19 +8327,104 @@ function unknownOptionHint(program, err) {
|
|
|
8301
8327
|
}
|
|
8302
8328
|
}
|
|
8303
8329
|
|
|
8304
|
-
// src/
|
|
8305
|
-
|
|
8306
|
-
|
|
8330
|
+
// src/version-gate.ts
|
|
8331
|
+
var import_node_fs10 = require("fs");
|
|
8332
|
+
var import_node_path7 = require("path");
|
|
8333
|
+
init_paths();
|
|
8334
|
+
var CHECK_INTERVAL_MS = 60 * 60 * 1e3;
|
|
8335
|
+
var REGISTRY_TIMEOUT_MS = 1500;
|
|
8336
|
+
var VERSION_GATE_BYPASS_ENV = "HEYARP_IGNORE_VERSION_GATE";
|
|
8337
|
+
var cacheFile = () => (0, import_node_path7.join)(arpHomeDir(), "update-check.json");
|
|
8338
|
+
function compareVersions(a, b) {
|
|
8339
|
+
const seg = (v, i) => Number.parseInt(v.split(".")[i] ?? "0", 10) || 0;
|
|
8340
|
+
for (let i = 0; i < 3; i++) {
|
|
8341
|
+
const d = seg(a, i) - seg(b, i);
|
|
8342
|
+
if (d !== 0) return d > 0 ? 1 : -1;
|
|
8343
|
+
}
|
|
8344
|
+
return 0;
|
|
8345
|
+
}
|
|
8346
|
+
function isClientBlocked(current, latest) {
|
|
8347
|
+
if (!latest) return false;
|
|
8348
|
+
return compareVersions(current, latest) < 0;
|
|
8349
|
+
}
|
|
8350
|
+
function isVersionGateExempt(argv) {
|
|
8351
|
+
if (argv.length === 0) return true;
|
|
8352
|
+
if (argv[0] === "help") return true;
|
|
8353
|
+
return argv.includes("--version") || argv.includes("-V") || argv.includes("--help") || argv.includes("-h");
|
|
8354
|
+
}
|
|
8355
|
+
async function fetchLatest(pkgName) {
|
|
8356
|
+
const ctrl = new AbortController();
|
|
8357
|
+
const timer = setTimeout(() => ctrl.abort(), REGISTRY_TIMEOUT_MS);
|
|
8307
8358
|
try {
|
|
8308
|
-
await (
|
|
8309
|
-
|
|
8310
|
-
|
|
8359
|
+
const res = await fetch(`https://registry.npmjs.org/-/package/${pkgName.replace("/", "%2F")}/dist-tags`, {
|
|
8360
|
+
signal: ctrl.signal,
|
|
8361
|
+
headers: { accept: "application/json" }
|
|
8311
8362
|
});
|
|
8363
|
+
if (!res.ok) return null;
|
|
8364
|
+
const body = await res.json();
|
|
8365
|
+
return typeof body.latest === "string" ? body.latest : null;
|
|
8312
8366
|
} catch {
|
|
8367
|
+
return null;
|
|
8368
|
+
} finally {
|
|
8369
|
+
clearTimeout(timer);
|
|
8313
8370
|
}
|
|
8314
8371
|
}
|
|
8372
|
+
async function resolveLatest(pkgName) {
|
|
8373
|
+
try {
|
|
8374
|
+
const cached = JSON.parse((0, import_node_fs10.readFileSync)(cacheFile(), "utf8"));
|
|
8375
|
+
if (typeof cached.latest === "string" && typeof cached.checkedAt === "number" && Date.now() - cached.checkedAt < CHECK_INTERVAL_MS) {
|
|
8376
|
+
return cached.latest;
|
|
8377
|
+
}
|
|
8378
|
+
} catch {
|
|
8379
|
+
}
|
|
8380
|
+
const fresh = await fetchLatest(pkgName);
|
|
8381
|
+
if (!fresh) return null;
|
|
8382
|
+
try {
|
|
8383
|
+
const file = cacheFile();
|
|
8384
|
+
(0, import_node_fs10.mkdirSync)((0, import_node_path7.dirname)(file), { recursive: true });
|
|
8385
|
+
(0, import_node_fs10.writeFileSync)(file, JSON.stringify({ checkedAt: Date.now(), latest: fresh }));
|
|
8386
|
+
} catch {
|
|
8387
|
+
}
|
|
8388
|
+
return fresh;
|
|
8389
|
+
}
|
|
8390
|
+
async function enforceMinClientVersion(pkg, argv) {
|
|
8391
|
+
if (process.env[VERSION_GATE_BYPASS_ENV]) return;
|
|
8392
|
+
if (isVersionGateExempt(argv)) return;
|
|
8393
|
+
let latest;
|
|
8394
|
+
try {
|
|
8395
|
+
latest = await resolveLatest(pkg.name);
|
|
8396
|
+
} catch {
|
|
8397
|
+
return;
|
|
8398
|
+
}
|
|
8399
|
+
if (!isClientBlocked(pkg.version, latest)) return;
|
|
8400
|
+
const update = `npm i -g ${pkg.name}@latest`;
|
|
8401
|
+
if (argv.includes("--json")) {
|
|
8402
|
+
console.error(
|
|
8403
|
+
JSON.stringify({
|
|
8404
|
+
code: "CLI_VERSION_TOO_OLD",
|
|
8405
|
+
message: `heyarp ${pkg.version} is out of date and blocked; the current release is ${latest}. Update with \`${update}\`, then re-run.`,
|
|
8406
|
+
details: { current: pkg.version, latest, update, bypassEnv: VERSION_GATE_BYPASS_ENV }
|
|
8407
|
+
})
|
|
8408
|
+
);
|
|
8409
|
+
} else {
|
|
8410
|
+
process.stderr.write(
|
|
8411
|
+
`
|
|
8412
|
+
heyarp ${pkg.version} is out of date and is blocked.
|
|
8413
|
+
The current release is ${latest}. Update, then re-run:
|
|
8414
|
+
|
|
8415
|
+
${update}
|
|
8416
|
+
|
|
8417
|
+
(emergency bypass: set ${VERSION_GATE_BYPASS_ENV}=1)
|
|
8418
|
+
|
|
8419
|
+
`
|
|
8420
|
+
);
|
|
8421
|
+
}
|
|
8422
|
+
process.exit(1);
|
|
8423
|
+
}
|
|
8424
|
+
|
|
8425
|
+
// src/cli.ts
|
|
8315
8426
|
async function main() {
|
|
8316
|
-
|
|
8427
|
+
await enforceMinClientVersion(package_default, process.argv.slice(2));
|
|
8317
8428
|
const program = new import_commander.Command();
|
|
8318
8429
|
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);
|
|
8319
8430
|
program.exitOverride();
|