codex-copilot-dx 0.6.21 → 0.7.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 +142 -323
- package/bin/cli.mjs +26 -130
- package/package.json +2 -8
- package/scripts/benchmark.mjs +0 -114
- package/src/adapter.mjs +22 -107
- package/src/auth-profile.mjs +18 -130
- package/src/cli-animation.mjs +108 -0
- package/src/cli-auth.mjs +44 -398
- package/src/cli-models.mjs +21 -49
- package/src/cli-options.mjs +53 -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/terminal-activity.mjs +40 -34
- package/src/terminal-animation.mjs +249 -0
- package/src/usage.mjs +0 -31
- package/src/user-settings.mjs +50 -0
- 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,25 +3,23 @@ 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",
|
|
22
|
+
"animation",
|
|
25
23
|
"auto-review-model",
|
|
26
24
|
"update",
|
|
27
25
|
"version",
|
|
@@ -54,15 +52,6 @@ function parseOptions(args, schema) {
|
|
|
54
52
|
return parsed;
|
|
55
53
|
}
|
|
56
54
|
|
|
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
55
|
function checkedOutputFormat(value) {
|
|
67
56
|
const format = value || "";
|
|
68
57
|
if (!new Set(["table", "plain"]).has(format)) {
|
|
@@ -78,7 +67,6 @@ function outputFormatOption(value) {
|
|
|
78
67
|
function baseCommand(command, extra = {}) {
|
|
79
68
|
return {
|
|
80
69
|
command,
|
|
81
|
-
configureClaudeDesktop: false,
|
|
82
70
|
showRequestId: false,
|
|
83
71
|
online: false,
|
|
84
72
|
compat: false,
|
|
@@ -88,7 +76,6 @@ function baseCommand(command, extra = {}) {
|
|
|
88
76
|
|
|
89
77
|
function checkedHelpTopic(parts = []) {
|
|
90
78
|
const normalized = parts.map((part, index) => {
|
|
91
|
-
if (index === 0 && part === "pm-studio") return "pms";
|
|
92
79
|
return part;
|
|
93
80
|
}).join(" ");
|
|
94
81
|
if (!HELP_TOPICS.has(normalized)) throw new Error(`Unknown help topic: ${parts.join(" ")}`);
|
|
@@ -102,14 +89,7 @@ function helpCommand(parts = []) {
|
|
|
102
89
|
function nestedHelp(command, rest) {
|
|
103
90
|
if (!rest.length || !HELP_COMMANDS.has(rest.at(-1))) return null;
|
|
104
91
|
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
92
|
if (command === "auth") {
|
|
110
|
-
if (args[0] === "login" && args[1] === "claude" && args.length === 2) {
|
|
111
|
-
return helpCommand(["auth", "login"]);
|
|
112
|
-
}
|
|
113
93
|
if (args.length > 1) unexpectedArgs(args.slice(1));
|
|
114
94
|
return helpCommand(["auth", ...args]);
|
|
115
95
|
}
|
|
@@ -118,6 +98,9 @@ function nestedHelp(command, rest) {
|
|
|
118
98
|
}
|
|
119
99
|
|
|
120
100
|
function parseStartOptions(args) {
|
|
101
|
+
if (args.some((option) => RETIRED_CLAUDE_OPTIONS.has(option))) {
|
|
102
|
+
return baseCommand("retired", { integration: "Claude App and Claude Code" });
|
|
103
|
+
}
|
|
121
104
|
const seen = new Set();
|
|
122
105
|
for (const option of args) {
|
|
123
106
|
const kind = START_OPTIONS.get(option);
|
|
@@ -125,7 +108,6 @@ function parseStartOptions(args) {
|
|
|
125
108
|
seen.add(kind);
|
|
126
109
|
}
|
|
127
110
|
return baseCommand("start", {
|
|
128
|
-
configureClaudeDesktop: seen.has("configure-claude-app"),
|
|
129
111
|
showRequestId: seen.has("show-request-id"),
|
|
130
112
|
});
|
|
131
113
|
}
|
|
@@ -134,12 +116,21 @@ export function parseCliArgs(args = []) {
|
|
|
134
116
|
const [command, ...rest] = args;
|
|
135
117
|
if (!command) return baseCommand("start");
|
|
136
118
|
if (HELP_COMMANDS.has(command)) {
|
|
137
|
-
const topic = rest
|
|
138
|
-
? ["auth", "login"]
|
|
139
|
-
: rest;
|
|
119
|
+
const topic = rest;
|
|
140
120
|
if (topic.length > 2) unexpectedArgs(topic.slice(2));
|
|
141
121
|
return helpCommand(topic);
|
|
142
122
|
}
|
|
123
|
+
const profileOptionIndex = rest.indexOf("--profile");
|
|
124
|
+
const requestedProfile = profileOptionIndex >= 0 ? rest[profileOptionIndex + 1] : "";
|
|
125
|
+
const retiredClaudeInvocation = RETIRED_CLAUDE_OPTIONS.has(command)
|
|
126
|
+
|| (command === "start" && rest.some((option) => RETIRED_CLAUDE_OPTIONS.has(option)))
|
|
127
|
+
|| (command === "auth" && rest[0] === "login" && rest[1] === "claude")
|
|
128
|
+
|| (command === "models" && requestedProfile === "claude")
|
|
129
|
+
|| (command === "doctor" && ["claude", "all"].includes(requestedProfile));
|
|
130
|
+
if (PM_COMMANDS.has(command)) return baseCommand("retired", { integration: "PM Studio" });
|
|
131
|
+
if (retiredClaudeInvocation) {
|
|
132
|
+
return baseCommand("retired", { integration: "Claude App and Claude Code" });
|
|
133
|
+
}
|
|
143
134
|
const requestedHelp = nestedHelp(command, rest);
|
|
144
135
|
if (requestedHelp) return requestedHelp;
|
|
145
136
|
if (VERSION_COMMANDS.has(command)) {
|
|
@@ -156,27 +147,20 @@ export function parseCliArgs(args = []) {
|
|
|
156
147
|
return baseCommand("usage", outputFormatOption(options["--format"]));
|
|
157
148
|
}
|
|
158
149
|
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
|
-
});
|
|
150
|
+
return baseCommand("retired", { integration: "PM Studio" });
|
|
171
151
|
}
|
|
172
152
|
if (command === "models") {
|
|
173
153
|
const options = parseOptions(rest, new Map([
|
|
174
154
|
["--profile", "value"],
|
|
175
155
|
["--format", "value"],
|
|
176
156
|
]));
|
|
157
|
+
const profile = options["--profile"];
|
|
158
|
+
if (profile === "claude") {
|
|
159
|
+
return baseCommand("retired", { integration: "Claude App and Claude Code" });
|
|
160
|
+
}
|
|
161
|
+
if (profile && profile !== "codex") throw new Error(`Profile must be codex: ${profile}`);
|
|
177
162
|
return {
|
|
178
163
|
...baseCommand("models"),
|
|
179
|
-
profile: checkedProfile(options["--profile"]),
|
|
180
164
|
...outputFormatOption(options["--format"]),
|
|
181
165
|
};
|
|
182
166
|
}
|
|
@@ -202,20 +186,14 @@ export function parseCliArgs(args = []) {
|
|
|
202
186
|
const [profile, ...loginArgs] = authArgs;
|
|
203
187
|
if (!profile) throw new Error("Missing auth login profile: expected claude");
|
|
204
188
|
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
|
-
};
|
|
189
|
+
return baseCommand("retired", { integration: "Claude App and Claude Code" });
|
|
216
190
|
}
|
|
217
191
|
throw new Error(`Unknown auth action: ${action}`);
|
|
218
192
|
}
|
|
193
|
+
if (command === "animation") {
|
|
194
|
+
if (rest.length) unexpectedArgs(rest);
|
|
195
|
+
return baseCommand("animation");
|
|
196
|
+
}
|
|
219
197
|
if (command === "auto-review-model") {
|
|
220
198
|
if (rest.length) unexpectedArgs(rest);
|
|
221
199
|
return baseCommand("auto-review-model");
|
|
@@ -237,13 +215,20 @@ export function parseCliArgs(args = []) {
|
|
|
237
215
|
["--compat", "flag"],
|
|
238
216
|
["--profile", "value"],
|
|
239
217
|
]));
|
|
218
|
+
const profile = options["--profile"];
|
|
219
|
+
if (profile === "claude" || profile === "all") {
|
|
220
|
+
return baseCommand("retired", { integration: "Claude App and Claude Code" });
|
|
221
|
+
}
|
|
222
|
+
if (profile && profile !== "codex") throw new Error(`Profile must be codex: ${profile}`);
|
|
240
223
|
return {
|
|
241
224
|
...baseCommand("doctor"),
|
|
242
225
|
online: Boolean(options["--online"]),
|
|
243
226
|
compat: Boolean(options["--compat"]),
|
|
244
|
-
profile: checkedProfile(options["--profile"], { allowAll: true }),
|
|
245
227
|
};
|
|
246
228
|
}
|
|
229
|
+
if (RETIRED_CLAUDE_OPTIONS.has(command)) {
|
|
230
|
+
return baseCommand("retired", { integration: "Claude App and Claude Code" });
|
|
231
|
+
}
|
|
247
232
|
if (START_OPTIONS.has(command)) return parseStartOptions([command, ...rest]);
|
|
248
233
|
throw new Error(`Unknown command or option: ${command}`);
|
|
249
234
|
}
|
|
@@ -288,18 +273,14 @@ export function cliCommandName() {
|
|
|
288
273
|
|
|
289
274
|
function topicHelp(name, topic) {
|
|
290
275
|
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.`,
|
|
276
|
+
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.`,
|
|
277
|
+
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.`,
|
|
278
|
+
"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.`,
|
|
279
|
+
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.`,
|
|
280
|
+
status: `Usage:\n ${name} status\n\nShows bounded runtime, routing, performance, queue, and cache metrics from a running adapter.`,
|
|
281
|
+
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
282
|
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.`,
|
|
283
|
+
animation: `Usage:\n ${name} animation\n\nInteractively selects the terminal activity animation used the next time the adapter starts.`,
|
|
303
284
|
"auto-review-model": `Usage:\n ${name} auto-review-model\n\nInteractively selects an enabled Responses model for Codex Auto-review.`,
|
|
304
285
|
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.`,
|
|
305
286
|
version: `Usage:\n ${name} --version`,
|
|
@@ -312,29 +293,26 @@ export function cliHelp(commandName = "ccdx", topic = "") {
|
|
|
312
293
|
const normalizedTopic = checkedHelpTopic(topic ? topic.split(" ") : []);
|
|
313
294
|
if (normalizedTopic) return topicHelp(name, normalizedTopic);
|
|
314
295
|
return `Usage:
|
|
315
|
-
${name} [start] [--
|
|
296
|
+
${name} [start] [--show-request-id]
|
|
316
297
|
${name} auth status [--online] [--format table|plain]
|
|
317
|
-
${name}
|
|
318
|
-
${name} doctor [--online] [--compat] [--profile codex|claude|all]
|
|
298
|
+
${name} doctor [--online] [--compat]
|
|
319
299
|
${name} status
|
|
320
|
-
${name} models [--
|
|
321
|
-
${name} pms status [--format table|plain]
|
|
322
|
-
${name} pms setup
|
|
323
|
-
${name} pms restore
|
|
300
|
+
${name} models [--format table|plain]
|
|
324
301
|
${name} usage [--format table|plain]
|
|
302
|
+
${name} animation
|
|
325
303
|
${name} auto-review-model
|
|
326
304
|
${name} update [npm|github]
|
|
327
305
|
${name} --version
|
|
328
306
|
${name} --help
|
|
329
307
|
|
|
330
308
|
Commands:
|
|
331
|
-
start Start or reuse the adapter and configure
|
|
332
|
-
auth Inspect
|
|
309
|
+
start Start or reuse the adapter and configure Codex
|
|
310
|
+
auth Inspect the saved GitHub Copilot account
|
|
333
311
|
doctor Diagnose local config; optional live and inference checks
|
|
334
312
|
status Show runtime routing, performance, queue, and cache health
|
|
335
313
|
models Query a saved account's live Copilot model catalog
|
|
336
|
-
pms, pm-studio Inspect, install, or restore the PM Studio patch
|
|
337
314
|
usage Summarize locally recorded token usage
|
|
315
|
+
animation Select the terminal activity animation
|
|
338
316
|
auto-review-model Select the Codex Auto-review Responses model
|
|
339
317
|
update Update the global package from npm or GitHub
|
|
340
318
|
|
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,
|