claudish 14.9.0 → 14.10.1

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 +260 -48
  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.9.0";
5494
+ var VERSION = "14.10.1";
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, switchSchema, blockedSchema, 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 });
@@ -16128,6 +16221,18 @@ var init_allowance_report_schema = __esm(() => {
16128
16221
  }).optional(),
16129
16222
  spark48: string2().regex(/^[\u2581\u2582\u2583\u2584\u2585\u2586\u2587\u2588\u2592\u2593\u250A ]*$/u)
16130
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
+ });
16131
16236
  sessionSchema = object({
16132
16237
  session: union([string2().max(8), literal("unattributed")]),
16133
16238
  parent: union([string2().max(8), _null3()]).optional(),
@@ -16170,9 +16275,19 @@ var init_allowance_report_schema = __esm(() => {
16170
16275
  blockedNow: boolean2(),
16171
16276
  status: _enum(["ok", "insufficient-evidence"]),
16172
16277
  trajectory: trajectorySchema,
16173
- sessions: array(sessionSchema)
16278
+ sessions: array(sessionSchema),
16279
+ usage: usageSchema.optional()
16174
16280
  });
16175
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 = [
16176
16291
  "accounts",
16177
16292
  "alerts",
16178
16293
  "burn",
@@ -16186,7 +16301,8 @@ var init_allowance_report_schema = __esm(() => {
16186
16301
  burn: true,
16187
16302
  combined: true,
16188
16303
  sessions: true,
16189
- trajectory: true
16304
+ trajectory: true,
16305
+ usage: true
16190
16306
  });
16191
16307
  allowanceStatusAnswerSchema = object({
16192
16308
  contract_version: literal(1),
@@ -16197,7 +16313,7 @@ var init_allowance_report_schema = __esm(() => {
16197
16313
  }).superRefine((answer, ctx) => {
16198
16314
  if (answer.allowance === null)
16199
16315
  return;
16200
- const wanted = answer.sections ?? ALLOWANCE_REPORT_SECTIONS;
16316
+ const wanted = answer.sections ?? ALLOWANCE_REPORT_SECTIONS_V1_BASE;
16201
16317
  for (const section of wanted) {
16202
16318
  if (answer.allowance[section] === undefined) {
16203
16319
  ctx.addIssue({
@@ -16658,7 +16774,7 @@ function cuOf(tokens, cfg) {
16658
16774
  const uncached = Math.max(0, tokens.input - tokens.cacheRead - tokens.cacheWrite);
16659
16775
  return uncached + w.cacheRead * tokens.cacheRead + w.cacheWrite * tokens.cacheWrite + w.output * tokens.output;
16660
16776
  }
16661
- 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;
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;
16662
16778
  var init_constants = __esm(() => {
16663
16779
  PROVIDER_COST_PRIORS = {
16664
16780
  "openai-codex": { cacheRead: 0.1, cacheWrite: 1, output: 4 },
@@ -17102,7 +17218,8 @@ function initialState() {
17102
17218
  sessions: {},
17103
17219
  seen: [],
17104
17220
  censorOpenAt: null,
17105
- lastAt: null
17221
+ lastAt: null,
17222
+ recordedFrom: null
17106
17223
  };
17107
17224
  }
17108
17225
  function observeAll(s, es, cfg) {
@@ -17146,6 +17263,7 @@ function fold(s, e, cfg, seen) {
17146
17263
  }
17147
17264
  switch (e.kind) {
17148
17265
  case "response": {
17266
+ record3(s, hourOf(e.at));
17149
17267
  const account = ensureAccount(s, e.account);
17150
17268
  const cu = cuOf(e.tokens, cfg);
17151
17269
  if (cu > 0) {
@@ -17166,6 +17284,7 @@ function fold(s, e, cfg, seen) {
17166
17284
  touch(s, e.at);
17167
17285
  return;
17168
17286
  case "no-eligible":
17287
+ record3(s, hourOf(e.at));
17169
17288
  if (e.until === undefined) {
17170
17289
  if (s.censorOpenAt === null)
17171
17290
  s.censorOpenAt = e.at;
@@ -17195,6 +17314,7 @@ function fold(s, e, cfg, seen) {
17195
17314
  return;
17196
17315
  }
17197
17316
  case "rollup": {
17317
+ record3(s, e.hour);
17198
17318
  const account = ensureAccount(s, e.account);
17199
17319
  const cu = cuOf(e.tokens, cfg);
17200
17320
  const mid = e.hour + HOUR_MS4 / 2;
@@ -17214,6 +17334,11 @@ function fold(s, e, cfg, seen) {
17214
17334
  }
17215
17335
  }
17216
17336
  }
17337
+ function record3(s, hour) {
17338
+ const from = s.recordedFrom ?? null;
17339
+ if (from === null || hour < from)
17340
+ s.recordedFrom = hour;
17341
+ }
17217
17342
  function touch(s, at) {
17218
17343
  if (s.lastAt === null || at > s.lastAt)
17219
17344
  s.lastAt = at;
@@ -20196,6 +20321,55 @@ var init_trajectory = __esm(() => {
20196
20321
  LEVELS = ["\u2581", "\u2582", "\u2583", "\u2584", "\u2585", "\u2586", "\u2587", "\u2588"];
20197
20322
  });
20198
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
+
20199
20373
  // src/auth/accounts/paths.ts
20200
20374
  import { homedir as homedir10 } from "os";
20201
20375
  import { join as join10 } from "path";
@@ -20968,8 +21142,8 @@ function censoredMinutesByHour(rows, dayBegin, dayEnd, openAtStart = new Set) {
20968
21142
  hours = new Map;
20969
21143
  byProvider.set(provider, hours);
20970
21144
  }
20971
- for (let h = Math.floor(from / HOUR_MS15) * HOUR_MS15;h < to; h += HOUR_MS15) {
20972
- 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);
20973
21147
  if (overlap > 0)
20974
21148
  hours.set(h, Math.min(60, (hours.get(h) ?? 0) + overlap / 60000));
20975
21149
  }
@@ -21011,7 +21185,7 @@ function* rollupDaySteps(day, rows, openAtStart) {
21011
21185
  for (const row of responses) {
21012
21186
  if (++n % COMPACT_SLICE_ROWS === 0)
21013
21187
  yield;
21014
- const hour = Math.floor(row.at / HOUR_MS15) * HOUR_MS15;
21188
+ const hour = Math.floor(row.at / HOUR_MS16) * HOUR_MS16;
21015
21189
  const key = [hour, row.provider, row.accountId, row.session ?? "-", row.model].join("\x00");
21016
21190
  const group = groups.get(key);
21017
21191
  if (group)
@@ -21077,7 +21251,7 @@ function* rollupDaySteps(day, rows, openAtStart) {
21077
21251
  `)}
21078
21252
  ` : "", openAtEnd };
21079
21253
  }
21080
- 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;
21081
21255
  var init_ledger_writer = __esm(() => {
21082
21256
  init_logger();
21083
21257
  init_atomic_write();
@@ -22109,8 +22283,8 @@ function vendorLabel(provider) {
22109
22283
  }
22110
22284
  function localCalendar(now) {
22111
22285
  const offsets = [];
22112
- const from = Math.floor((now - LOAD_HISTORY_MS) / HOUR_MS16) * HOUR_MS16;
22113
- 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) {
22114
22288
  const offsetMinutes = -new Date(t).getTimezoneOffset();
22115
22289
  if (offsets.length === 0 || offsets[offsets.length - 1]?.offsetMinutes !== offsetMinutes) {
22116
22290
  offsets.push({ from: offsets.length === 0 ? 0 : t, offsetMinutes });
@@ -22142,7 +22316,7 @@ function allowanceNotice(provider, transition, alert, accounts, formatTime = for
22142
22316
  return null;
22143
22317
  const { start, end } = gapSpan(alert);
22144
22318
  const who = accounts <= 1 ? "the account is" : accounts === 2 ? "both accounts are" : `all ${accounts} accounts are`;
22145
- const hours = Math.round((end - start) / HOUR_MS16);
22319
+ const hours = Math.round((end - start) / HOUR_MS17);
22146
22320
  const remedy = remedyText(alert.remedy, start, formatTime);
22147
22321
  const advice = remedy ? ` ${remedy.charAt(0).toUpperCase()}${remedy.slice(1)}.` : "";
22148
22322
  return `${vendor} allowance: at the current rate ${who} spent ${formatTime(start)} and blocked until ${formatTime(end)} (${hours} h).${advice} \`claudish account forecast\``;
@@ -22496,9 +22670,14 @@ class AllowanceService {
22496
22670
  m.loading = true;
22497
22671
  try {
22498
22672
  const now = this.clock();
22499
- const tail = createLedgerTail({ startAtEnd: true, now, env: this.env });
22673
+ const handoff = Math.floor((now - LOAD_RAW_MS) / HOUR_MS17) * HOUR_MS17;
22674
+ const tail = createLedgerTail({
22675
+ startAtEnd: true,
22676
+ fromDay: utcDay(handoff),
22677
+ now,
22678
+ env: this.env
22679
+ });
22500
22680
  await tail.tail();
22501
- const handoff = Math.floor((now - LOAD_RAW_MS) / HOUR_MS16) * HOUR_MS16;
22502
22681
  const [older, recent] = await Promise.all([
22503
22682
  readLedger({ sinceMs: now - LOAD_HISTORY_MS, untilMs: handoff, env: this.env }),
22504
22683
  readLedger({ sinceMs: handoff, source: "raw", env: this.env })
@@ -22580,7 +22759,7 @@ class AllowanceService {
22580
22759
  if (!m.state)
22581
22760
  return;
22582
22761
  const now = this.clock();
22583
- const horizon = m.cfg.SIM_MAX_STEPS * HOUR_MS16;
22762
+ const horizon = m.cfg.SIM_MAX_STEPS * HOUR_MS17;
22584
22763
  if (m.fc && m.fc.key === forecastKey(m.state, now, horizon, m.cal, m.cfg))
22585
22764
  return;
22586
22765
  m.fc = await runSliced(forecastSliced(m.state, now, horizon, m.cal, m.cfg));
@@ -22809,6 +22988,9 @@ async function runSliced(gen) {
22809
22988
  await new Promise((resolve) => setImmediate(resolve));
22810
22989
  }
22811
22990
  }
22991
+ function toSignificant(x, digits) {
22992
+ return x === 0 ? 0 : Number(x.toPrecision(digits));
22993
+ }
22812
22994
  function poolRemaining(views) {
22813
22995
  const read = views.filter(isRead);
22814
22996
  if (read.length === 0)
@@ -22836,7 +23018,7 @@ function likelihoodView(l) {
22836
23018
  let last = p.length - 1;
22837
23019
  while (last > first && p[last] === 0)
22838
23020
  last--;
22839
- return { start: iso2(l.start + first * HOUR_MS16), stepHours: 1, p: p.slice(first, last + 1) };
23021
+ return { start: iso2(l.start + first * HOUR_MS17), stepHours: 1, p: p.slice(first, last + 1) };
22840
23022
  }
22841
23023
  function switchView(sw) {
22842
23024
  return {
@@ -22857,9 +23039,37 @@ function sustainableOf(top, pace, burnLong) {
22857
23039
  return top.remedy.kind === "cut" ? top.remedy.cutToFraction * long : 0;
22858
23040
  return pace ? paceInCuPerHour(pace, long) : null;
22859
23041
  }
23042
+ function usageView(s, now, views) {
23043
+ const grid = usageByHour(s, now, USAGE_HOURS);
23044
+ const cell = (cu) => cu > 0 ? Math.max(1, Math.round(cu)) : 0;
23045
+ const byId = new Map(grid.accounts.map((a) => [a.account, a]));
23046
+ const listed = new Set(views.map((v) => v.account));
23047
+ 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));
23048
+ const censored = [];
23049
+ grid.censoredMinutes.forEach((minutes, i) => {
23050
+ const m = Math.min(60, Math.round(minutes));
23051
+ if (m > 0)
23052
+ censored.push([i, m]);
23053
+ });
23054
+ return {
23055
+ start: iso2(grid.start),
23056
+ stepHours: 1,
23057
+ hours: USAGE_HOURS,
23058
+ unit: "cu",
23059
+ coveredFrom: grid.coveredFrom === null ? null : iso2(grid.coveredFrom),
23060
+ accounts: [
23061
+ ...views.map((v) => ({
23062
+ accountId: v.account,
23063
+ cu: (byId.get(v.account)?.cu ?? new Array(grid.hours).fill(0)).map(cell)
23064
+ })),
23065
+ ...others.map((a) => ({ accountId: a.account, cu: a.cu.map(cell) }))
23066
+ ],
23067
+ censored
23068
+ };
23069
+ }
22860
23070
  function buildReport(input) {
22861
23071
  const { s, now, cfg, cal, fc } = input;
22862
- const horizonMs = Math.min(168 * HOUR_MS16, Math.max(HOUR_MS16, input.horizonMs));
23072
+ const horizonMs = Math.min(168 * HOUR_MS17, Math.max(HOUR_MS17, input.horizonMs));
22863
23073
  const evidence = evidenceOf(s, now);
22864
23074
  const none = evidence === "none";
22865
23075
  const views = accountViews(s, now, cfg);
@@ -22883,7 +23093,7 @@ function buildReport(input) {
22883
23093
  evidence,
22884
23094
  unit,
22885
23095
  assumption: unit === "account-fraction" ? "equal-capacity" : null,
22886
- horizonHours: Math.round(horizonMs / HOUR_MS16),
23096
+ horizonHours: Math.round(horizonMs / HOUR_MS17),
22887
23097
  accounts: views.map((v) => {
22888
23098
  const g = v.governing === null ? undefined : v.beta[v.governing];
22889
23099
  const k = v.binding === null || v.binding === v.governing ? undefined : v.kappa[v.binding];
@@ -22940,7 +23150,7 @@ function buildReport(input) {
22940
23150
  gapStartEpoch: start,
22941
23151
  gapStart: a.gap.start ? q(a.gap.start, iso2) : null,
22942
23152
  gapEnd: a.gap.end ? q(a.gap.end, iso2) : null,
22943
- gapHours: a.gap.lengthMs ? q(a.gap.lengthMs, (ms) => ms / HOUR_MS16) : null,
23153
+ gapHours: a.gap.lengthMs ? q(a.gap.lengthMs, (ms) => ms / HOUR_MS17) : null,
22944
23154
  pGap: Math.min(1, Math.max(0, a.pGap)),
22945
23155
  binding: a.gap.atLongRate.binding.map((b) => ({
22946
23156
  account: label(b.account),
@@ -22950,7 +23160,7 @@ function buildReport(input) {
22950
23160
  kind: r.kind,
22951
23161
  cutToPercent: r.kind === "cut" ? Math.round(r.cutToFraction * 100) : null,
22952
23162
  until: r.kind === "not-addressable" ? null : iso2(r.until),
22953
- pauseHours: r.kind === "not-addressable" || r.pauseMs === null ? null : r.pauseMs / HOUR_MS16,
23163
+ pauseHours: r.kind === "not-addressable" || r.pauseMs === null ? null : r.pauseMs / HOUR_MS17,
22954
23164
  reason: r.kind === "not-addressable" ? r.reason : null,
22955
23165
  text: remedyText(r, start, fmt)
22956
23166
  }
@@ -22966,9 +23176,9 @@ function buildReport(input) {
22966
23176
  })),
22967
23177
  forecast: traj.forecast.map((f) => ({
22968
23178
  at: iso2(f.at),
22969
- p10: f.q.p10,
22970
- p50: f.q.p50,
22971
- p90: f.q.p90,
23179
+ p10: toSignificant(f.q.p10, FORECAST_DIGITS),
23180
+ p50: toSignificant(f.q.p50, FORECAST_DIGITS),
23181
+ p90: toSignificant(f.q.p90, FORECAST_DIGITS),
22972
23182
  pBlocked: f.pBlocked
22973
23183
  })),
22974
23184
  resets: traj.resets.map((r) => ({
@@ -22980,7 +23190,7 @@ function buildReport(input) {
22980
23190
  blocked: traj.blocked.map(blockedView),
22981
23191
  historyByAccount: none ? [] : views.filter((v) => traj.historyByAccount[v.account] !== undefined).map((v) => ({
22982
23192
  accountId: v.account,
22983
- 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 }))
23193
+ 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 }))
22984
23194
  })),
22985
23195
  switches: traj.switches.map(switchView),
22986
23196
  slower: {
@@ -22990,8 +23200,8 @@ function buildReport(input) {
22990
23200
  },
22991
23201
  spark48: sparkline({
22992
23202
  ...traj,
22993
- history: traj.history.filter((h) => h.at >= now - 24 * HOUR_MS16),
22994
- forecast: traj.forecast.filter((f) => f.at <= now + 24 * HOUR_MS16)
23203
+ history: traj.history.filter((h) => h.at >= now - 24 * HOUR_MS17),
23204
+ forecast: traj.forecast.filter((f) => f.at <= now + 24 * HOUR_MS17)
22995
23205
  }, 48)
22996
23206
  },
22997
23207
  sessions: none ? [] : contributions(s, { now, window: "binding" }, cfg).map((c) => ({
@@ -23012,7 +23222,8 @@ function buildReport(input) {
23012
23222
  exactness: c.exactness,
23013
23223
  firstAt: iso2(c.firstAt),
23014
23224
  lastAt: iso2(c.lastAt)
23015
- }))
23225
+ })),
23226
+ usage: usageView(s, now, views)
23016
23227
  };
23017
23228
  return allowanceReportSchema.parse(report);
23018
23229
  }
@@ -23064,7 +23275,7 @@ function getAllowanceService() {
23064
23275
  }
23065
23276
  return instance;
23066
23277
  }
23067
- 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;
23278
+ 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;
23068
23279
  var init_allowance_service = __esm(() => {
23069
23280
  init_config();
23070
23281
  init_logger();
@@ -23083,6 +23294,7 @@ var init_allowance_service = __esm(() => {
23083
23294
  init_state();
23084
23295
  init_strategy();
23085
23296
  init_trajectory();
23297
+ init_usage();
23086
23298
  init_atomic_write();
23087
23299
  init_file_lock();
23088
23300
  init_ledger_reader();
@@ -23092,12 +23304,12 @@ var init_allowance_service = __esm(() => {
23092
23304
  init_registry();
23093
23305
  init_state_store();
23094
23306
  THREAD_IDLE_MS = 24 * 60 * 60 * 1000;
23095
- DAY_MS6 = 24 * HOUR_MS16;
23307
+ DAY_MS6 = 24 * HOUR_MS17;
23096
23308
  LOAD_HISTORY_MS = 42 * DAY_MS6;
23097
- LOAD_RAW_MS = 48 * HOUR_MS16;
23309
+ LOAD_RAW_MS = 48 * HOUR_MS17;
23098
23310
  SERVED_RECENTLY_MS = DAY_MS6;
23099
23311
  IN_FLIGHT_MAX_MS = 30 * 60000;
23100
- LOAD_RETRY_MAX_MS = HOUR_MS16;
23312
+ LOAD_RETRY_MAX_MS = HOUR_MS17;
23101
23313
  CALENDAR_FUTURE_MS = 9 * DAY_MS6;
23102
23314
  });
23103
23315
 
@@ -92651,22 +92863,22 @@ function dialogKindOf(reason) {
92651
92863
  function str3(v) {
92652
92864
  return typeof v === "string" && v !== "" ? v : null;
92653
92865
  }
92654
- function record4(v) {
92866
+ function record5(v) {
92655
92867
  return v !== null && typeof v === "object" && !Array.isArray(v) ? v : null;
92656
92868
  }
92657
92869
  function paneZero(listResult) {
92658
- const panes = record4(listResult)?.panes;
92870
+ const panes = record5(listResult)?.panes;
92659
92871
  if (!Array.isArray(panes))
92660
92872
  return null;
92661
92873
  for (const p of panes) {
92662
- const row = record4(p);
92874
+ const row = record5(p);
92663
92875
  if (row?.pane === 0)
92664
92876
  return row;
92665
92877
  }
92666
92878
  return null;
92667
92879
  }
92668
92880
  function parseGateInput(listResult, now) {
92669
- const input = record4(paneZero(listResult)?.input);
92881
+ const input = record5(paneZero(listResult)?.input);
92670
92882
  if (!input || typeof input.ready !== "boolean")
92671
92883
  return null;
92672
92884
  const reason = input.ready ? null : str3(input.reason);
@@ -92781,7 +92993,7 @@ function notAcceptedOutcome(r) {
92781
92993
  }
92782
92994
  function classifySendReply(r) {
92783
92995
  if (r.ok)
92784
- return okOutcome(record4(r.result) ?? {});
92996
+ return okOutcome(record5(r.result) ?? {});
92785
92997
  switch (r.code) {
92786
92998
  case "busy": {
92787
92999
  const reason = r.reason ?? "";
@@ -102163,7 +102375,7 @@ Report manually at https://github.com/anthropics/claudish/issues${autoSendHint}`
102163
102375
  });
102164
102376
  tools.push({
102165
102377
  name: "allowance_status",
102166
- 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.',
102378
+ 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.',
102167
102379
  inputSchema: {
102168
102380
  type: "object",
102169
102381
  properties: {
@@ -102183,7 +102395,7 @@ Report manually at https://github.com/anthropics/claudish/issues${autoSendHint}`
102183
102395
  enum: [...ALLOWANCE_REPORT_SECTIONS]
102184
102396
  },
102185
102397
  minItems: 1,
102186
- description: 'Report only these parts beside the header (default: all). Poll with ["accounts","burn","alerts"]; the trajectory and sessions are most of the bytes.'
102398
+ 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.'
102187
102399
  }
102188
102400
  }
102189
102401
  },
@@ -104667,7 +104879,7 @@ function graphLines(r, paint) {
104667
104879
  if (points.length === 0)
104668
104880
  return [];
104669
104881
  const start = points[0]?.at ?? 0;
104670
- const span = Math.max(HOUR_MS17, (points.at(-1)?.at ?? start) - start + HOUR_MS17);
104882
+ const span = Math.max(HOUR_MS18, (points.at(-1)?.at ?? start) - start + HOUR_MS18);
104671
104883
  const col = (ms) => Math.min(GRAPH_COLS - 1, Math.max(0, Math.floor((ms - start) / span * GRAPH_COLS)));
104672
104884
  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);
104673
104885
  const cols = Array.from({ length: GRAPH_COLS }, () => ({
@@ -104774,7 +104986,7 @@ function renderForecast(r, paint = PLAIN) {
104774
104986
  ...sessionLines(r, paint)
104775
104987
  ];
104776
104988
  }
104777
- 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.";
104989
+ 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.";
104778
104990
  var init_account_forecast_render = __esm(() => {
104779
104991
  init_constants();
104780
104992
  PLAIN = {
@@ -105025,8 +105237,8 @@ function parseForecastHorizon(value) {
105025
105237
  const m = /^(\d+(?:\.\d+)?)([hd])$/.exec(value.trim());
105026
105238
  if (!m)
105027
105239
  return null;
105028
- const ms = Number(m[1]) * (m[2] === "d" ? 24 : 1) * HOUR_MS18;
105029
- return ms >= HOUR_MS18 && ms <= 168 * HOUR_MS18 ? ms : null;
105240
+ const ms = Number(m[1]) * (m[2] === "d" ? 24 : 1) * HOUR_MS19;
105241
+ return ms >= HOUR_MS19 && ms <= 168 * HOUR_MS19 ? ms : null;
105030
105242
  }
105031
105243
  function forecastProvider(value) {
105032
105244
  if (value === "codex" || value === "openai-codex")
@@ -105039,7 +105251,7 @@ function forecastProvider(value) {
105039
105251
  return `account forecast: unknown provider "${value}"; the only provider with an allowance model is codex.`;
105040
105252
  }
105041
105253
  async function forecastCommand(args) {
105042
- let horizonMs = 168 * HOUR_MS18;
105254
+ let horizonMs = 168 * HOUR_MS19;
105043
105255
  let json = false;
105044
105256
  let provider = "openai-codex";
105045
105257
  if (args.includes("--help") || args.includes("-h")) {
@@ -105130,7 +105342,7 @@ Removing the legacy login (default, legacy-codex-file) requires --delete-file.
105130
105342
  New accounts use the macOS Keychain, or protected plaintext files where there is none.
105131
105343
  Add only accounts you own; vendor terms may restrict switching between subscriptions.
105132
105344
  With Codex accounts configured, use account add/login instead of \`claudish login codex\`.
105133
- Claude account mutations, import and use are not available. No token input or export.`, MUTATION_VERBS, HOUR_MS18 = 3600000, FORECAST_HELP = `Usage:
105345
+ Claude account mutations, import and use are not available. No token input or export.`, MUTATION_VERBS, HOUR_MS19 = 3600000, FORECAST_HELP = `Usage:
105134
105346
  claudish account forecast [--json] [--horizon <h|d>] [--provider codex]
105135
105347
 
105136
105348
  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.9.0",
3
+ "version": "14.10.1",
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.9.0",
75
- "@claudish/magmux-darwin-x64": "14.9.0",
76
- "@claudish/magmux-linux-arm64": "14.9.0",
77
- "@claudish/magmux-linux-x64": "14.9.0"
74
+ "@claudish/magmux-darwin-arm64": "14.10.1",
75
+ "@claudish/magmux-darwin-x64": "14.10.1",
76
+ "@claudish/magmux-linux-arm64": "14.10.1",
77
+ "@claudish/magmux-linux-x64": "14.10.1"
78
78
  },
79
79
  "author": "Jack Rudenko <i@madappgang.com>",
80
80
  "license": "MIT",