copilot-hub 0.1.26 → 0.1.29
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/apps/agent-engine/dist/config.js +30 -18
- package/apps/control-plane/.env.example +2 -3
- package/apps/control-plane/dist/config.js +30 -18
- package/apps/control-plane/dist/copilot-hub.js +16 -4
- package/apps/control-plane/dist/hub-token-config.js +37 -0
- package/apps/control-plane/dist/test/hub-token-config.test.js +46 -0
- package/package.json +1 -1
- package/packages/core/dist/env-config.d.ts +10 -0
- package/packages/core/dist/env-config.js +66 -0
- package/packages/core/dist/env-config.js.map +1 -0
- package/packages/core/dist/index.d.ts +2 -1
- package/packages/core/dist/index.js +2 -1
- package/packages/core/dist/index.js.map +1 -1
- package/packages/core/dist/workspace-paths.d.ts +12 -1
- package/packages/core/dist/workspace-paths.js +30 -6
- package/packages/core/dist/workspace-paths.js.map +1 -1
- package/packages/core/package.json +4 -0
- package/scripts/dist/codex-runtime.mjs +47 -12
- package/scripts/dist/configure.mjs +21 -7
- package/scripts/dist/daemon.mjs +17 -0
- package/scripts/src/codex-runtime.mts +80 -10
- package/scripts/src/configure.mts +27 -15
- package/scripts/src/daemon.mts +28 -0
- package/scripts/test/codex-runtime.test.mjs +59 -0
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { spawnSync } from "node:child_process";
|
|
4
|
-
import dotenv from "dotenv";
|
|
5
4
|
import { createWorkspaceBoundaryPolicy, assertWorkspaceAllowed, parseWorkspaceAllowedRoots, } from "@copilot-hub/core/workspace-policy";
|
|
6
5
|
import { parseTurnActivityTimeoutSetting } from "@copilot-hub/core/codex-app-utils";
|
|
7
|
-
import {
|
|
6
|
+
import { loadCopilotHubEnvironment } from "@copilot-hub/core";
|
|
7
|
+
import { resolveOptionalPathFromBase, resolvePathFromBase } from "@copilot-hub/core/config-paths";
|
|
8
8
|
import { getDefaultExternalWorkspaceBasePath, getKernelRootPath, } from "@copilot-hub/core/workspace-paths";
|
|
9
|
-
const
|
|
9
|
+
const loadedEnvironment = loadEnvironment();
|
|
10
|
+
const envBaseDir = loadedEnvironment.baseDir;
|
|
11
|
+
const envFilePath = loadedEnvironment.envPath;
|
|
12
|
+
const envFileValues = loadedEnvironment.fileValues;
|
|
13
|
+
const envOverrideKeys = loadedEnvironment.overriddenKeys;
|
|
10
14
|
const kernelRootPath = getKernelRootPath();
|
|
11
15
|
const configuredDefaultWorkspaceRoot = String(process.env.DEFAULT_WORKSPACE_ROOT ?? "").trim();
|
|
12
16
|
const defaultWorkspaceRoot = resolveWorkspaceRoot(configuredDefaultWorkspaceRoot || getDefaultExternalWorkspaceBasePath(kernelRootPath));
|
|
@@ -85,6 +89,9 @@ const defaultAllowedChatIds = new Set((process.env.TELEGRAM_ALLOWED_CHAT_IDS ??
|
|
|
85
89
|
fs.mkdirSync(dataDir, { recursive: true });
|
|
86
90
|
export const config = {
|
|
87
91
|
envBaseDir,
|
|
92
|
+
envFilePath,
|
|
93
|
+
envFileValues,
|
|
94
|
+
envOverrideKeys,
|
|
88
95
|
defaultProviderKind,
|
|
89
96
|
providerDefaults: {
|
|
90
97
|
defaultKind: defaultProviderKind,
|
|
@@ -125,28 +132,15 @@ export const config = {
|
|
|
125
132
|
defaultAllowedChatIds,
|
|
126
133
|
};
|
|
127
134
|
function loadEnvironment() {
|
|
128
|
-
|
|
129
|
-
const resolvedEnvPath = configuredEnvPath ? path.resolve(configuredEnvPath) : "";
|
|
130
|
-
const baseDir = resolveConfigBaseDir({
|
|
131
|
-
configuredBaseDir: process.env.COPILOT_HUB_ENV_BASE_DIR,
|
|
132
|
-
configuredEnvPath: resolvedEnvPath,
|
|
135
|
+
return loadCopilotHubEnvironment({
|
|
133
136
|
cwd: process.cwd(),
|
|
134
137
|
});
|
|
135
|
-
if (configuredEnvPath) {
|
|
136
|
-
process.env.COPILOT_HUB_ENV_PATH = resolvedEnvPath;
|
|
137
|
-
dotenv.config({ path: resolvedEnvPath });
|
|
138
|
-
}
|
|
139
|
-
else {
|
|
140
|
-
dotenv.config();
|
|
141
|
-
}
|
|
142
|
-
process.env.COPILOT_HUB_ENV_BASE_DIR = baseDir;
|
|
143
|
-
return baseDir;
|
|
144
138
|
}
|
|
145
139
|
function resolveCodexBin(rawValue) {
|
|
146
140
|
const value = String(rawValue ?? "").trim();
|
|
147
141
|
const normalized = value.toLowerCase();
|
|
148
142
|
if (value && normalized !== "codex") {
|
|
149
|
-
return value;
|
|
143
|
+
return normalizeConfiguredCodexBin(value);
|
|
150
144
|
}
|
|
151
145
|
if (process.platform === "win32") {
|
|
152
146
|
const npmGlobalCodex = findWindowsNpmGlobalCodexBin();
|
|
@@ -160,6 +154,24 @@ function resolveCodexBin(rawValue) {
|
|
|
160
154
|
}
|
|
161
155
|
return value || "codex";
|
|
162
156
|
}
|
|
157
|
+
function normalizeConfiguredCodexBin(value) {
|
|
158
|
+
const normalizedValue = String(value ?? "").trim();
|
|
159
|
+
if (process.platform !== "win32" || !normalizedValue) {
|
|
160
|
+
return normalizedValue;
|
|
161
|
+
}
|
|
162
|
+
const basename = path.win32.basename(normalizedValue).toLowerCase();
|
|
163
|
+
if (basename !== "codex.cmd" && basename !== "codex.bat") {
|
|
164
|
+
return normalizedValue;
|
|
165
|
+
}
|
|
166
|
+
if (path.win32.isAbsolute(normalizedValue)) {
|
|
167
|
+
const wrapperDir = path.win32.dirname(normalizedValue);
|
|
168
|
+
const entrypoint = path.win32.join(wrapperDir, "node_modules", "@openai", "codex", "bin", "codex.js");
|
|
169
|
+
if (fs.existsSync(entrypoint)) {
|
|
170
|
+
return entrypoint;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return findWindowsNpmGlobalCodexBin() || normalizedValue;
|
|
174
|
+
}
|
|
163
175
|
function findVscodeCodexExe() {
|
|
164
176
|
const userProfile = process.env.USERPROFILE;
|
|
165
177
|
if (!userProfile) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
HUB_TELEGRAM_TOKEN_ENV=HUB_TELEGRAM_TOKEN_FILE
|
|
2
|
+
HUB_TELEGRAM_TOKEN_FILE=123456:replace_me
|
|
3
3
|
HUB_ID=copilot_hub
|
|
4
4
|
HUB_NAME=Copilot Hub
|
|
5
5
|
# Optional. If empty, defaults to Desktop/copilot_workspaces (Windows/macOS/Linux)
|
|
@@ -21,4 +21,3 @@ CODEX_SANDBOX=danger-full-access
|
|
|
21
21
|
CODEX_APPROVAL_POLICY=never
|
|
22
22
|
TURN_ACTIVITY_TIMEOUT_MS=0
|
|
23
23
|
MAX_THREAD_MESSAGES=200
|
|
24
|
-
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { spawnSync } from "node:child_process";
|
|
4
|
-
import
|
|
4
|
+
import { loadCopilotHubEnvironment } from "@copilot-hub/core";
|
|
5
5
|
import { parseTurnActivityTimeoutSetting } from "@copilot-hub/core/codex-app-utils";
|
|
6
|
-
import {
|
|
6
|
+
import { resolveOptionalPathFromBase, resolvePathFromBase } from "@copilot-hub/core/config-paths";
|
|
7
7
|
import { createWorkspaceBoundaryPolicy, assertWorkspaceAllowed, parseWorkspaceAllowedRoots, } from "@copilot-hub/core/workspace-policy";
|
|
8
8
|
import { normalizeAdminBotId, normalizeAdminTokenEnv } from "./kernel/admin-contract.js";
|
|
9
9
|
import { getDefaultExternalWorkspaceBasePath, getKernelRootPath, } from "@copilot-hub/core/workspace-paths";
|
|
10
|
-
const
|
|
10
|
+
const loadedEnvironment = loadEnvironment();
|
|
11
|
+
const envBaseDir = loadedEnvironment.baseDir;
|
|
12
|
+
const envFilePath = loadedEnvironment.envPath;
|
|
13
|
+
const envFileValues = loadedEnvironment.fileValues;
|
|
14
|
+
const envOverrideKeys = loadedEnvironment.overriddenKeys;
|
|
11
15
|
const kernelRootPath = getKernelRootPath();
|
|
12
16
|
const configuredDefaultWorkspaceRoot = String(process.env.DEFAULT_WORKSPACE_ROOT ?? "").trim();
|
|
13
17
|
const defaultWorkspaceRoot = resolveWorkspaceRoot(configuredDefaultWorkspaceRoot || getDefaultExternalWorkspaceBasePath(kernelRootPath));
|
|
@@ -89,6 +93,9 @@ const defaultAllowedChatIds = new Set((process.env.TELEGRAM_ALLOWED_CHAT_IDS ??
|
|
|
89
93
|
fs.mkdirSync(dataDir, { recursive: true });
|
|
90
94
|
export const config = {
|
|
91
95
|
envBaseDir,
|
|
96
|
+
envFilePath,
|
|
97
|
+
envFileValues,
|
|
98
|
+
envOverrideKeys,
|
|
92
99
|
defaultProviderKind,
|
|
93
100
|
providerDefaults: {
|
|
94
101
|
defaultKind: defaultProviderKind,
|
|
@@ -132,28 +139,15 @@ export const config = {
|
|
|
132
139
|
defaultAllowedChatIds,
|
|
133
140
|
};
|
|
134
141
|
function loadEnvironment() {
|
|
135
|
-
|
|
136
|
-
const resolvedEnvPath = configuredEnvPath ? path.resolve(configuredEnvPath) : "";
|
|
137
|
-
const baseDir = resolveConfigBaseDir({
|
|
138
|
-
configuredBaseDir: process.env.COPILOT_HUB_ENV_BASE_DIR,
|
|
139
|
-
configuredEnvPath: resolvedEnvPath,
|
|
142
|
+
return loadCopilotHubEnvironment({
|
|
140
143
|
cwd: process.cwd(),
|
|
141
144
|
});
|
|
142
|
-
if (configuredEnvPath) {
|
|
143
|
-
process.env.COPILOT_HUB_ENV_PATH = resolvedEnvPath;
|
|
144
|
-
dotenv.config({ path: resolvedEnvPath });
|
|
145
|
-
}
|
|
146
|
-
else {
|
|
147
|
-
dotenv.config();
|
|
148
|
-
}
|
|
149
|
-
process.env.COPILOT_HUB_ENV_BASE_DIR = baseDir;
|
|
150
|
-
return baseDir;
|
|
151
145
|
}
|
|
152
146
|
function resolveCodexBin(rawValue) {
|
|
153
147
|
const value = String(rawValue ?? "").trim();
|
|
154
148
|
const normalized = value.toLowerCase();
|
|
155
149
|
if (value && normalized !== "codex") {
|
|
156
|
-
return value;
|
|
150
|
+
return normalizeConfiguredCodexBin(value);
|
|
157
151
|
}
|
|
158
152
|
if (process.platform === "win32") {
|
|
159
153
|
const npmGlobalCodex = findWindowsNpmGlobalCodexBin();
|
|
@@ -167,6 +161,24 @@ function resolveCodexBin(rawValue) {
|
|
|
167
161
|
}
|
|
168
162
|
return value || "codex";
|
|
169
163
|
}
|
|
164
|
+
function normalizeConfiguredCodexBin(value) {
|
|
165
|
+
const normalizedValue = String(value ?? "").trim();
|
|
166
|
+
if (process.platform !== "win32" || !normalizedValue) {
|
|
167
|
+
return normalizedValue;
|
|
168
|
+
}
|
|
169
|
+
const basename = path.win32.basename(normalizedValue).toLowerCase();
|
|
170
|
+
if (basename !== "codex.cmd" && basename !== "codex.bat") {
|
|
171
|
+
return normalizedValue;
|
|
172
|
+
}
|
|
173
|
+
if (path.win32.isAbsolute(normalizedValue)) {
|
|
174
|
+
const wrapperDir = path.win32.dirname(normalizedValue);
|
|
175
|
+
const entrypoint = path.win32.join(wrapperDir, "node_modules", "@openai", "codex", "bin", "codex.js");
|
|
176
|
+
if (fs.existsSync(entrypoint)) {
|
|
177
|
+
return entrypoint;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return findWindowsNpmGlobalCodexBin() || normalizedValue;
|
|
181
|
+
}
|
|
170
182
|
function findVscodeCodexExe() {
|
|
171
183
|
const userProfile = process.env.USERPROFILE;
|
|
172
184
|
if (!userProfile) {
|
|
@@ -3,16 +3,20 @@ import { BotRuntime } from "@copilot-hub/core/bot-runtime";
|
|
|
3
3
|
import { config } from "./config.js";
|
|
4
4
|
import { assertWorkspaceAllowed } from "@copilot-hub/core/workspace-policy";
|
|
5
5
|
import { createChannelAdapter } from "./channels/channel-factory.js";
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
|
|
6
|
+
import { isUsableTelegramToken, resolveHubTelegramToken } from "./hub-token-config.js";
|
|
7
|
+
const tokenResolution = resolveHubTelegramToken({
|
|
8
|
+
env: process.env,
|
|
9
|
+
envFileValues: config.envFileValues,
|
|
10
|
+
});
|
|
11
|
+
const tokenEnvName = tokenResolution.tokenEnvName;
|
|
12
|
+
const hubToken = tokenResolution.token;
|
|
9
13
|
if (!hubToken) {
|
|
10
14
|
throw new Error([
|
|
11
15
|
`Hub Telegram token is missing (${tokenEnvName}).`,
|
|
12
16
|
"Set this token to start copilot-hub.",
|
|
13
17
|
].join("\n"));
|
|
14
18
|
}
|
|
15
|
-
if (!
|
|
19
|
+
if (!isUsableTelegramToken(hubToken)) {
|
|
16
20
|
throw new Error([
|
|
17
21
|
`Hub Telegram token in ${tokenEnvName} is invalid.`,
|
|
18
22
|
"Run 'copilot-hub configure' and paste a real BotFather token.",
|
|
@@ -73,6 +77,14 @@ const runtime = new BotRuntime({
|
|
|
73
77
|
let shuttingDown = false;
|
|
74
78
|
await bootstrap();
|
|
75
79
|
async function bootstrap() {
|
|
80
|
+
for (const warning of tokenResolution.warnings) {
|
|
81
|
+
console.warn(`[copilot_hub] ${warning}`);
|
|
82
|
+
}
|
|
83
|
+
if (config.envOverrideKeys.includes("HUB_TELEGRAM_TOKEN_ENV") ||
|
|
84
|
+
config.envOverrideKeys.includes(tokenEnvName)) {
|
|
85
|
+
console.warn(`[copilot_hub] Config file '${config.envFilePath ?? ".env"}' overrode a pre-existing process environment value for the hub token settings.`);
|
|
86
|
+
}
|
|
87
|
+
console.log(`[copilot_hub] using hub Telegram token variable '${tokenEnvName}' from ${tokenResolution.source === "env_file" ? "config file" : "process environment"}.`);
|
|
76
88
|
await runtime.startChannels();
|
|
77
89
|
console.log(`[copilot_hub] online as '${hubId}' on workspace '${hubWorkspaceRoot}'.`);
|
|
78
90
|
registerSignals();
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const DEFAULT_HUB_TELEGRAM_TOKEN_ENV = "HUB_TELEGRAM_TOKEN_FILE";
|
|
2
|
+
const LEGACY_HUB_TELEGRAM_TOKEN_ENV = "HUB_TELEGRAM_TOKEN";
|
|
3
|
+
const TELEGRAM_TOKEN_PATTERN = /^\d{5,}:[A-Za-z0-9_-]{20,}$/;
|
|
4
|
+
export function resolveHubTelegramToken({ env = process.env, envFileValues = {}, } = {}) {
|
|
5
|
+
const fileTokenEnvName = String(envFileValues.HUB_TELEGRAM_TOKEN_ENV ?? "").trim();
|
|
6
|
+
const processTokenEnvName = String(env.HUB_TELEGRAM_TOKEN_ENV ?? "").trim();
|
|
7
|
+
const tokenEnvName = fileTokenEnvName || processTokenEnvName || DEFAULT_HUB_TELEGRAM_TOKEN_ENV;
|
|
8
|
+
const fileToken = String(envFileValues[tokenEnvName] ?? "").trim();
|
|
9
|
+
const processToken = String(env[tokenEnvName] ?? "").trim();
|
|
10
|
+
const token = fileToken || processToken;
|
|
11
|
+
const warnings = [];
|
|
12
|
+
if (fileTokenEnvName && processTokenEnvName && fileTokenEnvName !== processTokenEnvName) {
|
|
13
|
+
warnings.push(`Config file selects hub token variable '${fileTokenEnvName}', overriding pre-existing process env selector '${processTokenEnvName}'.`);
|
|
14
|
+
}
|
|
15
|
+
if (tokenEnvName === LEGACY_HUB_TELEGRAM_TOKEN_ENV) {
|
|
16
|
+
warnings.push(`Hub token variable '${LEGACY_HUB_TELEGRAM_TOKEN_ENV}' is deprecated. Run 'copilot-hub configure' to migrate to '${DEFAULT_HUB_TELEGRAM_TOKEN_ENV}'.`);
|
|
17
|
+
}
|
|
18
|
+
if (fileToken && processToken && fileToken !== processToken) {
|
|
19
|
+
const detail = isUsableTelegramToken(fileToken)
|
|
20
|
+
? `Using the token saved in the config file for '${tokenEnvName}' instead of the conflicting process environment value.`
|
|
21
|
+
: `Config file value for '${tokenEnvName}' overrides the conflicting process environment value.`;
|
|
22
|
+
warnings.push(detail);
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
tokenEnvName,
|
|
26
|
+
token,
|
|
27
|
+
source: fileToken ? "env_file" : "process_env",
|
|
28
|
+
warnings,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
export function isUsableTelegramToken(value) {
|
|
32
|
+
const token = String(value ?? "").trim();
|
|
33
|
+
if (!token || token.toLowerCase().includes("replace_me")) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
return TELEGRAM_TOKEN_PATTERN.test(token);
|
|
37
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
let configPromise = null;
|
|
4
|
+
async function loadConfig() {
|
|
5
|
+
if (!configPromise) {
|
|
6
|
+
const specifier = ["..", "hub-token-config.js"].join("/");
|
|
7
|
+
configPromise = import(specifier);
|
|
8
|
+
}
|
|
9
|
+
return configPromise;
|
|
10
|
+
}
|
|
11
|
+
test("resolveHubTelegramToken prefers the config file token over a conflicting process env token", async () => {
|
|
12
|
+
const { resolveHubTelegramToken } = await loadConfig();
|
|
13
|
+
const result = resolveHubTelegramToken({
|
|
14
|
+
env: {
|
|
15
|
+
HUB_TELEGRAM_TOKEN_ENV: "HUB_TELEGRAM_TOKEN",
|
|
16
|
+
HUB_TELEGRAM_TOKEN: "123456:invalid_process_value_ABCDEFGHIJKLM",
|
|
17
|
+
},
|
|
18
|
+
envFileValues: {
|
|
19
|
+
HUB_TELEGRAM_TOKEN_ENV: "HUB_TELEGRAM_TOKEN",
|
|
20
|
+
HUB_TELEGRAM_TOKEN: "123456:valid_file_value_ABCDEFGHIJKLMNOPQRSTUVWXYZ",
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
assert.equal(result.tokenEnvName, "HUB_TELEGRAM_TOKEN");
|
|
24
|
+
assert.equal(result.source, "env_file");
|
|
25
|
+
assert.equal(result.token, "123456:valid_file_value_ABCDEFGHIJKLMNOPQRSTUVWXYZ");
|
|
26
|
+
assert.match(result.warnings.join("\n"), /deprecated/i);
|
|
27
|
+
});
|
|
28
|
+
test("resolveHubTelegramToken uses the dedicated file token variable by default", async () => {
|
|
29
|
+
const { resolveHubTelegramToken } = await loadConfig();
|
|
30
|
+
const result = resolveHubTelegramToken({
|
|
31
|
+
env: {},
|
|
32
|
+
envFileValues: {
|
|
33
|
+
HUB_TELEGRAM_TOKEN_ENV: "HUB_TELEGRAM_TOKEN_FILE",
|
|
34
|
+
HUB_TELEGRAM_TOKEN_FILE: "123456:valid_file_value_ABCDEFGHIJKLMNOPQRSTUVWXYZ",
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
assert.equal(result.tokenEnvName, "HUB_TELEGRAM_TOKEN_FILE");
|
|
38
|
+
assert.equal(result.source, "env_file");
|
|
39
|
+
assert.equal(result.warnings.length, 0);
|
|
40
|
+
});
|
|
41
|
+
test("isUsableTelegramToken recognizes valid telegram token formats", async () => {
|
|
42
|
+
const { isUsableTelegramToken } = await loadConfig();
|
|
43
|
+
assert.equal(isUsableTelegramToken("123456:valid_file_value_ABCDEFGHIJKLMNOPQRSTUVWXYZ"), true);
|
|
44
|
+
assert.equal(isUsableTelegramToken("123456:replace_me"), false);
|
|
45
|
+
assert.equal(isUsableTelegramToken(""), false);
|
|
46
|
+
});
|
package/package.json
CHANGED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface LoadedCopilotHubEnvironment {
|
|
2
|
+
baseDir: string;
|
|
3
|
+
envPath: string | null;
|
|
4
|
+
fileValues: Record<string, string>;
|
|
5
|
+
overriddenKeys: string[];
|
|
6
|
+
}
|
|
7
|
+
export declare function loadCopilotHubEnvironment({ env, cwd, }?: {
|
|
8
|
+
env?: NodeJS.ProcessEnv;
|
|
9
|
+
cwd?: string;
|
|
10
|
+
}): LoadedCopilotHubEnvironment;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import process from "node:process";
|
|
4
|
+
import dotenv from "dotenv";
|
|
5
|
+
import { resolveConfigBaseDir } from "./config-paths.js";
|
|
6
|
+
export function loadCopilotHubEnvironment({ env = process.env, cwd = process.cwd(), } = {}) {
|
|
7
|
+
const configuredEnvPath = String(env.COPILOT_HUB_ENV_PATH ?? "").trim();
|
|
8
|
+
const resolvedEnvPath = configuredEnvPath ? path.resolve(configuredEnvPath) : "";
|
|
9
|
+
const discoveredEnvPath = resolvedEnvPath || resolveDefaultEnvPath(cwd);
|
|
10
|
+
const baseDir = resolveConfigBaseDir({
|
|
11
|
+
configuredBaseDir: env.COPILOT_HUB_ENV_BASE_DIR,
|
|
12
|
+
configuredEnvPath: discoveredEnvPath,
|
|
13
|
+
cwd,
|
|
14
|
+
});
|
|
15
|
+
const fileValues = loadEnvFileValues(discoveredEnvPath);
|
|
16
|
+
const overriddenKeys = applyEnvFileValues(env, fileValues);
|
|
17
|
+
if (resolvedEnvPath) {
|
|
18
|
+
env.COPILOT_HUB_ENV_PATH = resolvedEnvPath;
|
|
19
|
+
}
|
|
20
|
+
env.COPILOT_HUB_ENV_BASE_DIR = baseDir;
|
|
21
|
+
return {
|
|
22
|
+
baseDir,
|
|
23
|
+
envPath: discoveredEnvPath || null,
|
|
24
|
+
fileValues,
|
|
25
|
+
overriddenKeys,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function resolveDefaultEnvPath(cwd) {
|
|
29
|
+
const candidate = path.resolve(String(cwd ?? process.cwd()), ".env");
|
|
30
|
+
return fs.existsSync(candidate) ? candidate : "";
|
|
31
|
+
}
|
|
32
|
+
function loadEnvFileValues(filePath) {
|
|
33
|
+
if (!filePath || !fs.existsSync(filePath)) {
|
|
34
|
+
return {};
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
const raw = fs.readFileSync(filePath, "utf8");
|
|
38
|
+
return normalizeEnvMap(dotenv.parse(raw));
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return {};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function applyEnvFileValues(env, fileValues) {
|
|
45
|
+
const overriddenKeys = [];
|
|
46
|
+
for (const [key, value] of Object.entries(fileValues)) {
|
|
47
|
+
const previousValue = String(env[key] ?? "");
|
|
48
|
+
if (previousValue && previousValue !== value) {
|
|
49
|
+
overriddenKeys.push(key);
|
|
50
|
+
}
|
|
51
|
+
env[key] = value;
|
|
52
|
+
}
|
|
53
|
+
return overriddenKeys.sort();
|
|
54
|
+
}
|
|
55
|
+
function normalizeEnvMap(value) {
|
|
56
|
+
const output = {};
|
|
57
|
+
for (const [key, entry] of Object.entries(value ?? {})) {
|
|
58
|
+
const normalizedKey = String(key ?? "").trim();
|
|
59
|
+
if (!normalizedKey) {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
output[normalizedKey] = String(entry ?? "").trim();
|
|
63
|
+
}
|
|
64
|
+
return output;
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=env-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-config.js","sourceRoot":"","sources":["../src/env-config.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
export { createWorkspaceBoundaryPolicy, assertWorkspaceAllowed, isPathInside, normalizeAbsolutePath, parseWorkspaceAllowedRoots, } from "./workspace-policy.js";
|
|
2
2
|
export { normalizeThreadId } from "./thread-id.js";
|
|
3
3
|
export { createProjectFingerprint } from "./project-fingerprint.js";
|
|
4
|
-
export { DEFAULT_EXTERNAL_WORKSPACES_DIRNAME, getKernelRootPath, getDefaultExternalWorkspaceBasePath, resolveDefaultWorkspaceForBot, isPathInside as isWorkspacePathInside, } from "./workspace-paths.js";
|
|
4
|
+
export { DEFAULT_EXTERNAL_WORKSPACES_DIRNAME, getKernelRootPath, resolveKernelRootPath, getDefaultExternalWorkspaceBasePath, resolveExternalWorkspaceBasePath, resolveDefaultWorkspaceForBot, isPathInside as isWorkspacePathInside, } from "./workspace-paths.js";
|
|
5
5
|
export { resolveConfigBaseDir, resolveProcessConfigBaseDir, resolvePathFromBase, resolveOptionalPathFromBase, } from "./config-paths.js";
|
|
6
|
+
export { loadCopilotHubEnvironment } from "./env-config.js";
|
|
6
7
|
export { InstanceLock } from "./instance-lock.js";
|
|
7
8
|
export { JsonStateStore } from "./state-store.js";
|
|
8
9
|
export { assertControlPermission } from "./control-permission.js";
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
export { createWorkspaceBoundaryPolicy, assertWorkspaceAllowed, isPathInside, normalizeAbsolutePath, parseWorkspaceAllowedRoots, } from "./workspace-policy.js";
|
|
2
2
|
export { normalizeThreadId } from "./thread-id.js";
|
|
3
3
|
export { createProjectFingerprint } from "./project-fingerprint.js";
|
|
4
|
-
export { DEFAULT_EXTERNAL_WORKSPACES_DIRNAME, getKernelRootPath, getDefaultExternalWorkspaceBasePath, resolveDefaultWorkspaceForBot, isPathInside as isWorkspacePathInside, } from "./workspace-paths.js";
|
|
4
|
+
export { DEFAULT_EXTERNAL_WORKSPACES_DIRNAME, getKernelRootPath, resolveKernelRootPath, getDefaultExternalWorkspaceBasePath, resolveExternalWorkspaceBasePath, resolveDefaultWorkspaceForBot, isPathInside as isWorkspacePathInside, } from "./workspace-paths.js";
|
|
5
5
|
export { resolveConfigBaseDir, resolveProcessConfigBaseDir, resolvePathFromBase, resolveOptionalPathFromBase, } from "./config-paths.js";
|
|
6
|
+
export { loadCopilotHubEnvironment } from "./env-config.js";
|
|
6
7
|
export { InstanceLock } from "./instance-lock.js";
|
|
7
8
|
export { JsonStateStore } from "./state-store.js";
|
|
8
9
|
export { assertControlPermission } from "./control-permission.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,6BAA6B,EAC7B,sBAAsB,EACtB,YAAY,EACZ,qBAAqB,EACrB,0BAA0B,GAC3B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,EACL,mCAAmC,EACnC,iBAAiB,EACjB,mCAAmC,EACnC,6BAA6B,EAC7B,YAAY,IAAI,qBAAqB,GACtC,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,oBAAoB,EACpB,2BAA2B,EAC3B,mBAAmB,EACnB,2BAA2B,GAC5B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EACL,qBAAqB,EACrB,uBAAuB,EACvB,6BAA6B,GAC9B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC9E,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EACL,eAAe,EACf,sBAAsB,EACtB,eAAe,EACf,oBAAoB,GACrB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,0BAA0B,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC3F,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,6BAA6B,EAC7B,sBAAsB,EACtB,YAAY,EACZ,qBAAqB,EACrB,0BAA0B,GAC3B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,EACL,mCAAmC,EACnC,iBAAiB,EACjB,qBAAqB,EACrB,mCAAmC,EACnC,gCAAgC,EAChC,6BAA6B,EAC7B,YAAY,IAAI,qBAAqB,GACtC,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,oBAAoB,EACpB,2BAA2B,EAC3B,mBAAmB,EACnB,2BAA2B,GAC5B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EACL,qBAAqB,EACrB,uBAAuB,EACvB,6BAA6B,GAC9B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC9E,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EACL,eAAe,EACf,sBAAsB,EACtB,eAAe,EACf,oBAAoB,GACrB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,0BAA0B,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC3F,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC"}
|
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
export declare const DEFAULT_EXTERNAL_WORKSPACES_DIRNAME = "copilot_workspaces";
|
|
2
2
|
export declare function getKernelRootPath(): string;
|
|
3
|
-
export declare function
|
|
3
|
+
export declare function resolveKernelRootPath({ env, moduleUrl, cwd, }?: {
|
|
4
|
+
env?: NodeJS.ProcessEnv;
|
|
5
|
+
moduleUrl?: string;
|
|
6
|
+
cwd?: string;
|
|
7
|
+
}): string;
|
|
8
|
+
export declare function getDefaultExternalWorkspaceBasePath(kernelRoot?: string): string;
|
|
9
|
+
export declare function resolveExternalWorkspaceBasePath({ kernelRootPath, desktopCandidates, homeDir, tempDir, }: {
|
|
10
|
+
kernelRootPath: string;
|
|
11
|
+
desktopCandidates?: readonly string[];
|
|
12
|
+
homeDir?: string;
|
|
13
|
+
tempDir?: string;
|
|
14
|
+
}): string;
|
|
4
15
|
export declare function resolveDefaultWorkspaceForBot(botId: unknown, kernelRoot?: string): string;
|
|
5
16
|
export declare function isPathInside(parentPath: unknown, candidatePath: unknown): boolean;
|
|
@@ -1,18 +1,42 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import os from "node:os";
|
|
3
3
|
import path from "node:path";
|
|
4
|
+
import process from "node:process";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
4
6
|
export const DEFAULT_EXTERNAL_WORKSPACES_DIRNAME = "copilot_workspaces";
|
|
5
7
|
const DESKTOP_DIRNAME = "Desktop";
|
|
6
8
|
export function getKernelRootPath() {
|
|
7
|
-
return
|
|
9
|
+
return resolveKernelRootPath();
|
|
8
10
|
}
|
|
9
|
-
export function
|
|
10
|
-
const
|
|
11
|
-
|
|
11
|
+
export function resolveKernelRootPath({ env = process.env, moduleUrl = import.meta.url, cwd = process.cwd(), } = {}) {
|
|
12
|
+
const configuredRoot = String(env.COPILOT_HUB_KERNEL_ROOT ?? "").trim();
|
|
13
|
+
if (configuredRoot) {
|
|
14
|
+
return path.resolve(configuredRoot);
|
|
15
|
+
}
|
|
16
|
+
const moduleFilePath = String(moduleUrl ?? "").trim();
|
|
17
|
+
if (moduleFilePath) {
|
|
18
|
+
return path.resolve(path.dirname(fileURLToPath(moduleFilePath)), "..", "..", "..");
|
|
19
|
+
}
|
|
20
|
+
return path.resolve(String(cwd ?? process.cwd()));
|
|
21
|
+
}
|
|
22
|
+
export function getDefaultExternalWorkspaceBasePath(kernelRoot = getKernelRootPath()) {
|
|
23
|
+
return resolveExternalWorkspaceBasePath({
|
|
24
|
+
kernelRootPath: kernelRoot,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
export function resolveExternalWorkspaceBasePath({ kernelRootPath, desktopCandidates = getDesktopCandidates(), homeDir = os.homedir(), tempDir = os.tmpdir(), }) {
|
|
12
28
|
const desktopRoot = desktopCandidates.find((candidate) => directoryExists(candidate)) ??
|
|
13
29
|
desktopCandidates[0] ??
|
|
14
|
-
|
|
15
|
-
|
|
30
|
+
path.resolve(String(homeDir ?? "").trim() || process.cwd(), DESKTOP_DIRNAME);
|
|
31
|
+
const preferredRoot = path.resolve(desktopRoot, DEFAULT_EXTERNAL_WORKSPACES_DIRNAME);
|
|
32
|
+
if (!isPathInside(kernelRootPath, preferredRoot)) {
|
|
33
|
+
return preferredRoot;
|
|
34
|
+
}
|
|
35
|
+
const homeFallbackRoot = path.resolve(String(homeDir ?? "").trim() || process.cwd(), DEFAULT_EXTERNAL_WORKSPACES_DIRNAME);
|
|
36
|
+
if (!isPathInside(kernelRootPath, homeFallbackRoot)) {
|
|
37
|
+
return homeFallbackRoot;
|
|
38
|
+
}
|
|
39
|
+
return path.resolve(String(tempDir ?? "").trim() || process.cwd(), DEFAULT_EXTERNAL_WORKSPACES_DIRNAME);
|
|
16
40
|
}
|
|
17
41
|
export function resolveDefaultWorkspaceForBot(botId, kernelRoot = getKernelRootPath()) {
|
|
18
42
|
const id = String(botId ?? "").trim();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace-paths.js","sourceRoot":"","sources":["../src/workspace-paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"workspace-paths.js","sourceRoot":"","sources":["../src/workspace-paths.ts"],"names":[],"mappings":"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"}
|
|
@@ -34,6 +34,10 @@
|
|
|
34
34
|
"types": "./dist/config-paths.d.ts",
|
|
35
35
|
"import": "./dist/config-paths.js"
|
|
36
36
|
},
|
|
37
|
+
"./env-config": {
|
|
38
|
+
"types": "./dist/env-config.d.ts",
|
|
39
|
+
"import": "./dist/env-config.js"
|
|
40
|
+
},
|
|
37
41
|
"./instance-lock": {
|
|
38
42
|
"types": "./dist/instance-lock.d.ts",
|
|
39
43
|
"import": "./dist/instance-lock.js"
|
|
@@ -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) {
|
|
@@ -15,7 +15,8 @@ const engineExamplePath = path.join(repoRoot, "apps", "agent-engine", ".env.exam
|
|
|
15
15
|
const controlPlaneEnvPath = layout.controlPlaneEnvPath;
|
|
16
16
|
const controlPlaneExamplePath = path.join(repoRoot, "apps", "control-plane", ".env.example");
|
|
17
17
|
const TELEGRAM_TOKEN_PATTERN = /^\d{5,}:[A-Za-z0-9_-]{20,}$/;
|
|
18
|
-
const DEFAULT_CONTROL_PLANE_TOKEN_ENV = "
|
|
18
|
+
const DEFAULT_CONTROL_PLANE_TOKEN_ENV = "HUB_TELEGRAM_TOKEN_FILE";
|
|
19
|
+
const LEGACY_CONTROL_PLANE_TOKEN_ENV = "HUB_TELEGRAM_TOKEN";
|
|
19
20
|
const args = new Set(process.argv.slice(2));
|
|
20
21
|
const requiredOnly = args.has("--required-only");
|
|
21
22
|
await main();
|
|
@@ -44,9 +45,7 @@ async function main() {
|
|
|
44
45
|
writeLines(controlPlaneEnvPath, controlPlaneLines);
|
|
45
46
|
}
|
|
46
47
|
async function configureRequiredTokens({ rl, controlPlaneLines }) {
|
|
47
|
-
const
|
|
48
|
-
const controlPlaneTokenEnvName = nonEmpty(controlPlaneMap.HUB_TELEGRAM_TOKEN_ENV, DEFAULT_CONTROL_PLANE_TOKEN_ENV);
|
|
49
|
-
setEnvValue(controlPlaneLines, "HUB_TELEGRAM_TOKEN_ENV", controlPlaneTokenEnvName);
|
|
48
|
+
const controlPlaneTokenEnvName = migrateControlPlaneTokenEnv(controlPlaneLines);
|
|
50
49
|
const postControlPlaneMap = parseEnvMap(controlPlaneLines);
|
|
51
50
|
const currentToken = String(postControlPlaneMap[controlPlaneTokenEnvName] ?? "").trim();
|
|
52
51
|
if (isUsableTelegramToken(currentToken)) {
|
|
@@ -62,10 +61,8 @@ async function configureRequiredTokens({ rl, controlPlaneLines }) {
|
|
|
62
61
|
console.log("Required token saved.");
|
|
63
62
|
}
|
|
64
63
|
async function configureAll({ rl, controlPlaneLines }) {
|
|
65
|
-
const controlPlaneMap = parseEnvMap(controlPlaneLines);
|
|
66
64
|
console.log("\nCopilot Hub control-plane configuration\n");
|
|
67
|
-
const controlPlaneTokenEnvDefault =
|
|
68
|
-
setEnvValue(controlPlaneLines, "HUB_TELEGRAM_TOKEN_ENV", controlPlaneTokenEnvDefault);
|
|
65
|
+
const controlPlaneTokenEnvDefault = migrateControlPlaneTokenEnv(controlPlaneLines);
|
|
69
66
|
const currentControlPlaneToken = String(parseEnvMap(controlPlaneLines)[controlPlaneTokenEnvDefault] ?? "").trim();
|
|
70
67
|
const newControlPlaneToken = currentControlPlaneToken
|
|
71
68
|
? await askTelegramToken(rl, "Control-plane Telegram token (press Enter to keep current)", true)
|
|
@@ -77,6 +74,23 @@ async function configureAll({ rl, controlPlaneLines }) {
|
|
|
77
74
|
console.log("- Control-plane token left unchanged.");
|
|
78
75
|
}
|
|
79
76
|
}
|
|
77
|
+
function migrateControlPlaneTokenEnv(lines) {
|
|
78
|
+
const controlPlaneMap = parseEnvMap(lines);
|
|
79
|
+
const configuredTokenEnvName = nonEmpty(controlPlaneMap.HUB_TELEGRAM_TOKEN_ENV, DEFAULT_CONTROL_PLANE_TOKEN_ENV);
|
|
80
|
+
const shouldMigrateLegacyName = configuredTokenEnvName === LEGACY_CONTROL_PLANE_TOKEN_ENV;
|
|
81
|
+
const nextTokenEnvName = shouldMigrateLegacyName
|
|
82
|
+
? DEFAULT_CONTROL_PLANE_TOKEN_ENV
|
|
83
|
+
: configuredTokenEnvName;
|
|
84
|
+
setEnvValue(lines, "HUB_TELEGRAM_TOKEN_ENV", nextTokenEnvName);
|
|
85
|
+
if (shouldMigrateLegacyName) {
|
|
86
|
+
const legacyToken = String(controlPlaneMap[LEGACY_CONTROL_PLANE_TOKEN_ENV] ?? "").trim();
|
|
87
|
+
const dedicatedToken = String(controlPlaneMap[DEFAULT_CONTROL_PLANE_TOKEN_ENV] ?? "").trim();
|
|
88
|
+
if (legacyToken && !dedicatedToken) {
|
|
89
|
+
setEnvValue(lines, DEFAULT_CONTROL_PLANE_TOKEN_ENV, legacyToken);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return nextTokenEnvName;
|
|
93
|
+
}
|
|
80
94
|
function ensureEnvFile(envPath, examplePath) {
|
|
81
95
|
fs.mkdirSync(path.dirname(envPath), { recursive: true });
|
|
82
96
|
if (fs.existsSync(envPath)) {
|
package/scripts/dist/daemon.mjs
CHANGED
|
@@ -508,6 +508,23 @@ function detectFatalStartupError(ensureResult) {
|
|
|
508
508
|
detectedAt: new Date().toISOString(),
|
|
509
509
|
};
|
|
510
510
|
}
|
|
511
|
+
const invalidHubTokenLine = findLineContaining(evidenceChunks, (line) => line.includes("hub telegram token in") && line.includes("is invalid"));
|
|
512
|
+
if (invalidHubTokenLine) {
|
|
513
|
+
return {
|
|
514
|
+
reason: invalidHubTokenLine,
|
|
515
|
+
action: "Run 'copilot-hub configure' to save a valid hub token in the control-plane config, then retry service.",
|
|
516
|
+
detectedAt: new Date().toISOString(),
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
const workspaceRootLine = findLineContaining(evidenceChunks, (line) => line.includes("default_workspace_root must be outside kernel directory") ||
|
|
520
|
+
line.includes("hub_workspace_root must be outside kernel directory"));
|
|
521
|
+
if (workspaceRootLine) {
|
|
522
|
+
return {
|
|
523
|
+
reason: workspaceRootLine,
|
|
524
|
+
action: "Set DEFAULT_WORKSPACE_ROOT to a folder outside the copilot-hub installation, then retry service.",
|
|
525
|
+
detectedAt: new Date().toISOString(),
|
|
526
|
+
};
|
|
527
|
+
}
|
|
511
528
|
return null;
|
|
512
529
|
}
|
|
513
530
|
function readLogTail(filePath, maxLines = 120) {
|
|
@@ -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) {
|
|
@@ -18,7 +18,8 @@ const engineExamplePath = path.join(repoRoot, "apps", "agent-engine", ".env.exam
|
|
|
18
18
|
const controlPlaneEnvPath = layout.controlPlaneEnvPath;
|
|
19
19
|
const controlPlaneExamplePath = path.join(repoRoot, "apps", "control-plane", ".env.example");
|
|
20
20
|
const TELEGRAM_TOKEN_PATTERN = /^\d{5,}:[A-Za-z0-9_-]{20,}$/;
|
|
21
|
-
const DEFAULT_CONTROL_PLANE_TOKEN_ENV = "
|
|
21
|
+
const DEFAULT_CONTROL_PLANE_TOKEN_ENV = "HUB_TELEGRAM_TOKEN_FILE";
|
|
22
|
+
const LEGACY_CONTROL_PLANE_TOKEN_ENV = "HUB_TELEGRAM_TOKEN";
|
|
22
23
|
|
|
23
24
|
const args = new Set(process.argv.slice(2));
|
|
24
25
|
const requiredOnly = args.has("--required-only");
|
|
@@ -53,13 +54,7 @@ async function main() {
|
|
|
53
54
|
}
|
|
54
55
|
|
|
55
56
|
async function configureRequiredTokens({ rl, controlPlaneLines }) {
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
const controlPlaneTokenEnvName = nonEmpty(
|
|
59
|
-
controlPlaneMap.HUB_TELEGRAM_TOKEN_ENV,
|
|
60
|
-
DEFAULT_CONTROL_PLANE_TOKEN_ENV,
|
|
61
|
-
);
|
|
62
|
-
setEnvValue(controlPlaneLines, "HUB_TELEGRAM_TOKEN_ENV", controlPlaneTokenEnvName);
|
|
57
|
+
const controlPlaneTokenEnvName = migrateControlPlaneTokenEnv(controlPlaneLines);
|
|
63
58
|
|
|
64
59
|
const postControlPlaneMap = parseEnvMap(controlPlaneLines);
|
|
65
60
|
const currentToken = String(postControlPlaneMap[controlPlaneTokenEnvName] ?? "").trim();
|
|
@@ -82,15 +77,9 @@ async function configureRequiredTokens({ rl, controlPlaneLines }) {
|
|
|
82
77
|
}
|
|
83
78
|
|
|
84
79
|
async function configureAll({ rl, controlPlaneLines }) {
|
|
85
|
-
const controlPlaneMap = parseEnvMap(controlPlaneLines);
|
|
86
|
-
|
|
87
80
|
console.log("\nCopilot Hub control-plane configuration\n");
|
|
88
81
|
|
|
89
|
-
const controlPlaneTokenEnvDefault =
|
|
90
|
-
controlPlaneMap.HUB_TELEGRAM_TOKEN_ENV,
|
|
91
|
-
DEFAULT_CONTROL_PLANE_TOKEN_ENV,
|
|
92
|
-
);
|
|
93
|
-
setEnvValue(controlPlaneLines, "HUB_TELEGRAM_TOKEN_ENV", controlPlaneTokenEnvDefault);
|
|
82
|
+
const controlPlaneTokenEnvDefault = migrateControlPlaneTokenEnv(controlPlaneLines);
|
|
94
83
|
const currentControlPlaneToken = String(
|
|
95
84
|
parseEnvMap(controlPlaneLines)[controlPlaneTokenEnvDefault] ?? "",
|
|
96
85
|
).trim();
|
|
@@ -106,6 +95,29 @@ async function configureAll({ rl, controlPlaneLines }) {
|
|
|
106
95
|
}
|
|
107
96
|
}
|
|
108
97
|
|
|
98
|
+
function migrateControlPlaneTokenEnv(lines) {
|
|
99
|
+
const controlPlaneMap = parseEnvMap(lines);
|
|
100
|
+
const configuredTokenEnvName = nonEmpty(
|
|
101
|
+
controlPlaneMap.HUB_TELEGRAM_TOKEN_ENV,
|
|
102
|
+
DEFAULT_CONTROL_PLANE_TOKEN_ENV,
|
|
103
|
+
);
|
|
104
|
+
const shouldMigrateLegacyName = configuredTokenEnvName === LEGACY_CONTROL_PLANE_TOKEN_ENV;
|
|
105
|
+
const nextTokenEnvName = shouldMigrateLegacyName
|
|
106
|
+
? DEFAULT_CONTROL_PLANE_TOKEN_ENV
|
|
107
|
+
: configuredTokenEnvName;
|
|
108
|
+
setEnvValue(lines, "HUB_TELEGRAM_TOKEN_ENV", nextTokenEnvName);
|
|
109
|
+
|
|
110
|
+
if (shouldMigrateLegacyName) {
|
|
111
|
+
const legacyToken = String(controlPlaneMap[LEGACY_CONTROL_PLANE_TOKEN_ENV] ?? "").trim();
|
|
112
|
+
const dedicatedToken = String(controlPlaneMap[DEFAULT_CONTROL_PLANE_TOKEN_ENV] ?? "").trim();
|
|
113
|
+
if (legacyToken && !dedicatedToken) {
|
|
114
|
+
setEnvValue(lines, DEFAULT_CONTROL_PLANE_TOKEN_ENV, legacyToken);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return nextTokenEnvName;
|
|
119
|
+
}
|
|
120
|
+
|
|
109
121
|
function ensureEnvFile(envPath, examplePath) {
|
|
110
122
|
fs.mkdirSync(path.dirname(envPath), { recursive: true });
|
|
111
123
|
if (fs.existsSync(envPath)) {
|
package/scripts/src/daemon.mts
CHANGED
|
@@ -600,6 +600,34 @@ function detectFatalStartupError(ensureResult) {
|
|
|
600
600
|
};
|
|
601
601
|
}
|
|
602
602
|
|
|
603
|
+
const invalidHubTokenLine = findLineContaining(
|
|
604
|
+
evidenceChunks,
|
|
605
|
+
(line) => line.includes("hub telegram token in") && line.includes("is invalid"),
|
|
606
|
+
);
|
|
607
|
+
if (invalidHubTokenLine) {
|
|
608
|
+
return {
|
|
609
|
+
reason: invalidHubTokenLine,
|
|
610
|
+
action:
|
|
611
|
+
"Run 'copilot-hub configure' to save a valid hub token in the control-plane config, then retry service.",
|
|
612
|
+
detectedAt: new Date().toISOString(),
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
const workspaceRootLine = findLineContaining(
|
|
617
|
+
evidenceChunks,
|
|
618
|
+
(line) =>
|
|
619
|
+
line.includes("default_workspace_root must be outside kernel directory") ||
|
|
620
|
+
line.includes("hub_workspace_root must be outside kernel directory"),
|
|
621
|
+
);
|
|
622
|
+
if (workspaceRootLine) {
|
|
623
|
+
return {
|
|
624
|
+
reason: workspaceRootLine,
|
|
625
|
+
action:
|
|
626
|
+
"Set DEFAULT_WORKSPACE_ROOT to a folder outside the copilot-hub installation, then retry service.",
|
|
627
|
+
detectedAt: new Date().toISOString(),
|
|
628
|
+
};
|
|
629
|
+
}
|
|
630
|
+
|
|
603
631
|
return null;
|
|
604
632
|
}
|
|
605
633
|
|
|
@@ -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
|
+
});
|