codex-copilot-dx 0.4.38 → 0.4.40
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 +1 -1
- package/bin/cli.mjs +21 -2
- package/package.json +1 -1
- package/src/claude-desktop-config.mjs +71 -13
- package/src/startup.mjs +3 -7
package/README.md
CHANGED
|
@@ -107,7 +107,7 @@ Or set:
|
|
|
107
107
|
CCDX_CONFIGURE_CLAUDE_DESKTOP=1 npx codex-copilot-dx@latest
|
|
108
108
|
```
|
|
109
109
|
|
|
110
|
-
This writes a local Claude App 3P gateway profile that points to the adapter root URL, such as `http://127.0.0.1:2026`. The profile uses a generated local bearer key unless `CCDX_CLAUDE_DESKTOP_API_KEY` is set. Later starts restore that key only from the active managed profile when its gateway URL matches the adapter. Restart Claude App after running the
|
|
110
|
+
This writes a local Claude App 3P gateway profile that points to the adapter root URL, such as `http://127.0.0.1:2026`. The profile uses a generated local bearer key unless `CCDX_CLAUDE_DESKTOP_API_KEY` is set. Later starts restore that key only from the active managed profile when its gateway URL matches the adapter. Once that managed profile is active, successful Copilot model refreshes automatically keep its `inferenceModels` list current without changing the gateway key or other profile settings. Restart Claude App after the initial setup. Later model changes require no profile reconfiguration, although a running Claude App may need to be reopened if it has not reloaded the updated profile yet.
|
|
111
111
|
|
|
112
112
|
When reusing an already-running adapter, Claude App profile updates require `CCDX_CLAUDE_DESKTOP_API_KEY` or `CCDX_PROXY_API_KEY` so the profile key matches the running process. Otherwise the existing adapter is left untouched.
|
|
113
113
|
|
package/bin/cli.mjs
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { ensureAuth, openCodex } from "../src/launcher.mjs";
|
|
4
4
|
import { ensureCodexConfig } from "../src/config.mjs";
|
|
5
5
|
import { ensureClaudeConfig } from "../src/claude-config.mjs";
|
|
6
|
-
import { applyClaudeDesktopConfig, formatClaudeDesktopApplyResult, generatedClaudeDesktopApiKey, loadManagedClaudeDesktopApiKey } from "../src/claude-desktop-config.mjs";
|
|
6
|
+
import { applyClaudeDesktopConfig, formatClaudeDesktopApplyResult, generatedClaudeDesktopApiKey, loadManagedClaudeDesktopApiKey, syncManagedClaudeDesktopModels } from "../src/claude-desktop-config.mjs";
|
|
7
7
|
import { startAdapter } from "../src/adapter.mjs";
|
|
8
8
|
import { cacheModelEndpoints, listModels, refreshVSCodeVersion } from "../src/copilot.mjs";
|
|
9
9
|
import { claudeDesktopModelDefsFromCopilotModels, claudeDesktopModelIds, codexAutoReviewModelStatus, gptModelIdsFromCopilotModels, parseModelAliasEnv } from "../src/models.mjs";
|
|
@@ -129,10 +129,14 @@ async function refreshClaudeDesktopModelDefs() {
|
|
|
129
129
|
} else {
|
|
130
130
|
console.log(status("warn", "Copilot models response contained no Claude models; using built-in Claude models"));
|
|
131
131
|
}
|
|
132
|
+
syncClaudeDesktopProfileModels(MODEL_REGISTRY.modelDefs);
|
|
132
133
|
return modelDefs;
|
|
133
134
|
} catch (e) {
|
|
134
135
|
const fallback = MODEL_REGISTRY.modelDefs?.length ? `${MODEL_REGISTRY.source} model list` : "built-in model list";
|
|
135
|
-
|
|
136
|
+
const message = ctrl.signal.aborted
|
|
137
|
+
? `Model refresh timed out after ${MODEL_REFRESH_TIMEOUT_MS}ms; using ${fallback}`
|
|
138
|
+
: `Could not refresh model list; using ${fallback} (${e.message})`;
|
|
139
|
+
console.log(status("warn", message));
|
|
136
140
|
return MODEL_REGISTRY.modelDefs;
|
|
137
141
|
} finally {
|
|
138
142
|
clearTimeout(timer);
|
|
@@ -143,6 +147,20 @@ function currentClaudeDesktopApiKey() {
|
|
|
143
147
|
return String(process.env.CCDX_CLAUDE_DESKTOP_API_KEY || process.env.CCDX_PROXY_API_KEY || "").trim();
|
|
144
148
|
}
|
|
145
149
|
|
|
150
|
+
function syncClaudeDesktopProfileModels(modelDefs = MODEL_REGISTRY.modelDefs) {
|
|
151
|
+
const result = syncManagedClaudeDesktopModels({
|
|
152
|
+
port: ADAPTER_PORT,
|
|
153
|
+
host: ADAPTER_HOST,
|
|
154
|
+
modelIds: claudeDesktopModelIds(process.env, { modelDefs }),
|
|
155
|
+
});
|
|
156
|
+
if (result.updated) {
|
|
157
|
+
console.log(status("ok", `Updated Claude App profile models: ${result.modelIds.join(", ")}`));
|
|
158
|
+
} else if (result.error) {
|
|
159
|
+
console.log(status("warn", `Could not update Claude App profile models (${result.error.message})`));
|
|
160
|
+
}
|
|
161
|
+
return result;
|
|
162
|
+
}
|
|
163
|
+
|
|
146
164
|
async function reuseRunningAdapterIfAvailable() {
|
|
147
165
|
const running = await checkRunningAdapter({
|
|
148
166
|
port: ADAPTER_PORT,
|
|
@@ -228,6 +246,7 @@ try {
|
|
|
228
246
|
refresh: refreshClaudeDesktopModelDefs,
|
|
229
247
|
});
|
|
230
248
|
const claudeDesktopModelDefs = modelInitialization.modelDefs;
|
|
249
|
+
syncClaudeDesktopProfileModels(claudeDesktopModelDefs);
|
|
231
250
|
|
|
232
251
|
if (!isLoopbackHost(ADAPTER_HOST)) {
|
|
233
252
|
console.log(status("warn", `ADAPTER_HOST=${ADAPTER_HOST} exposes the adapter beyond loopback because CCDX_ALLOW_LAN=1 is set. Use only on trusted networks.`));
|
package/package.json
CHANGED
|
@@ -159,34 +159,92 @@ function readActiveProfile(paths) {
|
|
|
159
159
|
return readJsonFile(path.join(paths.configLibraryPath, `${appliedId}.json`), {});
|
|
160
160
|
}
|
|
161
161
|
|
|
162
|
-
|
|
162
|
+
function activeManagedProfile({
|
|
163
163
|
port = 2026,
|
|
164
164
|
host = "127.0.0.1",
|
|
165
165
|
home = os.homedir(),
|
|
166
166
|
platform = process.platform,
|
|
167
167
|
env = process.env,
|
|
168
168
|
} = {}) {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
169
|
+
const paths = claudeDesktopPaths(home, platform, env);
|
|
170
|
+
const meta = readJsonFile(paths.metaPath, {});
|
|
171
|
+
if (String(meta.appliedId || "").trim() !== DEFAULT_CLAUDE_DESKTOP_PROFILE_ID) return null;
|
|
172
|
+
|
|
173
|
+
const profilePath = path.join(paths.configLibraryPath, `${DEFAULT_CLAUDE_DESKTOP_PROFILE_ID}.json`);
|
|
174
|
+
const profile = readJsonFile(profilePath, {});
|
|
175
|
+
if (profile.inferenceProvider !== "gateway") return null;
|
|
176
|
+
if (String(profile.inferenceGatewayAuthScheme || "").trim().toLowerCase() !== "bearer") return null;
|
|
173
177
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
+
const profileBaseUrl = String(profile.inferenceGatewayBaseUrl || "").trim();
|
|
179
|
+
validateClaudeDesktopBaseUrl(profileBaseUrl);
|
|
180
|
+
if (new URL(profileBaseUrl).href !== new URL(localGatewayBaseUrl(host, port)).href) return null;
|
|
181
|
+
|
|
182
|
+
return { profilePath, profile };
|
|
183
|
+
}
|
|
178
184
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
185
|
+
function normalizedModelIds(modelIds) {
|
|
186
|
+
const ids = [];
|
|
187
|
+
const seen = new Set();
|
|
188
|
+
for (const value of Array.isArray(modelIds) ? modelIds : []) {
|
|
189
|
+
const id = String(value || "").trim();
|
|
190
|
+
if (!id || seen.has(id)) continue;
|
|
191
|
+
ids.push(id);
|
|
192
|
+
seen.add(id);
|
|
193
|
+
}
|
|
194
|
+
return ids;
|
|
195
|
+
}
|
|
182
196
|
|
|
183
|
-
|
|
197
|
+
export function loadManagedClaudeDesktopApiKey({
|
|
198
|
+
port = 2026,
|
|
199
|
+
host = "127.0.0.1",
|
|
200
|
+
home = os.homedir(),
|
|
201
|
+
platform = process.platform,
|
|
202
|
+
env = process.env,
|
|
203
|
+
} = {}) {
|
|
204
|
+
try {
|
|
205
|
+
const managed = activeManagedProfile({ port, host, home, platform, env });
|
|
206
|
+
const apiKey = String(managed?.profile.inferenceGatewayApiKey || "").trim();
|
|
184
207
|
return apiKey && apiKey !== "dummy" ? apiKey : "";
|
|
185
208
|
} catch {
|
|
186
209
|
return "";
|
|
187
210
|
}
|
|
188
211
|
}
|
|
189
212
|
|
|
213
|
+
export function syncManagedClaudeDesktopModels({
|
|
214
|
+
modelIds,
|
|
215
|
+
port = 2026,
|
|
216
|
+
host = "127.0.0.1",
|
|
217
|
+
home = os.homedir(),
|
|
218
|
+
platform = process.platform,
|
|
219
|
+
env = process.env,
|
|
220
|
+
} = {}) {
|
|
221
|
+
const normalizedIds = normalizedModelIds(modelIds);
|
|
222
|
+
if (!normalizedIds.length) return { updated: false, reason: "empty-model-list", modelIds: normalizedIds };
|
|
223
|
+
|
|
224
|
+
try {
|
|
225
|
+
const managed = activeManagedProfile({ port, host, home, platform, env });
|
|
226
|
+
if (!managed) return { updated: false, reason: "not-managed", modelIds: normalizedIds };
|
|
227
|
+
|
|
228
|
+
const inferenceModels = JSON.stringify(normalizedIds);
|
|
229
|
+
if (managed.profile.inferenceModels === inferenceModels) {
|
|
230
|
+
return { updated: false, reason: "unchanged", profilePath: managed.profilePath, modelIds: normalizedIds };
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const updated = writeJsonFile(managed.profilePath, {
|
|
234
|
+
...managed.profile,
|
|
235
|
+
inferenceModels,
|
|
236
|
+
});
|
|
237
|
+
return {
|
|
238
|
+
updated,
|
|
239
|
+
reason: updated ? "updated" : "unchanged",
|
|
240
|
+
profilePath: managed.profilePath,
|
|
241
|
+
modelIds: normalizedIds,
|
|
242
|
+
};
|
|
243
|
+
} catch (error) {
|
|
244
|
+
return { updated: false, reason: "error", error, modelIds: normalizedIds };
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
190
248
|
export function applyClaudeDesktopConfig({
|
|
191
249
|
port = 2026,
|
|
192
250
|
host = "127.0.0.1",
|
package/src/startup.mjs
CHANGED
|
@@ -2,16 +2,12 @@ export async function initializeModelRegistry({
|
|
|
2
2
|
loadCached,
|
|
3
3
|
currentModelDefs,
|
|
4
4
|
refresh,
|
|
5
|
-
onBackgroundError = () => {},
|
|
6
5
|
}) {
|
|
7
|
-
if (
|
|
8
|
-
return { modelDefs:
|
|
6
|
+
if (loadCached()) {
|
|
7
|
+
return { modelDefs: currentModelDefs(), source: "cache", backgroundRefresh: null };
|
|
9
8
|
}
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
.then(refresh)
|
|
13
|
-
.catch(onBackgroundError);
|
|
14
|
-
return { modelDefs: currentModelDefs(), source: "cache", backgroundRefresh };
|
|
10
|
+
return { modelDefs: await refresh(), source: "live", backgroundRefresh: null };
|
|
15
11
|
}
|
|
16
12
|
|
|
17
13
|
export function runInBackground(task, onError = () => {}) {
|