codex-copilot-dx 0.6.21 → 0.7.0
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 +123 -326
- package/bin/cli.mjs +13 -129
- package/package.json +2 -8
- package/scripts/benchmark.mjs +0 -114
- package/src/adapter.mjs +19 -106
- package/src/auth-profile.mjs +18 -130
- package/src/cli-auth.mjs +44 -398
- package/src/cli-models.mjs +21 -49
- package/src/cli-options.mjs +45 -75
- package/src/cli-status.mjs +6 -23
- package/src/config.mjs +2 -8
- package/src/copilot.mjs +2 -2
- package/src/doctor.mjs +44 -291
- package/src/model-cache.mjs +4 -11
- package/src/models.mjs +0 -184
- package/src/observability.mjs +1 -38
- package/src/profile-model-runtime.mjs +61 -189
- package/src/profile-routing.mjs +2 -102
- package/src/profile-runtime.mjs +15 -68
- package/src/responses-handler.mjs +1 -1
- package/src/responses-proxy.mjs +1 -1
- package/src/running-adapter.mjs +2 -4
- package/src/stream-errors.mjs +3 -6
- package/src/stream-performance.mjs +1 -1
- package/src/usage.mjs +0 -31
- package/src/anthropic-handler.mjs +0 -195
- package/src/anthropic.mjs +0 -387
- package/src/claude-config.mjs +0 -57
- package/src/claude-desktop-config.mjs +0 -317
- package/src/cli-error.mjs +0 -50
- package/src/pm-studio-asar.mjs +0 -1244
- package/src/pm-studio-bundle-content.mjs +0 -165
- package/src/pm-studio-relay.mjs +0 -563
- package/src/pm-studio-setup-lock.mjs +0 -336
- package/src/pm-studio-setup.mjs +0 -1581
- package/src/pm-studio-status.mjs +0 -369
- package/src/token-counter-service.mjs +0 -211
- package/src/token-counter-worker.mjs +0 -16
package/src/auth-profile.mjs
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import os from "node:os";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import { atomicWriteFilePairSync, atomicWriteFileSync } from "./atomic-file.mjs";
|
|
5
3
|
import {
|
|
6
4
|
githubTokenLockPath,
|
|
7
5
|
githubTokenMetadataPath,
|
|
@@ -11,172 +9,62 @@ import {
|
|
|
11
9
|
githubTokenFingerprint,
|
|
12
10
|
normalizeGithubIdentity,
|
|
13
11
|
} from "./github-identity.mjs";
|
|
14
|
-
import { withFileLock } from "./lock.mjs";
|
|
15
|
-
import { parseSafePositiveInteger, RUNTIME_DEFAULTS } from "./runtime-config.mjs";
|
|
16
12
|
|
|
17
13
|
export const AUTH_PROFILE_CODEX = "codex";
|
|
18
|
-
export const AUTH_PROFILE_CLAUDE = "claude";
|
|
19
|
-
|
|
20
|
-
const AUTH_PROFILES = new Set([AUTH_PROFILE_CODEX, AUTH_PROFILE_CLAUDE]);
|
|
21
14
|
|
|
22
15
|
function checkedProfile(profile) {
|
|
23
16
|
const value = String(profile || "").trim().toLowerCase();
|
|
24
|
-
if (
|
|
17
|
+
if (value !== AUTH_PROFILE_CODEX) {
|
|
18
|
+
throw new Error(`Unsupported authentication profile: ${profile}`);
|
|
19
|
+
}
|
|
25
20
|
return value;
|
|
26
21
|
}
|
|
27
22
|
|
|
28
23
|
export function authProfilePaths(profile, { home = os.homedir() } = {}) {
|
|
29
24
|
const name = checkedProfile(profile);
|
|
30
|
-
if (name === AUTH_PROFILE_CODEX) {
|
|
31
|
-
return {
|
|
32
|
-
profile: name,
|
|
33
|
-
tokenPath: githubTokenPath(home),
|
|
34
|
-
metadataPath: githubTokenMetadataPath(home),
|
|
35
|
-
lockPath: githubTokenLockPath(home),
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const directory = path.join(home, ".local", "share", "copilot-api", "profiles", AUTH_PROFILE_CLAUDE);
|
|
40
|
-
const tokenPath = path.join(directory, "github_token");
|
|
41
25
|
return {
|
|
42
26
|
profile: name,
|
|
43
|
-
tokenPath,
|
|
44
|
-
metadataPath:
|
|
45
|
-
lockPath:
|
|
27
|
+
tokenPath: githubTokenPath(home),
|
|
28
|
+
metadataPath: githubTokenMetadataPath(home),
|
|
29
|
+
lockPath: githubTokenLockPath(home),
|
|
46
30
|
};
|
|
47
31
|
}
|
|
48
32
|
|
|
49
33
|
function readOptionalFile(filePath) {
|
|
50
34
|
try {
|
|
51
|
-
return { exists: true, data: fs.readFileSync(filePath)
|
|
35
|
+
return { exists: true, data: fs.readFileSync(filePath) };
|
|
52
36
|
} catch (error) {
|
|
53
|
-
if (error?.code === "ENOENT") return { exists: false, data: null
|
|
37
|
+
if (error?.code === "ENOENT") return { exists: false, data: null };
|
|
54
38
|
throw error;
|
|
55
39
|
}
|
|
56
40
|
}
|
|
57
41
|
|
|
58
42
|
function parsedMetadata(snapshot) {
|
|
59
|
-
if (!snapshot.exists) return
|
|
43
|
+
if (!snapshot.exists) return null;
|
|
60
44
|
try {
|
|
61
|
-
return
|
|
45
|
+
return JSON.parse(snapshot.data.toString("utf8"));
|
|
62
46
|
} catch {
|
|
63
|
-
return
|
|
47
|
+
return null;
|
|
64
48
|
}
|
|
65
49
|
}
|
|
66
50
|
|
|
67
51
|
export function readAuthProfileCredentials(profile, { home = os.homedir() } = {}) {
|
|
68
52
|
const paths = authProfilePaths(profile, { home });
|
|
69
53
|
const tokenSnapshot = readOptionalFile(paths.tokenPath);
|
|
70
|
-
const metadataSnapshot = readOptionalFile(paths.metadataPath);
|
|
71
54
|
const token = tokenSnapshot.exists ? tokenSnapshot.data.toString("utf8").trim() : "";
|
|
72
|
-
const
|
|
73
|
-
const metadataFingerprint = metadataResult.value?.token_fingerprint;
|
|
55
|
+
const metadata = parsedMetadata(readOptionalFile(paths.metadataPath));
|
|
74
56
|
const metadataMatchesToken = Boolean(token)
|
|
75
|
-
&& Boolean(
|
|
76
|
-
&&
|
|
77
|
-
const metadataIdentity = normalizeGithubIdentity(metadataResult.value);
|
|
78
|
-
const identity = metadataMatchesToken ? metadataIdentity : null;
|
|
79
|
-
|
|
80
|
-
if (paths.profile === AUTH_PROFILE_CODEX) {
|
|
81
|
-
const configured = tokenSnapshot.exists;
|
|
82
|
-
return {
|
|
83
|
-
profile: paths.profile,
|
|
84
|
-
configured,
|
|
85
|
-
valid: configured && Boolean(token),
|
|
86
|
-
reason: !configured ? "unconfigured" : token ? "" : "empty_token",
|
|
87
|
-
token,
|
|
88
|
-
identity,
|
|
89
|
-
metadata: metadataResult.value,
|
|
90
|
-
paths,
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// Metadata is written last, but any credential artifact reserves the Claude
|
|
95
|
-
// profile. A partial write must fail closed instead of borrowing Codex.
|
|
96
|
-
const configured = metadataSnapshot.exists || tokenSnapshot.exists;
|
|
97
|
-
let reason = "";
|
|
98
|
-
if (!configured) reason = "unconfigured";
|
|
99
|
-
else if (!metadataSnapshot.exists) reason = "missing_metadata";
|
|
100
|
-
else if (metadataResult.malformed) reason = "metadata_malformed";
|
|
101
|
-
else if (!tokenSnapshot.exists) reason = "missing_token";
|
|
102
|
-
else if (!token) reason = "empty_token";
|
|
103
|
-
else if (!metadataIdentity) reason = "metadata_identity_missing";
|
|
104
|
-
else if (!metadataFingerprint || metadataFingerprint !== githubTokenFingerprint(token)) reason = "token_metadata_mismatch";
|
|
57
|
+
&& Boolean(metadata?.token_fingerprint)
|
|
58
|
+
&& metadata.token_fingerprint === githubTokenFingerprint(token);
|
|
105
59
|
|
|
106
60
|
return {
|
|
107
61
|
profile: paths.profile,
|
|
108
|
-
configured,
|
|
109
|
-
valid:
|
|
110
|
-
reason,
|
|
62
|
+
configured: tokenSnapshot.exists,
|
|
63
|
+
valid: tokenSnapshot.exists && Boolean(token),
|
|
64
|
+
reason: !tokenSnapshot.exists ? "unconfigured" : token ? "" : "empty_token",
|
|
111
65
|
token,
|
|
112
|
-
identity,
|
|
113
|
-
metadata: metadataResult.value,
|
|
114
|
-
paths,
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
function lockOptions(env = process.env) {
|
|
119
|
-
return {
|
|
120
|
-
timeoutMs: parseSafePositiveInteger(env.CCDX_TOKEN_LOCK_TIMEOUT_MS, RUNTIME_DEFAULTS.tokenLockTimeoutMs),
|
|
121
|
-
staleMs: parseSafePositiveInteger(env.CCDX_TOKEN_LOCK_STALE_MS, RUNTIME_DEFAULTS.tokenLockStaleMs),
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
export function withAuthProfileLock(profile, fn, {
|
|
126
|
-
home = os.homedir(),
|
|
127
|
-
env = process.env,
|
|
128
|
-
...options
|
|
129
|
-
} = {}) {
|
|
130
|
-
const { lockPath } = authProfilePaths(profile, { home });
|
|
131
|
-
return withFileLock(lockPath, fn, { ...lockOptions(env), ...options });
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
export function writeClaudeAuthProfile(token, identity, {
|
|
135
|
-
home = os.homedir(),
|
|
136
|
-
now = () => new Date(),
|
|
137
|
-
writeFile = atomicWriteFileSync,
|
|
138
|
-
unlinkFile = fs.unlinkSync,
|
|
139
|
-
} = {}) {
|
|
140
|
-
const cleanToken = String(token || "").trim();
|
|
141
|
-
const normalizedIdentity = normalizeGithubIdentity(identity);
|
|
142
|
-
if (!cleanToken) throw new Error("Claude GitHub token is empty");
|
|
143
|
-
if (!normalizedIdentity) throw new Error("Claude GitHub account identity is missing");
|
|
144
|
-
|
|
145
|
-
const paths = authProfilePaths(AUTH_PROFILE_CLAUDE, { home });
|
|
146
|
-
const directory = path.dirname(paths.tokenPath);
|
|
147
|
-
fs.mkdirSync(directory, { recursive: true, mode: 0o700 });
|
|
148
|
-
fs.chmodSync(directory, 0o700);
|
|
149
|
-
|
|
150
|
-
const timestamp = now();
|
|
151
|
-
const updatedAt = timestamp instanceof Date ? timestamp.toISOString() : new Date(timestamp).toISOString();
|
|
152
|
-
const metadata = `${JSON.stringify({
|
|
153
|
-
profile: AUTH_PROFILE_CLAUDE,
|
|
154
|
-
...normalizedIdentity,
|
|
155
|
-
token_fingerprint: githubTokenFingerprint(cleanToken),
|
|
156
|
-
updated_at: updatedAt,
|
|
157
|
-
}, null, 2)}\n`;
|
|
158
|
-
|
|
159
|
-
// Commit the activation marker last. Readers never observe a configured
|
|
160
|
-
// Claude profile unless the token and its fingerprint agree.
|
|
161
|
-
atomicWriteFilePairSync(
|
|
162
|
-
paths.tokenPath,
|
|
163
|
-
cleanToken,
|
|
164
|
-
paths.metadataPath,
|
|
66
|
+
identity: metadataMatchesToken ? normalizeGithubIdentity(metadata) : null,
|
|
165
67
|
metadata,
|
|
166
|
-
{ mode: 0o600, writeFile, unlinkFile },
|
|
167
|
-
);
|
|
168
|
-
|
|
169
|
-
return {
|
|
170
|
-
profile: AUTH_PROFILE_CLAUDE,
|
|
171
|
-
identity: normalizedIdentity,
|
|
172
68
|
paths,
|
|
173
69
|
};
|
|
174
70
|
}
|
|
175
|
-
|
|
176
|
-
export function profileReauthMessage(profile, { home = os.homedir() } = {}) {
|
|
177
|
-
const name = checkedProfile(profile);
|
|
178
|
-
if (name === AUTH_PROFILE_CLAUDE) {
|
|
179
|
-
return "Claude authentication is unavailable. Run `ccdx auth login claude --reauth`, then restart ccdx.";
|
|
180
|
-
}
|
|
181
|
-
return `Codex authentication is unavailable at ${authProfilePaths(name, { home }).tokenPath}. Run ccdx again to log in.`;
|
|
182
|
-
}
|