@walkhi/code-relax 0.1.0-beta.44 → 0.1.0-beta.45
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/dist/build-platform.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"layout":"npm-platform-packages","version":"0.1.0-beta.
|
|
1
|
+
{"layout":"npm-platform-packages","version":"0.1.0-beta.45"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
$ErrorActionPreference = 'Stop'
|
|
2
2
|
[Console]::InputEncoding = New-Object System.Text.UTF8Encoding($false)
|
|
3
3
|
[Console]::OutputEncoding = New-Object System.Text.UTF8Encoding($false)
|
|
4
|
+
$brokerStarted = $false
|
|
4
5
|
try {
|
|
5
6
|
$spec = [Console]::In.ReadToEnd() | ConvertFrom-Json
|
|
6
7
|
# WMI owns this launch, not the caller's kill-on-close Desktop job hierarchy.
|
|
@@ -13,10 +14,15 @@ try {
|
|
|
13
14
|
$request = Join-Path $launchRoot ($instance + '.request.json')
|
|
14
15
|
$diagnostic = Join-Path $launchRoot ($instance + '.broker.log')
|
|
15
16
|
$spec | Add-Member -NotePropertyName instance -NotePropertyValue $instance
|
|
16
|
-
$spec | Add-Member -NotePropertyName diagnostic -NotePropertyValue $diagnostic
|
|
17
17
|
$requestTemporary = $request + '.tmp'
|
|
18
18
|
[IO.File]::WriteAllText($requestTemporary, ($spec | ConvertTo-Json -Compress -Depth 10), (New-Object Text.UTF8Encoding($false)))
|
|
19
19
|
[IO.File]::Move($requestTemporary, $request)
|
|
20
|
+
# MSIX can redirect a newly written file even when its existing parent
|
|
21
|
+
# resolves outside the package. Resolve the file handle, not just the folder.
|
|
22
|
+
$request = [IsolatedProcess]::ResolvePath($request)
|
|
23
|
+
$launchRoot = [IO.Path]::GetDirectoryName($request)
|
|
24
|
+
$ready = Join-Path $launchRoot ($instance + '.json')
|
|
25
|
+
$diagnostic = Join-Path $launchRoot ($instance + '.broker.log')
|
|
20
26
|
$startup = New-CimInstance -ClassName Win32_ProcessStartup -ClientOnly -Property @{
|
|
21
27
|
ShowWindow=[uint16]0; CreateFlags=[uint32]0x1000010
|
|
22
28
|
}
|
|
@@ -26,6 +32,7 @@ try {
|
|
|
26
32
|
CommandLine=$command; CurrentDirectory=$env:USERPROFILE; ProcessStartupInformation=$startup
|
|
27
33
|
}
|
|
28
34
|
if ($broker.ReturnValue -ne 0) { throw ('Windows process broker failed: ' + $broker.ReturnValue) }
|
|
35
|
+
$brokerStarted = $true
|
|
29
36
|
$deadline = [DateTime]::UtcNow.AddSeconds(30)
|
|
30
37
|
while (-not (Test-Path -LiteralPath $ready)) {
|
|
31
38
|
if ([DateTime]::UtcNow -gt $deadline) {
|
|
@@ -44,6 +51,8 @@ try {
|
|
|
44
51
|
[Console]::Error.WriteLine($_.Exception.Message)
|
|
45
52
|
exit 1
|
|
46
53
|
} finally {
|
|
47
|
-
|
|
54
|
+
# Once launched, the worker owns consumption. A slow broker must not lose
|
|
55
|
+
# its request merely because this caller timed out; never launch a retry.
|
|
56
|
+
if (-not $brokerStarted -and $request -and (Test-Path -LiteralPath $request)) { Remove-Item -LiteralPath $request -Force }
|
|
48
57
|
if ($requestTemporary -and (Test-Path -LiteralPath $requestTemporary)) { Remove-Item -LiteralPath $requestTemporary -Force }
|
|
49
58
|
}
|
|
@@ -989,7 +989,7 @@ function controlPayload(value) {
|
|
|
989
989
|
const message = JSON.parse(value);
|
|
990
990
|
if (message.type === 'unsubscribe') return true;
|
|
991
991
|
return ['request', 'subscribe'].includes(message.type) && typeof message.path === 'string' &&
|
|
992
|
-
(message.path === '/api/health' || message.path.startsWith('/api/shared-recovery'));
|
|
992
|
+
(message.path === '/api/health' || message.path === '/api/desktop/start' || message.path.startsWith('/api/shared-recovery'));
|
|
993
993
|
} catch { return false; }
|
|
994
994
|
}
|
|
995
995
|
|
package/dist/src/server.mjs
CHANGED
|
@@ -261,10 +261,10 @@ async function handleRequest(request, response) {
|
|
|
261
261
|
if (request.method === 'GET' && url.pathname === '/api/shared-recovery') {
|
|
262
262
|
sendJson(response, 200, await recoveryStatus(stateRoot)); return;
|
|
263
263
|
}
|
|
264
|
-
if (request.method === 'POST' &&
|
|
264
|
+
if (request.method === 'POST' && ['/api/shared-recovery', '/api/desktop/start'].includes(url.pathname)) {
|
|
265
265
|
const body = await readJsonBody(request);
|
|
266
266
|
if (body.confirmed !== true || typeof body.operationId !== 'string') throw new RequestError(400, '请确认重新打开当前 Codex 并接入 Codex 内核后再继续。');
|
|
267
|
-
sendJson(response, 202, await requestRecovery(stateRoot, body)); return;
|
|
267
|
+
sendJson(response, 202, await requestRecovery(stateRoot, { ...body, startOnly: url.pathname === '/api/desktop/start' })); return;
|
|
268
268
|
}
|
|
269
269
|
if (url.pathname === '/api/service/update' && request.method === 'GET') {
|
|
270
270
|
sendJson(response, 200, await checkServiceUpdate(stateRoot)); return;
|
|
@@ -9,13 +9,19 @@ import { desktopHost } from './platform/desktop-host.mjs';
|
|
|
9
9
|
const versionPattern = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/;
|
|
10
10
|
const statusPath = root => path.join(root, 'service-update.json');
|
|
11
11
|
const installation = () => readRecord(path.join(runtimePaths().serviceRoot, 'installation.json'));
|
|
12
|
+
export function publicUpdateOperation(record, installedVersion) {
|
|
13
|
+
if (!record) return null;
|
|
14
|
+
return { operationId: record.operationId, targetVersion: record.targetVersion,
|
|
15
|
+
status: record.status, targetInstalled: Boolean(installedVersion && installedVersion === record.targetVersion),
|
|
16
|
+
error: record.status === 'failed' ? '上次更新未完整完成,请查看工作站更新日志。' : null,
|
|
17
|
+
installedVersion: record.installedVersion || null };
|
|
18
|
+
}
|
|
12
19
|
export function serviceUpdateStatus(root) {
|
|
13
20
|
const record = readRecord(statusPath(root));
|
|
14
21
|
const installed = installation();
|
|
15
22
|
return { supported: Boolean(installed?.npmCliPath && fs.existsSync(installed.npmCliPath)),
|
|
16
23
|
currentVersion: installed?.version || null,
|
|
17
|
-
operation: record
|
|
18
|
-
status: record.status, error: record.error || null, installedVersion: record.installedVersion || null } : null };
|
|
24
|
+
operation: publicUpdateOperation(record, installed?.version) };
|
|
19
25
|
}
|
|
20
26
|
export async function checkServiceUpdate(root) {
|
|
21
27
|
const result = await fetch('https://registry.npmjs.org/@walkhi%2fcode-relax/latest', { signal: AbortSignal.timeout(12000) });
|
|
@@ -64,7 +70,7 @@ export async function requestServiceUpdate(root, body) {
|
|
|
64
70
|
pid: owner.pid, created: owner.created, executable: owner.executable } });
|
|
65
71
|
} catch (error) {
|
|
66
72
|
writeRecord(statusPath(root), { ...readRecord(statusPath(root)), status: 'failed', error: error.message });
|
|
67
|
-
throw
|
|
73
|
+
throw new Error('工作站更新启动未完成,请查看工作站更新日志;结果确认前不要重复提交。');
|
|
68
74
|
}
|
|
69
75
|
return serviceUpdateStatus(root);
|
|
70
76
|
} finally { scheduling = false; }
|
|
@@ -51,7 +51,7 @@ export async function planRecovery(stateRoot, host, available = portAvailable) {
|
|
|
51
51
|
return { desktop: info.desktop, action };
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
export async function requestRecovery(stateRoot, { confirmed, operationId = randomUUID() } = {}, host = desktopHost) {
|
|
54
|
+
export async function requestRecovery(stateRoot, { confirmed, operationId = randomUUID(), startOnly = false } = {}, host = desktopHost) {
|
|
55
55
|
if (host.desktopIntegration === false) throw new Error('此平台尚不支持 Desktop 自动接入。');
|
|
56
56
|
if (confirmed !== true) throw new Error(recoveryWarning + ' 请明确确认后再执行。');
|
|
57
57
|
if (!/^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$/i.test(operationId)) throw new Error('无效的恢复操作编号。');
|
|
@@ -60,12 +60,13 @@ export async function requestRecovery(stateRoot, { confirmed, operationId = rand
|
|
|
60
60
|
if (previous.operationId === operationId) return previous;
|
|
61
61
|
if (active(previous)) throw new Error('已有恢复操作正在执行,请查看恢复状态。');
|
|
62
62
|
const planned = await planRecovery(stateRoot, host);
|
|
63
|
+
if (startOnly && (await host.inspect()).running) throw new Error('Codex 桌面端已经启动,未执行重启。');
|
|
63
64
|
let lock;
|
|
64
65
|
try { lock = fs.openSync(lockPath(stateRoot), 'wx'); }
|
|
65
66
|
catch (error) { if (error.code === 'EEXIST') throw new Error('已有恢复操作,请先查看恢复状态。'); throw error; }
|
|
66
67
|
fs.writeFileSync(lock, JSON.stringify({ operationId })); fs.closeSync(lock);
|
|
67
68
|
const record = { operationId, status: 'scheduled', stage: 'prepared', startedAt: new Date().toISOString(),
|
|
68
|
-
message: 'Codex 连接请求已接受,电脑管理连接保持运行。', steps: recoverySteps(), ...planned };
|
|
69
|
+
message: 'Codex 连接请求已接受,电脑管理连接保持运行。', startOnly, steps: recoverySteps().filter(step => !startOnly || step.id !== 'stopping-desktop'), ...planned };
|
|
69
70
|
try {
|
|
70
71
|
writeRecord(recordPath(stateRoot), record);
|
|
71
72
|
const log = path.join(stateRoot, 'shared-recovery.log');
|
|
@@ -103,7 +104,9 @@ export async function runRecovery(stateRoot, operationId, dependencies = {}) {
|
|
|
103
104
|
const planned = await planRecovery(stateRoot, host, available);
|
|
104
105
|
record = { ...record, ...planned };
|
|
105
106
|
if (fs.existsSync(path.join(stateRoot, 'desktop-launch.lock'))) throw new Error('Desktop 正在启动,未与启动操作并行恢复。');
|
|
106
|
-
|
|
107
|
+
if (record.startOnly) {
|
|
108
|
+
if ((await host.inspect()).running) throw new Error('Codex 桌面端已经启动,未执行重启。');
|
|
109
|
+
} else { stage('stopping-desktop'); await host.closeDesktop(record.desktop); }
|
|
107
110
|
await waitFor(async () => !(await host.inspect()).running, '当前 Codex Desktop 未退出,未继续接入 Codex 内核。');
|
|
108
111
|
stage('starting-app-server'); await start({ stateRoot, host, recoveryId: operationId, progress: stage });
|
|
109
112
|
stage('checking-execution');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@walkhi/code-relax",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.45",
|
|
4
4
|
"private": false,
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|
|
@@ -41,8 +41,8 @@
|
|
|
41
41
|
"tag": "beta"
|
|
42
42
|
},
|
|
43
43
|
"optionalDependencies": {
|
|
44
|
-
"@walkhi/code-relax-native-win32-x64": "0.1.0-beta.
|
|
45
|
-
"@walkhi/code-relax-native-darwin-arm64": "0.1.0-beta.
|
|
46
|
-
"@walkhi/code-relax-native-darwin-x64": "0.1.0-beta.
|
|
44
|
+
"@walkhi/code-relax-native-win32-x64": "0.1.0-beta.45",
|
|
45
|
+
"@walkhi/code-relax-native-darwin-arm64": "0.1.0-beta.45",
|
|
46
|
+
"@walkhi/code-relax-native-darwin-x64": "0.1.0-beta.45"
|
|
47
47
|
}
|
|
48
48
|
}
|