claudish 14.8.0 → 14.10.0

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.
Files changed (2) hide show
  1. package/dist/index.js +316 -83
  2. package/package.json +5 -5
package/dist/index.js CHANGED
@@ -1716,6 +1716,12 @@ function handleIntersectionResults(result, left, right) {
1716
1716
  result.value = merged.data;
1717
1717
  return result;
1718
1718
  }
1719
+ function handleTupleResult(result, final, index) {
1720
+ if (result.issues.length) {
1721
+ final.issues.push(...prefixIssues(index, result.issues));
1722
+ }
1723
+ final.value[index] = result.value;
1724
+ }
1719
1725
  function handleOptionalResult(result, input) {
1720
1726
  if (result.issues.length && input === undefined) {
1721
1727
  return { issues: [], value: undefined };
@@ -1764,7 +1770,7 @@ function handleRefineResult(result, payload, input, inst) {
1764
1770
  payload.issues.push(issue(_iss));
1765
1771
  }
1766
1772
  }
1767
- var $ZodType, $ZodString, $ZodStringFormat, $ZodGUID, $ZodUUID, $ZodEmail, $ZodURL, $ZodEmoji, $ZodNanoID, $ZodCUID, $ZodCUID2, $ZodULID, $ZodXID, $ZodKSUID, $ZodISODateTime, $ZodISODate, $ZodISOTime, $ZodISODuration, $ZodIPv4, $ZodIPv6, $ZodCIDRv4, $ZodCIDRv6, $ZodBase64, $ZodBase64URL, $ZodE164, $ZodJWT, $ZodNumber, $ZodNumberFormat, $ZodBoolean, $ZodNull, $ZodUnknown, $ZodNever, $ZodArray, $ZodObject, $ZodObjectJIT, $ZodUnion, $ZodDiscriminatedUnion, $ZodIntersection, $ZodRecord, $ZodEnum, $ZodLiteral, $ZodTransform, $ZodOptional, $ZodNullable, $ZodDefault, $ZodPrefault, $ZodNonOptional, $ZodCatch, $ZodPipe, $ZodReadonly, $ZodCustom;
1773
+ var $ZodType, $ZodString, $ZodStringFormat, $ZodGUID, $ZodUUID, $ZodEmail, $ZodURL, $ZodEmoji, $ZodNanoID, $ZodCUID, $ZodCUID2, $ZodULID, $ZodXID, $ZodKSUID, $ZodISODateTime, $ZodISODate, $ZodISOTime, $ZodISODuration, $ZodIPv4, $ZodIPv6, $ZodCIDRv4, $ZodCIDRv6, $ZodBase64, $ZodBase64URL, $ZodE164, $ZodJWT, $ZodNumber, $ZodNumberFormat, $ZodBoolean, $ZodNull, $ZodUnknown, $ZodNever, $ZodArray, $ZodObject, $ZodObjectJIT, $ZodUnion, $ZodDiscriminatedUnion, $ZodIntersection, $ZodTuple, $ZodRecord, $ZodEnum, $ZodLiteral, $ZodTransform, $ZodOptional, $ZodNullable, $ZodDefault, $ZodPrefault, $ZodNonOptional, $ZodCatch, $ZodPipe, $ZodReadonly, $ZodCustom;
1768
1774
  var init_schemas = __esm(() => {
1769
1775
  init_checks();
1770
1776
  init_core();
@@ -2510,6 +2516,74 @@ var init_schemas = __esm(() => {
2510
2516
  return handleIntersectionResults(payload, left, right);
2511
2517
  };
2512
2518
  });
2519
+ $ZodTuple = /* @__PURE__ */ $constructor("$ZodTuple", (inst, def) => {
2520
+ $ZodType.init(inst, def);
2521
+ const items = def.items;
2522
+ inst._zod.parse = (payload, ctx) => {
2523
+ const input = payload.value;
2524
+ if (!Array.isArray(input)) {
2525
+ payload.issues.push({
2526
+ input,
2527
+ inst,
2528
+ expected: "tuple",
2529
+ code: "invalid_type"
2530
+ });
2531
+ return payload;
2532
+ }
2533
+ payload.value = [];
2534
+ const proms = [];
2535
+ const reversedIndex = [...items].reverse().findIndex((item) => item._zod.optin !== "optional");
2536
+ const optStart = reversedIndex === -1 ? 0 : items.length - reversedIndex;
2537
+ if (!def.rest) {
2538
+ const tooBig = input.length > items.length;
2539
+ const tooSmall = input.length < optStart - 1;
2540
+ if (tooBig || tooSmall) {
2541
+ payload.issues.push({
2542
+ ...tooBig ? { code: "too_big", maximum: items.length } : { code: "too_small", minimum: items.length },
2543
+ input,
2544
+ inst,
2545
+ origin: "array"
2546
+ });
2547
+ return payload;
2548
+ }
2549
+ }
2550
+ let i = -1;
2551
+ for (const item of items) {
2552
+ i++;
2553
+ if (i >= input.length) {
2554
+ if (i >= optStart)
2555
+ continue;
2556
+ }
2557
+ const result = item._zod.run({
2558
+ value: input[i],
2559
+ issues: []
2560
+ }, ctx);
2561
+ if (result instanceof Promise) {
2562
+ proms.push(result.then((result) => handleTupleResult(result, payload, i)));
2563
+ } else {
2564
+ handleTupleResult(result, payload, i);
2565
+ }
2566
+ }
2567
+ if (def.rest) {
2568
+ const rest = input.slice(items.length);
2569
+ for (const el of rest) {
2570
+ i++;
2571
+ const result = def.rest._zod.run({
2572
+ value: el,
2573
+ issues: []
2574
+ }, ctx);
2575
+ if (result instanceof Promise) {
2576
+ proms.push(result.then((result) => handleTupleResult(result, payload, i)));
2577
+ } else {
2578
+ handleTupleResult(result, payload, i);
2579
+ }
2580
+ }
2581
+ }
2582
+ if (proms.length)
2583
+ return Promise.all(proms).then(() => payload);
2584
+ return payload;
2585
+ };
2586
+ });
2513
2587
  $ZodRecord = /* @__PURE__ */ $constructor("$ZodRecord", (inst, def) => {
2514
2588
  $ZodType.init(inst, def);
2515
2589
  inst._zod.parse = (payload, ctx) => {
@@ -3701,6 +3775,17 @@ function intersection(left, right) {
3701
3775
  right
3702
3776
  });
3703
3777
  }
3778
+ function tuple(items, _paramsOrRest, _params) {
3779
+ const hasRest = _paramsOrRest instanceof $ZodType;
3780
+ const params = hasRest ? _params : _paramsOrRest;
3781
+ const rest = hasRest ? _paramsOrRest : null;
3782
+ return new ZodTuple({
3783
+ type: "tuple",
3784
+ items,
3785
+ rest,
3786
+ ...normalizeParams(params)
3787
+ });
3788
+ }
3704
3789
  function record(keyType, valueType, params) {
3705
3790
  return new ZodRecord({
3706
3791
  type: "record",
@@ -3799,7 +3884,7 @@ function superRefine(fn) {
3799
3884
  function preprocess(fn, schema) {
3800
3885
  return pipe(transform(fn), schema);
3801
3886
  }
3802
- var ZodType, _ZodString, ZodString, ZodStringFormat, ZodEmail, ZodGUID, ZodUUID, ZodURL, ZodEmoji, ZodNanoID, ZodCUID, ZodCUID2, ZodULID, ZodXID, ZodKSUID, ZodIPv4, ZodIPv6, ZodCIDRv4, ZodCIDRv6, ZodBase64, ZodBase64URL, ZodE164, ZodJWT, ZodNumber, ZodNumberFormat, ZodBoolean, ZodNull, ZodUnknown, ZodNever, ZodArray, ZodObject, ZodUnion, ZodDiscriminatedUnion, ZodIntersection, ZodRecord, ZodEnum, ZodLiteral, ZodTransform, ZodOptional, ZodNullable, ZodDefault, ZodPrefault, ZodNonOptional, ZodCatch, ZodPipe, ZodReadonly, ZodCustom;
3887
+ var ZodType, _ZodString, ZodString, ZodStringFormat, ZodEmail, ZodGUID, ZodUUID, ZodURL, ZodEmoji, ZodNanoID, ZodCUID, ZodCUID2, ZodULID, ZodXID, ZodKSUID, ZodIPv4, ZodIPv6, ZodCIDRv4, ZodCIDRv6, ZodBase64, ZodBase64URL, ZodE164, ZodJWT, ZodNumber, ZodNumberFormat, ZodBoolean, ZodNull, ZodUnknown, ZodNever, ZodArray, ZodObject, ZodUnion, ZodDiscriminatedUnion, ZodIntersection, ZodTuple, ZodRecord, ZodEnum, ZodLiteral, ZodTransform, ZodOptional, ZodNullable, ZodDefault, ZodPrefault, ZodNonOptional, ZodCatch, ZodPipe, ZodReadonly, ZodCustom;
3803
3888
  var init_schemas2 = __esm(() => {
3804
3889
  init_core2();
3805
3890
  init_core2();
@@ -4103,6 +4188,14 @@ var init_schemas2 = __esm(() => {
4103
4188
  $ZodIntersection.init(inst, def);
4104
4189
  ZodType.init(inst, def);
4105
4190
  });
4191
+ ZodTuple = /* @__PURE__ */ $constructor("ZodTuple", (inst, def) => {
4192
+ $ZodTuple.init(inst, def);
4193
+ ZodType.init(inst, def);
4194
+ inst.rest = (rest) => inst.clone({
4195
+ ...inst._zod.def,
4196
+ rest
4197
+ });
4198
+ });
4106
4199
  ZodRecord = /* @__PURE__ */ $constructor("ZodRecord", (inst, def) => {
4107
4200
  $ZodRecord.init(inst, def);
4108
4201
  ZodType.init(inst, def);
@@ -5398,7 +5491,7 @@ var init_onepassword_config = __esm(() => {
5398
5491
  });
5399
5492
 
5400
5493
  // src/version.ts
5401
- var VERSION = "14.8.0";
5494
+ var VERSION = "14.10.0";
5402
5495
 
5403
5496
  // src/redact.ts
5404
5497
  function isPlaceholder(value) {
@@ -16042,7 +16135,7 @@ var init_minimax_model_dialect = __esm(() => {
16042
16135
  });
16043
16136
 
16044
16137
  // src/auth/accounts/allowance-report-schema.ts
16045
- var ALLOWANCE_REPORT_SCHEMA = "claudish.allowance.v1", iso, fraction, finite, nonNegative, quantilesOf = (t) => object({ p10: t, p25: t, p50: t, p75: t, p90: t }), alertLevel, strategyName, evidence, unit, provenance, semantics, gapKind, exactness, accountSchema, remedySchema, alertSchema, historyPoint, trajectorySchema, sessionSchema, allowanceReportSchema, ALLOWANCE_REPORT_SECTIONS, partialReport, allowanceStatusAnswerSchema;
16138
+ var ALLOWANCE_REPORT_SCHEMA = "claudish.allowance.v1", iso, fraction, finite, nonNegative, quantilesOf = (t) => object({ p10: t, p25: t, p50: t, p75: t, p90: t }), alertLevel, strategyName, evidence, unit, provenance, semantics, gapKind, exactness, accountSchema, remedySchema, alertSchema, historyPoint, switchSchema, blockedSchema, trajectorySchema, usageSchema, sessionSchema, allowanceReportSchema, ALLOWANCE_REPORT_SECTIONS, ALLOWANCE_REPORT_SECTIONS_V1_BASE, partialReport, allowanceStatusAnswerSchema;
16046
16139
  var init_allowance_report_schema = __esm(() => {
16047
16140
  init_zod();
16048
16141
  iso = exports_iso.datetime({ offset: true });
@@ -16101,26 +16194,45 @@ var init_allowance_report_schema = __esm(() => {
16101
16194
  remaining: finite,
16102
16195
  provenance: _enum(["observed", "reset-inferred"])
16103
16196
  });
16197
+ switchSchema = object({
16198
+ accountId: string2(),
16199
+ soonest: iso,
16200
+ usual: iso,
16201
+ latest: iso,
16202
+ probability: fraction,
16203
+ likelihood: object({
16204
+ start: iso,
16205
+ stepHours: literal(1),
16206
+ p: array(number2().min(0).max(1)).min(1)
16207
+ }).optional()
16208
+ });
16209
+ blockedSchema = object({ from: iso, to: iso, kind: gapKind, probability: fraction });
16104
16210
  trajectorySchema = object({
16105
16211
  history: array(historyPoint),
16106
16212
  historyByAccount: array(object({ accountId: string2(), history: array(historyPoint) })).optional(),
16107
16213
  forecast: array(object({ at: iso, p10: finite, p50: finite, p90: finite, pBlocked: fraction })),
16108
16214
  resets: array(object({ at: iso, account: string2(), window: string2(), projected: boolean2() })),
16109
- blocked: array(object({ from: iso, to: iso, kind: gapKind, probability: fraction })),
16110
- switches: array(object({
16111
- accountId: string2(),
16112
- soonest: iso,
16113
- usual: iso,
16114
- latest: iso,
16115
- probability: fraction,
16116
- likelihood: object({
16117
- start: iso,
16118
- stepHours: literal(1),
16119
- p: array(number2().min(0).max(1)).min(1)
16120
- }).optional()
16121
- })).optional(),
16215
+ blocked: array(blockedSchema),
16216
+ switches: array(switchSchema).optional(),
16217
+ slower: object({
16218
+ factor: number2().gt(0).lt(1),
16219
+ switches: array(switchSchema),
16220
+ blocked: array(blockedSchema)
16221
+ }).optional(),
16122
16222
  spark48: string2().regex(/^[\u2581\u2582\u2583\u2584\u2585\u2586\u2587\u2588\u2592\u2593\u250A ]*$/u)
16123
16223
  });
16224
+ usageSchema = object({
16225
+ start: iso,
16226
+ stepHours: literal(1),
16227
+ hours: literal(336),
16228
+ unit: literal("cu"),
16229
+ coveredFrom: iso.nullable(),
16230
+ accounts: array(object({
16231
+ accountId: string2(),
16232
+ cu: array(number2().int().min(0)).length(336)
16233
+ })),
16234
+ censored: array(tuple([number2().int().min(0).max(335), number2().int().min(1).max(60)]))
16235
+ });
16124
16236
  sessionSchema = object({
16125
16237
  session: union([string2().max(8), literal("unattributed")]),
16126
16238
  parent: union([string2().max(8), _null3()]).optional(),
@@ -16163,9 +16275,19 @@ var init_allowance_report_schema = __esm(() => {
16163
16275
  blockedNow: boolean2(),
16164
16276
  status: _enum(["ok", "insufficient-evidence"]),
16165
16277
  trajectory: trajectorySchema,
16166
- sessions: array(sessionSchema)
16278
+ sessions: array(sessionSchema),
16279
+ usage: usageSchema.optional()
16167
16280
  });
16168
16281
  ALLOWANCE_REPORT_SECTIONS = [
16282
+ "accounts",
16283
+ "alerts",
16284
+ "burn",
16285
+ "combined",
16286
+ "sessions",
16287
+ "trajectory",
16288
+ "usage"
16289
+ ];
16290
+ ALLOWANCE_REPORT_SECTIONS_V1_BASE = [
16169
16291
  "accounts",
16170
16292
  "alerts",
16171
16293
  "burn",
@@ -16179,7 +16301,8 @@ var init_allowance_report_schema = __esm(() => {
16179
16301
  burn: true,
16180
16302
  combined: true,
16181
16303
  sessions: true,
16182
- trajectory: true
16304
+ trajectory: true,
16305
+ usage: true
16183
16306
  });
16184
16307
  allowanceStatusAnswerSchema = object({
16185
16308
  contract_version: literal(1),
@@ -16190,7 +16313,7 @@ var init_allowance_report_schema = __esm(() => {
16190
16313
  }).superRefine((answer, ctx) => {
16191
16314
  if (answer.allowance === null)
16192
16315
  return;
16193
- const wanted = answer.sections ?? ALLOWANCE_REPORT_SECTIONS;
16316
+ const wanted = answer.sections ?? ALLOWANCE_REPORT_SECTIONS_V1_BASE;
16194
16317
  for (const section of wanted) {
16195
16318
  if (answer.allowance[section] === undefined) {
16196
16319
  ctx.addIssue({
@@ -16651,7 +16774,7 @@ function cuOf(tokens, cfg) {
16651
16774
  const uncached = Math.max(0, tokens.input - tokens.cacheRead - tokens.cacheWrite);
16652
16775
  return uncached + w.cacheRead * tokens.cacheRead + w.cacheWrite * tokens.cacheWrite + w.output * tokens.output;
16653
16776
  }
16654
- var PROVIDER_COST_PRIORS, MINUTE_MS2 = 60000, HOUR_MS2, DEFAULT_ALLOWANCE_CONFIG, LOOKAHEAD_TRAJ_PATHS = 40, MIN_PATH_SHARE = 0.1, PACE_MAX_MULT = 64, PACE_BISECT_STEPS = 4;
16777
+ var PROVIDER_COST_PRIORS, MINUTE_MS2 = 60000, HOUR_MS2, DEFAULT_ALLOWANCE_CONFIG, LOOKAHEAD_TRAJ_PATHS = 40, MIN_PATH_SHARE = 0.1, SLOWER_FACTOR, PACE_MAX_MULT = 64, PACE_BISECT_STEPS = 4, USAGE_HOURS = 336;
16655
16778
  var init_constants = __esm(() => {
16656
16779
  PROVIDER_COST_PRIORS = {
16657
16780
  "openai-codex": { cacheRead: 0.1, cacheWrite: 1, output: 4 },
@@ -16714,6 +16837,7 @@ var init_constants = __esm(() => {
16714
16837
  SESSION_TTL_D: 8,
16715
16838
  SESSIONS_MAX: 2048
16716
16839
  };
16840
+ SLOWER_FACTOR = 2 / 3;
16717
16841
  });
16718
16842
 
16719
16843
  // src/auth/accounts/allowance/capacity.ts
@@ -17094,7 +17218,8 @@ function initialState() {
17094
17218
  sessions: {},
17095
17219
  seen: [],
17096
17220
  censorOpenAt: null,
17097
- lastAt: null
17221
+ lastAt: null,
17222
+ recordedFrom: null
17098
17223
  };
17099
17224
  }
17100
17225
  function observeAll(s, es, cfg) {
@@ -17138,6 +17263,7 @@ function fold(s, e, cfg, seen) {
17138
17263
  }
17139
17264
  switch (e.kind) {
17140
17265
  case "response": {
17266
+ record3(s, hourOf(e.at));
17141
17267
  const account = ensureAccount(s, e.account);
17142
17268
  const cu = cuOf(e.tokens, cfg);
17143
17269
  if (cu > 0) {
@@ -17158,6 +17284,7 @@ function fold(s, e, cfg, seen) {
17158
17284
  touch(s, e.at);
17159
17285
  return;
17160
17286
  case "no-eligible":
17287
+ record3(s, hourOf(e.at));
17161
17288
  if (e.until === undefined) {
17162
17289
  if (s.censorOpenAt === null)
17163
17290
  s.censorOpenAt = e.at;
@@ -17187,6 +17314,7 @@ function fold(s, e, cfg, seen) {
17187
17314
  return;
17188
17315
  }
17189
17316
  case "rollup": {
17317
+ record3(s, e.hour);
17190
17318
  const account = ensureAccount(s, e.account);
17191
17319
  const cu = cuOf(e.tokens, cfg);
17192
17320
  const mid = e.hour + HOUR_MS4 / 2;
@@ -17206,6 +17334,11 @@ function fold(s, e, cfg, seen) {
17206
17334
  }
17207
17335
  }
17208
17336
  }
17337
+ function record3(s, hour) {
17338
+ const from = s.recordedFrom ?? null;
17339
+ if (from === null || hour < from)
17340
+ s.recordedFrom = hour;
17341
+ }
17209
17342
  function touch(s, at) {
17210
17343
  if (s.lastAt === null || at > s.lastAt)
17211
17344
  s.lastAt = at;
@@ -20049,7 +20182,8 @@ function trajectory(s, now, horizonMs, cal, cfg) {
20049
20182
  blocked: [],
20050
20183
  switches: [],
20051
20184
  lostAtReset: {},
20052
- historyByAccount
20185
+ historyByAccount,
20186
+ slower: { factor: SLOWER_FACTOR, switches: [], blocked: [] }
20053
20187
  };
20054
20188
  if (evidenceOf(s, now) === "none" || all.length === 0)
20055
20189
  return empty;
@@ -20062,19 +20196,23 @@ function trajectory(s, now, horizonMs, cal, cfg) {
20062
20196
  const alertCfg = alertModelConfig(cfg);
20063
20197
  const paths = trajPaths(alertCfg);
20064
20198
  const results = [];
20199
+ const slowerResults = [];
20200
+ const run = (drawn, demand) => simulate(drawn, demand, cfg, {
20201
+ now,
20202
+ strategy: STRATEGIES[alertCfg.strategy],
20203
+ thread: { account: null, lastSwitchAt: null, contextTokens: null },
20204
+ poolActive: s.poolActive ?? null,
20205
+ horizonMs
20206
+ });
20065
20207
  for (let p = 0;p < paths; p++) {
20066
20208
  const demand = sampleDemandPath(model, rng);
20067
20209
  const drawn = views.map((v) => drawCapacity(v, rng));
20068
- results.push(simulate(drawn, demand, cfg, {
20069
- now,
20070
- strategy: STRATEGIES[alertCfg.strategy],
20071
- thread: { account: null, lastSwitchAt: null, contextTokens: null },
20072
- poolActive: s.poolActive ?? null,
20073
- horizonMs
20074
- }));
20210
+ results.push(run(drawn, demand));
20211
+ slowerResults.push(run(drawn, demand.map((d) => d * SLOWER_FACTOR)));
20075
20212
  }
20076
20213
  const h0 = hourStart(now);
20077
20214
  const forecast = [];
20215
+ const slowerForecast = [];
20078
20216
  for (let k = 0;k < buckets; k++) {
20079
20217
  const at = h0 + k * HOUR_MS14;
20080
20218
  if (at > end)
@@ -20087,6 +20225,8 @@ function trajectory(s, now, horizonMs, cal, cfg) {
20087
20225
  blocked++;
20088
20226
  }
20089
20227
  forecast.push({ at, q: quantilesOf2(values), pBlocked: blocked / paths });
20228
+ const slowerBlocked = slowerResults.filter((r) => r.blocked[k]?.blocked).length;
20229
+ slowerForecast.push({ at, q: forecast[k].q, pBlocked: slowerBlocked / paths });
20090
20230
  }
20091
20231
  return {
20092
20232
  unit,
@@ -20096,7 +20236,12 @@ function trajectory(s, now, horizonMs, cal, cfg) {
20096
20236
  blocked: blockedRuns(results, forecast),
20097
20237
  switches: switchesOf2(results, views, s.poolActive ?? null, now, end),
20098
20238
  lostAtReset: lostAtResetOf(results, views),
20099
- historyByAccount
20239
+ historyByAccount,
20240
+ slower: {
20241
+ factor: SLOWER_FACTOR,
20242
+ switches: switchesOf2(slowerResults, views, s.poolActive ?? null, now, end),
20243
+ blocked: blockedRuns(slowerResults, slowerForecast)
20244
+ }
20100
20245
  };
20101
20246
  }
20102
20247
  function sparkline(t, cells) {
@@ -20176,6 +20321,55 @@ var init_trajectory = __esm(() => {
20176
20321
  LEVELS = ["\u2581", "\u2582", "\u2583", "\u2584", "\u2585", "\u2586", "\u2587", "\u2588"];
20177
20322
  });
20178
20323
 
20324
+ // src/auth/accounts/allowance/usage.ts
20325
+ function usageByHour(s, now, hours = USAGE_HOURS) {
20326
+ const cells = Math.max(1, Math.floor(hours));
20327
+ const start = hourOf(now) - (cells - 1) * HOUR_MS15;
20328
+ const end = start + cells * HOUR_MS15;
20329
+ const cellOf = (at) => Math.floor((at - start) / HOUR_MS15);
20330
+ const accounts = Object.values(s.accounts).map((a) => {
20331
+ const cu = new Array(cells).fill(0);
20332
+ for (const served of a.served) {
20333
+ if (served.at < start || served.at >= end)
20334
+ continue;
20335
+ const i = cellOf(served.at);
20336
+ cu[i] = (cu[i] ?? 0) + served.cu;
20337
+ }
20338
+ return { account: a.id, order: a.order, enabled: a.enabled, cu };
20339
+ });
20340
+ const censoredMinutes = new Array(cells).fill(0);
20341
+ for (const bucket of s.demand) {
20342
+ if (bucket.hour < start || bucket.hour >= end || bucket.censoredMinutes <= 0)
20343
+ continue;
20344
+ const i = cellOf(bucket.hour);
20345
+ censoredMinutes[i] = Math.min(60, (censoredMinutes[i] ?? 0) + bucket.censoredMinutes);
20346
+ }
20347
+ const open = s.censorOpenAt;
20348
+ if (open !== null) {
20349
+ const until = Math.min(now, end);
20350
+ for (let hour = Math.max(hourOf(open), start);hour < until; hour += HOUR_MS15) {
20351
+ const minutes = (Math.min(until, hour + HOUR_MS15) - Math.max(open, hour)) / MINUTE_MS11;
20352
+ if (minutes <= 0)
20353
+ continue;
20354
+ const i = cellOf(hour);
20355
+ censoredMinutes[i] = Math.min(60, (censoredMinutes[i] ?? 0) + minutes);
20356
+ }
20357
+ }
20358
+ const recorded = s.recordedFrom ?? s.demand[0]?.hour ?? null;
20359
+ return {
20360
+ start,
20361
+ hours: cells,
20362
+ accounts,
20363
+ censoredMinutes,
20364
+ coveredFrom: recorded === null ? null : Math.max(recorded, start)
20365
+ };
20366
+ }
20367
+ var MINUTE_MS11 = 60000, HOUR_MS15 = 3600000;
20368
+ var init_usage = __esm(() => {
20369
+ init_constants();
20370
+ init_state();
20371
+ });
20372
+
20179
20373
  // src/auth/accounts/paths.ts
20180
20374
  import { homedir as homedir10 } from "os";
20181
20375
  import { join as join10 } from "path";
@@ -20948,8 +21142,8 @@ function censoredMinutesByHour(rows, dayBegin, dayEnd, openAtStart = new Set) {
20948
21142
  hours = new Map;
20949
21143
  byProvider.set(provider, hours);
20950
21144
  }
20951
- for (let h = Math.floor(from / HOUR_MS15) * HOUR_MS15;h < to; h += HOUR_MS15) {
20952
- const overlap = Math.min(to, h + HOUR_MS15) - Math.max(from, h);
21145
+ for (let h = Math.floor(from / HOUR_MS16) * HOUR_MS16;h < to; h += HOUR_MS16) {
21146
+ const overlap = Math.min(to, h + HOUR_MS16) - Math.max(from, h);
20953
21147
  if (overlap > 0)
20954
21148
  hours.set(h, Math.min(60, (hours.get(h) ?? 0) + overlap / 60000));
20955
21149
  }
@@ -20991,7 +21185,7 @@ function* rollupDaySteps(day, rows, openAtStart) {
20991
21185
  for (const row of responses) {
20992
21186
  if (++n % COMPACT_SLICE_ROWS === 0)
20993
21187
  yield;
20994
- const hour = Math.floor(row.at / HOUR_MS15) * HOUR_MS15;
21188
+ const hour = Math.floor(row.at / HOUR_MS16) * HOUR_MS16;
20995
21189
  const key = [hour, row.provider, row.accountId, row.session ?? "-", row.model].join("\x00");
20996
21190
  const group = groups.get(key);
20997
21191
  if (group)
@@ -21057,7 +21251,7 @@ function* rollupDaySteps(day, rows, openAtStart) {
21057
21251
  `)}
21058
21252
  ` : "", openAtEnd };
21059
21253
  }
21060
- var LEDGER_QUEUE_MAX = 1024, RAW_DAY_MAX_BYTES, RAW_RETENTION_DAYS = 30, ROLLUP_RETENTION_DAYS = 180, COMPACT_LOCK_STALE_MS, COMPACT_DEFER_MS = 60000, COMPACT_RETRY_MS = 60000, COMPACT_FAILED_RETRY_MS, COMPACT_SLICE_ROWS = 2000, DAY_MS5 = 86400000, HOUR_MS15 = 3600000, DAY_FILE2, queue, dropped = 0, draining = null, scheduled = false, fullDays, compactedDay = null, compactTimer = null, idleProbe = null;
21254
+ var LEDGER_QUEUE_MAX = 1024, RAW_DAY_MAX_BYTES, RAW_RETENTION_DAYS = 30, ROLLUP_RETENTION_DAYS = 180, COMPACT_LOCK_STALE_MS, COMPACT_DEFER_MS = 60000, COMPACT_RETRY_MS = 60000, COMPACT_FAILED_RETRY_MS, COMPACT_SLICE_ROWS = 2000, DAY_MS5 = 86400000, HOUR_MS16 = 3600000, DAY_FILE2, queue, dropped = 0, draining = null, scheduled = false, fullDays, compactedDay = null, compactTimer = null, idleProbe = null;
21061
21255
  var init_ledger_writer = __esm(() => {
21062
21256
  init_logger();
21063
21257
  init_atomic_write();
@@ -22089,8 +22283,8 @@ function vendorLabel(provider) {
22089
22283
  }
22090
22284
  function localCalendar(now) {
22091
22285
  const offsets = [];
22092
- const from = Math.floor((now - LOAD_HISTORY_MS) / HOUR_MS16) * HOUR_MS16;
22093
- for (let t = from;t <= now + CALENDAR_FUTURE_MS; t += HOUR_MS16) {
22286
+ const from = Math.floor((now - LOAD_HISTORY_MS) / HOUR_MS17) * HOUR_MS17;
22287
+ for (let t = from;t <= now + CALENDAR_FUTURE_MS; t += HOUR_MS17) {
22094
22288
  const offsetMinutes = -new Date(t).getTimezoneOffset();
22095
22289
  if (offsets.length === 0 || offsets[offsets.length - 1]?.offsetMinutes !== offsetMinutes) {
22096
22290
  offsets.push({ from: offsets.length === 0 ? 0 : t, offsetMinutes });
@@ -22122,7 +22316,7 @@ function allowanceNotice(provider, transition, alert, accounts, formatTime = for
22122
22316
  return null;
22123
22317
  const { start, end } = gapSpan(alert);
22124
22318
  const who = accounts <= 1 ? "the account is" : accounts === 2 ? "both accounts are" : `all ${accounts} accounts are`;
22125
- const hours = Math.round((end - start) / HOUR_MS16);
22319
+ const hours = Math.round((end - start) / HOUR_MS17);
22126
22320
  const remedy = remedyText(alert.remedy, start, formatTime);
22127
22321
  const advice = remedy ? ` ${remedy.charAt(0).toUpperCase()}${remedy.slice(1)}.` : "";
22128
22322
  return `${vendor} allowance: at the current rate ${who} spent ${formatTime(start)} and blocked until ${formatTime(end)} (${hours} h).${advice} \`claudish account forecast\``;
@@ -22478,7 +22672,7 @@ class AllowanceService {
22478
22672
  const now = this.clock();
22479
22673
  const tail = createLedgerTail({ startAtEnd: true, now, env: this.env });
22480
22674
  await tail.tail();
22481
- const handoff = Math.floor((now - LOAD_RAW_MS) / HOUR_MS16) * HOUR_MS16;
22675
+ const handoff = Math.floor((now - LOAD_RAW_MS) / HOUR_MS17) * HOUR_MS17;
22482
22676
  const [older, recent] = await Promise.all([
22483
22677
  readLedger({ sinceMs: now - LOAD_HISTORY_MS, untilMs: handoff, env: this.env }),
22484
22678
  readLedger({ sinceMs: handoff, source: "raw", env: this.env })
@@ -22560,7 +22754,7 @@ class AllowanceService {
22560
22754
  if (!m.state)
22561
22755
  return;
22562
22756
  const now = this.clock();
22563
- const horizon = m.cfg.SIM_MAX_STEPS * HOUR_MS16;
22757
+ const horizon = m.cfg.SIM_MAX_STEPS * HOUR_MS17;
22564
22758
  if (m.fc && m.fc.key === forecastKey(m.state, now, horizon, m.cal, m.cfg))
22565
22759
  return;
22566
22760
  m.fc = await runSliced(forecastSliced(m.state, now, horizon, m.cal, m.cfg));
@@ -22789,6 +22983,9 @@ async function runSliced(gen) {
22789
22983
  await new Promise((resolve) => setImmediate(resolve));
22790
22984
  }
22791
22985
  }
22986
+ function toSignificant(x, digits) {
22987
+ return x === 0 ? 0 : Number(x.toPrecision(digits));
22988
+ }
22792
22989
  function poolRemaining(views) {
22793
22990
  const read = views.filter(isRead);
22794
22991
  if (read.length === 0)
@@ -22816,7 +23013,20 @@ function likelihoodView(l) {
22816
23013
  let last = p.length - 1;
22817
23014
  while (last > first && p[last] === 0)
22818
23015
  last--;
22819
- return { start: iso2(l.start + first * HOUR_MS16), stepHours: 1, p: p.slice(first, last + 1) };
23016
+ return { start: iso2(l.start + first * HOUR_MS17), stepHours: 1, p: p.slice(first, last + 1) };
23017
+ }
23018
+ function switchView(sw) {
23019
+ return {
23020
+ accountId: sw.account,
23021
+ soonest: iso2(sw.q.p10),
23022
+ usual: iso2(sw.q.p50),
23023
+ latest: iso2(sw.q.p90),
23024
+ probability: Math.min(1, Math.max(0, sw.probability)),
23025
+ likelihood: likelihoodView(sw.likelihood)
23026
+ };
23027
+ }
23028
+ function blockedView(b) {
23029
+ return { from: iso2(b.from.p50), to: iso2(b.to.p50), kind: b.kind, probability: b.probability };
22820
23030
  }
22821
23031
  function sustainableOf(top, pace, burnLong) {
22822
23032
  const long = Number.isFinite(burnLong) ? Math.max(0, burnLong) : 0;
@@ -22824,9 +23034,37 @@ function sustainableOf(top, pace, burnLong) {
22824
23034
  return top.remedy.kind === "cut" ? top.remedy.cutToFraction * long : 0;
22825
23035
  return pace ? paceInCuPerHour(pace, long) : null;
22826
23036
  }
23037
+ function usageView(s, now, views) {
23038
+ const grid = usageByHour(s, now, USAGE_HOURS);
23039
+ const cell = (cu) => cu > 0 ? Math.max(1, Math.round(cu)) : 0;
23040
+ const byId = new Map(grid.accounts.map((a) => [a.account, a]));
23041
+ const listed = new Set(views.map((v) => v.account));
23042
+ const others = grid.accounts.filter((a) => !listed.has(a.account) && a.cu.some((cu) => cu > 0)).sort((a, b) => a.order - b.order || (a.account < b.account ? -1 : 1));
23043
+ const censored = [];
23044
+ grid.censoredMinutes.forEach((minutes, i) => {
23045
+ const m = Math.min(60, Math.round(minutes));
23046
+ if (m > 0)
23047
+ censored.push([i, m]);
23048
+ });
23049
+ return {
23050
+ start: iso2(grid.start),
23051
+ stepHours: 1,
23052
+ hours: USAGE_HOURS,
23053
+ unit: "cu",
23054
+ coveredFrom: grid.coveredFrom === null ? null : iso2(grid.coveredFrom),
23055
+ accounts: [
23056
+ ...views.map((v) => ({
23057
+ accountId: v.account,
23058
+ cu: (byId.get(v.account)?.cu ?? new Array(grid.hours).fill(0)).map(cell)
23059
+ })),
23060
+ ...others.map((a) => ({ accountId: a.account, cu: a.cu.map(cell) }))
23061
+ ],
23062
+ censored
23063
+ };
23064
+ }
22827
23065
  function buildReport(input) {
22828
23066
  const { s, now, cfg, cal, fc } = input;
22829
- const horizonMs = Math.min(168 * HOUR_MS16, Math.max(HOUR_MS16, input.horizonMs));
23067
+ const horizonMs = Math.min(168 * HOUR_MS17, Math.max(HOUR_MS17, input.horizonMs));
22830
23068
  const evidence = evidenceOf(s, now);
22831
23069
  const none = evidence === "none";
22832
23070
  const views = accountViews(s, now, cfg);
@@ -22850,7 +23088,7 @@ function buildReport(input) {
22850
23088
  evidence,
22851
23089
  unit,
22852
23090
  assumption: unit === "account-fraction" ? "equal-capacity" : null,
22853
- horizonHours: Math.round(horizonMs / HOUR_MS16),
23091
+ horizonHours: Math.round(horizonMs / HOUR_MS17),
22854
23092
  accounts: views.map((v) => {
22855
23093
  const g = v.governing === null ? undefined : v.beta[v.governing];
22856
23094
  const k = v.binding === null || v.binding === v.governing ? undefined : v.kappa[v.binding];
@@ -22907,7 +23145,7 @@ function buildReport(input) {
22907
23145
  gapStartEpoch: start,
22908
23146
  gapStart: a.gap.start ? q(a.gap.start, iso2) : null,
22909
23147
  gapEnd: a.gap.end ? q(a.gap.end, iso2) : null,
22910
- gapHours: a.gap.lengthMs ? q(a.gap.lengthMs, (ms) => ms / HOUR_MS16) : null,
23148
+ gapHours: a.gap.lengthMs ? q(a.gap.lengthMs, (ms) => ms / HOUR_MS17) : null,
22911
23149
  pGap: Math.min(1, Math.max(0, a.pGap)),
22912
23150
  binding: a.gap.atLongRate.binding.map((b) => ({
22913
23151
  account: label(b.account),
@@ -22917,7 +23155,7 @@ function buildReport(input) {
22917
23155
  kind: r.kind,
22918
23156
  cutToPercent: r.kind === "cut" ? Math.round(r.cutToFraction * 100) : null,
22919
23157
  until: r.kind === "not-addressable" ? null : iso2(r.until),
22920
- pauseHours: r.kind === "not-addressable" || r.pauseMs === null ? null : r.pauseMs / HOUR_MS16,
23158
+ pauseHours: r.kind === "not-addressable" || r.pauseMs === null ? null : r.pauseMs / HOUR_MS17,
22921
23159
  reason: r.kind === "not-addressable" ? r.reason : null,
22922
23160
  text: remedyText(r, start, fmt)
22923
23161
  }
@@ -22933,9 +23171,9 @@ function buildReport(input) {
22933
23171
  })),
22934
23172
  forecast: traj.forecast.map((f) => ({
22935
23173
  at: iso2(f.at),
22936
- p10: f.q.p10,
22937
- p50: f.q.p50,
22938
- p90: f.q.p90,
23174
+ p10: toSignificant(f.q.p10, FORECAST_DIGITS),
23175
+ p50: toSignificant(f.q.p50, FORECAST_DIGITS),
23176
+ p90: toSignificant(f.q.p90, FORECAST_DIGITS),
22939
23177
  pBlocked: f.pBlocked
22940
23178
  })),
22941
23179
  resets: traj.resets.map((r) => ({
@@ -22944,28 +23182,21 @@ function buildReport(input) {
22944
23182
  window: r.window,
22945
23183
  projected: r.projected
22946
23184
  })),
22947
- blocked: traj.blocked.map((b) => ({
22948
- from: iso2(b.from.p50),
22949
- to: iso2(b.to.p50),
22950
- kind: b.kind,
22951
- probability: b.probability
22952
- })),
23185
+ blocked: traj.blocked.map(blockedView),
22953
23186
  historyByAccount: none ? [] : views.filter((v) => traj.historyByAccount[v.account] !== undefined).map((v) => ({
22954
23187
  accountId: v.account,
22955
- history: (traj.historyByAccount[v.account] ?? []).filter((h) => h.at >= now - 24 * HOUR_MS16).map((h) => ({ at: iso2(h.at), remaining: h.remaining, provenance: h.provenance }))
22956
- })),
22957
- switches: traj.switches.map((sw) => ({
22958
- accountId: sw.account,
22959
- soonest: iso2(sw.q.p10),
22960
- usual: iso2(sw.q.p50),
22961
- latest: iso2(sw.q.p90),
22962
- probability: Math.min(1, Math.max(0, sw.probability)),
22963
- likelihood: likelihoodView(sw.likelihood)
23188
+ history: (traj.historyByAccount[v.account] ?? []).filter((h) => h.at >= now - 24 * HOUR_MS17).map((h) => ({ at: iso2(h.at), remaining: h.remaining, provenance: h.provenance }))
22964
23189
  })),
23190
+ switches: traj.switches.map(switchView),
23191
+ slower: {
23192
+ factor: Math.round(traj.slower.factor * 1000) / 1000,
23193
+ switches: traj.slower.switches.map(switchView),
23194
+ blocked: traj.slower.blocked.map(blockedView)
23195
+ },
22965
23196
  spark48: sparkline({
22966
23197
  ...traj,
22967
- history: traj.history.filter((h) => h.at >= now - 24 * HOUR_MS16),
22968
- forecast: traj.forecast.filter((f) => f.at <= now + 24 * HOUR_MS16)
23198
+ history: traj.history.filter((h) => h.at >= now - 24 * HOUR_MS17),
23199
+ forecast: traj.forecast.filter((f) => f.at <= now + 24 * HOUR_MS17)
22969
23200
  }, 48)
22970
23201
  },
22971
23202
  sessions: none ? [] : contributions(s, { now, window: "binding" }, cfg).map((c) => ({
@@ -22986,7 +23217,8 @@ function buildReport(input) {
22986
23217
  exactness: c.exactness,
22987
23218
  firstAt: iso2(c.firstAt),
22988
23219
  lastAt: iso2(c.lastAt)
22989
- }))
23220
+ })),
23221
+ usage: usageView(s, now, views)
22990
23222
  };
22991
23223
  return allowanceReportSchema.parse(report);
22992
23224
  }
@@ -23038,7 +23270,7 @@ function getAllowanceService() {
23038
23270
  }
23039
23271
  return instance;
23040
23272
  }
23041
- var THREAD_MAP_MAX = 512, THREAD_IDLE_MS, HOUR_MS16 = 3600000, DAY_MS6, LOAD_HISTORY_MS, LOAD_RAW_MS, LOAD_DEFER_MS = 1000, REFRESH_MIN_MS = 60000, SERVED_RECENTLY_MS, ALERTS_LOCK_WAIT_MS = 200, ALERTS_LOCK_STALE_MS = 1e4, ALERTS_CAS_ATTEMPTS = 3, IN_FLIGHT_MAX_MS, PENDING_MAX = 4096, LOAD_RETRY_MIN_MS = 60000, LOAD_RETRY_MAX_MS, ANNOUNCED_MAX = 256, CALENDAR_FUTURE_MS, DECLINE = () => null, iso2 = (at) => new Date(at).toISOString(), instance, safeRankerWarned = false;
23273
+ var THREAD_MAP_MAX = 512, THREAD_IDLE_MS, HOUR_MS17 = 3600000, DAY_MS6, LOAD_HISTORY_MS, LOAD_RAW_MS, LOAD_DEFER_MS = 1000, REFRESH_MIN_MS = 60000, SERVED_RECENTLY_MS, ALERTS_LOCK_WAIT_MS = 200, ALERTS_LOCK_STALE_MS = 1e4, ALERTS_CAS_ATTEMPTS = 3, IN_FLIGHT_MAX_MS, PENDING_MAX = 4096, LOAD_RETRY_MIN_MS = 60000, LOAD_RETRY_MAX_MS, ANNOUNCED_MAX = 256, CALENDAR_FUTURE_MS, DECLINE = () => null, iso2 = (at) => new Date(at).toISOString(), FORECAST_DIGITS = 4, instance, safeRankerWarned = false;
23042
23274
  var init_allowance_service = __esm(() => {
23043
23275
  init_config();
23044
23276
  init_logger();
@@ -23057,6 +23289,7 @@ var init_allowance_service = __esm(() => {
23057
23289
  init_state();
23058
23290
  init_strategy();
23059
23291
  init_trajectory();
23292
+ init_usage();
23060
23293
  init_atomic_write();
23061
23294
  init_file_lock();
23062
23295
  init_ledger_reader();
@@ -23066,12 +23299,12 @@ var init_allowance_service = __esm(() => {
23066
23299
  init_registry();
23067
23300
  init_state_store();
23068
23301
  THREAD_IDLE_MS = 24 * 60 * 60 * 1000;
23069
- DAY_MS6 = 24 * HOUR_MS16;
23302
+ DAY_MS6 = 24 * HOUR_MS17;
23070
23303
  LOAD_HISTORY_MS = 42 * DAY_MS6;
23071
- LOAD_RAW_MS = 48 * HOUR_MS16;
23304
+ LOAD_RAW_MS = 48 * HOUR_MS17;
23072
23305
  SERVED_RECENTLY_MS = DAY_MS6;
23073
23306
  IN_FLIGHT_MAX_MS = 30 * 60000;
23074
- LOAD_RETRY_MAX_MS = HOUR_MS16;
23307
+ LOAD_RETRY_MAX_MS = HOUR_MS17;
23075
23308
  CALENDAR_FUTURE_MS = 9 * DAY_MS6;
23076
23309
  });
23077
23310
 
@@ -92625,22 +92858,22 @@ function dialogKindOf(reason) {
92625
92858
  function str3(v) {
92626
92859
  return typeof v === "string" && v !== "" ? v : null;
92627
92860
  }
92628
- function record4(v) {
92861
+ function record5(v) {
92629
92862
  return v !== null && typeof v === "object" && !Array.isArray(v) ? v : null;
92630
92863
  }
92631
92864
  function paneZero(listResult) {
92632
- const panes = record4(listResult)?.panes;
92865
+ const panes = record5(listResult)?.panes;
92633
92866
  if (!Array.isArray(panes))
92634
92867
  return null;
92635
92868
  for (const p of panes) {
92636
- const row = record4(p);
92869
+ const row = record5(p);
92637
92870
  if (row?.pane === 0)
92638
92871
  return row;
92639
92872
  }
92640
92873
  return null;
92641
92874
  }
92642
92875
  function parseGateInput(listResult, now) {
92643
- const input = record4(paneZero(listResult)?.input);
92876
+ const input = record5(paneZero(listResult)?.input);
92644
92877
  if (!input || typeof input.ready !== "boolean")
92645
92878
  return null;
92646
92879
  const reason = input.ready ? null : str3(input.reason);
@@ -92755,7 +92988,7 @@ function notAcceptedOutcome(r) {
92755
92988
  }
92756
92989
  function classifySendReply(r) {
92757
92990
  if (r.ok)
92758
- return okOutcome(record4(r.result) ?? {});
92991
+ return okOutcome(record5(r.result) ?? {});
92759
92992
  switch (r.code) {
92760
92993
  case "busy": {
92761
92994
  const reason = r.reason ?? "";
@@ -102137,7 +102370,7 @@ Report manually at https://github.com/anthropics/claudish/issues${autoSendHint}`
102137
102370
  });
102138
102371
  tools.push({
102139
102372
  name: "allowance_status",
102140
- description: 'Report the local Codex account pool\'s allowance: {contract_version, capabilities, allowance, reason?}. `allowance` is the claudish.allowance.v1 report of THIS machine\'s claudish sessions (accounts, remaining capacity, burn rate, projected gaps with remedies, trajectory, per-session shares), or null with a `reason` when there is no account pool. `sections` limits the report to those parts (accounts, combined, burn, alerts, trajectory, sessions) beside its header, and the answer then lists them in `sections`; a frequent poll should pass ["accounts","burn","alerts"]. Read-only; it sends nothing to any vendor.',
102373
+ description: 'Report the local Codex account pool\'s allowance: {contract_version, capabilities, allowance, reason?}. `allowance` is the claudish.allowance.v1 report of THIS machine\'s claudish sessions (accounts, remaining capacity, burn rate, projected gaps with remedies, trajectory, per-session shares, 14 days of hourly usage per account), or null with a `reason` when there is no account pool. `sections` limits the report to those parts (accounts, combined, burn, alerts, trajectory, sessions, usage) beside its header, and the answer then lists them in `sections`; a frequent poll should pass ["accounts","burn","alerts"]. Read-only; it sends nothing to any vendor.',
102141
102374
  inputSchema: {
102142
102375
  type: "object",
102143
102376
  properties: {
@@ -102157,7 +102390,7 @@ Report manually at https://github.com/anthropics/claudish/issues${autoSendHint}`
102157
102390
  enum: [...ALLOWANCE_REPORT_SECTIONS]
102158
102391
  },
102159
102392
  minItems: 1,
102160
- description: 'Report only these parts beside the header (default: all). Poll with ["accounts","burn","alerts"]; the trajectory and sessions are most of the bytes.'
102393
+ description: 'Report only these parts beside the header (default: all). Poll with ["accounts","burn","alerts"]; the trajectory, sessions and usage are most of the bytes.'
102161
102394
  }
102162
102395
  }
102163
102396
  },
@@ -104641,7 +104874,7 @@ function graphLines(r, paint) {
104641
104874
  if (points.length === 0)
104642
104875
  return [];
104643
104876
  const start = points[0]?.at ?? 0;
104644
- const span = Math.max(HOUR_MS17, (points.at(-1)?.at ?? start) - start + HOUR_MS17);
104877
+ const span = Math.max(HOUR_MS18, (points.at(-1)?.at ?? start) - start + HOUR_MS18);
104645
104878
  const col = (ms) => Math.min(GRAPH_COLS - 1, Math.max(0, Math.floor((ms - start) / span * GRAPH_COLS)));
104646
104879
  const scale = r.unit === "account-fraction" ? Math.max(1, r.accounts.length) : Math.max(...points.map((p) => Math.max(p.v, p.hi ?? 0)), 0);
104647
104880
  const cols = Array.from({ length: GRAPH_COLS }, () => ({
@@ -104748,7 +104981,7 @@ function renderForecast(r, paint = PLAIN) {
104748
104981
  ...sessionLines(r, paint)
104749
104982
  ];
104750
104983
  }
104751
- var PLAIN, HOUR_MS17 = 3600000, GRAPH_COLS = 60, GRAPH_ROWS = 10, SESSIONS_SHOWN = 10, SHORT_WINDOW_MAX_MIN = 360, DAYS, NO_USAGE_LINE = "No usage observed yet \u2014 the forecast starts after the first pooled response.";
104984
+ var PLAIN, HOUR_MS18 = 3600000, GRAPH_COLS = 60, GRAPH_ROWS = 10, SESSIONS_SHOWN = 10, SHORT_WINDOW_MAX_MIN = 360, DAYS, NO_USAGE_LINE = "No usage observed yet \u2014 the forecast starts after the first pooled response.";
104752
104985
  var init_account_forecast_render = __esm(() => {
104753
104986
  init_constants();
104754
104987
  PLAIN = {
@@ -104999,8 +105232,8 @@ function parseForecastHorizon(value) {
104999
105232
  const m = /^(\d+(?:\.\d+)?)([hd])$/.exec(value.trim());
105000
105233
  if (!m)
105001
105234
  return null;
105002
- const ms = Number(m[1]) * (m[2] === "d" ? 24 : 1) * HOUR_MS18;
105003
- return ms >= HOUR_MS18 && ms <= 168 * HOUR_MS18 ? ms : null;
105235
+ const ms = Number(m[1]) * (m[2] === "d" ? 24 : 1) * HOUR_MS19;
105236
+ return ms >= HOUR_MS19 && ms <= 168 * HOUR_MS19 ? ms : null;
105004
105237
  }
105005
105238
  function forecastProvider(value) {
105006
105239
  if (value === "codex" || value === "openai-codex")
@@ -105013,7 +105246,7 @@ function forecastProvider(value) {
105013
105246
  return `account forecast: unknown provider "${value}"; the only provider with an allowance model is codex.`;
105014
105247
  }
105015
105248
  async function forecastCommand(args) {
105016
- let horizonMs = 168 * HOUR_MS18;
105249
+ let horizonMs = 168 * HOUR_MS19;
105017
105250
  let json = false;
105018
105251
  let provider = "openai-codex";
105019
105252
  if (args.includes("--help") || args.includes("-h")) {
@@ -105104,7 +105337,7 @@ Removing the legacy login (default, legacy-codex-file) requires --delete-file.
105104
105337
  New accounts use the macOS Keychain, or protected plaintext files where there is none.
105105
105338
  Add only accounts you own; vendor terms may restrict switching between subscriptions.
105106
105339
  With Codex accounts configured, use account add/login instead of \`claudish login codex\`.
105107
- Claude account mutations, import and use are not available. No token input or export.`, MUTATION_VERBS, HOUR_MS18 = 3600000, FORECAST_HELP = `Usage:
105340
+ Claude account mutations, import and use are not available. No token input or export.`, MUTATION_VERBS, HOUR_MS19 = 3600000, FORECAST_HELP = `Usage:
105108
105341
  claudish account forecast [--json] [--horizon <h|d>] [--provider codex]
105109
105342
 
105110
105343
  The allowance trajectory, alerts and sessions of a claudish provider's account pool.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudish",
3
- "version": "14.8.0",
3
+ "version": "14.10.0",
4
4
  "description": "Run Claude Code with any model - OpenRouter, Ollama, LM Studio & local models",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -71,10 +71,10 @@
71
71
  "ai"
72
72
  ],
73
73
  "optionalDependencies": {
74
- "@claudish/magmux-darwin-arm64": "14.8.0",
75
- "@claudish/magmux-darwin-x64": "14.8.0",
76
- "@claudish/magmux-linux-arm64": "14.8.0",
77
- "@claudish/magmux-linux-x64": "14.8.0"
74
+ "@claudish/magmux-darwin-arm64": "14.10.0",
75
+ "@claudish/magmux-darwin-x64": "14.10.0",
76
+ "@claudish/magmux-linux-arm64": "14.10.0",
77
+ "@claudish/magmux-linux-x64": "14.10.0"
78
78
  },
79
79
  "author": "Jack Rudenko <i@madappgang.com>",
80
80
  "license": "MIT",