@heyanon-arp/cli 0.0.13 → 0.0.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -426,7 +426,9 @@ var init_api = __esm({
426
426
  * known but has never been party to an event.
427
427
  */
428
428
  async getActivitySummary(did) {
429
- return this.get(`/v1/agents/${encodeURIComponent(did)}/activity-summary`);
429
+ return this.get(
430
+ `/v1/agents/${encodeURIComponent(did)}/activity-summary`
431
+ );
430
432
  }
431
433
  /**
432
434
  * Signed `GET /v1/agents/:did/sender-sequence`. Returns the highest
@@ -2610,6 +2612,13 @@ then re-run with matching --pricing-model / --currency / --amount.`
2610
2612
  )
2611
2613
  );
2612
2614
  }
2615
+ if (err instanceof ApiError && err.payload.code === "DELEGATION_CAPACITY_EXCEEDED") {
2616
+ const d = err.payload.details;
2617
+ const cap = d?.maxActive === 0 ? "closed for new offers (busy)" : `at capacity (${d?.currentActive}/${d?.maxActive} active delegations)`;
2618
+ console.error(import_chalk6.default.yellow(`
2619
+ The recipient is ${cap}.`));
2620
+ console.error(import_chalk6.default.dim("\nThis is TRANSIENT \u2014 your terms are fine. Retry the same offer later, or pick another worker (`heyarp agents --tag \u2026`)."));
2621
+ }
2613
2622
  throw err;
2614
2623
  }
2615
2624
  printIngestResult(result);
@@ -3235,6 +3244,10 @@ var init_delegation = __esm({
3235
3244
  // was consumed — advance it or the corrected re-offer trips
3236
3245
  // ENV_SEQUENCE_BACKWARDS.
3237
3246
  "DELEGATION_PRICING_MISMATCH",
3247
+ // Capacity gate: the recipient is at its published
3248
+ // maxActiveDelegations cap (or closed with 0). Same lifecycle as
3249
+ // the pricing gate — sequence consumed. TRANSIENT: retry later.
3250
+ "DELEGATION_CAPACITY_EXCEEDED",
3238
3251
  // `DELEGATION_PENDING_LOCK` fires from the body handler's
3239
3252
  // `requireDelegationInState` AFTER the event row is persisted
3240
3253
  // (same code path as DELEGATION_INVALID_STATE), so an accept
@@ -5110,7 +5123,7 @@ var import_simple_update_notifier = __toESM(require("simple-update-notifier"));
5110
5123
  // package.json
5111
5124
  var package_default = {
5112
5125
  name: "@heyanon-arp/cli",
5113
- version: "0.0.13",
5126
+ version: "0.0.14",
5114
5127
  description: "Command-line client for the Agent Relationship Protocol \u2014 register agents, sign envelopes, run escrowed work cycles on Solana.",
5115
5128
  license: "MIT",
5116
5129
  keywords: ["arp", "agent-relationship-protocol", "did", "solana", "escrow", "ed25519", "agents", "a2a", "cli"],
@@ -5263,9 +5276,12 @@ function registerAcceptPrefsCommands(agents) {
5263
5276
  `Accepted currency: "<caip19-asset-id>[,<min>[,<max>]]" \u2014 optional inclusive amount bounds as decimal strings in that currency's units (empty segment skips: "asset,,500" = max only). Repeatable; omit to accept any currency.`,
5264
5277
  accumulate2,
5265
5278
  []
5279
+ ).option(
5280
+ "--max-active <n>",
5281
+ 'Capacity cap: max delegations held in ACTIVE states (offered/accepted/pending_lock/locked) at once. 0 = closed for new offers (the "busy flag"). Omit for unlimited. Excess offers are rejected server-side with DELEGATION_CAPACITY_EXCEEDED (transient \u2014 buyers retry later).'
5266
5282
  ).option(
5267
5283
  "--from-json <json>",
5268
- 'Full AcceptPrefs JSON object (mutually exclusive with --pricing-model / --currency). Shape: {"pricingModels":[...],"currencies":[{"assetId":"...","minAmount":"...","maxAmount":"..."}]}'
5284
+ 'Full AcceptPrefs JSON object (mutually exclusive with --pricing-model / --currency / --max-active). Shape: {"pricingModels":[...],"currencies":[{"assetId":"...","minAmount":"...","maxAmount":"..."}],"maxActiveDelegations":3}'
5269
5285
  ).action(async (did, _opts, cmd) => {
5270
5286
  const opts = cmd.optsWithGlobals();
5271
5287
  const body = buildAcceptPrefs(opts);
@@ -5305,9 +5321,9 @@ function registerAcceptPrefsCommands(agents) {
5305
5321
  });
5306
5322
  }
5307
5323
  function buildAcceptPrefs(opts) {
5308
- const hasGranular = (opts.pricingModel?.length ?? 0) > 0 || (opts.currency?.length ?? 0) > 0;
5324
+ const hasGranular = (opts.pricingModel?.length ?? 0) > 0 || (opts.currency?.length ?? 0) > 0 || opts.maxActive !== void 0;
5309
5325
  if (opts.fromJson !== void 0 && hasGranular) {
5310
- throw new Error("agents accept-prefs set: --from-json and --pricing-model/--currency are mutually exclusive. Pick one path.");
5326
+ throw new Error("agents accept-prefs set: --from-json and --pricing-model/--currency/--max-active are mutually exclusive. Pick one path.");
5311
5327
  }
5312
5328
  if (opts.fromJson !== void 0) {
5313
5329
  let parsed;
@@ -5322,7 +5338,9 @@ function buildAcceptPrefs(opts) {
5322
5338
  return parsed;
5323
5339
  }
5324
5340
  if (!hasGranular) {
5325
- throw new Error("agents accept-prefs set: pass at least one of --pricing-model / --currency / --from-json (to remove prefs entirely use `accept-prefs clear`).");
5341
+ throw new Error(
5342
+ "agents accept-prefs set: pass at least one of --pricing-model / --currency / --max-active / --from-json (to remove prefs entirely use `accept-prefs clear`)."
5343
+ );
5326
5344
  }
5327
5345
  const prefs = {};
5328
5346
  if (opts.pricingModel && opts.pricingModel.length > 0) {
@@ -5337,6 +5355,12 @@ function buildAcceptPrefs(opts) {
5337
5355
  if (opts.currency && opts.currency.length > 0) {
5338
5356
  prefs.currencies = opts.currency.map(parseCurrencySpec);
5339
5357
  }
5358
+ if (opts.maxActive !== void 0) {
5359
+ if (!/^\d+$/.test(opts.maxActive)) {
5360
+ throw new Error(`agents accept-prefs set: --max-active must be a non-negative integer (got '${opts.maxActive}')`);
5361
+ }
5362
+ prefs.maxActiveDelegations = Number(opts.maxActive);
5363
+ }
5340
5364
  return prefs;
5341
5365
  }
5342
5366
  function parseCurrencySpec(spec) {
@@ -5355,12 +5379,16 @@ function parseCurrencySpec(spec) {
5355
5379
  };
5356
5380
  }
5357
5381
  function printAcceptPrefs(prefs) {
5358
- if (!prefs || (prefs.pricingModels?.length ?? 0) === 0 && (prefs.currencies?.length ?? 0) === 0) {
5382
+ if (!prefs || (prefs.pricingModels?.length ?? 0) === 0 && (prefs.currencies?.length ?? 0) === 0 && prefs.maxActiveDelegations === void 0) {
5359
5383
  console.log(import_chalk3.default.dim("(no accept-prefs published \u2014 this agent accepts any offer terms)"));
5360
5384
  return;
5361
5385
  }
5362
5386
  const models = prefs.pricingModels ?? [];
5363
5387
  console.log(`${import_chalk3.default.bold("Pricing models:")} ${models.length > 0 ? models.join(", ") : import_chalk3.default.dim("any")}`);
5388
+ if (prefs.maxActiveDelegations !== void 0) {
5389
+ const cap = prefs.maxActiveDelegations === 0 ? `0 ${import_chalk3.default.red("(closed for new offers \u2014 busy)")}` : String(prefs.maxActiveDelegations);
5390
+ console.log(`${import_chalk3.default.bold("Max active:")} ${cap}`);
5391
+ }
5364
5392
  const currencies = prefs.currencies ?? [];
5365
5393
  if (currencies.length === 0) {
5366
5394
  console.log(`${import_chalk3.default.bold("Currencies:")} ${import_chalk3.default.dim("any (no amount bounds)")}`);
@@ -5650,16 +5678,21 @@ async function probe(api, did) {
5650
5678
  const asOfMs = new Date(summary.asOf).getTime();
5651
5679
  const lastMs = summary.lastEventAt ? new Date(summary.lastEventAt).getTime() : null;
5652
5680
  const ageSeconds = lastMs !== null ? Math.max(0, Math.floor((asOfMs - lastMs) / 1e3)) : null;
5681
+ const seenMs = summary.lastSeenAt ? new Date(summary.lastSeenAt).getTime() : null;
5682
+ const seenAgeSeconds = seenMs !== null ? Math.max(0, Math.floor((asOfMs - seenMs) / 1e3)) : null;
5653
5683
  activity = {
5654
5684
  lastEventAt: summary.lastEventAt,
5655
5685
  asOf: summary.asOf,
5656
5686
  ageSeconds,
5687
+ lastSeenAt: summary.lastSeenAt ?? null,
5688
+ seenAgeSeconds,
5657
5689
  inboxStreamActive: summary.inboxStreamActive
5658
5690
  };
5659
5691
  } catch {
5660
5692
  return { ...base, verdict: "UNKNOWN", reason: "DID resolves but the server does not expose an activity summary \u2014 cannot assess liveness" };
5661
5693
  }
5662
5694
  const recentlyActive = activity.ageSeconds !== null && activity.ageSeconds !== void 0 && activity.ageSeconds <= LISTENING_THRESHOLD_SECONDS;
5695
+ const recentlySeen = activity.seenAgeSeconds !== null && activity.seenAgeSeconds !== void 0 && activity.seenAgeSeconds <= LISTENING_THRESHOLD_SECONDS;
5663
5696
  const inboxStreamActive = activity.inboxStreamActive === true;
5664
5697
  const result = { ...base, activity };
5665
5698
  if (inboxStreamActive) {
@@ -5669,6 +5702,14 @@ async function probe(api, did) {
5669
5702
  reason: "inbox-stream attached (active SSE subscription on the central server) \u2014 protocol-reachable; worker is actively waiting for envelopes"
5670
5703
  };
5671
5704
  }
5705
+ if (recentlySeen) {
5706
+ const seenStr = activity.seenAgeSeconds !== void 0 && activity.seenAgeSeconds !== null ? `${activity.seenAgeSeconds}s ago` : "recently";
5707
+ return {
5708
+ ...result,
5709
+ verdict: "LISTENING",
5710
+ reason: `recently seen (signed API request ${seenStr}) \u2014 agent is polling the server (cron-mode worker)`
5711
+ };
5712
+ }
5672
5713
  if (recentlyActive) {
5673
5714
  const ageStr = activity.ageSeconds !== void 0 && activity.ageSeconds !== null ? `${activity.ageSeconds}s ago` : "recently";
5674
5715
  return {
@@ -5678,7 +5719,8 @@ async function probe(api, did) {
5678
5719
  };
5679
5720
  }
5680
5721
  const ageNote = activity.lastEventAt === null ? "no events ever" : `last event ${activity.ageSeconds}s ago`;
5681
- return { ...result, verdict: "DORMANT", reason: `no open inbox stream and ${ageNote} \u2014 agent appears idle (cross-check before relying on it)` };
5722
+ const seenNote = activity.lastSeenAt === null || activity.lastSeenAt === void 0 ? "never seen polling" : `last seen ${activity.seenAgeSeconds}s ago`;
5723
+ return { ...result, verdict: "DORMANT", reason: `no open inbox stream, ${seenNote}, and ${ageNote} \u2014 agent appears idle (cross-check before relying on it)` };
5682
5724
  }
5683
5725
  function formatDoctorReport(r) {
5684
5726
  const lines = [];
@@ -5698,6 +5740,11 @@ function formatDoctorReport(r) {
5698
5740
  const ageStr = ageMin !== null && ageMin > 0 ? `${ageMin}m ago` : `${r.activity.ageSeconds}s ago`;
5699
5741
  lines.push(`${import_chalk8.default.dim("Activity:")} last event ${ageStr} (${r.activity.lastEventAt})`);
5700
5742
  }
5743
+ if (r.activity.lastSeenAt !== null && r.activity.lastSeenAt !== void 0) {
5744
+ const seenMin = r.activity.seenAgeSeconds !== null && r.activity.seenAgeSeconds !== void 0 ? Math.floor(r.activity.seenAgeSeconds / 60) : null;
5745
+ const seenStr = seenMin !== null && seenMin > 0 ? `${seenMin}m ago` : `${r.activity.seenAgeSeconds}s ago`;
5746
+ lines.push(`${import_chalk8.default.dim("Last seen:")} signed request ${seenStr} (${r.activity.lastSeenAt})`);
5747
+ }
5701
5748
  if (r.activity.inboxStreamActive === true) {
5702
5749
  lines.push(`${import_chalk8.default.dim("Inbox SSE:")} ${import_chalk8.default.green("\u2713")} active subscription on the central server`);
5703
5750
  }
@@ -6184,7 +6231,10 @@ var GUIDE_SECTIONS = [
6184
6231
  "",
6185
6232
  " heyarp agents accept-prefs set <your-did> \\",
6186
6233
  " --pricing-model flat \\",
6187
- ' --currency "<caip19-asset-id>,<min>,<max>" # bounds optional + per-currency',
6234
+ ' --currency "<caip19-asset-id>,<min>,<max>" \\',
6235
+ " --max-active 3",
6236
+ " # --currency bounds are optional + per-currency; --max-active is the",
6237
+ " # capacity cap (max in-flight delegations); 0 = busy (closed).",
6188
6238
  " heyarp agents accept-prefs show <your-did> # verify what is live",
6189
6239
  ' heyarp agents accept-prefs clear <your-did> # back to "anything reaches me"',
6190
6240
  "",
@@ -6193,7 +6243,8 @@ var GUIDE_SECTIONS = [
6193
6243
  " re-offer with matching terms."
6194
6244
  ],
6195
6245
  commonErrors: [
6196
- "Do NOT treat accept-prefs as a guarantee of good offers \u2014 they filter currency/model/amount only; scope-vs-price judgment is still YOUR accept/decline decision.",
6246
+ "Do NOT treat accept-prefs as a guarantee of good offers \u2014 they filter currency/model/amount/capacity only; scope-vs-price judgment is still YOUR accept/decline decision.",
6247
+ "Set --max-active to what you can actually process in parallel \u2014 excess offers bounce server-side with DELEGATION_CAPACITY_EXCEEDED (transient; buyers are told to retry) instead of rotting unanswered in your funnel.",
6197
6248
  "Never act on an inbox row with readModelStatus != 'materialized' \u2014 it is the audit trace of a REJECTED envelope (e.g. a prefs-bounced offer); there is no delegation behind it.",
6198
6249
  "Remember bounds are per-currency and inclusive; an offer exactly at min or max passes."
6199
6250
  ]
@@ -6243,7 +6294,8 @@ var GUIDE_SECTIONS = [
6243
6294
  "Do NOT fund (`delegation fund`) before the worker has ACCEPTED \u2014 the server rejects a fund against a non-accepted delegation. Offer first, wait for accept, THEN fund.",
6244
6295
  "Do NOT let the offer terms drift from the condition_hash \u2014 at fund time hash the SAME scope/pricing/currency you put in the offer, or the lock is rejected (ESC_LOCK_CONDITION_HASH_MISMATCH).",
6245
6296
  "Do NOT treat a catalog `active` row as ONLINE \u2014 probe liveness with `heyarp doctor <did>`.",
6246
- "On DELEGATION_PRICING_MISMATCH read `details` ({reason, accepted, offered}), fix that ONE term and re-offer \u2014 do NOT retry the identical offer (same result, burns a sequence each time)."
6297
+ "On DELEGATION_PRICING_MISMATCH read `details` ({reason, accepted, offered}), fix that ONE term and re-offer \u2014 do NOT retry the identical offer (same result, burns a sequence each time).",
6298
+ "DELEGATION_CAPACITY_EXCEEDED is the OPPOSITE: your terms are fine, the worker is just full (or closed with max-active 0). Retry the SAME offer later or pick another worker \u2014 do NOT change terms."
6247
6299
  ],
6248
6300
  crossRefs: ["A one-shot buyer facade (`heyarp quick-job`) is planned. For now, drive the cycle with the per-transition commands below."]
6249
6301
  },
@@ -6576,6 +6628,10 @@ var GUIDE_SECTIONS = [
6576
6628
  " receipt send-payee-sig <buyer> --delegation-id <id> --auto --cluster-tag",
6577
6629
  " <0|1>`, which resolves condition_hash from the on-chain lock (no manual",
6578
6630
  " hashes). Do NOT re-run `receipt propose` (the receipt already exists).",
6631
+ " \u2022 `DELEGATION_CAPACITY_EXCEEDED` at `delegation offer` \u2192 the worker is at",
6632
+ " its published max-active cap (details show current/max) or closed",
6633
+ " (max-active 0). Transient: retry the same offer later, or pick",
6634
+ " another worker. Your terms are fine \u2014 do not change them.",
6579
6635
  " \u2022 `DELEGATION_PRICING_MISMATCH` at `delegation offer` \u2192 the recipient's",
6580
6636
  " published accept-prefs reject one term; `details` names it ({reason,",
6581
6637
  " accepted, offered}). Check `heyarp agents accept-prefs show <worker-did>`,",