@agentdeck/bridge 1.0.20 → 1.0.22
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/adapters/openclaw.d.ts +55 -1
- package/dist/adapters/openclaw.d.ts.map +1 -1
- package/dist/adapters/openclaw.js +278 -45
- package/dist/adapters/openclaw.js.map +1 -1
- package/dist/adb-reverse.d.ts +26 -3
- package/dist/adb-reverse.d.ts.map +1 -1
- package/dist/adb-reverse.js +26 -5
- package/dist/adb-reverse.js.map +1 -1
- package/dist/apme/adapters/openclaw-hook.d.ts +45 -1
- package/dist/apme/adapters/openclaw-hook.d.ts.map +1 -1
- package/dist/apme/adapters/openclaw-hook.js +84 -4
- package/dist/apme/adapters/openclaw-hook.js.map +1 -1
- package/dist/apme/claude-transcript-reader.d.ts +54 -0
- package/dist/apme/claude-transcript-reader.d.ts.map +1 -1
- package/dist/apme/claude-transcript-reader.js +77 -0
- package/dist/apme/claude-transcript-reader.js.map +1 -1
- package/dist/apme/collector.d.ts +63 -5
- package/dist/apme/collector.d.ts.map +1 -1
- package/dist/apme/collector.js +147 -10
- package/dist/apme/collector.js.map +1 -1
- package/dist/apme/store.d.ts +23 -1
- package/dist/apme/store.d.ts.map +1 -1
- package/dist/apme/store.js +81 -2
- package/dist/apme/store.js.map +1 -1
- package/dist/apme/types.d.ts +1 -1
- package/dist/apme/types.d.ts.map +1 -1
- package/dist/apme/types.js.map +1 -1
- package/dist/auth.d.ts +37 -0
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +23 -0
- package/dist/auth.js.map +1 -1
- package/dist/ble-sync-spawn.d.ts +27 -0
- package/dist/ble-sync-spawn.d.ts.map +1 -1
- package/dist/ble-sync-spawn.js +32 -0
- package/dist/ble-sync-spawn.js.map +1 -1
- package/dist/bridge-core.d.ts +21 -4
- package/dist/bridge-core.d.ts.map +1 -1
- package/dist/bridge-core.js +52 -23
- package/dist/bridge-core.js.map +1 -1
- package/dist/claude-interrupt-marker.d.ts +31 -0
- package/dist/claude-interrupt-marker.d.ts.map +1 -0
- package/dist/claude-interrupt-marker.js +58 -0
- package/dist/claude-interrupt-marker.js.map +1 -0
- package/dist/claude-turn-watchdog.d.ts +23 -0
- package/dist/claude-turn-watchdog.d.ts.map +1 -1
- package/dist/claude-turn-watchdog.js +30 -4
- package/dist/claude-turn-watchdog.js.map +1 -1
- package/dist/cli.d.ts +6 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +411 -115
- package/dist/cli.js.map +1 -1
- package/dist/codex-rate-limits-live.d.ts +58 -9
- package/dist/codex-rate-limits-live.d.ts.map +1 -1
- package/dist/codex-rate-limits-live.js +64 -15
- package/dist/codex-rate-limits-live.js.map +1 -1
- package/dist/codex-rate-limits.d.ts +2 -2
- package/dist/codex-rate-limits.d.ts.map +1 -1
- package/dist/codex-rate-limits.js +34 -16
- package/dist/codex-rate-limits.js.map +1 -1
- package/dist/daemon-port.d.ts +90 -0
- package/dist/daemon-port.d.ts.map +1 -0
- package/dist/daemon-port.js +119 -0
- package/dist/daemon-port.js.map +1 -0
- package/dist/daemon-server.d.ts +60 -3
- package/dist/daemon-server.d.ts.map +1 -1
- package/dist/daemon-server.js +362 -109
- package/dist/daemon-server.js.map +1 -1
- package/dist/daemon-settings.d.ts +46 -0
- package/dist/daemon-settings.d.ts.map +1 -0
- package/dist/daemon-settings.js +85 -0
- package/dist/daemon-settings.js.map +1 -0
- package/dist/daemon-takeover.d.ts +75 -0
- package/dist/daemon-takeover.d.ts.map +1 -0
- package/dist/daemon-takeover.js +137 -0
- package/dist/daemon-takeover.js.map +1 -0
- package/dist/daemon.js +1 -1
- package/dist/hook-server.d.ts.map +1 -1
- package/dist/hook-server.js +17 -0
- package/dist/hook-server.js.map +1 -1
- package/dist/idotmatrix/idotmatrix-daemon-sync.d.ts.map +1 -1
- package/dist/idotmatrix/idotmatrix-daemon-sync.js +13 -1
- package/dist/idotmatrix/idotmatrix-daemon-sync.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +34 -12
- package/dist/index.js.map +1 -1
- package/dist/kiro-diagnostics.d.ts +90 -0
- package/dist/kiro-diagnostics.d.ts.map +1 -0
- package/dist/kiro-diagnostics.js +278 -0
- package/dist/kiro-diagnostics.js.map +1 -0
- package/dist/kiro-session.d.ts +113 -0
- package/dist/kiro-session.d.ts.map +1 -0
- package/dist/kiro-session.js +688 -0
- package/dist/kiro-session.js.map +1 -0
- package/dist/kiro-timeline-feed.d.ts +45 -0
- package/dist/kiro-timeline-feed.d.ts.map +1 -0
- package/dist/kiro-timeline-feed.js +116 -0
- package/dist/kiro-timeline-feed.js.map +1 -0
- package/dist/kiro-transcript-timeline.d.ts +57 -0
- package/dist/kiro-transcript-timeline.d.ts.map +1 -0
- package/dist/kiro-transcript-timeline.js +183 -0
- package/dist/kiro-transcript-timeline.js.map +1 -0
- package/dist/linux-service.d.ts +2 -1
- package/dist/linux-service.d.ts.map +1 -1
- package/dist/linux-service.js +8 -3
- package/dist/linux-service.js.map +1 -1
- package/dist/mdns-discover.d.ts +27 -0
- package/dist/mdns-discover.d.ts.map +1 -1
- package/dist/mdns-discover.js +60 -7
- package/dist/mdns-discover.js.map +1 -1
- package/dist/mdns.d.ts.map +1 -1
- package/dist/mdns.js +16 -3
- package/dist/mdns.js.map +1 -1
- package/dist/modules/adb-module.d.ts.map +1 -1
- package/dist/modules/adb-module.js +5 -2
- package/dist/modules/adb-module.js.map +1 -1
- package/dist/modules/index.d.ts +2 -1
- package/dist/modules/index.d.ts.map +1 -1
- package/dist/modules/index.js +1 -0
- package/dist/modules/index.js.map +1 -1
- package/dist/modules/types.d.ts +34 -9
- package/dist/modules/types.d.ts.map +1 -1
- package/dist/modules/types.js +34 -1
- package/dist/modules/types.js.map +1 -1
- package/dist/network-posture.d.ts +67 -0
- package/dist/network-posture.d.ts.map +1 -0
- package/dist/network-posture.js +100 -0
- package/dist/network-posture.js.map +1 -0
- package/dist/observed-steering.d.ts +14 -0
- package/dist/observed-steering.d.ts.map +1 -1
- package/dist/observed-steering.js +18 -0
- package/dist/observed-steering.js.map +1 -1
- package/dist/observed-turn-watchdogs.d.ts +84 -0
- package/dist/observed-turn-watchdogs.d.ts.map +1 -0
- package/dist/observed-turn-watchdogs.js +134 -0
- package/dist/observed-turn-watchdogs.js.map +1 -0
- package/dist/openclaw-session.d.ts +10 -0
- package/dist/openclaw-session.d.ts.map +1 -1
- package/dist/openclaw-session.js +12 -0
- package/dist/openclaw-session.js.map +1 -1
- package/dist/passive-observer.d.ts +19 -0
- package/dist/passive-observer.d.ts.map +1 -1
- package/dist/passive-observer.js +208 -24
- package/dist/passive-observer.js.map +1 -1
- package/dist/pixoo/micro-glyphs.d.ts +1 -1
- package/dist/pixoo/micro-glyphs.d.ts.map +1 -1
- package/dist/pixoo/micro-glyphs.js +2 -0
- package/dist/pixoo/micro-glyphs.js.map +1 -1
- package/dist/pixoo/official-dot-glyphs.generated.d.ts +1 -1
- package/dist/pixoo/official-dot-glyphs.generated.d.ts.map +1 -1
- package/dist/pixoo/official-dot-glyphs.generated.js +47 -0
- package/dist/pixoo/official-dot-glyphs.generated.js.map +1 -1
- package/dist/pixoo/pixoo-discover.d.ts +8 -1
- package/dist/pixoo/pixoo-discover.d.ts.map +1 -1
- package/dist/pixoo/pixoo-discover.js +15 -8
- package/dist/pixoo/pixoo-discover.js.map +1 -1
- package/dist/pixoo/pixoo-renderer.d.ts +4 -2
- package/dist/pixoo/pixoo-renderer.d.ts.map +1 -1
- package/dist/pixoo/pixoo-renderer.js +105 -36
- package/dist/pixoo/pixoo-renderer.js.map +1 -1
- package/dist/pixoo/pixoo-settings.d.ts +19 -2
- package/dist/pixoo/pixoo-settings.d.ts.map +1 -1
- package/dist/pixoo/pixoo-settings.js +22 -4
- package/dist/pixoo/pixoo-settings.js.map +1 -1
- package/dist/pixoo/pixoo-sprites.d.ts.map +1 -1
- package/dist/pixoo/pixoo-sprites.js +2 -0
- package/dist/pixoo/pixoo-sprites.js.map +1 -1
- package/dist/python-ble-runtime.d.ts +2 -0
- package/dist/python-ble-runtime.d.ts.map +1 -1
- package/dist/python-ble-runtime.js +101 -7
- package/dist/python-ble-runtime.js.map +1 -1
- package/dist/session-aggregator.d.ts +9 -1
- package/dist/session-aggregator.d.ts.map +1 -1
- package/dist/session-aggregator.js +1 -1
- package/dist/session-aggregator.js.map +1 -1
- package/dist/session-registry.d.ts +71 -3
- package/dist/session-registry.d.ts.map +1 -1
- package/dist/session-registry.js +126 -19
- package/dist/session-registry.js.map +1 -1
- package/dist/subagent-timeline.d.ts +38 -7
- package/dist/subagent-timeline.d.ts.map +1 -1
- package/dist/subagent-timeline.js +154 -23
- package/dist/subagent-timeline.js.map +1 -1
- package/dist/timebox/timebox-daemon-sync.d.ts.map +1 -1
- package/dist/timebox/timebox-daemon-sync.js +11 -1
- package/dist/timebox/timebox-daemon-sync.js.map +1 -1
- package/dist/timeline-store.d.ts.map +1 -1
- package/dist/timeline-store.js +26 -1
- package/dist/timeline-store.js.map +1 -1
- package/dist/tui/renderer.d.ts.map +1 -1
- package/dist/tui/renderer.js +13 -1
- package/dist/tui/renderer.js.map +1 -1
- package/dist/tui/terrarium.d.ts.map +1 -1
- package/dist/tui/terrarium.js +10 -5
- package/dist/tui/terrarium.js.map +1 -1
- package/dist/usage-api.d.ts +28 -1
- package/dist/usage-api.d.ts.map +1 -1
- package/dist/usage-api.js +74 -33
- package/dist/usage-api.js.map +1 -1
- package/dist/usage-event.d.ts.map +1 -1
- package/dist/usage-event.js +2 -17
- package/dist/usage-event.js.map +1 -1
- package/dist/utils/redact-secrets.d.ts +3 -0
- package/dist/utils/redact-secrets.d.ts.map +1 -0
- package/dist/utils/redact-secrets.js +29 -0
- package/dist/utils/redact-secrets.js.map +1 -0
- package/dist/windows-service.d.ts +2 -1
- package/dist/windows-service.d.ts.map +1 -1
- package/dist/windows-service.js +6 -3
- package/dist/windows-service.js.map +1 -1
- package/package.json +3 -3
|
@@ -1,4 +1,26 @@
|
|
|
1
1
|
import type { CodexRateLimits } from '@agentdeck/shared';
|
|
2
|
+
interface RawLiveWindow {
|
|
3
|
+
usedPercent?: number;
|
|
4
|
+
/** The app-server spells the window length differently from the rollout
|
|
5
|
+
* (`windowDurationMins` vs `window_minutes`); accept both. */
|
|
6
|
+
windowDurationMins?: number;
|
|
7
|
+
windowMinutes?: number;
|
|
8
|
+
resetsAt?: number;
|
|
9
|
+
}
|
|
10
|
+
interface RawLiveCredits {
|
|
11
|
+
hasCredits?: boolean;
|
|
12
|
+
unlimited?: boolean;
|
|
13
|
+
balance?: string | number;
|
|
14
|
+
}
|
|
15
|
+
interface RawLiveRateLimits {
|
|
16
|
+
primary?: RawLiveWindow | null;
|
|
17
|
+
secondary?: RawLiveWindow | null;
|
|
18
|
+
planType?: string;
|
|
19
|
+
limitId?: string;
|
|
20
|
+
/** Set only on a limit scoped to one model/feature — see `isModelScopedCodexLimit`. */
|
|
21
|
+
limitName?: string | null;
|
|
22
|
+
credits?: RawLiveCredits | null;
|
|
23
|
+
}
|
|
2
24
|
/**
|
|
3
25
|
* Map an `account/rateLimits/read` result onto the wire shape. `capturedAt` is
|
|
4
26
|
* the instant WE asked — unlike the passive read (which carries the rollout
|
|
@@ -6,6 +28,16 @@ import type { CodexRateLimits } from '@agentdeck/shared';
|
|
|
6
28
|
* what clears the age footnote downstream. Exported for unit testing.
|
|
7
29
|
*/
|
|
8
30
|
export declare function parseLiveCodexRateLimits(result: unknown, capturedAt: string): CodexRateLimits | null;
|
|
31
|
+
/**
|
|
32
|
+
* The account-wide limit block among what `account/rateLimits/read` returned.
|
|
33
|
+
*
|
|
34
|
+
* Prefers the top-level `rateLimits` (what the Codex CLI shows) and falls back
|
|
35
|
+
* to the first unnamed entry of `rateLimitsByLimitId`. Returns null when every
|
|
36
|
+
* family is model-scoped: "no account-wide reading" is the honest answer, and
|
|
37
|
+
* the caller then keeps whatever the rollout path found rather than adopting one
|
|
38
|
+
* model's quota as the account's. Exported for unit testing.
|
|
39
|
+
*/
|
|
40
|
+
export declare function pickAccountWideLiveLimits(top?: RawLiveRateLimits | null, byLimitId?: Record<string, RawLiveRateLimits> | null): RawLiveRateLimits | null;
|
|
9
41
|
/**
|
|
10
42
|
* How to hand the Codex binary to `spawn`.
|
|
11
43
|
*
|
|
@@ -34,27 +66,44 @@ export declare function queryCodexRateLimitsLive(opts?: {
|
|
|
34
66
|
timeoutMs?: number;
|
|
35
67
|
}): Promise<CodexRateLimits | null>;
|
|
36
68
|
/**
|
|
37
|
-
* Choose the
|
|
38
|
-
*
|
|
39
|
-
*
|
|
69
|
+
* Choose between the passive rollout reading and the live app-server reading.
|
|
70
|
+
*
|
|
71
|
+
* Plan agreement first, capture time second (`codexSnapshotOutranks`). Recency
|
|
72
|
+
* alone let the wrong one win in exactly the case the live query exists to
|
|
73
|
+
* cover: a Codex session opened before a plan change keeps writing old-plan
|
|
74
|
+
* rollout snapshots with ever-newer timestamps, so the live answer — correct,
|
|
75
|
+
* current, and the ONLY source carrying the new tier — lost every comparison and
|
|
76
|
+
* was then voided as a mismatch. A snapshot with no `capturedAt` at all loses to
|
|
77
|
+
* a stamped one within its match class; ties keep the passive reading, which is
|
|
78
|
+
* the on-disk ground truth. Exported for unit testing.
|
|
40
79
|
*/
|
|
41
|
-
export declare function
|
|
80
|
+
export declare function pickBestCodexRateLimits(passive: CodexRateLimits | null, live: CodexRateLimits | null, accountPlan?: string): CodexRateLimits | null;
|
|
42
81
|
/** Throttle policy, kept pure so the cadence is testable without spawning. */
|
|
43
82
|
export declare function shouldQueryCodexRateLimitsLive(input: {
|
|
44
83
|
nowMs: number;
|
|
45
84
|
lastAttemptMs: number;
|
|
46
85
|
consecutiveFailures: number;
|
|
47
86
|
passiveCapturedAtMs: number;
|
|
87
|
+
/** False when the passive snapshot is stamped with a plan the account no
|
|
88
|
+
* longer holds — i.e. it is about to be voided and carries no usable number.
|
|
89
|
+
* Defaults to true so callers that know no account tier behave as before. */
|
|
90
|
+
passivePlanMatchesAccount?: boolean;
|
|
48
91
|
}): boolean;
|
|
49
92
|
/** Last live snapshot, or null if none has been obtained. */
|
|
50
93
|
export declare function getLiveCodexRateLimits(): CodexRateLimits | null;
|
|
51
94
|
/**
|
|
52
|
-
* Daemon entry point: return the
|
|
53
|
-
* kick off a throttled background refresh when the passive one has gone quiet
|
|
54
|
-
*
|
|
55
|
-
*
|
|
95
|
+
* Daemon entry point: return the better of the passive and live readings, and
|
|
96
|
+
* kick off a throttled background refresh when the passive one has gone quiet
|
|
97
|
+
* OR has been minted under a plan the account no longer holds. Fire-and-forget
|
|
98
|
+
* by design — the current call is answered from cache so usage building never
|
|
99
|
+
* awaits a subprocess.
|
|
100
|
+
*
|
|
101
|
+
* `accountPlan` is the live tier from `auth.json`. Passing it is what lets both
|
|
102
|
+
* halves of this function tell "old" from "void"; omitting it keeps the previous
|
|
103
|
+
* newest-wins behaviour.
|
|
56
104
|
*/
|
|
57
|
-
export declare function codexRateLimitsWithLiveRefresh(passive: CodexRateLimits | null): CodexRateLimits | null;
|
|
105
|
+
export declare function codexRateLimitsWithLiveRefresh(passive: CodexRateLimits | null, accountPlan?: string): CodexRateLimits | null;
|
|
58
106
|
/** Test hook — clears the module-level cache and throttle state. */
|
|
59
107
|
export declare function __resetCodexRateLimitsLiveForTest(): void;
|
|
108
|
+
export {};
|
|
60
109
|
//# sourceMappingURL=codex-rate-limits-live.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex-rate-limits-live.d.ts","sourceRoot":"","sources":["../src/codex-rate-limits-live.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"codex-rate-limits-live.d.ts","sourceRoot":"","sources":["../src/codex-rate-limits-live.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAgB,eAAe,EAAwB,MAAM,mBAAmB,CAAC;AAiD7F,UAAU,aAAa;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;mEAC+D;IAC/D,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,UAAU,cAAc;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC3B;AAED,UAAU,iBAAiB;IACzB,OAAO,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;IAC/B,SAAS,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uFAAuF;IACvF,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,OAAO,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;CACjC;AA+BD;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CA0BpG;AAED;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CACvC,GAAG,CAAC,EAAE,iBAAiB,GAAG,IAAI,EAC9B,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,GAAG,IAAI,GACnD,iBAAiB,GAAG,IAAI,CAM1B;AAMD;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAC3C;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAGrC;AAED;;;;GAIG;AACH,wBAAsB,wBAAwB,CAC5C,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GAClE,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAyEjC;AAQD;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,eAAe,GAAG,IAAI,EAC/B,IAAI,EAAE,eAAe,GAAG,IAAI,EAC5B,WAAW,CAAC,EAAE,MAAM,GACnB,eAAe,GAAG,IAAI,CAUxB;AAED,8EAA8E;AAC9E,wBAAgB,8BAA8B,CAAC,KAAK,EAAE;IACpD,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mBAAmB,EAAE,MAAM,CAAC;IAC5B;;kFAE8E;IAC9E,yBAAyB,CAAC,EAAE,OAAO,CAAC;CACrC,GAAG,OAAO,CAyBV;AAOD,6DAA6D;AAC7D,wBAAgB,sBAAsB,IAAI,eAAe,GAAG,IAAI,CAE/D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,eAAe,GAAG,IAAI,EAC/B,WAAW,CAAC,EAAE,MAAM,GACnB,eAAe,GAAG,IAAI,CAiCxB;AAED,oEAAoE;AACpE,wBAAgB,iCAAiC,IAAI,IAAI,CAKxD"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { spawn } from 'child_process';
|
|
2
|
+
import { codexSnapshotMatchesAccountPlan, codexSnapshotOutranks, isModelScopedCodexLimit, } from '@agentdeck/shared';
|
|
2
3
|
/**
|
|
3
4
|
* Active Codex rate-limit read via the local `codex app-server` JSON-RPC.
|
|
4
5
|
*
|
|
@@ -78,7 +79,14 @@ function toCredits(raw) {
|
|
|
78
79
|
* what clears the age footnote downstream. Exported for unit testing.
|
|
79
80
|
*/
|
|
80
81
|
export function parseLiveCodexRateLimits(result, capturedAt) {
|
|
81
|
-
const
|
|
82
|
+
const res = result;
|
|
83
|
+
// The top-level block is the account's today, and that is what the Codex CLI
|
|
84
|
+
// itself presents. But the app-server also returns every family keyed by id,
|
|
85
|
+
// so when the top level is scoped to one model there is still an account-wide
|
|
86
|
+
// answer in the map — take it rather than reporting a single model's quota as
|
|
87
|
+
// the account's. (Not currently reachable; the guard costs one lookup and the
|
|
88
|
+
// alternative is the rollout bug in a place with no second source.)
|
|
89
|
+
const rl = pickAccountWideLiveLimits(res?.rateLimits, res?.rateLimitsByLimitId);
|
|
82
90
|
if (!rl || typeof rl !== 'object')
|
|
83
91
|
return null;
|
|
84
92
|
const primary = toWindow(rl.primary);
|
|
@@ -96,6 +104,24 @@ export function parseLiveCodexRateLimits(result, capturedAt) {
|
|
|
96
104
|
capturedAt,
|
|
97
105
|
};
|
|
98
106
|
}
|
|
107
|
+
/**
|
|
108
|
+
* The account-wide limit block among what `account/rateLimits/read` returned.
|
|
109
|
+
*
|
|
110
|
+
* Prefers the top-level `rateLimits` (what the Codex CLI shows) and falls back
|
|
111
|
+
* to the first unnamed entry of `rateLimitsByLimitId`. Returns null when every
|
|
112
|
+
* family is model-scoped: "no account-wide reading" is the honest answer, and
|
|
113
|
+
* the caller then keeps whatever the rollout path found rather than adopting one
|
|
114
|
+
* model's quota as the account's. Exported for unit testing.
|
|
115
|
+
*/
|
|
116
|
+
export function pickAccountWideLiveLimits(top, byLimitId) {
|
|
117
|
+
if (top && !isModelScopedCodexLimit(top.limitName))
|
|
118
|
+
return top;
|
|
119
|
+
for (const candidate of Object.values(byLimitId ?? {})) {
|
|
120
|
+
if (candidate && !isModelScopedCodexLimit(candidate.limitName))
|
|
121
|
+
return candidate;
|
|
122
|
+
}
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
99
125
|
function codexBinary() {
|
|
100
126
|
return process.env.AGENTDECK_CODEX_BIN || (process.platform === 'win32' ? 'codex.cmd' : 'codex');
|
|
101
127
|
}
|
|
@@ -204,26 +230,43 @@ function capturedAtMs(rl) {
|
|
|
204
230
|
return isNaN(ms) ? 0 : ms;
|
|
205
231
|
}
|
|
206
232
|
/**
|
|
207
|
-
* Choose the
|
|
208
|
-
*
|
|
209
|
-
*
|
|
233
|
+
* Choose between the passive rollout reading and the live app-server reading.
|
|
234
|
+
*
|
|
235
|
+
* Plan agreement first, capture time second (`codexSnapshotOutranks`). Recency
|
|
236
|
+
* alone let the wrong one win in exactly the case the live query exists to
|
|
237
|
+
* cover: a Codex session opened before a plan change keeps writing old-plan
|
|
238
|
+
* rollout snapshots with ever-newer timestamps, so the live answer — correct,
|
|
239
|
+
* current, and the ONLY source carrying the new tier — lost every comparison and
|
|
240
|
+
* was then voided as a mismatch. A snapshot with no `capturedAt` at all loses to
|
|
241
|
+
* a stamped one within its match class; ties keep the passive reading, which is
|
|
242
|
+
* the on-disk ground truth. Exported for unit testing.
|
|
210
243
|
*/
|
|
211
|
-
export function
|
|
244
|
+
export function pickBestCodexRateLimits(passive, live, accountPlan) {
|
|
212
245
|
if (!live)
|
|
213
246
|
return passive;
|
|
214
247
|
if (!passive)
|
|
215
248
|
return live;
|
|
216
|
-
return
|
|
249
|
+
return codexSnapshotOutranks({ planType: live.planType, capturedAtMs: capturedAtMs(live) }, { planType: passive.planType, capturedAtMs: capturedAtMs(passive) }, accountPlan)
|
|
250
|
+
? live
|
|
251
|
+
: passive;
|
|
217
252
|
}
|
|
218
253
|
/** Throttle policy, kept pure so the cadence is testable without spawning. */
|
|
219
254
|
export function shouldQueryCodexRateLimitsLive(input) {
|
|
220
|
-
const { nowMs, lastAttemptMs, consecutiveFailures, passiveCapturedAtMs } = input;
|
|
255
|
+
const { nowMs, lastAttemptMs, consecutiveFailures, passiveCapturedAtMs, passivePlanMatchesAccount = true, } = input;
|
|
221
256
|
const interval = consecutiveFailures >= MAX_CONSECUTIVE_FAILURES ? FAILURE_BACKOFF_MS : MIN_QUERY_INTERVAL_MS;
|
|
257
|
+
// Spawn throttles are unconditional: a mismatch is a reason to prefer the live
|
|
258
|
+
// read, never a licence to spawn a subprocess on every usage build.
|
|
222
259
|
if (lastAttemptMs > 0 && nowMs - lastAttemptMs < interval)
|
|
223
260
|
return false;
|
|
224
|
-
// Codex is mid-turn: the rollout is already writing fresh readings
|
|
225
|
-
if
|
|
261
|
+
// Codex is mid-turn: the rollout is already writing fresh readings — but only
|
|
262
|
+
// if those readings are usable at all. A snapshot stamped with a retired plan
|
|
263
|
+
// is voided downstream, so "the passive read is fresh" would suppress the one
|
|
264
|
+
// source that still has a number, precisely while Codex is being used hardest.
|
|
265
|
+
if (passivePlanMatchesAccount &&
|
|
266
|
+
passiveCapturedAtMs > 0 &&
|
|
267
|
+
nowMs - passiveCapturedAtMs < PASSIVE_FRESH_MS) {
|
|
226
268
|
return false;
|
|
269
|
+
}
|
|
227
270
|
return true;
|
|
228
271
|
}
|
|
229
272
|
let cachedLive = null;
|
|
@@ -235,12 +278,17 @@ export function getLiveCodexRateLimits() {
|
|
|
235
278
|
return cachedLive;
|
|
236
279
|
}
|
|
237
280
|
/**
|
|
238
|
-
* Daemon entry point: return the
|
|
239
|
-
* kick off a throttled background refresh when the passive one has gone quiet
|
|
240
|
-
*
|
|
241
|
-
*
|
|
281
|
+
* Daemon entry point: return the better of the passive and live readings, and
|
|
282
|
+
* kick off a throttled background refresh when the passive one has gone quiet
|
|
283
|
+
* OR has been minted under a plan the account no longer holds. Fire-and-forget
|
|
284
|
+
* by design — the current call is answered from cache so usage building never
|
|
285
|
+
* awaits a subprocess.
|
|
286
|
+
*
|
|
287
|
+
* `accountPlan` is the live tier from `auth.json`. Passing it is what lets both
|
|
288
|
+
* halves of this function tell "old" from "void"; omitting it keeps the previous
|
|
289
|
+
* newest-wins behaviour.
|
|
242
290
|
*/
|
|
243
|
-
export function codexRateLimitsWithLiveRefresh(passive) {
|
|
291
|
+
export function codexRateLimitsWithLiveRefresh(passive, accountPlan) {
|
|
244
292
|
if (process.env.AGENTDECK_CODEX_LIVE_USAGE !== '0') {
|
|
245
293
|
const nowMs = Date.now();
|
|
246
294
|
if (!inFlight &&
|
|
@@ -249,6 +297,7 @@ export function codexRateLimitsWithLiveRefresh(passive) {
|
|
|
249
297
|
lastAttemptMs,
|
|
250
298
|
consecutiveFailures,
|
|
251
299
|
passiveCapturedAtMs: capturedAtMs(passive),
|
|
300
|
+
passivePlanMatchesAccount: codexSnapshotMatchesAccountPlan(passive?.planType, accountPlan),
|
|
252
301
|
})) {
|
|
253
302
|
inFlight = true;
|
|
254
303
|
lastAttemptMs = nowMs;
|
|
@@ -270,7 +319,7 @@ export function codexRateLimitsWithLiveRefresh(passive) {
|
|
|
270
319
|
});
|
|
271
320
|
}
|
|
272
321
|
}
|
|
273
|
-
return
|
|
322
|
+
return pickBestCodexRateLimits(passive, cachedLive, accountPlan);
|
|
274
323
|
}
|
|
275
324
|
/** Test hook — clears the module-level cache and throttle state. */
|
|
276
325
|
export function __resetCodexRateLimitsLiveForTest() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex-rate-limits-live.js","sourceRoot":"","sources":["../src/codex-rate-limits-live.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"codex-rate-limits-live.js","sourceRoot":"","sources":["../src/codex-rate-limits-live.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,7 +4,7 @@ import type { CodexRateLimits } from '@agentdeck/shared';
|
|
|
4
4
|
* Exported (root-injectable) for unit testing; `readCodexRateLimits` wraps this
|
|
5
5
|
* with mtime caching against the live `~/.codex/sessions` tree.
|
|
6
6
|
*/
|
|
7
|
-
export declare function pickCodexRateLimits(root?: string): CodexRateLimits | null;
|
|
7
|
+
export declare function pickCodexRateLimits(root?: string, accountPlan?: string): CodexRateLimits | null;
|
|
8
8
|
/**
|
|
9
9
|
* Parse the newest `rate_limits` snapshot out of a chunk of rollout JSONL text
|
|
10
10
|
* (typically the file tail). Scans lines from the end so the most recent
|
|
@@ -12,5 +12,5 @@ export declare function pickCodexRateLimits(root?: string): CodexRateLimits | nu
|
|
|
12
12
|
* rate-limit line is found.
|
|
13
13
|
*/
|
|
14
14
|
export declare function parseCodexRateLimitsFromText(text: string): CodexRateLimits | null;
|
|
15
|
-
export declare function readCodexRateLimits(root?: string): CodexRateLimits | null;
|
|
15
|
+
export declare function readCodexRateLimits(root?: string, accountPlan?: string): CodexRateLimits | null;
|
|
16
16
|
//# sourceMappingURL=codex-rate-limits.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex-rate-limits.d.ts","sourceRoot":"","sources":["../src/codex-rate-limits.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"codex-rate-limits.d.ts","sourceRoot":"","sources":["../src/codex-rate-limits.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAgB,eAAe,EAAwB,MAAM,mBAAmB,CAAC;AAkK7F;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,GAAE,MAA8B,EACpC,WAAW,CAAC,EAAE,MAAM,GACnB,eAAe,GAAG,IAAI,CAExB;AA0DD;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAsCjF;AASD,wBAAgB,mBAAmB,CACjC,IAAI,GAAE,MAA8B,EACpC,WAAW,CAAC,EAAE,MAAM,GACnB,eAAe,GAAG,IAAI,CAaxB"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import os from 'os';
|
|
3
3
|
import path from 'path';
|
|
4
|
+
import { codexSnapshotOutranks, isModelScopedCodexLimit } from '@agentdeck/shared';
|
|
4
5
|
const defaultSessionsRoot = () => path.join(os.homedir(), '.codex', 'sessions');
|
|
5
6
|
/** List immediate subdirectory names of `dir`, sorted newest-first (numeric,
|
|
6
7
|
* so "10" > "9"). Returns [] on any read error. */
|
|
@@ -67,17 +68,22 @@ function candidateRolloutFiles(root, maxDays = 3, maxFiles = 6) {
|
|
|
67
68
|
files.sort((a, b) => b.mtime - a.mtime);
|
|
68
69
|
return files.slice(0, maxFiles);
|
|
69
70
|
}
|
|
70
|
-
/** Scan every candidate and return the usable rate-limits snapshot
|
|
71
|
-
* newest CAPTURE timestamp.
|
|
71
|
+
/** Scan every candidate and return the best usable rate-limits snapshot.
|
|
72
72
|
*
|
|
73
73
|
* File mtime only identifies which rollouts are active enough to inspect. It
|
|
74
74
|
* cannot decide which ACCOUNT snapshot is newest when several Codex sessions
|
|
75
75
|
* append concurrently: a reasoning/tool line can make one file newest while
|
|
76
76
|
* its last rate_limits line is older than a snapshot in another file. Choosing
|
|
77
|
-
* the first usable file made usage move backwards or appear frozen.
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
77
|
+
* the first usable file made usage move backwards or appear frozen.
|
|
78
|
+
*
|
|
79
|
+
* `accountPlan` (the live tier from `auth.json`) makes the ranking plan-aware —
|
|
80
|
+
* see `codexSnapshotOutranks`. Without it a Codex session left open across a
|
|
81
|
+
* plan change wins on recency forever with a snapshot that is voided one step
|
|
82
|
+
* later, blanking every gauge while a valid snapshot sits in another rollout.
|
|
83
|
+
* Omitting it (tests, an API-key install with no tier) keeps pure newest-wins. */
|
|
84
|
+
function parseFirstUsable(candidates, accountPlan) {
|
|
85
|
+
let best = null;
|
|
86
|
+
let bestCapturedAtMs = -Infinity;
|
|
81
87
|
for (const { full, mtime } of candidates) {
|
|
82
88
|
const tail = readTail(full);
|
|
83
89
|
const parsed = tail ? parseCodexRateLimitsFromText(tail) : null;
|
|
@@ -89,21 +95,22 @@ function parseFirstUsable(candidates) {
|
|
|
89
95
|
// snapshot this anchor exists to expose. mtime is the fallback.
|
|
90
96
|
parsed.capturedAt = parsed.capturedAt ?? new Date(mtime).toISOString();
|
|
91
97
|
const capturedAtMs = new Date(parsed.capturedAt).getTime();
|
|
92
|
-
if (!
|
|
93
|
-
|
|
94
|
-
|
|
98
|
+
if (!best ||
|
|
99
|
+
codexSnapshotOutranks({ planType: parsed.planType, capturedAtMs }, { planType: best.planType, capturedAtMs: bestCapturedAtMs }, accountPlan)) {
|
|
100
|
+
best = parsed;
|
|
101
|
+
bestCapturedAtMs = capturedAtMs;
|
|
95
102
|
}
|
|
96
103
|
}
|
|
97
104
|
}
|
|
98
|
-
return
|
|
105
|
+
return best;
|
|
99
106
|
}
|
|
100
107
|
/**
|
|
101
108
|
* Read the newest usable Codex rate-limits snapshot from a sessions tree.
|
|
102
109
|
* Exported (root-injectable) for unit testing; `readCodexRateLimits` wraps this
|
|
103
110
|
* with mtime caching against the live `~/.codex/sessions` tree.
|
|
104
111
|
*/
|
|
105
|
-
export function pickCodexRateLimits(root = defaultSessionsRoot()) {
|
|
106
|
-
return parseFirstUsable(candidateRolloutFiles(root));
|
|
112
|
+
export function pickCodexRateLimits(root = defaultSessionsRoot(), accountPlan) {
|
|
113
|
+
return parseFirstUsable(candidateRolloutFiles(root), accountPlan);
|
|
107
114
|
}
|
|
108
115
|
/** Read the trailing bytes of a file without slurping the whole rollout (these
|
|
109
116
|
* can grow to many MB). The newest `rate_limits` line is always near the end. */
|
|
@@ -177,6 +184,13 @@ export function parseCodexRateLimitsFromText(text) {
|
|
|
177
184
|
const rl = obj?.payload?.rate_limits;
|
|
178
185
|
if (!rl)
|
|
179
186
|
continue;
|
|
187
|
+
// A per-model limit is a different QUANTITY, not a staler one, so keep
|
|
188
|
+
// scanning instead of returning it: within one session the family
|
|
189
|
+
// alternates hour to hour, and the account-wide line usually sits further
|
|
190
|
+
// back in this same tail. Returning null for the file would throw that
|
|
191
|
+
// line away along with the scoped one.
|
|
192
|
+
if (isModelScopedCodexLimit(rl.limit_name))
|
|
193
|
+
continue;
|
|
180
194
|
const primary = toWindow(rl.primary);
|
|
181
195
|
const secondary = toWindow(rl.secondary);
|
|
182
196
|
const credits = toCredits(rl.credits);
|
|
@@ -206,12 +220,16 @@ export function parseCodexRateLimitsFromText(text) {
|
|
|
206
220
|
// another candidate remain invisible until the first file changed again.
|
|
207
221
|
let cacheKey = '';
|
|
208
222
|
let cacheValue = null;
|
|
209
|
-
export function readCodexRateLimits(root = defaultSessionsRoot()) {
|
|
223
|
+
export function readCodexRateLimits(root = defaultSessionsRoot(), accountPlan) {
|
|
210
224
|
const candidates = candidateRolloutFiles(root);
|
|
211
|
-
|
|
212
|
-
|
|
225
|
+
// The account tier is part of the key, not just the files: the selection is
|
|
226
|
+
// plan-aware, so the same set of rollouts ranks differently the instant the
|
|
227
|
+
// user's plan changes. Keying on files alone would serve the pre-upgrade
|
|
228
|
+
// winner until some rollout happened to be touched again.
|
|
229
|
+
const key = `${accountPlan ?? ''}|${candidates.map(({ full, mtime }) => `${full}:${mtime}`).join('|')}`;
|
|
230
|
+
if (candidates.length > 0 && key === cacheKey)
|
|
213
231
|
return cacheValue;
|
|
214
|
-
const parsed = parseFirstUsable(candidates);
|
|
232
|
+
const parsed = parseFirstUsable(candidates, accountPlan);
|
|
215
233
|
cacheKey = key;
|
|
216
234
|
cacheValue = parsed;
|
|
217
235
|
return parsed;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex-rate-limits.js","sourceRoot":"","sources":["../src/codex-rate-limits.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"codex-rate-limits.js","sourceRoot":"","sources":["../src/codex-rate-limits.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,qBAAqB,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAgDnF,MAAM,mBAAmB,GAAG,GAAW,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;AAOxF;oDACoD;AACpD,SAAS,aAAa,CAAC,GAAW;IAChC,IAAI,CAAC;QACH,OAAO,EAAE;aACN,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;aACzC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;aAC9B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;aAClB,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACtE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;2EAG2E;AAC3E,SAAS,aAAa,CAAC,IAAY,EAAE,OAAe;IAClD,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,MAAM,IAAI,IAAI,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC;QACvC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QACtC,KAAK,MAAM,KAAK,IAAI,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC;YAC3C,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YAC3C,KAAK,MAAM,GAAG,IAAI,aAAa,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC1C,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC;gBACnC,IAAI,GAAG,CAAC,MAAM,IAAI,OAAO;oBAAE,OAAO,GAAG,CAAC;YACxC,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;4CAI4C;AAC5C,SAAS,qBAAqB,CAAC,IAAY,EAAE,OAAO,GAAG,CAAC,EAAE,QAAQ,GAAG,CAAC;IACpE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IACpC,MAAM,KAAK,GAAuB,EAAE,CAAC;IACrC,KAAK,MAAM,MAAM,IAAI,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC;QAClD,IAAI,OAAiB,CAAC;QACtB,IAAI,CAAC;YACH,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QACnC,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QACD,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACxB,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;gBAAE,SAAS;YACjE,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;YAClC,IAAI,CAAC;gBACH,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;YACzD,CAAC;YAAC,MAAM,CAAC;gBACP,6BAA6B;YAC/B,CAAC;QACH,CAAC;IACH,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;IACxC,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;AAClC,CAAC;AAED;;;;;;;;;;;;kFAYkF;AAClF,SAAS,gBAAgB,CACvB,UAA8B,EAC9B,WAAoB;IAEpB,IAAI,IAAI,GAA2B,IAAI,CAAC;IACxC,IAAI,gBAAgB,GAAG,CAAC,QAAQ,CAAC;IACjC,KAAK,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,UAAU,EAAE,CAAC;QACzC,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC5B,MAAM,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,4BAA4B,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAChE,IAAI,MAAM,EAAE,CAAC;YACX,2EAA2E;YAC3E,wEAAwE;YACxE,2EAA2E;YAC3E,4EAA4E;YAC5E,gEAAgE;YAChE,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC;YACvE,MAAM,YAAY,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE,CAAC;YAC3D,IACE,CAAC,IAAI;gBACL,qBAAqB,CACnB,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,YAAY,EAAE,EAC3C,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,YAAY,EAAE,gBAAgB,EAAE,EAC3D,WAAW,CACZ,EACD,CAAC;gBACD,IAAI,GAAG,MAAM,CAAC;gBACd,gBAAgB,GAAG,YAAY,CAAC;YAClC,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CACjC,OAAe,mBAAmB,EAAE,EACpC,WAAoB;IAEpB,OAAO,gBAAgB,CAAC,qBAAqB,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC,CAAC;AACpE,CAAC;AAED;kFACkF;AAClF,SAAS,QAAQ,CAAC,IAAY,EAAE,QAAQ,GAAG,MAAM;IAC/C,IAAI,EAAE,GAAkB,IAAI,CAAC;IAC7B,IAAI,CAAC;QACH,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QAC5B,MAAM,IAAI,GAAG,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC;QACnC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,GAAG,QAAQ,CAAC,CAAC;QAC3C,MAAM,GAAG,GAAG,IAAI,GAAG,KAAK,CAAC;QACzB,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC9B,EAAE,CAAC,QAAQ,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;QACpC,OAAO,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;YAAS,CAAC;QACT,IAAI,EAAE,KAAK,IAAI;YACb,IAAI,CAAC;gBACH,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;YACnB,CAAC;YAAC,MAAM,CAAC;gBACP,YAAY;YACd,CAAC;IACL,CAAC;AACH,CAAC;AAED,SAAS,SAAS,CAAC,GAAgB;IACjC,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO,GAAG,CAAC,WAAW,KAAK,SAAS,IAAI,OAAO,GAAG,CAAC,SAAS,KAAK,SAAS,IAAI,GAAG,CAAC,OAAO,IAAI,IAAI,CAAC,EAAE,CAAC;QAChH,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO;QACL,UAAU,EAAE,GAAG,CAAC,WAAW,KAAK,IAAI;QACpC,SAAS,EAAE,GAAG,CAAC,SAAS,KAAK,IAAI;QACjC,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS;KAC/D,CAAC;AACJ,CAAC;AAED;sEACsE;AACtE,SAAS,qBAAqB,CAAC,EAAW;IACxC,IAAI,OAAO,EAAE,KAAK,QAAQ,IAAI,CAAC,EAAE;QAAE,OAAO,SAAS,CAAC;IACpD,MAAM,EAAE,GAAG,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;IAClC,OAAO,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;AAC5D,CAAC;AAED,SAAS,QAAQ,CAAC,GAAe;IAC/B,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,CAAC,YAAY,KAAK,QAAQ,IAAI,OAAO,GAAG,CAAC,cAAc,KAAK,QAAQ,EAAE,CAAC;QAC3F,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,QAAQ,GACZ,OAAO,GAAG,CAAC,SAAS,KAAK,QAAQ,IAAI,GAAG,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IACpH,OAAO;QACL,WAAW,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,YAAY,CAAC,CAAC;QACzD,aAAa,EAAE,GAAG,CAAC,cAAc;QACjC,QAAQ;KACT,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,4BAA4B,CAAC,IAAY;IACvD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC/B,KAAK,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3C,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC7B,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC;YAAE,SAAS;QACrD,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAG1B,CAAC;YACF,MAAM,EAAE,GAAG,GAAG,EAAE,OAAO,EAAE,WAAW,CAAC;YACrC,IAAI,CAAC,EAAE;gBAAE,SAAS;YAClB,uEAAuE;YACvE,kEAAkE;YAClE,0EAA0E;YAC1E,uEAAuE;YACvE,uCAAuC;YACvC,IAAI,uBAAuB,CAAC,EAAE,CAAC,UAAU,CAAC;gBAAE,SAAS;YACrD,MAAM,OAAO,GAAG,QAAQ,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC;YACrC,MAAM,SAAS,GAAG,QAAQ,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC;YACzC,MAAM,OAAO,GAAG,SAAS,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC;YACtC,MAAM,OAAO,GAAG,OAAO,EAAE,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC;YAC1E,uEAAuE;YACvE,yEAAyE;YACzE,IAAI,CAAC,OAAO,IAAI,CAAC,SAAS,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO;gBAAE,SAAS;YAC7D,OAAO;gBACL,OAAO;gBACP,SAAS;gBACT,QAAQ,EAAE,OAAO,EAAE,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS;gBACrE,OAAO;gBACP,OAAO;gBACP,UAAU,EAAE,qBAAqB,CAAC,GAAG,CAAC,SAAS,CAAC;aACjD,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC;YACP,uEAAuE;QACzE,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,wEAAwE;AACxE,+EAA+E;AAC/E,gFAAgF;AAChF,yEAAyE;AACzE,IAAI,QAAQ,GAAG,EAAE,CAAC;AAClB,IAAI,UAAU,GAA2B,IAAI,CAAC;AAE9C,MAAM,UAAU,mBAAmB,CACjC,OAAe,mBAAmB,EAAE,EACpC,WAAoB;IAEpB,MAAM,UAAU,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;IAC/C,4EAA4E;IAC5E,4EAA4E;IAC5E,yEAAyE;IACzE,0DAA0D;IAC1D,MAAM,GAAG,GAAG,GAAG,WAAW,IAAI,EAAE,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,GAAG,IAAI,IAAI,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;IACxG,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,IAAI,GAAG,KAAK,QAAQ;QAAE,OAAO,UAAU,CAAC;IAEjE,MAAM,MAAM,GAAG,gBAAgB,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;IACzD,QAAQ,GAAG,GAAG,CAAC;IACf,UAAU,GAAG,MAAM,CAAC;IACpB,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The CLI daemon's **preferred port** — the port it intends to serve, as
|
|
3
|
+
* opposed to the port it ended up on.
|
|
4
|
+
*
|
|
5
|
+
* Roadmap item 11 (docs/ENTERPRISE-ROADMAP.md §1.5) asks for a persistent
|
|
6
|
+
* `daemonPort` for the CLI to match the macOS app's `AppPreferences.daemonPort`.
|
|
7
|
+
* The reason it matters is not configurability for its own sake — it is that
|
|
8
|
+
* without a recorded intent, a daemon that landed on a fallback port has no way
|
|
9
|
+
* to know it is on the wrong one.
|
|
10
|
+
*
|
|
11
|
+
* ## Intent is persisted; the outcome never is
|
|
12
|
+
*
|
|
13
|
+
* This is the rule the whole module exists to enforce. `daemon.json` records
|
|
14
|
+
* where the daemon *is*, and every client resolves through it. This setting
|
|
15
|
+
* records where the daemon *wants to be*. Persisting the outcome instead would
|
|
16
|
+
* be self-reinforcing: a daemon bumped to 9121 by a transient hold would write
|
|
17
|
+
* 9121 down and start there forever, turning a 14-second kernel reservation
|
|
18
|
+
* into a permanent move. So nothing in the daemon's startup path ever writes
|
|
19
|
+
* this value — only the user does, via `agentdeck daemon port <n>`.
|
|
20
|
+
*
|
|
21
|
+
* ## Sources
|
|
22
|
+
*
|
|
23
|
+
* `-p/--port` › `AGENTDECK_DAEMON_PORT` › `settings.json` `daemonPort` › 9120.
|
|
24
|
+
* All four are statements of intent; they differ only in precedence and in how
|
|
25
|
+
* long they last. The resolved `source` is carried alongside the number because
|
|
26
|
+
* one caller needs it: `daemon start` treats a port the user typed on THIS
|
|
27
|
+
* invocation differently from one it merely defaulted to (an explicit choice
|
|
28
|
+
* fails loudly rather than quietly binding a different port).
|
|
29
|
+
*/
|
|
30
|
+
/** `settings.json` key. Same name as the macOS app's `prefs.daemonPort`. */
|
|
31
|
+
export declare const DAEMON_PORT_SETTING_KEY = "daemonPort";
|
|
32
|
+
/** Environment override, for a shell or MDM profile that cannot edit files. */
|
|
33
|
+
export declare const DAEMON_PORT_ENV_VAR = "AGENTDECK_DAEMON_PORT";
|
|
34
|
+
/**
|
|
35
|
+
* Accepted range, mirroring `AppPreferences.clampPort` (1024–65535). Below 1024
|
|
36
|
+
* needs root on every platform we support, which the daemon never has.
|
|
37
|
+
*/
|
|
38
|
+
export declare const DAEMON_PORT_MIN = 1024;
|
|
39
|
+
export declare const DAEMON_PORT_MAX = 65535;
|
|
40
|
+
/**
|
|
41
|
+
* How long the daemon waits for its preferred port to come free before
|
|
42
|
+
* conceding to a fallback, when nothing answers `/health` on it.
|
|
43
|
+
*
|
|
44
|
+
* Sized from a measurement, not a guess: cancelling a listener on macOS leaves
|
|
45
|
+
* a NECP reservation on the port for ~14s (bindable at ~17s, measured
|
|
46
|
+
* 2026-08-06 — `lsof` shows zero sockets for the whole interval and `bind()`
|
|
47
|
+
* still returns EADDRINUSE). 20s clears that with margin.
|
|
48
|
+
*
|
|
49
|
+
* The wait polls, so it costs only as long as the port is actually held. The
|
|
50
|
+
* full budget is paid only when something outside AgentDeck really is
|
|
51
|
+
* listening there — once per daemon start, with a log line saying so.
|
|
52
|
+
*/
|
|
53
|
+
export declare const PREFERRED_PORT_RECLAIM_MS = 20000;
|
|
54
|
+
export type DaemonPortSource = 'flag' | 'env' | 'settings' | 'default';
|
|
55
|
+
export interface ResolvedDaemonPort {
|
|
56
|
+
port: number;
|
|
57
|
+
source: DaemonPortSource;
|
|
58
|
+
}
|
|
59
|
+
/** True when `value` is a port this daemon may be asked to bind. */
|
|
60
|
+
export declare function isValidDaemonPort(value: unknown): value is number;
|
|
61
|
+
/**
|
|
62
|
+
* Parse a port written as text (a flag value, an env var). Returns null for
|
|
63
|
+
* anything that is not a valid port — including `"9120abc"`, which `parseInt`
|
|
64
|
+
* would happily read as 9120.
|
|
65
|
+
*/
|
|
66
|
+
export declare function parseDaemonPort(raw: string | undefined | null): number | null;
|
|
67
|
+
/**
|
|
68
|
+
* The persisted preference, or null when absent or unusable.
|
|
69
|
+
*
|
|
70
|
+
* Lenient on purpose: a malformed `daemonPort` must fall through to the
|
|
71
|
+
* default rather than stop the daemon from starting. The *setter* is the strict
|
|
72
|
+
* half — it rejects out-of-range input with a message, so a typo is caught
|
|
73
|
+
* where the user can see it instead of silently reverting six weeks later.
|
|
74
|
+
*/
|
|
75
|
+
export declare function preferredDaemonPortFrom(settings: Record<string, unknown>): number | null;
|
|
76
|
+
export interface ResolveDaemonPortInput {
|
|
77
|
+
/** `-p/--port` as typed on THIS invocation, or undefined when defaulted. */
|
|
78
|
+
flag?: string | number | null;
|
|
79
|
+
env?: NodeJS.ProcessEnv;
|
|
80
|
+
settings?: Record<string, unknown>;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Resolve the preferred port and where it came from. Pure — every input is
|
|
84
|
+
* injectable so the precedence order can be pinned without touching the real
|
|
85
|
+
* environment or the real settings file.
|
|
86
|
+
*/
|
|
87
|
+
export declare function resolveDaemonPort(input?: ResolveDaemonPortInput): ResolvedDaemonPort;
|
|
88
|
+
/** Human-readable provenance, for `daemon port` and the startup log. */
|
|
89
|
+
export declare function describeDaemonPortSource(source: DaemonPortSource): string;
|
|
90
|
+
//# sourceMappingURL=daemon-port.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon-port.d.ts","sourceRoot":"","sources":["../src/daemon-port.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAKH,4EAA4E;AAC5E,eAAO,MAAM,uBAAuB,eAAe,CAAC;AAEpD,+EAA+E;AAC/E,eAAO,MAAM,mBAAmB,0BAA0B,CAAC;AAE3D;;;GAGG;AACH,eAAO,MAAM,eAAe,OAAO,CAAC;AACpC,eAAO,MAAM,eAAe,QAAQ,CAAC;AAErC;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,yBAAyB,QAAS,CAAC;AAEhD,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,KAAK,GAAG,UAAU,GAAG,SAAS,CAAC;AAEvE,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,gBAAgB,CAAC;CAC1B;AAED,oEAAoE;AACpE,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAKjE;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAK7E;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,GAAG,IAAI,CAMxF;AAED,MAAM,WAAW,sBAAsB;IACrC,4EAA4E;IAC5E,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,GAAE,sBAA2B,GAAG,kBAAkB,CAYxF;AAED,wEAAwE;AACxE,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAOzE"}
|