@vacbo/opencode-anthropic-fix 0.1.7 → 0.1.9
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 +88 -88
- package/dist/opencode-anthropic-auth-cli.mjs +804 -507
- package/dist/opencode-anthropic-auth-plugin.js +4751 -4109
- package/package.json +67 -59
- package/src/__tests__/billing-edge-cases.test.ts +59 -59
- package/src/__tests__/bun-proxy.parallel.test.ts +388 -382
- package/src/__tests__/cc-comparison.test.ts +87 -87
- package/src/__tests__/cc-credentials.test.ts +254 -250
- package/src/__tests__/cch-drift-checker.test.ts +51 -51
- package/src/__tests__/cch-native-style.test.ts +56 -56
- package/src/__tests__/debug-gating.test.ts +42 -42
- package/src/__tests__/decomposition-smoke.test.ts +68 -68
- package/src/__tests__/fingerprint-regression.test.ts +575 -566
- package/src/__tests__/helpers/conversation-history.smoke.test.ts +271 -271
- package/src/__tests__/helpers/conversation-history.ts +119 -119
- package/src/__tests__/helpers/deferred.smoke.test.ts +103 -103
- package/src/__tests__/helpers/deferred.ts +69 -69
- package/src/__tests__/helpers/in-memory-storage.smoke.test.ts +155 -155
- package/src/__tests__/helpers/in-memory-storage.ts +88 -88
- package/src/__tests__/helpers/mock-bun-proxy.smoke.test.ts +68 -68
- package/src/__tests__/helpers/mock-bun-proxy.ts +189 -189
- package/src/__tests__/helpers/plugin-fetch-harness.smoke.test.ts +273 -273
- package/src/__tests__/helpers/plugin-fetch-harness.ts +288 -288
- package/src/__tests__/helpers/sse.smoke.test.ts +236 -236
- package/src/__tests__/helpers/sse.ts +209 -209
- package/src/__tests__/index.parallel.test.ts +605 -595
- package/src/__tests__/sanitization-regex.test.ts +112 -112
- package/src/__tests__/state-bounds.test.ts +90 -90
- package/src/account-identity.test.ts +197 -192
- package/src/account-identity.ts +69 -67
- package/src/account-state.test.ts +86 -86
- package/src/account-state.ts +25 -25
- package/src/accounts/matching.test.ts +335 -0
- package/src/accounts/matching.ts +167 -0
- package/src/accounts/persistence.test.ts +345 -0
- package/src/accounts/persistence.ts +432 -0
- package/src/accounts/repair.test.ts +276 -0
- package/src/accounts/repair.ts +407 -0
- package/src/accounts.dedup.test.ts +621 -621
- package/src/accounts.test.ts +933 -929
- package/src/accounts.ts +633 -989
- package/src/backoff.test.ts +345 -345
- package/src/backoff.ts +219 -219
- package/src/betas.ts +124 -124
- package/src/bun-fetch.test.ts +345 -342
- package/src/bun-fetch.ts +424 -424
- package/src/bun-proxy.test.ts +25 -25
- package/src/bun-proxy.ts +209 -209
- package/src/cc-credentials.ts +111 -111
- package/src/circuit-breaker.test.ts +184 -184
- package/src/circuit-breaker.ts +169 -169
- package/src/cli/commands/auth.ts +963 -0
- package/src/cli/commands/config.ts +547 -0
- package/src/cli/formatting.test.ts +406 -0
- package/src/cli/formatting.ts +219 -0
- package/src/cli.ts +255 -2022
- package/src/commands/handlers/betas.ts +100 -0
- package/src/commands/handlers/config.ts +99 -0
- package/src/commands/handlers/files.ts +375 -0
- package/src/commands/oauth-flow.ts +181 -166
- package/src/commands/prompts.ts +61 -61
- package/src/commands/router.test.ts +421 -0
- package/src/commands/router.ts +143 -635
- package/src/config.test.ts +482 -482
- package/src/config.ts +412 -404
- package/src/constants.ts +48 -48
- package/src/drift/cch-constants.ts +95 -95
- package/src/env.ts +111 -105
- package/src/headers/billing.ts +33 -33
- package/src/headers/builder.ts +130 -130
- package/src/headers/cch.ts +75 -75
- package/src/headers/stainless.ts +25 -25
- package/src/headers/user-agent.ts +23 -23
- package/src/index.ts +436 -828
- package/src/models.ts +27 -27
- package/src/oauth.test.ts +102 -102
- package/src/oauth.ts +178 -178
- package/src/parent-pid-watcher.test.ts +148 -148
- package/src/parent-pid-watcher.ts +69 -69
- package/src/plugin-helpers.ts +82 -82
- package/src/refresh-helpers.ts +145 -139
- package/src/refresh-lock.test.ts +94 -94
- package/src/refresh-lock.ts +93 -93
- package/src/request/body.history.test.ts +579 -571
- package/src/request/body.ts +255 -255
- package/src/request/metadata.ts +65 -65
- package/src/request/retry.test.ts +156 -156
- package/src/request/retry.ts +67 -67
- package/src/request/url.ts +21 -21
- package/src/request-orchestration-helpers.ts +648 -0
- package/src/response/index.ts +5 -5
- package/src/response/mcp.ts +58 -58
- package/src/response/streaming.test.ts +313 -311
- package/src/response/streaming.ts +412 -410
- package/src/rotation.test.ts +304 -301
- package/src/rotation.ts +205 -205
- package/src/storage.test.ts +547 -547
- package/src/storage.ts +315 -291
- package/src/system-prompt/builder.ts +38 -38
- package/src/system-prompt/index.ts +5 -5
- package/src/system-prompt/normalize.ts +60 -60
- package/src/system-prompt/sanitize.ts +30 -30
- package/src/thinking.ts +21 -20
- package/src/token-refresh.test.ts +265 -265
- package/src/token-refresh.ts +219 -214
- package/src/types.ts +30 -30
- package/dist/bun-proxy.mjs +0 -291
package/src/cc-credentials.ts
CHANGED
|
@@ -4,164 +4,164 @@ import { homedir } from "node:os";
|
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
|
|
6
6
|
export interface CCCredential {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
accessToken: string;
|
|
8
|
+
refreshToken: string;
|
|
9
|
+
expiresAt: number;
|
|
10
|
+
subscriptionType?: string;
|
|
11
|
+
source: "cc-keychain" | "cc-file";
|
|
12
|
+
label: string;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
type CCCredentialSource = CCCredential["source"];
|
|
16
16
|
|
|
17
17
|
interface CredentialParseMeta {
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
source: CCCredentialSource;
|
|
19
|
+
label: string;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
interface SecurityCommandError {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
status?: number | null;
|
|
24
|
+
code?: string;
|
|
25
|
+
signal?: string | null;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
const SECURITY_TIMEOUT_MS = 5000;
|
|
29
29
|
const SECURITY_HANDLED_EXIT_CODES = new Set([36, 44, 128]);
|
|
30
30
|
const CLAUDE_CODE_SERVICE_PATTERN = /"svce"<blob>="(Claude Code-credentials[^"]*)"/g;
|
|
31
31
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
32
|
-
|
|
32
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
function isValidCredentialShape(value: unknown): value is {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
accessToken: string;
|
|
37
|
+
refreshToken: string;
|
|
38
|
+
expiresAt: number;
|
|
39
|
+
subscriptionType?: string;
|
|
40
40
|
} {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
41
|
+
if (!isRecord(value)) return false;
|
|
42
|
+
if (typeof value.accessToken !== "string" || value.accessToken.length === 0) return false;
|
|
43
|
+
if (typeof value.refreshToken !== "string" || value.refreshToken.length === 0) return false;
|
|
44
|
+
if (typeof value.expiresAt !== "number" || !Number.isFinite(value.expiresAt)) return false;
|
|
45
|
+
if (value.subscriptionType !== undefined && typeof value.subscriptionType !== "string") return false;
|
|
46
|
+
return true;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
function parseCCCredentialWithMeta(raw: string, meta: CredentialParseMeta): CCCredential | null {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
50
|
+
try {
|
|
51
|
+
const parsed: unknown = JSON.parse(raw);
|
|
52
|
+
if (!isRecord(parsed)) return null;
|
|
53
|
+
|
|
54
|
+
const wrapped = parsed.claudeAiOauth;
|
|
55
|
+
const candidate = isValidCredentialShape(wrapped)
|
|
56
|
+
? wrapped
|
|
57
|
+
: isValidCredentialShape(parsed)
|
|
58
|
+
? parsed
|
|
59
|
+
: parsed.mcpOAuth !== undefined && parsed.accessToken === undefined
|
|
60
|
+
? null
|
|
61
|
+
: null;
|
|
62
|
+
|
|
63
|
+
if (!candidate) return null;
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
accessToken: candidate.accessToken,
|
|
67
|
+
refreshToken: candidate.refreshToken,
|
|
68
|
+
expiresAt: candidate.expiresAt,
|
|
69
|
+
subscriptionType: candidate.subscriptionType,
|
|
70
|
+
source: meta.source,
|
|
71
|
+
label: meta.label,
|
|
72
|
+
};
|
|
73
|
+
} catch {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
function extractClaudeCodeServices(raw: string): string[] {
|
|
79
|
-
|
|
79
|
+
const services = new Set<string>();
|
|
80
80
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
81
|
+
for (const match of raw.matchAll(CLAUDE_CODE_SERVICE_PATTERN)) {
|
|
82
|
+
const service = match[1]?.trim();
|
|
83
|
+
if (service) services.add(service);
|
|
84
|
+
}
|
|
85
85
|
|
|
86
|
-
|
|
86
|
+
return Array.from(services);
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
function shellQuote(value: string): string {
|
|
90
|
-
|
|
90
|
+
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
function runSecurityCommand(command: string): string | null {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
94
|
+
try {
|
|
95
|
+
return execSync(command, {
|
|
96
|
+
encoding: "utf-8",
|
|
97
|
+
timeout: SECURITY_TIMEOUT_MS,
|
|
98
|
+
});
|
|
99
|
+
} catch (error) {
|
|
100
|
+
const securityError = error as SecurityCommandError;
|
|
101
|
+
if (typeof securityError.status === "number" && SECURITY_HANDLED_EXIT_CODES.has(securityError.status)) {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
if (securityError.code === "ETIMEDOUT" || securityError.signal === "SIGTERM") {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
return null;
|
|
106
108
|
}
|
|
107
|
-
return null;
|
|
108
|
-
}
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
export function parseCCCredentialData(raw: string): CCCredential | null {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
112
|
+
return parseCCCredentialWithMeta(raw, {
|
|
113
|
+
source: "cc-file",
|
|
114
|
+
label: join(homedir(), ".claude", ".credentials.json"),
|
|
115
|
+
});
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
export function readCCCredentialsFromKeychain(): CCCredential[] | null {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
119
|
+
if (process.platform !== "darwin") return null;
|
|
120
|
+
|
|
121
|
+
const dumpOutput = runSecurityCommand("security dump-keychain");
|
|
122
|
+
if (!dumpOutput) return null;
|
|
123
|
+
|
|
124
|
+
const services = extractClaudeCodeServices(dumpOutput);
|
|
125
|
+
if (services.length === 0) return null;
|
|
126
|
+
|
|
127
|
+
const credentials: CCCredential[] = [];
|
|
128
|
+
for (const service of services) {
|
|
129
|
+
const rawCredential = runSecurityCommand(`security find-generic-password -s ${shellQuote(service)} -w`);
|
|
130
|
+
if (!rawCredential) return null;
|
|
131
|
+
const credential = parseCCCredentialWithMeta(rawCredential, {
|
|
132
|
+
source: "cc-keychain",
|
|
133
|
+
label: service,
|
|
134
|
+
});
|
|
135
|
+
if (credential) credentials.push(credential);
|
|
136
|
+
}
|
|
137
137
|
|
|
138
|
-
|
|
138
|
+
return credentials.length > 0 ? credentials : null;
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
export function readCCCredentialsFromFile(): CCCredential | null {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
142
|
+
const credentialsPath = join(homedir(), ".claude", ".credentials.json");
|
|
143
|
+
|
|
144
|
+
try {
|
|
145
|
+
const raw = readFileSync(credentialsPath, "utf-8");
|
|
146
|
+
return parseCCCredentialWithMeta(raw, {
|
|
147
|
+
source: "cc-file",
|
|
148
|
+
label: credentialsPath,
|
|
149
|
+
});
|
|
150
|
+
} catch {
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
153
|
}
|
|
154
154
|
|
|
155
155
|
export function readCCCredentials(): CCCredential[] {
|
|
156
|
-
|
|
156
|
+
const credentials: CCCredential[] = [];
|
|
157
157
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
158
|
+
if (process.platform === "darwin") {
|
|
159
|
+
const keychainCredentials = readCCCredentialsFromKeychain();
|
|
160
|
+
if (keychainCredentials) credentials.push(...keychainCredentials);
|
|
161
|
+
}
|
|
162
162
|
|
|
163
|
-
|
|
164
|
-
|
|
163
|
+
const fileCredential = readCCCredentialsFromFile();
|
|
164
|
+
if (fileCredential) credentials.push(fileCredential);
|
|
165
165
|
|
|
166
|
-
|
|
166
|
+
return credentials;
|
|
167
167
|
}
|