@askalf/dario 6.0.35 → 6.0.37
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.d.ts +36 -0
- package/dist/cli.js +48 -34
- package/dist/version.js +24 -10
- package/package.json +1 -1
package/dist/cli.d.ts
CHANGED
|
@@ -105,6 +105,42 @@ export declare function parseBooleanEnv(value: string | undefined): boolean | un
|
|
|
105
105
|
* Set(['thinking','env']) — value "thinking,env" → preserve listed
|
|
106
106
|
*/
|
|
107
107
|
export declare function resolvePreserveOrchestrationTags(args: string[], env: string | undefined): Set<string> | undefined;
|
|
108
|
+
/**
|
|
109
|
+
* The seat shape a running proxy returns from `/accounts`.
|
|
110
|
+
*
|
|
111
|
+
* Everything past `alias` is optional on purpose. A freshly installed CLI
|
|
112
|
+
* routinely queries a proxy still running the PREVIOUS release, whose seats
|
|
113
|
+
* predate whichever field the newest feature added — `sharesWindowWith`,
|
|
114
|
+
* `organizationId` and `grantedAt` all arrived that way (dario#1248 review).
|
|
115
|
+
* The payload is accepted on `mode` + `accounts` alone, so the renderer, not
|
|
116
|
+
* the fetch, is where a missing field would throw. Defaulting each one here
|
|
117
|
+
* keeps `accounts list --live` degrading to a thinner line instead of dying
|
|
118
|
+
* with a TypeError and skipping the on-disk fallback it advertises.
|
|
119
|
+
*/
|
|
120
|
+
export interface LiveSeat {
|
|
121
|
+
alias?: string;
|
|
122
|
+
status?: string;
|
|
123
|
+
action?: 'none' | 'wait' | 'regrant';
|
|
124
|
+
util5h?: number;
|
|
125
|
+
util7d?: number;
|
|
126
|
+
utilAgeMs?: number | null;
|
|
127
|
+
resetInMs?: number | null;
|
|
128
|
+
requestCount?: number;
|
|
129
|
+
rejectedCount?: number;
|
|
130
|
+
organizationId?: string | null;
|
|
131
|
+
sharesWindowWith?: string[];
|
|
132
|
+
grantedAt?: number | null;
|
|
133
|
+
}
|
|
134
|
+
export interface LivePayload {
|
|
135
|
+
mode?: string;
|
|
136
|
+
accounts?: LiveSeat[];
|
|
137
|
+
distinctWindows?: number;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Render the live pool listing. Pure — returns the lines rather than printing
|
|
141
|
+
* them, so a legacy payload can be driven straight through it in a test.
|
|
142
|
+
*/
|
|
143
|
+
export declare function formatLiveAccountsListing(payload: LivePayload, port: number, now: number): string[];
|
|
108
144
|
/**
|
|
109
145
|
* Decide whether this module is being invoked as the CLI entry point or
|
|
110
146
|
* imported as a library. Pure, exported for tests; the file-bottom uses
|
package/dist/cli.js
CHANGED
|
@@ -894,6 +894,52 @@ function parsePositiveIntFlag(prefix) {
|
|
|
894
894
|
}
|
|
895
895
|
return n;
|
|
896
896
|
}
|
|
897
|
+
/**
|
|
898
|
+
* Render the live pool listing. Pure — returns the lines rather than printing
|
|
899
|
+
* them, so a legacy payload can be driven straight through it in a test.
|
|
900
|
+
*/
|
|
901
|
+
export function formatLiveAccountsListing(payload, port, now) {
|
|
902
|
+
const seats = Array.isArray(payload.accounts) ? payload.accounts : [];
|
|
903
|
+
const num = (v) => (typeof v === 'number' && Number.isFinite(v) ? v : 0);
|
|
904
|
+
const pct = (n) => `${Math.round(num(n) * 100)}%`;
|
|
905
|
+
const mins = (ms) => {
|
|
906
|
+
const m = Math.max(1, Math.round(ms / 60_000));
|
|
907
|
+
return m >= 60 ? `${Math.floor(m / 60)}h ${m % 60}m` : `${m}m`;
|
|
908
|
+
};
|
|
909
|
+
const age = (ms) => typeof ms !== 'number' || !Number.isFinite(ms)
|
|
910
|
+
? 'never measured'
|
|
911
|
+
: ms < 60_000 ? `read ${Math.round(ms / 1000)}s ago` : `read ${mins(ms)} ago`;
|
|
912
|
+
const lines = [];
|
|
913
|
+
lines.push('');
|
|
914
|
+
lines.push(` dario — Accounts (live, from http://127.0.0.1:${port})`);
|
|
915
|
+
lines.push(' ────────────────');
|
|
916
|
+
lines.push('');
|
|
917
|
+
const windows = typeof payload.distinctWindows === 'number' ? payload.distinctWindows : seats.length;
|
|
918
|
+
lines.push(` Pool of ${seats.length} (${seats.length === 1 ? '1 seat' : seats.length + ' seats'} on ${windows} distinct window${windows === 1 ? '' : 's'})`);
|
|
919
|
+
lines.push('');
|
|
920
|
+
for (const s of seats) {
|
|
921
|
+
const alias = typeof s.alias === 'string' ? s.alias : '(unnamed)';
|
|
922
|
+
const rawStatus = typeof s.status === 'string' ? s.status : 'unknown';
|
|
923
|
+
const status = rawStatus === 'rejected' && typeof s.resetInMs === 'number' ? `rejected, back in ${mins(s.resetInMs)}` : rawStatus;
|
|
924
|
+
lines.push(` ${alias.padEnd(20)} ${status.padEnd(26)} 5h ${pct(s.util5h).padEnd(6)} 7d ${pct(s.util7d).padEnd(6)} ${age(s.utilAgeMs)}`);
|
|
925
|
+
// The one-word next step (dario#1244): a parked seat wants nothing from
|
|
926
|
+
// the operator; an auth-failure streak wants a re-grant.
|
|
927
|
+
const next = s.action === 'regrant' ? 'next: re-grant this seat (dario accounts remove + add)'
|
|
928
|
+
: s.action === 'wait' ? 'next: nothing, it comes back on its own'
|
|
929
|
+
: null;
|
|
930
|
+
const facts = [
|
|
931
|
+
`served ${num(s.requestCount)}`,
|
|
932
|
+
`429s ${num(s.rejectedCount)}`,
|
|
933
|
+
...(next ? [next] : []),
|
|
934
|
+
typeof s.organizationId === 'string' && s.organizationId ? `org ${s.organizationId.slice(0, 8)}…` : 'org not yet observed',
|
|
935
|
+
...(Array.isArray(s.sharesWindowWith) && s.sharesWindowWith.length > 0 ? [`shares its window with ${s.sharesWindowWith.join(', ')}`] : []),
|
|
936
|
+
];
|
|
937
|
+
lines.push(` ${''.padEnd(20)} ${facts.join(' · ')}`);
|
|
938
|
+
lines.push(` ${''.padEnd(20)} ${describeGrantAge(grantAge(typeof s.grantedAt === 'number' ? s.grantedAt : undefined, now))}`);
|
|
939
|
+
}
|
|
940
|
+
lines.push('');
|
|
941
|
+
return lines;
|
|
942
|
+
}
|
|
897
943
|
/**
|
|
898
944
|
* `dario accounts list --live` — the running proxy's view of the pool
|
|
899
945
|
* (dario#1244): status with its countdown, the reading and its age, 429s
|
|
@@ -924,40 +970,8 @@ async function accountsListLive() {
|
|
|
924
970
|
}
|
|
925
971
|
if (!payload || payload.mode !== 'pool' || !Array.isArray(payload.accounts))
|
|
926
972
|
return false;
|
|
927
|
-
const
|
|
928
|
-
|
|
929
|
-
const pct = (n) => `${Math.round(n * 100)}%`;
|
|
930
|
-
const mins = (ms) => {
|
|
931
|
-
const m = Math.max(1, Math.round(ms / 60_000));
|
|
932
|
-
return m >= 60 ? `${Math.floor(m / 60)}h ${m % 60}m` : `${m}m`;
|
|
933
|
-
};
|
|
934
|
-
const age = (ms) => ms === null ? 'never measured' : ms < 60_000 ? `read ${Math.round(ms / 1000)}s ago` : `read ${mins(ms)} ago`;
|
|
935
|
-
console.log('');
|
|
936
|
-
console.log(` dario — Accounts (live, from http://127.0.0.1:${port})`);
|
|
937
|
-
console.log(' ────────────────');
|
|
938
|
-
console.log('');
|
|
939
|
-
const windows = payload.distinctWindows ?? seats.length;
|
|
940
|
-
console.log(` Pool of ${seats.length} (${seats.length === 1 ? '1 seat' : seats.length + ' seats'} on ${windows} distinct window${windows === 1 ? '' : 's'})`);
|
|
941
|
-
console.log('');
|
|
942
|
-
for (const s of seats) {
|
|
943
|
-
const status = s.status === 'rejected' && typeof s.resetInMs === 'number' ? `rejected, back in ${mins(s.resetInMs)}` : s.status;
|
|
944
|
-
console.log(` ${s.alias.padEnd(20)} ${status.padEnd(26)} 5h ${pct(s.util5h).padEnd(6)} 7d ${pct(s.util7d).padEnd(6)} ${age(s.utilAgeMs)}`);
|
|
945
|
-
// The one-word next step (dario#1244): a parked seat wants nothing from
|
|
946
|
-
// the operator; an auth-failure streak wants a re-grant.
|
|
947
|
-
const next = s.action === 'regrant' ? 'next: re-grant this seat (dario accounts remove + add)'
|
|
948
|
-
: s.action === 'wait' ? 'next: nothing, it comes back on its own'
|
|
949
|
-
: null;
|
|
950
|
-
const facts = [
|
|
951
|
-
`served ${s.requestCount}`,
|
|
952
|
-
`429s ${s.rejectedCount}`,
|
|
953
|
-
...(next ? [next] : []),
|
|
954
|
-
s.organizationId ? `org ${s.organizationId.slice(0, 8)}…` : 'org not yet observed',
|
|
955
|
-
...(s.sharesWindowWith.length > 0 ? [`shares its window with ${s.sharesWindowWith.join(', ')}`] : []),
|
|
956
|
-
];
|
|
957
|
-
console.log(` ${''.padEnd(20)} ${facts.join(' · ')}`);
|
|
958
|
-
console.log(` ${''.padEnd(20)} ${describeGrantAge(grantAge(s.grantedAt ?? undefined, now))}`);
|
|
959
|
-
}
|
|
960
|
-
console.log('');
|
|
973
|
+
for (const line of formatLiveAccountsListing(payload, port, Date.now()))
|
|
974
|
+
console.log(line);
|
|
961
975
|
return true;
|
|
962
976
|
}
|
|
963
977
|
async function accounts() {
|
package/dist/version.js
CHANGED
|
@@ -1,28 +1,42 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* dario's own package version,
|
|
2
|
+
* dario's own package version, bound at module load.
|
|
3
3
|
*
|
|
4
4
|
* Surfaced on `/status` and `/health` (#640) so a headless operator can confirm
|
|
5
5
|
* an auto-update actually rolled the running proxy — `curl /health | jq .version`
|
|
6
6
|
* beats exec-ing into the container to read package.json.
|
|
7
|
+
*
|
|
8
|
+
* WHY AT MODULE LOAD, NOT ON FIRST CALL. This used to read package.json lazily
|
|
9
|
+
* the first time someone asked, and cache that. `npm i -g` rewrites
|
|
10
|
+
* package.json under the running install without touching the process, so a
|
|
11
|
+
* proxy that had not served `/status` before an upgrade answered its first one
|
|
12
|
+
* with the NEW version while still executing the OLD code — precisely the
|
|
13
|
+
* opposite of what the field exists to report. It cost the reporter on #1244 a
|
|
14
|
+
* round trip: `/status` read 6.0.34 while `GET /admin/accounts` was still
|
|
15
|
+
* emitting the 6.0.33 field set, so the advice he had been given ("upgrade,
|
|
16
|
+
* then read `organization_id`") looked already done.
|
|
17
|
+
*
|
|
18
|
+
* Reading at import binds the value to the process. proxy.ts imports this at
|
|
19
|
+
* startup, so `/status` reports the build that is actually answering until it
|
|
20
|
+
* restarts — the only claim the field can honestly make.
|
|
7
21
|
*/
|
|
8
22
|
import { readFileSync } from 'node:fs';
|
|
9
23
|
import { join, dirname } from 'node:path';
|
|
10
24
|
import { fileURLToPath } from 'node:url';
|
|
11
|
-
|
|
12
|
-
export function darioVersion() {
|
|
13
|
-
if (cached !== null)
|
|
14
|
-
return cached;
|
|
15
|
-
let v = 'unknown';
|
|
25
|
+
function readVersion() {
|
|
16
26
|
try {
|
|
17
27
|
// dist/version.js → ../package.json (same layout the MCP server + CLI use).
|
|
18
28
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
19
29
|
const pkg = JSON.parse(readFileSync(join(here, '..', 'package.json'), 'utf-8'));
|
|
20
30
|
if (typeof pkg.version === 'string')
|
|
21
|
-
|
|
31
|
+
return pkg.version;
|
|
22
32
|
}
|
|
23
33
|
catch {
|
|
24
|
-
// package.json missing/malformed —
|
|
34
|
+
// package.json missing/malformed — report 'unknown', never throw.
|
|
25
35
|
}
|
|
26
|
-
|
|
27
|
-
|
|
36
|
+
return 'unknown';
|
|
37
|
+
}
|
|
38
|
+
/** Read once, at import. See the note above for why not on first call. */
|
|
39
|
+
const VERSION = readVersion();
|
|
40
|
+
export function darioVersion() {
|
|
41
|
+
return VERSION;
|
|
28
42
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@askalf/dario",
|
|
3
|
-
"version": "6.0.
|
|
3
|
+
"version": "6.0.37",
|
|
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": {
|