143 lines
4.1 KiB
JavaScript
143 lines
4.1 KiB
JavaScript
#!/usr/bin/env node
|
||
/**
|
||
* 准备三端沙箱运行时资源
|
||
*
|
||
* 约定:
|
||
* - 子模块目录:../agent-sandbox-runtime(相对 crates/agent-electron-client)
|
||
* - 清单文件:manifest.json
|
||
* - 目标目录:resources/sandbox-runtime/bin
|
||
*
|
||
* (仅 Windows 客户端)Sandbox helper:manifest 的 win32 产物或另行构建的
|
||
* qiming-sandbox-helper.exe;亦可由 Rust crate crates/windows-sandbox-helper
|
||
* 通过 npm run build:sandbox-helper 生成到 resources/sandbox-helper。
|
||
*/
|
||
|
||
const fs = require("fs");
|
||
const path = require("path");
|
||
const crypto = require("crypto");
|
||
const { getProjectRoot } = require("../utils/project-paths");
|
||
|
||
const projectRoot = getProjectRoot();
|
||
const cratesDir = path.resolve(projectRoot, "..");
|
||
const sandboxRuntimeSubmodule = path.join(cratesDir, "agent-sandbox-runtime");
|
||
const manifestPath = path.join(sandboxRuntimeSubmodule, "manifest.json");
|
||
const targetRoot = path.join(projectRoot, "resources", "sandbox-runtime");
|
||
const targetBin = path.join(targetRoot, "bin");
|
||
|
||
function getPlatformKey() {
|
||
const arch = process.env.TARGET_ARCH || process.arch;
|
||
return `${process.platform}-${arch}`;
|
||
}
|
||
|
||
function sha256(filePath) {
|
||
const hash = crypto.createHash("sha256");
|
||
const data = fs.readFileSync(filePath);
|
||
hash.update(data);
|
||
return hash.digest("hex");
|
||
}
|
||
|
||
function ensureDir(dirPath) {
|
||
if (!fs.existsSync(dirPath)) {
|
||
fs.mkdirSync(dirPath, { recursive: true });
|
||
}
|
||
}
|
||
|
||
function normalizeEntry(entry) {
|
||
if (!entry) return null;
|
||
if (typeof entry === "string") {
|
||
return { source: entry };
|
||
}
|
||
if (typeof entry !== "object") return null;
|
||
const source = entry.source || entry.path || entry.file;
|
||
if (!source || typeof source !== "string") return null;
|
||
return {
|
||
source,
|
||
sha256: typeof entry.sha256 === "string" ? entry.sha256.toLowerCase() : null,
|
||
targetName: typeof entry.targetName === "string" ? entry.targetName : null,
|
||
};
|
||
}
|
||
|
||
function loadManifest() {
|
||
if (!fs.existsSync(manifestPath)) {
|
||
console.warn(
|
||
`[prepare-sandbox-runtime] 未找到 manifest: ${manifestPath},跳过(子模块未初始化或未接入)`,
|
||
);
|
||
return null;
|
||
}
|
||
const raw = fs.readFileSync(manifestPath, "utf-8");
|
||
return JSON.parse(raw);
|
||
}
|
||
|
||
function resolvePlatformArtifact(manifest, key) {
|
||
const table = manifest.platforms || manifest.artifacts || {};
|
||
return normalizeEntry(table[key]);
|
||
}
|
||
|
||
function main() {
|
||
const key = getPlatformKey();
|
||
const manifest = loadManifest();
|
||
if (!manifest) return;
|
||
|
||
const artifact = resolvePlatformArtifact(manifest, key);
|
||
if (!artifact) {
|
||
console.warn(
|
||
`[prepare-sandbox-runtime] manifest 未提供平台 ${key} 的产物定义,跳过`,
|
||
);
|
||
return;
|
||
}
|
||
|
||
const sourcePath = path.isAbsolute(artifact.source)
|
||
? artifact.source
|
||
: path.join(sandboxRuntimeSubmodule, artifact.source);
|
||
|
||
if (!fs.existsSync(sourcePath)) {
|
||
throw new Error(
|
||
`[prepare-sandbox-runtime] 产物不存在: ${sourcePath}(platform=${key})`,
|
||
);
|
||
}
|
||
|
||
if (artifact.sha256) {
|
||
const current = sha256(sourcePath);
|
||
if (current !== artifact.sha256) {
|
||
throw new Error(
|
||
`[prepare-sandbox-runtime] 校验失败: expected=${artifact.sha256}, actual=${current}, file=${sourcePath}`,
|
||
);
|
||
}
|
||
}
|
||
|
||
ensureDir(targetBin);
|
||
const targetName = artifact.targetName || path.basename(sourcePath);
|
||
const targetPath = path.join(targetBin, targetName);
|
||
fs.copyFileSync(sourcePath, targetPath);
|
||
|
||
if (process.platform !== "win32") {
|
||
try {
|
||
fs.chmodSync(targetPath, 0o755);
|
||
} catch (_) {}
|
||
}
|
||
|
||
const resolved = {
|
||
version: manifest.version || "unknown",
|
||
platform: key,
|
||
source: sourcePath,
|
||
target: targetPath,
|
||
sha256: artifact.sha256 || null,
|
||
preparedAt: new Date().toISOString(),
|
||
};
|
||
fs.writeFileSync(
|
||
path.join(targetRoot, "resolved-manifest.json"),
|
||
JSON.stringify(resolved, null, 2),
|
||
"utf-8",
|
||
);
|
||
fs.writeFileSync(path.join(targetBin, ".platform-key"), key, "utf-8");
|
||
|
||
console.log(`[prepare-sandbox-runtime] ${key} -> ${targetName}`);
|
||
}
|
||
|
||
try {
|
||
main();
|
||
} catch (error) {
|
||
console.error(error instanceof Error ? error.message : String(error));
|
||
process.exit(1);
|
||
}
|