@walkhi/code-relax 0.1.0-beta.2 → 0.1.0-beta.21
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 +55 -71
- package/dist/bin/codex-remote.mjs +150 -126
- package/dist/bin/manage-relay-admin.mjs +20 -0
- package/dist/bin/migrate-relay-db.mjs +107 -0
- package/dist/bin/self-relay-admin.mjs +8 -0
- package/dist/bin/self-relay-demo.mjs +2 -2
- package/dist/bin/self-relay-server.mjs +18 -10
- package/dist/shared/app-server-events.cjs +42 -15
- package/dist/shared/file-mentions.cjs +35 -0
- package/dist/shared/server-requests.cjs +86 -58
- package/dist/skills/code-relax/SKILL.md +7 -6
- package/dist/src/desktop-launcher.mjs +16 -21
- package/dist/src/file-upload-session.mjs +124 -0
- package/dist/src/lan-socket-server.mjs +52 -9
- package/dist/src/managed-app-server.mjs +44 -13
- package/dist/src/message-images.mjs +0 -18
- package/dist/src/onboarding.mjs +9 -11
- package/dist/src/platform/README.md +1 -1
- package/dist/src/platform/windows/background-process.mjs +1 -1
- package/dist/src/platform/windows/codex-runtime.mjs +251 -0
- package/dist/src/platform/windows/desktop-host.mjs +17 -3
- package/dist/src/platform/windows/desktop-info.ps1 +2 -4
- package/dist/src/platform/windows/desktop-runtime.ps1 +10 -0
- package/dist/src/platform/windows/desktop-shortcuts.ps1 +7 -14
- package/dist/src/platform/windows/launch-worker.mjs +42 -0
- package/dist/src/platform/windows/resident-start.js +20 -0
- package/dist/src/platform/windows/resident-startup.ps1 +76 -20
- package/dist/src/platform/windows/service-host.mjs +4 -16
- package/dist/src/platform/windows/start-hidden-console.ps1 +10 -5
- package/dist/src/platform/windows/stop-desktop.ps1 +7 -4
- package/dist/src/platform/windows/user-environment.mjs +1 -1
- package/dist/src/runtime-discovery.mjs +43 -0
- package/dist/src/self-relay/admin-cloud.mjs +101 -0
- package/dist/src/self-relay/admin-page.mjs +79 -0
- package/dist/src/self-relay/admin-server.mjs +66 -0
- package/dist/src/self-relay/admin-state.mjs +82 -19
- package/dist/src/self-relay/admin-style.mjs +9 -0
- package/dist/src/self-relay/admin-usage-page.mjs +28 -0
- package/dist/src/self-relay/connector.mjs +243 -30
- package/dist/src/self-relay/demo.mjs +3 -4
- package/dist/src/self-relay/email-accounts.mjs +141 -0
- package/dist/src/self-relay/lifecycle.mjs +99 -142
- package/dist/src/self-relay/mysql-state.mjs +104 -0
- package/dist/src/self-relay/p2p-probe.mjs +1 -1
- package/dist/src/self-relay/server.mjs +335 -59
- package/dist/src/self-relay/usage-diagnostics.mjs +46 -0
- package/dist/src/self-relay/usage-meter.mjs +125 -0
- package/dist/src/server.mjs +731 -1439
- package/dist/src/service-control.mjs +4 -4
- package/dist/src/service-doctor.mjs +27 -29
- package/dist/src/service-health.mjs +2 -2
- package/dist/src/service-install.mjs +1 -4
- package/dist/src/service-lifecycle.mjs +19 -19
- package/dist/src/shared-app-server.mjs +277 -270
- package/dist/src/shared-catalog.mjs +1 -11
- package/dist/src/shared-recovery.mjs +11 -9
- package/dist/src/shared-thread-stream.mjs +1 -1
- package/dist/src/skill-install.mjs +0 -13
- package/package.json +17 -18
- package/tools/postinstall.mjs +69 -15
- package/dist/src/app-server-client.mjs +0 -468
- package/dist/src/app-server-tasks.mjs +0 -358
- package/dist/src/debug-ui.mjs +0 -131
- package/dist/src/platform/windows/desktop-monitor.mjs +0 -34
- package/dist/src/platform/windows/desktop-shortcut-run.ps1 +0 -5
- package/dist/src/platform/windows/desktop-tools.mjs +0 -48
- package/dist/src/platform/windows/launch-worker.ps1 +0 -20
- package/dist/src/thread-catalog.mjs +0 -47
- package/dist/tools/find-desktop-pipe.mjs +0 -10
- package/dist/web/activity-view.js +0 -283
- package/dist/web/approval-ui.js +0 -188
- package/dist/web/capabilities.js +0 -57
- package/dist/web/chat-transport.js +0 -202
- package/dist/web/chat.css +0 -782
- package/dist/web/chat.js +0 -3830
- package/dist/web/client-platform.js +0 -11
- package/dist/web/community-view.js +0 -20
- package/dist/web/community.css +0 -77
- package/dist/web/community.html +0 -37
- package/dist/web/composer-controller.js +0 -101
- package/dist/web/conversation-controller.js +0 -99
- package/dist/web/disclosure-state-controller.js +0 -95
- package/dist/web/draft-controller.js +0 -103
- package/dist/web/harmony-platform.js +0 -52
- package/dist/web/highlight-powershell.min.js +0 -39
- package/dist/web/highlight.min.js +0 -1262
- package/dist/web/history-cache.js +0 -240
- package/dist/web/history-controller.js +0 -167
- package/dist/web/index.html +0 -325
- package/dist/web/lan-session.js +0 -122
- package/dist/web/link-action-controller.js +0 -212
- package/dist/web/message-send-controller.js +0 -177
- package/dist/web/message-view.js +0 -98
- package/dist/web/p2p-data-channel.js +0 -50
- package/dist/web/p2p-diagnostics.js +0 -28
- package/dist/web/p2p-probe.js +0 -123
- package/dist/web/page-resume.js +0 -28
- package/dist/web/pending-message-store.js +0 -108
- package/dist/web/queue-controller.js +0 -82
- package/dist/web/resources.json +0 -1
- package/dist/web/self-relay-session.js +0 -129
- package/dist/web/server-requests.js +0 -67
- package/dist/web/station-connection-controller.js +0 -75
- package/dist/web/task-list-view.js +0 -296
- package/dist/web/thread-attention-controller.js +0 -124
- package/dist/web/thread-context-controller.js +0 -30
- package/dist/web/thread-list-controller.js +0 -61
- package/dist/web/thread-list-sync.js +0 -86
- package/dist/web/thread-title-controller.js +0 -57
- package/dist/web/timeline-formatters.js +0 -249
- package/dist/web/timeline-reducer.js +0 -81
- package/dist/web/timeline-renderer.js +0 -161
- package/dist/web/timeline-scroll-controller.js +0 -50
- package/dist/web/timeline-sync.js +0 -67
- package/dist/web/usage-controller.js +0 -258
- package/dist/web/vendor/README.md +0 -14
- package/dist/web/vendor/highlight-powershell.min.js +0 -39
- package/dist/web/vendor/highlight.LICENSE.txt +0 -29
- package/dist/web/vendor/highlight.min.js +0 -1262
- package/dist/web/vendor/lucide.LICENSE.txt +0 -17
|
@@ -29,7 +29,7 @@ export async function openControl({ instanceId, secret, shutdown, status = () =>
|
|
|
29
29
|
}
|
|
30
30
|
if (request.method === 'POST') response.once('finish', () => {
|
|
31
31
|
Promise.resolve(shutdown()).catch(error => {
|
|
32
|
-
console.error('
|
|
32
|
+
console.error('桌面服务关闭失败:', error.message);
|
|
33
33
|
process.exitCode = 1;
|
|
34
34
|
});
|
|
35
35
|
});
|
|
@@ -56,16 +56,16 @@ export function controlRequest(session, method = 'GET', action = '') {
|
|
|
56
56
|
response.on('end', () => {
|
|
57
57
|
try {
|
|
58
58
|
if (response.statusCode === 409) throw new Error(JSON.parse(body).error);
|
|
59
|
-
if (response.statusCode !== 200) throw new Error('
|
|
59
|
+
if (response.statusCode !== 200) throw new Error('桌面服务管理通道身份验证失败。');
|
|
60
60
|
const identity = JSON.parse(body);
|
|
61
61
|
if (identity.instanceId !== session.instanceId || identity.pid !== session.pid) {
|
|
62
|
-
throw new Error('
|
|
62
|
+
throw new Error('桌面服务实例身份不匹配。');
|
|
63
63
|
}
|
|
64
64
|
resolve(identity);
|
|
65
65
|
} catch (error) { reject(error); }
|
|
66
66
|
});
|
|
67
67
|
});
|
|
68
|
-
request.on('timeout', () => request.destroy(new Error('
|
|
68
|
+
request.on('timeout', () => request.destroy(new Error('桌面服务管理通道响应超时。')));
|
|
69
69
|
request.on('error', reject);
|
|
70
70
|
request.end();
|
|
71
71
|
});
|
|
@@ -2,11 +2,11 @@ import fs from 'node:fs';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { readRecord } from './service-lifecycle.mjs';
|
|
4
4
|
import { inspectSkill } from './skill-install.mjs';
|
|
5
|
-
import {
|
|
6
|
-
import { managedAppServerUrl } from './managed-app-server.mjs';
|
|
5
|
+
import { recoveryStatus } from './shared-recovery.mjs';
|
|
7
6
|
|
|
8
|
-
export async function doctor({ paths, host, service, skillTarget }) {
|
|
7
|
+
export async function doctor({ paths, host, service, skillTarget, ensureAutostart }) {
|
|
9
8
|
const checks = [];
|
|
9
|
+
let installedVersion;
|
|
10
10
|
const add = (id, status, message) => checks.push({ id, status, message });
|
|
11
11
|
const check = async (id, task) => {
|
|
12
12
|
try { await task(); } catch (error) { add(id, 'error', error.message); }
|
|
@@ -15,49 +15,47 @@ export async function doctor({ paths, host, service, skillTarget }) {
|
|
|
15
15
|
const record = readRecord(path.join(paths.serviceRoot, 'installation.json'));
|
|
16
16
|
if (!record || !fs.existsSync(path.join(paths.serviceRoot, 'dist/bin/codex-remote.mjs'))) throw Error('尚未完整部署服务,请重新安装 Code Relax。');
|
|
17
17
|
if (!record.nodeExecutable || !fs.existsSync(record.nodeExecutable)) throw Error('记录的 Node 已失效,请用可用的 Node 重新安装 Code Relax。');
|
|
18
|
-
|
|
18
|
+
installedVersion = record.version;
|
|
19
|
+
add('installation', 'ok', `已安装版本:${record.version};Node:${record.nodeExecutable}`);
|
|
19
20
|
});
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
add('shared-service', 'ok', sharedUrl ? '完整控制连接可用。' : '当前使用基础控制。');
|
|
24
|
-
});
|
|
25
|
-
await check('desktop', async () => {
|
|
26
|
-
await host.desktopEnvironment(readRecord(path.join(paths.stateRoot, 'bridge-startup-context.json')), sharedUrl);
|
|
27
|
-
add('desktop', 'ok', 'Desktop 来源上下文和工具管道已定位;实际任务操作尚未验证。');
|
|
21
|
+
await check('bridge-runtime', async () => {
|
|
22
|
+
await host.bridgeEnvironment();
|
|
23
|
+
add('bridge-runtime', 'ok', '桌面服务启动环境已就绪;实际任务操作尚未验证。');
|
|
28
24
|
});
|
|
29
25
|
await check('network', async () => {
|
|
30
26
|
const address = await host.lanAddress();
|
|
31
27
|
if (!address) throw Error('未找到局域网 IPv4;请连接受信任的 Wi-Fi 或有线网络。');
|
|
32
28
|
add('network', 'ok', `局域网地址:${address}`);
|
|
33
29
|
});
|
|
30
|
+
await check('autostart', async () => {
|
|
31
|
+
const state = await ensureAutostart();
|
|
32
|
+
add('autostart', 'ok', `当前用户登录自启:${state.repaired ? '已自动恢复' : '已启用'}。`);
|
|
33
|
+
});
|
|
34
34
|
await check('service', async () => {
|
|
35
35
|
const state = await service.status();
|
|
36
36
|
add('service', state.running ? 'ok' : 'warning', state.running
|
|
37
|
-
? `本机服务正常:${state.mode},端口 ${state.port}` : '服务未就绪;安装后执行 relax start。');
|
|
37
|
+
? `本机服务正常:${state.mode},端口 ${state.port},运行版本:${state.version || '未知'}` : '服务未就绪;安装后执行 relax start。');
|
|
38
|
+
if (state.running && installedVersion && state.version !== installedVersion) add('service-version', 'warning', state.version
|
|
39
|
+
? `已安装版本 ${installedVersion},但当前运行版本为 ${state.version};请重新执行安装或重启工作站服务。`
|
|
40
|
+
: `已安装版本 ${installedVersion},但当前运行的桌面服务未报告版本,可能仍是旧进程;请重新执行安装或重启桌面服务。`);
|
|
38
41
|
if (state.running) add('managed-app-server', state.managedAppServer?.state === 'ready' ? 'ok' : 'error',
|
|
39
|
-
state.managedAppServer?.state === 'ready' ? '
|
|
40
|
-
: state.managedAppServer?.error || '
|
|
42
|
+
state.managedAppServer?.state === 'ready' ? 'Codex 内核已就绪。'
|
|
43
|
+
: state.managedAppServer?.error || 'Codex 内核尚未就绪。');
|
|
41
44
|
if (state.managedAppServer?.updatePending) add('managed-app-server-update', 'warning',
|
|
42
|
-
'
|
|
45
|
+
'已选择另一版本 CLI;当前 app-server 继续完成任务,下次内核启动时采用选定版本。');
|
|
46
|
+
if (state.managedAppServer?.launcherRestartRequired) add('managed-app-server-launcher', 'warning',
|
|
47
|
+
'安装文件已经更新,但当前 app-server 仍由旧启动链创建;隐藏控制台等运行时修复尚未生效,请执行 relax setup 或重启 Windows。');
|
|
43
48
|
});
|
|
44
|
-
await check('desktop-
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
} else if (environment.userValue === managedAppServerUrl) {
|
|
49
|
-
add('desktop-environment', 'ok', `Desktop 后续启动地址:${managedAppServerUrl}`);
|
|
50
|
-
} else {
|
|
51
|
-
add('desktop-environment', 'warning', environment.userValue
|
|
52
|
-
? `用户配置了其他 app-server 地址:${environment.userValue}`
|
|
53
|
-
: '尚未配置 Desktop 后续启动地址;请重新执行 setup。');
|
|
54
|
-
}
|
|
49
|
+
await check('desktop-recovery', async () => {
|
|
50
|
+
const state = await recoveryStatus(paths.stateRoot);
|
|
51
|
+
add('desktop-recovery', state.status === 'failed' ? 'warning' : 'ok',
|
|
52
|
+
`最近 Desktop 接入:${state.message || state.status}${state.error ? `;${state.error}` : ''}`);
|
|
55
53
|
});
|
|
56
54
|
await check('skill', async () => {
|
|
57
55
|
const state = inspectSkill(skillTarget);
|
|
58
56
|
add('skill', state.managed ? 'ok' : 'warning', state.managed ? '本包管理的 Skill 已安装。'
|
|
59
|
-
: state.installed ? '存在同名自定义 Skill,本包不会覆盖。' : '
|
|
57
|
+
: state.installed ? '存在同名自定义 Skill,本包不会覆盖。' : 'Skill 未安装;重新执行 relax setup。');
|
|
60
58
|
});
|
|
61
|
-
add('firewall', 'warning', '
|
|
59
|
+
add('firewall', 'warning', '移动端连通性未验证。首次启动请允许记录的 Node 在受信任的专用网络通信;若曾拒绝,可在 Windows 安全中心的防火墙“允许应用通过防火墙”中检查该 Node。不要关闭整个防火墙。');
|
|
62
60
|
return { ready: !checks.some(item => item.status === 'error'), lanAccess: 'unverified', checks };
|
|
63
61
|
}
|
|
@@ -14,7 +14,7 @@ export function serviceHealth(session) {
|
|
|
14
14
|
socket.terminate();
|
|
15
15
|
if (error) reject(error); else resolve(value);
|
|
16
16
|
};
|
|
17
|
-
const timer = setTimeout(() => finish(new Error('
|
|
17
|
+
const timer = setTimeout(() => finish(new Error('桌面服务健康检查超时。')), 6000);
|
|
18
18
|
socket.on('open', () => socket.send(JSON.stringify({ type: 'auth', token })));
|
|
19
19
|
socket.on('message', data => {
|
|
20
20
|
try {
|
|
@@ -28,6 +28,6 @@ export function serviceHealth(session) {
|
|
|
28
28
|
});
|
|
29
29
|
socket.on('error', error => finish(error.code === 'ECONNREFUSED' ? null : error));
|
|
30
30
|
socket.on('close', code => finish(new Error(code === 1008
|
|
31
|
-
? '
|
|
31
|
+
? '桌面服务健康检查鉴权失败。' : '桌面服务健康检查连接已断开。')));
|
|
32
32
|
});
|
|
33
33
|
}
|
|
@@ -22,8 +22,6 @@ export async function installService(source, target, executable, stateRoot, hook
|
|
|
22
22
|
if (!fs.existsSync(path.join(source, 'dist/bin/codex-remote.mjs'))) throw new Error('缺少发布构建;源码目录请先执行 npm run build。');
|
|
23
23
|
if (!fs.existsSync(path.join(source, 'node_modules'))) throw new Error('缺少包依赖,请重新安装完整 npm 包。');
|
|
24
24
|
const parent = path.dirname(target);
|
|
25
|
-
const legacyUploadsRoots = readRecord(path.join(target, 'installation.json'))?.legacyUploadsRoots || [];
|
|
26
|
-
if (fs.existsSync(path.join(source, 'src/server.mjs'))) legacyUploadsRoots.push(path.join(source, 'uploads'));
|
|
27
25
|
fs.mkdirSync(parent, { recursive: true });
|
|
28
26
|
const stage = path.join(parent, `service-stage-${randomUUID()}`);
|
|
29
27
|
const backup = path.join(parent, `service-backup-${randomUUID()}`);
|
|
@@ -34,8 +32,7 @@ export async function installService(source, target, executable, stateRoot, hook
|
|
|
34
32
|
}
|
|
35
33
|
await exec(executable, [path.join(stage, 'dist/bin/codex-remote.mjs'), '--help'], { windowsHide: true });
|
|
36
34
|
await exec(executable, ['-e', 'const r=require("node:module").createRequire(process.argv[1]); r("sharp"); r("qrcode"); r("ws"); r("node-datachannel");', path.join(stage, 'package.json')], { windowsHide: true });
|
|
37
|
-
writeRecord(path.join(stage, 'installation.json'), { installedAt: new Date().toISOString(), source, nodeExecutable: executable, stateRoot,
|
|
38
|
-
legacyUploadsRoots: [...new Set(legacyUploadsRoots)],
|
|
35
|
+
writeRecord(path.join(stage, 'installation.json'), { installedAt: new Date().toISOString(), source, nodeExecutable: executable, stateRoot,
|
|
39
36
|
version: readRecord(path.join(source, 'package.json')).version });
|
|
40
37
|
const previous = fs.existsSync(target);
|
|
41
38
|
let previousMoved = false, activated = false;
|
|
@@ -23,12 +23,11 @@ export function lifecycle({ stateRoot, host }) {
|
|
|
23
23
|
fs.mkdirSync(stateRoot, { recursive: true });
|
|
24
24
|
const sessionPath = path.join(stateRoot, 'bridge-session.json');
|
|
25
25
|
const configPath = path.join(stateRoot, 'bridge-config.json');
|
|
26
|
-
const contextPath = path.join(stateRoot, 'bridge-startup-context.json');
|
|
27
26
|
const scriptPath = fileURLToPath(new URL('./server.mjs', import.meta.url));
|
|
28
27
|
|
|
29
28
|
async function alive(session) {
|
|
30
29
|
if (!session?.controlPort || !session.instanceId || !session.controlSecret) {
|
|
31
|
-
if (await health(session)) throw new Error('
|
|
30
|
+
if (await health(session)) throw new Error('当前为旧版桌面服务,请先使用旧版停止入口结束服务,再启动新版。');
|
|
32
31
|
return false;
|
|
33
32
|
}
|
|
34
33
|
try { await controlRequest(session); return true; }
|
|
@@ -36,7 +35,7 @@ export function lifecycle({ stateRoot, host }) {
|
|
|
36
35
|
}
|
|
37
36
|
async function stop() {
|
|
38
37
|
const session = readRecord(sessionPath);
|
|
39
|
-
if (!await alive(session)) return { stopped: true, message: '
|
|
38
|
+
if (!await alive(session)) return { stopped: true, message: '桌面服务已停止。' };
|
|
40
39
|
await controlRequest(session, 'POST');
|
|
41
40
|
const deadline = Date.now() + 10000;
|
|
42
41
|
while (true) {
|
|
@@ -46,22 +45,22 @@ export function lifecycle({ stateRoot, host }) {
|
|
|
46
45
|
// Verify refusal on the next connection; never resend the shutdown request.
|
|
47
46
|
if (error.code !== 'ECONNRESET') throw error;
|
|
48
47
|
}
|
|
49
|
-
if (Date.now() > deadline) throw new Error('
|
|
48
|
+
if (Date.now() > deadline) throw new Error('桌面服务未在 10 秒内退出;未强杀进程。');
|
|
50
49
|
await delay(100);
|
|
51
50
|
}
|
|
52
|
-
return { stopped: true, message: '
|
|
51
|
+
return { stopped: true, message: '桌面服务已正常关闭。' };
|
|
53
52
|
}
|
|
54
53
|
async function status() {
|
|
55
54
|
const session = readRecord(sessionPath);
|
|
56
55
|
const running = await alive(session);
|
|
57
56
|
const result = running ? await health(session) : null;
|
|
58
57
|
return { running: running && result?.status === 'ok', processRunning: running, pid: session?.pid,
|
|
59
|
-
port: session?.port, mode: result?.transportMode, execution: result?.execution,
|
|
58
|
+
port: session?.port, mode: result?.transportMode, version: result?.version, execution: result?.execution,
|
|
60
59
|
managedAppServer: result?.managedAppServer, desktop: result?.desktop,
|
|
61
60
|
desktopRestartRecommended: result?.desktopRestartRecommended === true,
|
|
62
61
|
resident: result?.resident === true };
|
|
63
62
|
}
|
|
64
|
-
async function pair() {
|
|
63
|
+
async function pair() {
|
|
65
64
|
const session = readRecord(sessionPath);
|
|
66
65
|
const connection = await alive(session) ? await health(session) : null;
|
|
67
66
|
if (connection?.status !== 'ok' || !session.lan) {
|
|
@@ -76,15 +75,17 @@ export function lifecycle({ stateRoot, host }) {
|
|
|
76
75
|
execution: connection.execution, managedAppServer: connection.managedAppServer, desktop: connection.desktop,
|
|
77
76
|
desktopRestartRecommended: connection.desktopRestartRecommended === true, accessUrl: session.accessUrl,
|
|
78
77
|
qrPath: path.join(stateRoot, 'connection-qr.png') };
|
|
79
|
-
}
|
|
78
|
+
}
|
|
79
|
+
async function restartManagedAppServer() {
|
|
80
|
+
const session = readRecord(sessionPath);
|
|
81
|
+
if (!await alive(session)) throw new Error('桌面服务尚未运行,无法迁移 Codex 内核。');
|
|
82
|
+
return controlRequest(session, 'POST', 'restart-managed-app-server');
|
|
83
|
+
}
|
|
80
84
|
async function start() {
|
|
81
85
|
let session = readRecord(sessionPath);
|
|
82
86
|
if (await alive(session)) {
|
|
83
87
|
const result = await health(session);
|
|
84
88
|
if (session.scriptPath === scriptPath && session.lan && result?.status === 'ok' && result.resident) {
|
|
85
|
-
const context = readRecord(contextPath) || {};
|
|
86
|
-
const sourceThreadId = process.env.CODEX_THREAD_ID || process.env.CODEX_SESSION_ID || context.sourceThreadId;
|
|
87
|
-
writeRecord(contextPath, { sourceThreadId });
|
|
88
89
|
await controlRequest(session, 'POST', 'refresh-execution');
|
|
89
90
|
return pair();
|
|
90
91
|
}
|
|
@@ -97,9 +98,8 @@ export function lifecycle({ stateRoot, host }) {
|
|
|
97
98
|
throw new Error('bridge-config.json 中端口或 Token 无效;不会自动重置凭据。');
|
|
98
99
|
}
|
|
99
100
|
const address = await host.lanAddress() || '127.0.0.1';
|
|
100
|
-
const { executable, environment } = await host.
|
|
101
|
-
writeRecord(configPath, config);
|
|
102
|
-
writeRecord(contextPath, { sourceThreadId: environment.CODEX_THREAD_ID || environment.CODEX_SESSION_ID });
|
|
101
|
+
const { executable, environment } = await host.bridgeEnvironment();
|
|
102
|
+
writeRecord(configPath, config);
|
|
103
103
|
const instanceId = randomUUID();
|
|
104
104
|
const controlSecret = randomBytes(32).toString('base64url');
|
|
105
105
|
const readyPath = path.join(stateRoot, `bridge-ready-${instanceId}.json`);
|
|
@@ -110,11 +110,11 @@ export function lifecycle({ stateRoot, host }) {
|
|
|
110
110
|
const deadline = Date.now() + 10000;
|
|
111
111
|
let ready;
|
|
112
112
|
while (!(ready = readRecord(readyPath))) {
|
|
113
|
-
if (!processAlive(pid)) throw new Error('
|
|
114
|
-
if (Date.now() > deadline) throw new Error('
|
|
113
|
+
if (!processAlive(pid)) throw new Error('桌面服务启动失败,请查看 bridge.stderr.log。');
|
|
114
|
+
if (Date.now() > deadline) throw new Error('桌面服务未在 10 秒内就绪。');
|
|
115
115
|
await delay(100);
|
|
116
116
|
}
|
|
117
|
-
if (ready.instanceId !== instanceId || ready.pid !== pid) throw new Error('
|
|
117
|
+
if (ready.instanceId !== instanceId || ready.pid !== pid) throw new Error('桌面服务启动实例不匹配。');
|
|
118
118
|
session = { ...ready, controlSecret, executablePath: executable, scriptPath, port: config.port,
|
|
119
119
|
lan: true, appServer: false, accessUrl: `http://${address}:${config.port}/?token=${config.token}`,
|
|
120
120
|
startedAt: new Date().toISOString() };
|
|
@@ -126,5 +126,5 @@ export function lifecycle({ stateRoot, host }) {
|
|
|
126
126
|
throw error;
|
|
127
127
|
} finally { fs.rmSync(readyPath, { force: true }); }
|
|
128
128
|
}
|
|
129
|
-
return { start, pair, status, stop };
|
|
130
|
-
}
|
|
129
|
+
return { start, pair, status, stop, restartManagedAppServer };
|
|
130
|
+
}
|