@scrylog/cli 0.2.0 → 0.3.1
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/README.md +46 -7
- 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/assets/providers/SOURCES.md +21 -0
- package/dist/cli/assets/providers/claude-terminal.png +0 -0
- package/dist/cli/assets/providers/claude-terminal.svg +62 -0
- package/dist/cli/assets/providers/claude.png +0 -0
- package/dist/cli/assets/providers/copilot.png +0 -0
- package/dist/cli/assets/providers/copilot.svg +44 -0
- package/dist/cli/assets/providers/openai-terminal.png +0 -0
- package/dist/cli/assets/providers/openai-terminal.svg +62 -0
- package/dist/cli/assets/providers/openai.png +0 -0
- package/dist/cli/assets/providers/opencode-terminal.png +0 -0
- package/dist/cli/assets/providers/opencode-terminal.svg +62 -0
- package/dist/cli/assets/providers/opencode.png +0 -0
- package/dist/cli/assets/providers/shell.png +0 -0
- package/dist/cli/assets/providers/shell.svg +23 -0
- package/dist/cli/assets/providers/unknown.png +0 -0
- package/dist/cli/assets/providers/unknown.svg +23 -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 +26 -20
- package/src/postinstall.cjs +11 -0
- package/src/api/docs/sessions.keys.ts +0 -6
- package/src/api/docs/sessions.ts +0 -81
- package/src/api/docs/system.keys.ts +0 -5
- package/src/api/docs/system.ts +0 -66
- 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 -47
- package/src/api/routes/system.ts +0 -103
- package/src/api/routes/usage.ts +0 -15
- package/src/api/routes/webhooks/claude.ts +0 -141
- package/src/api/routes/webhooks/codex.ts +0 -175
- package/src/api/routes/webhooks/opencode.ts +0 -111
- package/src/api/routes.ts +0 -93
- package/src/api/schemas/common.ts +0 -21
- package/src/api/schemas/sessions.ts +0 -72
- package/src/api/schemas/usage.ts +0 -50
- 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 -632
- 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 -148
- 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 -295
- 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 -282
- 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 -472
- package/src/daemon/collectors/tmux/enrichment.ts +0 -241
- 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 -193
- package/src/daemon/index.ts +0 -207
- package/src/daemon/scheduler.ts +0 -86
- package/src/daemon/store.ts +0 -588
- 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/neo-blessed.d.ts +0 -4
- package/src/oc/index.ts +0 -302
- package/src/service/manager.ts +0 -284
- package/src/shared/config.ts +0 -478
- 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-view.ts +0 -241
- package/src/shared/types.ts +0 -299
- package/src/shared/utils.ts +0 -339
- package/src/tui/app.ts +0 -920
- package/src/tui/client.ts +0 -149
- package/src/tui/index.ts +0 -217
- 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 -178
- package/src/usage/clients/anthropic-web-usage.ts +0 -245
- package/src/usage/clients/claude-cli-probe.ts +0 -187
- package/src/usage/clients/codex-oauth-usage.ts +0 -113
- package/src/usage/clients/opencode-go-usage.ts +0 -441
- package/src/usage/index.ts +0 -20
- package/src/usage/mappers.ts +0 -273
- package/src/usage/planner.ts +0 -54
- package/src/usage/providers/claude.ts +0 -113
- package/src/usage/providers/codex.ts +0 -34
- package/src/usage/providers/opencode-go.ts +0 -37
- package/src/usage/resolver.ts +0 -4
- package/src/usage/resolvers/browser-cookies.ts +0 -470
- package/src/usage/resolvers/claude-auth.ts +0 -108
- package/src/usage/resolvers/claude-cli.ts +0 -24
- package/src/usage/resolvers/claude-desktop-auth.ts +0 -160
- package/src/usage/resolvers/claude-web.ts +0 -16
- package/src/usage/resolvers/codex-auth.ts +0 -117
- package/src/usage/resolvers/opencode-go-web.ts +0 -14
- package/src/usage/types.ts +0 -190
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
-
import { homedir } from "node:os";
|
|
3
|
-
import { join } from "node:path";
|
|
4
|
-
import type { TokenResolver } from "../resolver";
|
|
5
|
-
import type { ClaudeOAuthCredentials } from "../types";
|
|
6
|
-
import { IS_MAC, IS_WINDOWS } from "../../shared/platform";
|
|
7
|
-
import { getChromiumSafeStorageKey, decryptSafeStorageBlob } from "./browser-cookies";
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Shape of a single entry in the `oauth:tokenCache` field of Claude Desktop's
|
|
11
|
-
* `config.json`. The key in the outer Record is a colon-separated composite:
|
|
12
|
-
* `<accountId>:<orgId>:<audience>:<space-separated scopes>`
|
|
13
|
-
*/
|
|
14
|
-
interface TokenCacheEntry {
|
|
15
|
-
token: string;
|
|
16
|
-
refreshToken?: string;
|
|
17
|
-
/** Milliseconds since Unix epoch */
|
|
18
|
-
expiresAt?: number;
|
|
19
|
-
subscriptionType?: string;
|
|
20
|
-
rateLimitTier?: string;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Reads the Claude Desktop app's local OAuth token cache and surfaces it as a
|
|
25
|
-
* `ClaudeOAuthCredentials` so the OAuth usage route works without Claude Code CLI.
|
|
26
|
-
*
|
|
27
|
-
* Data source:
|
|
28
|
-
* macOS: ~/Library/Application Support/Claude/config.json → oauth:tokenCache
|
|
29
|
-
* Windows: %APPDATA%/Anthropic/Claude/config.json → oauth:tokenCache
|
|
30
|
-
* Linux: Claude Desktop is unavailable; resolver always returns null.
|
|
31
|
-
*
|
|
32
|
-
* The `oauth:tokenCache` value is an Electron safeStorage blob (base64, v10/v11
|
|
33
|
-
* AES-128-CBC) decrypted with the Keychain key from "Claude Safe Storage".
|
|
34
|
-
*/
|
|
35
|
-
export class ClaudeDesktopAuthResolver implements TokenResolver<ClaudeOAuthCredentials> {
|
|
36
|
-
private readonly debug = (message: string, meta?: Record<string, unknown>) => {
|
|
37
|
-
if (process.env.SCRYLOG_DEBUG_AUTH) {
|
|
38
|
-
process.stderr.write(
|
|
39
|
-
`[scrylog:claude-desktop-auth] ${message}${meta ? ` ${JSON.stringify(meta)}` : ""}\n`
|
|
40
|
-
);
|
|
41
|
-
}
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
async resolve(): Promise<ClaudeOAuthCredentials | null> {
|
|
45
|
-
const configPath = this.getConfigPath();
|
|
46
|
-
if (!configPath) {
|
|
47
|
-
this.debug("Claude Desktop not supported on this platform", { platform: process.platform });
|
|
48
|
-
return null;
|
|
49
|
-
}
|
|
50
|
-
if (!existsSync(configPath)) {
|
|
51
|
-
this.debug("Claude Desktop config.json not found", { path: configPath });
|
|
52
|
-
return null;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
try {
|
|
56
|
-
const raw = readFileSync(configPath, "utf8");
|
|
57
|
-
const cfg = JSON.parse(raw) as Record<string, unknown>;
|
|
58
|
-
const blobB64 = cfg["oauth:tokenCache"];
|
|
59
|
-
if (typeof blobB64 !== "string" || !blobB64) {
|
|
60
|
-
this.debug("oauth:tokenCache missing or not a string in config.json");
|
|
61
|
-
return null;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const buf = Buffer.from(blobB64, "base64");
|
|
65
|
-
const key = getChromiumSafeStorageKey("Claude Safe Storage", "Claude");
|
|
66
|
-
if (!key) {
|
|
67
|
-
this.debug("Failed to retrieve Claude Safe Storage key from Keychain");
|
|
68
|
-
return null;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const plaintext = decryptSafeStorageBlob(buf, key);
|
|
72
|
-
if (!plaintext) {
|
|
73
|
-
this.debug("Failed to decrypt oauth:tokenCache blob");
|
|
74
|
-
return null;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const cache = JSON.parse(plaintext) as Record<string, TokenCacheEntry>;
|
|
78
|
-
const creds = this.selectBestEntry(cache);
|
|
79
|
-
if (creds) {
|
|
80
|
-
this.debug("Resolved Claude Desktop OAuth credentials");
|
|
81
|
-
} else {
|
|
82
|
-
this.debug("No usable entry found in oauth:tokenCache");
|
|
83
|
-
}
|
|
84
|
-
return creds;
|
|
85
|
-
} catch (err) {
|
|
86
|
-
this.debug("Error reading Claude Desktop config", {
|
|
87
|
-
error: err instanceof Error ? err.message : String(err),
|
|
88
|
-
});
|
|
89
|
-
return null;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
async isAvailable(): Promise<boolean> {
|
|
94
|
-
return (await this.resolve()) !== null;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
private getConfigPath(): string | null {
|
|
98
|
-
const home = homedir();
|
|
99
|
-
if (IS_MAC) {
|
|
100
|
-
return join(home, "Library", "Application Support", "Claude", "config.json");
|
|
101
|
-
}
|
|
102
|
-
if (IS_WINDOWS) {
|
|
103
|
-
const appData = process.env.APPDATA ?? join(home, "AppData", "Roaming");
|
|
104
|
-
return join(appData, "Anthropic", "Claude", "config.json");
|
|
105
|
-
}
|
|
106
|
-
// Linux: Claude Desktop is not available
|
|
107
|
-
return null;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Pick the best (longest-lived, has user:profile scope) non-expired token entry.
|
|
112
|
-
*
|
|
113
|
-
* The cache key format is:
|
|
114
|
-
* `<accountId>:<orgId>:<audience>:<space-separated scopes>`
|
|
115
|
-
* e.g.
|
|
116
|
-
* `uuid1:uuid2:https://api.anthropic.com:user:inference user:file_upload user:profile ...`
|
|
117
|
-
*
|
|
118
|
-
* AnthropicOAuthUsageClient requires the `user:profile` scope, so entries that
|
|
119
|
-
* lack it are skipped.
|
|
120
|
-
*/
|
|
121
|
-
private selectBestEntry(
|
|
122
|
-
cache: Record<string, TokenCacheEntry>
|
|
123
|
-
): ClaudeOAuthCredentials | null {
|
|
124
|
-
const now = Date.now();
|
|
125
|
-
let bestCreds: ClaudeOAuthCredentials | null = null;
|
|
126
|
-
let bestExpiresAt = -Infinity;
|
|
127
|
-
|
|
128
|
-
for (const [scopeKey, entry] of Object.entries(cache)) {
|
|
129
|
-
if (!entry.token) continue;
|
|
130
|
-
// Discard expired entries
|
|
131
|
-
if (entry.expiresAt !== undefined && entry.expiresAt <= now) continue;
|
|
132
|
-
// Require user:profile scope for the OAuth usage endpoint
|
|
133
|
-
if (!scopeKey.includes("user:profile")) continue;
|
|
134
|
-
|
|
135
|
-
const expiresAt = entry.expiresAt ?? Infinity;
|
|
136
|
-
if (expiresAt > bestExpiresAt) {
|
|
137
|
-
bestExpiresAt = expiresAt;
|
|
138
|
-
|
|
139
|
-
// Parse space-separated scopes from the composite key.
|
|
140
|
-
// Key format after the audience URL: "...:<audience>:<scopes>"
|
|
141
|
-
const audienceMatch = scopeKey.match(/:[^:]+:\/\/[^:]+:(.+)$/);
|
|
142
|
-
const scopes = audienceMatch ? audienceMatch[1].split(" ") : undefined;
|
|
143
|
-
|
|
144
|
-
bestCreds = {
|
|
145
|
-
accessToken: entry.token,
|
|
146
|
-
refreshToken: entry.refreshToken,
|
|
147
|
-
expiresAt:
|
|
148
|
-
entry.expiresAt !== undefined
|
|
149
|
-
? new Date(entry.expiresAt).toISOString()
|
|
150
|
-
: undefined,
|
|
151
|
-
scopes,
|
|
152
|
-
subscriptionType: entry.subscriptionType,
|
|
153
|
-
rateLimitTier: entry.rateLimitTier,
|
|
154
|
-
};
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
return bestCreds;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import type { TokenResolver } from "../resolver";
|
|
2
|
-
import type { ClaudeWebSession } from "../types";
|
|
3
|
-
import { extractCookies, buildCookieHeader } from "./browser-cookies";
|
|
4
|
-
|
|
5
|
-
export class ClaudeWebResolver implements TokenResolver<ClaudeWebSession> {
|
|
6
|
-
async resolve(): Promise<ClaudeWebSession | null> {
|
|
7
|
-
const cookies = extractCookies("claude.ai");
|
|
8
|
-
const sessionKey = cookies.find((c) => c.name === "sessionKey");
|
|
9
|
-
if (!sessionKey) return null;
|
|
10
|
-
return { cookieHeader: buildCookieHeader(cookies) };
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
async isAvailable(): Promise<boolean> {
|
|
14
|
-
return (await this.resolve()) !== null;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
-
import { homedir } from "node:os";
|
|
3
|
-
import { join } from "node:path";
|
|
4
|
-
import type { TokenResolver } from "../resolver";
|
|
5
|
-
import type { CodexOAuthCredentials } from "../types";
|
|
6
|
-
|
|
7
|
-
function getCodexDir(): string {
|
|
8
|
-
if (process.env.CODEX_HOME) return process.env.CODEX_HOME;
|
|
9
|
-
return join(homedir(), ".codex");
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
function readConfigToml(codexDir: string): string | undefined {
|
|
13
|
-
const path = join(codexDir, "config.toml");
|
|
14
|
-
if (!existsSync(path)) return undefined;
|
|
15
|
-
try {
|
|
16
|
-
const content = readFileSync(path, "utf8");
|
|
17
|
-
for (const line of content.split(/\r?\n/)) {
|
|
18
|
-
const match = line.match(/^chatgpt_base_url\s*=\s*"(.+)"\s*$/);
|
|
19
|
-
if (match) return match[1];
|
|
20
|
-
}
|
|
21
|
-
} catch {
|
|
22
|
-
// ignore
|
|
23
|
-
}
|
|
24
|
-
return undefined;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function decodeJwtClaims(token: string): { email?: string; sub?: string; org_id?: string } {
|
|
28
|
-
try {
|
|
29
|
-
const payload = token.split(".")[1];
|
|
30
|
-
if (!payload) return {};
|
|
31
|
-
const json = JSON.parse(Buffer.from(payload, "base64url").toString("utf8")) as Record<string, unknown>;
|
|
32
|
-
return {
|
|
33
|
-
email: typeof json["email"] === "string" ? json["email"] : undefined,
|
|
34
|
-
sub: typeof json["sub"] === "string" ? json["sub"] : undefined,
|
|
35
|
-
org_id: typeof json["org_id"] === "string" ? json["org_id"] : undefined,
|
|
36
|
-
};
|
|
37
|
-
} catch {
|
|
38
|
-
return {};
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Extract access_token and related fields from Codex auth.json.
|
|
44
|
-
* Codex CLI writes credentials in a nested "tokens" object, e.g.:
|
|
45
|
-
* { "tokens": { "access_token": "...", "refresh_token": "...", "account_id": "..." } }
|
|
46
|
-
* Some versions may write flat keys. This helper supports both formats.
|
|
47
|
-
*/
|
|
48
|
-
function extractTokens(raw: Record<string, unknown>): {
|
|
49
|
-
accessToken: string | undefined;
|
|
50
|
-
accountId: string | undefined;
|
|
51
|
-
refreshToken: string | undefined;
|
|
52
|
-
} {
|
|
53
|
-
const tokens =
|
|
54
|
-
typeof raw["tokens"] === "object" && raw["tokens"] !== null
|
|
55
|
-
? (raw["tokens"] as Record<string, unknown>)
|
|
56
|
-
: undefined;
|
|
57
|
-
|
|
58
|
-
const accessToken =
|
|
59
|
-
typeof raw["access_token"] === "string"
|
|
60
|
-
? raw["access_token"]
|
|
61
|
-
: typeof tokens?.["access_token"] === "string"
|
|
62
|
-
? tokens["access_token"]
|
|
63
|
-
: undefined;
|
|
64
|
-
|
|
65
|
-
const accountId =
|
|
66
|
-
typeof tokens?.["account_id"] === "string" ? tokens["account_id"] : undefined;
|
|
67
|
-
|
|
68
|
-
const refreshToken =
|
|
69
|
-
typeof raw["refresh_token"] === "string"
|
|
70
|
-
? raw["refresh_token"]
|
|
71
|
-
: typeof tokens?.["refresh_token"] === "string"
|
|
72
|
-
? tokens["refresh_token"]
|
|
73
|
-
: undefined;
|
|
74
|
-
|
|
75
|
-
return { accessToken, accountId, refreshToken };
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
export class CodexAuthResolver implements TokenResolver<CodexOAuthCredentials> {
|
|
79
|
-
async resolve(): Promise<CodexOAuthCredentials | null> {
|
|
80
|
-
const codexDir = getCodexDir();
|
|
81
|
-
const authPath = join(codexDir, "auth.json");
|
|
82
|
-
if (!existsSync(authPath)) return null;
|
|
83
|
-
|
|
84
|
-
try {
|
|
85
|
-
const raw = JSON.parse(readFileSync(authPath, "utf8")) as Record<string, unknown>;
|
|
86
|
-
const tokens = extractTokens(raw);
|
|
87
|
-
if (!tokens.accessToken) return null;
|
|
88
|
-
|
|
89
|
-
const claims = decodeJwtClaims(tokens.accessToken);
|
|
90
|
-
const chatgptBaseUrl = readConfigToml(codexDir);
|
|
91
|
-
|
|
92
|
-
return {
|
|
93
|
-
accessToken: tokens.accessToken,
|
|
94
|
-
refreshToken: tokens.refreshToken,
|
|
95
|
-
expiresAt: typeof raw["expires_at"] === "string" ? raw["expires_at"] : undefined,
|
|
96
|
-
accountEmail: claims.email ?? null,
|
|
97
|
-
accountId: tokens.accountId ?? claims.sub ?? claims.org_id ?? null,
|
|
98
|
-
...(chatgptBaseUrl ? { chatgptBaseUrl } : {}),
|
|
99
|
-
};
|
|
100
|
-
} catch {
|
|
101
|
-
return null;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
async isAvailable(): Promise<boolean> {
|
|
106
|
-
const codexDir = getCodexDir();
|
|
107
|
-
const authPath = join(codexDir, "auth.json");
|
|
108
|
-
if (!existsSync(authPath)) return false;
|
|
109
|
-
try {
|
|
110
|
-
const raw = JSON.parse(readFileSync(authPath, "utf8")) as Record<string, unknown>;
|
|
111
|
-
const { accessToken } = extractTokens(raw);
|
|
112
|
-
return typeof accessToken === "string" && accessToken.length > 0;
|
|
113
|
-
} catch {
|
|
114
|
-
return false;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type { TokenResolver } from "../resolver";
|
|
2
|
-
import { extractCookies, buildCookieHeader } from "./browser-cookies";
|
|
3
|
-
|
|
4
|
-
export class OpenCodeGoWebResolver implements TokenResolver<{ cookies: string }> {
|
|
5
|
-
async resolve(): Promise<{ cookies: string } | null> {
|
|
6
|
-
const cookies = extractCookies("opencode.ai");
|
|
7
|
-
if (cookies.length === 0) return null;
|
|
8
|
-
return { cookies: buildCookieHeader(cookies) };
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
async isAvailable(): Promise<boolean> {
|
|
12
|
-
return (await this.resolve()) !== null;
|
|
13
|
-
}
|
|
14
|
-
}
|
package/src/usage/types.ts
DELETED
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
// Standardized unified types for usage limits — all providers share the same structure
|
|
2
|
-
|
|
3
|
-
export interface UsageWindow {
|
|
4
|
-
/** Machine-readable identifier, e.g. "session", "weekly", "monthly", "designs" */
|
|
5
|
-
id: string;
|
|
6
|
-
/** Human-readable label, e.g. "Current Session", "Weekly", "Monthly" */
|
|
7
|
-
title: string;
|
|
8
|
-
/** Percentage used (0-100) */
|
|
9
|
-
usedPercent: number;
|
|
10
|
-
/** Absolute usage count (requests, tokens, credits) — optional */
|
|
11
|
-
used?: number;
|
|
12
|
-
/** Absolute limit — optional */
|
|
13
|
-
limit?: number;
|
|
14
|
-
/** Window duration in minutes — optional */
|
|
15
|
-
windowMinutes?: number;
|
|
16
|
-
/** Reset timestamp (ISO 8601) — preferred */
|
|
17
|
-
resetsAt?: string | null;
|
|
18
|
-
/** Seconds until reset — computed if not provided by provider */
|
|
19
|
-
resetInSec?: number;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export interface ProviderCostSnapshot {
|
|
23
|
-
/** Amount used */
|
|
24
|
-
used: number;
|
|
25
|
-
/** Limit amount */
|
|
26
|
-
limit: number;
|
|
27
|
-
/** Currency code, e.g. "USD" */
|
|
28
|
-
currency: string;
|
|
29
|
-
/** Billing period label, e.g. "Monthly" */
|
|
30
|
-
period: string;
|
|
31
|
-
/** Reset timestamp (ISO 8601) */
|
|
32
|
-
resetsAt?: string | null;
|
|
33
|
-
/** Last update timestamp (ISO 8601) */
|
|
34
|
-
updatedAt: string;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export interface UsageProviderEntry {
|
|
38
|
-
/** Provider identifier, e.g. "claude", "opencode-go" */
|
|
39
|
-
provider: string;
|
|
40
|
-
|
|
41
|
-
/** Account identifier — stable across hosts for grouping. null only when provider is unavailable or identity could not be determined. */
|
|
42
|
-
accountId: string | null;
|
|
43
|
-
|
|
44
|
-
/** Whether this provider is available on this machine (credentials detected) */
|
|
45
|
-
available: boolean;
|
|
46
|
-
|
|
47
|
-
/** Status of this provider */
|
|
48
|
-
status: "ok" | "error" | "unavailable" | "pending";
|
|
49
|
-
|
|
50
|
-
/** Metadata about the data source and account */
|
|
51
|
-
metadata?: {
|
|
52
|
-
/** How the data was obtained, e.g. "oauth", "web", "cli" */
|
|
53
|
-
dataSource?: string;
|
|
54
|
-
/** Account email if known */
|
|
55
|
-
accountEmail?: string | null;
|
|
56
|
-
/** Organization/account name if known */
|
|
57
|
-
accountOrganization?: string | null;
|
|
58
|
-
/** Subscription type, e.g. "pro", "free" */
|
|
59
|
-
subscriptionType?: string | null;
|
|
60
|
-
/** Rate limit tier */
|
|
61
|
-
rateLimitTier?: string | null;
|
|
62
|
-
/** Workspace ID (OpenCode Go) */
|
|
63
|
-
workspaceId?: string | null;
|
|
64
|
-
/** Workspace name (OpenCode Go) */
|
|
65
|
-
workspaceName?: string | null;
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
/** Errors specific to this provider (only present when status === "error") */
|
|
69
|
-
errors?: string[];
|
|
70
|
-
|
|
71
|
-
/** Usage windows — standardized for all providers */
|
|
72
|
-
windows?: UsageWindow[];
|
|
73
|
-
|
|
74
|
-
/** Cost/overage snapshot if available */
|
|
75
|
-
cost?: ProviderCostSnapshot | null;
|
|
76
|
-
|
|
77
|
-
/** Last update timestamp (ISO 8601) */
|
|
78
|
-
updatedAt?: string;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export interface UsageState {
|
|
82
|
-
/** All configured providers, including unavailable ones */
|
|
83
|
-
providers: UsageProviderEntry[];
|
|
84
|
-
/** Global refresh timestamp */
|
|
85
|
-
lastRefreshedAt: number;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// Legacy provider-specific snapshots (internal use only, mapped to UsageProviderEntry)
|
|
89
|
-
|
|
90
|
-
export interface ClaudeUsageSnapshot {
|
|
91
|
-
source: "oauth" | "web" | "cli";
|
|
92
|
-
primary: RateWindowLegacy;
|
|
93
|
-
secondary: RateWindowLegacy | null;
|
|
94
|
-
opus: RateWindowLegacy | null;
|
|
95
|
-
extraRateWindows: NamedRateWindowLegacy[];
|
|
96
|
-
providerCost: ProviderCostSnapshotLegacy | null;
|
|
97
|
-
updatedAt: Date;
|
|
98
|
-
accountEmail: string | null;
|
|
99
|
-
accountOrganization: string | null;
|
|
100
|
-
loginMethod: string | null;
|
|
101
|
-
subscriptionType: string | null;
|
|
102
|
-
rateLimitTier: string | null;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
export interface OpenCodeGoUsageSnapshot {
|
|
106
|
-
source: "web";
|
|
107
|
-
hasMonthlyUsage: boolean;
|
|
108
|
-
rollingUsagePercent: number;
|
|
109
|
-
weeklyUsagePercent: number;
|
|
110
|
-
monthlyUsagePercent: number;
|
|
111
|
-
rollingResetInSec: number;
|
|
112
|
-
weeklyResetInSec: number;
|
|
113
|
-
monthlyResetInSec: number;
|
|
114
|
-
updatedAt: Date;
|
|
115
|
-
workspaceId: string | null;
|
|
116
|
-
workspaceName: string | null;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// Legacy internal types (used by providers before mapping to unified model)
|
|
120
|
-
|
|
121
|
-
export interface RateWindowLegacy {
|
|
122
|
-
usedPercent: number;
|
|
123
|
-
windowMinutes: number;
|
|
124
|
-
resetsAt: Date | null;
|
|
125
|
-
resetDescription: string | null;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
export interface NamedRateWindowLegacy {
|
|
129
|
-
id: string;
|
|
130
|
-
title: string;
|
|
131
|
-
window: RateWindowLegacy;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
export interface ProviderCostSnapshotLegacy {
|
|
135
|
-
used: number;
|
|
136
|
-
limit: number;
|
|
137
|
-
currencyCode: string;
|
|
138
|
-
period: string;
|
|
139
|
-
resetsAt: Date | null;
|
|
140
|
-
updatedAt: Date;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// Credential types
|
|
144
|
-
|
|
145
|
-
export interface ClaudeOAuthCredentials {
|
|
146
|
-
accessToken: string;
|
|
147
|
-
refreshToken?: string;
|
|
148
|
-
expiresAt?: string;
|
|
149
|
-
scopes?: string[];
|
|
150
|
-
rateLimitTier?: string;
|
|
151
|
-
subscriptionType?: string;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
export interface CodexOAuthCredentials {
|
|
155
|
-
accessToken: string;
|
|
156
|
-
refreshToken?: string;
|
|
157
|
-
expiresAt?: string;
|
|
158
|
-
accountEmail?: string | null;
|
|
159
|
-
accountId?: string | null;
|
|
160
|
-
chatgptBaseUrl?: string;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
export interface ClaudeWebSession {
|
|
164
|
-
cookieHeader: string;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
export type ClaudeDataSource = "oauth" | "web" | "cli" | "auto";
|
|
168
|
-
|
|
169
|
-
export interface ClaudePlannerDecision {
|
|
170
|
-
primary: ClaudeDataSource;
|
|
171
|
-
fallback: ClaudeDataSource[];
|
|
172
|
-
webExtras: boolean;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
export type CodexDataSource = "oauth" | "auto";
|
|
176
|
-
|
|
177
|
-
export interface CodexUsageSnapshot {
|
|
178
|
-
source: "oauth";
|
|
179
|
-
planType: string | null;
|
|
180
|
-
primaryWindow: RateWindowLegacy | null;
|
|
181
|
-
secondaryWindow: RateWindowLegacy | null;
|
|
182
|
-
credits: {
|
|
183
|
-
hasCredits: boolean;
|
|
184
|
-
unlimited: boolean;
|
|
185
|
-
balance: number | null;
|
|
186
|
-
} | null;
|
|
187
|
-
updatedAt: Date;
|
|
188
|
-
accountEmail: string | null;
|
|
189
|
-
accountId: string | null;
|
|
190
|
-
}
|