Skip to content

Commit 3d4b136

Browse files
committed
chore: sync Qwen Code v0.21.13 (8/9)
1 parent 84d8b1b commit 3d4b136

100 files changed

Lines changed: 20602 additions & 5119 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

packages/desktop-shell/scripts/prepare-runtime.js

Lines changed: 122 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,20 @@ const sourceRoot = process.env.OPENWORK_ROOT?.trim()
1717
? path.resolve(process.env.OPENWORK_ROOT)
1818
: repoRoot;
1919
const runtimeDir = path.join(packageDir, 'runtime');
20-
const packageRoot = path.join(runtimeDir, 'openwork');
20+
const finalPackageRoot = path.join(runtimeDir, 'openwork');
2121
const refreshChecksums = process.argv.indexOf('--refresh-checksums');
2222
if (refreshChecksums !== -1) {
2323
const root = process.argv[refreshChecksums + 1]
2424
? path.resolve(process.argv[refreshChecksums + 1])
25-
: packageRoot;
25+
: finalPackageRoot;
2626
writeChecksums(root);
2727
console.log(`Refreshed OpenWork runtime checksums at ${root}`);
2828
process.exit(0);
2929
}
30+
fs.mkdirSync(runtimeDir, { recursive: true });
31+
recoverInterruptedRuntime();
32+
const stagingRoot = fs.mkdtempSync(path.join(runtimeDir, '.prepare-'));
33+
const packageRoot = path.join(stagingRoot, 'openwork');
3034
const libDir = path.join(packageRoot, 'lib');
3135
const nodeDir = path.join(packageRoot, 'node');
3236
const toolsDir = path.join(packageRoot, 'tools');
@@ -93,48 +97,52 @@ for (const required of [
9397
}
9498
}
9599

