@indigoai-us/hq-cli 5.345.145 → 5.345.146

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/CHANGELOG.md CHANGED
@@ -2,6 +2,9 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [5.345.146] — 2026-10-17
6
+ - `hq capacity route` and `hq lanes create --account auto` can now use a Claude account whose weekly limit is used up but whose paid extra usage is on. Pass `--allow-extra-usage` to allow it; the account is picked last. Without the flag, the refusal now says extra usage is on and names the flag.
7
+
5
8
  ## [5.345.145] — 2026-10-17
6
9
  - `hq core checkpoint`: the background checkpoint helper now fills in automatic
7
10
  saves that were queued before it started. It writes its own report first,
@@ -10375,6 +10375,10 @@ export declare const COMMAND_CATALOG: readonly [{
10375
10375
  readonly description: "Minimum headroom percent the pick must clear (0-100)";
10376
10376
  readonly hidden: false;
10377
10377
  readonly defaultValue: "15";
10378
+ }, {
10379
+ readonly flags: "--allow-extra-usage";
10380
+ readonly description: "Rank a Claude account whose plan limit is used up but whose paid extra usage is on (ranked last)";
10381
+ readonly hidden: false;
10378
10382
  }, {
10379
10383
  readonly flags: "--json";
10380
10384
  readonly description: "Print the route result as JSON (default)";
@@ -14052,6 +14056,10 @@ export declare const COMMAND_CATALOG: readonly [{
14052
14056
  readonly flags: "--account <id>";
14053
14057
  readonly description: "Provider account id, or 'auto' to pick the account with the most room (all accounts are one pool across companies)";
14054
14058
  readonly hidden: false;
14059
+ }, {
14060
+ readonly flags: "--allow-extra-usage";
14061
+ readonly description: "With --account auto, allow a Claude account whose plan limit is used up but whose paid extra usage is on; ranked last";
14062
+ readonly hidden: false;
14055
14063
  }, {
14056
14064
  readonly flags: "--model <id>";
14057
14065
  readonly description: "Model id for the provider CLI";
@@ -12573,6 +12573,11 @@ export const COMMAND_CATALOG = [
12573
12573
  "hidden": false,
12574
12574
  "defaultValue": "15"
12575
12575
  },
12576
+ {
12577
+ "flags": "--allow-extra-usage",
12578
+ "description": "Rank a Claude account whose plan limit is used up but whose paid extra usage is on (ranked last)",
12579
+ "hidden": false
12580
+ },
12576
12581
  {
12577
12582
  "flags": "--json",
12578
12583
  "description": "Print the route result as JSON (default)",
@@ -17082,6 +17087,11 @@ export const COMMAND_CATALOG = [
17082
17087
  "description": "Provider account id, or 'auto' to pick the account with the most room (all accounts are one pool across companies)",
17083
17088
  "hidden": false
17084
17089
  },
17090
+ {
17091
+ "flags": "--allow-extra-usage",
17092
+ "description": "With --account auto, allow a Claude account whose plan limit is used up but whose paid extra usage is on; ranked last",
17093
+ "hidden": false
17094
+ },
17085
17095
  {
17086
17096
  "flags": "--model <id>",
17087
17097
  "description": "Model id for the provider CLI",
@@ -358,6 +358,7 @@ export function registerCapacityCommand(program) {
358
358
  .option("--model <id>", "Model id. Narrows --provider any to the mapped provider")
359
359
  .option("--prefer <list>", "Comma-separated preferred provider order", "claude,codex,grok")
360
360
  .option("--floor <percent>", "Minimum headroom percent the pick must clear (0-100)", "15")
361
+ .option("--allow-extra-usage", "Rank a Claude account whose plan limit is used up but whose paid extra usage is on (ranked last)")
361
362
  .option("--json", "Print the route result as JSON (default)")
362
363
  .option("--text", "Print a single-line text summary instead of JSON")
363
364
  .action((_opts, command) => {
@@ -394,6 +395,7 @@ export function registerCapacityCommand(program) {
394
395
  collectorEnabled: mark ? mark.enabled : null,
395
396
  capacityStale: freshness.stale,
396
397
  lanesError,
398
+ allowExtraUsage: opts.allowExtraUsage === true,
397
399
  });
398
400
  }
399
401
  catch (err) {
@@ -3483,6 +3483,7 @@ async function runCreate(ctx, opts) {
3483
3483
  collectorEnabled: readCollectorMark(ledgerOptions)?.enabled ?? null,
3484
3484
  capacityStale: capacityViewAge(view.generatedAt, ctx.now().getTime()).stale,
3485
3485
  lanesError: routeLanesError,
3486
+ allowExtraUsage: opts.allowExtraUsage === true,
3486
3487
  });
3487
3488
  if (!result.ok || !result.pick) {
3488
3489
  const resetSuffix = result.next_reset ? `; next reset ${result.next_reset}` : "";
@@ -9935,6 +9936,7 @@ export function registerLanesCommand(parent, deps = {}) {
9935
9936
  .option("--remote-control", "Open a Claude lane in Remote Control using account a for login and the selected account for inference")
9936
9937
  .option("--title <text>", "Human-readable Claude Remote Control session title; required with --remote-control")
9937
9938
  .option("--account <id>", "Provider account id, or 'auto' to pick the account with the most room (all accounts are one pool across companies)")
9939
+ .option("--allow-extra-usage", "With --account auto, allow a Claude account whose plan limit is used up but whose paid extra usage is on; ranked last")
9938
9940
  .option("--model <id>", "Model id for the provider CLI")
9939
9941
  .option("--effort <level>", "Effort level; claude: low|medium|high|xhigh|max, codex: minimal|low|medium|high|xhigh|max|ultra, grok: low|medium|high|xhigh")
9940
9942
  .option("--senior <ref>", "session:<id> | lane:<id> | user")
@@ -1,6 +1,6 @@
1
1
  import type { LaneRecord, LaneState, LanesConfig } from "../lanes/types.js";
2
2
  import { type LaneProvider } from "../lanes/types.js";
3
- import { type NowLimit, type NowView } from "./ledger.js";
3
+ import { type NowAccount, type NowLimit, type NowView } from "./ledger.js";
4
4
  /** All lane providers, in the stable order boss-route uses for ranking ties. */
5
5
  export declare const ROUTE_PROVIDERS: readonly LaneProvider[];
6
6
  /** Lane states that count against an account's live load. */
@@ -28,6 +28,12 @@ export declare const OLD_READING_PENALTY = 10;
28
28
  * view stale). Sits below any account with fresh known headroom.
29
29
  */
30
30
  export declare const UNKNOWN_USAGE_SCORE = -100;
31
+ /**
32
+ * Score for an account whose plan limit is used up but which still runs on
33
+ * paid extra usage. Ranked only with --allow-extra-usage, below every account
34
+ * with plan room or unknown usage.
35
+ */
36
+ export declare const EXTRA_USAGE_SCORE = -200;
31
37
  /** Default --floor applied by the CLI (percent headroom to clear). */
32
38
  export declare const DEFAULT_FLOOR = 15;
33
39
  /** Default --prefer order applied by the CLI. */
@@ -85,6 +91,8 @@ export interface RouteRanked {
85
91
  lane_flags: string;
86
92
  /** True when no usable reading exists and the account is ranked as unknown. */
87
93
  usage_unknown: boolean;
94
+ /** True when a plan limit is used up and the lane would spend paid extra usage. */
95
+ extra_usage?: boolean;
88
96
  }
89
97
  /** Live lane on an account the router would avoid; command names a replacement. */
90
98
  export interface RouteMove {
@@ -130,6 +138,12 @@ export interface PickAccountInput {
130
138
  capacityStale?: boolean;
131
139
  /** Error summary when the lanes list could not be read. */
132
140
  lanesError?: string | null;
141
+ /**
142
+ * Owner opt-in (2026-10-17): rank an account whose plan limit is used up
143
+ * but whose Claude extra usage is enabled and not capped. Off by default so
144
+ * lanes never spend paid usage without being asked to.
145
+ */
146
+ allowExtraUsage?: boolean;
133
147
  }
134
148
  export declare class RouteUsageError extends Error {
135
149
  readonly code = "route_usage";
@@ -141,6 +155,12 @@ export declare function resolveRequestedProviders(raw: readonly string[] | undef
141
155
  export declare function resolvePreferOrder(raw: readonly string[] | undefined): LaneProvider[];
142
156
  /** Parse `--floor <n>`; 0..100 inclusive, default DEFAULT_FLOOR when missing. */
143
157
  export declare function resolveFloor(raw: string | number | undefined): number;
158
+ /**
159
+ * True when the account's Claude extra usage reading says the provider will
160
+ * keep serving it after a plan limit runs out: enabled, not at its monthly
161
+ * cap, and not stopped by a spend control.
162
+ */
163
+ export declare function hasExtraUsageRoom(account: NowAccount): boolean;
144
164
  /**
145
165
  * Pure routing decision over a snapshot: scores every signed-in lane account,
146
166
  * applies the --prefer order under the --floor headroom, returns the pick (or
@@ -47,6 +47,12 @@ export const OLD_READING_PENALTY = 10;
47
47
  * view stale). Sits below any account with fresh known headroom.
48
48
  */
49
49
  export const UNKNOWN_USAGE_SCORE = -100;
50
+ /**
51
+ * Score for an account whose plan limit is used up but which still runs on
52
+ * paid extra usage. Ranked only with --allow-extra-usage, below every account
53
+ * with plan room or unknown usage.
54
+ */
55
+ export const EXTRA_USAGE_SCORE = -200;
50
56
  /** Default --floor applied by the CLI (percent headroom to clear). */
51
57
  export const DEFAULT_FLOOR = 15;
52
58
  /** Default --prefer order applied by the CLI. */
@@ -178,6 +184,27 @@ function liveLaneCount(lanes, provider, account) {
178
184
  }
179
185
  return count;
180
186
  }
187
+ /**
188
+ * True when the account's Claude extra usage reading says the provider will
189
+ * keep serving it after a plan limit runs out: enabled, not at its monthly
190
+ * cap, and not stopped by a spend control.
191
+ */
192
+ export function hasExtraUsageRoom(account) {
193
+ const limits = account.limits ?? [];
194
+ const extra = limits.find((l) => l.kind === "credits" && l.limitId === "extra_usage");
195
+ if (!extra || extra.hasCredits !== true)
196
+ return false;
197
+ if (extra.spendControlReached === true)
198
+ return false;
199
+ if (typeof extra.usedPercent === "number" && extra.usedPercent >= 100)
200
+ return false;
201
+ const spend = limits.find((l) => l.kind === "credits" && l.limitId === "spend");
202
+ if (spend?.spendControlReached === true)
203
+ return false;
204
+ if (spend && typeof spend.usedPercent === "number" && spend.usedPercent >= 100)
205
+ return false;
206
+ return true;
207
+ }
181
208
  function limitAgeMs(view, nowMs) {
182
209
  if (!view.resetPassed || !view.limit.resetsAt)
183
210
  return view.readAge;
@@ -368,9 +395,49 @@ export function pickAccount(input) {
368
395
  && row.readAge <= LIMIT_STALE_MS
369
396
  && (row.limit.state === "exhausted" || (typeof row.used === "number" && row.used >= 100)));
370
397
  if (exhausted) {
398
+ const extraRoom = providerId === "claude" && hasExtraUsageRoom(account);
399
+ if (extraRoom && input.allowExtraUsage === true) {
400
+ const live = liveLaneCount(lanes, providerId, laneMatch.id);
401
+ const weekly = applicable.find((l) => l.kind === "weekly_all");
402
+ const whyParts = [
403
+ `${labelLimit(exhausted.limit)} used up; runs on paid extra usage (--allow-extra-usage)`,
404
+ ];
405
+ if (live)
406
+ whyParts.push(`${live} live lane${live === 1 ? "" : "s"} already on it`);
407
+ if (tokenExpired)
408
+ whyParts.push("sign-in renews when the lane starts");
409
+ ranked.push({
410
+ provider: providerId,
411
+ account: laneMatch.id,
412
+ label,
413
+ organization: account.organization ?? null,
414
+ headroom: 0,
415
+ score: EXTRA_USAGE_SCORE - live * LANE_PENALTY,
416
+ live_lanes: live,
417
+ reset_soon: false,
418
+ token_expired: tokenExpired,
419
+ reading_age_h: Math.round(limitAgeMs(exhausted, nowMs) / 36e5),
420
+ binding: {
421
+ limit: labelLimit(exhausted.limit),
422
+ used_percent: typeof exhausted.used === "number" ? exhausted.used : 100,
423
+ resets_at: exhausted.limit.resetsAt ?? null,
424
+ },
425
+ weekly_resets_at: weekly?.resetsAt ?? null,
426
+ why: whyParts.join("; "),
427
+ lane_flags: `--provider ${providerId} --account ${laneMatch.id}`,
428
+ usage_unknown: false,
429
+ extra_usage: true,
430
+ });
431
+ continue;
432
+ }
371
433
  skipped.push({
372
434
  ...base,
373
- reason: `${labelLimit(exhausted.limit)} used up`,
435
+ reason: extraRoom
436
+ ? `${labelLimit(exhausted.limit)} used up; extra usage is on`
437
+ : `${labelLimit(exhausted.limit)} used up`,
438
+ ...(extraRoom
439
+ ? { fix: "pass --allow-extra-usage to run on paid extra usage" }
440
+ : {}),
374
441
  resets_at: exhausted.limit.resetsAt ?? null,
375
442
  });
376
443
  continue;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indigoai-us/hq-cli",
3
- "version": "5.345.145",
3
+ "version": "5.345.146",
4
4
  "description": "HQ by Indigo management CLI — modules and cloud sync",
5
5
  "main": "dist/index.js",
6
6
  "bin": {