@askalf/dario 5.5.65 → 5.5.66

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/doctor.d.ts CHANGED
@@ -77,6 +77,29 @@ export interface IdentityDriftInput {
77
77
  accountUuid: string;
78
78
  }>;
79
79
  }
80
+ /**
81
+ * The OAuth doctor row, as a pure decision — mirrors checkIdentityDrift so the
82
+ * branch logic is unit-testable without touching the filesystem.
83
+ *
84
+ * WHY THIS EXISTS. The legacy `credentials.json` is not what serves once an
85
+ * account pool exists: dario#805 deliberately keeps a NEWER pool token and
86
+ * refuses to overwrite that file, so "credentials.json is stale" is an expected
87
+ * steady state — every recovery that restores a pool account leaves one behind.
88
+ * Reporting that as `OAuth expired` while the pool answers every request is a
89
+ * false alarm, and dario-doctor-watch opens an issue for it on EVERY run:
90
+ * dario#1105 was filed while a live probe was returning 200 on both Haiku and
91
+ * Sonnet. A watcher that cries wolf on a healthy proxy trains its reader to
92
+ * ignore it, which is the failure the watcher exists to prevent.
93
+ *
94
+ * So: a live pool overrides a dead legacy file (and says so, rather than hiding
95
+ * it), and only "nothing can serve" is reported as a failure.
96
+ */
97
+ export declare function oauthCheckRow(input: {
98
+ legacyStatus: string;
99
+ legacyCanRefresh: boolean;
100
+ poolHealthy: number;
101
+ poolTotal: number;
102
+ }): Check;
80
103
  export declare function checkIdentityDrift(input: IdentityDriftInput): Check[];
81
104
  export declare function probeNpmLatestCC(): string | null;
