@walkhi/code-relax 0.1.0-beta.50 → 0.1.0-beta.51

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.
Files changed (89) hide show
  1. package/README.md +105 -105
  2. package/dist/bin/cleanup-accounts.mjs +63 -63
  3. package/dist/bin/codex-remote.mjs +403 -403
  4. package/dist/bin/publish-android-release.mjs +63 -63
  5. package/dist/bin/release-upload-server.mjs +190 -190
  6. package/dist/build-platform.json +1 -1
  7. package/dist/get-shared-service-url.ps1 +14 -14
  8. package/dist/shared/code-browser.cjs +159 -159
  9. package/dist/shared/file-changes.cjs +31 -31
  10. package/dist/shared/file-citations.cjs +117 -117
  11. package/dist/shared/file-mentions.cjs +92 -92
  12. package/dist/shared/message-delivery.cjs +115 -115
  13. package/dist/shared/p2p-file-channel.cjs +87 -87
  14. package/dist/shared/server-requests.cjs +311 -311
  15. package/dist/shared/timeline-sync.cjs +173 -173
  16. package/dist/skills/code-relax/SKILL.md +22 -22
  17. package/dist/src/bounded-process-log.mjs +63 -63
  18. package/dist/src/celsius-client.mjs +107 -107
  19. package/dist/src/dots-approval-timeline.mjs +99 -99
  20. package/dist/src/dots-avatar.mjs +42 -42
  21. package/dist/src/dots-chat-projection.mjs +50 -50
  22. package/dist/src/dots-chat-server.mjs +483 -483
  23. package/dist/src/dots-message-images.mjs +319 -319
  24. package/dist/src/dots-profile.mjs +77 -77
  25. package/dist/src/dots-room-activity.mjs +172 -172
  26. package/dist/src/dots-room-client.mjs +135 -135
  27. package/dist/src/dots-room-projection.mjs +94 -94
  28. package/dist/src/dots-schedules.mjs +66 -66
  29. package/dist/src/dots-summary-tasks.mjs +32 -32
  30. package/dist/src/dots-task-catalog.mjs +430 -430
  31. package/dist/src/file-transfer-range.mjs +22 -22
  32. package/dist/src/file-upload-session.mjs +130 -130
  33. package/dist/src/hosted-history-app-server.mjs +103 -103
  34. package/dist/src/hosted-history-cache.mjs +113 -113
  35. package/dist/src/lan-socket-server.mjs +266 -266
  36. package/dist/src/managed-app-server.mjs +373 -373
  37. package/dist/src/managed-endpoint.mjs +25 -25
  38. package/dist/src/message-upload-files.mjs +109 -109
  39. package/dist/src/onboarding.mjs +12 -12
  40. package/dist/src/platform/README.md +1 -1
  41. package/dist/src/platform/codex-protocol.mjs +46 -46
  42. package/dist/src/platform/desktop-project-store.mjs +208 -208
  43. package/dist/src/platform/linux/desktop-host.mjs +87 -87
  44. package/dist/src/platform/linux/process.mjs +53 -53
  45. package/dist/src/platform/linux/system.mjs +50 -50
  46. package/dist/src/platform/linux/user-environment.mjs +9 -9
  47. package/dist/src/platform/macos/codex-runtime.mjs +125 -125
  48. package/dist/src/platform/macos/desktop-host.mjs +86 -86
  49. package/dist/src/platform/macos/user-environment.mjs +9 -9
  50. package/dist/src/platform/native-package.mjs +58 -58
  51. package/dist/src/platform/windows/activate-desktop.ps1 +49 -49
  52. package/dist/src/platform/windows/codex-runtime.mjs +215 -215
  53. package/dist/src/platform/windows/credential-store.mjs +27 -27
  54. package/dist/src/platform/windows/credential-store.ps1 +49 -49
  55. package/dist/src/platform/windows/desktop-host.mjs +65 -65
  56. package/dist/src/platform/windows/desktop-info.ps1 +38 -38
  57. package/dist/src/platform/windows/desktop-project-registration.mjs +4 -4
  58. package/dist/src/platform/windows/desktop-shortcuts.ps1 +14 -14
  59. package/dist/src/platform/windows/dots-profile.mjs +49 -49
  60. package/dist/src/platform/windows/launch-worker.mjs +41 -41
  61. package/dist/src/platform/windows/project-locations.mjs +16 -16
  62. package/dist/src/platform/windows/service-host.mjs +35 -35
  63. package/dist/src/platform/windows/user-environment.mjs +52 -52
  64. package/dist/src/project-management.mjs +58 -58
  65. package/dist/src/runtime-discovery.mjs +47 -47
  66. package/dist/src/self-relay/account-cleanup.mjs +30 -30
  67. package/dist/src/self-relay/admin-page.mjs +80 -80
  68. package/dist/src/self-relay/admin-style.mjs +14 -14
  69. package/dist/src/self-relay/connector.mjs +439 -439
  70. package/dist/src/self-relay/demo.mjs +31 -31
  71. package/dist/src/self-relay/diagnostics.mjs +54 -54
  72. package/dist/src/self-relay/email-accounts.mjs +183 -183
  73. package/dist/src/self-relay/file-wire.mjs +13 -13
  74. package/dist/src/self-relay/p2p-probe.mjs +168 -168
  75. package/dist/src/self-relay/privacy-page.mjs +26 -26
  76. package/dist/src/self-relay/public-releases.mjs +67 -67
  77. package/dist/src/self-relay/rtc-file-bridge.mjs +41 -41
  78. package/dist/src/self-relay/usage-meter.mjs +141 -141
  79. package/dist/src/server.mjs +5 -4
  80. package/dist/src/service-doctor.mjs +148 -148
  81. package/dist/src/service-install.mjs +97 -97
  82. package/dist/src/service-lifecycle.mjs +139 -139
  83. package/dist/src/shared-app-server.mjs +666 -666
  84. package/dist/src/shared-catalog.mjs +132 -132
  85. package/dist/src/shared-thread-stream.mjs +165 -165
  86. package/dist/src/usage-reset.mjs +17 -17
  87. package/dist/src/workstation-downloads.mjs +120 -120
  88. package/package.json +4 -4
  89. package/tools/postinstall.mjs +186 -186
