dsh-xdpool 2.6.1 → 2.6.3

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/lib/index.d.ts CHANGED
@@ -858,7 +858,7 @@ export declare const WORKBUDDY_AUTH_FILE_ENV = "WORKBUDDY_AUTH_FILE";
858
858
  */
859
859
  interface WorkBuddySkippedFile {
860
860
  path: string;
861
- reason: 'encrypted' | 'unreadable' | 'malformed';
861
+ reason: 'encrypted' | 'expired' | 'unreadable' | 'malformed';
862
862
  }
863
863
  interface WorkBuddyCredential {
864
864
  accessToken: string;
@@ -1202,6 +1202,19 @@ export declare class WorkBuddyAccountPool {
1202
1202
  * instead of silently showing half a pool.
1203
1203
  */
1204
1204
  skippedFilesInOrder(): readonly WorkBuddySkippedFile[];
1205
+ /**
1206
+ * Delete expired snapshots that a newer credential for the same account supersedes.
1207
+ *
1208
+ * Returns the paths actually removed. See the call site for the full safety rule; the
1209
+ * short version is that it touches ONLY files classified `expired`, ONLY when the same
1210
+ * `uin` is already served by a different (loaded) file, and never a live file.
1211
+ *
1212
+ * `uin` rather than `uid`: it is the billing identity, so two sign-ins of one person
1213
+ * match even when the desktop app wrote them from different installs. A file whose
1214
+ * identity cannot be read is left alone — deleting a credential on a guess is worse than
1215
+ * keeping a dead one on the card.
1216
+ */
1217
+ private pruneExpiredSnapshots;
1205
1218
  /** Rescan the auth directories and merge newly discovered accounts. */
1206
1219
  scan(): Promise<WorkBuddyAccount[]>;
1207
1220
  /** All accounts, cooldown state included. */
@@ -1216,6 +1229,39 @@ export declare class WorkBuddyAccountPool {
1216
1229
  * model, e.g. CLI diagnostics).
1217
1230
  */
1218
1231
  private available;
1232
+ /**
1233
+ * The pool ordered into three bands, so a resting account is deferred instead of
1234
+ * discarded.
1235
+ *
1236
+ * `available()` answers a binary question, and a binary answer loses the
1237
+ * distinction that matters most when a pool is under pressure:
1238
+ *
1239
+ * - an account that still HAS credits but was rate-limited a moment ago is
1240
+ * healthy — it should be tried AFTER the others, not treated as gone;
1241
+ * - an account resting after a failure is the last resort, but it is still a
1242
+ * resort: when it is the only one, trying it beats failing the request.
1243
+ *
1244
+ * A pool that drops both from the list turns "every account is cooling for
1245
+ * twenty more seconds" into an error the user reads as "no account available",
1246
+ * which is a different and much more alarming statement.
1247
+ *
1248
+ * The bands:
1249
+ *
1250
+ * 1. `ready` — passes every gate `available()` checks.
1251
+ * 2. `limited` — region-eligible and not disabled/reserved, but cooling for
1252
+ * this model or account-wide. Ordered by when it comes back,
1253
+ * so the account that recovers first is spent first.
1254
+ * 3. `resting` — sign-in was rejected by the upstream. It never heals on a
1255
+ * timer, so it is only tried when 1 and 2 are both empty.
1256
+ *
1257
+ * `disabled` and `reserve` accounts appear in NO band: those are user choices,
1258
+ * and overriding them is not resilience, it is ignoring an instruction.
1259
+ *
1260
+ * Kept separate from `available()` rather than replacing it, so the binary
1261
+ * question still has a binary answer for callers that want one (diagnostics,
1262
+ * the status document) without either copy drifting from the other.
1263
+ */
1264
+ private rankedPool;
1219
1265
  /**
1220
1266
  * Why no account is available right now, for an accurate error.
1221
1267
  *
@@ -1324,6 +1370,13 @@ export declare class WorkBuddyAccountPool {
1324
1370
  * `conversationKey` is only consulted under `sticky`; other modes ignore it.
1325
1371
  */
1326
1372
  acquire(modelId?: string, region?: WorkBuddyRegion, conversationKey?: string, reserveExempt?: ReadonlySet<string>): Promise<WorkBuddyAccount | undefined>;
1373
+ /**
1374
+ * Whether an account belongs to a band that is currently in play.
1375
+ *
1376
+ * Only `ready` accounts are eligible for the probe shortcut: picking a resting
1377
+ * account ahead of a healthy one is the very thing the bands exist to prevent.
1378
+ */
1379
+ private isStageEligible;
1327
1380
  /** How the pool currently spreads requests. Shown on the card. */
1328
1381
  currentDistribution(): AccountDistribution;
1329
1382
  /**
@@ -2206,7 +2259,7 @@ interface PoolWebStatus {
2206
2259
  interface PoolWebSkippedFile {
2207
2260
  /** Basename only; the full path lives in the desktop app's auth directory. */
2208
2261
  file: string;
2209
- reason: 'encrypted' | 'unreadable' | 'malformed';
2262
+ reason: 'encrypted' | 'expired' | 'unreadable' | 'malformed';
2210
2263
  }
2211
2264
  /** How a region's model list was obtained. */
2212
2265
  type PoolWebCatalogSource = 'live' | 'fallback';
@@ -2934,6 +2987,28 @@ declare class UsageRecorder {
2934
2987
  size(): number;
2935
2988
  /** Forget every retained call. */
2936
2989
  reset(): void;
2990
+ /**
2991
+ * Refill today's samples from the pack's own ledger.
2992
+ *
2993
+ * WHY THIS EXISTS
2994
+ *
2995
+ * `samples` is process memory, so every restart emptied the usage panel and the pool
2996
+ * card — "网关尚未上报 token 数" after a restart was not the gateway declining to
2997
+ * answer, it was this recorder having forgotten. The pack, meanwhile, persists a 90-day
2998
+ * day-aggregated ledger on disk, so the same period was already recorded and simply not
2999
+ * read.
3000
+ *
3001
+ * Called ONCE at startup, before the first request. It REPLACES rather than appends:
3002
+ * whatever is in memory at that moment is either empty (a fresh process) or belongs to
3003
+ * the same ledger entries, and adding both would double every figure.
3004
+ *
3005
+ * The rows are synthesised at DAY granularity — one `UsageCall` per (channel, model) with
3006
+ * the day's totals — because that is the resolution the ledger keeps. Per-call timestamps
3007
+ * are not recoverable, so the panel's "recent calls" list stays empty after a restart
3008
+ * while its totals are right; inventing timestamps to fill the list would be worse than
3009
+ * an empty list.
3010
+ */
3011
+ backfill(calls: readonly UsageCall[]): void;
2937
3012
  /** Aggregate the retained window. */
2938
3013
  summary(): UsageSummary;
2939
3014
  /**
@@ -4272,6 +4347,15 @@ interface PoolStatusRouteOptions {
4272
4347
  * document. The catalog refresh is what makes a new chain pickable at once.
4273
4348
  */
4274
4349
  saveCombos?: (raw: unknown) => Promise<PoolWebCombosStatus>;
4350
+ /**
4351
+ * Estimated credit spend per channel and model, for the composer strip.
4352
+ *
4353
+ * Its own endpoint rather than a field of the status document: the pool card polls
4354
+ * status every 30 seconds, and the ledger roll-up would be recomputed on every one
4355
+ * of those polls for a number that changes once per request. The strip asks on its
4356
+ * own cadence.
4357
+ */
4358
+ creditsSpend?: (days: number | undefined) => Promise<unknown>;
4275
4359
  /**
4276
4360
  * The relay's current state, or undefined when this build has no relay.
4277
4361
  *