@my-life-buddies/cli 0.24.1-dev.0 → 0.24.1-dev.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  这份说明按一次开发过程展开:登记搭子,准备工程,在本地预览,然后上传程序包。所有搭子统一使用 `@my-life-buddies/buddy-runtime`,业务能力通过 Prompt、`src/buddy-options.mjs` 和 Tool 实现。
6
6
 
7
- 新建工程统一查询公共 npm dev 最新 Runtime,并写入准确版本与锁文件,不提供版本选择;查询或锁文件生成失败时停止,不回退旧版本。版本策略与联调范围见 [Runtime 集成说明](../../docs/runtime-integration.md)。
7
+ 空白工程模板不预置 Runtime 依赖或版本。新建工程统一查询公共 npm dev 最新 Runtime,并写入准确版本与锁文件,不提供版本选择;查询或锁文件生成失败时停止,不回退旧版本。版本策略与联调范围见 [Runtime 集成说明](../../docs/runtime-integration.md)。
8
8
 
9
9
  ## 准备 CLI 和平台地址
10
10
 
@@ -90,7 +90,7 @@ npm run release -- --publish # 显式发布当前 dev 分支到 npm dev
90
90
 
91
91
  `dev` 构建 `@my-life-buddies/cli@dev`,只包含 `buddy-cli-sit` 命令。版本必须是 `x.y.z-dev.N`;发布校验拒绝 latest 标签。main 用同一个包名发布 `latest` 正式版本,提供 `buddy-cli`;两个版本必须分目录安装才能共存,同一目录中安装会互相替换。Core 和 Preview 保留 monorepo 开发边界并标记为 `private`,构建时合入 CLI 的内部模块;Preview 页面和工程模板资源进入 CLI 包;Creator 与 Avatar Skill 使用时独立加载。安装不会请求 `@buddy/cli-core` 或 `@buddy/preview`。第三方运行依赖按正常 npm dependencies 安装,构建工具 esbuild 不进入安装依赖。根工作区标记为 `private`。
92
92
 
93
- 版本维护:每批修改 CLI 发布内容时递增一次版本,默认 patch;根包和内部工作区版本、依赖引用、锁文件一起更新。Agent 工程自己的项目版本独立。升级 Runtime 时同步模板依赖与模板锁文件,并运行独立安装验收。
93
+ 版本维护:每批修改 CLI 发布内容时递增一次版本,默认 patch;根包和内部工作区版本、依赖引用、锁文件一起更新。Agent 工程自己的项目版本独立。Runtime 版本由创建时动态查询并锁定;发布前验证真实 Runtime 的动态解析和独立安装,不向空白模板写入基准版本。
94
94
 
95
95
  SIT CLI 固定连接 SIT `https://buddies.sit.dots.chat`,无需配置地址:
96
96
 
package/dist/bin/core.js CHANGED
@@ -179,8 +179,8 @@ async function validateRuntimeDatasets(projectRoot, requirements = []) {
179
179
  }
180
180
 
181
181
  // packages/cli-core/src/init/scaffold.ts
182
- import { lstat as lstat6, mkdir as mkdir6, open as open3, readFile as readFile8, rename as rename6, rmdir as rmdir2, unlink as unlink4 } from "node:fs/promises";
183
- import { resolve as resolve4 } from "node:path";
182
+ import { lstat as lstat6, mkdir as mkdir6, open as open3, readFile as readFile10, rename as rename6, rmdir as rmdir2, unlink as unlink4 } from "node:fs/promises";
183
+ import { resolve as resolve5 } from "node:path";
184
184
  import { randomUUID as randomUUID4 } from "node:crypto";
185
185
 
186
186
  // packages/cli-core/src/config/index.ts
@@ -1248,52 +1248,175 @@ var MODEL_IDS = Object.freeze([
1248
1248
  ]);
1249
1249
  var DEFAULT_MODEL_ID = "kimi-k2.6";
1250
1250
 