96-
fs.rmSync(runtimeDir, { recursive: true, force: true });
97-
fs.mkdirSync(libDir, { recursive: true });
98-
fs.writeFileSync(path.join(packageRoot, '.gitkeep'), '');
99-
fs.mkdirSync(binDir, { recursive: true });
100-
copyDirectory(distDir, libDir);
101-
installRuntimeDependencies(libDir, target);
102-
await installNodeRuntime(nodeDir, target);
103-
copyDocumentTools();
104-
await installUvRuntime(path.join(toolsDir, 'uv'), target);
105-
writeLaunchers(target);
106-
copyRequiredFile(
107-
path.join(sourceRoot, 'LICENSE'),
108-
path.join(packageRoot, 'LICENSE'),
109-
);
110-
copyRequiredFile(
111-
path.join(packageDir, 'NOTICE'),
112-
path.join(packageRoot, 'NOTICE'),
113-
);
114-
const nodeLicense = path.join(nodeDir, 'LICENSE');
115-
if (!fs.existsSync(nodeLicense)) {
116-
throw new Error(`Bundled Node.js license is missing: ${nodeLicense}`);
100+
try {
101+
fs.mkdirSync(libDir, { recursive: true });
102+
fs.writeFileSync(path.join(packageRoot, '.gitkeep'), '');
103+
fs.mkdirSync(binDir, { recursive: true });
104+
copyDirectory(distDir, libDir);
105+
installRuntimeDependencies(libDir, target);
106+
await installNodeRuntime(nodeDir, target);
107+
copyDocumentTools();
108+
await installUvRuntime(path.join(toolsDir, 'uv'), target);
109+
writeLaunchers(target);
110+
copyRequiredFile(
111+
path.join(sourceRoot, 'LICENSE'),
112+
path.join(packageRoot, 'LICENSE'),
113+
);
114+
copyRequiredFile(
115+
path.join(packageDir, 'NOTICE'),
116+
path.join(packageRoot, 'NOTICE'),
117+
);
118+
const nodeLicense = path.join(nodeDir, 'LICENSE');
119+
if (!fs.existsSync(nodeLicense)) {
120+
throw new Error(`Bundled Node.js license is missing: ${nodeLicense}`);
121+
}
122+
fs.writeFileSync(
123+
path.join(packageRoot, 'manifest.json'),
124+
`${JSON.stringify(
125+
{
126+
name: '@openwork/desktop-shell',
127+
desktopVersion,
128+
qwenCodeVersion,
129+
qwenCodeCommit: process.env.QWEN_CODE_COMMIT || gitCommit(sourceRoot),
130+
target,
131+
node: `v${process.versions.node}`,
132+
uv: uvVersion,
133+
builtAt: new Date().toISOString(),
134+
},
135+
null,
136+
2,
137+
)}\n`,
138+
);
139+
writeChecksums();
140+
replaceRuntime();
141+
} finally {
142+
fs.rmSync(stagingRoot, { recursive: true, force: true });
117143
}
118-
fs.writeFileSync(
119-
path.join(packageRoot, 'manifest.json'),
120-
`${JSON.stringify(
121-
{
122-
name: '@openwork/desktop-shell',
123-
desktopVersion,
124-
qwenCodeVersion,
125-
qwenCodeCommit: process.env.QWEN_CODE_COMMIT || gitCommit(sourceRoot),
126-
target,
127-
node: `v${process.versions.node}`,
128-
uv: uvVersion,
129-
builtAt: new Date().toISOString(),
130-
},
131-
null,
132-
2,
133-
)}\n`,
134-
);
135-
writeChecksums();
136144
console.log(
137-
`Prepared OpenWork desktop runtime at ${path.relative(repoRoot, packageRoot)}`,
145+
`Prepared OpenWork desktop runtime at ${path.relative(repoRoot, finalPackageRoot)}`,
138146
);
139147

140148
async function installNodeRuntime(destination, desktopTarget) {
@@ -148,19 +156,40 @@ async function installNodeRuntime(destination, desktopTarget) {
148156
}
149157
const archiveName = nodeArchiveName(nodeVersion, desktopTarget);
150158
const downloadRoot = `https://nodejs.org/dist/v${nodeVersion}`;
159+
const cacheRoot = process.env.QWEN_DESKTOP_NODE_CACHE_DIR
160+
? path.resolve(process.env.QWEN_DESKTOP_NODE_CACHE_DIR)
161+
: path.join(os.tmpdir(), 'qwen-desktop-node-cache');
162+
const cacheDir = path.join(cacheRoot, `v${nodeVersion}`);
163+
const cachedArchivePath = path.join(cacheDir, archiveName);
151164
const temporaryRoot = fs.mkdtempSync(
152165
path.join(os.tmpdir(), 'openwork-desktop-node-'),
153166
);
154167
try {
155168
const checksumsPath = path.join(temporaryRoot, 'SHASUMS256.txt');
156169
const archivePath = path.join(temporaryRoot, archiveName);
157170
await download(`${downloadRoot}/SHASUMS256.txt`, checksumsPath);
158-
await download(`${downloadRoot}/${archiveName}`, archivePath);
159-
verifyChecksum(
160-
archivePath,
161-
archiveName,
162-
fs.readFileSync(checksumsPath, 'utf8'),
163-
);
171+
const checksums = fs.readFileSync(checksumsPath, 'utf8');
172+
if (
173+
copyValidCachedArchive(
174+
cachedArchivePath,
175+
archivePath,
176+
archiveName,
177+
checksums,
178+
)
179+
) {
180+
console.log(`Using cached Node.js runtime ${archiveName}`);
181+
} else {
182+
await download(`${downloadRoot}/${archiveName}`, archivePath);
183+
verifyChecksum(archivePath, archiveName, checksums);
184+
fs.mkdirSync(cacheDir, { recursive: true });
185+
const temporaryCachePath = `${cachedArchivePath}.${process.pid}.tmp`;
186+
try {
187+
fs.copyFileSync(archivePath, temporaryCachePath);
188+
fs.renameSync(temporaryCachePath, cachedArchivePath);
189+
} finally {
190+
fs.rmSync(temporaryCachePath, { force: true });
191+
}
192+
}
164193
extractArchive(archivePath, temporaryRoot);
165194
const extractedRoot = path.join(
166195
temporaryRoot,
@@ -175,6 +204,24 @@ async function installNodeRuntime(destination, desktopTarget) {
175204
}
176205
}
177206

207+
function copyValidCachedArchive(
208+
cachedArchivePath,
209+
archivePath,
210+
archiveName,
211+
checksums,
212+
) {
213+
if (!fs.existsSync(cachedArchivePath)) return false;
214+
try {
215+
fs.copyFileSync(cachedArchivePath, archivePath);
216+
verifyChecksum(archivePath, archiveName, checksums);
217+
return true;
218+
} catch {
219+
fs.rmSync(cachedArchivePath, { force: true });
220+
fs.rmSync(archivePath, { force: true });
221+
return false;
222+
}
223+
}
224+
178225
function copyDocumentTools() {
179226
const resources = path.join(
180227
sourceRoot,
@@ -414,3 +461,30 @@ function copyDirectory(source, destination) {
414461
filter: (entry) => path.basename(entry) !== '.DS_Store',
415462
});
416463
}
464+
465+
function recoverInterruptedRuntime() {
466+
for (const entry of fs.readdirSync(runtimeDir)) {
467+
if (!entry.startsWith('.prepare-')) continue;
468+
const staleRoot = path.join(runtimeDir, entry);
469+
const previousRoot = path.join(staleRoot, 'previous');
470+
if (!fs.existsSync(finalPackageRoot) && fs.existsSync(previousRoot)) {
471+
fs.renameSync(previousRoot, finalPackageRoot);
472+
}
473+
fs.rmSync(staleRoot, { recursive: true, force: true });
474+
}
475+
}
476+
477+
function replaceRuntime() {
478+
const previousRoot = path.join(stagingRoot, 'previous');
479+
if (fs.existsSync(finalPackageRoot)) {
480+
fs.renameSync(finalPackageRoot, previousRoot);
481+
}
482+
try {
483+
fs.renameSync(packageRoot, finalPackageRoot);
484+
} catch (error) {
485+
if (fs.existsSync(previousRoot)) {
486+
fs.renameSync(previousRoot, finalPackageRoot);
487+
}
488+
throw error;
489+
}
490+
}

packages/desktop-shell/scripts/smoke-packaged.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@ const packageDir = path.resolve(
1111
path.dirname(fileURLToPath(import.meta.url)),
1212
'..',
1313
);
14+
const repoRoot = path.resolve(packageDir, '../..');
1415
const executable = process.argv[2];
1516
if (!executable)
1617
throw new Error('Usage: node scripts/smoke-packaged.js <executable>');
1718
if (!fs.statSync(executable, { throwIfNoEntry: false })?.isFile()) {
1819
throw new Error(`Packaged executable is missing: ${executable}`);
1920
}
21+
verifyMacRuntimeCommit();
2022

2123
const workspace = fs.mkdtempSync(
2224
path.join(os.tmpdir(), 'openwork-desktop-smoke-'),
@@ -216,3 +218,23 @@ function terminate(pid) {
216218
// The process may already have exited after the smoke succeeded or failed.
217219
}
218220
}
221+
222+
function verifyMacRuntimeCommit() {
223+
if (process.platform !== 'darwin') return;
224+
const manifestPath = path.resolve(
225+
path.dirname(executable),
226+
'../Resources/runtime/qwen-code/manifest.json',
227+
);
228+
const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
229+
const expected =
230+
process.env.QWEN_CODE_COMMIT ||
231+
execFileSync('git', ['rev-parse', 'HEAD'], {
232+
cwd: process.env.QWEN_CODE_ROOT || repoRoot,
233+
encoding: 'utf8',
234+
}).trim();
235+
if (manifest.qwenCodeCommit !== expected) {
236+
throw new Error(
237+
`Packaged runtime commit mismatch: expected ${expected}, found ${manifest.qwenCodeCommit || 'missing'}`,
238+
);
239+
}
240+
}

packages/desktop-shell/scripts/test-release.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ try {
3131
await testBootstrapStartup();
3232
testMacosPermissions();
3333
testReleaseWorkflow();
34+
testRuntimePreparationContract();
3435
testElectronBridgeManifest(path.join(root, 'electron-bridge'));
3536
testChecksumRefresh(path.join(root, 'checksums'));
3637
testVersionSynchronization(path.join(root, 'version'));
@@ -323,6 +324,21 @@ function testElectronBridgeManifest(directory) {
323324
assert.match(failure.stderr, /Expected one Electron bridge artifact/);
324325
}
325326

327+
function testRuntimePreparationContract() {
328+
const source = fs.readFileSync(
329+
path.join(packageDir, 'scripts', 'prepare-runtime.js'),
330+
'utf8',
331+
);
332+
assert.match(source, /QWEN_DESKTOP_NODE_CACHE_DIR/);
333+
assert.match(
334+
source,
335+
/const finalPackageRoot = path\.join\(runtimeDir, 'openwork'\)/,
336+
);
337+
assert.ok(
338+
source.indexOf('replaceRuntime();') > source.indexOf('writeChecksums();'),
339+
);
340+
}
341+
326342
function testChecksumRefresh(directory) {
327343
fs.mkdirSync(path.join(directory, 'nested'), { recursive: true });
328344
fs.writeFileSync(path.join(directory, 'one.txt'), 'one');
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"$schema": "../gen/schemas/desktop-schema.json",
3+
"identifier": "web-shell-external-url",
4+
"description": "Allows the daemon-served Web Shell to open browser-safe external URLs.",
5+
"local": false,
6+
"remote": { "urls": ["http://127.0.0.1:*"] },
7+
"windows": ["main"],
8+
"permissions": [
9+
{
10+
"identifier": "opener:allow-open-url",
11+
"allow": [
12+
{ "url": "http://*" },
13+
{ "url": "https://*" },
14+
{ "url": "mailto:*" }
15+
]
16+
}
17+
]
18+
}

0 commit comments

Comments
 (0)