@askalf/dario 4.8.136 → 4.8.137
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/analytics.js +12 -0
- package/dist/notify.d.ts +16 -0
- package/dist/notify.js +56 -38
- package/dist/proxy.js +5 -5
- package/package.json +1 -1
package/dist/analytics.js
CHANGED
|
@@ -25,6 +25,16 @@ export function billingBucketFromClaim(claim) {
|
|
|
25
25
|
switch (claim) {
|
|
26
26
|
case 'five_hour':
|
|
27
27
|
case 'seven_day':
|
|
28
|
+
// `*_overage_included` — the plan's INCLUDED overage credit, observed live
|
|
29
|
+
// 2026-07-05 on a Max account at 7d 82% with the `7d_oi` bucket at 99%:
|
|
30
|
+
// fable answered normally (genuine model echo, stop_reason end_turn),
|
|
31
|
+
// status=allowed_warning, overage-utilization 0 — $0 out of pocket, so it
|
|
32
|
+
// is subscription billing, not extra usage. Real paid overage still
|
|
33
|
+
// arrives as `overage` and still halts the guard. Pre-classification the
|
|
34
|
+
// guard's halt-on-unknown design 503'd the proxy on every such claim
|
|
35
|
+
// (30-min cooldown loops) exactly when the weekly window tightens.
|
|
36
|
+
case 'five_hour_overage_included':
|
|
37
|
+
case 'seven_day_overage_included':
|
|
28
38
|
return 'subscription';
|
|
29
39
|
case 'five_hour_fallback':
|
|
30
40
|
case 'seven_day_fallback':
|
|
@@ -49,6 +59,8 @@ export const SUBSCRIPTION_CLAIMS = new Set([
|
|
|
49
59
|
'seven_day',
|
|
50
60
|
'five_hour_fallback',
|
|
51
61
|
'seven_day_fallback',
|
|
62
|
+
'five_hour_overage_included',
|
|
63
|
+
'seven_day_overage_included',
|
|
52
64
|
]);
|
|
53
65
|
/**
|
|
54
66
|
* The sentinel `claim` dario assigns when a response carried no rate-limit
|
package/dist/notify.d.ts
CHANGED
|
@@ -22,6 +22,22 @@
|
|
|
22
22
|
*
|
|
23
23
|
* See dario#288 — overage-guard.
|
|
24
24
|
*/
|
|
25
|
+
/**
|
|
26
|
+
* Spawn a detached, output-ignored child and swallow EVERY failure mode.
|
|
27
|
+
*
|
|
28
|
+
* The subtle one: a missing binary does NOT throw from `spawn()` — it
|
|
29
|
+
* surfaces as an ASYNC `'error'` event on the ChildProcess, and with no
|
|
30
|
+
* handler attached that's an uncaught exception that kills the whole
|
|
31
|
+
* process. Seen live 2026-07-05 (#672): `spawn notify-send` ENOENT inside
|
|
32
|
+
* the Docker image crashed the proxy on every overage-guard event — the
|
|
33
|
+
* guard fired, notify killed the process, docker restarted it, ~15s of
|
|
34
|
+
* refused connections per event. The existing try/catch only covered the
|
|
35
|
+
* sync-throw path (EMFILE etc.), which is also kept here.
|
|
36
|
+
*
|
|
37
|
+
* Exported for test/notify.mjs, which spawns a guaranteed-nonexistent
|
|
38
|
+
* binary and asserts the process survives the async error event.
|
|
39
|
+
*/
|
|
40
|
+
export declare function spawnFireAndForget(cmd: string, args: string[]): void;
|
|
25
41
|
/**
|
|
26
42
|
* Fire a native notification. Returns immediately — the underlying spawn
|
|
27
43
|
* is fire-and-forget. Errors (missing binary, permission denied, no
|
package/dist/notify.js
CHANGED
|
@@ -24,6 +24,32 @@
|
|
|
24
24
|
*/
|
|
25
25
|
import { spawn } from 'node:child_process';
|
|
26
26
|
import { platform } from 'node:os';
|
|
27
|
+
/**
|
|
28
|
+
* Spawn a detached, output-ignored child and swallow EVERY failure mode.
|
|
29
|
+
*
|
|
30
|
+
* The subtle one: a missing binary does NOT throw from `spawn()` — it
|
|
31
|
+
* surfaces as an ASYNC `'error'` event on the ChildProcess, and with no
|
|
32
|
+
* handler attached that's an uncaught exception that kills the whole
|
|
33
|
+
* process. Seen live 2026-07-05 (#672): `spawn notify-send` ENOENT inside
|
|
34
|
+
* the Docker image crashed the proxy on every overage-guard event — the
|
|
35
|
+
* guard fired, notify killed the process, docker restarted it, ~15s of
|
|
36
|
+
* refused connections per event. The existing try/catch only covered the
|
|
37
|
+
* sync-throw path (EMFILE etc.), which is also kept here.
|
|
38
|
+
*
|
|
39
|
+
* Exported for test/notify.mjs, which spawns a guaranteed-nonexistent
|
|
40
|
+
* binary and asserts the process survives the async error event.
|
|
41
|
+
*/
|
|
42
|
+
export function spawnFireAndForget(cmd, args) {
|
|
43
|
+
try {
|
|
44
|
+
const child = spawn(cmd, args, { detached: true, stdio: 'ignore' });
|
|
45
|
+
child.on('error', () => { });
|
|
46
|
+
child.unref();
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
// Sync throw path (EMFILE and friends); silent — same contract as
|
|
50
|
+
// the notification itself: best-effort, never load-bearing.
|
|
51
|
+
}
|
|
52
|
+
}
|
|
27
53
|
/**
|
|
28
54
|
* Fire a native notification. Returns immediately — the underlying spawn
|
|
29
55
|
* is fire-and-forget. Errors (missing binary, permission denied, no
|
|
@@ -47,46 +73,38 @@ export function notify(title, message) {
|
|
|
47
73
|
const safeTitle = sanitize(title);
|
|
48
74
|
const safeMessage = sanitize(message);
|
|
49
75
|
const plat = platform();
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
], { detached: true, stdio: 'ignore' }).unref();
|
|
60
|
-
}
|
|
61
|
-
else if (plat === 'linux') {
|
|
62
|
-
spawn('notify-send', [safeTitle, safeMessage], {
|
|
63
|
-
detached: true,
|
|
64
|
-
stdio: 'ignore',
|
|
65
|
-
}).unref();
|
|
66
|
-
}
|
|
67
|
-
else if (plat === 'win32') {
|
|
68
|
-
// BurntToast is the cleanest path — single-line PowerShell, real
|
|
69
|
-
// Windows toast notification. If BurntToast isn't installed the
|
|
70
|
-
// command fails silently (stdio: ignore swallows the error
|
|
71
|
-
// output), which is the desired behavior.
|
|
72
|
-
//
|
|
73
|
-
// We don't probe-then-spawn; the cost of one failed BurntToast
|
|
74
|
-
// attempt is the same as one probe attempt, and probing makes the
|
|
75
|
-
// hot path slower for the success case.
|
|
76
|
-
const ps = `try { Import-Module BurntToast -ErrorAction Stop; New-BurntToastNotification -Text '${safeTitle}', '${safeMessage}' } catch { exit 1 }`;
|
|
77
|
-
spawn('powershell.exe', [
|
|
78
|
-
'-NoProfile',
|
|
79
|
-
'-NonInteractive',
|
|
80
|
-
'-Command',
|
|
81
|
-
ps,
|
|
82
|
-
], { detached: true, stdio: 'ignore' }).unref();
|
|
83
|
-
}
|
|
84
|
-
// freebsd / openbsd / aix / sunos / android — BEL only. There's no
|
|
85
|
-
// single "right" native notification on these platforms.
|
|
76
|
+
if (plat === 'darwin') {
|
|
77
|
+
// AppleScript single-quote inside the script body would need
|
|
78
|
+
// escaping; sanitize() strips them so the literal substitution
|
|
79
|
+
// below stays safe. Spawned via array argv to avoid a shell
|
|
80
|
+
// entirely.
|
|
81
|
+
spawnFireAndForget('osascript', [
|
|
82
|
+
'-e',
|
|
83
|
+
`display notification "${safeMessage}" with title "${safeTitle}"`,
|
|
84
|
+
]);
|
|
86
85
|
}
|
|
87
|
-
|
|
88
|
-
|
|
86
|
+
else if (plat === 'linux') {
|
|
87
|
+
spawnFireAndForget('notify-send', [safeTitle, safeMessage]);
|
|
88
|
+
}
|
|
89
|
+
else if (plat === 'win32') {
|
|
90
|
+
// BurntToast is the cleanest path — single-line PowerShell, real
|
|
91
|
+
// Windows toast notification. If BurntToast isn't installed the
|
|
92
|
+
// command fails silently (stdio: ignore swallows the error
|
|
93
|
+
// output), which is the desired behavior.
|
|
94
|
+
//
|
|
95
|
+
// We don't probe-then-spawn; the cost of one failed BurntToast
|
|
96
|
+
// attempt is the same as one probe attempt, and probing makes the
|
|
97
|
+
// hot path slower for the success case.
|
|
98
|
+
const ps = `try { Import-Module BurntToast -ErrorAction Stop; New-BurntToastNotification -Text '${safeTitle}', '${safeMessage}' } catch { exit 1 }`;
|
|
99
|
+
spawnFireAndForget('powershell.exe', [
|
|
100
|
+
'-NoProfile',
|
|
101
|
+
'-NonInteractive',
|
|
102
|
+
'-Command',
|
|
103
|
+
ps,
|
|
104
|
+
]);
|
|
89
105
|
}
|
|
106
|
+
// freebsd / openbsd / aix / sunos / android — BEL only. There's no
|
|
107
|
+
// single "right" native notification on these platforms.
|
|
90
108
|
}
|
|
91
109
|
/**
|
|
92
110
|
* Strip characters that would break the embedded shell/AppleScript
|
package/dist/proxy.js
CHANGED
|
@@ -13,7 +13,7 @@ import { buildCCRequest, applyCcPromptCaching, parseEffortSuffix, reverseMapResp
|
|
|
13
13
|
import { stampCch, hasCchSeed } from './cch.js';
|
|
14
14
|
import { describeTemplate, detectDrift, checkCCCompat } from './live-fingerprint.js';
|
|
15
15
|
import { AccountPool, computeStickyKey, parseRateLimits, modelFamily, isInAuthCooldown, authCooldownMs, reconcilePoolAccounts } from './pool.js';
|
|
16
|
-
import { Analytics, billingBucketFromClaim } from './analytics.js';
|
|
16
|
+
import { Analytics, billingBucketFromClaim, SUBSCRIPTION_CLAIMS } from './analytics.js';
|
|
17
17
|
import { OverageGuard, buildHaltErrorBody } from './overage-guard.js';
|
|
18
18
|
import { notify as osNotify } from './notify.js';
|
|
19
19
|
import { loadAllAccounts, loadAccount, refreshAccountToken, resyncLoginFromCredentialsIfStale, ensureLoginCredentialsInPool } from './accounts.js';
|
|
@@ -2897,10 +2897,10 @@ export async function startProxy(opts = {}) {
|
|
|
2897
2897
|
if (overageUtil !== null) {
|
|
2898
2898
|
overagePct = `${Math.round(parseFloat(overageUtil) * 100)}%`;
|
|
2899
2899
|
}
|
|
2900
|
-
else if (billingClaim
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2900
|
+
else if (billingClaim && SUBSCRIPTION_CLAIMS.has(billingClaim)) {
|
|
2901
|
+
// Any subscription-side claim (incl. *_overage_included) with no
|
|
2902
|
+
// overage-utilization header means $0 extra usage — same sync
|
|
2903
|
+
// source as the guard so this list can't drift again.
|
|
2904
2904
|
overagePct = '0%';
|
|
2905
2905
|
}
|
|
2906
2906
|
else {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@askalf/dario",
|
|
3
|
-
"version": "4.8.
|
|
3
|
+
"version": "4.8.137",
|
|
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": {
|