@askalf/dario 6.12.10 → 6.12.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +10 -2
- package/dist/doctor-core.js +11 -1
- package/dist/pool.d.ts +12 -5
- package/dist/pool.js +34 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -52,7 +52,7 @@ function readBudgetFlags(args) {
|
|
|
52
52
|
return budget;
|
|
53
53
|
}
|
|
54
54
|
import { loadAllAccounts as loadAllAccountsForIdentity, regenerateClientIdentity } from './accounts.js';
|
|
55
|
-
import { maskEmail, parsePoolHeadroomFloor, configuredPoolRouting, describePoolStrategy } from './pool.js';
|
|
55
|
+
import { maskEmail, parsePoolHeadroomFloor, headroomFloorProblem, headroomFloorFlagProblem, configuredPoolRouting, describePoolStrategy } from './pool.js';
|
|
56
56
|
import { realpathSync, readFileSync } from 'node:fs';
|
|
57
57
|
import { join } from 'node:path';
|
|
58
58
|
import { homedir } from 'node:os';
|
|
@@ -541,12 +541,20 @@ async function proxy() {
|
|
|
541
541
|
// used rather than ride it into the 429.
|
|
542
542
|
const poolHeadroomFloorFromFlag = args.find((a) => a.startsWith('--pool-headroom-floor='))?.split('=')[1];
|
|
543
543
|
if (poolHeadroomFloorFromFlag !== undefined && parsePoolHeadroomFloor(poolHeadroomFloorFromFlag) === null) {
|
|
544
|
-
console.error(`[dario] Invalid --pool-headroom-floor
|
|
544
|
+
console.error(`[dario] Invalid --pool-headroom-floor: ${headroomFloorFlagProblem(poolHeadroomFloorFromFlag)}`);
|
|
545
545
|
process.exit(1);
|
|
546
546
|
}
|
|
547
547
|
const poolHeadroomFloor = poolHeadroomFloorFromFlag
|
|
548
548
|
?? process.env['DARIO_POOL_HEADROOM_FLOOR']
|
|
549
549
|
?? fileCfg.pool?.headroomFloor;
|
|
550
|
+
// An invalid flag value aborts startup; an invalid env or config value warns and uses the
|
|
551
|
+
// default floor.
|
|
552
|
+
if (poolHeadroomFloorFromFlag === undefined) {
|
|
553
|
+
const floorSource = process.env['DARIO_POOL_HEADROOM_FLOOR'] !== undefined ? 'DARIO_POOL_HEADROOM_FLOOR' : 'pool.headroomFloor in the config file';
|
|
554
|
+
const floorProblem = headroomFloorProblem(poolHeadroomFloor);
|
|
555
|
+
if (floorProblem)
|
|
556
|
+
console.warn(`[dario] ${floorSource}: ${floorProblem} Using the default 2%.`);
|
|
557
|
+
}
|
|
550
558
|
// --pool-shared-state — share rate-limit readings and sticky bindings with
|
|
551
559
|
// the other instances through the refresh-lock service (docs/multi-instance.md).
|
|
552
560
|
const poolSharedState = args.includes('--pool-shared-state')
|
package/dist/doctor-core.js
CHANGED
|
@@ -1133,7 +1133,7 @@ export async function runChecks(opts = {}) {
|
|
|
1133
1133
|
// (v5.0): it confirms the sole account is eligible, not rejected.
|
|
1134
1134
|
if (aliases.length >= 1) {
|
|
1135
1135
|
try {
|
|
1136
|
-
const { AccountPool, configuredPoolRouting, describePoolStrategy } = await import('./pool.js');
|
|
1136
|
+
const { AccountPool, configuredPoolRouting, describePoolStrategy, headroomFloorProblem } = await import('./pool.js');
|
|
1137
1137
|
const { loadConfig } = await import('./config-file.js');
|
|
1138
1138
|
// The preview must use the strategy the proxy will run, not the
|
|
1139
1139
|
// default: `new AccountPool()` here always predicted a max-headroom
|
|
@@ -1159,6 +1159,16 @@ export async function runChecks(opts = {}) {
|
|
|
1159
1159
|
: `no eligible account — all rejected or near-expiry (${ps.exhausted}/${ps.accounts} exhausted)`)
|
|
1160
1160
|
+ ` · ${describePoolStrategy(routing.strategy, routing.headroomFloor)} (env/config; a running proxy's --pool-strategy flag shows in GET /status)`,
|
|
1161
1161
|
});
|
|
1162
|
+
// Same precedence as configuredPoolRouting: the env var shadows the config file.
|
|
1163
|
+
const floorCandidate = process.env['DARIO_POOL_HEADROOM_FLOOR'] ?? loadConfig().config.pool?.headroomFloor;
|
|
1164
|
+
const floorProblem = headroomFloorProblem(floorCandidate);
|
|
1165
|
+
if (floorProblem) {
|
|
1166
|
+
checks.push({
|
|
1167
|
+
status: 'warn',
|
|
1168
|
+
label: 'Pool headroom floor',
|
|
1169
|
+
detail: `${process.env['DARIO_POOL_HEADROOM_FLOOR'] !== undefined ? 'DARIO_POOL_HEADROOM_FLOOR' : 'pool.headroomFloor'}: ${floorProblem} The default 2% is in effect.`,
|
|
1170
|
+
});
|
|
1171
|
+
}
|
|
1162
1172
|
}
|
|
1163
1173
|
catch (err) {
|
|
1164
1174
|
checks.push({ status: 'warn', label: 'Pool routing', detail: `check failed: ${err.message}` });
|
package/dist/pool.d.ts
CHANGED
|
@@ -588,12 +588,19 @@ export declare const MAX_POOL_HEADROOM_FLOOR = 0.5;
|
|
|
588
588
|
*/
|
|
589
589
|
export declare function parsePoolHeadroomFloor(value: string | number | null | undefined): number | null;
|
|
590
590
|
/**
|
|
591
|
-
*
|
|
592
|
-
* file
|
|
593
|
-
*
|
|
594
|
-
*
|
|
595
|
-
*
|
|
591
|
+
* Why a configured floor cannot be used, or null when it can (or is unset). The env var and the
|
|
592
|
+
* config file fall back to the default on a bad value, so without this a typo runs silently on 2%.
|
|
593
|
+
* A value between the maximum and 100% most likely names the usage at which to leave a seat
|
|
594
|
+
* rather than the headroom left (dario#1333 set `95` for "leave at 95% used"), so the message
|
|
595
|
+
* names the complement, never below the minimum. Pure.
|
|
596
596
|
*/
|
|
597
|
+
export declare function headroomFloorProblem(value: string | number | null | undefined): string | null;
|
|
598
|
+
/**
|
|
599
|
+
* Why a `--pool-headroom-floor` value was rejected. Unlike the env var and the config file, an
|
|
600
|
+
* empty flag value is an error rather than "unset", so this never returns null. Call it only for
|
|
601
|
+
* a value `parsePoolHeadroomFloor` rejected.
|
|
602
|
+
*/
|
|
603
|
+
export declare function headroomFloorFlagProblem(value: string): string;
|
|
597
604
|
export declare function resolvePoolHeadroomFloor(explicit?: string | number | null, env?: NodeJS.ProcessEnv): number;
|
|
598
605
|
/**
|
|
599
606
|
* The 7-day reset `expiring-first` orders by, in epoch ms: the seat's own
|
package/dist/pool.js
CHANGED
|
@@ -813,6 +813,40 @@ export function parsePoolHeadroomFloor(value) {
|
|
|
813
813
|
* out-of-bounds values fall through to the next source and finally to the
|
|
814
814
|
* default, matching `resolvePoolStrategy`.
|
|
815
815
|
*/
|
|
816
|
+
const floorPct = (r) => `${Math.round(r * 1000) / 10}%`;
|
|
817
|
+
const unusableFloor = (raw) => `"${raw}" is not a usable headroom floor. Use a ratio or percent between ${floorPct(MIN_POOL_HEADROOM_FLOOR)} and ${floorPct(MAX_POOL_HEADROOM_FLOOR)} (e.g. 0.05 or 5%)`;
|
|
818
|
+
/**
|
|
819
|
+
* Why a configured floor cannot be used, or null when it can (or is unset). The env var and the
|
|
820
|
+
* config file fall back to the default on a bad value, so without this a typo runs silently on 2%.
|
|
821
|
+
* A value between the maximum and 100% most likely names the usage at which to leave a seat
|
|
822
|
+
* rather than the headroom left (dario#1333 set `95` for "leave at 95% used"), so the message
|
|
823
|
+
* names the complement, never below the minimum. Pure.
|
|
824
|
+
*/
|
|
825
|
+
export function headroomFloorProblem(value) {
|
|
826
|
+
if (value === undefined || value === null)
|
|
827
|
+
return null;
|
|
828
|
+
const raw = String(value).trim();
|
|
829
|
+
if (raw === '' || parsePoolHeadroomFloor(value) !== null)
|
|
830
|
+
return null;
|
|
831
|
+
const base = unusableFloor(raw);
|
|
832
|
+
let n = typeof value === 'number' ? value : Number(raw.endsWith('%') ? raw.slice(0, -1).trim() : raw);
|
|
833
|
+
if (typeof value === 'string' && raw.endsWith('%'))
|
|
834
|
+
n /= 100;
|
|
835
|
+
if (Number.isFinite(n) && n > 1)
|
|
836
|
+
n /= 100;
|
|
837
|
+
if (!Number.isFinite(n) || n <= MAX_POOL_HEADROOM_FLOOR || n >= 1)
|
|
838
|
+
return `${base}.`;
|
|
839
|
+
const left = Math.max(1 - n, MIN_POOL_HEADROOM_FLOOR);
|
|
840
|
+
return `${base}. The floor is the headroom left on a seat, not its usage: to leave a seat at ${floorPct(n)} used, set ${floorPct(left)}.`;
|
|
841
|
+
}
|
|
842
|
+
/**
|
|
843
|
+
* Why a `--pool-headroom-floor` value was rejected. Unlike the env var and the config file, an
|
|
844
|
+
* empty flag value is an error rather than "unset", so this never returns null. Call it only for
|
|
845
|
+
* a value `parsePoolHeadroomFloor` rejected.
|
|
846
|
+
*/
|
|
847
|
+
export function headroomFloorFlagProblem(value) {
|
|
848
|
+
return headroomFloorProblem(value) ?? `${unusableFloor(value.trim())}.`;
|
|
849
|
+
}
|
|
816
850
|
export function resolvePoolHeadroomFloor(explicit, env = process.env) {
|
|
817
851
|
for (const c of [explicit, env.DARIO_POOL_HEADROOM_FLOOR]) {
|
|
818
852
|
const n = parsePoolHeadroomFloor(c);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@askalf/dario",
|
|
3
|
-
"version": "6.12.
|
|
3
|
+
"version": "6.12.11",
|
|
4
4
|
"description": "Use your Claude and ChatGPT subscriptions in Cursor, Cline, Aider, Claude Code and the Agent SDK — at subscription pricing, not per-token API bills. One local Anthropic + OpenAI-compatible endpoint: either plan answers either wire shape, with automatic failover when one hits its limit.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|