1251
+ // packages/cli-core/src/config/runtime-policy.ts
1252
+ import { readFile as readFile8, realpath as realpath3 } from "node:fs/promises";
1253
+ import { createRequire as createRequire2 } from "node:module";
1254
+ import { resolve as resolve4 } from "node:path";
1255
+
1256
+ // packages/cli-core/src/config/runtime-update.ts
1257
+ import { readFile as readFile7 } from "node:fs/promises";
1258
+ import { join as join7 } from "node:path";
1259
+ async function projectRuntimeVersion(root) {
1260
+ try {
1261
+ return runtimeDependencyVersion(JSON.parse(await readFile7(join7(root, "package.json"), "utf8")));
1262
+ } catch (cause) {
1263
+ if (cause.code === "ENOENT") return void 0;
1264
+ throw cause;
1265
+ }
1266
+ }
1267
+ function compareVersions(left, right) {
1268
+ const parts = (value) => {
1269
+ const [core, ...suffix] = value.split("-");
1270
+ return { core: core.split(".").map(BigInt), pre: suffix.length ? suffix.join("-").split(".") : [] };
1271
+ };
1272
+ const a = parts(left), b = parts(right);
1273
+ for (let i = 0; i < 3; i++) if (a.core[i] !== b.core[i]) return a.core[i] < b.core[i] ? -1 : 1;
1274
+ if (!a.pre.length || !b.pre.length) return a.pre.length === b.pre.length ? 0 : a.pre.length ? -1 : 1;
1275
+ for (let i = 0; i < Math.max(a.pre.length, b.pre.length); i++) {
1276
+ const x = a.pre[i], y = b.pre[i];
1277
+ if (x === y) continue;
1278
+ if (x === void 0 || y === void 0) return x === void 0 ? -1 : 1;
1279
+ const nx = /^\d+$/.test(x), ny = /^\d+$/.test(y);
1280
+ if (nx && ny) return BigInt(x) < BigInt(y) ? -1 : 1;
1281
+ if (nx !== ny) return nx ? -1 : 1;
1282
+ return x < y ? -1 : 1;
1283
+ }
1284
+ return 0;
1285
+ }
1286
+ async function runtimeVersionStatus(project, latest) {
1287
+ const current = project ? await projectRuntimeVersion(project) : void 0;
1288
+ let versionStatus;
1289
+ if (!project) versionStatus = "no_project";
1290
+ else if (!current) versionStatus = "unconfigured";
1291
+ else if (current === latest) versionStatus = "current";
1292
+ else versionStatus = compareVersions(current, latest) < 0 ? "update_available" : "project_ahead";
1293
+ return {
1294
+ projectRuntimeVersion: current ?? null,
1295
+ latestRuntimeVersion: latest,
1296
+ versionStatus,
1297
+ adaptationRequired: versionStatus !== "no_project" && versionStatus !== "current"
1298
+ };
1299
+ }
1300
+ function reportRuntimeVersion(status, report) {
1301
+ if (status.versionStatus === "no_project") return;
1302
+ report(`Runtime \u7248\u672C\uFF1A\u5DE5\u7A0B ${status.projectRuntimeVersion ?? "\u672A\u9501\u5B9A\u51C6\u786E\u7248\u672C"}\uFF0Cnpm dev \u6700\u65B0 ${status.latestRuntimeVersion}\u3002`);
1303
+ if (status.adaptationRequired) {
1304
+ report("\u8BF7\u7531\u4F60\u6216\u5F00\u53D1 Agent \u66F4\u65B0\u4F9D\u8D56\u5E76\u9002\u914D\uFF1A\u68C0\u67E5\u65B0\u7248 Runtime \u7684\u542F\u52A8\u53C2\u6570\u3001\u6A21\u578B\u3001datasets\u3001\u5DE5\u5177\u53CA Hook\uFF0C\u5B8C\u6210\u9002\u914D\u540E\u9A8C\u8BC1 DEV\u3002CLI \u672A\u4FEE\u6539\u5DE5\u7A0B\u4F9D\u8D56\u6216\u914D\u7F6E\uFF1BDEV \u542F\u52A8\u3001\u81EA\u52A8\u91CD\u8F7D\u548C push \u5FC5\u987B\u901A\u8FC7\u6700\u65B0 Runtime \u68C0\u67E5\u3002");
1305
+ report(`\u5728\u5DE5\u7A0B\u6839\u76EE\u5F55\u6267\u884C\uFF1Anpm install --save-exact ${BUDDY_RUNTIME_PACKAGE}@${status.latestRuntimeVersion} --registry=${RUNTIME_REGISTRY} --@my-life-buddies:registry=${RUNTIME_REGISTRY}`);
1306
+ }
1307
+ }
1308
+ async function checkRuntimeUpdate(root, report, options = {}) {
1309
+ options.signal?.throwIfAborted();
1310
+ try {
1311
+ const latest = await latestRuntimeVersion(options);
1312
+ reportRuntimeVersion(await runtimeVersionStatus(root, latest), report);
1313
+ options.signal?.throwIfAborted();
1314
+ return;
1315
+ } catch (cause) {
1316
+ options.signal?.throwIfAborted();
1317
+ report(`\u65E0\u6CD5\u68C0\u67E5 Runtime \u66F4\u65B0\uFF1A${cause instanceof Error ? cause.message : String(cause)}\u3002\u672C\u6B21\u672A\u786E\u8BA4 npm dev \u6700\u65B0\u7248\u672C\uFF1B\u53EF\u7EE7\u7EED\u67E5\u770B\u6216\u4FEE\u6539\u5DE5\u7A0B\uFF0CDEV \u542F\u52A8\u548C push \u4F1A\u53E6\u884C\u4E25\u683C\u68C0\u67E5\u3002`);
1318
+ }
1319
+ }
1320
+
1321
+ // packages/cli-core/src/config/runtime-policy.ts
1322
+ var RuntimeRequirementError = class extends Error {
1323
+ constructor(code2, message, options) {
1324
+ super(message, options);
1325
+ this.code = code2;
1326
+ this.name = "RuntimeRequirementError";
1327
+ }
1328
+ code;
1329
+ };
1330
+ function assertRequiredRuntime(actual, expected) {
1331
+ if (actual === expected) return;
1332
+ throw new RuntimeRequirementError(
1333
+ "RUNTIME_VERSION_MISMATCH",
1334
+ `\u5DF2\u963B\u6B62\u8FD0\u884C\u6216\u4E0A\u4F20\uFF1A\u5DE5\u7A0B Runtime ${actual ?? "\u672A\u9501\u5B9A\u51C6\u786E\u7248\u672C"}\uFF0Cnpm dev \u6700\u65B0\u7248\u672C ${expected}\u3002\u5FC5\u987B\u4F7F\u7528\u5B8C\u5168\u4E00\u81F4\u7684\u7248\u672C\u3002
1335
+ \u8BF7\u7531\u4F60\u6216\u5F00\u53D1 Agent \u66F4\u65B0\u4F9D\u8D56\u548C\u9501\u6587\u4EF6\uFF0C\u9002\u914D\u542F\u52A8\u53C2\u6570\u3001\u6A21\u578B\u3001datasets\u3001\u5DE5\u5177\u53CA Hook \u540E\u91CD\u8BD5\u3002
1336
+ npm install --save-exact ${BUDDY_RUNTIME_PACKAGE}@${expected} --registry=${RUNTIME_REGISTRY} --@my-life-buddies:registry=${RUNTIME_REGISTRY}`
1337
+ );
1338
+ }
1339
+ function assertNpmRuntimeLock(contents, expected) {
1340
+ const lock = JSON.parse(contents);
1341
+ const installed2 = lock.lockfileVersion === 1 ? lock.dependencies?.[BUDDY_RUNTIME_PACKAGE] : lock.packages?.[`node_modules/${BUDDY_RUNTIME_PACKAGE}`];
1342
+ if (installed2?.version !== expected || lock.lockfileVersion !== 1 && runtimeDependencyVersion(lock.packages?.[""]) !== expected) {
1343
+ throw new RuntimeRequirementError("RUNTIME_DEPENDENCY_INVALID", `package-lock.json \u7684 Runtime \u4E0E\u8981\u6C42\u7684 ${expected} \u4E0D\u4E00\u81F4\u3002\u8BF7\u66F4\u65B0\u9501\u6587\u4EF6\u5E76\u91CD\u65B0\u5B89\u88C5\u4F9D\u8D56\u540E\u91CD\u8BD5\u3002`);
1344
+ }
1345
+ }
1346
+ async function requireProjectRuntime(root, options = {}) {
1347
+ const declared = await projectRuntimeVersion(root);
1348
+ if (!declared) throw new RuntimeRequirementError("RUNTIME_DEPENDENCY_INVALID", "\u5DE5\u7A0B\u5FC5\u987B\u5728 package.json \u58F0\u660E npm dev \u6700\u65B0 Runtime \u7684\u51C6\u786E\u7248\u672C\uFF0C\u5E76\u5B89\u88C5\u4F9D\u8D56\u548C\u9501\u6587\u4EF6\uFF1B\u4E0D\u80FD\u4F7F\u7528 dev\u3001latest \u6216\u7248\u672C\u8303\u56F4\u4F5C\u4E3A\u5DE5\u7A0B\u4F9D\u8D56\u3002");
1349
+ let expected;
1350
+ try {
1351
+ expected = await latestRuntimeVersion(options);
1352
+ } catch (cause) {
1353
+ options.signal?.throwIfAborted();
1354
+ throw new RuntimeRequirementError("RUNTIME_CHECK_FAILED", `\u65E0\u6CD5\u786E\u8BA4 npm dev \u6700\u65B0 Runtime\uFF0C\u5DF2\u963B\u6B62\u8FD0\u884C\u6216\u4E0A\u4F20\uFF1A${cause instanceof Error ? cause.message : String(cause)}\u3002\u8BF7\u6062\u590D\u8FDE\u63A5\u540E\u91CD\u8BD5\u3002`, { cause });
1355
+ }
1356
+ try {
1357
+ assertRequiredRuntime(await projectRuntimeVersion(root), expected);
1358
+ const installedPath = await realpath3(resolve4(root, "node_modules", BUDDY_RUNTIME_PACKAGE, "package.json"));
1359
+ const fromProject = createRequire2(resolve4(root, "package.json")).resolve(`${BUDDY_RUNTIME_PACKAGE}/package.json`);
1360
+ if (await realpath3(fromProject) !== installedPath) throw new Error("Runtime \u5FC5\u987B\u5B89\u88C5\u5728\u5F53\u524D\u5DE5\u7A0B\u4E2D");
1361
+ const installed2 = JSON.parse(await readFile8(installedPath, "utf8"));
1362
+ if (installed2.version !== expected) throw new Error(`Runtime \u5B9E\u9645\u5B89\u88C5 ${installed2.version}\uFF0C\u8981\u6C42 ${expected}`);
1363
+ let lock;
1364
+ try {
1365
+ lock = await readFile8(resolve4(root, "package-lock.json"), "utf8");
1366
+ } catch (cause) {
1367
+ if (cause.code !== "ENOENT") throw cause;
1368
+ }
1369
+ if (lock !== void 0) assertNpmRuntimeLock(lock, expected);
1370
+ options.signal?.throwIfAborted();
1371
+ return expected;
1372
+ } catch (cause) {
1373
+ options.signal?.throwIfAborted();
1374
+ if (cause instanceof RuntimeRequirementError) throw cause;
1375
+ throw new RuntimeRequirementError("RUNTIME_DEPENDENCY_INVALID", `Runtime \u4F9D\u8D56\u6821\u9A8C\u5931\u8D25\uFF1A${cause instanceof Error ? cause.message : String(cause)}\u3002\u8BF7\u66F4\u65B0\u4F9D\u8D56\u53CA\u9501\u6587\u4EF6\u5E76\u5B89\u88C5\uFF1Bnpm \u5DE5\u7A0B\u53EF\u8FD0\u884C npm ci\u3002`, { cause });
1376
+ }
1377
+ }
1378
+
1251
1379
  // packages/cli-core/src/init/runtime-template.ts
