codex-copilot-dx 0.6.20 → 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 +3 -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/cli-models.mjs
CHANGED
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
import os from "node:os";
|
|
2
2
|
import { validateGithubToken } from "./auth.mjs";
|
|
3
3
|
import {
|
|
4
|
-
AUTH_PROFILE_CLAUDE,
|
|
5
4
|
AUTH_PROFILE_CODEX,
|
|
6
5
|
readAuthProfileCredentials,
|
|
7
6
|
} from "./auth-profile.mjs";
|
|
8
7
|
import { buildHeaders, FALLBACK_VSCODE_VERSION, parseApiBase } from "./copilot.mjs";
|
|
9
|
-
import {
|
|
10
|
-
isClaudeCopilotCatalogEntry,
|
|
11
|
-
isClaudeCopilotModel,
|
|
12
|
-
} from "./models.mjs";
|
|
13
8
|
import { status } from "./status.mjs";
|
|
14
9
|
import {
|
|
15
10
|
cliOutputFormat,
|
|
@@ -22,7 +17,6 @@ const DEFAULT_MODELS_TIMEOUT_MS = 10000;
|
|
|
22
17
|
const SUPPORTED_ENDPOINTS = [
|
|
23
18
|
["responses", new Set(["/responses", "/v1/responses"])],
|
|
24
19
|
["chat", new Set(["/chat/completions"])],
|
|
25
|
-
["messages", new Set(["/v1/messages"])],
|
|
26
20
|
];
|
|
27
21
|
|
|
28
22
|
function safeText(value, fallback = "") {
|
|
@@ -47,19 +41,15 @@ export function selectableCopilotModels(payload) {
|
|
|
47
41
|
const models = [];
|
|
48
42
|
const seen = new Set();
|
|
49
43
|
for (const model of data) {
|
|
50
|
-
if (
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
if (policyState && policyState !== "enabled") continue;
|
|
56
|
-
const capabilityType = safeText(model?.capabilities?.type).toLowerCase();
|
|
57
|
-
if (capabilityType && capabilityType !== "chat") continue;
|
|
58
|
-
}
|
|
44
|
+
if (model?.model_picker_enabled !== true) continue;
|
|
45
|
+
const policyState = safeText(model?.policy?.state).toLowerCase();
|
|
46
|
+
if (policyState && policyState !== "enabled") continue;
|
|
47
|
+
const capabilityType = safeText(model?.capabilities?.type).toLowerCase();
|
|
48
|
+
if (capabilityType && capabilityType !== "chat") continue;
|
|
59
49
|
|
|
60
50
|
const id = safeText(model?.id);
|
|
61
51
|
const endpoints = endpointLabels(model);
|
|
62
|
-
if (!id || id === "codex-auto-review" || !endpoints.length || seen.has(id)) continue;
|
|
52
|
+
if (!id.startsWith("gpt-") || id === "codex-auto-review" || !endpoints.length || seen.has(id)) continue;
|
|
63
53
|
seen.add(id);
|
|
64
54
|
models.push({
|
|
65
55
|
id,
|
|
@@ -87,27 +77,14 @@ async function responseText(response) {
|
|
|
87
77
|
}
|
|
88
78
|
}
|
|
89
79
|
|
|
90
|
-
function
|
|
91
|
-
const requested = String(profile || AUTH_PROFILE_CODEX).trim().toLowerCase();
|
|
92
|
-
if (requested !== AUTH_PROFILE_CODEX && requested !== AUTH_PROFILE_CLAUDE) {
|
|
93
|
-
throw new Error(`Unsupported models profile: ${profile}`);
|
|
94
|
-
}
|
|
95
|
-
|
|
80
|
+
function readModelCredentials(home) {
|
|
96
81
|
let credentials;
|
|
97
82
|
try {
|
|
98
|
-
credentials = readAuthProfileCredentials(
|
|
83
|
+
credentials = readAuthProfileCredentials(AUTH_PROFILE_CODEX, { home });
|
|
99
84
|
} catch (error) {
|
|
100
|
-
|
|
101
|
-
throw new Error(`Could not read the ${label}: ${error.message}`);
|
|
85
|
+
throw new Error(`Could not read the GitHub token: ${error.message}`);
|
|
102
86
|
}
|
|
103
87
|
if (credentials.valid) return credentials;
|
|
104
|
-
|
|
105
|
-
if (requested === AUTH_PROFILE_CLAUDE) {
|
|
106
|
-
if (!credentials.configured) {
|
|
107
|
-
throw new Error("Claude GitHub profile is not configured. Run ccdx auth login claude.");
|
|
108
|
-
}
|
|
109
|
-
throw new Error(`Claude GitHub profile is invalid (${credentials.reason || "unknown"}). Run ccdx auth login claude --reauth.`);
|
|
110
|
-
}
|
|
111
88
|
if (!credentials.configured) throw new Error("GitHub token not found. Start ccdx once to log in.");
|
|
112
89
|
if (credentials.reason === "empty_token") throw new Error("GitHub token file is empty. Start ccdx again to log in.");
|
|
113
90
|
throw new Error(`GitHub token is unavailable (${credentials.reason || "unknown"}). Start ccdx again to log in.`);
|
|
@@ -115,18 +92,15 @@ function readModelProfile(profile, home) {
|
|
|
115
92
|
|
|
116
93
|
export async function fetchLiveCopilotModels({
|
|
117
94
|
home = os.homedir(),
|
|
118
|
-
profile = AUTH_PROFILE_CODEX,
|
|
119
95
|
fetchImpl = fetch,
|
|
120
96
|
timeoutMs = DEFAULT_MODELS_TIMEOUT_MS,
|
|
121
97
|
vscodeVersion = FALLBACK_VSCODE_VERSION,
|
|
122
98
|
} = {}) {
|
|
123
|
-
const credentials =
|
|
124
|
-
const githubToken = credentials.token;
|
|
125
|
-
|
|
99
|
+
const credentials = readModelCredentials(home);
|
|
126
100
|
const controller = new AbortController();
|
|
127
101
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
128
102
|
try {
|
|
129
|
-
const validation = await validateGithubToken(
|
|
103
|
+
const validation = await validateGithubToken(credentials.token, {
|
|
130
104
|
fetchImpl,
|
|
131
105
|
signal: controller.signal,
|
|
132
106
|
});
|
|
@@ -161,7 +135,7 @@ export async function fetchLiveCopilotModels({
|
|
|
161
135
|
const catalog = selectableCopilotModels(payload);
|
|
162
136
|
let upstreamHost = "GitHub Copilot";
|
|
163
137
|
try { upstreamHost = new URL(apiBase).hostname; } catch {}
|
|
164
|
-
return { ...catalog, profile:
|
|
138
|
+
return { ...catalog, profile: AUTH_PROFILE_CODEX, upstreamHost: safeText(upstreamHost, "GitHub Copilot") };
|
|
165
139
|
} catch (error) {
|
|
166
140
|
if (controller.signal.aborted && !/timed out/.test(error?.message || "")) {
|
|
167
141
|
throw new Error(`Live model lookup timed out after ${timeoutMs}ms`);
|
|
@@ -172,21 +146,20 @@ export async function fetchLiveCopilotModels({
|
|
|
172
146
|
}
|
|
173
147
|
}
|
|
174
148
|
|
|
175
|
-
function liveCatalogHeader(catalog, { commandName,
|
|
149
|
+
function liveCatalogHeader(catalog, { commandName, models }) {
|
|
176
150
|
const responses = models.filter((model) => model.endpoints.includes("responses")).length;
|
|
177
151
|
const chat = models.filter((model) => model.endpoints.includes("chat")).length;
|
|
178
|
-
const claude = models.filter(isClaudeCopilotCatalogEntry).length;
|
|
179
152
|
return [
|
|
180
|
-
`${commandName} models
|
|
181
|
-
status("ok", `Live catalog from ${safeText(catalog?.upstreamHost, "GitHub Copilot")}: ${models.length} selectable of ${Number(catalog?.advertised) || 0} advertised`),
|
|
182
|
-
status("info", `Responses: ${responses}; Chat: ${chat}
|
|
153
|
+
`${commandName} models`,
|
|
154
|
+
status("ok", `Live catalog from ${safeText(catalog?.upstreamHost, "GitHub Copilot")}: ${models.length} selectable GPT models of ${Number(catalog?.advertised) || 0} advertised`),
|
|
155
|
+
status("info", `Responses: ${responses}; Chat: ${chat}`),
|
|
183
156
|
];
|
|
184
157
|
}
|
|
185
158
|
|
|
186
|
-
function formatLiveCopilotModelsPlain(catalog, { commandName,
|
|
187
|
-
const lines = liveCatalogHeader(catalog, { commandName,
|
|
159
|
+
function formatLiveCopilotModelsPlain(catalog, { commandName, models }, { sanitize = false } = {}) {
|
|
160
|
+
const lines = liveCatalogHeader(catalog, { commandName, models });
|
|
188
161
|
if (!models.length) {
|
|
189
|
-
lines.push(status("warn", "No selectable models were advertised for this account"));
|
|
162
|
+
lines.push(status("warn", "No selectable GPT models were advertised for this account"));
|
|
190
163
|
return (sanitize ? lines.map((line) => terminalCell(line, { fallback: "" })) : lines).join("\n");
|
|
191
164
|
}
|
|
192
165
|
|
|
@@ -209,15 +182,14 @@ export function formatLiveCopilotModels(catalog, {
|
|
|
209
182
|
width = cliOutputWidth(output),
|
|
210
183
|
} = {}) {
|
|
211
184
|
const models = Array.isArray(catalog?.models) ? catalog.models : [];
|
|
212
|
-
const
|
|
213
|
-
const context = { commandName, profile, models };
|
|
185
|
+
const context = { commandName, models };
|
|
214
186
|
if (cliOutputFormat(format, output) === "plain") {
|
|
215
187
|
return formatLiveCopilotModelsPlain(catalog, context);
|
|
216
188
|
}
|
|
217
189
|
|
|
218
190
|
const lines = liveCatalogHeader(catalog, context);
|
|
219
191
|
if (!models.length) {
|
|
220
|
-
lines.push(status("warn", "No selectable models were advertised for this account"));
|
|
192
|
+
lines.push(status("warn", "No selectable GPT models were advertised for this account"));
|
|
221
193
|
return lines.join("\n");
|
|
222
194
|
}
|
|
223
195
|
|
package/src/cli-options.mjs
CHANGED
|
@@ -3,24 +3,21 @@ import { MAX_TIMER_DELAY_MS } from "./runtime-config.mjs";
|
|
|
3
3
|
const HELP_COMMANDS = new Set(["help", "--help", "-h"]);
|
|
4
4
|
const VERSION_COMMANDS = new Set(["version", "--version", "-v"]);
|
|
5
5
|
const START_OPTIONS = new Map([
|
|
6
|
-
["--configure-claude-desktop", "configure-claude-app"],
|
|
7
|
-
["--configure-claude-app", "configure-claude-app"],
|
|
8
6
|
["--show-request-id", "show-request-id"],
|
|
9
7
|
]);
|
|
8
|
+
const RETIRED_CLAUDE_OPTIONS = new Set([
|
|
9
|
+
"--configure-claude-desktop",
|
|
10
|
+
"--configure-claude-app",
|
|
11
|
+
]);
|
|
10
12
|
const PM_COMMANDS = new Set(["pms", "pm-studio"]);
|
|
11
13
|
const HELP_TOPICS = new Set([
|
|
12
14
|
"",
|
|
13
15
|
"start",
|
|
14
16
|
"auth",
|
|
15
17
|
"auth status",
|
|
16
|
-
"auth login",
|
|
17
18
|
"doctor",
|
|
18
19
|
"status",
|
|
19
20
|
"models",
|
|
20
|
-
"pms",
|
|
21
|
-
"pms setup",
|
|
22
|
-
"pms status",
|
|
23
|
-
"pms restore",
|
|
24
21
|
"usage",
|
|
25
22
|
"auto-review-model",
|
|
26
23
|
"update",
|
|
@@ -54,15 +51,6 @@ function parseOptions(args, schema) {
|
|
|
54
51
|
return parsed;
|
|
55
52
|
}
|
|
56
53
|
|
|
57
|
-
function checkedProfile(value, { allowAll = false } = {}) {
|
|
58
|
-
const profile = value || "codex";
|
|
59
|
-
const allowed = allowAll ? new Set(["codex", "claude", "all"]) : new Set(["codex", "claude"]);
|
|
60
|
-
if (!allowed.has(profile)) {
|
|
61
|
-
throw new Error(`Profile must be ${allowAll ? "codex, claude, or all" : "codex or claude"}: ${profile}`);
|
|
62
|
-
}
|
|
63
|
-
return profile;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
54
|
function checkedOutputFormat(value) {
|
|
67
55
|
const format = value || "";
|
|
68
56
|
if (!new Set(["table", "plain"]).has(format)) {
|
|
@@ -78,7 +66,6 @@ function outputFormatOption(value) {
|
|
|
78
66
|
function baseCommand(command, extra = {}) {
|
|
79
67
|
return {
|
|
80
68
|
command,
|
|
81
|
-
configureClaudeDesktop: false,
|
|
82
69
|
showRequestId: false,
|
|
83
70
|
online: false,
|
|
84
71
|
compat: false,
|
|
@@ -88,7 +75,6 @@ function baseCommand(command, extra = {}) {
|
|
|
88
75
|
|
|
89
76
|
function checkedHelpTopic(parts = []) {
|
|
90
77
|
const normalized = parts.map((part, index) => {
|
|
91
|
-
if (index === 0 && part === "pm-studio") return "pms";
|
|
92
78
|
return part;
|
|
93
79
|
}).join(" ");
|
|
94
80
|
if (!HELP_TOPICS.has(normalized)) throw new Error(`Unknown help topic: ${parts.join(" ")}`);
|
|
@@ -102,14 +88,7 @@ function helpCommand(parts = []) {
|
|
|
102
88
|
function nestedHelp(command, rest) {
|
|
103
89
|
if (!rest.length || !HELP_COMMANDS.has(rest.at(-1))) return null;
|
|
104
90
|
const args = rest.slice(0, -1);
|
|
105
|
-
if (PM_COMMANDS.has(command)) {
|
|
106
|
-
if (args.length > 1) unexpectedArgs(args.slice(1));
|
|
107
|
-
return helpCommand(["pms", ...args]);
|
|
108
|
-
}
|
|
109
91
|
if (command === "auth") {
|
|
110
|
-
if (args[0] === "login" && args[1] === "claude" && args.length === 2) {
|
|
111
|
-
return helpCommand(["auth", "login"]);
|
|
112
|
-
}
|
|
113
92
|
if (args.length > 1) unexpectedArgs(args.slice(1));
|
|
114
93
|
return helpCommand(["auth", ...args]);
|
|
115
94
|
}
|
|
@@ -118,6 +97,9 @@ function nestedHelp(command, rest) {
|
|
|
118
97
|
}
|
|
119
98
|
|
|
120
99
|
function parseStartOptions(args) {
|
|
100
|
+
if (args.some((option) => RETIRED_CLAUDE_OPTIONS.has(option))) {
|
|
101
|
+
return baseCommand("retired", { integration: "Claude App and Claude Code" });
|
|
102
|
+
}
|
|
121
103
|
const seen = new Set();
|
|
122
104
|
for (const option of args) {
|
|
123
105
|
const kind = START_OPTIONS.get(option);
|
|
@@ -125,7 +107,6 @@ function parseStartOptions(args) {
|
|
|
125
107
|
seen.add(kind);
|
|
126
108
|
}
|
|
127
109
|
return baseCommand("start", {
|
|
128
|
-
configureClaudeDesktop: seen.has("configure-claude-app"),
|
|
129
110
|
showRequestId: seen.has("show-request-id"),
|
|
130
111
|
});
|
|
131
112
|
}
|
|
@@ -134,12 +115,21 @@ export function parseCliArgs(args = []) {
|
|
|
134
115
|
const [command, ...rest] = args;
|
|
135
116
|
if (!command) return baseCommand("start");
|
|
136
117
|
if (HELP_COMMANDS.has(command)) {
|
|
137
|
-
const topic = rest
|
|
138
|
-
? ["auth", "login"]
|
|
139
|
-
: rest;
|
|
118
|
+
const topic = rest;
|
|
140
119
|
if (topic.length > 2) unexpectedArgs(topic.slice(2));
|
|
141
120
|
return helpCommand(topic);
|
|
142
121
|
}
|
|
122
|
+
const profileOptionIndex = rest.indexOf("--profile");
|
|
123
|
+
const requestedProfile = profileOptionIndex >= 0 ? rest[profileOptionIndex + 1] : "";
|
|
124
|
+
const retiredClaudeInvocation = RETIRED_CLAUDE_OPTIONS.has(command)
|
|
125
|
+
|| (command === "start" && rest.some((option) => RETIRED_CLAUDE_OPTIONS.has(option)))
|
|
126
|
+
|| (command === "auth" && rest[0] === "login" && rest[1] === "claude")
|
|
127
|
+
|| (command === "models" && requestedProfile === "claude")
|
|
128
|
+
|| (command === "doctor" && ["claude", "all"].includes(requestedProfile));
|
|
129
|
+
if (PM_COMMANDS.has(command)) return baseCommand("retired", { integration: "PM Studio" });
|
|
130
|
+
if (retiredClaudeInvocation) {
|
|
131
|
+
return baseCommand("retired", { integration: "Claude App and Claude Code" });
|
|
132
|
+
}
|
|
143
133
|
const requestedHelp = nestedHelp(command, rest);
|
|
144
134
|
if (requestedHelp) return requestedHelp;
|
|
145
135
|
if (VERSION_COMMANDS.has(command)) {
|
|
@@ -156,27 +146,20 @@ export function parseCliArgs(args = []) {
|
|
|
156
146
|
return baseCommand("usage", outputFormatOption(options["--format"]));
|
|
157
147
|
}
|
|
158
148
|
if (PM_COMMANDS.has(command)) {
|
|
159
|
-
|
|
160
|
-
if (!action) throw new Error("Missing pms action: expected setup, status, or restore");
|
|
161
|
-
if (!new Set(["setup", "status", "restore"]).has(action)) throw new Error(`Unknown pms action: ${action}`);
|
|
162
|
-
if (action === "setup" || action === "restore") {
|
|
163
|
-
if (pmsArgs.length) unexpectedArgs(pmsArgs);
|
|
164
|
-
return baseCommand("pms", { action });
|
|
165
|
-
}
|
|
166
|
-
const options = parseOptions(pmsArgs, new Map([["--format", "value"]]));
|
|
167
|
-
return baseCommand("pms", {
|
|
168
|
-
action,
|
|
169
|
-
...outputFormatOption(options["--format"]),
|
|
170
|
-
});
|
|
149
|
+
return baseCommand("retired", { integration: "PM Studio" });
|
|
171
150
|
}
|
|
172
151
|
if (command === "models") {
|
|
173
152
|
const options = parseOptions(rest, new Map([
|
|
174
153
|
["--profile", "value"],
|
|
175
154
|
["--format", "value"],
|
|
176
155
|
]));
|
|
156
|
+
const profile = options["--profile"];
|
|
157
|
+
if (profile === "claude") {
|
|
158
|
+
return baseCommand("retired", { integration: "Claude App and Claude Code" });
|
|
159
|
+
}
|
|
160
|
+
if (profile && profile !== "codex") throw new Error(`Profile must be codex: ${profile}`);
|
|
177
161
|
return {
|
|
178
162
|
...baseCommand("models"),
|
|
179
|
-
profile: checkedProfile(options["--profile"]),
|
|
180
163
|
...outputFormatOption(options["--format"]),
|
|
181
164
|
};
|
|
182
165
|
}
|
|
@@ -202,17 +185,7 @@ export function parseCliArgs(args = []) {
|
|
|
202
185
|
const [profile, ...loginArgs] = authArgs;
|
|
203
186
|
if (!profile) throw new Error("Missing auth login profile: expected claude");
|
|
204
187
|
if (profile !== "claude") throw new Error(`Auth login profile must be claude: ${profile}`);
|
|
205
|
-
|
|
206
|
-
["--github-login", "value"],
|
|
207
|
-
["--reauth", "flag"],
|
|
208
|
-
]));
|
|
209
|
-
return {
|
|
210
|
-
...baseCommand("auth"),
|
|
211
|
-
action: "login",
|
|
212
|
-
profile: "claude",
|
|
213
|
-
expectedLogin: options["--github-login"] || "",
|
|
214
|
-
reauth: Boolean(options["--reauth"]),
|
|
215
|
-
};
|
|
188
|
+
return baseCommand("retired", { integration: "Claude App and Claude Code" });
|
|
216
189
|
}
|
|
217
190
|
throw new Error(`Unknown auth action: ${action}`);
|
|
218
191
|
}
|
|
@@ -237,13 +210,20 @@ export function parseCliArgs(args = []) {
|
|
|
237
210
|
["--compat", "flag"],
|
|
238
211
|
["--profile", "value"],
|
|
239
212
|
]));
|
|
213
|
+
const profile = options["--profile"];
|
|
214
|
+
if (profile === "claude" || profile === "all") {
|
|
215
|
+
return baseCommand("retired", { integration: "Claude App and Claude Code" });
|
|
216
|
+
}
|
|
217
|
+
if (profile && profile !== "codex") throw new Error(`Profile must be codex: ${profile}`);
|
|
240
218
|
return {
|
|
241
219
|
...baseCommand("doctor"),
|
|
242
220
|
online: Boolean(options["--online"]),
|
|
243
221
|
compat: Boolean(options["--compat"]),
|
|
244
|
-
profile: checkedProfile(options["--profile"], { allowAll: true }),
|
|
245
222
|
};
|
|
246
223
|
}
|
|
224
|
+
if (RETIRED_CLAUDE_OPTIONS.has(command)) {
|
|
225
|
+
return baseCommand("retired", { integration: "Claude App and Claude Code" });
|
|
226
|
+
}
|
|
247
227
|
if (START_OPTIONS.has(command)) return parseStartOptions([command, ...rest]);
|
|
248
228
|
throw new Error(`Unknown command or option: ${command}`);
|
|
249
229
|
}
|
|
@@ -288,17 +268,12 @@ export function cliCommandName() {
|
|
|
288
268
|
|
|
289
269
|
function topicHelp(name, topic) {
|
|
290
270
|
const sections = {
|
|
291
|
-
start: `Usage:\n ${name} [start] [--
|
|
292
|
-
auth: `Usage:\n ${name} auth status [--online] [--format table|plain]\n
|
|
293
|
-
"auth status": `Usage:\n ${name} auth status [--online] [--format table|plain]\n\nShows account
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
models: `Usage:\n ${name} models [--profile codex|claude] [--format table|plain]\n\nPerforms a fresh, read-only Copilot model-directory lookup for one saved profile. Interactive terminals use a table by default.`,
|
|
298
|
-
pms: `Usage:\n ${name} pms status [--format table|plain]\n ${name} pms setup\n ${name} pms restore\n ${name} pm-studio status [--format table|plain]\n ${name} pm-studio setup\n ${name} pm-studio restore\n\nInspects, installs, or restores the fail-closed PM Studio split-origin patch. setup and restore modify the installed app only after source-bound compatibility and backup checks pass.`,
|
|
299
|
-
"pms setup": `Usage:\n ${name} pms setup\n\nBacks up, patches, verifies, and ad-hoc signs an exact or structurally compatible PM Studio bundle. Unverifiable versions and drift are never modified.`,
|
|
300
|
-
"pms status": `Usage:\n ${name} pms status [--format table|plain]\n\nRead-only inspection of the installed PM Studio version, patch integrity, Claude profile, and relay availability. Interactive terminals use a table by default.`,
|
|
301
|
-
"pms restore": `Usage:\n ${name} pms restore\n\nRestores the installed PM Studio bundle from its exact source-bound verified backup. The explicit command authorizes the change; no confirmation prompt is shown. Missing, ambiguous, version-mismatched, or drifted records are never restored.`,
|
|
271
|
+
start: `Usage:\n ${name} [start] [--show-request-id]\n\nStarts or reuses the local adapter, updates Codex configuration, and attempts to open Codex or ChatGPT when auto-launch is enabled and supported.`,
|
|
272
|
+
auth: `Usage:\n ${name} auth status [--online] [--format table|plain]\n\nShows the saved GitHub Copilot account without exposing credentials. --online also verifies its entitlement and model catalog.`,
|
|
273
|
+
"auth status": `Usage:\n ${name} auth status [--online] [--format table|plain]\n\nShows the saved GitHub Copilot account without exposing credentials. --online also verifies its entitlement and model catalog. Interactive terminals use a table by default.`,
|
|
274
|
+
doctor: `Usage:\n ${name} doctor [--online] [--compat]\n\nChecks the local credential, Codex configuration, and adapter. --online validates account entitlement; --compat sends minimal inference requests and consumes a small amount of Copilot usage.`,
|
|
275
|
+
status: `Usage:\n ${name} status\n\nShows bounded runtime, routing, performance, queue, and cache metrics from a running adapter.`,
|
|
276
|
+
models: `Usage:\n ${name} models [--format table|plain]\n\nPerforms a fresh, read-only Copilot model-directory lookup for the saved account. Interactive terminals use a table by default.`,
|
|
302
277
|
usage: `Usage:\n ${name} usage [--format table|plain]\n\nSummarizes local token usage metadata without reading prompt or completion content. Interactive terminals use a table by default.`,
|
|
303
278
|
"auto-review-model": `Usage:\n ${name} auto-review-model\n\nInteractively selects an enabled Responses model for Codex Auto-review.`,
|
|
304
279
|
update: `Usage:\n ${name} update [npm|github]\n\nUpdates the global package from the configured npm registry or GitHub main. With no source, an interactive terminal prompts for one.`,
|
|
@@ -312,15 +287,11 @@ export function cliHelp(commandName = "ccdx", topic = "") {
|
|
|
312
287
|
const normalizedTopic = checkedHelpTopic(topic ? topic.split(" ") : []);
|
|
313
288
|
if (normalizedTopic) return topicHelp(name, normalizedTopic);
|
|
314
289
|
return `Usage:
|
|
315
|
-
${name} [start] [--
|
|
290
|
+
${name} [start] [--show-request-id]
|
|
316
291
|
${name} auth status [--online] [--format table|plain]
|
|
317
|
-
${name}
|
|
318
|
-
${name} doctor [--online] [--compat] [--profile codex|claude|all]
|
|
292
|
+
${name} doctor [--online] [--compat]
|
|
319
293
|
${name} status
|
|
320
|
-
${name} models [--
|
|
321
|
-
${name} pms status [--format table|plain]
|
|
322
|
-
${name} pms setup
|
|
323
|
-
${name} pms restore
|
|
294
|
+
${name} models [--format table|plain]
|
|
324
295
|
${name} usage [--format table|plain]
|
|
325
296
|
${name} auto-review-model
|
|
326
297
|
${name} update [npm|github]
|
|
@@ -328,12 +299,11 @@ export function cliHelp(commandName = "ccdx", topic = "") {
|
|
|
328
299
|
${name} --help
|
|
329
300
|
|
|
330
301
|
Commands:
|
|
331
|
-
start Start or reuse the adapter and configure
|
|
332
|
-
auth Inspect
|
|
302
|
+
start Start or reuse the adapter and configure Codex
|
|
303
|
+
auth Inspect the saved GitHub Copilot account
|
|
333
304
|
doctor Diagnose local config; optional live and inference checks
|
|
334
305
|
status Show runtime routing, performance, queue, and cache health
|
|
335
306
|
models Query a saved account's live Copilot model catalog
|
|
336
|
-
pms, pm-studio Inspect, install, or restore the PM Studio patch
|
|
337
307
|
usage Summarize locally recorded token usage
|
|
338
308
|
auto-review-model Select the Codex Auto-review Responses model
|
|
339
309
|
update Update the global package from npm or GitHub
|
package/src/cli-status.mjs
CHANGED
|
@@ -61,29 +61,14 @@ function profileSummary(label, profile = {}) {
|
|
|
61
61
|
const token = client.token_cached
|
|
62
62
|
? `token cached (${duration(client.token_expires_in_ms)} remaining)`
|
|
63
63
|
: "token not cached";
|
|
64
|
-
return `${label} ${mode}: ${token}, ${count(models.models)}
|
|
64
|
+
return `${label} ${mode}: ${token}, ${count(models.models)} models (${source})`;
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
function routingTarget(value) {
|
|
68
68
|
if (value === "codex") return "Codex";
|
|
69
|
-
if (value === "claude") return "Claude";
|
|
70
69
|
return "unknown";
|
|
71
70
|
}
|
|
72
71
|
|
|
73
|
-
function pmRouteSummary(requests = {}) {
|
|
74
|
-
const routes = requests.by_route;
|
|
75
|
-
if (!routes || typeof routes !== "object") return null;
|
|
76
|
-
const names = ["pm_models", "pm_chat_completions"];
|
|
77
|
-
const totals = names.reduce((summary, name) => {
|
|
78
|
-
const route = routes[name] || {};
|
|
79
|
-
summary.total += finiteNumber(route.total) || 0;
|
|
80
|
-
summary.active += finiteNumber(route.active) || 0;
|
|
81
|
-
summary.errors += finiteNumber(route.errors) || 0;
|
|
82
|
-
return summary;
|
|
83
|
-
}, { total: 0, active: 0, errors: 0 });
|
|
84
|
-
return `PM relay: ${count(totals.total)} requests, ${count(totals.active)} active, ${count(totals.errors)} errors; models ${count(routes.pm_models?.total)}, chat ${count(routes.pm_chat_completions?.total)}`;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
72
|
function errorCode(error) {
|
|
88
73
|
const seen = new Set();
|
|
89
74
|
const pending = [error];
|
|
@@ -171,15 +156,13 @@ export function formatAdapterStatus({ baseUrl, data }, { commandName = "ccdx", c
|
|
|
171
156
|
if (imageHistory && typeof imageHistory === "object") {
|
|
172
157
|
lines.push(status("info", `Visual history: ${count(imageHistory.active_recovery_trees)} recovery trees, ${count(imageHistory.adapted_requests)} adapted requests, ${count(imageHistory.historical_images_omitted)} older images omitted, ${count(imageHistory.timeouts_recorded)} timeouts`));
|
|
173
158
|
}
|
|
174
|
-
lines.push(status("info", `Models: ${count(models.models)} total
|
|
175
|
-
if (data.profiles?.codex
|
|
176
|
-
lines.push(status("info", `
|
|
159
|
+
lines.push(status("info", `Models: ${count(models.models)} total; Copilot token ${copilot.token_cached ? `cached (${duration(copilot.token_expires_in_ms)} remaining)` : "not cached"}`));
|
|
160
|
+
if (data.profiles?.codex) {
|
|
161
|
+
lines.push(status("info", `Profile: ${profileSummary("Codex", data.profiles.codex)}`));
|
|
177
162
|
}
|
|
178
|
-
if (data.routing) {
|
|
179
|
-
lines.push(status("info", `Routing: /v1/responses -> ${routingTarget(data.routing.responses)}
|
|
163
|
+
if (data.routing?.responses) {
|
|
164
|
+
lines.push(status("info", `Routing: /v1/responses -> ${routingTarget(data.routing.responses)}`));
|
|
180
165
|
}
|
|
181
|
-
const pmSummary = pmRouteSummary(requests);
|
|
182
|
-
if (pmSummary) lines.push(status("info", pmSummary));
|
|
183
166
|
lines.push(status("info", `Limits: request body ${mebibytes(limits.max_body_bytes)}, decoded body ${mebibytes(limits.max_decoded_body_bytes)}`));
|
|
184
167
|
return lines.join("\n");
|
|
185
168
|
}
|
package/src/config.mjs
CHANGED
|
@@ -80,8 +80,7 @@ function setTomlKey(lines, sectionName, key, value) {
|
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
export function computeUpdatedCodexConfig(content, adapterPort = 2026, adapterHost = "127.0.0.1") {
|
|
83
|
-
const
|
|
84
|
-
const baseUrl = `${anthropicBaseUrl}/v1`;
|
|
83
|
+
const baseUrl = `${adapterBaseUrl(adapterHost, adapterPort)}/v1`;
|
|
85
84
|
const hadTrailingNewline = content.endsWith("\n");
|
|
86
85
|
const lines = content.split("\n");
|
|
87
86
|
if (hadTrailingNewline) lines.pop();
|
|
@@ -103,8 +102,6 @@ export function computeUpdatedCodexConfig(content, adapterPort = 2026, adapterHo
|
|
|
103
102
|
|
|
104
103
|
changed = setTopLevelTomlDefault(lines, "model_context_window", MODEL_CONTEXT_WINDOW) || changed;
|
|
105
104
|
changed = setTopLevelTomlDefault(lines, "model_auto_compact_token_limit", MODEL_AUTO_COMPACT_TOKEN_LIMIT) || changed;
|
|
106
|
-
changed = setTomlKey(lines, "shell_environment_policy.set", "ANTHROPIC_AUTH_TOKEN", "dummy") || changed;
|
|
107
|
-
changed = setTomlKey(lines, "shell_environment_policy.set", "ANTHROPIC_BASE_URL", anthropicBaseUrl) || changed;
|
|
108
105
|
changed = setTomlKey(lines, "shell_environment_policy.set", "OPENAI_BASE_URL", baseUrl) || changed;
|
|
109
106
|
changed = setTomlKey(lines, "shell_environment_policy.set", "OPENAI_API_KEY", "dummy") || changed;
|
|
110
107
|
|
|
@@ -112,8 +109,7 @@ export function computeUpdatedCodexConfig(content, adapterPort = 2026, adapterHo
|
|
|
112
109
|
}
|
|
113
110
|
|
|
114
111
|
function initialCodexConfig(adapterPort, adapterHost) {
|
|
115
|
-
const
|
|
116
|
-
const baseUrl = `${anthropicBaseUrl}/v1`;
|
|
112
|
+
const baseUrl = `${adapterBaseUrl(adapterHost, adapterPort)}/v1`;
|
|
117
113
|
return `openai_base_url = "${baseUrl}"
|
|
118
114
|
model_context_window = ${MODEL_CONTEXT_WINDOW}
|
|
119
115
|
model_auto_compact_token_limit = ${MODEL_AUTO_COMPACT_TOKEN_LIMIT}
|
|
@@ -122,8 +118,6 @@ model_auto_compact_token_limit = ${MODEL_AUTO_COMPACT_TOKEN_LIMIT}
|
|
|
122
118
|
inherit = "core"
|
|
123
119
|
|
|
124
120
|
[shell_environment_policy.set]
|
|
125
|
-
ANTHROPIC_AUTH_TOKEN = "dummy"
|
|
126
|
-
ANTHROPIC_BASE_URL = "${anthropicBaseUrl}"
|
|
127
121
|
OPENAI_BASE_URL = "${baseUrl}"
|
|
128
122
|
OPENAI_API_KEY = "dummy"
|
|
129
123
|
`;
|
package/src/copilot.mjs
CHANGED
|
@@ -259,9 +259,9 @@ export async function refreshVSCodeVersion() {
|
|
|
259
259
|
return cachedVersion;
|
|
260
260
|
}
|
|
261
261
|
|
|
262
|
-
// Stateful Copilot data lives inside
|
|
262
|
+
// Stateful Copilot data lives inside client instances. These module-level
|
|
263
263
|
// wrappers preserve every existing export as the default Codex compatibility
|
|
264
|
-
// layer while
|
|
264
|
+
// layer while retaining isolated client injection for internal callers.
|
|
265
265
|
export function createCopilotClient(options = {}) {
|
|
266
266
|
return createCopilotClientRuntime({
|
|
267
267
|
...options,
|