@@ -1,139 +1,139 @@
1
- import fs from 'node:fs';
2
- import path from 'node:path';
3
- import { startBackground, processAlive } from './background-process.mjs';
4
- import { randomBytes, randomUUID } from 'node:crypto';
5
- import { setTimeout as delay } from 'node:timers/promises';
6
- import { fileURLToPath } from 'node:url';
7
- import { controlRequest } from './service-control.mjs';
8
- import { serviceHealth as health } from './service-health.mjs';
9
-
10
- export function readRecord(file) {
11
- try { return JSON.parse(fs.readFileSync(file, 'utf8').replace(/^\uFEFF/, '')); }
12
- catch (error) { if (error.code === 'ENOENT') return null; throw error; }
13
- }
14
- export function writeRecord(file, value) {
15
- const temp = `${file}.${randomUUID()}.tmp`;
16
- try {
17
- fs.writeFileSync(temp, JSON.stringify(value, null, 2), { mode: 0o600 });
18
- fs.renameSync(temp, file);
19
- } finally { fs.rmSync(temp, { force: true }); }
20
- }
21
-
22
- export function lifecycle({ stateRoot, host }) {
23
- fs.mkdirSync(stateRoot, { recursive: true });
24
- const sessionPath = path.join(stateRoot, 'bridge-session.json');
25
- const configPath = path.join(stateRoot, 'bridge-config.json');
26
- const scriptPath = fileURLToPath(new URL('./server.mjs', import.meta.url));
27
-
28
- async function alive(session) {
29
- if (!session?.controlPort || !session.instanceId || !session.controlSecret) {
30
- if (await health(session)) throw new Error('当前为旧版桌面服务,请先使用旧版停止入口结束服务,再启动新版。');
31
- return false;
32
- }
33
- try { await controlRequest(session); return true; }
34
- catch (error) { if (error.code === 'ECONNREFUSED') return false; throw error; }
35
- }
36
- async function stop() {
37
- const session = readRecord(sessionPath);
38
- if (!await alive(session)) return { stopped: true, message: '桌面服务已停止。' };
39
- await controlRequest(session, 'POST');
40
- const deadline = Date.now() + 10000;
41
- while (true) {
42
- try { if (!await alive(session)) break; }
43
- catch (error) {
44
- // A connection accepted just before the listener closes may be reset.
45
- // Verify refusal on the next connection; never resend the shutdown request.
46
- if (error.code !== 'ECONNRESET') throw error;
47
- }
48
- if (Date.now() > deadline) throw new Error('桌面服务未在 10 秒内退出;未强杀进程。');
49
- await delay(100);
50
- }
51
- return { stopped: true, message: '桌面服务已正常关闭。' };
52
- }
53
- async function status() {
54
- const session = readRecord(sessionPath);
55
- const running = await alive(session);
56
- const result = running ? await health(session) : null;
57
- return { running: running && result?.status === 'ok', processRunning: running, pid: session?.pid,
58
- port: session?.port, mode: result?.transportMode, version: result?.version, execution: result?.execution,
59
- managedAppServer: result?.managedAppServer, desktop: result?.desktop,
60
- keepAwake: result?.keepAwake,
61
- desktopRestartRecommended: result?.desktopRestartRecommended === true,
62
- resident: result?.resident === true };
63
- }
64
- async function pair() {
65
- const session = readRecord(sessionPath);
66
- const connection = await alive(session) ? await health(session) : null;
67
- if (connection?.status !== 'ok' || !session.lan) {
68
- throw new Error('没有健康的局域网服务,请先执行 relax start。');
69
- }
70
- const address = await host.lanAddress();
71
- const url = new URL(session.accessUrl);
72
- url.hostname = address || '127.0.0.1';
73
- session.accessUrl = url.href;
74
- writeRecord(sessionPath, session);
75
- return { pid: session.pid, port: session.port, version: connection.version, transportMode: connection.transportMode,
76
- execution: connection.execution, managedAppServer: connection.managedAppServer, desktop: connection.desktop,
77
- desktopRestartRecommended: connection.desktopRestartRecommended === true, accessUrl: session.accessUrl,
78
- qrPath: path.join(stateRoot, 'connection-qr.png') };
79
- }
80
- async function restartManagedAppServer(confirmed = false) {
81
- const session = readRecord(sessionPath);
82
- if (!await alive(session)) throw new Error('桌面服务尚未运行,无法迁移 Codex 内核。');
83
- const action = confirmed ? 'restart-managed-app-server-confirmed' : 'restart-managed-app-server';
84
- return controlRequest(session, 'POST', action);
85
- }
86
- async function startBridge() {
87
- let session = readRecord(sessionPath);
88
- if (await alive(session)) {
89
- const result = await health(session);
90
- if (session.scriptPath === scriptPath && session.lan && result?.status === 'ok' && result.resident) {
91
- await controlRequest(session, 'POST', 'refresh-execution');
92
- return pair();
93
- }
94
- await stop();
95
- }
96
- let config = readRecord(configPath);
97
- if (!config && session?.lan) config = { port: session.port, token: new URL(session.accessUrl).searchParams.get('token') };
98
- config ||= { port: 45831, token: randomBytes(32).toString('base64url') };
99
- if (!Number.isInteger(config.port) || config.port < 1 || config.port > 65535 || !/^[A-Za-z0-9_-]{20,}$/.test(config.token)) {
100
- throw new Error('bridge-config.json 中端口或 Token 无效;不会自动重置凭据。');
101
- }
102
- const address = await host.lanAddress() || '127.0.0.1';
103
- const { executable, environment } = await host.bridgeEnvironment();
104
- writeRecord(configPath, config);
105
- const instanceId = randomUUID();
106
- const controlSecret = randomBytes(32).toString('base64url');
107
- const readyPath = path.join(stateRoot, `bridge-ready-${instanceId}.json`);
108
- const pid = await startBackground(executable, [scriptPath, '--lan', '--port', String(config.port), '--token', config.token],
109
- { ...environment, CODEX_REMOTE_INSTANCE: instanceId, CODEX_REMOTE_CONTROL_SECRET: controlSecret,
110
- CODEX_REMOTE_READY_PATH: readyPath }, [path.join(stateRoot, 'bridge.stdout.log'), path.join(stateRoot, 'bridge.stderr.log')]);
111
- try {
112
- const deadline = Date.now() + 10000;
113
- let ready;
114
- while (!(ready = readRecord(readyPath))) {
115
- if (!processAlive(pid)) throw new Error('桌面服务启动失败,请查看 bridge.stderr.log。');
116
- if (Date.now() > deadline) throw new Error('桌面服务未在 10 秒内就绪。');
117
- await delay(100);
118
- }
119
- if (ready.instanceId !== instanceId || ready.pid !== pid) throw new Error('桌面服务启动实例不匹配。');
120
- session = { ...ready, controlSecret, executablePath: executable, scriptPath, port: config.port,
121
- lan: true, appServer: false, accessUrl: `http://${address}:${config.port}/?token=${config.token}`,
122
- startedAt: new Date().toISOString() };
123
- await controlRequest(session);
124
- writeRecord(sessionPath, session);
125
- return await pair();
126
- } catch (error) {
127
- if (processAlive(pid)) process.kill(pid);
128
- throw error;
129
- } finally { fs.rmSync(readyPath, { force: true }); }
130
- }
131
- async function start() {
132
- const result = await startBridge();
133
- if (fs.existsSync(path.join(stateRoot, 'self-relay-config.json'))) {
134
- await controlRequest(readRecord(sessionPath), 'POST', 'relay-start');
135
- }
136
- return result;
137
- }
138
- return { start, pair, status, stop, restartManagedAppServer };
139
- }
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { startBackground, processAlive } from './background-process.mjs';
4
+ import { randomBytes, randomUUID } from 'node:crypto';
5
+ import { setTimeout as delay } from 'node:timers/promises';
6
+ import { fileURLToPath } from 'node:url';
7
+ import { controlRequest } from './service-control.mjs';
8
+ import { serviceHealth as health } from './service-health.mjs';
9
+
10
+ export function readRecord(file) {
11
+ try { return JSON.parse(fs.readFileSync(file, 'utf8').replace(/^\uFEFF/, '')); }
12
+ catch (error) { if (error.code === 'ENOENT') return null; throw error; }
13
+ }
14
+ export function writeRecord(file, value) {
15
+ const temp = `${file}.${randomUUID()}.tmp`;
16
+ try {
17
+ fs.writeFileSync(temp, JSON.stringify(value, null, 2), { mode: 0o600 });
18
+ fs.renameSync(temp, file);
19
+ } finally { fs.rmSync(temp, { force: true }); }
20
+ }
21
+
22
+ export function lifecycle({ stateRoot, host }) {
23
+ fs.mkdirSync(stateRoot, { recursive: true });
24
+ const sessionPath = path.join(stateRoot, 'bridge-session.json');
25
+ const configPath = path.join(stateRoot, 'bridge-config.json');
26
+ const scriptPath = fileURLToPath(new URL('./server.mjs', import.meta.url));
27
+
28
+ async function alive(session) {
29
+ if (!session?.controlPort || !session.instanceId || !session.controlSecret) {
30
+ if (await health(session)) throw new Error('当前为旧版桌面服务,请先使用旧版停止入口结束服务,再启动新版。');
31
+ return false;
32
+ }
33
+ try { await controlRequest(session); return true; }
34
+ catch (error) { if (error.code === 'ECONNREFUSED') return false; throw error; }
35
+ }
36
+ async function stop() {
37
+ const session = readRecord(sessionPath);
38
+ if (!await alive(session)) return { stopped: true, message: '桌面服务已停止。' };
39
+ await controlRequest(session, 'POST');
40
+ const deadline = Date.now() + 10000;
41
+ while (true) {
42
+ try { if (!await alive(session)) break; }
43
+ catch (error) {
44
+ // A connection accepted just before the listener closes may be reset.
45
+ // Verify refusal on the next connection; never resend the shutdown request.
46
+ if (error.code !== 'ECONNRESET') throw error;
47
+ }
48
+ if (Date.now() > deadline) throw new Error('桌面服务未在 10 秒内退出;未强杀进程。');
49
+ await delay(100);
50
+ }
51
+ return { stopped: true, message: '桌面服务已正常关闭。' };
52
+ }
53
+ async function status() {
54
+ const session = readRecord(sessionPath);
55
+ const running = await alive(session);
56
+ const result = running ? await health(session) : null;
57
+ return { running: running && result?.status === 'ok', processRunning: running, pid: session?.pid,
58
+ port: session?.port, mode: result?.transportMode, version: result?.version, execution: result?.execution,
59
+ managedAppServer: result?.managedAppServer, desktop: result?.desktop,
60
+ keepAwake: result?.keepAwake,
61
+ desktopRestartRecommended: result?.desktopRestartRecommended === true,
62
+ resident: result?.resident === true };
63
+ }
64
+ async function pair() {
65
+ const session = readRecord(sessionPath);
66
+ const connection = await alive(session) ? await health(session) : null;
67
+ if (connection?.status !== 'ok' || !session.lan) {
68
+ throw new Error('没有健康的局域网服务,请先执行 relax start。');
69
+ }
70
+ const address = await host.lanAddress();
71
+ const url = new URL(session.accessUrl);
72
+ url.hostname = address || '127.0.0.1';
73
+ session.accessUrl = url.href;
74
+ writeRecord(sessionPath, session);
75
+ return { pid: session.pid, port: session.port, version: connection.version, transportMode: connection.transportMode,
76
+ execution: connection.execution, managedAppServer: connection.managedAppServer, desktop: connection.desktop,
77
+ desktopRestartRecommended: connection.desktopRestartRecommended === true, accessUrl: session.accessUrl,
78
+ qrPath: path.join(stateRoot, 'connection-qr.png') };
79
+ }
80
+ async function restartManagedAppServer(confirmed = false) {
81
+ const session = readRecord(sessionPath);
82
+ if (!await alive(session)) throw new Error('桌面服务尚未运行,无法迁移 Codex 内核。');
83
+ const action = confirmed ? 'restart-managed-app-server-confirmed' : 'restart-managed-app-server';
84
+ return controlRequest(session, 'POST', action);
85
+ }
86
+ async function startBridge() {
87
+ let session = readRecord(sessionPath);
88
+ if (await alive(session)) {
89
+ const result = await health(session);
90
+ if (session.scriptPath === scriptPath && session.lan && result?.status === 'ok' && result.resident) {
91
+ await controlRequest(session, 'POST', 'refresh-execution');
92
+ return pair();
93
+ }
94
+ await stop();
95
+ }
96
+ let config = readRecord(configPath);
97
+ if (!config && session?.lan) config = { port: session.port, token: new URL(session.accessUrl).searchParams.get('token') };
98
+ config ||= { port: 45831, token: randomBytes(32).toString('base64url') };
99
+ if (!Number.isInteger(config.port) || config.port < 1 || config.port > 65535 || !/^[A-Za-z0-9_-]{20,}$/.test(config.token)) {
100
+ throw new Error('bridge-config.json 中端口或 Token 无效;不会自动重置凭据。');
101
+ }
102
+ const address = await host.lanAddress() || '127.0.0.1';
103
+ const { executable, environment } = await host.bridgeEnvironment();
104
+ writeRecord(configPath, config);
105
+ const instanceId = randomUUID();
106
+ const controlSecret = randomBytes(32).toString('base64url');
107
+ const readyPath = path.join(stateRoot, `bridge-ready-${instanceId}.json`);
108
+ const pid = await startBackground(executable, [scriptPath, '--lan', '--port', String(config.port), '--token', config.token],
109
+ { ...environment, CODEX_REMOTE_INSTANCE: instanceId, CODEX_REMOTE_CONTROL_SECRET: controlSecret,
110
+ CODEX_REMOTE_READY_PATH: readyPath }, [path.join(stateRoot, 'bridge.stdout.log'), path.join(stateRoot, 'bridge.stderr.log')]);
111
+ try {
112
+ const deadline = Date.now() + 10000;
113
+ let ready;
114
+ while (!(ready = readRecord(readyPath))) {
115
+ if (!processAlive(pid)) throw new Error('桌面服务启动失败,请查看 bridge.stderr.log。');
116
+ if (Date.now() > deadline) throw new Error('桌面服务未在 10 秒内就绪。');
117
+ await delay(100);
118
+ }
119
+ if (ready.instanceId !== instanceId || ready.pid !== pid) throw new Error('桌面服务启动实例不匹配。');
120
+ session = { ...ready, controlSecret, executablePath: executable, scriptPath, port: config.port,
121
+ lan: true, appServer: false, accessUrl: `http://${address}:${config.port}/?token=${config.token}`,
122
+ startedAt: new Date().toISOString() };
123
+ await controlRequest(session);
124
+ writeRecord(sessionPath, session);
125
+ return await pair();
126
+ } catch (error) {
127
+ if (processAlive(pid)) process.kill(pid);
128
+ throw error;
129
+ } finally { fs.rmSync(readyPath, { force: true }); }
130
+ }
131
+ async function start() {
132
+ const result = await startBridge();
133
+ if (fs.existsSync(path.join(stateRoot, 'self-relay-config.json'))) {
134
+ await controlRequest(readRecord(sessionPath), 'POST', 'relay-start');
135
+ }
136
+ return result;
137
+ }
138
+ return { start, pair, status, stop, restartManagedAppServer };
139
+ }