82
105
  /**
package/dist/doctor.js CHANGED
@@ -88,6 +88,39 @@ export function formatChecksJson(checks) {
88
88
  checks,
89
89
  }, null, 2);
90
90
  }
91
+ /**
92
+ * The OAuth doctor row, as a pure decision — mirrors checkIdentityDrift so the
93
+ * branch logic is unit-testable without touching the filesystem.
94
+ *
95
+ * WHY THIS EXISTS. The legacy `credentials.json` is not what serves once an
96
+ * account pool exists: dario#805 deliberately keeps a NEWER pool token and
97
+ * refuses to overwrite that file, so "credentials.json is stale" is an expected
98
+ * steady state — every recovery that restores a pool account leaves one behind.
99
+ * Reporting that as `OAuth expired` while the pool answers every request is a
100
+ * false alarm, and dario-doctor-watch opens an issue for it on EVERY run:
101
+ * dario#1105 was filed while a live probe was returning 200 on both Haiku and
102
+ * Sonnet. A watcher that cries wolf on a healthy proxy trains its reader to
103
+ * ignore it, which is the failure the watcher exists to prevent.
104
+ *
105
+ * So: a live pool overrides a dead legacy file (and says so, rather than hiding
106
+ * it), and only "nothing can serve" is reported as a failure.
107
+ */
108
+ export function oauthCheckRow(input) {
109
+ const { legacyStatus, legacyCanRefresh, poolHealthy, poolTotal } = input;
110
+ if (poolHealthy > 0) {
111
+ return {
112
+ status: 'ok',
113
+ label: 'OAuth',
114
+ detail: `pool credential live (${poolHealthy}/${poolTotal} account${poolTotal === 1 ? '' : 's'}) — ` +
115
+ `the legacy credentials.json is ${legacyStatus} and unused (dario#805)`,
116
+ };
117
+ }
118
+ return {
119
+ status: legacyStatus === 'expired' && legacyCanRefresh ? 'warn' : 'fail',
120
+ label: 'OAuth',
121
+ detail: legacyStatus === 'none' ? 'not authenticated — run `dario login`' : legacyStatus,
122
+ };
123
+ }
91
124
  export function checkIdentityDrift(input) {
92
125
  const { live, poolAccounts } = input;
93
126
  // Short-prefix for surfaced IDs — 64-char userIDs and 36-char UUIDs are
@@ -477,11 +510,20 @@ export async function runChecks(opts = {}) {
477
510
  const { getStatus } = await import('./oauth.js');
478
511
  const s = await getStatus();
479
512
  if (!s.authenticated) {
480
- checks.push({
481
- status: s.status === 'expired' && s.canRefresh ? 'warn' : 'fail',
482
- label: 'OAuth',
483
- detail: s.status === 'none' ? 'not authenticated — run `dario login`' : s.status,
484
- });
513
+ // What actually serves is the POOL, not the legacy credentials.json —
514
+ // so ask the pool before reporting an auth failure. See oauthCheckRow.
515
+ let poolHealthy = 0, poolTotal = 0;
516
+ try {
517
+ const { listAccountAliases, loadAllAccounts } = await import('./accounts.js');
518
+ if ((await listAccountAliases()).length > 0) {
519
+ const loaded = await loadAllAccounts();
520
+ const now = Date.now();
521
+ poolTotal = loaded.length;
522
+ poolHealthy = loaded.filter((a) => a.expiresAt > now).length;
523
+ }
524
+ }
525
+ catch { /* pool unreadable — oauthCheckRow falls back to the legacy verdict */ }
526
+ checks.push(oauthCheckRow({ legacyStatus: s.status, legacyCanRefresh: !!s.canRefresh, poolHealthy, poolTotal }));
485
527
  }
486
528
  else {
487
529
  checks.push({ status: 'ok', label: 'OAuth', detail: `${s.status} (expires in ${s.expiresIn})` });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@askalf/dario",
3
- "version": "5.5.65",
3
+ "version": "5.5.66",
4
4
  "description": "Use your Claude Pro/Max subscription in any tool — Cursor, Cline, Aider, the Agent SDK, your scripts — at subscription pricing, not per-token API bills. One local Anthropic + OpenAI-compatible endpoint.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -24,7 +24,7 @@
24
24
  "scripts": {
25
25
  "build": "tsc && cp src/cc-template-data.json dist/",
26
26
  "test": "node --test --test-concurrency=8 test/all.test.mjs",
27
- "test:serial": "node test/issue-29-tool-translation.mjs && node test/hybrid-tools.mjs && node test/tool-schema-contract.mjs && node test/scrub-paths.mjs && node test/provider-prefix.mjs && node test/analytics-recording.mjs && node test/analytics-billing-bucket.mjs && node test/failover-429.mjs && node test/pool-sticky.mjs && node test/live-fingerprint.mjs && node test/proxy-header-order.mjs && node test/proxy-body-order.mjs && node test/runtime-fingerprint.mjs && node test/pacing.mjs && node test/stream-drain.mjs && node test/subagent.mjs && node test/mcp-protocol.mjs && node test/mcp-tools.mjs && node test/mcp-e2e.mjs && node test/session-rotation.mjs && node test/drift-detection.mjs && node test/cc-authorize-probe-classifier.mjs && node test/compat-range.mjs && node test/doctor-formatter.mjs && node test/doctor-identity-drift.mjs && node test/atomic-write.mjs && node test/account-refresh-singleflight.mjs && node test/durable-token-persist.mjs && node test/streaming-edge-cases.mjs && node test/client-detection.mjs && node test/manual-oauth-flow.mjs && node test/scrub-template.mjs && node test/context-bleed.mjs && node test/passthrough-header-forwarding.mjs && node test/capture-provenance.mjs && node test/sanitize-messages.mjs && node test/platform-tools.mjs && node test/strict-template-flags.mjs && node test/request-queue.mjs && node test/effort-flag.mjs && node test/template-invariants.mjs",
27
+ "test:serial": "node test/issue-29-tool-translation.mjs && node test/hybrid-tools.mjs && node test/tool-schema-contract.mjs && node test/scrub-paths.mjs && node test/provider-prefix.mjs && node test/analytics-recording.mjs && node test/analytics-billing-bucket.mjs && node test/failover-429.mjs && node test/pool-sticky.mjs && node test/live-fingerprint.mjs && node test/proxy-header-order.mjs && node test/proxy-body-order.mjs && node test/runtime-fingerprint.mjs && node test/pacing.mjs && node test/stream-drain.mjs && node test/subagent.mjs && node test/mcp-protocol.mjs && node test/mcp-tools.mjs && node test/mcp-e2e.mjs && node test/session-rotation.mjs && node test/drift-detection.mjs && node test/cc-authorize-probe-classifier.mjs && node test/compat-range.mjs && node test/doctor-formatter.mjs && node test/doctor-identity-drift.mjs && node test/doctor-oauth-pool.mjs && node test/atomic-write.mjs && node test/account-refresh-singleflight.mjs && node test/durable-token-persist.mjs && node test/streaming-edge-cases.mjs && node test/client-detection.mjs && node test/manual-oauth-flow.mjs && node test/scrub-template.mjs && node test/context-bleed.mjs && node test/passthrough-header-forwarding.mjs && node test/capture-provenance.mjs && node test/sanitize-messages.mjs && node test/platform-tools.mjs && node test/strict-template-flags.mjs && node test/request-queue.mjs && node test/effort-flag.mjs && node test/template-invariants.mjs",
28
28
  "audit": "npm audit --production --audit-level=high",
29
29
  "prepublishOnly": "npm run build",
30
30
  "start": "node dist/cli.js",