copilot-hub 0.1.26 → 0.1.28
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.
|
@@ -146,7 +146,7 @@ function resolveCodexBin(rawValue) {
|
|
|
146
146
|
const value = String(rawValue ?? "").trim();
|
|
147
147
|
const normalized = value.toLowerCase();
|
|
148
148
|
if (value && normalized !== "codex") {
|
|
149
|
-
return value;
|
|
149
|
+
return normalizeConfiguredCodexBin(value);
|
|
150
150
|
}
|
|
151
151
|
if (process.platform === "win32") {
|
|
152
152
|
const npmGlobalCodex = findWindowsNpmGlobalCodexBin();
|
|
@@ -160,6 +160,24 @@ function resolveCodexBin(rawValue) {
|
|
|
160
160
|
}
|
|
161
161
|
return value || "codex";
|
|
162
162
|
}
|
|
163
|
+
function normalizeConfiguredCodexBin(value) {
|
|
164
|
+
const normalizedValue = String(value ?? "").trim();
|
|
165
|
+
if (process.platform !== "win32" || !normalizedValue) {
|
|
166
|
+
return normalizedValue;
|
|
167
|
+
}
|
|
168
|
+
const basename = path.win32.basename(normalizedValue).toLowerCase();
|
|
169
|
+
if (basename !== "codex.cmd" && basename !== "codex.bat") {
|
|
170
|
+
return normalizedValue;
|
|
171
|
+
}
|
|
172
|
+
if (path.win32.isAbsolute(normalizedValue)) {
|
|
173
|
+
const wrapperDir = path.win32.dirname(normalizedValue);
|
|
174
|
+
const entrypoint = path.win32.join(wrapperDir, "node_modules", "@openai", "codex", "bin", "codex.js");
|
|
175
|
+
if (fs.existsSync(entrypoint)) {
|
|
176
|
+
return entrypoint;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return findWindowsNpmGlobalCodexBin() || normalizedValue;
|
|
180
|
+
}
|
|
163
181
|
function findVscodeCodexExe() {
|
|
164
182
|
const userProfile = process.env.USERPROFILE;
|
|
165
183
|
if (!userProfile) {
|
|
@@ -153,7 +153,7 @@ function resolveCodexBin(rawValue) {
|
|
|
153
153
|
const value = String(rawValue ?? "").trim();
|
|
154
154
|
const normalized = value.toLowerCase();
|
|
155
155
|
if (value && normalized !== "codex") {
|
|
156
|
-
return value;
|
|
156
|
+
return normalizeConfiguredCodexBin(value);
|
|
157
157
|
}
|
|
158
158
|
if (process.platform === "win32") {
|
|
159
159
|
const npmGlobalCodex = findWindowsNpmGlobalCodexBin();
|
|
@@ -167,6 +167,24 @@ function resolveCodexBin(rawValue) {
|
|
|
167
167
|
}
|
|
168
168
|
return value || "codex";
|
|
169
169
|
}
|
|
170
|
+
function normalizeConfiguredCodexBin(value) {
|
|
171
|
+
const normalizedValue = String(value ?? "").trim();
|
|
172
|
+
if (process.platform !== "win32" || !normalizedValue) {
|
|
173
|
+
return normalizedValue;
|
|
174
|
+
}
|
|
175
|
+
const basename = path.win32.basename(normalizedValue).toLowerCase();
|
|
176
|
+
if (basename !== "codex.cmd" && basename !== "codex.bat") {
|
|
177
|
+
return normalizedValue;
|
|
178
|
+
}
|
|
179
|
+
if (path.win32.isAbsolute(normalizedValue)) {
|
|
180
|
+
const wrapperDir = path.win32.dirname(normalizedValue);
|
|
181
|
+
const entrypoint = path.win32.join(wrapperDir, "node_modules", "@openai", "codex", "bin", "codex.js");
|
|
182
|
+
if (fs.existsSync(entrypoint)) {
|
|
183
|
+
return entrypoint;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return findWindowsNpmGlobalCodexBin() || normalizedValue;
|
|
187
|
+
}
|
|
170
188
|
function findVscodeCodexExe() {
|
|
171
189
|
const userProfile = process.env.USERPROFILE;
|
|
172
190
|
if (!userProfile) {
|
package/package.json
CHANGED
|
@@ -42,9 +42,9 @@ export function resolveCodexBinForStart({ repoRoot, agentEngineEnvPath, controlP
|
|
|
42
42
|
userConfigured: false,
|
|
43
43
|
};
|
|
44
44
|
}
|
|
45
|
-
export function resolveCompatibleInstalledCodexBin({ repoRoot, env = process.env, }) {
|
|
45
|
+
export function resolveCompatibleInstalledCodexBin({ repoRoot, env = process.env, platform = process.platform, }) {
|
|
46
46
|
const matches = [];
|
|
47
|
-
for (const candidate of listCodexBinCandidates(env, repoRoot)) {
|
|
47
|
+
for (const candidate of listCodexBinCandidates(env, repoRoot, platform)) {
|
|
48
48
|
const probe = probeCodexVersion({
|
|
49
49
|
codexBin: candidate,
|
|
50
50
|
repoRoot,
|
|
@@ -55,7 +55,7 @@ export function resolveCompatibleInstalledCodexBin({ repoRoot, env = process.env
|
|
|
55
55
|
matches.push({
|
|
56
56
|
candidate,
|
|
57
57
|
version: probe.version,
|
|
58
|
-
priority: getCodexCandidatePriority(candidate, env, repoRoot),
|
|
58
|
+
priority: getCodexCandidatePriority(candidate, env, repoRoot, platform),
|
|
59
59
|
});
|
|
60
60
|
}
|
|
61
61
|
if (matches.length === 0) {
|
|
@@ -134,12 +134,17 @@ export function buildCodexCompatibilityError({ resolved, probe, includeInstallHi
|
|
|
134
134
|
return lines.join("\n");
|
|
135
135
|
}
|
|
136
136
|
function buildResolvedCodexBin({ value, source, env, repoRoot, }) {
|
|
137
|
-
const
|
|
137
|
+
const normalizedValue = normalizeConfiguredCodexBin({
|
|
138
|
+
value,
|
|
139
|
+
env,
|
|
140
|
+
repoRoot,
|
|
141
|
+
});
|
|
142
|
+
const normalized = String(normalizedValue ?? "")
|
|
138
143
|
.trim()
|
|
139
144
|
.toLowerCase();
|
|
140
145
|
if (normalized && normalized !== "codex") {
|
|
141
146
|
return {
|
|
142
|
-
bin:
|
|
147
|
+
bin: normalizedValue,
|
|
143
148
|
source,
|
|
144
149
|
userConfigured: true,
|
|
145
150
|
};
|
|
@@ -151,20 +156,43 @@ function buildResolvedCodexBin({ value, source, env, repoRoot, }) {
|
|
|
151
156
|
userConfigured: false,
|
|
152
157
|
};
|
|
153
158
|
}
|
|
159
|
+
export function normalizeConfiguredCodexBin({ value, env = process.env, repoRoot, platform = process.platform, }) {
|
|
160
|
+
const normalizedValue = String(value ?? "").trim();
|
|
161
|
+
if (!normalizedValue || platform !== "win32") {
|
|
162
|
+
return normalizedValue;
|
|
163
|
+
}
|
|
164
|
+
const normalizedBasename = path.win32.basename(normalizedValue).toLowerCase();
|
|
165
|
+
if (normalizedBasename !== "codex.cmd" && normalizedBasename !== "codex.bat") {
|
|
166
|
+
return normalizedValue;
|
|
167
|
+
}
|
|
168
|
+
if (path.win32.isAbsolute(normalizedValue)) {
|
|
169
|
+
const pathModule = selectPathModule(normalizedValue);
|
|
170
|
+
const wrapperDir = pathModule.dirname(normalizedValue);
|
|
171
|
+
const entrypoint = pathModule.join(wrapperDir, "node_modules", "@openai", "codex", "bin", "codex.js");
|
|
172
|
+
if (fs.existsSync(entrypoint)) {
|
|
173
|
+
return entrypoint;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return findWindowsNpmGlobalCodexBin(env, repoRoot, platform) || normalizedValue;
|
|
177
|
+
}
|
|
154
178
|
function findDetectedCodexBin(env, repoRoot) {
|
|
155
179
|
if (process.platform !== "win32") {
|
|
156
180
|
return "";
|
|
157
181
|
}
|
|
158
|
-
return findWindowsNpmGlobalCodexBin(env, repoRoot) || findVscodeCodexExe(env) || "";
|
|
182
|
+
return (findWindowsNpmGlobalCodexBin(env, repoRoot, process.platform) || findVscodeCodexExe(env) || "");
|
|
159
183
|
}
|
|
160
|
-
function listCodexBinCandidates(env, repoRoot) {
|
|
161
|
-
return dedupe([
|
|
184
|
+
function listCodexBinCandidates(env, repoRoot, platform) {
|
|
185
|
+
return dedupe([
|
|
186
|
+
"codex",
|
|
187
|
+
findWindowsNpmGlobalCodexBin(env, repoRoot, platform),
|
|
188
|
+
findVscodeCodexExe(env),
|
|
189
|
+
]);
|
|
162
190
|
}
|
|
163
|
-
function getCodexCandidatePriority(candidate, env, repoRoot) {
|
|
191
|
+
function getCodexCandidatePriority(candidate, env, repoRoot, platform) {
|
|
164
192
|
if (candidate === "codex") {
|
|
165
193
|
return 0;
|
|
166
194
|
}
|
|
167
|
-
const npmGlobal = findWindowsNpmGlobalCodexBin(env, repoRoot);
|
|
195
|
+
const npmGlobal = findWindowsNpmGlobalCodexBin(env, repoRoot, platform);
|
|
168
196
|
if (npmGlobal && candidate === npmGlobal) {
|
|
169
197
|
return 1;
|
|
170
198
|
}
|
|
@@ -198,8 +226,8 @@ function findVscodeCodexExe(env) {
|
|
|
198
226
|
}
|
|
199
227
|
return "";
|
|
200
228
|
}
|
|
201
|
-
function findWindowsNpmGlobalCodexBin(env, repoRoot) {
|
|
202
|
-
if (
|
|
229
|
+
function findWindowsNpmGlobalCodexBin(env, repoRoot, platform) {
|
|
230
|
+
if (platform !== "win32") {
|
|
203
231
|
return "";
|
|
204
232
|
}
|
|
205
233
|
const packageRoots = [];
|
|
@@ -231,6 +259,13 @@ function findWindowsNpmGlobalCodexBin(env, repoRoot) {
|
|
|
231
259
|
}
|
|
232
260
|
return "";
|
|
233
261
|
}
|
|
262
|
+
function selectPathModule(filePath) {
|
|
263
|
+
const normalized = String(filePath ?? "").trim();
|
|
264
|
+
if (/^[A-Za-z]:[\\/]/.test(normalized) || normalized.includes("\\")) {
|
|
265
|
+
return path.win32;
|
|
266
|
+
}
|
|
267
|
+
return path.posix;
|
|
268
|
+
}
|
|
234
269
|
function readNpmPrefix(repoRoot) {
|
|
235
270
|
const result = spawnNpm(["config", "get", "prefix"], repoRoot);
|
|
236
271
|
if (result.error || result.status !== 0) {
|
|
@@ -82,13 +82,15 @@ export function resolveCodexBinForStart({
|
|
|
82
82
|
export function resolveCompatibleInstalledCodexBin({
|
|
83
83
|
repoRoot,
|
|
84
84
|
env = process.env,
|
|
85
|
+
platform = process.platform,
|
|
85
86
|
}: {
|
|
86
87
|
repoRoot: string;
|
|
87
88
|
env?: NodeJS.ProcessEnv;
|
|
89
|
+
platform?: NodeJS.Platform;
|
|
88
90
|
}): string {
|
|
89
91
|
const matches: Array<{ candidate: string; version: string; priority: number }> = [];
|
|
90
92
|
|
|
91
|
-
for (const candidate of listCodexBinCandidates(env, repoRoot)) {
|
|
93
|
+
for (const candidate of listCodexBinCandidates(env, repoRoot, platform)) {
|
|
92
94
|
const probe = probeCodexVersion({
|
|
93
95
|
codexBin: candidate,
|
|
94
96
|
repoRoot,
|
|
@@ -100,7 +102,7 @@ export function resolveCompatibleInstalledCodexBin({
|
|
|
100
102
|
matches.push({
|
|
101
103
|
candidate,
|
|
102
104
|
version: probe.version,
|
|
103
|
-
priority: getCodexCandidatePriority(candidate, env, repoRoot),
|
|
105
|
+
priority: getCodexCandidatePriority(candidate, env, repoRoot, platform),
|
|
104
106
|
});
|
|
105
107
|
}
|
|
106
108
|
|
|
@@ -230,12 +232,17 @@ function buildResolvedCodexBin({
|
|
|
230
232
|
env: NodeJS.ProcessEnv;
|
|
231
233
|
repoRoot: string;
|
|
232
234
|
}): ResolvedCodexBin {
|
|
233
|
-
const
|
|
235
|
+
const normalizedValue = normalizeConfiguredCodexBin({
|
|
236
|
+
value,
|
|
237
|
+
env,
|
|
238
|
+
repoRoot,
|
|
239
|
+
});
|
|
240
|
+
const normalized = String(normalizedValue ?? "")
|
|
234
241
|
.trim()
|
|
235
242
|
.toLowerCase();
|
|
236
243
|
if (normalized && normalized !== "codex") {
|
|
237
244
|
return {
|
|
238
|
-
bin:
|
|
245
|
+
bin: normalizedValue,
|
|
239
246
|
source,
|
|
240
247
|
userConfigured: true,
|
|
241
248
|
};
|
|
@@ -249,28 +256,79 @@ function buildResolvedCodexBin({
|
|
|
249
256
|
};
|
|
250
257
|
}
|
|
251
258
|
|
|
259
|
+
export function normalizeConfiguredCodexBin({
|
|
260
|
+
value,
|
|
261
|
+
env = process.env,
|
|
262
|
+
repoRoot,
|
|
263
|
+
platform = process.platform,
|
|
264
|
+
}: {
|
|
265
|
+
value: string;
|
|
266
|
+
env?: NodeJS.ProcessEnv;
|
|
267
|
+
repoRoot: string;
|
|
268
|
+
platform?: NodeJS.Platform;
|
|
269
|
+
}): string {
|
|
270
|
+
const normalizedValue = String(value ?? "").trim();
|
|
271
|
+
if (!normalizedValue || platform !== "win32") {
|
|
272
|
+
return normalizedValue;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const normalizedBasename = path.win32.basename(normalizedValue).toLowerCase();
|
|
276
|
+
if (normalizedBasename !== "codex.cmd" && normalizedBasename !== "codex.bat") {
|
|
277
|
+
return normalizedValue;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
if (path.win32.isAbsolute(normalizedValue)) {
|
|
281
|
+
const pathModule = selectPathModule(normalizedValue);
|
|
282
|
+
const wrapperDir = pathModule.dirname(normalizedValue);
|
|
283
|
+
const entrypoint = pathModule.join(
|
|
284
|
+
wrapperDir,
|
|
285
|
+
"node_modules",
|
|
286
|
+
"@openai",
|
|
287
|
+
"codex",
|
|
288
|
+
"bin",
|
|
289
|
+
"codex.js",
|
|
290
|
+
);
|
|
291
|
+
if (fs.existsSync(entrypoint)) {
|
|
292
|
+
return entrypoint;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
return findWindowsNpmGlobalCodexBin(env, repoRoot, platform) || normalizedValue;
|
|
297
|
+
}
|
|
298
|
+
|
|
252
299
|
function findDetectedCodexBin(env: NodeJS.ProcessEnv, repoRoot: string): string {
|
|
253
300
|
if (process.platform !== "win32") {
|
|
254
301
|
return "";
|
|
255
302
|
}
|
|
256
303
|
|
|
257
|
-
return
|
|
304
|
+
return (
|
|
305
|
+
findWindowsNpmGlobalCodexBin(env, repoRoot, process.platform) || findVscodeCodexExe(env) || ""
|
|
306
|
+
);
|
|
258
307
|
}
|
|
259
308
|
|
|
260
|
-
function listCodexBinCandidates(
|
|
261
|
-
|
|
309
|
+
function listCodexBinCandidates(
|
|
310
|
+
env: NodeJS.ProcessEnv,
|
|
311
|
+
repoRoot: string,
|
|
312
|
+
platform: NodeJS.Platform,
|
|
313
|
+
): string[] {
|
|
314
|
+
return dedupe([
|
|
315
|
+
"codex",
|
|
316
|
+
findWindowsNpmGlobalCodexBin(env, repoRoot, platform),
|
|
317
|
+
findVscodeCodexExe(env),
|
|
318
|
+
]);
|
|
262
319
|
}
|
|
263
320
|
|
|
264
321
|
function getCodexCandidatePriority(
|
|
265
322
|
candidate: string,
|
|
266
323
|
env: NodeJS.ProcessEnv,
|
|
267
324
|
repoRoot: string,
|
|
325
|
+
platform: NodeJS.Platform,
|
|
268
326
|
): number {
|
|
269
327
|
if (candidate === "codex") {
|
|
270
328
|
return 0;
|
|
271
329
|
}
|
|
272
330
|
|
|
273
|
-
const npmGlobal = findWindowsNpmGlobalCodexBin(env, repoRoot);
|
|
331
|
+
const npmGlobal = findWindowsNpmGlobalCodexBin(env, repoRoot, platform);
|
|
274
332
|
if (npmGlobal && candidate === npmGlobal) {
|
|
275
333
|
return 1;
|
|
276
334
|
}
|
|
@@ -312,8 +370,12 @@ function findVscodeCodexExe(env: NodeJS.ProcessEnv): string {
|
|
|
312
370
|
return "";
|
|
313
371
|
}
|
|
314
372
|
|
|
315
|
-
function findWindowsNpmGlobalCodexBin(
|
|
316
|
-
|
|
373
|
+
function findWindowsNpmGlobalCodexBin(
|
|
374
|
+
env: NodeJS.ProcessEnv,
|
|
375
|
+
repoRoot: string,
|
|
376
|
+
platform: NodeJS.Platform,
|
|
377
|
+
): string {
|
|
378
|
+
if (platform !== "win32") {
|
|
317
379
|
return "";
|
|
318
380
|
}
|
|
319
381
|
|
|
@@ -351,6 +413,14 @@ function findWindowsNpmGlobalCodexBin(env: NodeJS.ProcessEnv, repoRoot: string):
|
|
|
351
413
|
return "";
|
|
352
414
|
}
|
|
353
415
|
|
|
416
|
+
function selectPathModule(filePath: string): typeof path.posix | typeof path.win32 {
|
|
417
|
+
const normalized = String(filePath ?? "").trim();
|
|
418
|
+
if (/^[A-Za-z]:[\\/]/.test(normalized) || normalized.includes("\\")) {
|
|
419
|
+
return path.win32;
|
|
420
|
+
}
|
|
421
|
+
return path.posix;
|
|
422
|
+
}
|
|
423
|
+
|
|
354
424
|
function readNpmPrefix(repoRoot: string): string {
|
|
355
425
|
const result = spawnNpm(["config", "get", "prefix"], repoRoot);
|
|
356
426
|
if (result.error || result.status !== 0) {
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import test from "node:test";
|
|
6
|
+
import { normalizeConfiguredCodexBin } from "../dist/codex-runtime.mjs";
|
|
7
|
+
|
|
8
|
+
test("normalizeConfiguredCodexBin remaps absolute Windows npm wrappers to codex.js", () => {
|
|
9
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "copilot-hub-codex-bin-"));
|
|
10
|
+
const wrapperDir = path.join(tempDir, "npm");
|
|
11
|
+
const packageDir = path.join(wrapperDir, "node_modules", "@openai", "codex", "bin");
|
|
12
|
+
fs.mkdirSync(packageDir, { recursive: true });
|
|
13
|
+
|
|
14
|
+
const wrapperPath = path.join(wrapperDir, "codex.cmd");
|
|
15
|
+
const entrypointPath = path.join(packageDir, "codex.js");
|
|
16
|
+
fs.writeFileSync(wrapperPath, "@echo off\r\n", "utf8");
|
|
17
|
+
fs.writeFileSync(entrypointPath, "console.log('ok');\n", "utf8");
|
|
18
|
+
|
|
19
|
+
const resolved = normalizeConfiguredCodexBin({
|
|
20
|
+
value: wrapperPath,
|
|
21
|
+
env: {},
|
|
22
|
+
repoRoot: tempDir,
|
|
23
|
+
platform: "win32",
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
assert.equal(resolved, entrypointPath);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("normalizeConfiguredCodexBin resolves bare codex.cmd through detected npm install", () => {
|
|
30
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "copilot-hub-codex-bin-"));
|
|
31
|
+
const appDataDir = path.join(tempDir, "AppData", "Roaming");
|
|
32
|
+
const packageDir = path.join(appDataDir, "npm", "node_modules", "@openai", "codex", "bin");
|
|
33
|
+
fs.mkdirSync(packageDir, { recursive: true });
|
|
34
|
+
|
|
35
|
+
const entrypointPath = path.join(packageDir, "codex.js");
|
|
36
|
+
fs.writeFileSync(entrypointPath, "console.log('ok');\n", "utf8");
|
|
37
|
+
|
|
38
|
+
const resolved = normalizeConfiguredCodexBin({
|
|
39
|
+
value: "codex.cmd",
|
|
40
|
+
env: {
|
|
41
|
+
APPDATA: appDataDir,
|
|
42
|
+
},
|
|
43
|
+
repoRoot: tempDir,
|
|
44
|
+
platform: "win32",
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
assert.equal(resolved, entrypointPath);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test("normalizeConfiguredCodexBin preserves non-wrapper commands", () => {
|
|
51
|
+
const resolved = normalizeConfiguredCodexBin({
|
|
52
|
+
value: "C:/tools/codex.exe",
|
|
53
|
+
env: {},
|
|
54
|
+
repoRoot: process.cwd(),
|
|
55
|
+
platform: "win32",
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
assert.equal(resolved, "C:/tools/codex.exe");
|
|
59
|
+
});
|