根因:启动器的运行时解析第三顺位是开发检出 ~/Dev/ant/ant-copilot,同事机器没有该目录 → 插件装上、MCP 起不来;而私有 registry 匿名读返回 401,走 npm 安装等于要求每台机器都配 Gitea token。 改法:① 打包产物随插件分发(plugins/<产品>/runtime/,3.96MB 自包含单文件 + manifest 记录来源版本/提交/大小/sha256);② 启动器每次拉起比对 sha256,缺失或被改动即从插件包安装到 ~/.deta/runtime(首次启动零操作、升级自动同步);③ 新增 deta install-runtime(显式安装 + 补装可选依赖 @resvg/resvg-js + 装完立刻做一次真实 MCP 握手自证),status/doctor 显示运行时来源与预览图依赖状态;④ 契约校验加 E6:运行时包必须自洽(sha256/字节数/manifest.pluginVersion 与插件版本一致),拦住“升版本忘重跑 sync-runtime”。 实测:全新 HOME(模拟同事机器、无开发检出、无凭据)下供给探针 10/10 通过 —— 首次启动自动安装、启动行指向沙箱运行时、install-runtime 握手 39 个工具、重复安装幂等、运行时被改动自动修复、插件包缺运行时两处都给打包缺陷指引;已装副本 0.3.14 独立验证(含 npm 自动补装 @resvg 2 包)。studio 0.3.14 / writer 0.1.5。
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* 把领域服务运行时(ant-copilot 的 esbuild 打包产物)同步进插件包。
|
||||
*
|
||||
* 为什么随插件分发而不是 npm 安装:`@ringoarch/ant-copilot` 发在私有 Gitea registry 上,
|
||||
* 匿名 GET 包元数据返回 401 —— 走 npm 路线等于要求每个同事机器上都配一个 Gitea token。
|
||||
* 打包产物本身是自包含单文件(依赖全内联),把它放进插件包即可做到「装插件 = 拿到运行时」。
|
||||
*
|
||||
* 用法:
|
||||
* node scripts/sync-runtime.mjs # studio + writer
|
||||
* node scripts/sync-runtime.mjs studio # 只同步指定插件
|
||||
* ANT_COPILOT_DIR=~/Dev/ant/ant-copilot node scripts/sync-runtime.mjs
|
||||
*
|
||||
* 前置:源仓库已构建(`npm run build:mcp` → dist/deta-mcp.mjs)。
|
||||
* 产物:plugins/<插件>/runtime/dist/deta-mcp.mjs + plugins/<插件>/runtime/manifest.json
|
||||
* manifest 记录来源版本/提交/大小/sha256 —— 供启动器与 install-runtime 自校验(防拷错、防陈旧)。
|
||||
*/
|
||||
import { execFileSync } from 'node:child_process';
|
||||
import { createHash } from 'node:crypto';
|
||||
import { copyFileSync, existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
|
||||
import { dirname, join, resolve } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
||||
const SRC_REPO = resolve(process.env.ANT_COPILOT_DIR ?? join(process.env.HOME ?? '', 'Dev/ant/ant-copilot'));
|
||||
const SRC_ENTRY = join(SRC_REPO, 'dist/deta-mcp.mjs');
|
||||
const plugins = process.argv.slice(2).filter((a) => !a.startsWith('-'));
|
||||
const targets = plugins.length ? plugins : ['studio', 'writer'];
|
||||
|
||||
function die(msg) {
|
||||
process.stderr.write(`[sync-runtime] ${msg}\n`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!existsSync(SRC_ENTRY)) {
|
||||
die(`源打包产物不存在:${SRC_ENTRY}\n 请先在 ${SRC_REPO} 执行 npm run build:mcp`);
|
||||
}
|
||||
|
||||
const bytes = readFileSync(SRC_ENTRY);
|
||||
const sha256 = createHash('sha256').update(bytes).digest('hex');
|
||||
const version = JSON.parse(readFileSync(join(SRC_REPO, 'package.json'), 'utf8')).version;
|
||||
let gitSha = '';
|
||||
try {
|
||||
gitSha = execFileSync('git', ['rev-parse', '--short', 'HEAD'], { cwd: SRC_REPO, encoding: 'utf8' }).trim();
|
||||
} catch {
|
||||
gitSha = 'unknown'; // 允许在非 git 检出(如 CI 解包目录)中运行
|
||||
}
|
||||
let pluginVersion = {};
|
||||
const manifest = {
|
||||
source: '@ringoarch/ant-copilot',
|
||||
version,
|
||||
gitSha,
|
||||
builtAt: new Date().toISOString(),
|
||||
entry: 'dist/deta-mcp.mjs',
|
||||
sha256,
|
||||
bytes: bytes.length,
|
||||
note: '由 scripts/sync-runtime.mjs 生成;勿手工编辑。安装到 ~/.deta/runtime 由启动器/install-runtime 完成。',
|
||||
};
|
||||
|
||||
for (const name of targets) {
|
||||
const pluginDir = join(ROOT, 'plugins', name);
|
||||
const pj = join(pluginDir, '.codex-plugin', 'plugin.json');
|
||||
if (!existsSync(pj)) die(`插件不存在或清单缺失:${pj}`);
|
||||
const pv = JSON.parse(readFileSync(pj, 'utf8')).version ?? null;
|
||||
const outDir = join(pluginDir, 'runtime', 'dist');
|
||||
mkdirSync(outDir, { recursive: true });
|
||||
const outEntry = join(outDir, 'deta-mcp.mjs');
|
||||
copyFileSync(SRC_ENTRY, outEntry);
|
||||
const out = { ...manifest, plugin: name, pluginVersion: pv };
|
||||
writeFileSync(join(pluginDir, 'runtime', 'manifest.json'), `${JSON.stringify(out, null, 2)}\n`);
|
||||
const size = statSync(outEntry).size;
|
||||
if (size !== bytes.length) die(`写入后大小不一致(${size} != ${bytes.length}):${outEntry}`);
|
||||
process.stdout.write(
|
||||
`[sync-runtime] ${name}: ${(size / 1048576).toFixed(2)}MB sha256=${sha256.slice(0, 12)}… `
|
||||
+ `来自 ${manifest.source}@${version} (${gitSha})\n`,
|
||||
);
|
||||
}
|
||||
process.stdout.write(`[sync-runtime] 完成。提交 runtime/ 后同事装插件即自带运行时。\n`);
|
||||
Reference in New Issue
Block a user