@scrylog/cli 0.3.0 → 0.3.2
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/assets/highlights-eq9cgrbb.scm +604 -0
- package/dist/assets/highlights-ghv9g403.scm +205 -0
- package/dist/assets/highlights-hk7bwhj4.scm +284 -0
- package/dist/assets/highlights-r812a2qc.scm +150 -0
- package/dist/assets/highlights-x6tmsnaa.scm +115 -0
- package/dist/assets/injections-73j83es3.scm +27 -0
- package/dist/assets/parser.worker-xyhf83rf.js +4563 -0
- package/dist/assets/tree-sitter-3jzf13jk.wasm +0 -0
- package/dist/assets/tree-sitter-javascript-nd0q4pe9.wasm +0 -0
- package/dist/assets/tree-sitter-markdown-411r6y9b.wasm +0 -0
- package/dist/assets/tree-sitter-markdown_inline-j5349f42.wasm +0 -0
- package/dist/assets/tree-sitter-typescript-zxjzwt75.wasm +0 -0
- package/dist/assets/tree-sitter-zig-e78zbjpm.wasm +0 -0
- package/dist/cli/index.js +499 -0
- package/dist/cli/index.js.map +61 -0
- package/dist/daemon/index.js +670 -0
- package/dist/daemon/index.js.map +1475 -0
- package/dist/hooks/claude.js +6 -0
- package/dist/hooks/claude.js.map +11 -0
- package/dist/hooks/codex.js +10 -0
- package/dist/hooks/codex.js.map +11 -0
- package/dist/mcp/index.js +100 -0
- package/dist/mcp/index.js.map +231 -0
- package/dist/oc/index.js +21 -0
- package/dist/oc/index.js.map +10 -0
- package/package.json +16 -13
- package/src/api/docs/sessions.keys.ts +0 -6
- package/src/api/docs/sessions.ts +0 -82
- package/src/api/docs/system.keys.ts +0 -5
- package/src/api/docs/system.ts +0 -69
- package/src/api/docs/usage.keys.ts +0 -3
- package/src/api/docs/usage.ts +0 -24
- package/src/api/docs/webhooks.keys.ts +0 -5
- package/src/api/docs/webhooks.ts +0 -78
- package/src/api/index.ts +0 -18
- package/src/api/lib/auth.ts +0 -43
- package/src/api/lib/errors.ts +0 -28
- package/src/api/lib/route.ts +0 -18
- package/src/api/models/claude.ts +0 -4
- package/src/api/models/codex.ts +0 -4
- package/src/api/models/opencode.ts +0 -11
- package/src/api/routes/sessions.ts +0 -51
- package/src/api/routes/system.ts +0 -106
- package/src/api/routes/usage.ts +0 -15
- package/src/api/routes/webhooks/claude.ts +0 -149
- package/src/api/routes/webhooks/codex.ts +0 -175
- package/src/api/routes/webhooks/opencode.ts +0 -112
- package/src/api/routes.ts +0 -93
- package/src/api/schemas/common.ts +0 -29
- package/src/api/schemas/sessions.ts +0 -86
- package/src/api/schemas/usage.ts +0 -51
- package/src/api/schemas/webhooks/claude.ts +0 -32
- package/src/api/schemas/webhooks/codex.ts +0 -34
- package/src/api/schemas/webhooks/opencode.ts +0 -29
- package/src/api/services/claude-session.ts +0 -9
- package/src/api/services/codex-session.ts +0 -8
- package/src/api/services/opencode-session.ts +0 -73
- package/src/classifier.ts +0 -206
- package/src/cli/commands.ts +0 -714
- package/src/cli/index.ts +0 -18
- package/src/cli/program.ts +0 -175
- package/src/cli/prompt.ts +0 -44
- package/src/daemon/cli.ts +0 -27
- package/src/daemon/collectors/claude/README.md +0 -108
- package/src/daemon/collectors/claude/collector.ts +0 -423
- package/src/daemon/collectors/claude/discovery.ts +0 -127
- package/src/daemon/collectors/claude/hooks.ts +0 -181
- package/src/daemon/collectors/claude/index.ts +0 -8
- package/src/daemon/collectors/claude/jsonl.ts +0 -85
- package/src/daemon/collectors/claude/transcript.ts +0 -246
- package/src/daemon/collectors/codex/README.md +0 -147
- package/src/daemon/collectors/codex/collector.ts +0 -661
- package/src/daemon/collectors/codex/discovery.ts +0 -104
- package/src/daemon/collectors/codex/hooks.ts +0 -179
- package/src/daemon/collectors/codex/index.ts +0 -7
- package/src/daemon/collectors/codex/jsonl.ts +0 -108
- package/src/daemon/collectors/codex/transcript.ts +0 -299
- package/src/daemon/collectors/git.ts +0 -353
- package/src/daemon/collectors/herdr/collector.ts +0 -128
- package/src/daemon/collectors/herdr/index.ts +0 -2
- package/src/daemon/collectors/herdr/normalization.ts +0 -111
- package/src/daemon/collectors/opencode/README.md +0 -106
- package/src/daemon/collectors/opencode/collector.ts +0 -545
- package/src/daemon/collectors/opencode/discovery.ts +0 -257
- package/src/daemon/collectors/opencode/index.ts +0 -5
- package/src/daemon/collectors/opencode/session-builder.ts +0 -59
- package/src/daemon/collectors/opencode-db.ts +0 -294
- package/src/daemon/collectors/process.ts +0 -201
- package/src/daemon/collectors/tmux/README.md +0 -128
- package/src/daemon/collectors/tmux/collector.ts +0 -492
- package/src/daemon/collectors/tmux/enrichment.ts +0 -242
- package/src/daemon/collectors/tmux/index.ts +0 -4
- package/src/daemon/collectors/tmux/parse.ts +0 -128
- package/src/daemon/collectors/usage.ts +0 -259
- package/src/daemon/index.ts +0 -209
- package/src/daemon/scheduler.ts +0 -86
- package/src/daemon/store.ts +0 -630
- package/src/detect.ts +0 -143
- package/src/hooks/claude.ts +0 -596
- package/src/hooks/codex.ts +0 -517
- package/src/legacy/classifier.ts +0 -215
- package/src/legacy/detect.ts +0 -143
- package/src/mcp/client-server.ts +0 -21
- package/src/mcp/http-handler.ts +0 -126
- package/src/mcp/index.ts +0 -61
- package/src/mcp/resources/config-current.ts +0 -19
- package/src/mcp/resources/index.ts +0 -11
- package/src/mcp/resources/sessions-active.ts +0 -19
- package/src/mcp/resources/sessions-all.ts +0 -19
- package/src/mcp/schemas/sessions.ts +0 -3
- package/src/mcp/server.ts +0 -17
- package/src/mcp/services/api-adapter.ts +0 -48
- package/src/mcp/services/data-source.ts +0 -22
- package/src/mcp/services/store-adapter.ts +0 -40
- package/src/mcp/tools/get-active-sessions.ts +0 -16
- package/src/mcp/tools/get-session-children.ts +0 -24
- package/src/mcp/tools/get-session-messages.ts +0 -24
- package/src/mcp/tools/get-session.ts +0 -23
- package/src/mcp/tools/index.ts +0 -15
- package/src/mcp/tools/list-sessions.ts +0 -16
- package/src/oc/index.ts +0 -302
- package/src/service/manager.ts +0 -284
- package/src/shared/config.ts +0 -511
- package/src/shared/ipc.ts +0 -80
- package/src/shared/logger.ts +0 -248
- package/src/shared/paths.ts +0 -73
- package/src/shared/platform.ts +0 -110
- package/src/shared/session-exclusions.ts +0 -5
- package/src/shared/session-view.ts +0 -302
- package/src/shared/terminal-capabilities.ts +0 -130
- package/src/shared/types.ts +0 -330
- package/src/shared/utils.ts +0 -339
- package/src/shared/version.ts +0 -44
- package/src/tui/App.tsx +0 -240
- package/src/tui/client.ts +0 -163
- package/src/tui/components/BindingsModal.tsx +0 -82
- package/src/tui/components/DashboardHeader.tsx +0 -256
- package/src/tui/components/KeyBar.tsx +0 -67
- package/src/tui/components/SessionDetailModal.tsx +0 -169
- package/src/tui/components/SessionsView.tsx +0 -184
- package/src/tui/components/TabBar.tsx +0 -40
- package/src/tui/components/UsageSummaryPane.tsx +0 -272
- package/src/tui/components/UsageView.tsx +0 -242
- package/src/tui/components/tool-icons.ts +0 -24
- package/src/tui/index.tsx +0 -106
- package/src/tui/keybindings.ts +0 -49
- package/src/tui/model.ts +0 -295
- package/src/tui/state.ts +0 -77
- package/src/tui/theme.ts +0 -110
- package/src/types.ts +0 -113
- package/src/usage/README.md +0 -323
- package/src/usage/api.ts +0 -99
- package/src/usage/client.ts +0 -3
- package/src/usage/clients/anthropic-oauth-usage.ts +0 -258
- package/src/usage/clients/anthropic-web-usage.ts +0 -329
- package/src/usage/clients/claude-cli-probe.ts +0 -513
- package/src/usage/clients/codex-app-server.ts +0 -354
- package/src/usage/clients/codex-oauth-usage.ts +0 -240
- package/src/usage/clients/opencode-go-api.ts +0 -100
- package/src/usage/clients/opencode-go-usage.ts +0 -577
- package/src/usage/errors.ts +0 -33
- package/src/usage/index.ts +0 -20
- package/src/usage/local/opencode-go-local.ts +0 -194
- package/src/usage/mappers.ts +0 -282
- package/src/usage/planner.ts +0 -118
- package/src/usage/providers/claude.ts +0 -233
- package/src/usage/providers/codex.ts +0 -115
- package/src/usage/providers/opencode-go.ts +0 -115
- package/src/usage/resolver.ts +0 -4
- package/src/usage/resolvers/browser-cookies.ts +0 -808
- package/src/usage/resolvers/claude-auth.ts +0 -208
- package/src/usage/resolvers/claude-cli.ts +0 -24
- package/src/usage/resolvers/claude-desktop-auth.ts +0 -170
- package/src/usage/resolvers/claude-web.ts +0 -82
- package/src/usage/resolvers/codex-auth.ts +0 -174
- package/src/usage/resolvers/keychain-coordinator.ts +0 -397
- package/src/usage/resolvers/opencode-go-web.ts +0 -55
- package/src/usage/types.ts +0 -225
- package/src/usage/web-session-cache.ts +0 -37
- /package/{src/tui → dist/cli}/assets/providers/SOURCES.md +0 -0
- /package/{src/tui → dist/cli}/assets/providers/claude-terminal.png +0 -0
- /package/{src/tui → dist/cli}/assets/providers/claude-terminal.svg +0 -0
- /package/{src/tui → dist/cli}/assets/providers/claude.png +0 -0
- /package/{src/tui → dist/cli}/assets/providers/copilot.png +0 -0
- /package/{src/tui → dist/cli}/assets/providers/copilot.svg +0 -0
- /package/{src/tui → dist/cli}/assets/providers/openai-terminal.png +0 -0
- /package/{src/tui → dist/cli}/assets/providers/openai-terminal.svg +0 -0
- /package/{src/tui → dist/cli}/assets/providers/openai.png +0 -0
- /package/{src/tui → dist/cli}/assets/providers/opencode-terminal.png +0 -0
- /package/{src/tui → dist/cli}/assets/providers/opencode-terminal.svg +0 -0
- /package/{src/tui → dist/cli}/assets/providers/opencode.png +0 -0
- /package/{src/tui → dist/cli}/assets/providers/shell.png +0 -0
- /package/{src/tui → dist/cli}/assets/providers/shell.svg +0 -0
- /package/{src/tui → dist/cli}/assets/providers/unknown.png +0 -0
- /package/{src/tui → dist/cli}/assets/providers/unknown.svg +0 -0
|
@@ -1,329 +0,0 @@
|
|
|
1
|
-
import type { UsageClient } from "../client";
|
|
2
|
-
import type { ClaudeUsageSnapshot, NamedRateWindowLegacy, ProviderCostSnapshotLegacy, RateWindowLegacy, ClaudeWebSession } from "../types";
|
|
3
|
-
import { classifyUsageError, UsageError } from "../errors";
|
|
4
|
-
import { usageWebSessionCache } from "../web-session-cache";
|
|
5
|
-
import { CLAUDE_WEB_CACHE_KEY } from "../resolvers/claude-web";
|
|
6
|
-
|
|
7
|
-
export class InvalidCredentialsError extends UsageError {
|
|
8
|
-
constructor(message: string) {
|
|
9
|
-
super("invalid-credentials", message);
|
|
10
|
-
this.name = "InvalidCredentialsError";
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
interface Org {
|
|
15
|
-
uuid: string;
|
|
16
|
-
name?: string;
|
|
17
|
-
capabilities?: string[];
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
interface UsageResponse {
|
|
21
|
-
five_hour?: { utilization?: number | null; resets_at?: string | null } | null;
|
|
22
|
-
seven_day?: { utilization?: number | null; resets_at?: string | null } | null;
|
|
23
|
-
seven_day_sonnet?: { utilization?: number | null; resets_at?: string | null } | null;
|
|
24
|
-
seven_day_opus?: { utilization?: number | null; resets_at?: string | null } | null;
|
|
25
|
-
seven_day_design?: { utilization?: number | null; resets_at?: string | null } | null;
|
|
26
|
-
seven_day_routines?: { utilization?: number | null; resets_at?: string | null } | null;
|
|
27
|
-
[key: string]: unknown;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
interface OverageResponse {
|
|
31
|
-
monthly_credit_limit?: number;
|
|
32
|
-
currency?: string;
|
|
33
|
-
used_credits?: number;
|
|
34
|
-
is_enabled?: boolean;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
interface AccountResponse {
|
|
38
|
-
email_address?: string;
|
|
39
|
-
memberships?: Array<{
|
|
40
|
-
organization?: {
|
|
41
|
-
uuid: string;
|
|
42
|
-
name?: string;
|
|
43
|
-
rate_limit_tier?: string;
|
|
44
|
-
billing_type?: string;
|
|
45
|
-
};
|
|
46
|
-
}>;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const DESIGN_ALTERNATES = [
|
|
50
|
-
"seven_day_design",
|
|
51
|
-
"seven_day_claude_design",
|
|
52
|
-
"claude_design",
|
|
53
|
-
"design",
|
|
54
|
-
"seven_day_omelette",
|
|
55
|
-
"omelette",
|
|
56
|
-
"omelette_promotional",
|
|
57
|
-
];
|
|
58
|
-
|
|
59
|
-
const ROUTINES_ALTERNATES = [
|
|
60
|
-
"seven_day_routines",
|
|
61
|
-
"seven_day_claude_routines",
|
|
62
|
-
"claude_routines",
|
|
63
|
-
"routines",
|
|
64
|
-
"routine",
|
|
65
|
-
"seven_day_cowork",
|
|
66
|
-
"cowork",
|
|
67
|
-
];
|
|
68
|
-
|
|
69
|
-
const OAUTH_APPS_ALTERNATES = ["seven_day_oauth_apps", "oauth_apps"];
|
|
70
|
-
|
|
71
|
-
function pickWindowData(data: UsageResponse, keys: string[]): { utilization?: number | null; resets_at?: string | null } | null {
|
|
72
|
-
for (const key of keys) {
|
|
73
|
-
const val = data[key];
|
|
74
|
-
if (val && typeof val === "object") {
|
|
75
|
-
return val as { utilization?: number | null; resets_at?: string | null };
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
return null;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function toRateWindow(
|
|
82
|
-
utilization: number | null | undefined,
|
|
83
|
-
resetsAt: string | null | undefined,
|
|
84
|
-
windowMinutes: number,
|
|
85
|
-
): RateWindowLegacy {
|
|
86
|
-
const usedPercent = typeof utilization === "number" ? Math.max(0, Math.min(100, utilization)) : 0;
|
|
87
|
-
const resetsAtDate = resetsAt ? new Date(resetsAt) : null;
|
|
88
|
-
const resetDescription = resetsAtDate && !Number.isNaN(resetsAtDate.getTime())
|
|
89
|
-
? resetsAtDate.toLocaleString()
|
|
90
|
-
: null;
|
|
91
|
-
return {
|
|
92
|
-
usedPercent,
|
|
93
|
-
windowMinutes,
|
|
94
|
-
resetsAt: resetsAtDate && !Number.isNaN(resetsAtDate.getTime()) ? resetsAtDate : null,
|
|
95
|
-
resetDescription,
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
export class AnthropicWebUsageClient implements UsageClient<ClaudeWebSession, ClaudeUsageSnapshot> {
|
|
100
|
-
async fetch(creds: ClaudeWebSession, options?: { signal?: AbortSignal }): Promise<ClaudeUsageSnapshot> {
|
|
101
|
-
const candidates: string[] = [...new Set(creds.cookieCandidates ?? (creds.cookieHeader ? [creds.cookieHeader] : []))].slice(0, 2);
|
|
102
|
-
let expectedRevision = creds.cacheRevision ?? usageWebSessionCache.observe(CLAUDE_WEB_CACHE_KEY).revision;
|
|
103
|
-
|
|
104
|
-
for (let index = 0; index < candidates.length; index++) {
|
|
105
|
-
let rotated = false;
|
|
106
|
-
try {
|
|
107
|
-
const snapshot = await this.fetchWithCookie(candidates[index]!, options?.signal, (cookieHeader) => {
|
|
108
|
-
const stored = usageWebSessionCache.store(CLAUDE_WEB_CACHE_KEY, cookieHeader, expectedRevision);
|
|
109
|
-
if (stored) expectedRevision = stored.revision;
|
|
110
|
-
rotated = true;
|
|
111
|
-
});
|
|
112
|
-
if (!rotated) {
|
|
113
|
-
const stored = usageWebSessionCache.store(CLAUDE_WEB_CACHE_KEY, candidates[index]!, expectedRevision);
|
|
114
|
-
if (stored) expectedRevision = stored.revision;
|
|
115
|
-
}
|
|
116
|
-
return snapshot;
|
|
117
|
-
} catch (error) {
|
|
118
|
-
const failure = classifyUsageError(error);
|
|
119
|
-
if (failure.kind === "invalid-credentials") {
|
|
120
|
-
if (usageWebSessionCache.clear(CLAUDE_WEB_CACHE_KEY, expectedRevision)) expectedRevision = 0;
|
|
121
|
-
if (index + 1 < candidates.length) continue;
|
|
122
|
-
// Advance the demand-driven cursor at most once per attempt, keeping
|
|
123
|
-
// the two-candidate bound across imported and rotated candidates.
|
|
124
|
-
const imported = candidates.length < 2 ? (await creds.importNext?.()) ?? null : null;
|
|
125
|
-
if (imported && !candidates.includes(imported)) {
|
|
126
|
-
candidates.push(imported);
|
|
127
|
-
continue;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
throw failure;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
throw new InvalidCredentialsError("Session cookie invalid or expired");
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
private async fetchWithCookie(
|
|
137
|
-
initialCookieHeader: string,
|
|
138
|
-
signal: AbortSignal | undefined,
|
|
139
|
-
onCookieRotation: (cookieHeader: string) => void,
|
|
140
|
-
): Promise<ClaudeUsageSnapshot> {
|
|
141
|
-
let cookieHeader = initialCookieHeader;
|
|
142
|
-
const request = async (url: string): Promise<Response> => {
|
|
143
|
-
let response: Response;
|
|
144
|
-
try {
|
|
145
|
-
response = await fetch(url, {
|
|
146
|
-
signal,
|
|
147
|
-
headers: { Cookie: cookieHeader, Accept: "application/json" },
|
|
148
|
-
});
|
|
149
|
-
} catch (error) {
|
|
150
|
-
throw classifyUsageError(error);
|
|
151
|
-
}
|
|
152
|
-
const rotated = applyClaudeSessionRotation(cookieHeader, response.headers);
|
|
153
|
-
if (rotated !== cookieHeader) {
|
|
154
|
-
cookieHeader = rotated;
|
|
155
|
-
onCookieRotation(cookieHeader);
|
|
156
|
-
}
|
|
157
|
-
return response;
|
|
158
|
-
};
|
|
159
|
-
|
|
160
|
-
// 1. Fetch organizations
|
|
161
|
-
const orgRes = await request("https://claude.ai/api/organizations");
|
|
162
|
-
|
|
163
|
-
if (orgRes.status === 401) {
|
|
164
|
-
throw new InvalidCredentialsError("Session cookie invalid or expired");
|
|
165
|
-
}
|
|
166
|
-
if (orgRes.status === 403) throw new UsageError("forbidden", "Organizations access forbidden");
|
|
167
|
-
if (orgRes.status === 429) throw new UsageError("rate-limited", "Organizations fetch rate limited");
|
|
168
|
-
if (orgRes.status >= 500) throw new UsageError("transient", `Organizations fetch failed: ${orgRes.status}`);
|
|
169
|
-
if (!orgRes.ok) {
|
|
170
|
-
throw new UsageError("invalid-response", `Organizations fetch failed: ${orgRes.status}`);
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
const orgs = (await orgRes.json()) as Org[];
|
|
174
|
-
if (!Array.isArray(orgs) || orgs.length === 0) {
|
|
175
|
-
throw new UsageError("invalid-response", "No organizations found");
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// Select org
|
|
179
|
-
let org = orgs.find((o) => o.capabilities?.includes("chat"));
|
|
180
|
-
if (!org) {
|
|
181
|
-
org = orgs.find((o) => JSON.stringify(o.capabilities) !== '["api"]');
|
|
182
|
-
}
|
|
183
|
-
if (!org) {
|
|
184
|
-
org = orgs[0];
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// 2. Fetch usage
|
|
188
|
-
const usageRes = await request(`https://claude.ai/api/organizations/${org.uuid}/usage`);
|
|
189
|
-
|
|
190
|
-
if (usageRes.status === 401) {
|
|
191
|
-
throw new InvalidCredentialsError("Session cookie invalid or expired");
|
|
192
|
-
}
|
|
193
|
-
if (usageRes.status === 403) throw new UsageError("forbidden", "Usage access forbidden");
|
|
194
|
-
if (usageRes.status === 429) throw new UsageError("rate-limited", "Usage fetch rate limited");
|
|
195
|
-
if (usageRes.status >= 500) throw new UsageError("transient", `Usage fetch failed: ${usageRes.status}`);
|
|
196
|
-
if (!usageRes.ok) {
|
|
197
|
-
throw new UsageError("invalid-response", `Usage fetch failed: ${usageRes.status}`);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
const data = (await usageRes.json()) as UsageResponse;
|
|
201
|
-
|
|
202
|
-
// Null or missing windows mean "no usage recorded for the period" — a
|
|
203
|
-
// valid response, presented as an empty window at 0% (matches the
|
|
204
|
-
// reference implementation's "100% left" presentation).
|
|
205
|
-
const primaryWindow = pickWindowData(data, ["five_hour"]);
|
|
206
|
-
const secondaryWindow = pickWindowData(data, ["seven_day"]);
|
|
207
|
-
|
|
208
|
-
const primary = toRateWindow(
|
|
209
|
-
primaryWindow && typeof primaryWindow.utilization === "number" ? primaryWindow.utilization : 0,
|
|
210
|
-
primaryWindow?.resets_at ?? null,
|
|
211
|
-
300,
|
|
212
|
-
);
|
|
213
|
-
const secondary = secondaryWindow && typeof secondaryWindow.utilization === "number"
|
|
214
|
-
? toRateWindow(secondaryWindow.utilization, secondaryWindow.resets_at, 10080)
|
|
215
|
-
: null;
|
|
216
|
-
|
|
217
|
-
const opusWindow = pickWindowData(data, ["seven_day_sonnet", "seven_day_opus"]);
|
|
218
|
-
const opus = opusWindow && typeof opusWindow.utilization === "number"
|
|
219
|
-
? toRateWindow(opusWindow.utilization, opusWindow.resets_at, 10080)
|
|
220
|
-
: null;
|
|
221
|
-
|
|
222
|
-
const extraRateWindows: NamedRateWindowLegacy[] = [];
|
|
223
|
-
const designWindow = pickWindowData(data, DESIGN_ALTERNATES);
|
|
224
|
-
if (designWindow && typeof designWindow.utilization === "number") {
|
|
225
|
-
extraRateWindows.push({
|
|
226
|
-
id: "claude-design",
|
|
227
|
-
title: "Designs",
|
|
228
|
-
window: toRateWindow(designWindow.utilization, designWindow.resets_at, 10080),
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
const routinesWindow = pickWindowData(data, ROUTINES_ALTERNATES);
|
|
232
|
-
if (routinesWindow && typeof routinesWindow.utilization === "number") {
|
|
233
|
-
extraRateWindows.push({
|
|
234
|
-
id: "claude-routines",
|
|
235
|
-
title: "Daily Routines",
|
|
236
|
-
window: toRateWindow(routinesWindow.utilization, routinesWindow.resets_at, 10080),
|
|
237
|
-
});
|
|
238
|
-
}
|
|
239
|
-
const oauthAppsWindow = pickWindowData(data, OAUTH_APPS_ALTERNATES);
|
|
240
|
-
if (oauthAppsWindow && typeof oauthAppsWindow.utilization === "number") {
|
|
241
|
-
extraRateWindows.push({
|
|
242
|
-
id: "claude-oauth-apps",
|
|
243
|
-
title: "OAuth Apps",
|
|
244
|
-
window: toRateWindow(oauthAppsWindow.utilization, oauthAppsWindow.resets_at, 10080),
|
|
245
|
-
});
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
// 3. Best-effort overage
|
|
249
|
-
let providerCost: ProviderCostSnapshotLegacy | null = null;
|
|
250
|
-
try {
|
|
251
|
-
const overageRes = await request(`https://claude.ai/api/organizations/${org.uuid}/overage_spend_limit`);
|
|
252
|
-
if (overageRes.ok) {
|
|
253
|
-
const overage = (await overageRes.json()) as OverageResponse;
|
|
254
|
-
if (overage.is_enabled) {
|
|
255
|
-
providerCost = {
|
|
256
|
-
used: (overage.used_credits ?? 0) / 100,
|
|
257
|
-
limit: (overage.monthly_credit_limit ?? 0) / 100,
|
|
258
|
-
currencyCode: (overage.currency || "USD").trim() || "USD",
|
|
259
|
-
period: "Monthly",
|
|
260
|
-
resetsAt: null,
|
|
261
|
-
updatedAt: new Date(),
|
|
262
|
-
};
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
} catch (error) {
|
|
266
|
-
if (classifyUsageError(error).kind === "cancelled") throw error;
|
|
267
|
-
// Ignore best-effort failure
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
// 4. Best-effort account info
|
|
271
|
-
let accountEmail: string | null = null;
|
|
272
|
-
let accountOrganization: string | null = null;
|
|
273
|
-
let accountOrganizationId: string | null = null;
|
|
274
|
-
let loginMethod: string | null = null;
|
|
275
|
-
try {
|
|
276
|
-
const accountRes = await request("https://claude.ai/api/account");
|
|
277
|
-
if (accountRes.ok) {
|
|
278
|
-
const account = (await accountRes.json()) as AccountResponse;
|
|
279
|
-
if (account.email_address) {
|
|
280
|
-
accountEmail = account.email_address.trim();
|
|
281
|
-
}
|
|
282
|
-
const membership = account.memberships?.find((m) => m.organization?.uuid === org.uuid);
|
|
283
|
-
if (membership?.organization?.name) {
|
|
284
|
-
accountOrganization = membership.organization.name;
|
|
285
|
-
if (membership.organization.rate_limit_tier) {
|
|
286
|
-
loginMethod = membership.organization.rate_limit_tier;
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
accountOrganizationId = org.uuid;
|
|
290
|
-
}
|
|
291
|
-
} catch (error) {
|
|
292
|
-
if (classifyUsageError(error).kind === "cancelled") throw error;
|
|
293
|
-
// Ignore best-effort failure
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
return {
|
|
297
|
-
source: "web",
|
|
298
|
-
primary,
|
|
299
|
-
secondary,
|
|
300
|
-
opus,
|
|
301
|
-
extraRateWindows,
|
|
302
|
-
providerCost,
|
|
303
|
-
updatedAt: new Date(),
|
|
304
|
-
accountEmail,
|
|
305
|
-
accountOrganization,
|
|
306
|
-
accountOrganizationId,
|
|
307
|
-
loginMethod,
|
|
308
|
-
subscriptionType: null,
|
|
309
|
-
rateLimitTier: null,
|
|
310
|
-
};
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
function applyClaudeSessionRotation(current: string, headers: Headers): string {
|
|
315
|
-
const values = (headers as Headers & { getSetCookie?: () => string[] }).getSetCookie?.()
|
|
316
|
-
?? (headers.get("set-cookie") ? [headers.get("set-cookie")!] : []);
|
|
317
|
-
let sessionKey = current.split(";").map((part) => part.trim()).find((part) => part.startsWith("sessionKey="));
|
|
318
|
-
for (const value of values) {
|
|
319
|
-
const [pair, ...attributes] = value.split(";");
|
|
320
|
-
if (!pair?.trim().startsWith("sessionKey=")) continue;
|
|
321
|
-
const expired = attributes.some((attribute) => {
|
|
322
|
-
const [name, raw = ""] = attribute.trim().split("=", 2);
|
|
323
|
-
if (name?.toLowerCase() === "max-age") return Number(raw) <= 0;
|
|
324
|
-
return name?.toLowerCase() === "expires" && Date.parse(raw) <= Date.now();
|
|
325
|
-
});
|
|
326
|
-
sessionKey = expired || pair.trim() === "sessionKey=" ? undefined : pair.trim();
|
|
327
|
-
}
|
|
328
|
-
return sessionKey ?? "";
|
|
329
|
-
}
|