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.
@@ -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 (isClaudeCopilotCatalogEntry(model)) {
51
- if (!isClaudeCopilotModel(model)) continue;
52
- } else {
53
- if (model?.model_picker_enabled !== true) continue;
54
- const policyState = safeText(model?.policy?.state).toLowerCase();
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 readModelProfile(profile, home) {
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(requested, { home });
83
+ credentials = readAuthProfileCredentials(AUTH_PROFILE_CODEX, { home });
99
84
  } catch (error) {
100
- const label = requested === AUTH_PROFILE_CLAUDE ? "Claude GitHub profile" : "GitHub token";
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 = readModelProfile(profile, home);
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(githubToken, {
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: credentials.profile, upstreamHost: safeText(upstreamHost, "GitHub Copilot") };
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, profile, models }) {
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${profile === AUTH_PROFILE_CLAUDE ? " --profile claude" : ""}`,
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}; Claude/Anthropic: ${claude}`),
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, profile, models }, { sanitize = false } = {}) {
187
- const lines = liveCatalogHeader(catalog, { commandName, profile, models });
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 profile = catalog?.profile === AUTH_PROFILE_CLAUDE ? AUTH_PROFILE_CLAUDE : AUTH_PROFILE_CODEX;
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
 
@@ -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[0] === "auth" && rest[1] === "login" && rest[2] === "claude"
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
- const [action, ...pmsArgs] = rest;
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
- const options = parseOptions(loginArgs, new Map([
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] [--configure-claude-app] [--show-request-id]\n\nStarts or reuses the local adapter, updates Codex and Claude Code configuration, and attempts to open Codex or ChatGPT when auto-launch is enabled and supported.\n--configure-claude-app also creates or updates the managed Claude App gateway profile.`,
292
- auth: `Usage:\n ${name} auth status [--online] [--format table|plain]\n ${name} auth login claude [--github-login <login>] [--reauth]\n\nShows the two account profiles or configures the isolated Claude account. Device login starts only when no reusable local Copilot credential is available or --reauth is used.`,
293
- "auth status": `Usage:\n ${name} auth status [--online] [--format table|plain]\n\nShows account routing without exposing credentials. --online also verifies both configured Copilot entitlements and model catalogs. Interactive terminals use a table by default.`,
294
- "auth login": `Usage:\n ${name} auth login claude [--github-login <login>] [--reauth]\n\nReuses a compatible local Copilot credential when possible. --reauth forces GitHub Device Flow.`,
295
- doctor: `Usage:\n ${name} doctor [--online] [--compat] [--profile codex|claude|all]\n\nChecks local credentials, client configuration, PM Studio state, and the adapter. --online validates account entitlement; --compat sends minimal inference requests and consumes a small amount of Copilot usage.`,
296
- status: `Usage:\n ${name} status\n\nShows bounded runtime, routing, performance, cache, queue, and PM relay metrics from a running adapter.`,
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] [--configure-claude-app] [--show-request-id]
290
+ ${name} [start] [--show-request-id]
316
291
  ${name} auth status [--online] [--format table|plain]
317
- ${name} auth login claude [--github-login <login>] [--reauth]
318
- ${name} doctor [--online] [--compat] [--profile codex|claude|all]
292
+ ${name} doctor [--online] [--compat]
319
293
  ${name} status
320
- ${name} models [--profile codex|claude] [--format table|plain]
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 local clients
332
- auth Inspect or configure the Codex and Claude accounts
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
@@ -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)} total/${count(models.claude_models)} Claude models (${source})`;
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, ${count(models.claude_models)} Claude; Copilot token ${copilot.token_cached ? `cached (${duration(copilot.token_expires_in_ms)} remaining)` : "not cached"}`));
175
- if (data.profiles?.codex || data.profiles?.claude) {
176
- lines.push(status("info", `Profiles: ${profileSummary("Codex", data.profiles?.codex)}; ${profileSummary("Claude", data.profiles?.claude)}`));
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)}; /v1/messages -> ${routingTarget(data.routing.messages)}`));
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 anthropicBaseUrl = adapterBaseUrl(adapterHost, adapterPort);
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 anthropicBaseUrl = adapterBaseUrl(adapterHost, adapterPort);
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 per-profile clients. These module-level
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 allowing the adapter to use isolated Codex and Claude clients.
264
+ // layer while retaining isolated client injection for internal callers.
265
265
  export function createCopilotClient(options = {}) {
266
266
  return createCopilotClientRuntime({
267
267
  ...options,