1252
1380
  import { execFile as execFile3 } from "node:child_process";
1253
- import { mkdtemp as mkdtemp3, readFile as readFile7, rm as rm3, writeFile as writeFile5 } from "node:fs/promises";
1381
+ import { mkdtemp as mkdtemp3, readFile as readFile9, rm as rm3, writeFile as writeFile5 } from "node:fs/promises";
1254
1382
  import { tmpdir } from "node:os";
1255
- import { join as join7 } from "node:path";
1383
+ import { join as join8 } from "node:path";
1256
1384
  import { promisify as promisify3 } from "node:util";
1257
1385
  var execute3 = promisify3(execFile3);
1258
1386
  async function latestRuntimeTemplate(template, options) {
1259
- const bundledVersion = runtimeDependencyVersion(JSON.parse(template.packageJson));
1260
- if (!bundledVersion) throw new Error("CLI \u5DE5\u7A0B\u6A21\u677F\u7F3A\u5C11 Runtime \u7684\u51C6\u786E\u7248\u672C");
1261
1387
  let temporaryRoot;
1262
1388
  try {
1263
1389
  options.signal?.throwIfAborted();
1264
1390
  options.report("\u6B63\u5728\u67E5\u8BE2\u516C\u5171 npm dev \u7684\u6700\u65B0 Runtime\u2026");
1265
1391
  const version = await latestRuntimeVersion(options);
1266
- let result = template;
1267
- if (version !== bundledVersion) {
1268
- temporaryRoot = await mkdtemp3(join7(tmpdir(), "buddy-runtime-template-"));
1269
- await writeFile5(join7(temporaryRoot, "package.json"), template.packageJson);
1270
- await writeFile5(join7(temporaryRoot, "package-lock.json"), template.packageLock);
1271
- const userConfig = join7(temporaryRoot, ".npmrc");
1272
- await writeFile5(userConfig, `registry=${RUNTIME_REGISTRY}
1392
+ temporaryRoot = await mkdtemp3(join8(tmpdir(), "buddy-runtime-template-"));
1393
+ await writeFile5(join8(temporaryRoot, "package.json"), template.packageJson);
1394
+ await writeFile5(join8(temporaryRoot, "package-lock.json"), template.packageLock);
1395
+ const userConfig = join8(temporaryRoot, ".npmrc");
1396
+ await writeFile5(userConfig, `registry=${RUNTIME_REGISTRY}
1273
1397
  `);
1274
- options.report(`\u6B63\u5728\u4E3A Runtime ${version} \u751F\u6210\u4F9D\u8D56\u9501\u6587\u4EF6\u2026`);
1275
- const runNpm = options.runNpm ?? ((args, settings) => execute3("npm", args, { ...settings, encoding: "utf8", maxBuffer: 4 * 1024 * 1024 }));
1276
- await runNpm([
1277
- "install",
1278
- "--package-lock-only",
1279
- "--save-exact",
1280
- `${BUDDY_RUNTIME_PACKAGE}@${version}`,
1281
- "--ignore-scripts",
1282
- "--no-audit",
1283
- "--no-fund",
1284
- "--engine-strict",
1285
- `--registry=${RUNTIME_REGISTRY}`,
1286
- `--@my-life-buddies:registry=${RUNTIME_REGISTRY}`,
1287
- `--userconfig=${userConfig}`,
1288
- "--prefer-online",
1289
- "--fetch-retries=0",
1290
- "--fetch-timeout=20000"
1291
- ], { cwd: temporaryRoot, signal: options.signal, timeout: 6e4 });
1292
- result = {
1293
- packageJson: await readFile7(join7(temporaryRoot, "package.json"), "utf8"),
1294
- packageLock: await readFile7(join7(temporaryRoot, "package-lock.json"), "utf8")
1295
- };
1296
- }
1398
+ options.report(`\u6B63\u5728\u4E3A Runtime ${version} \u751F\u6210\u4F9D\u8D56\u9501\u6587\u4EF6\u2026`);
1399
+ const runNpm = options.runNpm ?? ((args, settings) => execute3("npm", args, { ...settings, encoding: "utf8", maxBuffer: 4 * 1024 * 1024 }));
1400
+ await runNpm([
1401
+ "install",
1402
+ "--package-lock-only",
1403
+ "--save-exact",
1404
+ `${BUDDY_RUNTIME_PACKAGE}@${version}`,
1405
+ "--ignore-scripts",
1406
+ "--no-audit",
1407
+ "--no-fund",
1408
+ "--engine-strict",
1409
+ `--registry=${RUNTIME_REGISTRY}`,
1410
+ `--@my-life-buddies:registry=${RUNTIME_REGISTRY}`,
1411
+ `--userconfig=${userConfig}`,
1412
+ "--prefer-online",
1413
+ "--fetch-retries=0",
1414
+ "--fetch-timeout=20000"
1415
+ ], { cwd: temporaryRoot, signal: options.signal, timeout: 6e4 });
1416
+ const result = {
1417
+ packageJson: await readFile9(join8(temporaryRoot, "package.json"), "utf8"),
1418
+ packageLock: await readFile9(join8(temporaryRoot, "package-lock.json"), "utf8")
1419
+ };
1297
1420
  const pkg = JSON.parse(result.packageJson);
1298
1421
  const lock = JSON.parse(result.packageLock);
1299
1422
  const locked = lock.packages?.[`node_modules/${BUDDY_RUNTIME_PACKAGE}`];
@@ -1306,7 +1429,7 @@ async function latestRuntimeTemplate(template, options) {
1306
1429
  } catch (cause) {
1307
1430
  if (options.signal?.aborted) throw new Error("Runtime \u7248\u672C\u67E5\u8BE2\u5DF2\u53D6\u6D88");
1308
1431
  const reason = cause instanceof Error && !cause.message.includes("Command failed") ? cause.message : "npm \u672A\u5B8C\u6210\u9501\u6587\u4EF6\u751F\u6210";
1309
- throw new Error(`\u672A\u80FD\u9501\u5B9A\u6700\u65B0 dev Runtime\uFF1A${reason}\u3002\u5DF2\u505C\u6B62\u751F\u6210\u5DE5\u7A0B\u4F9D\u8D56\uFF0C\u8BF7\u4FEE\u590D\u540E\u91CD\u8BD5\uFF1B\u4E0D\u4F1A\u56DE\u9000\u5230\u5185\u7F6E\u65E7\u7248\u672C\u3002`, { cause });
1432
+ throw new Error(`\u672A\u80FD\u9501\u5B9A\u6700\u65B0 dev Runtime\uFF1A${reason}\u3002\u5DF2\u505C\u6B62\u751F\u6210\u5DE5\u7A0B\u4F9D\u8D56\uFF0C\u8BF7\u4FEE\u590D\u540E\u91CD\u8BD5\uFF1B\u4E0D\u4F1A\u4F7F\u7528\u9884\u7F6E\u6216\u7F13\u5B58\u7684\u65E7\u7248\u672C\u3002`, { cause });
1310
1433
  } finally {
1311
1434
  if (temporaryRoot) await rm3(temporaryRoot, { recursive: true, force: true });
1312
1435
  }
@@ -1398,15 +1521,15 @@ try {
1398
1521
  `;
1399
1522
  }
1400
1523
  async function scaffoldPlatformAgent(projectRoot, name, options = {}) {
1401
- const path = resolve4(projectRoot, BUDDY_PLATFORM_AGENT_ENTRY);
1402
- const packagePath = resolve4(projectRoot, BUDDY_PLATFORM_PACKAGE_JSON);
1524
+ const path = resolve5(projectRoot, BUDDY_PLATFORM_AGENT_ENTRY);
1525
+ const packagePath = resolve5(projectRoot, BUDDY_PLATFORM_PACKAGE_JSON);
1403
1526
  if (!(await lstat6(packagePath)).isFile()) throw new Error("package.json \u5FC5\u987B\u662F\u666E\u901A\u6587\u4EF6");
1404
- const originalPackage = await readFile8(packagePath, "utf8");
1527
+ const originalPackage = await readFile10(packagePath, "utf8");
1405
1528
  const projectPackage = parseBuddyProjectManifest(originalPackage);
1406
1529
  const isIdentityDraft = Object.keys(projectPackage).every((key) => key === "buddyId");
1407
1530
  const hasAlternateLockfile = (await Promise.all(["pnpm-lock.yaml", "yarn.lock"].map(async (name2) => {
1408
1531
  try {
1409
- if (!(await lstat6(resolve4(projectRoot, name2))).isFile()) {
1532
+ if (!(await lstat6(resolve5(projectRoot, name2))).isFile()) {
1410
1533
  throw new TypeError(`\u4F9D\u8D56\u9501\u6587\u4EF6\u5FC5\u987B\u662F\u666E\u901A\u6587\u4EF6\uFF1A${name2}`);
1411
1534
  }
1412
1535
  return true;
@@ -1417,19 +1540,19 @@ async function scaffoldPlatformAgent(projectRoot, name, options = {}) {
1417
1540
  }))).some(Boolean);
1418
1541
  const files = [
1419
1542
  { path, content: platformAgentTemplate(name) },
1420
- { path: resolve4(projectRoot, BUDDY_PLATFORM_FACTORY_ENTRY), content: platformFactoryTemplate(options.model) },
1421
- { path: resolve4(projectRoot, BUDDY_PLATFORM_PACKAGE_JSON), content: await readFile8(new URL("../../resources/agent-template/package.json", import.meta.url), "utf8") },
1422
- ...hasAlternateLockfile ? [] : [{ path: resolve4(projectRoot, BUDDY_PLATFORM_PACKAGE_LOCK), content: await readFile8(new URL("../../resources/agent-template/package-lock.json", import.meta.url), "utf8") }],
1423
- { path: resolve4(projectRoot, BUDDY_PLATFORM_START_ENTRY), content: platformStartTemplate() },
1424
- { path: resolve4(projectRoot, "data-access.json"), content: '{\n "requirements": []\n}\n' },
1425
- { path: resolve4(projectRoot, ".gitignore"), content: "node_modules/\n/.env\n" },
1426
- { path: resolve4(projectRoot, ".env.example"), content: "# \u642D\u5B50\u8EAB\u4EFD\u7531 package.json \u9876\u5C42\u7684 buddyId \u63D0\u4F9B\u3002\n# \u9996\u6B21\u8FD0\u884C buddy-cli-sit dev \u6216\u5728\u540E\u53F0\u542F\u52A8 DEV \u65F6\uFF0CCLI \u4F1A\u51C6\u5907 .env\u3002\nBUDDY_TOKEN=\n# CLI \u81EA\u52A8\u5199\u5165 SIT \u7684 MLB_GATEWAY_URL\uFF0C\u4F9B Runtime \u4F7F\u7528\uFF1B\u65E0\u9700\u624B\u52A8\u8BBE\u7F6E\u3002\n# SIT CLI \u4E0D\u652F\u6301\u901A\u8FC7\u73AF\u5883\u53D8\u91CF\u6216 .env \u5207\u6362\u5E73\u53F0\u3002\n" }
1543
+ { path: resolve5(projectRoot, BUDDY_PLATFORM_FACTORY_ENTRY), content: platformFactoryTemplate(options.model) },
1544
+ { path: resolve5(projectRoot, BUDDY_PLATFORM_PACKAGE_JSON), content: await readFile10(new URL("../../resources/agent-template/package.json", import.meta.url), "utf8") },
1545
+ ...hasAlternateLockfile ? [] : [{ path: resolve5(projectRoot, BUDDY_PLATFORM_PACKAGE_LOCK), content: await readFile10(new URL("../../resources/agent-template/package-lock.json", import.meta.url), "utf8") }],
1546
+ { path: resolve5(projectRoot, BUDDY_PLATFORM_START_ENTRY), content: platformStartTemplate() },
1547
+ { path: resolve5(projectRoot, "data-access.json"), content: '{\n "requirements": []\n}\n' },
1548
+ { path: resolve5(projectRoot, ".gitignore"), content: "node_modules/\n/.env\n" },
1549
+ { path: resolve5(projectRoot, ".env.example"), content: "# \u642D\u5B50\u8EAB\u4EFD\u7531 package.json \u9876\u5C42\u7684 buddyId \u63D0\u4F9B\u3002\n# \u9996\u6B21\u8FD0\u884C buddy-cli-sit dev \u6216\u5728\u540E\u53F0\u542F\u52A8 DEV \u65F6\uFF0CCLI \u4F1A\u51C6\u5907 .env\u3002\nBUDDY_TOKEN=\n# CLI \u81EA\u52A8\u5199\u5165 SIT \u7684 MLB_GATEWAY_URL\uFF0C\u4F9B Runtime \u4F7F\u7528\uFF1B\u65E0\u9700\u624B\u52A8\u8BBE\u7F6E\u3002\n# SIT CLI \u4E0D\u652F\u6301\u901A\u8FC7\u73AF\u5883\u53D8\u91CF\u6216 .env \u5207\u6362\u5E73\u53F0\u3002\n" }
1427
1550
  ];
1428
1551
  const handles = [];
1429
1552
  const createdDirectories = [];
1430
1553
  try {
1431
1554
  for (const directory of PLATFORM_DIRECTORIES) {
1432
- const directoryPath = resolve4(projectRoot, directory);
1555
+ const directoryPath = resolve5(projectRoot, directory);
1433
1556
  try {
1434
1557
  await mkdir6(directoryPath, { mode: 448 });
1435
1558
  createdDirectories.push(directoryPath);
@@ -1450,20 +1573,28 @@ async function scaffoldPlatformAgent(projectRoot, name, options = {}) {
1450
1573
  }
1451
1574
  }
1452
1575
  }
1453
- const packageFile = files.find((file) => file.path === resolve4(projectRoot, BUDDY_PLATFORM_PACKAGE_JSON));
1454
- const lockFile = files.find((file) => file.path === resolve4(projectRoot, BUDDY_PLATFORM_PACKAGE_LOCK));
1576
+ const packageFile = files.find((file) => file.path === resolve5(projectRoot, BUDDY_PLATFORM_PACKAGE_JSON));
1577
+ const lockFile = files.find((file) => file.path === resolve5(projectRoot, BUDDY_PLATFORM_PACKAGE_LOCK));
1455
1578
  packageFile.content = JSON.stringify({ ...JSON.parse(packageFile.content), buddyId: projectPackage.buddyId }, null, 2) + "\n";
1456
- if (options.resolveDependencies && isIdentityDraft && lockFile && handles.some((file) => file.path === lockFile.path)) {
1457
- const template = await options.resolveDependencies({ packageJson: packageFile.content, packageLock: lockFile.content });
1579
+ if (isIdentityDraft) {
1580
+ const resolveDependencies = options.resolveDependencies ?? ((template2) => latestRuntimeTemplate(template2, { report() {
1581
+ } }));
1582
+ const template = await resolveDependencies({
1583
+ packageJson: packageFile.content,
1584
+ packageLock: lockFile?.content ?? await readFile10(new URL("../../resources/agent-template/package-lock.json", import.meta.url), "utf8")
1585
+ });
1458
1586
  if (parseBuddyProjectManifest(template.packageJson).buddyId !== projectPackage.buddyId) {
1459
1587
  throw new Error("\u4F9D\u8D56\u89E3\u6790\u6539\u53D8\u4E86 package.json.buddyId\uFF0C\u5DF2\u505C\u6B62\u8865\u9F50\u5DE5\u7A0B");
1460
1588
  }
1589
+ const version = runtimeDependencyVersion(JSON.parse(template.packageJson));
1590
+ if (!version) throw new Error("\u4F9D\u8D56\u89E3\u6790\u672A\u8FD4\u56DE Runtime \u7684\u51C6\u786E\u7248\u672C\uFF0C\u5DF2\u505C\u6B62\u8865\u9F50\u5DE5\u7A0B");
1591
+ assertNpmRuntimeLock(template.packageLock, version);
1461
1592
  packageFile.content = template.packageJson;
1462
- lockFile.content = template.packageLock;
1593
+ if (lockFile) lockFile.content = template.packageLock;
1463
1594
  }
1464
1595
  if (lockFile && (isIdentityDraft || handles.some((file) => file.path === lockFile.path))) {
1465
- const packageContents = isIdentityDraft ? packageFile.content : await readFile8(packageFile.path, "utf8");
1466
- const lockContents = handles.some((file) => file.path === lockFile.path) ? lockFile.content : await readFile8(lockFile.path, "utf8");
1596
+ const packageContents = isIdentityDraft ? packageFile.content : await readFile10(packageFile.path, "utf8");
1597
+ const lockContents = handles.some((file) => file.path === lockFile.path) ? lockFile.content : await readFile10(lockFile.path, "utf8");
1467
1598
  const declared = JSON.parse(packageContents).dependencies ?? {};
1468
1599
  const locked = JSON.parse(lockContents).packages?.[""]?.dependencies ?? {};
1469
1600
  if (JSON.stringify(Object.entries(declared).sort()) !== JSON.stringify(Object.entries(locked).sort())) {
@@ -1482,7 +1613,7 @@ async function scaffoldPlatformAgent(projectRoot, name, options = {}) {
1482
1613
  await handle.writeFile(packageFile.content, "utf8");
1483
1614
  await handle.sync();
1484
1615
  await handle.close();
1485
- if (!(await lstat6(packagePath)).isFile() || await readFile8(packagePath, "utf8") !== originalPackage) {
1616
+ if (!(await lstat6(packagePath)).isFile() || await readFile10(packagePath, "utf8") !== originalPackage) {
1486
1617
  throw new Error("\u8865\u9F50\u5DE5\u7A0B\u65F6 package.json \u5DF2\u6539\u53D8\uFF0C\u8BF7\u91CD\u8BD5");
1487
1618
  }
1488
1619
  await rename6(temporary, packagePath);
@@ -1509,136 +1640,6 @@ async function scaffoldPlatformAgent(projectRoot, name, options = {}) {
1509
1640
  // packages/cli-core/src/init/runtime-version.ts
1510
1641
  import { readFile as readFile11 } from "node:fs/promises";
1511
1642
  import { join as join9 } from "node:path";
1512
-
1513
- // packages/cli-core/src/config/runtime-policy.ts
1514
- import { readFile as readFile10, realpath as realpath3 } from "node:fs/promises";
1515
- import { createRequire as createRequire2 } from "node:module";
1516
- import { resolve as resolve5 } from "node:path";
1517
-
1518
- // packages/cli-core/src/config/runtime-update.ts
1519
- import { readFile as readFile9 } from "node:fs/promises";
1520
- import { join as join8 } from "node:path";
1521
- async function projectRuntimeVersion(root) {
1522
- try {
1523
- return runtimeDependencyVersion(JSON.parse(await readFile9(join8(root, "package.json"), "utf8")));
1524
- } catch (cause) {
1525
- if (cause.code === "ENOENT") return void 0;
1526
- throw cause;
1527
- }
1528
- }
1529
- function compareVersions(left, right) {
1530
- const parts = (value) => {
1531
- const [core, ...suffix] = value.split("-");
1532
- return { core: core.split(".").map(BigInt), pre: suffix.length ? suffix.join("-").split(".") : [] };
1533
- };
1534
- const a = parts(left), b = parts(right);
1535
- for (let i = 0; i < 3; i++) if (a.core[i] !== b.core[i]) return a.core[i] < b.core[i] ? -1 : 1;
1536
- if (!a.pre.length || !b.pre.length) return a.pre.length === b.pre.length ? 0 : a.pre.length ? -1 : 1;
1537
- for (let i = 0; i < Math.max(a.pre.length, b.pre.length); i++) {
1538
- const x = a.pre[i], y = b.pre[i];
1539
- if (x === y) continue;
1540
- if (x === void 0 || y === void 0) return x === void 0 ? -1 : 1;
1541
- const nx = /^\d+$/.test(x), ny = /^\d+$/.test(y);
1542
- if (nx && ny) return BigInt(x) < BigInt(y) ? -1 : 1;
1543
- if (nx !== ny) return nx ? -1 : 1;
1544
- return x < y ? -1 : 1;
1545
- }
1546
- return 0;
1547
- }
1548
- async function runtimeVersionStatus(project, latest) {
1549
- const current = project ? await projectRuntimeVersion(project) : void 0;
1550
- let versionStatus;
1551
- if (!project) versionStatus = "no_project";
1552
- else if (!current) versionStatus = "unconfigured";
1553
- else if (current === latest) versionStatus = "current";
1554
- else versionStatus = compareVersions(current, latest) < 0 ? "update_available" : "project_ahead";
1555
- return {
1556
- projectRuntimeVersion: current ?? null,
1557
- latestRuntimeVersion: latest,
1558
- versionStatus,
1559
- adaptationRequired: versionStatus !== "no_project" && versionStatus !== "current"
1560
- };
1561
- }
1562
- function reportRuntimeVersion(status, report) {
1563
- if (status.versionStatus === "no_project") return;
1564
- report(`Runtime \u7248\u672C\uFF1A\u5DE5\u7A0B ${status.projectRuntimeVersion ?? "\u672A\u9501\u5B9A\u51C6\u786E\u7248\u672C"}\uFF0Cnpm dev \u6700\u65B0 ${status.latestRuntimeVersion}\u3002`);
1565
- if (status.adaptationRequired) {
1566
- report("\u8BF7\u7531\u4F60\u6216\u5F00\u53D1 Agent \u66F4\u65B0\u4F9D\u8D56\u5E76\u9002\u914D\uFF1A\u68C0\u67E5\u65B0\u7248 Runtime \u7684\u542F\u52A8\u53C2\u6570\u3001\u6A21\u578B\u3001datasets\u3001\u5DE5\u5177\u53CA Hook\uFF0C\u5B8C\u6210\u9002\u914D\u540E\u9A8C\u8BC1 DEV\u3002CLI \u672A\u4FEE\u6539\u5DE5\u7A0B\u4F9D\u8D56\u6216\u914D\u7F6E\uFF1BDEV \u542F\u52A8\u3001\u81EA\u52A8\u91CD\u8F7D\u548C push \u5FC5\u987B\u901A\u8FC7\u6700\u65B0 Runtime \u68C0\u67E5\u3002");
1567
- report(`\u5728\u5DE5\u7A0B\u6839\u76EE\u5F55\u6267\u884C\uFF1Anpm install --save-exact ${BUDDY_RUNTIME_PACKAGE}@${status.latestRuntimeVersion} --registry=${RUNTIME_REGISTRY} --@my-life-buddies:registry=${RUNTIME_REGISTRY}`);
1568
- }
1569
- }
1570
- async function checkRuntimeUpdate(root, report, options = {}) {
1571
- options.signal?.throwIfAborted();
1572
- try {
1573
- const latest = await latestRuntimeVersion(options);
1574
- reportRuntimeVersion(await runtimeVersionStatus(root, latest), report);
1575
- options.signal?.throwIfAborted();
1576
- return;
1577
- } catch (cause) {
1578
- options.signal?.throwIfAborted();
1579
- report(`\u65E0\u6CD5\u68C0\u67E5 Runtime \u66F4\u65B0\uFF1A${cause instanceof Error ? cause.message : String(cause)}\u3002\u672C\u6B21\u672A\u786E\u8BA4 npm dev \u6700\u65B0\u7248\u672C\uFF1B\u53EF\u7EE7\u7EED\u67E5\u770B\u6216\u4FEE\u6539\u5DE5\u7A0B\uFF0CDEV \u542F\u52A8\u548C push \u4F1A\u53E6\u884C\u4E25\u683C\u68C0\u67E5\u3002`);
1580
- }
1581
- }
1582
-
1583
- // packages/cli-core/src/config/runtime-policy.ts
1584
- var RuntimeRequirementError = class extends Error {
1585
- constructor(code2, message, options) {
1586
- super(message, options);
1587
- this.code = code2;
1588
- this.name = "RuntimeRequirementError";
1589
- }
1590
- code;
1591
- };
1592
- function assertRequiredRuntime(actual, expected) {
1593
- if (actual === expected) return;
1594
- throw new RuntimeRequirementError(
1595
- "RUNTIME_VERSION_MISMATCH",
1596
- `\u5DF2\u963B\u6B62\u8FD0\u884C\u6216\u4E0A\u4F20\uFF1A\u5DE5\u7A0B Runtime ${actual ?? "\u672A\u9501\u5B9A\u51C6\u786E\u7248\u672C"}\uFF0Cnpm dev \u6700\u65B0\u7248\u672C ${expected}\u3002\u5FC5\u987B\u4F7F\u7528\u5B8C\u5168\u4E00\u81F4\u7684\u7248\u672C\u3002
1597
- \u8BF7\u7531\u4F60\u6216\u5F00\u53D1 Agent \u66F4\u65B0\u4F9D\u8D56\u548C\u9501\u6587\u4EF6\uFF0C\u9002\u914D\u542F\u52A8\u53C2\u6570\u3001\u6A21\u578B\u3001datasets\u3001\u5DE5\u5177\u53CA Hook \u540E\u91CD\u8BD5\u3002
1598
- npm install --save-exact ${BUDDY_RUNTIME_PACKAGE}@${expected} --registry=${RUNTIME_REGISTRY} --@my-life-buddies:registry=${RUNTIME_REGISTRY}`
1599
- );
1600
- }
1601
- function assertNpmRuntimeLock(contents, expected) {
1602
- const lock = JSON.parse(contents);
1603
- const installed2 = lock.lockfileVersion === 1 ? lock.dependencies?.[BUDDY_RUNTIME_PACKAGE] : lock.packages?.[`node_modules/${BUDDY_RUNTIME_PACKAGE}`];
1604
- if (installed2?.version !== expected || lock.lockfileVersion !== 1 && runtimeDependencyVersion(lock.packages?.[""]) !== expected) {
1605
- throw new RuntimeRequirementError("RUNTIME_DEPENDENCY_INVALID", `package-lock.json \u7684 Runtime \u4E0E\u8981\u6C42\u7684 ${expected} \u4E0D\u4E00\u81F4\u3002\u8BF7\u66F4\u65B0\u9501\u6587\u4EF6\u5E76\u91CD\u65B0\u5B89\u88C5\u4F9D\u8D56\u540E\u91CD\u8BD5\u3002`);
1606
- }
1607
- }
1608
- async function requireProjectRuntime(root, options = {}) {
1609
- const declared = await projectRuntimeVersion(root);
1610
- if (!declared) throw new RuntimeRequirementError("RUNTIME_DEPENDENCY_INVALID", "\u5DE5\u7A0B\u5FC5\u987B\u5728 package.json \u58F0\u660E npm dev \u6700\u65B0 Runtime \u7684\u51C6\u786E\u7248\u672C\uFF0C\u5E76\u5B89\u88C5\u4F9D\u8D56\u548C\u9501\u6587\u4EF6\uFF1B\u4E0D\u80FD\u4F7F\u7528 dev\u3001latest \u6216\u7248\u672C\u8303\u56F4\u4F5C\u4E3A\u5DE5\u7A0B\u4F9D\u8D56\u3002");
1611
- let expected;
1612
- try {
1613
- expected = await latestRuntimeVersion(options);
1614
- } catch (cause) {
1615
- options.signal?.throwIfAborted();
1616
- throw new RuntimeRequirementError("RUNTIME_CHECK_FAILED", `\u65E0\u6CD5\u786E\u8BA4 npm dev \u6700\u65B0 Runtime\uFF0C\u5DF2\u963B\u6B62\u8FD0\u884C\u6216\u4E0A\u4F20\uFF1A${cause instanceof Error ? cause.message : String(cause)}\u3002\u8BF7\u6062\u590D\u8FDE\u63A5\u540E\u91CD\u8BD5\u3002`, { cause });
1617
- }
1618
- try {
1619
- assertRequiredRuntime(await projectRuntimeVersion(root), expected);
1620
- const installedPath = await realpath3(resolve5(root, "node_modules", BUDDY_RUNTIME_PACKAGE, "package.json"));
1621
- const fromProject = createRequire2(resolve5(root, "package.json")).resolve(`${BUDDY_RUNTIME_PACKAGE}/package.json`);
1622
- if (await realpath3(fromProject) !== installedPath) throw new Error("Runtime \u5FC5\u987B\u5B89\u88C5\u5728\u5F53\u524D\u5DE5\u7A0B\u4E2D");
1623
- const installed2 = JSON.parse(await readFile10(installedPath, "utf8"));
1624
- if (installed2.version !== expected) throw new Error(`Runtime \u5B9E\u9645\u5B89\u88C5 ${installed2.version}\uFF0C\u8981\u6C42 ${expected}`);
1625
- let lock;
1626
- try {
1627
- lock = await readFile10(resolve5(root, "package-lock.json"), "utf8");
1628
- } catch (cause) {
1629
- if (cause.code !== "ENOENT") throw cause;
1630
- }
1631
- if (lock !== void 0) assertNpmRuntimeLock(lock, expected);
1632
- options.signal?.throwIfAborted();
1633
- return expected;
1634
- } catch (cause) {
1635
- options.signal?.throwIfAborted();
1636
- if (cause instanceof RuntimeRequirementError) throw cause;
1637
- throw new RuntimeRequirementError("RUNTIME_DEPENDENCY_INVALID", `Runtime \u4F9D\u8D56\u6821\u9A8C\u5931\u8D25\uFF1A${cause instanceof Error ? cause.message : String(cause)}\u3002\u8BF7\u66F4\u65B0\u4F9D\u8D56\u53CA\u9501\u6587\u4EF6\u5E76\u5B89\u88C5\uFF1Bnpm \u5DE5\u7A0B\u53EF\u8FD0\u884C npm ci\u3002`, { cause });
1638
- }
1639
- }
1640
-
1641
- // packages/cli-core/src/init/runtime-version.ts
1642
1643
  async function resolveInitRuntime(root, options = {}) {
1643
1644
  let latest;
1644
1645
  try {