feat: add CentOS7 single executable build

This commit is contained in:
shiyue
2026-06-24 10:36:03 +08:00
parent a794607817
commit 67914ba10f
8 changed files with 365 additions and 26 deletions

View File

@@ -12,8 +12,37 @@ const { createCodexAppRuntime } = require('./lib/codex-app-runtime');
const { createCodexRolloutStore } = require('./lib/codex-rollouts');
const { TOOLS: CCWEB_MCP_TOOLS } = require('./lib/ccweb-mcp-server');
if (process.argv.includes('--ccweb-mcp-server')) {
require('./lib/ccweb-mcp-server').runStdioServer();
return;
}
if (process.argv.includes('--codex-app-worker')) {
require('./lib/codex-app-worker');
return;
}
function resolveAppDir() {
const explicit = String(process.env.CC_WEB_APP_DIR || '').trim();
if (explicit) return path.resolve(explicit);
const execDir = process.execPath ? path.dirname(process.execPath) : '';
if (process.versions?.bun && execDir && fs.existsSync(path.join(execDir, 'public'))) {
return execDir;
}
return __dirname;
}
const APP_DIR = resolveAppDir();
const IS_BUN_SINGLE_EXECUTABLE = !!process.versions?.bun
&& process.execPath
&& !/^bun(?:\.exe)?$/i.test(path.basename(process.execPath));
const CCWEB_MCP_SERVER_ARG = '--ccweb-mcp-server';
const CODEX_APP_WORKER_ARG = '--codex-app-worker';
// Load .env
const envPath = path.join(__dirname, '.env');
const envPath = path.join(APP_DIR, '.env');
if (fs.existsSync(envPath)) {
for (const line of fs.readFileSync(envPath, 'utf8').split('\n')) {
const m = line.match(/^([^#=]+)=(.*)$/);
@@ -33,11 +62,10 @@ const PORT = parseInt(process.env.PORT) || 8002;
const CLAUDE_PATH = process.env.CLAUDE_PATH || 'claude';
const CODEX_PATH = process.env.CODEX_PATH || 'codex';
const INTERNAL_MCP_TOKEN = process.env.CC_WEB_INTERNAL_MCP_TOKEN || crypto.randomBytes(32).toString('hex');
const CONFIG_DIR = process.env.CC_WEB_CONFIG_DIR || path.join(__dirname, 'config');
const SESSIONS_DIR = process.env.CC_WEB_SESSIONS_DIR || path.join(__dirname, 'sessions');
const PUBLIC_DIR = process.env.CC_WEB_PUBLIC_DIR || path.join(__dirname, 'public');
const LOGS_DIR = process.env.CC_WEB_LOGS_DIR || path.join(__dirname, 'logs');
const CCWEB_MCP_SERVER_PATH = path.join(__dirname, 'lib', 'ccweb-mcp-server.js');
const CONFIG_DIR = process.env.CC_WEB_CONFIG_DIR || path.join(APP_DIR, 'config');
const SESSIONS_DIR = process.env.CC_WEB_SESSIONS_DIR || path.join(APP_DIR, 'sessions');
const PUBLIC_DIR = process.env.CC_WEB_PUBLIC_DIR || path.join(APP_DIR, 'public');
const LOGS_DIR = process.env.CC_WEB_LOGS_DIR || path.join(APP_DIR, 'logs');
const ATTACHMENTS_DIR = path.join(SESSIONS_DIR, '_attachments');
const ATTACHMENT_TTL_MS = 7 * 24 * 60 * 60 * 1000;
const MAX_ATTACHMENT_SIZE = 10 * 1024 * 1024;
@@ -1789,8 +1817,8 @@ function composerSkillRoots(options = {}) {
if (codexHome) roots.push(path.join(codexHome, 'skills'));
const homeDir = normalizeExistingDirPath(process.env.HOME || process.env.USERPROFILE || '');
if (homeDir) roots.push(path.join(homeDir, '.agents', 'skills'));
roots.push(path.join(__dirname, '.codex', 'skills'));
roots.push(path.join(__dirname, '.agents', 'skills'));
roots.push(path.join(APP_DIR, '.codex', 'skills'));
roots.push(path.join(APP_DIR, '.agents', 'skills'));
roots.push('/etc/codex/skills');
const seen = new Set();
return roots.filter((root) => {
@@ -1899,8 +1927,8 @@ function composerPromptRoots() {
const roots = [];
const codexHome = getCodexHomeDir();
if (codexHome) roots.push(path.join(codexHome, 'prompts'));
roots.push(path.join(__dirname, '.codex', 'prompts'));
roots.push(path.join(__dirname, '.agents', 'prompts'));
roots.push(path.join(APP_DIR, '.codex', 'prompts'));
roots.push(path.join(APP_DIR, '.agents', 'prompts'));
return roots;
}
@@ -6613,7 +6641,7 @@ const {
getDefaultCodexModel,
loadCodexConfig,
prepareCodexCustomRuntime,
ccwebMcpServerPath: CCWEB_MCP_SERVER_PATH,
ccwebMcpServerArg: CCWEB_MCP_SERVER_ARG,
internalMcpUrl: `http://127.0.0.1:${PORT}/api/internal/mcp`,
internalMcpToken: INTERNAL_MCP_TOKEN,
nodePath: process.execPath,
@@ -7577,7 +7605,7 @@ function codexAppTurnPermissionParams(session) {
}
function codexAppCcwebMcpEnv(session, options = {}) {
if (!session?.id || !INTERNAL_MCP_TOKEN || !CCWEB_MCP_SERVER_PATH) return null;
if (!session?.id || !INTERNAL_MCP_TOKEN) return null;
const rawHopCount = Number.parseInt(String(options.mcpContext?.hopCount || 0), 10);
const hopCount = Number.isFinite(rawHopCount) ? Math.max(0, rawHopCount) : 0;
return {
@@ -7594,7 +7622,7 @@ function codexAppThreadConfig(session, options = {}) {
return {
'mcp_servers.ccweb': {
command: process.execPath,
args: [CCWEB_MCP_SERVER_PATH],
args: [CCWEB_MCP_SERVER_ARG],
env: ccwebMcpEnv,
startup_timeout_sec: 10,
tool_timeout_sec: 60,
@@ -7707,12 +7735,17 @@ function getCodexAppClient() {
onLog: (level, event, data) => plog(level, event, data),
postInitialize: codexAppPostInitialize,
};
if (IS_BUN_SINGLE_EXECUTABLE) {
clientOptions.workerCommand = process.execPath;
clientOptions.workerArgs = [CODEX_APP_WORKER_ARG];
}
codexAppClient = CODEX_APP_WORKER_ENABLED
? createCodexAppWorkerClient(clientOptions)
: createCodexAppServerClient(clientOptions);
codexAppClientSignature = signature;
plog('INFO', 'codex_app_client_created', {
worker: CODEX_APP_WORKER_ENABLED,
workerLauncher: IS_BUN_SINGLE_EXECUTABLE ? 'single-executable' : 'source-file',
command: path.basename(spec.command || ''),
strippedEnvKeys: spec.strippedEnvKeys || [],
});
@@ -8059,11 +8092,11 @@ function handleCodexAppAbortSession(sessionId, ws = null) {
function handleCheckUpdate(ws) {
const localVersion = (() => {
try {
const cl = fs.readFileSync(path.join(__dirname, 'CHANGELOG.md'), 'utf8');
const cl = fs.readFileSync(path.join(APP_DIR, 'CHANGELOG.md'), 'utf8');
const m = cl.match(/##\s*v([\d.]+)/) || cl.match(/\*\*v([\d.]+)\*\*/);
if (m) return m[1];
} catch {}
try { return JSON.parse(fs.readFileSync(path.join(__dirname, 'package.json'), 'utf8')).version || 'unknown'; } catch {}
try { return JSON.parse(fs.readFileSync(path.join(APP_DIR, 'package.json'), 'utf8')).version || 'unknown'; } catch {}
return 'unknown';
})();