@my-life-buddies/cli 0.8.0 → 0.9.0

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/dist/bin/core.js CHANGED
@@ -1,53 +1,106 @@
1
- // packages/cli-core/src/config/models.ts
2
- var MODEL_IDS = Object.freeze([
3
- "kimi-k2.6",
4
- "kimi-k3",
5
- "deepseek-v4-flash",
6
- "deepseek-v4-pro"
7
- ]);
8
- var DEFAULT_MODEL_ID = MODEL_IDS[0];
9
-
10
1
  // packages/cli-core/src/commands/models.ts
11
- var MODELS_COMMAND_HELP = `\u7528\u6CD5: buddy-cli models [--json]
12
- \u67E5\u770B CLI \u5185\u7F6E\u7684\u6A21\u578B ID\uFF0C\u65E0\u9700\u767B\u5F55\u3001\u8054\u7F51\u6216 Agent \u5DE5\u7A0B\u3002
13
- \u5C06\u6240\u9009 ID \u5199\u5165 buddy.agent.json.model\uFF1B\u6A21\u677F\u5728 initialState.model \u4E2D\u4F7F\u7528\u5B83\u3002`;
14
- function runModelsCommand(args, io) {
15
- if (args.length === 1 && (args[0] === "--help" || args[0] === "-h")) {
16
- io.write(MODELS_COMMAND_HELP);
17
- } else if (args.length === 1 && args[0] === "--json") {
18
- io.write(JSON.stringify({ models: MODEL_IDS }, null, 2));
19
- } else if (args.length === 0) {
20
- io.write("CLI \u5185\u7F6E\u6A21\u578B\u76EE\u5F55\uFF08Runtime 0.12.0\uFF09\uFF1A");
21
- for (const id of MODEL_IDS) io.write(`- ${id}`);
22
- io.write("\u5C06\u6240\u9009 ID \u5199\u5165 buddy.agent.json.model\uFF1B\u672A\u8BBE\u7F6E\u65F6\u6A21\u677F\u4F7F\u7528 kimi-k2.6\u3002\u81EA\u5B9A\u4E49\u4F1A\u8BDD\u5DE5\u5382\u4E5F\u53EF\u6309\u4F1A\u8BDD\u8BBE\u7F6E initialState.model\u3002");
23
- } else {
24
- io.writeError(`models \u53C2\u6570\u65E0\u6548\u3002
25
- ${MODELS_COMMAND_HELP}`);
26
- return { exitCode: 2 };
27
- }
28
- return { exitCode: 0 };
2
+ import { resolve as resolve5 } from "node:path";
3
+
4
+ // packages/cli-core/src/config/runtime-catalog.ts
5
+ import { readFile, realpath } from "node:fs/promises";
6
+ import { createRequire } from "node:module";
7
+ import { resolve } from "node:path";
8
+ import { pathToFileURL } from "node:url";
9
+
10
+ // packages/cli-core/src/config/runtime-dependency.ts
11
+ var BUDDY_RUNTIME_PACKAGE = "@my-life-buddies/buddy-runtime";
12
+ function runtimeDependencyVersion(pkg) {
13
+ if (typeof pkg !== "object" || pkg === null || !("dependencies" in pkg)) return void 0;
14
+ const dependencies2 = pkg.dependencies;
15
+ if (typeof dependencies2 !== "object" || dependencies2 === null || !(BUDDY_RUNTIME_PACKAGE in dependencies2)) return void 0;
16
+ const version = dependencies2[BUDDY_RUNTIME_PACKAGE];
17
+ return typeof version === "string" && /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/u.test(version) ? version : void 0;
29
18
  }
30
19
 
31
- // packages/cli-core/src/commands/widgets.ts
32
- import { resolve as resolve5 } from "node:path";
20
+ // packages/cli-core/src/config/runtime-catalog.ts
21
+ async function loadRuntime(projectRoot) {
22
+ const packagePath = resolve(projectRoot, "package.json");
23
+ const expected = runtimeDependencyVersion(JSON.parse(await readFile(packagePath, "utf8")));
24
+ if (!expected) throw new Error(`package.json \u5FC5\u987B\u58F0\u660E ${BUDDY_RUNTIME_PACKAGE} \u7684\u51C6\u786E\u7248\u672C`);
25
+ const projectRequire = createRequire(packagePath);
26
+ let runtimePath;
27
+ try {
28
+ const installedPath = await realpath(resolve(projectRoot, "node_modules", BUDDY_RUNTIME_PACKAGE, "package.json"));
29
+ if (await realpath(projectRequire.resolve(`${BUDDY_RUNTIME_PACKAGE}/package.json`)) !== installedPath) {
30
+ throw new Error("Runtime \u5FC5\u987B\u5B89\u88C5\u5728\u5F53\u524D\u5DE5\u7A0B\u4E2D");
31
+ }
32
+ const installed = JSON.parse(await readFile(installedPath, "utf8"));
33
+ if (installed.version !== expected) throw new Error(`\u5DF2\u5B89\u88C5 ${installed.version}\uFF0C\u5DE5\u7A0B\u8981\u6C42 ${expected}`);
34
+ runtimePath = projectRequire.resolve(BUDDY_RUNTIME_PACKAGE);
35
+ } catch (cause) {
36
+ throw new Error(`\u5DE5\u7A0B\u7684 Runtime \u4F9D\u8D56\u672A\u6B63\u786E\u5B89\u88C5\uFF0C\u8BF7\u6309\u9501\u6587\u4EF6\u5B89\u88C5\u4F9D\u8D56\uFF1A${cause instanceof Error ? cause.message : String(cause)}`);
37
+ }
38
+ const runtime = await import(pathToFileURL(runtimePath).href);
39
+ return { runtime, runtimeVersion: expected, runtimePath };
40
+ }
41
+ async function readRuntimeDataCatalog(projectRoot) {
42
+ const { runtime, runtimeVersion: expected } = await loadRuntime(projectRoot);
43
+ const catalog = runtime.DATA_ACCESS_CAPABILITIES;
44
+ if (!Array.isArray(catalog)) {
45
+ throw new Error(`\u5DE5\u7A0B\u7684 Runtime ${expected} \u672A\u5BFC\u51FA DATA_ACCESS_CAPABILITIES\uFF0C\u8BF7\u4F7F\u7528\u5305\u542B\u6570\u636E\u76EE\u5F55\u7684\u65B0 Runtime \u5305\u3002`);
46
+ }
47
+ const seen = /* @__PURE__ */ new Set();
48
+ const datasets = catalog.map((value) => {
49
+ if (!value || typeof value !== "object") throw new Error("Runtime \u6570\u636E\u76EE\u5F55\u683C\u5F0F\u65E0\u6548");
50
+ const item = value;
51
+ if (typeof item.id !== "string" || !item.id.trim() || seen.has(item.id) || typeof item.title !== "string" || !item.title.trim() || typeof item.source !== "string" || !item.source.trim() || !Number.isSafeInteger(item.schemaVersion) || item.schemaVersion < 1) {
52
+ throw new Error("Runtime \u6570\u636E\u76EE\u5F55\u683C\u5F0F\u65E0\u6548\u6216\u5305\u542B\u91CD\u590D ID");
53
+ }
54
+ seen.add(item.id);
55
+ return Object.freeze({ id: item.id, title: item.title, source: item.source, schemaVersion: item.schemaVersion });
56
+ });
57
+ return Object.freeze({ runtimeVersion: expected, datasets: Object.freeze(datasets) });
58
+ }
59
+ async function readRuntimeModelCatalog(projectRoot) {
60
+ const { runtime, runtimeVersion, runtimePath } = await loadRuntime(projectRoot);
61
+ let models = runtime.MODEL_IDS;
62
+ if (models === void 0) {
63
+ try {
64
+ models = (await import(new URL("./model.js", pathToFileURL(runtimePath)).href)).MODEL_IDS;
65
+ } catch (cause) {
66
+ throw new Error(`Runtime ${runtimeVersion} \u7684\u6A21\u578B\u76EE\u5F55\u4E0D\u53EF\u8BFB\u53D6\uFF1A${cause instanceof Error ? cause.message : String(cause)}`);
67
+ }
68
+ }
69
+ if (!Array.isArray(models) || models.length === 0 || models.some((id) => typeof id !== "string" || !id.trim()) || new Set(models).size !== models.length) {
70
+ throw new Error(`Runtime ${runtimeVersion} \u7684 MODEL_IDS \u7F3A\u5931\u6216\u683C\u5F0F\u65E0\u6548`);
71
+ }
72
+ return Object.freeze({ runtimeVersion, models: Object.freeze([...models]) });
73
+ }
74
+ async function validateRuntimeModel(projectRoot, model) {
75
+ if (model === void 0) return;
76
+ const catalog = await readRuntimeModelCatalog(projectRoot);
77
+ if (!catalog.models.includes(model)) throw new Error(`/model\uFF1A\u5DE5\u7A0B Runtime ${catalog.runtimeVersion} \u4E0D\u652F\u6301 ${model}\uFF1B\u53EF\u9009 ${catalog.models.join("\u3001")}`);
78
+ }
79
+ async function validateRuntimeDatasets(projectRoot, requirements = []) {
80
+ const catalog = await readRuntimeDataCatalog(projectRoot);
81
+ const ids = new Set(catalog.datasets.map((item) => item.id));
82
+ for (const [index, item] of requirements.entries()) {
83
+ if (!ids.has(item.id)) throw new Error(`/datasets/${index}/id\uFF1A\u5DE5\u7A0B Runtime ${catalog.runtimeVersion} \u4E0D\u652F\u6301 ${item.id}`);
84
+ }
85
+ }
33
86
 
34
87
  // packages/cli-core/src/project-context.ts
35
- import { lstat as lstat4, realpath } from "node:fs/promises";
36
- import { dirname, join as join3, resolve as resolve3 } from "node:path";
88
+ import { lstat as lstat5, realpath as realpath2 } from "node:fs/promises";
89
+ import { dirname, join as join5, resolve as resolve4 } from "node:path";
37
90
 
38
91
  // packages/cli-core/src/config/index.ts
39
92
  import {
40
93
  link,
41
- lstat as lstat3,
42
- mkdir as mkdir2,
94
+ lstat as lstat4,
95
+ mkdir as mkdir3,
43
96
  open as open2,
44
- readFile as readFile2,
97
+ readFile as readFile5,
45
98
  readdir,
46
- rename,
99
+ rename as rename2,
47
100
  unlink as unlink2
48
101
  } from "node:fs/promises";
49
102
  import { randomUUID } from "node:crypto";
50
- import { isAbsolute, join as join2, resolve as resolve2, win32 } from "node:path";
103
+ import { isAbsolute, join as join4, resolve as resolve3, win32 } from "node:path";
51
104
  import { isDeepStrictEqual } from "node:util";
52
105
  import { Ajv2020 } from "ajv/dist/2020.js";
53
106
 
@@ -78,7 +131,7 @@ var buddy_agent_schema_default = {
78
131
  minLength: 1,
79
132
  maxLength: 128,
80
133
  pattern: "^[^\\s\\u0000-\\u001f\\u007f]+$",
81
- description: "\u4ECE buddy-cli models \u79BB\u7EBF\u67E5\u770B CLI \u5185\u7F6E\u6A21\u578B ID\uFF1B\u6A21\u677F\u5C06\u9009\u62E9\u4F20\u7ED9 initialState.model"
134
+ description: "\u4ECE buddy-cli models \u67E5\u770B Runtime \u6A21\u578B\u76EE\u5F55\uFF1B\u5DE5\u7A0B\u5185\u8BFB\u53D6\u5B89\u88C5\u7248\u672C\uFF0C\u5DE5\u7A0B\u5916\u8BFB\u53D6 npm \u6700\u65B0\u7248\u3002\u8FD0\u884C\u4E0E\u4E0A\u4F20\u9884\u68C0\u6309\u5DE5\u7A0B Runtime \u6821\u9A8C\u3002"
82
135
  },
83
136
  datasets: {
84
137
  type: "array",
@@ -110,12 +163,177 @@ var buddy_agent_schema_default = {
110
163
  };
111
164
 
112
165
  // packages/cli-core/src/project-files.ts
113
- import { lstat as lstat2 } from "node:fs/promises";
166
+ import { lstat as lstat3 } from "node:fs/promises";
167
+ import { join as join3 } from "node:path";
168
+
169
+ // packages/cli-core/src/init/scaffold.ts
170
+ import { lstat as lstat2, mkdir as mkdir2, open, readFile as readFile4, rmdir, unlink } from "node:fs/promises";
171
+ import { resolve as resolve2 } from "node:path";
172
+
173
+ // packages/cli-core/src/config/models.ts
174
+ var MODEL_IDS = Object.freeze([
175
+ "kimi-k2.6",
176
+ "kimi-k3",
177
+ "deepseek-v4-flash",
178
+ "deepseek-v4-pro"
179
+ ]);
180
+ var DEFAULT_MODEL_ID = "kimi-k2.6";
181
+
182
+ // packages/cli-core/src/init/runtime-template.ts
183
+ import { execFile as execFile2 } from "node:child_process";
184
+ import { mkdtemp as mkdtemp2, readFile as readFile3, rm as rm2, writeFile as writeFile2 } from "node:fs/promises";
185
+ import { tmpdir } from "node:os";
186
+ import { join as join2 } from "node:path";
187
+ import { promisify as promisify2 } from "node:util";
188
+
189
+ // packages/cli-core/src/config/runtime-package.ts
190
+ import { execFile } from "node:child_process";
191
+ import { lstat, mkdir, mkdtemp, readFile as readFile2, rename, rm, writeFile } from "node:fs/promises";
192
+ import { homedir } from "node:os";
114
193
  import { join } from "node:path";
194
+ import { promisify } from "node:util";
195
+ var RUNTIME_REGISTRY = "https://registry.npmjs.org/";
196
+ var execute = promisify(execFile);
197
+ async function latestRuntimeVersion(options = {}) {
198
+ options.signal?.throwIfAborted();
199
+ const timeout = AbortSignal.timeout(1e4);
200
+ const signal = options.signal ? AbortSignal.any([options.signal, timeout]) : timeout;
201
+ const response = await (options.fetch ?? globalThis.fetch)(`${RUNTIME_REGISTRY}${encodeURIComponent(BUDDY_RUNTIME_PACKAGE)}/latest`, {
202
+ signal,
203
+ headers: { Accept: "application/json" },
204
+ redirect: "error"
205
+ });
206
+ if (!response.ok) throw new Error(`npm \u8FD4\u56DE HTTP ${response.status}`);
207
+ const metadata = await response.json();
208
+ if (metadata?.name !== BUDDY_RUNTIME_PACKAGE || typeof metadata.version !== "string" || !/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/u.test(metadata.version)) {
209
+ throw new Error("npm latest \u672A\u8FD4\u56DE\u6B64 Runtime \u7684\u51C6\u786E\u7A33\u5B9A\u7248\u672C");
210
+ }
211
+ return metadata.version;
212
+ }
213
+ async function cachedLatestRuntimeRoot(options = {}) {
214
+ options.report?.("\u6B63\u5728\u67E5\u8BE2\u516C\u5171 npm \u7684\u6700\u65B0 Runtime\u2026");
215
+ const version = await latestRuntimeVersion(options);
216
+ const cache = options.cacheDirectory ?? join(homedir(), ".cache", "buddy-cli", "runtimes");
217
+ const destination = join(cache, version);
218
+ let cacheExists = false;
219
+ try {
220
+ await lstat(destination);
221
+ cacheExists = true;
222
+ } catch (cause) {
223
+ if (cause.code !== "ENOENT") throw cause;
224
+ }
225
+ if (cacheExists) {
226
+ try {
227
+ const pkg = JSON.parse(await readFile2(join(destination, "package.json"), "utf8"));
228
+ const installed = JSON.parse(await readFile2(join(destination, "node_modules", BUDDY_RUNTIME_PACKAGE, "package.json"), "utf8"));
229
+ if (runtimeDependencyVersion(pkg) === version && installed.version === version) return destination;
230
+ throw new Error("\u7F13\u5B58\u7248\u672C\u4E0D\u5339\u914D");
231
+ } catch (cause) {
232
+ throw new Error(`Runtime ${version} \u7684\u7F13\u5B58\u4E0D\u5B8C\u6574\uFF0C\u8BF7\u5220\u9664 ${destination} \u540E\u91CD\u8BD5`, { cause });
233
+ }
234
+ }
235
+ await mkdir(cache, { recursive: true });
236
+ const temporaryRoot = await mkdtemp(join(cache, `.install-${version}-`));
237
+ try {
238
+ await writeFile(join(temporaryRoot, "package.json"), JSON.stringify({
239
+ name: "buddy-runtime-catalog",
240
+ private: true,
241
+ type: "module",
242
+ dependencies: { [BUDDY_RUNTIME_PACKAGE]: version }
243
+ }));
244
+ const userConfig = join(temporaryRoot, ".npmrc");
245
+ await writeFile(userConfig, `registry=${RUNTIME_REGISTRY}
246
+ `);
247
+ options.report?.(`\u6B63\u5728\u7F13\u5B58 Runtime ${version} \u7684\u80FD\u529B\u76EE\u5F55\uFF0C\u9996\u6B21\u4F7F\u7528\u9700\u8981\u4E0B\u8F7D\u4F9D\u8D56\u2026`);
248
+ const runNpm = options.runNpm ?? ((args, settings) => execute("npm", args, { ...settings, encoding: "utf8", maxBuffer: 4 * 1024 * 1024 }));
249
+ await runNpm([
250
+ "install",
251
+ "--ignore-scripts",
252
+ "--no-audit",
253
+ "--no-fund",
254
+ "--engine-strict",
255
+ `--registry=${RUNTIME_REGISTRY}`,
256
+ `--@my-life-buddies:registry=${RUNTIME_REGISTRY}`,
257
+ `--userconfig=${userConfig}`,
258
+ "--prefer-online",
259
+ "--fetch-retries=0",
260
+ "--fetch-timeout=20000"
261
+ ], { cwd: temporaryRoot, signal: options.signal, timeout: 18e4 });
262
+ const installed = JSON.parse(await readFile2(join(temporaryRoot, "node_modules", BUDDY_RUNTIME_PACKAGE, "package.json"), "utf8"));
263
+ if (installed.version !== version) throw new Error(`\u7F13\u5B58\u7684 Runtime \u7248\u672C\u4E0E npm latest ${version} \u4E0D\u4E00\u81F4`);
264
+ options.signal?.throwIfAborted();
265
+ try {
266
+ await rename(temporaryRoot, destination);
267
+ } catch (cause) {
268
+ if (!["EEXIST", "ENOTEMPTY"].includes(cause.code ?? "")) throw cause;
269
+ }
270
+ return destination;
271
+ } finally {
272
+ await rm(temporaryRoot, { recursive: true, force: true });
273
+ }
274
+ }
275
+
276
+ // packages/cli-core/src/init/runtime-template.ts
277
+ var execute2 = promisify2(execFile2);
278
+ async function latestRuntimeTemplate(template, options) {
279
+ const bundledVersion = runtimeDependencyVersion(JSON.parse(template.packageJson));
280
+ if (!bundledVersion) throw new Error("CLI \u5DE5\u7A0B\u6A21\u677F\u7F3A\u5C11 Runtime \u7684\u51C6\u786E\u7248\u672C");
281
+ let temporaryRoot;
282
+ try {
283
+ options.signal?.throwIfAborted();
284
+ options.report("\u6B63\u5728\u67E5\u8BE2\u516C\u5171 npm \u7684\u6700\u65B0 Runtime\u2026");
285
+ const version = await latestRuntimeVersion(options);
286
+ let result = template;
287
+ if (version !== bundledVersion) {
288
+ temporaryRoot = await mkdtemp2(join2(tmpdir(), "buddy-runtime-template-"));
289
+ await writeFile2(join2(temporaryRoot, "package.json"), template.packageJson);
290
+ await writeFile2(join2(temporaryRoot, "package-lock.json"), template.packageLock);
291
+ const userConfig = join2(temporaryRoot, ".npmrc");
292
+ await writeFile2(userConfig, `registry=${RUNTIME_REGISTRY}
293
+ `);
294
+ options.report(`\u6B63\u5728\u4E3A Runtime ${version} \u751F\u6210\u4F9D\u8D56\u9501\u6587\u4EF6\u2026`);
295
+ const runNpm = options.runNpm ?? ((args, settings) => execute2("npm", args, { ...settings, encoding: "utf8", maxBuffer: 4 * 1024 * 1024 }));
296
+ await runNpm([
297
+ "install",
298
+ "--package-lock-only",
299
+ "--save-exact",
300
+ `${BUDDY_RUNTIME_PACKAGE}@${version}`,
301
+ "--ignore-scripts",
302
+ "--no-audit",
303
+ "--no-fund",
304
+ "--engine-strict",
305
+ `--registry=${RUNTIME_REGISTRY}`,
306
+ `--@my-life-buddies:registry=${RUNTIME_REGISTRY}`,
307
+ `--userconfig=${userConfig}`,
308
+ "--prefer-online",
309
+ "--fetch-retries=0",
310
+ "--fetch-timeout=20000"
311
+ ], { cwd: temporaryRoot, signal: options.signal, timeout: 6e4 });
312
+ result = {
313
+ packageJson: await readFile3(join2(temporaryRoot, "package.json"), "utf8"),
314
+ packageLock: await readFile3(join2(temporaryRoot, "package-lock.json"), "utf8")
315
+ };
316
+ }
317
+ const pkg = JSON.parse(result.packageJson);
318
+ const lock = JSON.parse(result.packageLock);
319
+ const locked = lock.packages?.[`node_modules/${BUDDY_RUNTIME_PACKAGE}`];
320
+ if (runtimeDependencyVersion(pkg) !== version || runtimeDependencyVersion(lock.packages?.[""]) !== version || locked?.version !== version || typeof locked.integrity !== "string" || !locked.integrity || typeof locked.resolved !== "string" || !locked.resolved.startsWith(RUNTIME_REGISTRY)) {
321
+ throw new Error("\u751F\u6210\u7684 Runtime \u7248\u672C\u4E0E\u4F9D\u8D56\u9501\u6587\u4EF6\u4E0D\u4E00\u81F4");
322
+ }
323
+ options.signal?.throwIfAborted();
324
+ options.report(`\u5DF2\u4ECE\u516C\u5171 npm latest \u9501\u5B9A Runtime ${version}\uFF08package.json \u4E0E package-lock.json\uFF09\u3002`);
325
+ return result;
326
+ } catch (cause) {
327
+ if (options.signal?.aborted) throw new Error("Runtime \u7248\u672C\u9009\u62E9\u5DF2\u53D6\u6D88");
328
+ const reason = cause instanceof Error && !cause.message.includes("Command failed") ? cause.message : "npm \u672A\u5B8C\u6210\u9501\u6587\u4EF6\u751F\u6210";
329
+ options.report(`\u672A\u80FD\u9501\u5B9A\u6700\u65B0 Runtime\uFF1A${reason}\u3002\u672C\u6B21\u4F7F\u7528 CLI \u968F\u9644\u7684 Runtime ${bundledVersion} \u53CA\u5176\u9501\u6587\u4EF6\uFF1B\u5B89\u88C5\u540E\u53EF\u663E\u5F0F\u5347\u7EA7\u5DE5\u7A0B\u4F9D\u8D56\u3002`);
330
+ return template;
331
+ } finally {
332
+ if (temporaryRoot) await rm2(temporaryRoot, { recursive: true, force: true });
333
+ }
334
+ }
115
335
 
116
336
  // packages/cli-core/src/init/scaffold.ts
117
- import { lstat, mkdir, open, readFile, rmdir, unlink } from "node:fs/promises";
118
- import { resolve } from "node:path";
119
337
  var BUDDY_PLATFORM_AGENT_ENTRY = "agent.md";
120
338
  var BUDDY_PLATFORM_FACTORY_ENTRY = "src/buddy-options.mjs";
121
339
  var BUDDY_PLATFORM_PACKAGE_JSON = "package.json";
@@ -206,11 +424,11 @@ try {
206
424
  }
207
425
  `;
208
426
  }
209
- async function scaffoldPlatformAgent(projectRoot, name) {
210
- const path = resolve(projectRoot, BUDDY_PLATFORM_AGENT_ENTRY);
427
+ async function scaffoldPlatformAgent(projectRoot, name, options = {}) {
428
+ const path = resolve2(projectRoot, BUDDY_PLATFORM_AGENT_ENTRY);
211
429
  const hasAlternateLockfile = (await Promise.all(["pnpm-lock.yaml", "yarn.lock"].map(async (name2) => {
212
430
  try {
213
- if (!(await lstat(resolve(projectRoot, name2))).isFile()) {
431
+ if (!(await lstat2(resolve2(projectRoot, name2))).isFile()) {
214
432
  throw new TypeError(`\u4F9D\u8D56\u9501\u6587\u4EF6\u5FC5\u987B\u662F\u666E\u901A\u6587\u4EF6\uFF1A${name2}`);
215
433
  }
216
434
  return true;
@@ -221,23 +439,23 @@ async function scaffoldPlatformAgent(projectRoot, name) {
221
439
  }))).some(Boolean);
222
440
  const files = [
223
441
  { path, content: platformAgentTemplate(name) },
224
- { path: resolve(projectRoot, BUDDY_PLATFORM_FACTORY_ENTRY), content: platformFactoryTemplate() },
225
- { path: resolve(projectRoot, BUDDY_PLATFORM_PACKAGE_JSON), content: await readFile(new URL("../../resources/agent-template/package.json", import.meta.url), "utf8") },
226
- ...hasAlternateLockfile ? [] : [{ path: resolve(projectRoot, BUDDY_PLATFORM_PACKAGE_LOCK), content: await readFile(new URL("../../resources/agent-template/package-lock.json", import.meta.url), "utf8") }],
227
- { path: resolve(projectRoot, BUDDY_PLATFORM_START_ENTRY), content: platformStartTemplate() }
442
+ { path: resolve2(projectRoot, BUDDY_PLATFORM_FACTORY_ENTRY), content: platformFactoryTemplate() },
443
+ { path: resolve2(projectRoot, BUDDY_PLATFORM_PACKAGE_JSON), content: await readFile4(new URL("../../resources/agent-template/package.json", import.meta.url), "utf8") },
444
+ ...hasAlternateLockfile ? [] : [{ path: resolve2(projectRoot, BUDDY_PLATFORM_PACKAGE_LOCK), content: await readFile4(new URL("../../resources/agent-template/package-lock.json", import.meta.url), "utf8") }],
445
+ { path: resolve2(projectRoot, BUDDY_PLATFORM_START_ENTRY), content: platformStartTemplate() }
228
446
  ];
229
447
  const handles = [];
230
448
  const createdDirectories = [];
231
449
  try {
232
450
  for (const directory of PLATFORM_DIRECTORIES) {
233
- const directoryPath = resolve(projectRoot, directory);
451
+ const directoryPath = resolve2(projectRoot, directory);
234
452
  try {
235
- await mkdir(directoryPath, { mode: 448 });
453
+ await mkdir2(directoryPath, { mode: 448 });
236
454
  createdDirectories.push(directoryPath);
237
455
  } catch (cause) {
238
456
  if (cause.code !== "EEXIST") throw cause;
239
457
  }
240
- if (!(await lstat(directoryPath)).isDirectory()) {
458
+ if (!(await lstat2(directoryPath)).isDirectory()) {
241
459
  throw new TypeError(`\u5B98\u65B9\u5DE5\u7A0B\u76EE\u5F55\u5FC5\u987B\u662F\u666E\u901A\u76EE\u5F55\uFF0C\u4E0D\u80FD\u4F7F\u7528\u6587\u4EF6\u6216\u7B26\u53F7\u94FE\u63A5\uFF1A${directoryPath}`);
242
460
  }
243
461
  }
@@ -246,11 +464,27 @@ async function scaffoldPlatformAgent(projectRoot, name) {
246
464
  handles.push({ path: file2.path, handle: await open(file2.path, "wx", 384) });
247
465
  } catch (cause) {
248
466
  if (cause.code !== "EEXIST") throw cause;
249
- if (!(await lstat(file2.path)).isFile()) {
467
+ if (!(await lstat2(file2.path)).isFile()) {
250
468
  throw new TypeError(`\u5B98\u65B9\u5DE5\u7A0B\u6587\u4EF6\u5FC5\u987B\u662F\u666E\u901A\u6587\u4EF6\uFF0C\u4E0D\u80FD\u4F7F\u7528\u76EE\u5F55\u6216\u7B26\u53F7\u94FE\u63A5\uFF1A${file2.path}`);
251
469
  }
252
470
  }
253
471
  }
472
+ const packageFile = files.find((file2) => file2.path === resolve2(projectRoot, BUDDY_PLATFORM_PACKAGE_JSON));
473
+ const lockFile = files.find((file2) => file2.path === resolve2(projectRoot, BUDDY_PLATFORM_PACKAGE_LOCK));
474
+ if (options.resolveDependencies && lockFile && handles.some((file2) => file2.path === packageFile.path) && handles.some((file2) => file2.path === lockFile.path)) {
475
+ const template = await options.resolveDependencies({ packageJson: packageFile.content, packageLock: lockFile.content });
476
+ packageFile.content = template.packageJson;
477
+ lockFile.content = template.packageLock;
478
+ }
479
+ if (lockFile && (handles.some((file2) => file2.path === packageFile.path) || handles.some((file2) => file2.path === lockFile.path))) {
480
+ const packageContents = handles.some((file2) => file2.path === packageFile.path) ? packageFile.content : await readFile4(packageFile.path, "utf8");
481
+ const lockContents = handles.some((file2) => file2.path === lockFile.path) ? lockFile.content : await readFile4(lockFile.path, "utf8");
482
+ const declared = JSON.parse(packageContents).dependencies ?? {};
483
+ const locked = JSON.parse(lockContents).packages?.[""]?.dependencies ?? {};
484
+ if (JSON.stringify(Object.entries(declared).sort()) !== JSON.stringify(Object.entries(locked).sort())) {
485
+ throw new Error("\u5DF2\u6709 package.json \u4E0E\u5F85\u8865\u9F50\u7684\u9501\u6587\u4EF6\u4E0D\u4E00\u81F4\uFF0C\u8BF7\u7528\u5DE5\u7A0B\u7684\u5305\u7BA1\u7406\u5668\u6062\u590D\u5339\u914D\u7684\u4F9D\u8D56\u6587\u4EF6\u540E\u91CD\u8BD5");
486
+ }
487
+ }
254
488
  for (const { path: filePath, handle } of handles) {
255
489
  const file2 = files.find((candidate) => candidate.path === filePath);
256
490
  await handle.writeFile(file2.content, "utf8");
@@ -280,7 +514,7 @@ async function missingBuddyAgentFiles(projectRoot) {
280
514
  ];
281
515
  const missing = await Promise.all(entries.map(async ([path, kind]) => {
282
516
  try {
283
- const entry = await lstat2(join(projectRoot, path));
517
+ const entry = await lstat3(join3(projectRoot, path));
284
518
  return (kind === "directory" ? entry.isDirectory() : entry.isFile()) ? void 0 : path;
285
519
  } catch (cause) {
286
520
  if (["ENOENT", "ENOTDIR"].includes(cause.code ?? "")) return path;
@@ -349,9 +583,6 @@ function validateBuddyProjectManifest(value) {
349
583
  return { ok: false, issues: schemaIssues(validateAgentSchema.errors) };
350
584
  }
351
585
  const manifest = value;
352
- if (manifest.model !== void 0 && !MODEL_IDS.includes(manifest.model)) {
353
- return { ok: false, issues: [{ path: "/model", message: `\u4E0D\u652F\u6301\u7684\u6A21\u578B ID\uFF1B\u53EF\u9009 ${MODEL_IDS.join("\u3001")}\uFF08buddy-cli models\uFF09` }] };
354
- }
355
586
  const seen = /* @__PURE__ */ new Set();
356
587
  for (const [index, dataset] of (manifest.datasets ?? []).entries()) {
357
588
  if (seen.has(dataset.id)) {
@@ -410,7 +641,7 @@ var ProjectInitializationError = class extends Error {
410
641
  };
411
642
  async function pathState(targetPath) {
412
643
  try {
413
- const entry = await lstat3(targetPath);
644
+ const entry = await lstat4(targetPath);
414
645
  if (!entry.isDirectory() || entry.isSymbolicLink()) return { kind: "other" };
415
646
  return { kind: "directory", identity: `${entry.dev}:${entry.ino}` };
416
647
  } catch (cause) {
@@ -430,7 +661,7 @@ function entryIdentity(entry) {
430
661
  }
431
662
  async function fileIdentity(targetPath) {
432
663
  try {
433
- const entry = await lstat3(targetPath);
664
+ const entry = await lstat4(targetPath);
434
665
  return entry.isFile() && !entry.isSymbolicLink() ? entryIdentity(entry) : void 0;
435
666
  } catch (cause) {
436
667
  if (cause.code === "ENOENT") return void 0;
@@ -439,7 +670,7 @@ async function fileIdentity(targetPath) {
439
670
  }
440
671
  async function unlinkMatchingFile(targetPath, expectedIdentity) {
441
672
  try {
442
- const entry = await lstat3(targetPath);
673
+ const entry = await lstat4(targetPath);
443
674
  if (!entry.isFile() || entry.isSymbolicLink() || entryIdentity(entry) !== expectedIdentity) {
444
675
  return false;
445
676
  }
@@ -477,7 +708,7 @@ async function readExistingManifest(agentConfigPath) {
477
708
  agentConfigPath
478
709
  );
479
710
  }
480
- const entry = await lstat3(agentConfigPath);
711
+ const entry = await lstat4(agentConfigPath);
481
712
  if (!entry.isFile() || entry.isSymbolicLink()) {
482
713
  throw new ProjectInitializationError(
483
714
  "TARGET_CHANGED",
@@ -486,7 +717,7 @@ async function readExistingManifest(agentConfigPath) {
486
717
  );
487
718
  }
488
719
  try {
489
- return parseBuddyProjectManifest(await readFile2(agentConfigPath, "utf8"));
720
+ return parseBuddyProjectManifest(await readFile5(agentConfigPath, "utf8"));
490
721
  } catch (cause) {
491
722
  throw new ProjectInitializationError(
492
723
  "TARGET_CHANGED",
@@ -497,8 +728,8 @@ async function readExistingManifest(agentConfigPath) {
497
728
  }
498
729
  }
499
730
  async function planBuddyDraftInitialization(directory) {
500
- const rootDirectory = resolve2(directory);
501
- const agentConfigPath = join2(rootDirectory, BUDDY_AGENT_FILENAME);
731
+ const rootDirectory = resolve3(directory);
732
+ const agentConfigPath = join4(rootDirectory, BUDDY_AGENT_FILENAME);
502
733
  const state2 = await pathState(rootDirectory);
503
734
  if (state2.kind === "other") {
504
735
  throw new ProjectInitializationError(
@@ -525,8 +756,8 @@ async function planBuddyDraftInitialization(directory) {
525
756
  };
526
757
  }
527
758
  async function planBuddyProjectInitialization(options) {
528
- const rootDirectory = resolve2(options.directory);
529
- const agentConfigPath = resolve2(rootDirectory, BUDDY_AGENT_FILENAME);
759
+ const rootDirectory = resolve3(options.directory);
760
+ const agentConfigPath = resolve3(rootDirectory, BUDDY_AGENT_FILENAME);
530
761
  const state2 = await pathState(rootDirectory);
531
762
  if (state2.kind === "other") {
532
763
  throw new ProjectInitializationError(
@@ -555,7 +786,7 @@ async function planBuddyProjectInitialization(options) {
555
786
  async function prepareInitializationDirectory(plan) {
556
787
  if (plan.createRootDirectory) {
557
788
  if ((await pathState(plan.rootDirectory)).kind !== "missing") throw targetChanged(plan);
558
- const firstCreatedDirectory = await mkdir2(plan.rootDirectory, { recursive: true });
789
+ const firstCreatedDirectory = await mkdir3(plan.rootDirectory, { recursive: true });
559
790
  if (firstCreatedDirectory === void 0) throw targetChanged(plan);
560
791
  const created = await pathState(plan.rootDirectory);
561
792
  if (created.kind !== "directory") throw targetChanged(plan);
@@ -570,7 +801,7 @@ async function prepareInitializationDirectory(plan) {
570
801
  async function publishNewFile(options) {
571
802
  let temporaryHandle;
572
803
  let publishedHandle;
573
- const temporaryPath = join2(
804
+ const temporaryPath = join4(
574
805
  options.rootDirectory,
575
806
  `.${options.temporaryLabel}.${process.pid}.${randomUUID()}.tmp`
576
807
  );
@@ -614,7 +845,7 @@ async function publishNewFile(options) {
614
845
  const afterPublish = await pathState(options.rootDirectory);
615
846
  const publishedFileIdentity = await fileIdentity(options.targetPath);
616
847
  const temporaryFileIdentity = await fileIdentity(temporaryPath);
617
- const publishedContents = publishedFileIdentity ? await readFile2(options.targetPath, "utf8") : void 0;
848
+ const publishedContents = publishedFileIdentity ? await readFile5(options.targetPath, "utf8") : void 0;
618
849
  if (afterPublish.kind !== "directory" || afterPublish.identity !== options.directoryIdentity || !publishedIdentity || publishedFileIdentity !== publishedIdentity || temporaryFileIdentity !== temporaryIdentity || publishedContents !== options.contents) {
619
850
  if (afterPublish.kind === "directory" && afterPublish.identity === options.directoryIdentity && publishedIdentity) {
620
851
  await unlinkMatchingFile(options.targetPath, publishedIdentity);
@@ -641,7 +872,7 @@ async function publishNewFile(options) {
641
872
  }
642
873
  }
643
874
  async function replaceExistingFile(options) {
644
- const temporaryPath = join2(
875
+ const temporaryPath = join4(
645
876
  options.rootDirectory,
646
877
  `.${options.temporaryLabel}.${process.pid}.${randomUUID()}.tmp`
647
878
  );
@@ -655,8 +886,8 @@ async function replaceExistingFile(options) {
655
886
  try {
656
887
  const root = await pathState(options.rootDirectory);
657
888
  if (root.kind !== "directory" || root.identity !== options.directoryIdentity || await fileIdentity(options.targetPath) !== options.expectedFileIdentity) throw targetChanged({ rootDirectory: options.rootDirectory });
658
- await rename(temporaryPath, options.targetPath);
659
- if (await readFile2(options.targetPath, "utf8") !== options.contents) {
889
+ await rename2(temporaryPath, options.targetPath);
890
+ if (await readFile5(options.targetPath, "utf8") !== options.contents) {
660
891
  throw targetChanged({ rootDirectory: options.rootDirectory });
661
892
  }
662
893
  } finally {
@@ -781,16 +1012,16 @@ async function initializeBuddyProject(options) {
781
1012
  return applyBuddyProjectInitialization(plan, options.config);
782
1013
  }
783
1014
  async function readBuddyProjectManifest(projectRoot) {
784
- const rootDirectory = resolve2(projectRoot);
785
- return parseBuddyProjectManifest(await readFile2(resolve2(rootDirectory, BUDDY_AGENT_FILENAME), "utf8"));
1015
+ const rootDirectory = resolve3(projectRoot);
1016
+ return parseBuddyProjectManifest(await readFile5(resolve3(rootDirectory, BUDDY_AGENT_FILENAME), "utf8"));
786
1017
  }
787
1018
  async function readBuddyAgentConfig(projectRoot) {
788
- const rootDirectory = resolve2(projectRoot);
789
- const source = await readFile2(resolve2(rootDirectory, BUDDY_AGENT_FILENAME), "utf8");
1019
+ const rootDirectory = resolve3(projectRoot);
1020
+ const source = await readFile5(resolve3(rootDirectory, BUDDY_AGENT_FILENAME), "utf8");
790
1021
  return parseBuddyAgentConfig(source);
791
1022
  }
792
1023
  async function readBuddyConfig(projectRoot) {
793
- const rootDirectory = resolve2(projectRoot);
1024
+ const rootDirectory = resolve3(projectRoot);
794
1025
  return combineBuddyProject(await readBuddyAgentConfig(rootDirectory));
795
1026
  }
796
1027
 
@@ -806,10 +1037,10 @@ var BuddyProjectContextError = class extends Error {
806
1037
  targetPath;
807
1038
  };
808
1039
  async function existingDirectory(target) {
809
- const requested = resolve3(target);
1040
+ const requested = resolve4(target);
810
1041
  let entry;
811
1042
  try {
812
- entry = await lstat4(requested);
1043
+ entry = await lstat5(requested);
813
1044
  } catch (cause) {
814
1045
  if (cause.code === "ENOENT") {
815
1046
  throw new BuddyProjectContextError(
@@ -828,12 +1059,12 @@ async function existingDirectory(target) {
828
1059
  requested
829
1060
  );
830
1061
  }
831
- return realpath(requested);
1062
+ return realpath2(requested);
832
1063
  }
833
1064
  async function projectFileState(directory, filename) {
834
- const configPath = join3(directory, filename);
1065
+ const configPath = join5(directory, filename);
835
1066
  try {
836
- const entry = await lstat4(configPath);
1067
+ const entry = await lstat5(configPath);
837
1068
  if (!entry.isFile() || entry.isSymbolicLink()) {
838
1069
  throw new BuddyProjectContextError(
839
1070
  "PROJECT_CONFIG_INVALID",
@@ -860,7 +1091,7 @@ async function findBuddyProjectRoot(startDirectory) {
860
1091
  return searchUp(await existingDirectory(startDirectory));
861
1092
  }
862
1093
  async function requireBuddyProjectRoot(startDirectory) {
863
- const requested = resolve3(startDirectory);
1094
+ const requested = resolve4(startDirectory);
864
1095
  const root = await findBuddyProjectRoot(requested);
865
1096
  if (root !== void 0) return root;
866
1097
  throw new BuddyProjectContextError(
@@ -874,7 +1105,7 @@ async function requireBuddyProjectRoot(startDirectory) {
874
1105
  }
875
1106
  async function requireBuddyAgentProjectRoot(startDirectory) {
876
1107
  const root = await requireBuddyProjectRoot(startDirectory);
877
- const agentPath = join3(root, BUDDY_AGENT_FILENAME);
1108
+ const agentPath = join5(root, BUDDY_AGENT_FILENAME);
878
1109
  try {
879
1110
  await readBuddyAgentConfig(root);
880
1111
  const missing = await missingBuddyAgentFiles(root);
@@ -893,10 +1124,10 @@ async function requireBuddyAgentProjectRoot(startDirectory) {
893
1124
  }
894
1125
  }
895
1126
  async function nearestExistingDirectory(target) {
896
- let candidate = resolve3(target);
1127
+ let candidate = resolve4(target);
897
1128
  while (true) {
898
1129
  try {
899
- const entry = await lstat4(candidate);
1130
+ const entry = await lstat5(candidate);
900
1131
  if (!entry.isDirectory()) {
901
1132
  throw new BuddyProjectContextError(
902
1133
  "PROJECT_DIRECTORY_INVALID",
@@ -904,7 +1135,7 @@ async function nearestExistingDirectory(target) {
904
1135
  candidate
905
1136
  );
906
1137
  }
907
- return realpath(candidate);
1138
+ return realpath2(candidate);
908
1139
  } catch (cause) {
909
1140
  if (cause.code !== "ENOENT") throw cause;
910
1141
  const parent = dirname(candidate);
@@ -914,7 +1145,7 @@ async function nearestExistingDirectory(target) {
914
1145
  }
915
1146
  }
916
1147
  async function assertOutsideBuddyProject(target) {
917
- const requested = resolve3(target);
1148
+ const requested = resolve4(target);
918
1149
  const container = await nearestExistingDirectory(requested);
919
1150
  const projectRoot = await searchUp(container);
920
1151
  if (projectRoot === void 0) return;
@@ -928,13 +1159,13 @@ async function assertOutsideBuddyProject(target) {
928
1159
  );
929
1160
  }
930
1161
  async function assertInitializableBuddyTarget(target) {
931
- const requested = resolve3(target);
1162
+ const requested = resolve4(target);
932
1163
  const container = await nearestExistingDirectory(requested);
933
1164
  const projectRoot = await searchUp(container);
934
1165
  if (projectRoot === void 0) return;
935
1166
  let requestedRoot = requested;
936
1167
  try {
937
- requestedRoot = await realpath(requested);
1168
+ requestedRoot = await realpath2(requested);
938
1169
  } catch (cause) {
939
1170
  if (cause.code !== "ENOENT") throw cause;
940
1171
  }
@@ -945,7 +1176,7 @@ async function assertInitializableBuddyTarget(target) {
945
1176
  } catch (cause) {
946
1177
  throw new BuddyProjectContextError(
947
1178
  "PROJECT_CONFIG_INVALID",
948
- `${join3(projectRoot, BUDDY_AGENT_FILENAME)} \u4E0D\u662F\u6709\u6548\u7684\u9879\u76EE\u6E05\u5355\u3002`,
1179
+ `${join5(projectRoot, BUDDY_AGENT_FILENAME)} \u4E0D\u662F\u6709\u6548\u7684\u9879\u76EE\u6E05\u5355\u3002`,
949
1180
  requested,
950
1181
  { cause }
951
1182
  );
@@ -961,10 +1192,54 @@ async function assertInitializableBuddyTarget(target) {
961
1192
  );
962
1193
  }
963
1194
 
1195
+ // packages/cli-core/src/commands/runtime-source.ts
1196
+ async function runtimeCatalogSource(directory, options = {}) {
1197
+ const project = await findBuddyProjectRoot(directory);
1198
+ if (project) return { root: project, source: "project" };
1199
+ return { root: await (options.latestRuntimeRoot?.() ?? cachedLatestRuntimeRoot(options)), source: "npm" };
1200
+ }
1201
+
1202
+ // packages/cli-core/src/commands/models.ts
1203
+ var MODELS_COMMAND_HELP = `\u7528\u6CD5: buddy-cli models [--directory <\u9879\u76EE\u76EE\u5F55>] [--json]
1204
+ \u5DE5\u7A0B\u5185\u8BFB\u53D6\u5DF2\u5B89\u88C5 Runtime \u7684\u6A21\u578B\u76EE\u5F55\uFF1B\u5DE5\u7A0B\u5916\u8054\u7F51\u8BFB\u53D6\u5E76\u7F13\u5B58\u516C\u5171 npm \u6700\u65B0 Runtime\u3002
1205
+ \u65E0\u9700\u767B\u5F55\u642D\u642D\u8D26\u53F7\u3002\u8F93\u51FA\u5305\u542B\u5B9E\u9645 Runtime \u7248\u672C\u548C\u6765\u6E90\u3002
1206
+ \u5C06\u6240\u9009 ID \u5199\u5165 buddy.agent.json.model\uFF1B\u6A21\u677F\u5728 initialState.model \u4E2D\u4F7F\u7528\u5B83\u3002`;
1207
+ async function runModelsCommand(args, io, cwd, options = {}) {
1208
+ try {
1209
+ if (args.length === 1 && (args[0] === "--help" || args[0] === "-h")) {
1210
+ io.write(MODELS_COMMAND_HELP);
1211
+ return { exitCode: 0 };
1212
+ }
1213
+ let directory;
1214
+ let json = false;
1215
+ for (let i = 0; i < args.length; i++) {
1216
+ if (args[i] === "--json" && !json) json = true;
1217
+ else if (args[i] === "--directory" && directory === void 0 && args[i + 1]?.trim() && !args[i + 1].startsWith("--")) directory = args[++i];
1218
+ else throw new Error(`models \u53C2\u6570\u65E0\u6548\uFF1A${args[i]}
1219
+ ${MODELS_COMMAND_HELP}`);
1220
+ }
1221
+ const { root, source } = await runtimeCatalogSource(resolve5(cwd, directory ?? "."), { report: (message) => io.writeError(message), ...options });
1222
+ const catalog = await readRuntimeModelCatalog(root);
1223
+ if (json) io.write(JSON.stringify({ source, ...catalog }, null, 2));
1224
+ else {
1225
+ io.write(`${source === "project" ? "\u5DE5\u7A0B" : "npm \u6700\u65B0"} Runtime ${catalog.runtimeVersion} \u63D0\u4F9B ${catalog.models.length} \u4E2A\u6A21\u578B\uFF1A`);
1226
+ for (const id of catalog.models) io.write(`- ${id}`);
1227
+ io.write("\u5C06\u6240\u9009 ID \u5199\u5165 buddy.agent.json.model\uFF1B\u81EA\u5B9A\u4E49\u4F1A\u8BDD\u5DE5\u5382\u4E5F\u53EF\u6309\u4F1A\u8BDD\u8BBE\u7F6E initialState.model\u3002");
1228
+ }
1229
+ return { exitCode: 0 };
1230
+ } catch (cause) {
1231
+ io.writeError(cause instanceof Error ? cause.message : String(cause));
1232
+ return { exitCode: 2 };
1233
+ }
1234
+ }
1235
+
1236
+ // packages/cli-core/src/commands/widgets.ts
1237
+ import { resolve as resolve7 } from "node:path";
1238
+
964
1239
  // packages/cli-core/src/widget-delivery.ts
965
1240
  import { createHash } from "node:crypto";
966
- import { lstat as lstat5, readFile as readFile3, realpath as realpath2, readdir as readdir2, mkdir as mkdir3, writeFile, rename as rename2 } from "node:fs/promises";
967
- import { join as join4, resolve as resolve4 } from "node:path";
1241
+ import { lstat as lstat6, readFile as readFile6, realpath as realpath3, readdir as readdir2, mkdir as mkdir4, writeFile as writeFile3, rename as rename3 } from "node:fs/promises";
1242
+ import { join as join6, resolve as resolve6 } from "node:path";
968
1243
  var LOCK = "widget-design.lock.json";
969
1244
  var IMPLEMENTATION = "widget-implementation.json";
970
1245
  var RECEIPTS = ".buddy/widget-verification.json";
@@ -982,12 +1257,12 @@ function portable(path) {
982
1257
  }
983
1258
  async function file(root, path, optional = false) {
984
1259
  portable(path);
985
- const base = await realpath2(root);
1260
+ const base = await realpath3(root);
986
1261
  let cursor = base;
987
1262
  const parts = path.split("/");
988
1263
  for (const [index, part] of parts.entries()) {
989
- cursor = join4(cursor, part);
990
- const stat2 = await lstat5(cursor).catch((e) => {
1264
+ cursor = join6(cursor, part);
1265
+ const stat2 = await lstat6(cursor).catch((e) => {
991
1266
  if (e.code === "ENOENT") return void 0;
992
1267
  throw e;
993
1268
  });
@@ -998,7 +1273,7 @@ async function file(root, path, optional = false) {
998
1273
  if (stat2.isSymbolicLink() || (index < parts.length - 1 ? !stat2.isDirectory() : !stat2.isFile())) throw new Error(`\u4E0D\u63A5\u53D7\u7B26\u53F7\u94FE\u63A5\u6216\u7279\u6B8A\u6587\u4EF6\uFF1A${path}`);
999
1274
  if (index === parts.length - 1 && stat2.size > 8 * 1024 * 1024) throw new Error(`\u6587\u4EF6\u8D85\u8FC7 8 MB\uFF1A${path}`);
1000
1275
  }
1001
- return readFile3(cursor);
1276
+ return readFile6(cursor);
1002
1277
  }
1003
1278
  async function jsonFile(root, path, optional = false) {
1004
1279
  const bytes = await file(root, path, optional);
@@ -1011,19 +1286,19 @@ async function jsonFile(root, path, optional = false) {
1011
1286
  }
1012
1287
  async function save(root, path, value) {
1013
1288
  portable(path);
1014
- let cursor = resolve4(root);
1289
+ let cursor = resolve6(root);
1015
1290
  for (const segment of path.split("/").slice(0, -1)) {
1016
- cursor = join4(cursor, segment);
1017
- await mkdir3(cursor).catch((e) => {
1291
+ cursor = join6(cursor, segment);
1292
+ await mkdir4(cursor).catch((e) => {
1018
1293
  if (e.code !== "EEXIST") throw e;
1019
1294
  });
1020
- const stat2 = await lstat5(cursor);
1295
+ const stat2 = await lstat6(cursor);
1021
1296
  if (!stat2.isDirectory() || stat2.isSymbolicLink()) throw new Error("\u5199\u5165\u76EE\u5F55\u4E0D\u5B89\u5168");
1022
1297
  }
1023
1298
  await file(root, path, true);
1024
- const target = join4(root, path), temp = `${target}.${process.pid}.${Date.now()}.tmp`;
1025
- await writeFile(temp, JSON.stringify(value, null, 2) + "\n", { flag: "wx", mode: 384 });
1026
- await rename2(temp, target);
1299
+ const target = join6(root, path), temp = `${target}.${process.pid}.${Date.now()}.tmp`;
1300
+ await writeFile3(temp, JSON.stringify(value, null, 2) + "\n", { flag: "wx", mode: 384 });
1301
+ await rename3(temp, target);
1027
1302
  }
1028
1303
  function validateLock(value) {
1029
1304
  if (!object(value) || value.schemaVersion !== 1 || !text(value.buddyId) || !text(value.revision) || !hashPattern.test(value.catalogHash) || !Array.isArray(value.items) || value.items.length > 100) throw new Error("\u8BBE\u8BA1\u7ED1\u5B9A\u6587\u4EF6\u65E0\u6548\uFF0C\u8BF7\u8FD0\u884C buddy-cli widgets sync");
@@ -1091,14 +1366,14 @@ async function sourceSnapshot(root) {
1091
1366
  const result = [];
1092
1367
  const visit = async (path, depth = 0) => {
1093
1368
  if (depth > 32 || result.length > 1e4) throw new Error("\u5B9E\u73B0\u6E90\u7801\u8D85\u51FA\u68C0\u67E5\u8303\u56F4");
1094
- const stat2 = await lstat5(join4(root, path)).catch((e) => {
1369
+ const stat2 = await lstat6(join6(root, path)).catch((e) => {
1095
1370
  if (e.code === "ENOENT") return void 0;
1096
1371
  throw e;
1097
1372
  });
1098
1373
  if (!stat2) return;
1099
1374
  if (stat2.isSymbolicLink()) throw new Error(`\u5B9E\u73B0\u4E0D\u80FD\u4F7F\u7528\u7B26\u53F7\u94FE\u63A5\uFF1A${path}`);
1100
1375
  if (stat2.isDirectory()) {
1101
- for (const name of (await readdir2(join4(root, path))).sort()) await visit(`${path}/${name}`, depth + 1);
1376
+ for (const name of (await readdir2(join6(root, path))).sort()) await visit(`${path}/${name}`, depth + 1);
1102
1377
  } else result.push([path, sha(await file(root, path))]);
1103
1378
  };
1104
1379
  for (const name of ["src", "resources", "widgets", "start.mjs", "agent.md", "buddy.agent.json", "package.json", "package-lock.json", "pnpm-lock.yaml", "yarn.lock"]) await visit(name);
@@ -1259,7 +1534,7 @@ async function runWidgetsCommand(args, io, cwd) {
1259
1534
  }
1260
1535
  if (action !== "verify" && (flags.has("--id") || flags.has("--evidence"))) throw new Error("--id / --evidence \u4EC5\u7528\u4E8E verify");
1261
1536
  if (action !== "check" && flags.has("--json")) throw new Error("--json \u4EC5\u7528\u4E8E check");
1262
- const root = await findBuddyProjectRoot(resolve5(cwd, flags.get("--directory") ?? "."));
1537
+ const root = await findBuddyProjectRoot(resolve7(cwd, flags.get("--directory") ?? "."));
1263
1538
  if (!root) throw new Error("\u8BF7\u5728\u642D\u5B50\u5DE5\u7A0B\u4E2D\u8FD0\u884C\uFF0C\u6216\u6307\u5B9A --directory");
1264
1539
  if (action === "sync") {
1265
1540
  await syncWidgetDesign(root);
@@ -1281,75 +1556,14 @@ async function runWidgetsCommand(args, io, cwd) {
1281
1556
  }
1282
1557
 
1283
1558
  // packages/cli-core/src/index.ts
1284
- import { lstat as lstat10 } from "node:fs/promises";
1285
-
1286
- // packages/cli-core/src/commands/datasets.ts
1287
- import { resolve as resolve7 } from "node:path";
1288
-
1289
- // packages/cli-core/src/config/runtime-catalog.ts
1290
- import { readFile as readFile4, realpath as realpath3 } from "node:fs/promises";
1291
- import { createRequire } from "node:module";
1292
- import { resolve as resolve6 } from "node:path";
1293
- import { pathToFileURL } from "node:url";
1294
-
1295
- // packages/cli-core/src/config/runtime-dependency.ts
1296
- var BUDDY_RUNTIME_PACKAGE = "@my-life-buddies/buddy-runtime";
1297
- function runtimeDependencyVersion(pkg) {
1298
- if (typeof pkg !== "object" || pkg === null || !("dependencies" in pkg)) return void 0;
1299
- const dependencies2 = pkg.dependencies;
1300
- if (typeof dependencies2 !== "object" || dependencies2 === null || !(BUDDY_RUNTIME_PACKAGE in dependencies2)) return void 0;
1301
- const version = dependencies2[BUDDY_RUNTIME_PACKAGE];
1302
- return typeof version === "string" && /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/u.test(version) ? version : void 0;
1303
- }
1304
-
1305
- // packages/cli-core/src/config/runtime-catalog.ts
1306
- async function readRuntimeDataCatalog(projectRoot) {
1307
- const packagePath = resolve6(projectRoot, "package.json");
1308
- const expected = runtimeDependencyVersion(JSON.parse(await readFile4(packagePath, "utf8")));
1309
- if (!expected) throw new Error(`package.json \u5FC5\u987B\u58F0\u660E ${BUDDY_RUNTIME_PACKAGE} \u7684\u51C6\u786E\u7248\u672C`);
1310
- const projectRequire = createRequire(packagePath);
1311
- let runtimePath;
1312
- try {
1313
- const installedPath = await realpath3(resolve6(projectRoot, "node_modules", BUDDY_RUNTIME_PACKAGE, "package.json"));
1314
- if (await realpath3(projectRequire.resolve(`${BUDDY_RUNTIME_PACKAGE}/package.json`)) !== installedPath) {
1315
- throw new Error("Runtime \u5FC5\u987B\u5B89\u88C5\u5728\u5F53\u524D\u5DE5\u7A0B\u4E2D");
1316
- }
1317
- const installed = JSON.parse(await readFile4(installedPath, "utf8"));
1318
- if (installed.version !== expected) throw new Error(`\u5DF2\u5B89\u88C5 ${installed.version}\uFF0C\u5DE5\u7A0B\u8981\u6C42 ${expected}`);
1319
- runtimePath = projectRequire.resolve(BUDDY_RUNTIME_PACKAGE);
1320
- } catch (cause) {
1321
- throw new Error(`\u5DE5\u7A0B\u7684 Runtime \u4F9D\u8D56\u672A\u6B63\u786E\u5B89\u88C5\uFF0C\u8BF7\u6309\u9501\u6587\u4EF6\u5B89\u88C5\u4F9D\u8D56\uFF1A${cause instanceof Error ? cause.message : String(cause)}`);
1322
- }
1323
- const runtime = await import(pathToFileURL(runtimePath).href);
1324
- const catalog = runtime.DATA_ACCESS_CAPABILITIES;
1325
- if (!Array.isArray(catalog)) {
1326
- throw new Error(`\u5DE5\u7A0B\u7684 Runtime ${expected} \u672A\u5BFC\u51FA DATA_ACCESS_CAPABILITIES\uFF0C\u8BF7\u4F7F\u7528\u5305\u542B\u6570\u636E\u76EE\u5F55\u7684\u65B0 Runtime \u5305\u3002`);
1327
- }
1328
- const seen = /* @__PURE__ */ new Set();
1329
- const datasets = catalog.map((value) => {
1330
- if (!value || typeof value !== "object") throw new Error("Runtime \u6570\u636E\u76EE\u5F55\u683C\u5F0F\u65E0\u6548");
1331
- const item = value;
1332
- if (typeof item.id !== "string" || !item.id.trim() || seen.has(item.id) || typeof item.title !== "string" || !item.title.trim() || typeof item.source !== "string" || !item.source.trim() || !Number.isSafeInteger(item.schemaVersion) || item.schemaVersion < 1) {
1333
- throw new Error("Runtime \u6570\u636E\u76EE\u5F55\u683C\u5F0F\u65E0\u6548\u6216\u5305\u542B\u91CD\u590D ID");
1334
- }
1335
- seen.add(item.id);
1336
- return Object.freeze({ id: item.id, title: item.title, source: item.source, schemaVersion: item.schemaVersion });
1337
- });
1338
- return Object.freeze({ runtimeVersion: expected, datasets: Object.freeze(datasets) });
1339
- }
1340
- async function validateRuntimeDatasets(projectRoot, requirements = []) {
1341
- const catalog = await readRuntimeDataCatalog(projectRoot);
1342
- const ids = new Set(catalog.datasets.map((item) => item.id));
1343
- for (const [index, item] of requirements.entries()) {
1344
- if (!ids.has(item.id)) throw new Error(`/datasets/${index}/id\uFF1A\u5DE5\u7A0B Runtime ${catalog.runtimeVersion} \u4E0D\u652F\u6301 ${item.id}`);
1345
- }
1346
- }
1559
+ import { lstat as lstat11 } from "node:fs/promises";
1347
1560
 
1348
1561
  // packages/cli-core/src/commands/datasets.ts
1562
+ import { resolve as resolve8 } from "node:path";
1349
1563
  var DATASETS_COMMAND_HELP = `\u7528\u6CD5: buddy-cli datasets [--directory <\u9879\u76EE\u76EE\u5F55>] [--json]
1350
- \u8BFB\u53D6\u5DE5\u7A0B\u6240\u5B89\u88C5 Runtime \u7684 DATA_ACCESS_CAPABILITIES\uFF0C\u65E0\u9700\u767B\u5F55\u6216\u8BF7\u6C42\u5E73\u53F0\u76EE\u5F55\u3002
1351
- \u5148\u6309\u5DE5\u7A0B\u9501\u6587\u4EF6\u5B89\u88C5\u4F9D\u8D56\u3002\u5C06\u6240\u9009 id \u4E0E\u7528\u9014 purpose \u5199\u5165 buddy.agent.json.datasets\uFF1B\u76EE\u5F55\u4E0D\u4EE3\u8868\u7528\u6237\u5DF2\u6388\u6743\u3002`;
1352
- async function runDatasetsCommand(args, io, cwd) {
1564
+ \u5DE5\u7A0B\u5185\u8BFB\u53D6\u5DF2\u5B89\u88C5 Runtime \u7684 DATA_ACCESS_CAPABILITIES\uFF1B\u5DE5\u7A0B\u5916\u8054\u7F51\u8BFB\u53D6\u5E76\u7F13\u5B58\u516C\u5171 npm \u6700\u65B0 Runtime\u3002
1565
+ \u65E0\u9700\u767B\u5F55\u642D\u642D\u8D26\u53F7\u3002\u5C06\u6240\u9009 id \u4E0E\u7528\u9014 purpose \u5199\u5165 buddy.agent.json.datasets\uFF1B\u76EE\u5F55\u4E0D\u4EE3\u8868\u7528\u6237\u5DF2\u6388\u6743\u3002`;
1566
+ async function runDatasetsCommand(args, io, cwd, options = {}) {
1353
1567
  try {
1354
1568
  if (args.length === 1 && (args[0] === "--help" || args[0] === "-h")) {
1355
1569
  io.write(DATASETS_COMMAND_HELP);
@@ -1363,13 +1577,14 @@ async function runDatasetsCommand(args, io, cwd) {
1363
1577
  else throw new Error(`datasets \u53C2\u6570\u65E0\u6548\uFF1A${args[i]}
1364
1578
  ${DATASETS_COMMAND_HELP}`);
1365
1579
  }
1366
- const root = await requireBuddyProjectRoot(resolve7(cwd, directory ?? "."));
1580
+ const { root, source } = await runtimeCatalogSource(resolve8(cwd, directory ?? "."), { report: (message) => io.writeError(message), ...options });
1367
1581
  const catalog = await readRuntimeDataCatalog(root);
1368
- if (json) io.write(JSON.stringify(catalog, null, 2));
1582
+ if (json) io.write(JSON.stringify({ source, ...catalog }, null, 2));
1369
1583
  else {
1370
- io.write(`\u5DE5\u7A0B Runtime ${catalog.runtimeVersion} \u63D0\u4F9B ${catalog.datasets.length} \u9879\u6570\u636E\u80FD\u529B\uFF1A`);
1584
+ io.write(`${source === "project" ? "\u5DE5\u7A0B" : "npm \u6700\u65B0"} Runtime ${catalog.runtimeVersion} \u63D0\u4F9B ${catalog.datasets.length} \u9879\u6570\u636E\u80FD\u529B\uFF1A`);
1371
1585
  for (const item of catalog.datasets) io.write(`- ${item.id} \u2014 ${item.title}\uFF08${item.source}\uFF0CSchema ${item.schemaVersion}\uFF09`);
1372
1586
  io.write("\u5C06\u6240\u9009 id \u548C purpose \u5199\u5165 buddy.agent.json.datasets\uFF1B\u7528\u6237\u6388\u6743\u7531\u5E73\u53F0\u5904\u7406\u3002");
1587
+ if (source === "project") io.write(`\u66F4\u65B0 CLI \u4E0D\u4F1A\u66F4\u65B0\u5DE5\u7A0B Runtime\u3002\u5982\u9700\u5347\u7EA7\u5230\u516C\u5171 npm \u6700\u65B0\u7248\uFF0C\u5728\u5DE5\u7A0B\u6839\u76EE\u5F55\u8FD0\u884C\uFF1Anpm install --save-exact ${BUDDY_RUNTIME_PACKAGE}@latest --registry=https://registry.npmjs.org/ --@my-life-buddies:registry=https://registry.npmjs.org/`);
1373
1588
  }
1374
1589
  return { exitCode: 0 };
1375
1590
  } catch (cause) {
@@ -1379,12 +1594,12 @@ ${DATASETS_COMMAND_HELP}`);
1379
1594
  }
1380
1595
 
1381
1596
  // packages/cli-core/src/index.ts
1382
- import { join as join11, resolve as resolve15 } from "node:path";
1597
+ import { join as join13, resolve as resolve16 } from "node:path";
1383
1598
 
1384
1599
  // packages/cli-core/src/init/creator.ts
1385
1600
  import { randomUUID as randomUUID2 } from "node:crypto";
1386
- import { link as link2, lstat as lstat6, mkdir as mkdir4, readFile as readFile5, unlink as unlink3, writeFile as writeFile2 } from "node:fs/promises";
1387
- import { join as join5 } from "node:path";
1601
+ import { link as link2, lstat as lstat7, mkdir as mkdir5, readFile as readFile7, unlink as unlink3, writeFile as writeFile4 } from "node:fs/promises";
1602
+ import { join as join7 } from "node:path";
1388
1603
  import { fileURLToPath } from "node:url";
1389
1604
 
1390
1605
  // packages/cli-core/src/init/development-handoff.ts
@@ -1462,11 +1677,11 @@ Tool \u548C Hook \u662F Runtime \u7684\u6269\u5C55\u70B9\uFF1BService \u53EA\u66
1462
1677
 
1463
1678
  \u5E73\u53F0\u80FD\u529B\u8981\u4EE5\u5B9E\u9645\u63A5\u5165\u4E3A\u51C6\u3002\u5F53\u524D Runtime \u63D0\u4F9B\u4F1A\u8BDD\u6D88\u606F\u3001Memory\u3001\u6388\u6743\u6570\u636E\u3001\u5C0F\u6302\u4EF6\u548C\u672C\u5730 Markdown \u8D44\u6599\u80FD\u529B\uFF1B\u6CA1\u6709\u63A5\u901A\u7684 Files\u3001Knowledge \u4E0D\u80FD\u56E0\u624B\u518C\u63D0\u5230\u5C31\u5BA3\u79F0\u53EF\u7528\u3002\u666E\u901A Tool \u4E5F\u4E0D\u4EE3\u8868\u5DF2\u7ECF\u63D0\u4F9B\u5B9A\u65F6\u3001\u957F\u671F\u4EFB\u52A1\u3001\u540E\u53F0\u8C03\u5EA6\u6216\u4E3B\u52A8\u89E6\u8FBE\u3002\u624B\u518C\u63CF\u8FF0\u7684\u4ED8\u8D39\u3001\u53D1\u5E03\u7B49\u670D\u52A1\u8BBE\u8BA1\u4E5F\u4E0D\u6784\u6210\u6267\u884C\u6536\u8D39\u6216\u53D1\u5E03\u52A8\u4F5C\u7684\u6388\u6743\u3002
1464
1679
 
1465
- \u9700\u8981\u7528\u6237\u6570\u636E\u65F6\uFF0C\u5148\u5728\u5DE5\u7A0B\u76EE\u5F55\u6267\u884C \`buddy-cli datasets\`\uFF08\u811A\u672C\u53EF\u7528 \`--json\`\uFF09\uFF0C\u4ECE\u5F53\u524D\u5B89\u88C5\u7684 Runtime \u5BFC\u51FA\u8BFB\u53D6\u5168\u90E8\u6570\u636E\u96C6\uFF1B\u4E0D\u8981\u6C42\u767B\u5F55\uFF0C\u4E0D\u4ECE Server \u62C9\u76EE\u5F55\u3002Runtime 0.12.0 \u542B 10 \u9879\uFF0CCLI \u4E0D\u590D\u5236\u679A\u4E3E\u3002\u628A\u5B9E\u9645\u9700\u8981\u7684 \`id\` \u548C\u7528\u9014 \`purpose\` \u5199\u5165 \`buddy.agent.json.datasets\`\uFF0C\u540C\u4E00 ID \u53EA\u5199\u4E00\u6B21\uFF0C\u7528\u9014\u4E0D\u80FD\u4E3A\u7A7A\u4E14\u6700\u591A 200 \u5B57\uFF1B\u65E0\u9700\u6C42\u65F6\u4FDD\u7559\u7A7A\u6570\u7EC4\u3002DEV \u548C\u58F0\u660E\u975E\u7A7A\u65F6\u7684 push \u9884\u68C0\u7528\u8FD9\u4EFD\u5DE5\u7A0B\u4F9D\u8D56\u6821\u9A8C ID\uFF1B\u9700\u8981\u5148\u5B89\u88C5\u4E0E package.json \u51C6\u786E\u7248\u672C\u4E00\u81F4\u7684 Runtime\u3002\u6E05\u5355\u58F0\u660E\u6570\u91CF\u4E0D\u7B49\u4E8E\u5355\u6B21\u67E5\u8BE2\u4E0A\u9650\uFF0C\u5F53\u524D\u4E00\u6B21\u67E5\u8BE2\u6700\u591A 8 \u9879\u3002
1680
+ \u9700\u8981\u7528\u6237\u6570\u636E\u65F6\uFF0C\u5148\u5728\u5DE5\u7A0B\u76EE\u5F55\u6267\u884C \`buddy-cli datasets\`\uFF08\u811A\u672C\u53EF\u7528 \`--json\`\uFF09\uFF0C\u4ECE\u5F53\u524D\u5B89\u88C5\u7684 Runtime \u5BFC\u51FA\u8BFB\u53D6\u5168\u90E8\u6570\u636E\u96C6\uFF1B\u4E0D\u8981\u6C42\u767B\u5F55\uFF0C\u4E0D\u4ECE Server \u62C9\u76EE\u5F55\u3002Runtime 0.12.2 \u542B 10 \u9879\uFF0CCLI \u4E0D\u590D\u5236\u679A\u4E3E\u3002\u628A\u5B9E\u9645\u9700\u8981\u7684 \`id\` \u548C\u7528\u9014 \`purpose\` \u5199\u5165 \`buddy.agent.json.datasets\`\uFF0C\u540C\u4E00 ID \u53EA\u5199\u4E00\u6B21\uFF0C\u7528\u9014\u4E0D\u80FD\u4E3A\u7A7A\u4E14\u6700\u591A 200 \u5B57\uFF1B\u65E0\u9700\u6C42\u65F6\u4FDD\u7559\u7A7A\u6570\u7EC4\u3002DEV \u548C\u58F0\u660E\u975E\u7A7A\u65F6\u7684 push \u9884\u68C0\u7528\u8FD9\u4EFD\u5DE5\u7A0B\u4F9D\u8D56\u6821\u9A8C ID\uFF1B\u9700\u8981\u5148\u5B89\u88C5\u4E0E package.json \u51C6\u786E\u7248\u672C\u4E00\u81F4\u7684 Runtime\u3002\u6E05\u5355\u58F0\u660E\u6570\u91CF\u4E0D\u7B49\u4E8E\u5355\u6B21\u67E5\u8BE2\u4E0A\u9650\uFF0C\u5F53\u524D\u4E00\u6B21\u67E5\u8BE2\u6700\u591A 8 \u9879\u3002
1466
1681
 
1467
1682
  \`start.mjs\` \u5C06\u58F0\u660E\u4EA4\u7ED9 \`StartOptions.dataRequirements\`\u3002Runtime \u5728\u5B9E\u9645\u6570\u636E\u67E5\u8BE2\u3001HealthKit \u6388\u6743\u548C\u4E3B\u52A8\u670D\u52A1\u8BF7\u6C42\u4E2D\u643A\u5E26\u5B8C\u6574\u58F0\u660E\uFF0C\u7531 Server \u6821\u9A8C\u8303\u56F4\u4E0E\u7528\u6237\u540C\u610F\uFF1B\u586B\u5199\u914D\u7F6E\u4E0D\u8868\u793A\u5DF2\u7ECF\u6388\u6743\u3002\u670D\u52A1\u7AEF\u4ECE\u4E0A\u4F20\u5305\u89E3\u6790\u5E76\u7ED1\u5B9A\u53D1\u5E03\u7248\u672C\u4ECD\u5F85\u5B9E\u73B0\u3002
1468
1683
 
1469
- \u6A21\u578B\u9700\u8981\u67E5\u6570\u636E\u65F6\uFF0C\u5728 \`src/buddy-options.mjs\` \u7684 \`initialState.tools\` \u4E2D\u52A0\u5165 \`conversation.tools.data_access_query\`\uFF1B\u9700\u8981\u5411\u7528\u6237\u7533\u8BF7\u65F6\u52A0\u5165 \`conversation.tools.data_access_request\`\uFF0C\u4F4D\u7F6E\u3001\u65E5\u5386\u7684\u4E00\u6B21\u6027\u7ED3\u679C\u901A\u8FC7 \`data_access_read_result\` \u8BFB\u53D6\uFF0CHealthKit \u5219\u91CD\u65B0\u67E5\u8BE2 Dataset\u3002\u4E1A\u52A1\u4EE3\u7801\u5BF9\u5E94\u4F7F\u7528 \`conversation.dataAccess.query/request/readResult\`\u3002\u5DE5\u7A0B\u6A21\u677F\u5DF2\u9501\u5B9A npm Runtime 0.12.0\u3002
1684
+ \u6A21\u578B\u9700\u8981\u67E5\u6570\u636E\u65F6\uFF0C\u5728 \`src/buddy-options.mjs\` \u7684 \`initialState.tools\` \u4E2D\u52A0\u5165 \`conversation.tools.data_access_query\`\uFF1B\u9700\u8981\u5411\u7528\u6237\u7533\u8BF7\u65F6\u52A0\u5165 \`conversation.tools.data_access_request\`\uFF0C\u4F4D\u7F6E\u3001\u65E5\u5386\u7684\u4E00\u6B21\u6027\u7ED3\u679C\u901A\u8FC7 \`data_access_read_result\` \u8BFB\u53D6\uFF0CHealthKit \u5219\u91CD\u65B0\u67E5\u8BE2 Dataset\u3002\u4E1A\u52A1\u4EE3\u7801\u5BF9\u5E94\u4F7F\u7528 \`conversation.dataAccess.query/request/readResult\`\u3002\u65B0\u5EFA\u5DE5\u7A0B\u52A8\u6001\u9009\u62E9\u516C\u5171 npm latest \u5E76\u9501\u5B9A\u51C6\u786E\u7248\u672C\uFF1B\u8054\u7F51\u5931\u8D25\u65F6\u660E\u786E\u63D0\u793A\u4F7F\u7528\u968F CLI \u9644\u5E26\u7684 Runtime 0.12.2\u3002\u5DF2\u6709\u5DE5\u7A0B\u901A\u8FC7\u5305\u7BA1\u7406\u5668\u663E\u5F0F\u5347\u7EA7\u4F9D\u8D56\u3002
1470
1685
 
1471
1686
  \u5C0F\u6302\u4EF6\u7684\u6A21\u578B\u5DE5\u5177\u4E3A \`widget_create\`\u3001\`widget_read\`\uFF08\u6574\u4E2A\u5C0F\u6302\u4EF6\uFF09\u3001\`widget_read_module\`\uFF08\u4E00\u4E2A\u6A21\u5757\uFF09\u3001\`widget_rename\`\u3001\`widget_write_record\`\u3001\`widget_delete_record\`\u3001\`widget_delete\`\uFF08\u6574\u4E2A\u5C0F\u6302\u4EF6\u8FDE\u8BB0\u5F55\uFF09\u548C \`widget_send\`\uFF0C\u6309\u4E1A\u52A1\u9700\u8981\u6CE8\u518C\u5230 \`initialState.tools\`\u3002\u4FEE\u6539\u8BB0\u5F55\u7528 \`conversation.widget.writeRecord(id, input)\`\uFF1B\u5220\u4E00\u6761\u8BB0\u5F55\u7528 \`conversation.widget.deleteRecord(id, module, recordId)\`\uFF0C\u4E0D\u80FD\u7528\u5220\u9664\u6574\u4E2A\u5C0F\u6302\u4EF6\u7684 \`conversation.widget.delete(id)\` \u4EE3\u66FF\u3002\u4E24\u4E2A\u8BFB\u53D6\u5DE5\u5177\u53EF\u7528\u4E8E\u4E3B\u52A8\u56DE\u5408\uFF0C\u5176\u4F59\u516D\u4E2A\u5199\u5165\u5DE5\u5177\u7531 Runtime \u963B\u6B62\u5728\u4E3B\u52A8\u56DE\u5408\u6267\u884C\u3002
1472
1687
 
@@ -1544,16 +1759,16 @@ var REQUIRED = [
1544
1759
  var CreatorPreparationError = class extends Error {
1545
1760
  };
1546
1761
  async function state(path) {
1547
- return lstat6(path).catch((cause) => {
1762
+ return lstat7(path).catch((cause) => {
1548
1763
  if (cause.code === "ENOENT") return void 0;
1549
1764
  throw cause;
1550
1765
  });
1551
1766
  }
1552
1767
  async function safeDirectory(path) {
1553
- await mkdir4(path, { mode: 448 }).catch((cause) => {
1768
+ await mkdir5(path, { mode: 448 }).catch((cause) => {
1554
1769
  if (cause.code !== "EEXIST") throw cause;
1555
1770
  });
1556
- if (!(await lstat6(path)).isDirectory()) {
1771
+ if (!(await lstat7(path)).isDirectory()) {
1557
1772
  throw new CreatorPreparationError(`\u521B\u4F5C\u76EE\u5F55\u5FC5\u987B\u662F\u666E\u901A\u76EE\u5F55\uFF0C\u4E0D\u80FD\u4F7F\u7528\u7B26\u53F7\u94FE\u63A5\uFF1A${path}`);
1558
1773
  }
1559
1774
  }
@@ -1563,11 +1778,11 @@ async function safeRead(path) {
1563
1778
  if (!entry.isFile() || entry.size > MAX_LOCAL_FILE_BYTES) {
1564
1779
  throw new CreatorPreparationError(`\u521B\u4F5C\u6587\u4EF6\u4E0D\u662F\u666E\u901A\u6587\u4EF6\u6216\u8D85\u51FA\u5927\u5C0F\u9650\u5236\uFF1A${path}`);
1565
1780
  }
1566
- return readFile5(path);
1781
+ return readFile7(path);
1567
1782
  }
1568
1783
  async function writeOnce(path, bytes) {
1569
1784
  const temporary = `${path}.${randomUUID2()}.tmp`;
1570
- await writeFile2(temporary, bytes, { flag: "wx", mode: 384 });
1785
+ await writeFile4(temporary, bytes, { flag: "wx", mode: 384 });
1571
1786
  try {
1572
1787
  await link2(temporary, path).catch((cause) => {
1573
1788
  if (cause.code !== "EEXIST") throw cause;
@@ -1578,17 +1793,17 @@ async function writeOnce(path, bytes) {
1578
1793
  }
1579
1794
  async function bundledSkill(root) {
1580
1795
  for (const path of REQUIRED) {
1581
- if (!(await state(join5(root, path)))?.isFile()) {
1796
+ if (!(await state(join7(root, path)))?.isFile()) {
1582
1797
  throw new CreatorPreparationError(`CLI \u5185\u7F6E Creator Skill \u4E0D\u5B8C\u6574\uFF0C\u8BF7\u91CD\u65B0\u5B89\u88C5 CLI\uFF08\u7F3A\u5C11 ${path}\uFF09\u3002\u4E0D\u4F1A\u5C1D\u8BD5\u5728\u7EBF\u4E0B\u8F7D\u6216\u8986\u76D6\u9879\u76EE\u8D44\u6599\u3002`);
1583
1798
  }
1584
1799
  }
1585
1800
  return root;
1586
1801
  }
1587
1802
  function handoffMarkdown(context, skillRoot, session, workspacePath) {
1588
- const contextPath = join5(context.projectRoot, ".buddy", "creator", "initial-context.json");
1803
+ const contextPath = join7(context.projectRoot, ".buddy", "creator", "initial-context.json");
1589
1804
  const openArgs = [
1590
1805
  "-B",
1591
- join5(skillRoot, "scripts/buddy.py"),
1806
+ join7(skillRoot, "scripts/buddy.py"),
1592
1807
  "open",
1593
1808
  "--workspace",
1594
1809
  workspacePath,
@@ -1618,7 +1833,7 @@ function handoffMarkdown(context, skillRoot, session, workspacePath) {
1618
1833
 
1619
1834
  ## \u73B0\u5728\u7531 Coding Agent \u6267\u884C
1620
1835
 
1621
- 1. \u5B8C\u6574\u8BFB\u53D6 ${JSON.stringify(join5(skillRoot, "SKILL.md"))} \u53CA\u5176\u6307\u5B9A\u7684 references\u3002\u4FDD\u7559\u539F\u6709\u56DB\u9636\u6BB5\u89C4\u5219\uFF0C\u7531\u5F53\u524D\u4E3B\u5BF9\u8BDD\u5B8C\u6210\u91C7\u8BBF\uFF1B\u65E0\u9700\u53E6\u8D77 Sub-agent \u6216\u8FD0\u884C\u91C7\u8BBF\u6A21\u578B\u670D\u52A1\u3002
1836
+ 1. \u5B8C\u6574\u8BFB\u53D6 ${JSON.stringify(join7(skillRoot, "SKILL.md"))} \u53CA\u5176\u6307\u5B9A\u7684 references\u3002\u4FDD\u7559\u539F\u6709\u56DB\u9636\u6BB5\u89C4\u5219\uFF0C\u7531\u5F53\u524D\u4E3B\u5BF9\u8BDD\u5B8C\u6210\u91C7\u8BBF\uFF1B\u65E0\u9700\u53E6\u8D77 Sub-agent \u6216\u8FD0\u884C\u91C7\u8BBF\u6A21\u578B\u670D\u52A1\u3002
1622
1837
  2. \u67E5\u627E\u5BBF\u4E3B\u6216\u7CFB\u7EDF\u5B9E\u9645\u53EF\u7528\u7684 Python 3.9+\uFF0C\u68C0\u67E5\u7248\u672C\uFF0C\u4FDD\u5B58\u5176\u7EDD\u5BF9\u8DEF\u5F84\u3002\u4E0D\u8981\u5199\u6B7B\u672C\u673A\u8DEF\u5F84\uFF0C\u4E0D\u5B89\u88C5 pip/npm \u4F9D\u8D56\u3002\u6CA1\u6709 Python \u65F6\u62A5\u544A\u7F3A\u53E3\uFF0C\u4FDD\u7559\u672C\u5730\u9879\u76EE\u3002\u6240\u6709 Python \u8C03\u7528\u5747\u52A0 -B\uFF0C\u5E76\u8BBE\u7F6E\u8FDB\u7A0B\u73AF\u5883\u53D8\u91CF PYTHONDONTWRITEBYTECODE=1\uFF08\u7531\u9884\u89C8\u5B50\u8FDB\u7A0B\u7EE7\u627F\uFF09\uFF0C\u907F\u514D\u5411 CLI \u5B89\u88C5\u76EE\u5F55\u5199\u5165\u5B57\u8282\u7801\u7F13\u5B58\u3002
1623
1838
  3. \u4F7F\u7528\u5DE5\u5177\u4F20\u9012\u72EC\u7ACB\u53C2\u6570\uFF0C\u4E0D\u62FC\u63A5 shell \u5B57\u7B26\u4E32\u3002\u5DE5\u4F5C\u76EE\u5F55\u4E3A ${JSON.stringify(context.projectRoot)}\uFF1B\u4EE5\u5B9E\u9645 Python \u8DEF\u5F84\u4E3A executable\uFF0C\u9996\u6B21\u6253\u5F00\u7684 argv \u5982\u4E0B\uFF1A
1624
1839
 
@@ -1655,11 +1870,11 @@ ${DEVELOPMENT_HANDOFF}
1655
1870
  `;
1656
1871
  }
1657
1872
  async function prepareCreatorSkill(context, io, options = {}) {
1658
- const root = join5(context.projectRoot, ".buddy", "creator");
1873
+ const root = join7(context.projectRoot, ".buddy", "creator");
1659
1874
  try {
1660
- await safeDirectory(join5(context.projectRoot, ".buddy"));
1875
+ await safeDirectory(join7(context.projectRoot, ".buddy"));
1661
1876
  await safeDirectory(root);
1662
- const sessionPath = join5(root, "session.json");
1877
+ const sessionPath = join7(root, "session.json");
1663
1878
  await writeOnce(sessionPath, JSON.stringify({
1664
1879
  schemaVersion: 1,
1665
1880
  platformBuddyId: context.buddyId,
@@ -1671,11 +1886,11 @@ async function prepareCreatorSkill(context, io, options = {}) {
1671
1886
  }
1672
1887
  options.signal?.throwIfAborted();
1673
1888
  const skillRoot = await bundledSkill(options.bundledSkillRoot ?? BUNDLED_CREATOR_SKILL_ROOT);
1674
- await safeDirectory(join5(root, "workspaces"));
1675
- const workspacePath = join5(root, "workspaces", session.creationKey);
1889
+ await safeDirectory(join7(root, "workspaces"));
1890
+ const workspacePath = join7(root, "workspaces", session.creationKey);
1676
1891
  const workspace = await state(workspacePath);
1677
1892
  if (workspace && !workspace.isDirectory()) throw new CreatorPreparationError("\u5DF2\u6709\u521B\u4F5C\u5DE5\u4F5C\u533A\u4E0D\u662F\u666E\u901A\u76EE\u5F55\u3002");
1678
- const contextPath = join5(root, "initial-context.json");
1893
+ const contextPath = join7(root, "initial-context.json");
1679
1894
  await writeOnce(contextPath, JSON.stringify({
1680
1895
  source: "platform_meta",
1681
1896
  name: context.appName,
@@ -1691,7 +1906,7 @@ async function prepareCreatorSkill(context, io, options = {}) {
1691
1906
  } catch {
1692
1907
  throw new CreatorPreparationError(`\u5DF2\u6709\u521D\u59CB\u80CC\u666F\u65E0\u6548\uFF0C\u5DF2\u4FDD\u7559\u539F\u6587\u4EF6\uFF0C\u8BF7\u68C0\u67E5\uFF1A${contextPath}`);
1693
1908
  }
1694
- const handoffPath = join5(root, "HANDOFF.md");
1909
+ const handoffPath = join7(root, "HANDOFF.md");
1695
1910
  const handoff = handoffMarkdown({
1696
1911
  ...context,
1697
1912
  appName: initial.name,
@@ -1702,11 +1917,11 @@ async function prepareCreatorSkill(context, io, options = {}) {
1702
1917
  if ((await safeRead(handoffPath))?.toString("utf8") !== handoff) {
1703
1918
  throw new CreatorPreparationError(`\u5DF2\u6709\u63A5\u7EED\u8BF4\u660E\u88AB\u4FEE\u6539\u6216\u9879\u76EE\u8DEF\u5F84\u5DF2\u53D8\u5316\uFF0C\u5DF2\u4FDD\u7559\u539F\u6587\u4EF6\u3002\u8BF7\u5907\u4EFD\u79FB\u8D70\u8BE5\u8BF4\u660E\u540E\u91CD\u8BD5\uFF1A${handoffPath}`);
1704
1919
  }
1705
- io.write(`\u4F7F\u7528 CLI \u5185\u7F6E Creator Skill\uFF0C\u65E0\u9700\u989D\u5916\u4E0B\u8F7D\uFF1A${join5(skillRoot, "SKILL.md")}`);
1920
+ io.write(`\u4F7F\u7528 CLI \u5185\u7F6E Creator Skill\uFF0C\u65E0\u9700\u989D\u5916\u4E0B\u8F7D\uFF1A${join7(skillRoot, "SKILL.md")}`);
1706
1921
  io.write(`\u4E0B\u4E00\u6B65\u4EA4\u7ED9 Codex / Claude Code \u7B49 Coding Agent\uFF1A\u8BF7\u8BFB\u53D6 ${JSON.stringify(handoffPath)}\uFF0C\u6309\u5F53\u524D\u9636\u6BB5\u63A5\u7EED\uFF1BCreator \u5B8C\u6210\u540E\u8FD4\u56DE CLI \u5F00\u53D1\u6D41\u7A0B\u3002`);
1707
1922
  io.write(DEVELOPMENT_HANDOFF_SUMMARY);
1708
1923
  io.write("\u672C\u547D\u4EE4\u53EA\u8D1F\u8D23\u8EAB\u4EFD\u767B\u8BB0\u548C Skill \u51C6\u5907\uFF0C\u4E0D\u4EE3\u8868\u91C7\u8BBF\u3001Booklet \u6216 Agent \u5DF2\u5B8C\u6210\u3002\u8BF7\u6309\u5DF2\u6709\u4F5C\u54C1\u8FDB\u5EA6\u63A5\u7EED\uFF0C\u56DB\u518C\u53CA\u5C0F\u6302\u4EF6\u8BBE\u8BA1\u9A8C\u6536\u3001\u4EA4\u4ED8\u6821\u9A8C\u5B8C\u6210\u540E\u81EA\u52A8\u8FDB\u5165\u5B98\u65B9 Runtime \u5F00\u53D1\uFF1B\u91CD\u590D create \u4F1A\u590D\u7528\u540C\u4E00\u4F5C\u54C1\u3002");
1709
- return { exitCode: 0, creator: { skillPath: join5(skillRoot, "SKILL.md"), handoffPath, workspacePath } };
1924
+ return { exitCode: 0, creator: { skillPath: join7(skillRoot, "SKILL.md"), handoffPath, workspacePath } };
1710
1925
  } catch (cause) {
1711
1926
  const message = cause instanceof CreatorPreparationError ? cause.message : "\u5185\u7F6E\u8D44\u6E90\u8BFB\u53D6\u6216\u672C\u5730\u5199\u5165\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5 CLI \u5B89\u88C5\u548C\u76EE\u5F55\u6743\u9650\u3002";
1712
1927
  io.writeError(`Creator Skill \u51C6\u5907\u5931\u8D25\uFF1A${message}`);
@@ -1766,7 +1981,7 @@ function validateBuddyMetaUpdate(meta2) {
1766
1981
  }
1767
1982
 
1768
1983
  // packages/cli-core/src/commands/dev.ts
1769
- import { resolve as resolve11 } from "node:path";
1984
+ import { resolve as resolve12 } from "node:path";
1770
1985
 
1771
1986
  // packages/cli-core/src/platform-url.ts
1772
1987
  var DEFAULT_MLB_TEST_URL = "http://47.116.168.81:8788";
@@ -2064,15 +2279,15 @@ function buildAgentEnvironment(options) {
2064
2279
 
2065
2280
  // packages/cli-core/src/dev/orchestrator.ts
2066
2281
  import { createHash as createHash3 } from "node:crypto";
2067
- import { readFile as readFile7 } from "node:fs/promises";
2068
- import { join as join7, resolve as resolve9 } from "node:path";
2282
+ import { readFile as readFile9 } from "node:fs/promises";
2283
+ import { join as join9, resolve as resolve10 } from "node:path";
2069
2284
 
2070
2285
  // packages/cli-core/src/dev/launch.ts
2071
2286
  import { lstatSync, readFileSync } from "node:fs";
2072
2287
  import { createRequire as createRequire2 } from "node:module";
2073
- import { dirname as dirname2, resolve as resolve8 } from "node:path";
2288
+ import { dirname as dirname2, resolve as resolve9 } from "node:path";
2074
2289
  async function officialAgentLaunchPlan(input) {
2075
- const entry = resolve8(input.projectRoot, BUDDY_PLATFORM_START_ENTRY);
2290
+ const entry = resolve9(input.projectRoot, BUDDY_PLATFORM_START_ENTRY);
2076
2291
  for (const [filename, kind] of [
2077
2292
  [dirname2(BUDDY_PLATFORM_FACTORY_ENTRY), "directory"],
2078
2293
  [BUDDY_PLATFORM_START_ENTRY, "file"],
@@ -2080,7 +2295,7 @@ async function officialAgentLaunchPlan(input) {
2080
2295
  [BUDDY_PLATFORM_PACKAGE_JSON, "file"]
2081
2296
  ]) {
2082
2297
  try {
2083
- const entry2 = lstatSync(resolve8(input.projectRoot, filename));
2298
+ const entry2 = lstatSync(resolve9(input.projectRoot, filename));
2084
2299
  if (!(kind === "directory" ? entry2.isDirectory() : entry2.isFile())) {
2085
2300
  throw new Error(`${filename} must be a regular ${kind}`);
2086
2301
  }
@@ -2093,7 +2308,7 @@ async function officialAgentLaunchPlan(input) {
2093
2308
  });
2094
2309
  }
2095
2310
  }
2096
- const packagePath = resolve8(input.projectRoot, BUDDY_PLATFORM_PACKAGE_JSON);
2311
+ const packagePath = resolve9(input.projectRoot, BUDDY_PLATFORM_PACKAGE_JSON);
2097
2312
  try {
2098
2313
  const expected = runtimeDependencyVersion(JSON.parse(readFileSync(packagePath, "utf8")));
2099
2314
  if (!expected) throw new Error(`package.json \u7684 dependencies \u5FC5\u987B\u58F0\u660E ${BUDDY_RUNTIME_PACKAGE} \u7684\u51C6\u786E\u7248\u672C`);
@@ -2101,6 +2316,7 @@ async function officialAgentLaunchPlan(input) {
2101
2316
  const installed = JSON.parse(readFileSync(runtimePath, "utf8")).version;
2102
2317
  if (installed !== expected) throw new Error(`Runtime \u5DF2\u5B89\u88C5 ${installed}\uFF0C\u5DE5\u7A0B\u8981\u6C42 ${expected}`);
2103
2318
  await validateRuntimeDatasets(input.projectRoot, input.datasets);
2319
+ await validateRuntimeModel(input.projectRoot, input.model);
2104
2320
  } catch (cause) {
2105
2321
  throw new BuddyDevError({
2106
2322
  code: "DEV_CONFIG_INVALID",
@@ -2143,16 +2359,16 @@ var NodeAgentProcessLauncher = class {
2143
2359
  }
2144
2360
  let hasExited = false;
2145
2361
  let spawned = false;
2146
- const exit = new Promise((resolve16) => {
2362
+ const exit = new Promise((resolve17) => {
2147
2363
  child.once("error", (error2) => {
2148
2364
  if (!spawned) {
2149
2365
  hasExited = true;
2150
- resolve16({ code: null, signal: null, error: error2 });
2366
+ resolve17({ code: null, signal: null, error: error2 });
2151
2367
  }
2152
2368
  });
2153
2369
  child.once("exit", (code2, signal) => {
2154
2370
  hasExited = true;
2155
- resolve16({ code: code2, signal });
2371
+ resolve17({ code: code2, signal });
2156
2372
  });
2157
2373
  });
2158
2374
  child.stdout?.on("data", (chunk) => {
@@ -2168,11 +2384,11 @@ var NodeAgentProcessLauncher = class {
2168
2384
  }
2169
2385
  });
2170
2386
  try {
2171
- await new Promise((resolve16, reject) => {
2387
+ await new Promise((resolve17, reject) => {
2172
2388
  const onSpawn = () => {
2173
2389
  spawned = true;
2174
2390
  child.off("error", onError);
2175
- resolve16();
2391
+ resolve17();
2176
2392
  };
2177
2393
  const onError = (error2) => {
2178
2394
  child.off("spawn", onSpawn);
@@ -2211,11 +2427,11 @@ var NodeAgentProcessLauncher = class {
2211
2427
  };
2212
2428
  function waitForExit(process2, timeoutMs) {
2213
2429
  if (process2.hasExited()) return Promise.resolve(true);
2214
- return new Promise((resolve16) => {
2215
- const timeout = setTimeout(() => resolve16(false), timeoutMs);
2430
+ return new Promise((resolve17) => {
2431
+ const timeout = setTimeout(() => resolve17(false), timeoutMs);
2216
2432
  process2.exit.then(() => {
2217
2433
  clearTimeout(timeout);
2218
- resolve16(true);
2434
+ resolve17(true);
2219
2435
  });
2220
2436
  });
2221
2437
  }
@@ -2298,7 +2514,7 @@ async function waitForGroupExit(pid, isGroupAlive, timeoutMs) {
2298
2514
  while (isGroupAlive(pid)) {
2299
2515
  const remaining = deadline - Date.now();
2300
2516
  if (remaining <= 0) return false;
2301
- await new Promise((resolve16) => setTimeout(resolve16, Math.min(25, remaining)));
2517
+ await new Promise((resolve17) => setTimeout(resolve17, Math.min(25, remaining)));
2302
2518
  }
2303
2519
  return true;
2304
2520
  }
@@ -2313,9 +2529,9 @@ function processTreeControllerFor(platform) {
2313
2529
 
2314
2530
  // packages/cli-core/src/dev/instance-lock.ts
2315
2531
  import { createHash as createHash2, randomUUID as randomUUID3 } from "node:crypto";
2316
- import { mkdir as mkdir5, readFile as readFile6, readdir as readdir3, rename as rename3, rmdir as rmdir2, unlink as unlink4, writeFile as writeFile3 } from "node:fs/promises";
2317
- import { homedir } from "node:os";
2318
- import { join as join6 } from "node:path";
2532
+ import { mkdir as mkdir6, readFile as readFile8, readdir as readdir3, rename as rename4, rmdir as rmdir2, unlink as unlink4, writeFile as writeFile5 } from "node:fs/promises";
2533
+ import { homedir as homedir2 } from "node:os";
2534
+ import { join as join8 } from "node:path";
2319
2535
  function alreadyRunningError() {
2320
2536
  const message = "\u8FD9\u4E2A\u642D\u5B50\u5DF2\u6709 DEV \u5B9E\u4F8B\u5728\u8FD0\u884C\u3002\u8BF7\u5148\u5728\u539F\u9884\u89C8\u9875\u70B9\u51FB\u300C\u505C\u6B62 DEV\u300D\uFF0C\u6216\u5728\u8FD0\u884C dev \u7684\u7EC8\u7AEF\u6309 Ctrl+C\uFF0C\u518D\u542F\u52A8\u3002";
2321
2537
  return Object.assign(new BuddyDevError({ code: "DEV_ALREADY_RUNNING", phase: "launch", message }), { publicMessage: message });
@@ -2335,20 +2551,20 @@ function code(error2) {
2335
2551
  return error2?.code;
2336
2552
  }
2337
2553
  async function acquireDevInstanceLock(options) {
2338
- const root = options.directory ?? join6(homedir(), ".buddy", "dev-locks");
2554
+ const root = options.directory ?? join8(homedir2(), ".buddy", "dev-locks");
2339
2555
  const key = createHash2("sha256").update(`${new URL(options.gatewayUrl).origin}
2340
2556
  ${options.devAgentId}`).digest("hex");
2341
- const path = join6(root, key);
2557
+ const path = join8(root, key);
2342
2558
  const ownerName = `owner-${randomUUID3()}.json`;
2343
- const candidate = join6(root, `.pending-${randomUUID3()}`);
2559
+ const candidate = join8(root, `.pending-${randomUUID3()}`);
2344
2560
  const owner = { pid: process.pid };
2345
- await mkdir5(root, { recursive: true, mode: 448 });
2346
- await mkdir5(candidate, { mode: 448 });
2347
- await writeFile3(join6(candidate, ownerName), JSON.stringify(owner), { mode: 384, flag: "wx" });
2561
+ await mkdir6(root, { recursive: true, mode: 448 });
2562
+ await mkdir6(candidate, { mode: 448 });
2563
+ await writeFile5(join8(candidate, ownerName), JSON.stringify(owner), { mode: 384, flag: "wx" });
2348
2564
  try {
2349
2565
  for (let attempt = 0; ; attempt++) {
2350
2566
  try {
2351
- await rename3(candidate, path);
2567
+ await rename4(candidate, path);
2352
2568
  break;
2353
2569
  } catch (error2) {
2354
2570
  if (!["EEXIST", "ENOTEMPTY"].includes(code(error2) ?? "")) throw error2;
@@ -2363,10 +2579,10 @@ ${options.devAgentId}`).digest("hex");
2363
2579
  }
2364
2580
  if (names.length === 0) continue;
2365
2581
  if (names.length !== 1 || !/^owner-[a-f0-9-]+\.json$/u.test(names[0])) throw alreadyRunningError();
2366
- const previousPath = join6(path, names[0]);
2582
+ const previousPath = join8(path, names[0]);
2367
2583
  let previous;
2368
2584
  try {
2369
- previous = JSON.parse(await readFile6(previousPath, "utf8"));
2585
+ previous = JSON.parse(await readFile8(previousPath, "utf8"));
2370
2586
  } catch (error2) {
2371
2587
  if (code(error2) === "ENOENT") continue;
2372
2588
  throw alreadyRunningError();
@@ -2383,17 +2599,17 @@ ${options.devAgentId}`).digest("hex");
2383
2599
  });
2384
2600
  }
2385
2601
  } finally {
2386
- await unlink4(join6(candidate, ownerName)).catch(() => void 0);
2602
+ await unlink4(join8(candidate, ownerName)).catch(() => void 0);
2387
2603
  await rmdir2(candidate).catch(() => void 0);
2388
2604
  }
2389
2605
  let released = false;
2390
2606
  return {
2391
2607
  async attachRuntime(pid) {
2392
2608
  if (!validPid(pid)) throw new TypeError("Runtime PID is invalid");
2393
- const temporary = join6(root, `.update-${randomUUID3()}`);
2609
+ const temporary = join8(root, `.update-${randomUUID3()}`);
2394
2610
  try {
2395
- await writeFile3(temporary, JSON.stringify({ ...owner, runtimePid: pid }), { mode: 384, flag: "wx" });
2396
- await rename3(temporary, join6(path, ownerName));
2611
+ await writeFile5(temporary, JSON.stringify({ ...owner, runtimePid: pid }), { mode: 384, flag: "wx" });
2612
+ await rename4(temporary, join8(path, ownerName));
2397
2613
  } finally {
2398
2614
  await unlink4(temporary).catch(() => void 0);
2399
2615
  }
@@ -2401,7 +2617,7 @@ ${options.devAgentId}`).digest("hex");
2401
2617
  async release() {
2402
2618
  if (released) return;
2403
2619
  released = true;
2404
- await unlink4(join6(path, ownerName)).catch((error2) => {
2620
+ await unlink4(join8(path, ownerName)).catch((error2) => {
2405
2621
  if (code(error2) !== "ENOENT") throw error2;
2406
2622
  });
2407
2623
  await rmdir2(path).catch((error2) => {
@@ -2454,6 +2670,7 @@ function validateLaunchPlan(value) {
2454
2670
  async function launchPlanFor(config, options, projectRoot, signal) {
2455
2671
  const provider = options.platformLaunchPlan ?? ((context) => officialAgentLaunchPlan({
2456
2672
  datasets: config.datasets,
2673
+ model: config.model,
2457
2674
  projectRoot: context.projectRoot
2458
2675
  }));
2459
2676
  try {
@@ -2644,7 +2861,7 @@ async function startBuddyDev(options) {
2644
2861
  const pollIntervalMs = positiveDuration(options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS, "pollIntervalMs");
2645
2862
  const stopGracePeriodMs = positiveDuration(options.stopGracePeriodMs ?? DEFAULT_STOP_GRACE_PERIOD_MS, "stopGracePeriodMs");
2646
2863
  const devAgentId = safeDevAgentId(options.devAgentId);
2647
- const projectRoot = resolve9(options.projectRoot);
2864
+ const projectRoot = resolve10(options.projectRoot);
2648
2865
  const lifecycle = new AbortController();
2649
2866
  const signal = options.signal === void 0 ? lifecycle.signal : AbortSignal.any([lifecycle.signal, options.signal]);
2650
2867
  let agentProcess;
@@ -2662,7 +2879,7 @@ async function startBuddyDev(options) {
2662
2879
  let config;
2663
2880
  let configSource;
2664
2881
  try {
2665
- configSource = await readFile7(join7(projectRoot, BUDDY_AGENT_FILENAME), "utf8");
2882
+ configSource = await readFile9(join9(projectRoot, BUDDY_AGENT_FILENAME), "utf8");
2666
2883
  config = combineBuddyProject(parseBuddyAgentConfig(configSource));
2667
2884
  } catch (cause) {
2668
2885
  throw new BuddyDevError({
@@ -2766,7 +2983,7 @@ async function startBuddyDev(options) {
2766
2983
  }
2767
2984
 
2768
2985
  // packages/cli-core/src/dev/starter.ts
2769
- import { resolve as resolve10 } from "node:path";
2986
+ import { resolve as resolve11 } from "node:path";
2770
2987
  function createBuddyDevStarter(options = {}) {
2771
2988
  const readManifest = options.readManifest ?? (async (projectRoot) => {
2772
2989
  const manifest = await readBuddyProjectManifest(projectRoot);
@@ -2775,7 +2992,7 @@ function createBuddyDevStarter(options = {}) {
2775
2992
  const startDev = options.startDev ?? startBuddyDev;
2776
2993
  return Object.freeze({
2777
2994
  async start(input) {
2778
- const projectRoot = resolve10(input.projectRoot);
2995
+ const projectRoot = resolve11(input.projectRoot);
2779
2996
  const manifest = await readManifest(projectRoot);
2780
2997
  return startDev({
2781
2998
  ...input,
@@ -2866,7 +3083,7 @@ async function runDevCommand(args, io, options = {}) {
2866
3083
  return { exitCode: 0 };
2867
3084
  }
2868
3085
  try {
2869
- const requestedRoot = resolve11(options.cwd ?? process.cwd(), parsed.directory);
3086
+ const requestedRoot = resolve12(options.cwd ?? process.cwd(), parsed.directory);
2870
3087
  const root = await (options.resolveProjectRoot ?? requireBuddyAgentProjectRoot)(requestedRoot);
2871
3088
  const environment = options.env ?? process.env;
2872
3089
  const url = appServerUrl(parsed.appServer, environment);
@@ -2919,7 +3136,7 @@ async function runDevCommand(args, io, options = {}) {
2919
3136
  }
2920
3137
 
2921
3138
  // packages/cli-core/src/commands/cloud.ts
2922
- import { resolve as resolve12 } from "node:path";
3139
+ import { resolve as resolve13 } from "node:path";
2923
3140
 
2924
3141
  // packages/cli-core/src/cloud/avatar.ts
2925
3142
  import { open as open3 } from "node:fs/promises";
@@ -3448,10 +3665,10 @@ function browserCommand(url) {
3448
3665
  }
3449
3666
  async function openExternalUrl(url) {
3450
3667
  const launch = browserCommand(url);
3451
- await new Promise((resolve16, reject) => {
3668
+ await new Promise((resolve17, reject) => {
3452
3669
  const child = spawn(launch.command, launch.args, { shell: false, stdio: "ignore", windowsHide: true });
3453
3670
  child.once("error", reject);
3454
- child.once("exit", (code2) => code2 === 0 ? resolve16() : reject(new Error(`browser launcher exited with ${code2 ?? "unknown"}`)));
3671
+ child.once("exit", (code2) => code2 === 0 ? resolve17() : reject(new Error(`browser launcher exited with ${code2 ?? "unknown"}`)));
3455
3672
  });
3456
3673
  }
3457
3674
  async function write(res, status, title, message, webUrl, tone = "error") {
@@ -3463,10 +3680,10 @@ async function write(res, status, title, message, webUrl, tone = "error") {
3463
3680
  "referrer-policy": "no-referrer",
3464
3681
  "x-content-type-options": "nosniff"
3465
3682
  });
3466
- await new Promise((resolve16, reject) => {
3683
+ await new Promise((resolve17, reject) => {
3467
3684
  res.once("error", reject);
3468
- res.once("close", resolve16);
3469
- res.end(renderLoginResult(title, message, webUrl, tone), resolve16);
3685
+ res.once("close", resolve17);
3686
+ res.end(renderLoginResult(title, message, webUrl, tone), resolve17);
3470
3687
  });
3471
3688
  }
3472
3689
  async function readJson(response) {
@@ -3501,11 +3718,11 @@ var LoopbackBrowserLoginAdapter = class {
3501
3718
  let settle;
3502
3719
  let reject;
3503
3720
  let settled = false;
3504
- const result = new Promise((resolve16, rejectResult) => {
3721
+ const result = new Promise((resolve17, rejectResult) => {
3505
3722
  settle = (value) => {
3506
3723
  if (!settled) {
3507
3724
  settled = true;
3508
- resolve16(value);
3725
+ resolve17(value);
3509
3726
  }
3510
3727
  };
3511
3728
  reject = (reason) => {
@@ -3524,9 +3741,9 @@ var LoopbackBrowserLoginAdapter = class {
3524
3741
  state: request.state
3525
3742
  }).then(settle, reject);
3526
3743
  });
3527
- await new Promise((resolve16, rejectListen) => {
3744
+ await new Promise((resolve17, rejectListen) => {
3528
3745
  server.once("error", rejectListen);
3529
- server.listen(0, "127.0.0.1", () => resolve16());
3746
+ server.listen(0, "127.0.0.1", () => resolve17());
3530
3747
  });
3531
3748
  const address = server.address();
3532
3749
  if (!address || typeof address === "string") {
@@ -3559,8 +3776,8 @@ var LoopbackBrowserLoginAdapter = class {
3559
3776
  } finally {
3560
3777
  clearTimeout(timer);
3561
3778
  request.signal?.removeEventListener("abort", abort);
3562
- await new Promise((resolve16) => {
3563
- server.close(() => resolve16());
3779
+ await new Promise((resolve17) => {
3780
+ server.close(() => resolve17());
3564
3781
  server.closeIdleConnections();
3565
3782
  server.closeAllConnections();
3566
3783
  });
@@ -3675,7 +3892,7 @@ function parse(source) {
3675
3892
  });
3676
3893
  }
3677
3894
  async function runCredentialCommand(input) {
3678
- return await new Promise((resolve16, reject) => {
3895
+ return await new Promise((resolve17, reject) => {
3679
3896
  const child = spawn2(input.command, [...input.args], {
3680
3897
  shell: false,
3681
3898
  windowsHide: true,
@@ -3691,7 +3908,7 @@ async function runCredentialCommand(input) {
3691
3908
  child.stdout.on("data", (chunk) => collect(stdout, chunk));
3692
3909
  child.stderr.on("data", (chunk) => collect(stderr, chunk));
3693
3910
  child.once("error", reject);
3694
- child.once("close", (code2) => resolve16({
3911
+ child.once("close", (code2) => resolve17({
3695
3912
  code: code2 ?? 1,
3696
3913
  stdout: Buffer.concat(stdout).toString("utf8"),
3697
3914
  stderr: Buffer.concat(stderr).toString("utf8")
@@ -3923,7 +4140,7 @@ function dependencies(options) {
3923
4140
  return { session: options.session, client: options.client };
3924
4141
  }
3925
4142
  function requestedDirectory(options, parsed) {
3926
- return resolve12(options.cwd ?? process.cwd(), parsed.values.get("--directory") ?? ".");
4143
+ return resolve13(options.cwd ?? process.cwd(), parsed.values.get("--directory") ?? ".");
3927
4144
  }
3928
4145
  function auditLabel(status) {
3929
4146
  if (status === "auditing") return "\u5BA1\u6838\u4E2D";
@@ -4007,7 +4224,7 @@ async function runAvatar(parsed, io, options) {
4007
4224
  const file2 = parsed.values.get("--file");
4008
4225
  let upload;
4009
4226
  try {
4010
- upload = file2 ? await readBuddyAvatarFile(resolve12(options.cwd ?? process.cwd(), file2)) : void 0;
4227
+ upload = file2 ? await readBuddyAvatarFile(resolve13(options.cwd ?? process.cwd(), file2)) : void 0;
4011
4228
  } catch (error2) {
4012
4229
  throw new CloudCommandUsageError(error2 instanceof Error ? error2.message : "\u65E0\u6CD5\u8BFB\u53D6\u5934\u50CF\u56FE\u7247");
4013
4230
  }
@@ -4076,8 +4293,8 @@ async function runCloudCommand(command, args, io, options = {}) {
4076
4293
  var CLOUD_COMMAND_HELP = HELP;
4077
4294
 
4078
4295
  // packages/cli-core/src/migration/index.ts
4079
- import { lstat as lstat7, open as open4, readdir as readdir4, realpath as realpath4, stat } from "node:fs/promises";
4080
- import { extname, isAbsolute as isAbsolute2, join as join8, relative, resolve as resolve13, sep, win32 as win322 } from "node:path";
4296
+ import { lstat as lstat8, open as open4, readdir as readdir4, realpath as realpath4, stat } from "node:fs/promises";
4297
+ import { extname, isAbsolute as isAbsolute2, join as join10, relative, resolve as resolve14, sep, win32 as win322 } from "node:path";
4081
4298
  var DEFAULT_SKILL_SCAN_LIMITS = Object.freeze({
4082
4299
  maxFiles: 128,
4083
4300
  maxFileBytes: 256 * 1024,
@@ -4230,7 +4447,7 @@ async function existingProjectRoot(value) {
4230
4447
  return rejectScan("SKILL_PROJECT_ROOT_INVALID", ".", "projectRoot \u5FC5\u987B\u6307\u5411\u4E00\u4E2A\u5DF2\u6709\u9879\u76EE\u76EE\u5F55\u3002");
4231
4448
  }
4232
4449
  try {
4233
- const root = await realpath4(resolve13(value));
4450
+ const root = await realpath4(resolve14(value));
4234
4451
  if (!(await stat(root)).isDirectory()) {
4235
4452
  return rejectScan("SKILL_PROJECT_ROOT_INVALID", ".", "projectRoot \u5FC5\u987B\u6307\u5411\u4E00\u4E2A\u5DF2\u6709\u9879\u76EE\u76EE\u5F55\u3002");
4236
4453
  }
@@ -4246,9 +4463,9 @@ async function existingProjectRoot(value) {
4246
4463
  }
4247
4464
  }
4248
4465
  async function existingSkillRoot(projectRoot, skillPath) {
4249
- const candidate = skillPath === "." ? projectRoot : join8(projectRoot, ...skillPath.split("/"));
4466
+ const candidate = skillPath === "." ? projectRoot : join10(projectRoot, ...skillPath.split("/"));
4250
4467
  try {
4251
- await lstat7(candidate);
4468
+ await lstat8(candidate);
4252
4469
  } catch (cause) {
4253
4470
  if (filesystemCode(cause) === "ENOENT") {
4254
4471
  return rejectScan("SKILL_ROOT_NOT_FOUND", skillPath, "\u627E\u4E0D\u5230\u6307\u5B9A\u7684 Skill \u76EE\u5F55\u3002");
@@ -4283,9 +4500,9 @@ async function existingSkillRoot(projectRoot, skillPath) {
4283
4500
  }
4284
4501
  async function assertEntrypoint(context) {
4285
4502
  const entryPath = reportChild(context.skillPath, "SKILL.md");
4286
- const candidate = join8(context.skillRoot, "SKILL.md");
4503
+ const candidate = join10(context.skillRoot, "SKILL.md");
4287
4504
  try {
4288
- await lstat7(candidate);
4505
+ await lstat8(candidate);
4289
4506
  const target = await realpath4(candidate);
4290
4507
  if (!isWithin(context.projectRoot, target) || !isWithin(context.skillRoot, target)) {
4291
4508
  rejectScan(
@@ -4387,7 +4604,7 @@ async function walkDirectory(actualDirectory, reportDirectory, ancestors, contex
4387
4604
  }
4388
4605
  for (const entry of entries) {
4389
4606
  const childReportPath = reportChild(reportDirectory, entry.name);
4390
- const childPath = join8(directory, entry.name);
4607
+ const childPath = join10(directory, entry.name);
4391
4608
  let target;
4392
4609
  try {
4393
4610
  target = await realpath4(childPath);
@@ -4842,8 +5059,8 @@ async function scanExternalSkillPortability(options) {
4842
5059
 
4843
5060
  // packages/cli-core/src/push/preflight.ts
4844
5061
  import { createHash as createHash6 } from "node:crypto";
4845
- import { lstat as lstat8, open as open5, readdir as readdir5, realpath as realpath5 } from "node:fs/promises";
4846
- import { isAbsolute as isAbsolute3, join as join9, relative as relative2, resolve as resolve14, sep as sep2, win32 as win323 } from "node:path";
5062
+ import { lstat as lstat9, open as open5, readdir as readdir5, realpath as realpath5 } from "node:fs/promises";
5063
+ import { isAbsolute as isAbsolute3, join as join11, relative as relative2, resolve as resolve15, sep as sep2, win32 as win323 } from "node:path";
4847
5064
 
4848
5065
  // packages/cli-core/src/push/errors.ts
4849
5066
  var PushPreflightError = class extends Error {
@@ -5031,10 +5248,10 @@ function normalizeBookletPath(value) {
5031
5248
  return normalized;
5032
5249
  }
5033
5250
  async function canonicalProjectRoot(projectRoot) {
5034
- const absolute = resolve14(projectRoot);
5251
+ const absolute = resolve15(projectRoot);
5035
5252
  let entry;
5036
5253
  try {
5037
- entry = await lstat8(absolute);
5254
+ entry = await lstat9(absolute);
5038
5255
  } catch (cause) {
5039
5256
  error({
5040
5257
  code: "PUSH_PROJECT_INVALID",
@@ -5062,10 +5279,10 @@ async function canonicalProjectRoot(projectRoot) {
5062
5279
  }
5063
5280
  }
5064
5281
  async function captureConfigWithinLimit(projectRoot, maxFileBytes, filename) {
5065
- const path = join9(projectRoot, filename);
5282
+ const path = join11(projectRoot, filename);
5066
5283
  let entry;
5067
5284
  try {
5068
- entry = await lstat8(path);
5285
+ entry = await lstat9(path);
5069
5286
  } catch (cause) {
5070
5287
  error({
5071
5288
  code: "PUSH_CONFIG_INVALID",
@@ -5265,10 +5482,10 @@ async function createManifest(options) {
5265
5482
  sensitiveEntriesExcluded += 1;
5266
5483
  continue;
5267
5484
  }
5268
- const absolutePath = join9(directory, name);
5485
+ const absolutePath = join11(directory, name);
5269
5486
  let entry;
5270
5487
  try {
5271
- entry = await lstat8(absolutePath);
5488
+ entry = await lstat9(absolutePath);
5272
5489
  } catch (cause) {
5273
5490
  error({
5274
5491
  code: "PUSH_FILE_CHANGED",
@@ -5517,8 +5734,8 @@ async function assertCapturedConfigStable(options) {
5517
5734
  }
5518
5735
  let current;
5519
5736
  try {
5520
- const path = join9(options.projectRoot, options.filename);
5521
- const entry = await lstat8(path);
5737
+ const path = join11(options.projectRoot, options.filename);
5738
+ const entry = await lstat9(path);
5522
5739
  if (!entry.isFile() || entry.isSymbolicLink()) {
5523
5740
  error({
5524
5741
  code: "PUSH_FILE_CHANGED",
@@ -5601,14 +5818,15 @@ async function createPushPreflight(options) {
5601
5818
  maxFileBytes: limits.maxFileBytes
5602
5819
  });
5603
5820
  const config = parseCapturedProject(agentEntry);
5604
- if (config.datasets?.length) {
5821
+ if (config.datasets?.length || config.model !== void 0) {
5605
5822
  try {
5606
- await validateRuntimeDatasets(projectRoot, config.datasets);
5823
+ if (config.datasets?.length) await validateRuntimeDatasets(projectRoot, config.datasets);
5824
+ await validateRuntimeModel(projectRoot, config.model);
5607
5825
  } catch (cause) {
5608
5826
  error({
5609
5827
  code: "PUSH_CONFIG_INVALID",
5610
5828
  path: BUDDY_AGENT_FILENAME,
5611
- message: `\u65E0\u6CD5\u6309\u5DE5\u7A0B Runtime \u6821\u9A8C\u6570\u636E\u58F0\u660E\uFF1A${cause instanceof Error ? cause.message : String(cause)}`,
5829
+ message: `\u65E0\u6CD5\u6309\u5DE5\u7A0B Runtime \u6821\u9A8C\u6A21\u578B\u6216\u6570\u636E\u58F0\u660E\uFF1A${cause instanceof Error ? cause.message : String(cause)}`,
5612
5830
  cause
5613
5831
  });
5614
5832
  }
@@ -5653,8 +5871,8 @@ async function createPushPreflight(options) {
5653
5871
 
5654
5872
  // packages/cli-core/src/push/bundle.ts
5655
5873
  import { createHash as createHash7 } from "node:crypto";
5656
- import { lstat as lstat9, readFile as readFile8, realpath as realpath6 } from "node:fs/promises";
5657
- import { join as join10, relative as relative3, sep as sep3, win32 as win324 } from "node:path";
5874
+ import { lstat as lstat10, readFile as readFile10, realpath as realpath6 } from "node:fs/promises";
5875
+ import { join as join12, relative as relative3, sep as sep3, win32 as win324 } from "node:path";
5658
5876
  import { Writable } from "node:stream";
5659
5877
  import { pipeline } from "node:stream/promises";
5660
5878
  import { createGzip } from "node:zlib";
@@ -5676,15 +5894,15 @@ function inside(root, target) {
5676
5894
  return path === "" || path !== ".." && !path.startsWith(`..${sep3}`) && !path.startsWith("/") && !win324.isAbsolute(path);
5677
5895
  }
5678
5896
  async function capture(root, file2) {
5679
- const absolute = join10(root, ...file2.path.split("/"));
5897
+ const absolute = join12(root, ...file2.path.split("/"));
5680
5898
  try {
5681
- const entry = await lstat9(absolute);
5899
+ const entry = await lstat10(absolute);
5682
5900
  if (!entry.isFile() || entry.isSymbolicLink() || entry.size !== file2.bytes) {
5683
5901
  changed(file2.path, `\u63D0\u4EA4\u524D\u6587\u4EF6\u53D1\u751F\u53D8\u5316\uFF1A${file2.path}`);
5684
5902
  }
5685
5903
  const canonical = await realpath6(absolute);
5686
5904
  if (!inside(root, canonical)) changed(file2.path, `\u63D0\u4EA4\u6587\u4EF6\u8D8A\u8FC7\u9879\u76EE\u6839\u76EE\u5F55\uFF1A${file2.path}`);
5687
- const contents = await readFile8(absolute);
5905
+ const contents = await readFile10(absolute);
5688
5906
  if (contents.byteLength !== file2.bytes || digest(contents) !== file2.digest) {
5689
5907
  changed(file2.path, `\u63D0\u4EA4\u524D\u6587\u4EF6\u5185\u5BB9\u53D1\u751F\u53D8\u5316\uFF1A${file2.path}`);
5690
5908
  }
@@ -5773,7 +5991,7 @@ var HELP2 = `\u642D\u642D Developer Platform CLI
5773
5991
  buddy-cli dev [--app-server <URL>] [--directory <\u9879\u76EE\u76EE\u5F55>]
5774
5992
  buddy-cli login | logout | push | status
5775
5993
  buddy-cli avatar (--file <\u56FE\u7247\u6587\u4EF6> | --clear) [--directory <\u9879\u76EE\u76EE\u5F55> | --buddy-id <\u642D\u5B50 ID>]
5776
- buddy-cli models [--json]
5994
+ buddy-cli models [--directory <\u9879\u76EE\u76EE\u5F55>] [--json]
5777
5995
  buddy-cli widgets sync | check | verify
5778
5996
  buddy-cli datasets [--directory <\u9879\u76EE\u76EE\u5F55>] [--json]
5779
5997
  buddy-cli preview [--app-server <URL>] [--directory <\u9879\u76EE\u76EE\u5F55>]
@@ -5786,8 +6004,8 @@ var HELP2 = `\u642D\u642D Developer Platform CLI
5786
6004
  dev \u542F\u52A8\u5B98\u65B9 Runtime \u5E76\u8FDE\u63A5 DEV App Server
5787
6005
  login \u901A\u8FC7\u6D4F\u89C8\u5668\u767B\u5F55\u642D\u642D\u8D26\u53F7
5788
6006
  logout \u9000\u51FA\u642D\u642D\u5F00\u53D1\u8005\u8D26\u53F7\u5E76\u6E05\u9664\u672C\u673A\u767B\u5F55\u72B6\u6001
5789
- models \u67E5\u770B CLI \u5185\u7F6E\u6A21\u578B ID\uFF08\u65E0\u9700\u767B\u5F55\u3001\u8054\u7F51\u6216 Agent \u5DE5\u7A0B\uFF09
5790
- datasets \u8BFB\u53D6\u5DE5\u7A0B Runtime \u63D0\u4F9B\u7684\u6570\u636E\u96C6\u76EE\u5F55\uFF08\u65E0\u9700\u767B\u5F55\uFF09
6007
+ models \u67E5\u770B Runtime \u6A21\u578B ID\uFF08\u5DE5\u7A0B\u5916\u8054\u7F51\u8BFB\u53D6\u6700\u65B0\u7248\uFF0C\u65E0\u9700\u767B\u5F55\uFF09
6008
+ datasets \u67E5\u770B Runtime \u6570\u636E\u96C6\u76EE\u5F55\uFF08\u5DE5\u7A0B\u5916\u8054\u7F51\u8BFB\u53D6\u6700\u65B0\u7248\uFF0C\u65E0\u9700\u767B\u5F55\uFF09
5791
6009
  push \u4E0A\u4F20 Agent \u5DE5\u7A0B\u548C commit\uFF0C\u63D0\u4EA4\u5E73\u53F0\u5BA1\u6838
5792
6010
  status \u67E5\u8BE2\u642D\u5B50\u7684\u8D44\u6599\u3001\u4EE3\u7801\u3001\u8FD0\u884C\u4E0E\u53D1\u5E03\u72B6\u6001
5793
6011
  avatar \u8BBE\u7F6E\u6216\u6E05\u9664\u642D\u5B50\u5934\u50CF\uFF0C\u4FDD\u7559\u5176\u4ED6\u4E91\u7AEF\u8D44\u6599
@@ -5996,7 +6214,7 @@ function defaultProjectDirectory(name) {
5996
6214
  return `./${folder}`;
5997
6215
  }
5998
6216
  async function initializeProjectRoute(route, args, io, options, application) {
5999
- const cwd = resolve15(options.cwd ?? process.cwd());
6217
+ const cwd = resolve16(options.cwd ?? process.cwd());
6000
6218
  const { name, tagline, intro } = application;
6001
6219
  const directoryInput = await textAnswer(
6002
6220
  io,
@@ -6005,7 +6223,7 @@ async function initializeProjectRoute(route, args, io, options, application) {
6005
6223
  "\u9879\u76EE\u76EE\u5F55\uFF08\u7A7A\u76EE\u5F55\u6216\u5DF2\u6709\u642D\u642D\u5DE5\u7A0B\uFF09",
6006
6224
  defaultProjectDirectory(name)
6007
6225
  );
6008
- const rootDirectory = resolve15(cwd, directoryInput);
6226
+ const rootDirectory = resolve16(cwd, directoryInput);
6009
6227
  await assertInitializableBuddyTarget(rootDirectory);
6010
6228
  const initializationTarget = { directory: rootDirectory, kind: "new" };
6011
6229
  const initializationPlan = options.initializeProject ? void 0 : await planBuddyProjectInitialization(initializationTarget);
@@ -6049,7 +6267,7 @@ async function initializeProjectRoute(route, args, io, options, application) {
6049
6267
  }
6050
6268
  async function runRoute(route, args, io, options) {
6051
6269
  if (!io.canPrompt) assertNonInteractiveProjectArguments(route, args);
6052
- const cwd = resolve15(options.cwd ?? process.cwd());
6270
+ const cwd = resolve16(options.cwd ?? process.cwd());
6053
6271
  const name = await textAnswer(io, args.name, "--name", "\u642D\u5B50\u540D\u79F0", void 0, BUDDY_PROFILE_TEXT_LIMITS.name);
6054
6272
  const tagline = await textAnswer(
6055
6273
  io,
@@ -6077,7 +6295,7 @@ async function runRoute(route, args, io, options) {
6077
6295
  "\u9879\u76EE\u76EE\u5F55",
6078
6296
  defaultProjectDirectory(name)
6079
6297
  );
6080
- const rootDirectory = resolve15(cwd, directoryInput);
6298
+ const rootDirectory = resolve16(cwd, directoryInput);
6081
6299
  await assertInitializableBuddyTarget(rootDirectory);
6082
6300
  const plan = await planBuddyDraftInitialization(rootDirectory);
6083
6301
  const existingBuddyId = plan.existingManifest?.buddyId;
@@ -6111,11 +6329,11 @@ async function runRoute(route, args, io, options) {
6111
6329
  return { ...result, route: "create", draft, buddyId };
6112
6330
  }
6113
6331
  async function resumeProjectArguments(args, cwd, options) {
6114
- const root = resolve15(cwd, args.directory?.trim() || ".");
6332
+ const root = resolve16(cwd, args.directory?.trim() || ".");
6115
6333
  await assertInitializableBuddyTarget(root);
6116
6334
  let entry;
6117
6335
  try {
6118
- entry = await lstat10(join11(root, "buddy.agent.json"));
6336
+ entry = await lstat11(join13(root, "buddy.agent.json"));
6119
6337
  } catch (cause) {
6120
6338
  if (cause.code === "ENOENT") return;
6121
6339
  throw cause;
@@ -6144,7 +6362,7 @@ async function runBuddyCli(args, io, options = {}) {
6144
6362
  try {
6145
6363
  const [command, ...rest] = args;
6146
6364
  if (!command) {
6147
- const cwd = resolve15(options.cwd ?? process.cwd());
6365
+ const cwd = resolve16(options.cwd ?? process.cwd());
6148
6366
  let projectRoot;
6149
6367
  try {
6150
6368
  projectRoot = await findBuddyProjectRoot(cwd);
@@ -6172,13 +6390,13 @@ async function runBuddyCli(args, io, options = {}) {
6172
6390
  io.write(HELP2);
6173
6391
  return { exitCode: 0 };
6174
6392
  }
6175
- if (command === "models") return runModelsCommand(rest, io);
6393
+ if (command === "models") return await runModelsCommand(rest, io, options.cwd ?? process.cwd(), options.runtimeCatalog);
6176
6394
  if (command === "widgets") return await runWidgetsCommand(rest, io, options.cwd ?? process.cwd());
6177
6395
  if (command === "preview") {
6178
6396
  return options.preview?.(rest, io) ?? failure("preview \u5BBF\u4E3B\u672A\u914D\u7F6E", io, true);
6179
6397
  }
6180
6398
  if (command === "datasets") {
6181
- return await runDatasetsCommand(rest, io, options.cwd ?? process.cwd());
6399
+ return await runDatasetsCommand(rest, io, options.cwd ?? process.cwd(), options.runtimeCatalog);
6182
6400
  }
6183
6401
  if (command === "dev") {
6184
6402
  return await runDevCommand(rest, io, {
@@ -6200,11 +6418,11 @@ async function runBuddyCli(args, io, options = {}) {
6200
6418
  }
6201
6419
  let route = routeFromMode(parsed.mode);
6202
6420
  if (route === void 0 && !io.canPrompt) requireModeForNonInteractive();
6203
- const cwd = resolve15(options.cwd ?? process.cwd());
6421
+ const cwd = resolve16(options.cwd ?? process.cwd());
6204
6422
  await assertInitializableBuddyTarget(cwd);
6205
6423
  if (parsed.directory !== void 0) {
6206
6424
  if (!parsed.directory.trim()) throw new CliUsageError("--directory \u4E0D\u80FD\u4E3A\u7A7A");
6207
- await assertInitializableBuddyTarget(resolve15(cwd, parsed.directory));
6425
+ await assertInitializableBuddyTarget(resolve16(cwd, parsed.directory));
6208
6426
  }
6209
6427
  await authenticate(options);
6210
6428
  await resumeProjectArguments(parsed, cwd, options);
@@ -6357,6 +6575,7 @@ export {
6357
6575
  isAbortLike,
6358
6576
  isSafeProjectRelativePath,
6359
6577
  isWindowsReservedPathSegment,
6578
+ latestRuntimeTemplate,
6360
6579
  normalizePlatformUrl,
6361
6580
  openExternalUrl,
6362
6581
  parseBuddyAgentConfig,