Files
qwen-code/scripts/opentui-package-assets.js
T
ChiGao c7c9717d07 fix(cli): run OpenTUI on private Bun 1.4.4 (#15387)
* fix(cli): run OpenTUI on private Bun 1.4.4

* docs(cli): bind runtime acceptance to integrated main

* test(cli): add permanent installed npm runtime acceptance

* ci: record installed TUI workflow size

* ci: record installed TUI job budget

* ci: quote missing installed artifact failure mode

* fix(core): preserve encrypted storage identity across Bun handoff

* fix(test): retain installed command startup evidence

* fix(cli): reject Bun loader options during npm handoff
2026-10-25 11:50:17 +08:00

131 lines
4.1 KiB
JavaScript

/**
* @license
* Copyright 2026 Qwen Team
* SPDX-License-Identifier: Apache-2.0
*/
import { execFileSync } from 'node:child_process';
import fs from 'node:fs';
import path from 'node:path';
import { parse as parseYaml } from 'yaml';
export const NPM_BUN_OPTIONAL_DEPENDENCIES = Object.fromEntries(
[
'@oven/bun-darwin-aarch64',
'@oven/bun-darwin-x64',
'@oven/bun-linux-aarch64',
'@oven/bun-linux-x64',
].map((name) => [name, '1.4.4']),
);
export const NPM_OPENTUI_NATIVE_ASSETS = {
'@opentui/core-darwin-arm64': 'libopentui.dylib',
'@opentui/core-darwin-x64': 'libopentui.dylib',
'@opentui/core-linux-arm64': 'libopentui.so',
'@opentui/core-linux-x64': 'libopentui.so',
};
export const OPENTUI_COMMON_ASSETS = [
'@opentui/core/parser.worker.js',
'@opentui/core/assets/javascript/highlights.scm',
'@opentui/core/assets/javascript/tree-sitter-javascript.wasm',
'@opentui/core/assets/typescript/highlights.scm',
'@opentui/core/assets/typescript/tree-sitter-typescript.wasm',
'@opentui/core/assets/markdown/highlights.scm',
'@opentui/core/assets/markdown/injections.scm',
'@opentui/core/assets/markdown/tree-sitter-markdown.wasm',
'@opentui/core/assets/markdown_inline/highlights.scm',
'@opentui/core/assets/markdown_inline/tree-sitter-markdown_inline.wasm',
'@opentui/core/assets/zig/highlights.scm',
'@opentui/core/assets/zig/tree-sitter-zig.wasm',
'web-tree-sitter/tree-sitter.wasm',
];
function lockedVersions(rootDir, packageNames) {
const keys = Object.keys(
parseYaml(fs.readFileSync(path.join(rootDir, 'pnpm-lock.yaml'), 'utf8'))
?.packages ?? {},
);
return Object.fromEntries(
packageNames.map((name) => {
const versions = keys
.filter((key) => key.startsWith(`${name}@`))
.map((key) => key.slice(name.length + 1));
if (versions.length !== 1) {
throw new Error(
`OpenTUI platform package version is not locked for ${name}`,
);
}
return [name, versions[0]];
}),
);
}
export function stageOpenTuiPackages(rootDir, runtimeDir, packageNames) {
const installDir = path.join(runtimeDir, 'opentui-modules');
fs.mkdirSync(installDir, { recursive: true });
const npmExecPath = process.env.npm_execpath;
if (!npmExecPath) {
throw new Error('npm_execpath is unavailable; run packaging via npm run');
}
const versions = lockedVersions(rootDir, packageNames);
execFileSync(
process.execPath,
[
npmExecPath,
'install',
'--prefix',
installDir,
'--package-lock=false',
'--no-save',
'--ignore-scripts',
'--force',
'--no-audit',
'--no-fund',
...Object.entries(versions).map(
([name, version]) => `${name}@${version}`,
),
],
{ cwd: rootDir, stdio: 'inherit' },
);
const modulesDir = path.join(installDir, 'node_modules');
for (const [name, version] of Object.entries(versions)) {
const installed = JSON.parse(
fs.readFileSync(path.join(modulesDir, name, 'package.json'), 'utf8'),
);
if (installed.name !== name || installed.version !== version) {
throw new Error(
`Staged OpenTUI package does not match ${name}@${version}`,
);
}
}
return modulesDir;
}
export function prepareNpmOpenTuiAssets(distDir, modulesDir) {
const assetRoot = path.join(distDir, 'opentui-assets');
if (modulesDir) {
for (const [name, library] of Object.entries(NPM_OPENTUI_NATIVE_ASSETS)) {
const destination = path.join(assetRoot, name, library);
fs.mkdirSync(path.dirname(destination), { recursive: true });
fs.copyFileSync(path.join(modulesDir, name, library), destination);
}
}
const required = [
...OPENTUI_COMMON_ASSETS,
...Object.entries(NPM_OPENTUI_NATIVE_ASSETS).map(
([name, library]) => `${name}/${library}`,
),
];
for (const key of required) {
let present = false;
try {
present = fs.statSync(path.join(assetRoot, key)).isFile();
} catch {
// Report the asset key instead of an absolute temporary staging path.
}
if (!present)
throw new Error(`Required npm OpenTUI asset not found: ${key}`);
}
}