import { parseArgs } from "node:util" import path from "node:path" import { mkdir, copyFile } from "node:fs/promises" const args = parseArgs({ options: { target: { type: "string" }, check: { type: "boolean" } } }).values if (!args.target) throw new Error("用法:bun script/install-agentpaas.ts --target /absolute/project [--check]") const source = path.resolve(import.meta.dir, "../.opencode") const target = path.resolve(args.target, ".opencode") if (target === source) throw new Error("目标不能是桥接源码目录") const manifest = (await Bun.file(path.join(source, "agentpaas-manifest.json")).json()) as { files: string[] } const changed: string[] = [] for (const name of manifest.files) { if (path.isAbsolute(name) || name.split(/[\\/]/).includes("..")) throw new Error("无效安装清单") const original = Bun.file(path.join(source, name)) const existing = Bun.file(path.join(target, name)) if ( (await existing.exists()) && Buffer.from(await existing.arrayBuffer()).equals(Buffer.from(await original.arrayBuffer())) ) continue changed.push(name) } if (args.check) { console.log(JSON.stringify({ current: !changed.length, changed }, null, 2)) process.exit(changed.length ? 1 : 0) } const backup = path.join(target, ".agentpaas-backups", `${Date.now()}-${crypto.randomUUID()}`) for (const name of changed) { const destination = path.join(target, name) if (await Bun.file(destination).exists()) { await mkdir(path.dirname(path.join(backup, name)), { recursive: true }) await copyFile(destination, path.join(backup, name)) } await mkdir(path.dirname(destination), { recursive: true }) await copyFile(path.join(source, name), destination) } console.log( JSON.stringify( { installed: target, updated: changed, backup_if_needed: backup, next: "设置 AGENTPAAS_URL 和 AGENTPAAS_API_KEY,使用当前 OpenCode fork 启动 --agent paas,或输入 /paas。不会修改你的模型或凭证配置。", }, null, 2, ), )