-
Notifications
You must be signed in to change notification settings - Fork 7
fix: release default web run port and align codex defaults #72
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -223,6 +223,150 @@ function resolveWebPort() { | |
| return parsed; | ||
| } | ||
|
|
||
| // #region releaseRunPortIfNeeded | ||
| function releaseRunPortIfNeeded(port, deps = {}) { | ||
| const numericPort = parseInt(String(port), 10); | ||
| if (numericPort !== DEFAULT_WEB_PORT) { | ||
| return { attempted: false, released: false, pids: [], reason: 'non-default-port' }; | ||
| } | ||
|
|
||
| const processRef = deps.process || process; | ||
| const runSpawnSync = deps.spawnSync || spawnSync; | ||
| const logger = deps.logger || console; | ||
| const killProcess = typeof deps.kill === 'function' | ||
| ? deps.kill | ||
| : (typeof processRef.kill === 'function' ? processRef.kill.bind(processRef) : null); | ||
| const seenPids = new Set(); | ||
| const candidatePids = new Set(); | ||
| const currentPid = Number(processRef.pid); | ||
| let released = false; | ||
|
|
||
| const addPidsFromText = (text, targetSet = seenPids) => { | ||
| if (!targetSet) { | ||
| return; | ||
| } | ||
| const lines = String(text || '').split(/\r?\n/); | ||
| for (const line of lines) { | ||
| const trimmed = line.trim(); | ||
| if (!/^\d+$/.test(trimmed)) { | ||
| continue; | ||
| } | ||
| targetSet.add(Number(trimmed)); | ||
| } | ||
| }; | ||
|
|
||
| const runCommand = (command, args, options = {}) => { | ||
| const { | ||
| stdoutPidSet = seenPids, | ||
| stderrPidSet = seenPids | ||
| } = options; | ||
| const result = runSpawnSync(command, args, { encoding: 'utf8' }); | ||
| if (result && result.stdout) addPidsFromText(result.stdout, stdoutPidSet); | ||
| if (result && result.stderr) addPidsFromText(result.stderr, stderrPidSet); | ||
| return result || {}; | ||
| }; | ||
|
|
||
| const addManagedRunPidsFromPs = (text, allowedPids = null) => { | ||
| const lines = String(text || '').split(/\r?\n/); | ||
| for (const line of lines) { | ||
| const normalizedLine = ` ${line.replace(/\s+/g, ' ').trim()} `; | ||
| if (!/(^|[\/\s])codexmate run(\s|$)/.test(normalizedLine) && !/(^|[\/\s])cli\.js run(\s|$)/.test(normalizedLine)) { | ||
| continue; | ||
| } | ||
| const pidMatch = line.match(/^\S+\s+(\d+)\s+/); | ||
| if (!pidMatch) { | ||
| continue; | ||
| } | ||
| const pid = Number(pidMatch[1]); | ||
| if (!Number.isFinite(pid) || pid <= 0 || pid === currentPid) { | ||
| continue; | ||
| } | ||
| if (allowedPids && !allowedPids.has(pid)) { | ||
| continue; | ||
| } | ||
| seenPids.add(pid); | ||
| } | ||
| }; | ||
|
|
||
| if (processRef.platform === 'win32') { | ||
| const netstatResult = runCommand('netstat', ['-ano', '-p', 'tcp']); | ||
| if (!(netstatResult && netstatResult.error)) { | ||
| const lines = String(netstatResult.stdout || '').split(/\r?\n/); | ||
| for (const line of lines) { | ||
| const parts = line.trim().split(/\s+/); | ||
| if (parts.length < 5) { | ||
| continue; | ||
| } | ||
| const localAddress = parts[1]; | ||
| const state = parts[3]; | ||
| const pidText = parts[4]; | ||
| if (state !== 'LISTENING' || !localAddress.endsWith(`:${numericPort}`) || !/^\d+$/.test(pidText)) { | ||
| continue; | ||
| } | ||
| seenPids.add(Number(pidText)); | ||
| } | ||
| for (const pid of seenPids) { | ||
| const taskkillResult = runCommand('taskkill', ['/PID', String(pid), '/F']); | ||
| if (!taskkillResult.error && taskkillResult.status === 0) { | ||
| released = true; | ||
| } | ||
| } | ||
| } | ||
| } else { | ||
| let psResult = null; | ||
| const readPsResult = () => { | ||
| if (psResult) { | ||
| return psResult; | ||
| } | ||
| psResult = runCommand('ps', ['-ef'], { stdoutPidSet: null, stderrPidSet: null }); | ||
| return psResult; | ||
| }; | ||
|
|
||
| const lsofResult = runCommand( | ||
| 'lsof', | ||
| ['-ti', `tcp:${numericPort}`], | ||
| { stdoutPidSet: candidatePids, stderrPidSet: null } | ||
| ); | ||
| if (!(lsofResult && lsofResult.error) && candidatePids.size > 0) { | ||
| const managedPsResult = readPsResult(); | ||
| if (!(managedPsResult && managedPsResult.error)) { | ||
| addManagedRunPidsFromPs(managedPsResult.stdout, candidatePids); | ||
| } | ||
| } | ||
| if (killProcess && seenPids.size === 0) { | ||
| const managedPsResult = readPsResult(); | ||
| if (!(managedPsResult && managedPsResult.error)) { | ||
| addManagedRunPidsFromPs(managedPsResult.stdout); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| if (processRef.platform !== 'win32' && killProcess && !released && seenPids.size > 0) { | ||
| for (const pid of seenPids) { | ||
| if (pid === currentPid) { | ||
| continue; | ||
| } | ||
| try { | ||
| killProcess(pid, 'SIGKILL'); | ||
| released = true; | ||
|
Comment on lines
+412
to
+440
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unix cleanup still kills by port instead of by requested listener. The non-Windows path ignores 🤖 Prompt for AI Agents |
||
| } catch (_) {} | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| } | ||
| } | ||
|
|
||
| if (released) { | ||
| logger.log(`~ 已释放端口 ${numericPort} 占用`); | ||
| } | ||
|
|
||
| return { | ||
| attempted: true, | ||
| released, | ||
| pids: Array.from(seenPids) | ||
| .filter((pid) => pid !== currentPid) | ||
| .sort((a, b) => a - b) | ||
| }; | ||
| } | ||
| // #endregion releaseRunPortIfNeeded | ||
|
|
||
| function resolveWebHost(options = {}) { | ||
| const optionHost = typeof options.host === 'string' ? options.host.trim() : ''; | ||
| if (optionHost) { | ||
|
|
@@ -236,7 +380,6 @@ function resolveWebHost(options = {}) { | |
| } | ||
|
|
||
| const EMPTY_CONFIG_FALLBACK_TEMPLATE = `model = "gpt-5.3-codex" | ||
| model_reasoning_effort = "high" | ||
| model_context_window = ${DEFAULT_MODEL_CONTEXT_WINDOW} | ||
| model_auto_compact_token_limit = ${DEFAULT_MODEL_AUTO_COMPACT_TOKEN_LIMIT} | ||
| disable_response_storage = true | ||
|
|
@@ -10845,6 +10988,7 @@ function cmdStart(options = {}) { | |
|
|
||
| const port = resolveWebPort(); | ||
| const host = resolveWebHost(options); | ||
| releaseRunPortIfNeeded(port); | ||
|
|
||
| let serverHandle = createWebServer({ | ||
| htmlPath, | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.