@my-life-buddies/cli 0.6.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.11.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,13 @@ 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.11.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.11.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
1685
+
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
1470
1687
 
1471
1688
  \u9700\u8981\u7528\u6237\u4ECE\u51E0\u4E2A\u9009\u9879\u4E2D\u9009\u62E9\u65F6\uFF0C\u5728 \`initialState.tools\` \u4E2D\u52A0\u5165 \`conversation.tools.ask_question\` \u5E76\u5728\u4EBA\u8BBE\u4E2D\u8BF4\u660E\u9002\u7528\u573A\u666F\u3002\u53D1\u9898\u5361\u6216\u6388\u6743\u5361\u540E\uFF0C\u672C\u8F6E\u7ED3\u675F\u5E76\u7B49\u5F85\u7528\u6237\uFF1BPreview \u80FD\u663E\u793A\u9009\u9879\u6587\u5B57\u5E76\u53D1\u9001\u7528\u6237\u7684\u6587\u5B57\u56DE\u7B54\uFF0C\u7CFB\u7EDF\u6570\u636E\u6388\u6743\u9700\u8981\u5728 App \u4E2D\u5B8C\u6210\u3002\u6A21\u677F\u7684 \`initialState.tools\` \u9ED8\u8BA4\u4E3A\u7A7A\u6570\u7EC4\uFF0C\u53EA\u52A0\u5165\u4E1A\u52A1\u5B9E\u9645\u9700\u8981\u7684\u5DE5\u5177\uFF1B\u8D44\u6599\u76EE\u5F55\u901A\u8FC7 \`resource_list\` \u53D1\u73B0\uFF0C\u4E0D\u81EA\u52A8\u6CE8\u5165\u7CFB\u7EDF\u63D0\u793A\u3002\u65B0\u4F1A\u8BDD\u7684\u95EE\u5019\u7531\u6A21\u578B\u6309\u4EBA\u8BBE\u751F\u6210\uFF0C\u4E0D\u53E6\u8BBE\u9759\u6001\u6B22\u8FCE\u8BED\u914D\u7F6E\u3002
1472
1689
 
@@ -1542,16 +1759,16 @@ var REQUIRED = [
1542
1759
  var CreatorPreparationError = class extends Error {
1543
1760
  };
1544
1761
  async function state(path) {
1545
- return lstat6(path).catch((cause) => {
1762
+ return lstat7(path).catch((cause) => {
1546
1763
  if (cause.code === "ENOENT") return void 0;
1547
1764
  throw cause;
1548
1765
  });
1549
1766
  }
1550
1767
  async function safeDirectory(path) {
1551
- await mkdir4(path, { mode: 448 }).catch((cause) => {
1768
+ await mkdir5(path, { mode: 448 }).catch((cause) => {
1552
1769
  if (cause.code !== "EEXIST") throw cause;
1553
1770
  });
1554
- if (!(await lstat6(path)).isDirectory()) {
1771
+ if (!(await lstat7(path)).isDirectory()) {
1555
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}`);
1556
1773
  }
1557
1774
  }
@@ -1561,11 +1778,11 @@ async function safeRead(path) {
1561
1778
  if (!entry.isFile() || entry.size > MAX_LOCAL_FILE_BYTES) {
1562
1779
  throw new CreatorPreparationError(`\u521B\u4F5C\u6587\u4EF6\u4E0D\u662F\u666E\u901A\u6587\u4EF6\u6216\u8D85\u51FA\u5927\u5C0F\u9650\u5236\uFF1A${path}`);
1563
1780
  }
1564
- return readFile5(path);
1781
+ return readFile7(path);
1565
1782
  }
1566
1783
  async function writeOnce(path, bytes) {
1567
1784
  const temporary = `${path}.${randomUUID2()}.tmp`;
1568
- await writeFile2(temporary, bytes, { flag: "wx", mode: 384 });
1785
+ await writeFile4(temporary, bytes, { flag: "wx", mode: 384 });
1569
1786
  try {
1570
1787
  await link2(temporary, path).catch((cause) => {
1571
1788
  if (cause.code !== "EEXIST") throw cause;
@@ -1576,17 +1793,17 @@ async function writeOnce(path, bytes) {
1576
1793
  }
1577
1794
  async function bundledSkill(root) {
1578
1795
  for (const path of REQUIRED) {
1579
- if (!(await state(join5(root, path)))?.isFile()) {
1796
+ if (!(await state(join7(root, path)))?.isFile()) {
1580
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`);
1581
1798
  }
1582
1799
  }
1583
1800
  return root;
1584
1801
  }
1585
1802
  function handoffMarkdown(context, skillRoot, session, workspacePath) {
1586
- const contextPath = join5(context.projectRoot, ".buddy", "creator", "initial-context.json");
1803
+ const contextPath = join7(context.projectRoot, ".buddy", "creator", "initial-context.json");
1587
1804
  const openArgs = [
1588
1805
  "-B",
1589
- join5(skillRoot, "scripts/buddy.py"),
1806
+ join7(skillRoot, "scripts/buddy.py"),
1590
1807
  "open",
1591
1808
  "--workspace",
1592
1809
  workspacePath,
@@ -1616,7 +1833,7 @@ function handoffMarkdown(context, skillRoot, session, workspacePath) {
1616
1833
 
1617
1834
  ## \u73B0\u5728\u7531 Coding Agent \u6267\u884C
1618
1835
 
1619
- 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
1620
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
1621
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
1622
1839
 
@@ -1653,11 +1870,11 @@ ${DEVELOPMENT_HANDOFF}
1653
1870
  `;
1654
1871
  }
1655
1872
  async function prepareCreatorSkill(context, io, options = {}) {
1656
- const root = join5(context.projectRoot, ".buddy", "creator");
1873
+ const root = join7(context.projectRoot, ".buddy", "creator");
1657
1874
  try {
1658
- await safeDirectory(join5(context.projectRoot, ".buddy"));
1875
+ await safeDirectory(join7(context.projectRoot, ".buddy"));
1659
1876
  await safeDirectory(root);
1660
- const sessionPath = join5(root, "session.json");
1877
+ const sessionPath = join7(root, "session.json");
1661
1878
  await writeOnce(sessionPath, JSON.stringify({
1662
1879
  schemaVersion: 1,
1663
1880
  platformBuddyId: context.buddyId,
@@ -1669,11 +1886,11 @@ async function prepareCreatorSkill(context, io, options = {}) {
1669
1886
  }
1670
1887
  options.signal?.throwIfAborted();
1671
1888
  const skillRoot = await bundledSkill(options.bundledSkillRoot ?? BUNDLED_CREATOR_SKILL_ROOT);
1672
- await safeDirectory(join5(root, "workspaces"));
1673
- const workspacePath = join5(root, "workspaces", session.creationKey);
1889
+ await safeDirectory(join7(root, "workspaces"));
1890
+ const workspacePath = join7(root, "workspaces", session.creationKey);
1674
1891
  const workspace = await state(workspacePath);
1675
1892
  if (workspace && !workspace.isDirectory()) throw new CreatorPreparationError("\u5DF2\u6709\u521B\u4F5C\u5DE5\u4F5C\u533A\u4E0D\u662F\u666E\u901A\u76EE\u5F55\u3002");
1676
- const contextPath = join5(root, "initial-context.json");
1893
+ const contextPath = join7(root, "initial-context.json");
1677
1894
  await writeOnce(contextPath, JSON.stringify({
1678
1895
  source: "platform_meta",
1679
1896
  name: context.appName,
@@ -1689,7 +1906,7 @@ async function prepareCreatorSkill(context, io, options = {}) {
1689
1906
  } catch {
1690
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}`);
1691
1908
  }
1692
- const handoffPath = join5(root, "HANDOFF.md");
1909
+ const handoffPath = join7(root, "HANDOFF.md");
1693
1910
  const handoff = handoffMarkdown({
1694
1911
  ...context,
1695
1912
  appName: initial.name,
@@ -1700,11 +1917,11 @@ async function prepareCreatorSkill(context, io, options = {}) {
1700
1917
  if ((await safeRead(handoffPath))?.toString("utf8") !== handoff) {
1701
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}`);
1702
1919
  }
1703
- 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")}`);
1704
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`);
1705
1922
  io.write(DEVELOPMENT_HANDOFF_SUMMARY);
1706
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");
1707
- return { exitCode: 0, creator: { skillPath: join5(skillRoot, "SKILL.md"), handoffPath, workspacePath } };
1924
+ return { exitCode: 0, creator: { skillPath: join7(skillRoot, "SKILL.md"), handoffPath, workspacePath } };
1708
1925
  } catch (cause) {
1709
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";
1710
1927
  io.writeError(`Creator Skill \u51C6\u5907\u5931\u8D25\uFF1A${message}`);
@@ -1746,7 +1963,7 @@ function validateBuddyAvatar(value) {
1746
1963
  if (value !== null) {
1747
1964
  let valid = false;
1748
1965
  if (typeof value === "string" && value.length > 0 && value.length <= 2048 && !/[\s\u0000-\u001f]/u.test(value)) {
1749
- valid = /^\/media\/[A-Za-z0-9_.-]+$/u.test(value);
1966
+ valid = /^\/media\/[A-Za-z0-9_.-]+(?:\?v=[a-f0-9]{16})?$/u.test(value);
1750
1967
  if (!valid) {
1751
1968
  try {
1752
1969
  const url = new URL(value);
@@ -1758,9 +1975,13 @@ function validateBuddyAvatar(value) {
1758
1975
  if (!valid) invalidRequest("avatar \u5FC5\u987B\u4E3A\u5408\u6CD5\u56FE\u7247\u5730\u5740\u6216 null");
1759
1976
  }
1760
1977
  }
1978
+ function validateBuddyMetaUpdate(meta2) {
1979
+ if (meta2.avatar !== void 0 && meta2.avatar !== null) invalidRequest("\u5934\u50CF\u5730\u5740\u7531\u5E73\u53F0\u751F\u6210\uFF0C\u8BF7\u4E0A\u4F20\u56FE\u7247\u6587\u4EF6\u6216\u4F20 null \u6E05\u9664");
1980
+ if (Object.keys(meta2).some((key) => key !== "avatar")) validateBuddyMeta(meta2);
1981
+ }
1761
1982
 
1762
1983
  // packages/cli-core/src/commands/dev.ts
1763
- import { resolve as resolve11 } from "node:path";
1984
+ import { resolve as resolve12 } from "node:path";
1764
1985
 
1765
1986
  // packages/cli-core/src/platform-url.ts
1766
1987
  var DEFAULT_MLB_TEST_URL = "http://47.116.168.81:8788";
@@ -2058,15 +2279,15 @@ function buildAgentEnvironment(options) {
2058
2279
 
2059
2280
  // packages/cli-core/src/dev/orchestrator.ts
2060
2281
  import { createHash as createHash3 } from "node:crypto";
2061
- import { readFile as readFile7 } from "node:fs/promises";
2062
- 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";
2063
2284
 
2064
2285
  // packages/cli-core/src/dev/launch.ts
2065
2286
  import { lstatSync, readFileSync } from "node:fs";
2066
2287
  import { createRequire as createRequire2 } from "node:module";
2067
- import { dirname as dirname2, resolve as resolve8 } from "node:path";
2288
+ import { dirname as dirname2, resolve as resolve9 } from "node:path";
2068
2289
  async function officialAgentLaunchPlan(input) {
2069
- const entry = resolve8(input.projectRoot, BUDDY_PLATFORM_START_ENTRY);
2290
+ const entry = resolve9(input.projectRoot, BUDDY_PLATFORM_START_ENTRY);
2070
2291
  for (const [filename, kind] of [
2071
2292
  [dirname2(BUDDY_PLATFORM_FACTORY_ENTRY), "directory"],
2072
2293
  [BUDDY_PLATFORM_START_ENTRY, "file"],
@@ -2074,7 +2295,7 @@ async function officialAgentLaunchPlan(input) {
2074
2295
  [BUDDY_PLATFORM_PACKAGE_JSON, "file"]
2075
2296
  ]) {
2076
2297
  try {
2077
- const entry2 = lstatSync(resolve8(input.projectRoot, filename));
2298
+ const entry2 = lstatSync(resolve9(input.projectRoot, filename));
2078
2299
  if (!(kind === "directory" ? entry2.isDirectory() : entry2.isFile())) {
2079
2300
  throw new Error(`${filename} must be a regular ${kind}`);
2080
2301
  }
@@ -2087,7 +2308,7 @@ async function officialAgentLaunchPlan(input) {
2087
2308
  });
2088
2309
  }
2089
2310
  }
2090
- const packagePath = resolve8(input.projectRoot, BUDDY_PLATFORM_PACKAGE_JSON);
2311
+ const packagePath = resolve9(input.projectRoot, BUDDY_PLATFORM_PACKAGE_JSON);
2091
2312
  try {
2092
2313
  const expected = runtimeDependencyVersion(JSON.parse(readFileSync(packagePath, "utf8")));
2093
2314
  if (!expected) throw new Error(`package.json \u7684 dependencies \u5FC5\u987B\u58F0\u660E ${BUDDY_RUNTIME_PACKAGE} \u7684\u51C6\u786E\u7248\u672C`);
@@ -2095,6 +2316,7 @@ async function officialAgentLaunchPlan(input) {
2095
2316
  const installed = JSON.parse(readFileSync(runtimePath, "utf8")).version;
2096
2317
  if (installed !== expected) throw new Error(`Runtime \u5DF2\u5B89\u88C5 ${installed}\uFF0C\u5DE5\u7A0B\u8981\u6C42 ${expected}`);
2097
2318
  await validateRuntimeDatasets(input.projectRoot, input.datasets);
2319
+ await validateRuntimeModel(input.projectRoot, input.model);
2098
2320
  } catch (cause) {
2099
2321
  throw new BuddyDevError({
2100
2322
  code: "DEV_CONFIG_INVALID",
@@ -2137,16 +2359,16 @@ var NodeAgentProcessLauncher = class {
2137
2359
  }
2138
2360
  let hasExited = false;
2139
2361
  let spawned = false;
2140
- const exit = new Promise((resolve16) => {
2362
+ const exit = new Promise((resolve17) => {
2141
2363
  child.once("error", (error2) => {
2142
2364
  if (!spawned) {
2143
2365
  hasExited = true;
2144
- resolve16({ code: null, signal: null, error: error2 });
2366
+ resolve17({ code: null, signal: null, error: error2 });
2145
2367
  }
2146
2368
  });
2147
2369
  child.once("exit", (code2, signal) => {
2148
2370
  hasExited = true;
2149
- resolve16({ code: code2, signal });
2371
+ resolve17({ code: code2, signal });
2150
2372
  });
2151
2373
  });
2152
2374
  child.stdout?.on("data", (chunk) => {
@@ -2162,11 +2384,11 @@ var NodeAgentProcessLauncher = class {
2162
2384
  }
2163
2385
  });
2164
2386
  try {
2165
- await new Promise((resolve16, reject) => {
2387
+ await new Promise((resolve17, reject) => {
2166
2388
  const onSpawn = () => {
2167
2389
  spawned = true;
2168
2390
  child.off("error", onError);
2169
- resolve16();
2391
+ resolve17();
2170
2392
  };
2171
2393
  const onError = (error2) => {
2172
2394
  child.off("spawn", onSpawn);
@@ -2205,11 +2427,11 @@ var NodeAgentProcessLauncher = class {
2205
2427
  };
2206
2428
  function waitForExit(process2, timeoutMs) {
2207
2429
  if (process2.hasExited()) return Promise.resolve(true);
2208
- return new Promise((resolve16) => {
2209
- const timeout = setTimeout(() => resolve16(false), timeoutMs);
2430
+ return new Promise((resolve17) => {
2431
+ const timeout = setTimeout(() => resolve17(false), timeoutMs);
2210
2432
  process2.exit.then(() => {
2211
2433
  clearTimeout(timeout);
2212
- resolve16(true);
2434
+ resolve17(true);
2213
2435
  });
2214
2436
  });
2215
2437
  }
@@ -2292,7 +2514,7 @@ async function waitForGroupExit(pid, isGroupAlive, timeoutMs) {
2292
2514
  while (isGroupAlive(pid)) {
2293
2515
  const remaining = deadline - Date.now();
2294
2516
  if (remaining <= 0) return false;
2295
- await new Promise((resolve16) => setTimeout(resolve16, Math.min(25, remaining)));
2517
+ await new Promise((resolve17) => setTimeout(resolve17, Math.min(25, remaining)));
2296
2518
  }
2297
2519
  return true;
2298
2520
  }
@@ -2307,9 +2529,9 @@ function processTreeControllerFor(platform) {
2307
2529
 
2308
2530
  // packages/cli-core/src/dev/instance-lock.ts
2309
2531
  import { createHash as createHash2, randomUUID as randomUUID3 } from "node:crypto";
2310
- 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";
2311
- import { homedir } from "node:os";
2312
- 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";
2313
2535
  function alreadyRunningError() {
2314
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";
2315
2537
  return Object.assign(new BuddyDevError({ code: "DEV_ALREADY_RUNNING", phase: "launch", message }), { publicMessage: message });
@@ -2329,20 +2551,20 @@ function code(error2) {
2329
2551
  return error2?.code;
2330
2552
  }
2331
2553
  async function acquireDevInstanceLock(options) {
2332
- const root = options.directory ?? join6(homedir(), ".buddy", "dev-locks");
2554
+ const root = options.directory ?? join8(homedir2(), ".buddy", "dev-locks");
2333
2555
  const key = createHash2("sha256").update(`${new URL(options.gatewayUrl).origin}
2334
2556
  ${options.devAgentId}`).digest("hex");
2335
- const path = join6(root, key);
2557
+ const path = join8(root, key);
2336
2558
  const ownerName = `owner-${randomUUID3()}.json`;
2337
- const candidate = join6(root, `.pending-${randomUUID3()}`);
2559
+ const candidate = join8(root, `.pending-${randomUUID3()}`);
2338
2560
  const owner = { pid: process.pid };
2339
- await mkdir5(root, { recursive: true, mode: 448 });
2340
- await mkdir5(candidate, { mode: 448 });
2341
- 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" });
2342
2564
  try {
2343
2565
  for (let attempt = 0; ; attempt++) {
2344
2566
  try {
2345
- await rename3(candidate, path);
2567
+ await rename4(candidate, path);
2346
2568
  break;
2347
2569
  } catch (error2) {
2348
2570
  if (!["EEXIST", "ENOTEMPTY"].includes(code(error2) ?? "")) throw error2;
@@ -2357,10 +2579,10 @@ ${options.devAgentId}`).digest("hex");
2357
2579
  }
2358
2580
  if (names.length === 0) continue;
2359
2581
  if (names.length !== 1 || !/^owner-[a-f0-9-]+\.json$/u.test(names[0])) throw alreadyRunningError();
2360
- const previousPath = join6(path, names[0]);
2582
+ const previousPath = join8(path, names[0]);
2361
2583
  let previous;
2362
2584
  try {
2363
- previous = JSON.parse(await readFile6(previousPath, "utf8"));
2585
+ previous = JSON.parse(await readFile8(previousPath, "utf8"));
2364
2586
  } catch (error2) {
2365
2587
  if (code(error2) === "ENOENT") continue;
2366
2588
  throw alreadyRunningError();
@@ -2377,17 +2599,17 @@ ${options.devAgentId}`).digest("hex");
2377
2599
  });
2378
2600
  }
2379
2601
  } finally {
2380
- await unlink4(join6(candidate, ownerName)).catch(() => void 0);
2602
+ await unlink4(join8(candidate, ownerName)).catch(() => void 0);
2381
2603
  await rmdir2(candidate).catch(() => void 0);
2382
2604
  }
2383
2605
  let released = false;
2384
2606
  return {
2385
2607
  async attachRuntime(pid) {
2386
2608
  if (!validPid(pid)) throw new TypeError("Runtime PID is invalid");
2387
- const temporary = join6(root, `.update-${randomUUID3()}`);
2609
+ const temporary = join8(root, `.update-${randomUUID3()}`);
2388
2610
  try {
2389
- await writeFile3(temporary, JSON.stringify({ ...owner, runtimePid: pid }), { mode: 384, flag: "wx" });
2390
- 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));
2391
2613
  } finally {
2392
2614
  await unlink4(temporary).catch(() => void 0);
2393
2615
  }
@@ -2395,7 +2617,7 @@ ${options.devAgentId}`).digest("hex");
2395
2617
  async release() {
2396
2618
  if (released) return;
2397
2619
  released = true;
2398
- await unlink4(join6(path, ownerName)).catch((error2) => {
2620
+ await unlink4(join8(path, ownerName)).catch((error2) => {
2399
2621
  if (code(error2) !== "ENOENT") throw error2;
2400
2622
  });
2401
2623
  await rmdir2(path).catch((error2) => {
@@ -2448,6 +2670,7 @@ function validateLaunchPlan(value) {
2448
2670
  async function launchPlanFor(config, options, projectRoot, signal) {
2449
2671
  const provider = options.platformLaunchPlan ?? ((context) => officialAgentLaunchPlan({
2450
2672
  datasets: config.datasets,
2673
+ model: config.model,
2451
2674
  projectRoot: context.projectRoot
2452
2675
  }));
2453
2676
  try {
@@ -2638,7 +2861,7 @@ async function startBuddyDev(options) {
2638
2861
  const pollIntervalMs = positiveDuration(options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS, "pollIntervalMs");
2639
2862
  const stopGracePeriodMs = positiveDuration(options.stopGracePeriodMs ?? DEFAULT_STOP_GRACE_PERIOD_MS, "stopGracePeriodMs");
2640
2863
  const devAgentId = safeDevAgentId(options.devAgentId);
2641
- const projectRoot = resolve9(options.projectRoot);
2864
+ const projectRoot = resolve10(options.projectRoot);
2642
2865
  const lifecycle = new AbortController();
2643
2866
  const signal = options.signal === void 0 ? lifecycle.signal : AbortSignal.any([lifecycle.signal, options.signal]);
2644
2867
  let agentProcess;
@@ -2656,7 +2879,7 @@ async function startBuddyDev(options) {
2656
2879
  let config;
2657
2880
  let configSource;
2658
2881
  try {
2659
- configSource = await readFile7(join7(projectRoot, BUDDY_AGENT_FILENAME), "utf8");
2882
+ configSource = await readFile9(join9(projectRoot, BUDDY_AGENT_FILENAME), "utf8");
2660
2883
  config = combineBuddyProject(parseBuddyAgentConfig(configSource));
2661
2884
  } catch (cause) {
2662
2885
  throw new BuddyDevError({
@@ -2760,7 +2983,7 @@ async function startBuddyDev(options) {
2760
2983
  }
2761
2984
 
2762
2985
  // packages/cli-core/src/dev/starter.ts
2763
- import { resolve as resolve10 } from "node:path";
2986
+ import { resolve as resolve11 } from "node:path";
2764
2987
  function createBuddyDevStarter(options = {}) {
2765
2988
  const readManifest = options.readManifest ?? (async (projectRoot) => {
2766
2989
  const manifest = await readBuddyProjectManifest(projectRoot);
@@ -2769,7 +2992,7 @@ function createBuddyDevStarter(options = {}) {
2769
2992
  const startDev = options.startDev ?? startBuddyDev;
2770
2993
  return Object.freeze({
2771
2994
  async start(input) {
2772
- const projectRoot = resolve10(input.projectRoot);
2995
+ const projectRoot = resolve11(input.projectRoot);
2773
2996
  const manifest = await readManifest(projectRoot);
2774
2997
  return startDev({
2775
2998
  ...input,
@@ -2860,7 +3083,7 @@ async function runDevCommand(args, io, options = {}) {
2860
3083
  return { exitCode: 0 };
2861
3084
  }
2862
3085
  try {
2863
- const requestedRoot = resolve11(options.cwd ?? process.cwd(), parsed.directory);
3086
+ const requestedRoot = resolve12(options.cwd ?? process.cwd(), parsed.directory);
2864
3087
  const root = await (options.resolveProjectRoot ?? requireBuddyAgentProjectRoot)(requestedRoot);
2865
3088
  const environment = options.env ?? process.env;
2866
3089
  const url = appServerUrl(parsed.appServer, environment);
@@ -2913,7 +3136,34 @@ async function runDevCommand(args, io, options = {}) {
2913
3136
  }
2914
3137
 
2915
3138
  // packages/cli-core/src/commands/cloud.ts
2916
- import { resolve as resolve12 } from "node:path";
3139
+ import { resolve as resolve13 } from "node:path";
3140
+
3141
+ // packages/cli-core/src/cloud/avatar.ts
3142
+ import { open as open3 } from "node:fs/promises";
3143
+ import { basename } from "node:path";
3144
+ var MAX_BUDDY_AVATAR_BYTES = 5 * 1024 * 1024;
3145
+ async function readBuddyAvatarFile(path) {
3146
+ const file2 = await open3(path, "r");
3147
+ try {
3148
+ const stat2 = await file2.stat();
3149
+ if (!stat2.isFile()) throw new Error("\u5934\u50CF\u5FC5\u987B\u662F\u666E\u901A\u56FE\u7247\u6587\u4EF6");
3150
+ if (!stat2.size || stat2.size > MAX_BUDDY_AVATAR_BYTES) throw new Error("\u5934\u50CF\u4E0D\u80FD\u4E3A\u7A7A\u4E14\u4E0D\u80FD\u8D85\u8FC7 5 MiB");
3151
+ const buffer = Buffer.alloc(MAX_BUDDY_AVATAR_BYTES + 1);
3152
+ let size = 0;
3153
+ while (size < buffer.length) {
3154
+ const { bytesRead } = await file2.read(buffer, size, buffer.length - size, null);
3155
+ if (!bytesRead) break;
3156
+ size += bytesRead;
3157
+ }
3158
+ if (!size || size > MAX_BUDDY_AVATAR_BYTES) throw new Error("\u5934\u50CF\u4E0D\u80FD\u4E3A\u7A7A\u4E14\u4E0D\u80FD\u8D85\u8FC7 5 MiB");
3159
+ const bytes = buffer.subarray(0, size);
3160
+ const mediaType = bytes.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10])) ? "image/png" : bytes.subarray(0, 3).equals(Buffer.from([255, 216, 255])) ? "image/jpeg" : bytes.toString("ascii", 0, 4) === "RIFF" && bytes.toString("ascii", 8, 12) === "WEBP" ? "image/webp" : void 0;
3161
+ if (!mediaType) throw new Error("\u4EC5\u652F\u6301 PNG\u3001JPEG\u3001WebP \u56FE\u7247\u6587\u4EF6");
3162
+ return { bytes, fileName: basename(path), mediaType };
3163
+ } finally {
3164
+ await file2.close();
3165
+ }
3166
+ }
2917
3167
 
2918
3168
  // packages/cli-core/src/cloud/auth.ts
2919
3169
  import { randomUUID as randomUUID4 } from "node:crypto";
@@ -3253,7 +3503,7 @@ var HttpDeveloperPlatformClient = class {
3253
3503
  "Content-Length": String(binaryBody.byteLength)
3254
3504
  }
3255
3505
  },
3256
- ...options.json !== void 0 ? { body: JSON.stringify(options.json) } : binaryBody === void 0 ? {} : { body: binaryBody },
3506
+ ...options.form !== void 0 ? { body: options.form } : options.json !== void 0 ? { body: JSON.stringify(options.json) } : binaryBody === void 0 ? {} : { body: binaryBody },
3257
3507
  redirect: "error",
3258
3508
  signal: controller.signal
3259
3509
  });
@@ -3280,7 +3530,14 @@ var HttpDeveloperPlatformClient = class {
3280
3530
  return buddy(await this.#request("/cli/buddies", "POST", { json: { meta: request.meta } }), true);
3281
3531
  }
3282
3532
  async updateBuddy(request) {
3283
- validateBuddyMeta(request.meta);
3533
+ validateBuddyMetaUpdate(request.meta);
3534
+ if (request.avatar) {
3535
+ if (request.meta.avatar === null) throw new CloudLifecycleError("INVALID_REQUEST", "\u4E0D\u80FD\u540C\u65F6\u4E0A\u4F20\u548C\u6E05\u9664\u5934\u50CF");
3536
+ const form = new FormData();
3537
+ form.set("meta", JSON.stringify(request.meta));
3538
+ form.set("avatar", new Blob([new Uint8Array(request.avatar.bytes)], { type: request.avatar.mediaType }), request.avatar.fileName);
3539
+ return buddy(await this.#request(`/cli/buddies/${encodeURIComponent(request.id)}/meta`, "PUT", { form }), true);
3540
+ }
3284
3541
  return buddy(await this.#request(`/cli/buddies/${encodeURIComponent(request.id)}/meta`, "PUT", {
3285
3542
  json: request.meta
3286
3543
  }), true);
@@ -3408,10 +3665,10 @@ function browserCommand(url) {
3408
3665
  }
3409
3666
  async function openExternalUrl(url) {
3410
3667
  const launch = browserCommand(url);
3411
- await new Promise((resolve16, reject) => {
3668
+ await new Promise((resolve17, reject) => {
3412
3669
  const child = spawn(launch.command, launch.args, { shell: false, stdio: "ignore", windowsHide: true });
3413
3670
  child.once("error", reject);
3414
- 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"}`)));
3415
3672
  });
3416
3673
  }
3417
3674
  async function write(res, status, title, message, webUrl, tone = "error") {
@@ -3423,10 +3680,10 @@ async function write(res, status, title, message, webUrl, tone = "error") {
3423
3680
  "referrer-policy": "no-referrer",
3424
3681
  "x-content-type-options": "nosniff"
3425
3682
  });
3426
- await new Promise((resolve16, reject) => {
3683
+ await new Promise((resolve17, reject) => {
3427
3684
  res.once("error", reject);
3428
- res.once("close", resolve16);
3429
- res.end(renderLoginResult(title, message, webUrl, tone), resolve16);
3685
+ res.once("close", resolve17);
3686
+ res.end(renderLoginResult(title, message, webUrl, tone), resolve17);
3430
3687
  });
3431
3688
  }
3432
3689
  async function readJson(response) {
@@ -3461,11 +3718,11 @@ var LoopbackBrowserLoginAdapter = class {
3461
3718
  let settle;
3462
3719
  let reject;
3463
3720
  let settled = false;
3464
- const result = new Promise((resolve16, rejectResult) => {
3721
+ const result = new Promise((resolve17, rejectResult) => {
3465
3722
  settle = (value) => {
3466
3723
  if (!settled) {
3467
3724
  settled = true;
3468
- resolve16(value);
3725
+ resolve17(value);
3469
3726
  }
3470
3727
  };
3471
3728
  reject = (reason) => {
@@ -3484,9 +3741,9 @@ var LoopbackBrowserLoginAdapter = class {
3484
3741
  state: request.state
3485
3742
  }).then(settle, reject);
3486
3743
  });
3487
- await new Promise((resolve16, rejectListen) => {
3744
+ await new Promise((resolve17, rejectListen) => {
3488
3745
  server.once("error", rejectListen);
3489
- server.listen(0, "127.0.0.1", () => resolve16());
3746
+ server.listen(0, "127.0.0.1", () => resolve17());
3490
3747
  });
3491
3748
  const address = server.address();
3492
3749
  if (!address || typeof address === "string") {
@@ -3519,8 +3776,8 @@ var LoopbackBrowserLoginAdapter = class {
3519
3776
  } finally {
3520
3777
  clearTimeout(timer);
3521
3778
  request.signal?.removeEventListener("abort", abort);
3522
- await new Promise((resolve16) => {
3523
- server.close(() => resolve16());
3779
+ await new Promise((resolve17) => {
3780
+ server.close(() => resolve17());
3524
3781
  server.closeIdleConnections();
3525
3782
  server.closeAllConnections();
3526
3783
  });
@@ -3635,7 +3892,7 @@ function parse(source) {
3635
3892
  });
3636
3893
  }
3637
3894
  async function runCredentialCommand(input) {
3638
- return await new Promise((resolve16, reject) => {
3895
+ return await new Promise((resolve17, reject) => {
3639
3896
  const child = spawn2(input.command, [...input.args], {
3640
3897
  shell: false,
3641
3898
  windowsHide: true,
@@ -3651,7 +3908,7 @@ async function runCredentialCommand(input) {
3651
3908
  child.stdout.on("data", (chunk) => collect(stdout, chunk));
3652
3909
  child.stderr.on("data", (chunk) => collect(stderr, chunk));
3653
3910
  child.once("error", reject);
3654
- child.once("close", (code2) => resolve16({
3911
+ child.once("close", (code2) => resolve17({
3655
3912
  code: code2 ?? 1,
3656
3913
  stdout: Buffer.concat(stdout).toString("utf8"),
3657
3914
  stderr: Buffer.concat(stderr).toString("utf8")
@@ -3711,7 +3968,7 @@ var SystemCloudTokenStore = class {
3711
3968
  };
3712
3969
 
3713
3970
  // packages/cli-core/src/cloud/mock-client.ts
3714
- import { randomBytes as randomBytes2 } from "node:crypto";
3971
+ import { createHash as createHash5, randomBytes as randomBytes2 } from "node:crypto";
3715
3972
  var MockDeveloperPlatformClient = class {
3716
3973
  #now;
3717
3974
  #buddies = /* @__PURE__ */ new Map();
@@ -3737,7 +3994,10 @@ var MockDeveloperPlatformClient = class {
3737
3994
  }
3738
3995
  async updateBuddy(request) {
3739
3996
  const current = this.#require(request.id);
3740
- const next = this.#value({ ...current, meta: request.meta, updatedAt: this.#now() });
3997
+ validateBuddyMetaUpdate(request.meta);
3998
+ const onlyAvatar = Object.keys(request.meta).every((key) => key === "avatar");
3999
+ const avatar = request.avatar ? `/media/avatar-${request.id}.webp?v=${createHash5("sha256").update(request.avatar.bytes).digest("hex").slice(0, 16)}` : request.meta.avatar === null ? null : current.meta?.avatar ?? null;
4000
+ const next = this.#value({ ...current, meta: { ...onlyAvatar ? current.meta : request.meta, avatar }, updatedAt: this.#now() });
3741
4001
  this.#buddies.set(request.id, next);
3742
4002
  return structuredClone(next);
3743
4003
  }
@@ -3823,9 +4083,9 @@ var HELP = Object.freeze({
3823
4083
  logout: "\u7528\u6CD5: buddy-cli logout",
3824
4084
  push: "\u7528\u6CD5: buddy-cli push [--directory <\u9879\u76EE\u76EE\u5F55>] [--commit <\u672C\u6B21\u6539\u52A8\u8BF4\u660E>]",
3825
4085
  status: "\u7528\u6CD5: buddy-cli status [--directory <\u9879\u76EE\u76EE\u5F55>]",
3826
- avatar: `\u7528\u6CD5: buddy-cli avatar (--url <\u56FE\u7247\u5730\u5740> | --clear) [--directory <\u9879\u76EE\u76EE\u5F55> | --buddy-id <\u642D\u5B50 ID>]
4086
+ avatar: `\u7528\u6CD5: buddy-cli avatar (--file <\u56FE\u7247\u6587\u4EF6> | --clear) [--directory <\u9879\u76EE\u76EE\u5F55> | --buddy-id <\u642D\u5B50 ID>]
3827
4087
  \u4FEE\u6539\u5F53\u524D\u9879\u76EE\u6216\u6307\u5B9A\u642D\u5B50\u7684\u4E91\u7AEF\u5934\u50CF\uFF0C\u4FDD\u7559\u5176\u4ED6\u8D44\u6599\uFF1B\u4E0D\u9700\u8981\u5B89\u88C5 Runtime \u6216\u4E0A\u4F20\u4EE3\u7801\u5305\u3002
3828
- --url \u63A5\u53D7 HTTP(S) \u56FE\u7247 URL \u6216\u5DF2\u6709\u7684 /media/... \u5730\u5740\uFF0C\u4E0D\u63A5\u53D7\u672C\u5730\u6587\u4EF6\u3002
4088
+ --file \u63A5\u53D7\u672C\u5730\u9759\u6001 PNG\u3001JPEG\u3001WebP \u56FE\u7247\uFF0C\u6700\u5927 5 MiB\uFF1BServer \u81EA\u52A8\u5904\u7406\u5E76\u751F\u6210\u5730\u5740\u3002
3829
4089
  \u9700\u8981\u5F53\u524D\u8D26\u53F7\u62E5\u6709\u8BE5\u642D\u5B50\uFF0C\u547D\u4EE4\u6267\u884C\u540E\u7ACB\u5373\u66F4\u65B0\u4E91\u7AEF\u8D44\u6599\u3002`
3830
4090
  });
3831
4091
  function parse2(args, command) {
@@ -3843,7 +4103,7 @@ function parse2(args, command) {
3843
4103
  values.set(flag2, "");
3844
4104
  continue;
3845
4105
  }
3846
- const allowed = command === "push" ? flag2 === "--directory" || flag2 === "--commit" : command === "avatar" ? ["--directory", "--buddy-id", "--url"].includes(flag2) : command === "status" && flag2 === "--directory";
4106
+ const allowed = command === "push" ? flag2 === "--directory" || flag2 === "--commit" : command === "avatar" ? ["--directory", "--buddy-id", "--file"].includes(flag2) : command === "status" && flag2 === "--directory";
3847
4107
  if (!allowed) throw new CloudCommandUsageError(`\u672A\u77E5\u53C2\u6570 ${flag2}`);
3848
4108
  const value = args[index + 1];
3849
4109
  if (value === void 0 || !value.trim() || command === "avatar" && value.startsWith("--")) throw new CloudCommandUsageError(`${flag2} \u7F3A\u5C11\u503C`);
@@ -3880,7 +4140,7 @@ function dependencies(options) {
3880
4140
  return { session: options.session, client: options.client };
3881
4141
  }
3882
4142
  function requestedDirectory(options, parsed) {
3883
- return resolve12(options.cwd ?? process.cwd(), parsed.values.get("--directory") ?? ".");
4143
+ return resolve13(options.cwd ?? process.cwd(), parsed.values.get("--directory") ?? ".");
3884
4144
  }
3885
4145
  function auditLabel(status) {
3886
4146
  if (status === "auditing") return "\u5BA1\u6838\u4E2D";
@@ -3955,17 +4215,18 @@ async function runPush(parsed, io, options) {
3955
4215
  return { exitCode: 0, buddyId: config.buddyId, version: receipt.version };
3956
4216
  }
3957
4217
  async function runAvatar(parsed, io, options) {
3958
- if (parsed.values.has("--url") === parsed.values.has("--clear")) {
3959
- throw new CloudCommandUsageError("\u5FC5\u987B\u9009\u62E9 --url <\u56FE\u7247\u5730\u5740> \u6216 --clear\uFF0C\u4E14\u4E0D\u80FD\u540C\u65F6\u4F7F\u7528");
4218
+ if (parsed.values.has("--file") === parsed.values.has("--clear")) {
4219
+ throw new CloudCommandUsageError("\u5FC5\u987B\u9009\u62E9 --file <\u56FE\u7247\u6587\u4EF6> \u6216 --clear\uFF0C\u4E14\u4E0D\u80FD\u540C\u65F6\u4F7F\u7528");
3960
4220
  }
3961
4221
  if (parsed.values.has("--buddy-id") && parsed.values.has("--directory")) {
3962
4222
  throw new CloudCommandUsageError("--buddy-id \u548C --directory \u4E0D\u80FD\u540C\u65F6\u4F7F\u7528");
3963
4223
  }
3964
- const avatar = parsed.values.get("--url") ?? null;
4224
+ const file2 = parsed.values.get("--file");
4225
+ let upload;
3965
4226
  try {
3966
- validateBuddyAvatar(avatar);
4227
+ upload = file2 ? await readBuddyAvatarFile(resolve13(options.cwd ?? process.cwd(), file2)) : void 0;
3967
4228
  } catch (error2) {
3968
- throw new CloudCommandUsageError(error2 instanceof Error ? error2.message : "\u5934\u50CF\u5730\u5740\u65E0\u6548");
4229
+ throw new CloudCommandUsageError(error2 instanceof Error ? error2.message : "\u65E0\u6CD5\u8BFB\u53D6\u5934\u50CF\u56FE\u7247");
3969
4230
  }
3970
4231
  let id = parsed.values.get("--buddy-id");
3971
4232
  if (id !== void 0 && !/^[A-Za-z0-9_-]{1,128}$/u.test(id)) throw new CloudCommandUsageError("--buddy-id \u5FC5\u987B\u662F\u6709\u6548\u7684\u642D\u5B50 ID");
@@ -3978,12 +4239,13 @@ async function runAvatar(parsed, io, options) {
3978
4239
  await session.token({ signal: options.signal });
3979
4240
  const current = await client.getBuddy({ id });
3980
4241
  if (current.id !== id) throw new CloudLifecycleError("PLATFORM_RESPONSE_INVALID", "\u5E73\u53F0\u8FD4\u56DE\u7684\u642D\u5B50\u8EAB\u4EFD\u4E0D\u5339\u914D");
3981
- const updated = await client.updateBuddy({ id, meta: { ...current.meta, avatar } });
3982
- if (updated.id !== id || updated.meta?.avatar !== avatar) {
4242
+ const updated = await client.updateBuddy({ id, meta: upload ? {} : { avatar: null }, ...upload ? { avatar: upload } : {} });
4243
+ const avatar = updated.meta?.avatar;
4244
+ if (updated.id !== id || (upload ? typeof avatar !== "string" || !avatar : avatar !== null)) {
3983
4245
  throw new CloudLifecycleError("PLATFORM_RESPONSE_INVALID", "\u5E73\u53F0\u672A\u786E\u8BA4\u5934\u50CF\u66F4\u65B0\uFF0C\u8BF7\u67E5\u8BE2\u642D\u5B50\u8D44\u6599\u786E\u8BA4\u7ED3\u679C");
3984
4246
  }
3985
4247
  io.write(`${avatar === null ? "\u5DF2\u6E05\u9664" : "\u5DF2\u66F4\u65B0"}\u642D\u5B50\u5934\u50CF\uFF1A${updated.meta?.name ?? id}\uFF08${id}\uFF09`);
3986
- if (avatar !== null) io.write(`\u5934\u50CF\uFF1A${avatar}`);
4248
+ if (typeof avatar === "string") io.write(`\u5934\u50CF\uFF1A${avatar}`);
3987
4249
  io.write("\u4E91\u7AEF\u8D44\u6599\u5DF2\u66F4\u65B0\uFF0C\u65E0\u9700 push \u6216\u91CD\u65B0\u53D1\u5E03\u7A0B\u5E8F\u5305\u3002");
3988
4250
  return { exitCode: 0, buddyId: id };
3989
4251
  }
@@ -4031,8 +4293,8 @@ async function runCloudCommand(command, args, io, options = {}) {
4031
4293
  var CLOUD_COMMAND_HELP = HELP;
4032
4294
 
4033
4295
  // packages/cli-core/src/migration/index.ts
4034
- import { lstat as lstat7, open as open3, readdir as readdir4, realpath as realpath4, stat } from "node:fs/promises";
4035
- 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";
4036
4298
  var DEFAULT_SKILL_SCAN_LIMITS = Object.freeze({
4037
4299
  maxFiles: 128,
4038
4300
  maxFileBytes: 256 * 1024,
@@ -4185,7 +4447,7 @@ async function existingProjectRoot(value) {
4185
4447
  return rejectScan("SKILL_PROJECT_ROOT_INVALID", ".", "projectRoot \u5FC5\u987B\u6307\u5411\u4E00\u4E2A\u5DF2\u6709\u9879\u76EE\u76EE\u5F55\u3002");
4186
4448
  }
4187
4449
  try {
4188
- const root = await realpath4(resolve13(value));
4450
+ const root = await realpath4(resolve14(value));
4189
4451
  if (!(await stat(root)).isDirectory()) {
4190
4452
  return rejectScan("SKILL_PROJECT_ROOT_INVALID", ".", "projectRoot \u5FC5\u987B\u6307\u5411\u4E00\u4E2A\u5DF2\u6709\u9879\u76EE\u76EE\u5F55\u3002");
4191
4453
  }
@@ -4201,9 +4463,9 @@ async function existingProjectRoot(value) {
4201
4463
  }
4202
4464
  }
4203
4465
  async function existingSkillRoot(projectRoot, skillPath) {
4204
- const candidate = skillPath === "." ? projectRoot : join8(projectRoot, ...skillPath.split("/"));
4466
+ const candidate = skillPath === "." ? projectRoot : join10(projectRoot, ...skillPath.split("/"));
4205
4467
  try {
4206
- await lstat7(candidate);
4468
+ await lstat8(candidate);
4207
4469
  } catch (cause) {
4208
4470
  if (filesystemCode(cause) === "ENOENT") {
4209
4471
  return rejectScan("SKILL_ROOT_NOT_FOUND", skillPath, "\u627E\u4E0D\u5230\u6307\u5B9A\u7684 Skill \u76EE\u5F55\u3002");
@@ -4238,9 +4500,9 @@ async function existingSkillRoot(projectRoot, skillPath) {
4238
4500
  }
4239
4501
  async function assertEntrypoint(context) {
4240
4502
  const entryPath = reportChild(context.skillPath, "SKILL.md");
4241
- const candidate = join8(context.skillRoot, "SKILL.md");
4503
+ const candidate = join10(context.skillRoot, "SKILL.md");
4242
4504
  try {
4243
- await lstat7(candidate);
4505
+ await lstat8(candidate);
4244
4506
  const target = await realpath4(candidate);
4245
4507
  if (!isWithin(context.projectRoot, target) || !isWithin(context.skillRoot, target)) {
4246
4508
  rejectScan(
@@ -4342,7 +4604,7 @@ async function walkDirectory(actualDirectory, reportDirectory, ancestors, contex
4342
4604
  }
4343
4605
  for (const entry of entries) {
4344
4606
  const childReportPath = reportChild(reportDirectory, entry.name);
4345
- const childPath = join8(directory, entry.name);
4607
+ const childPath = join10(directory, entry.name);
4346
4608
  let target;
4347
4609
  try {
4348
4610
  target = await realpath4(childPath);
@@ -4384,7 +4646,7 @@ async function scanFile(actualPath, reportPath, context) {
4384
4646
  }
4385
4647
  let handle;
4386
4648
  try {
4387
- handle = await open3(actualPath, "r");
4649
+ handle = await open4(actualPath, "r");
4388
4650
  } catch (cause) {
4389
4651
  return rejectScan("SKILL_SCAN_IO_ERROR", reportPath, "\u65E0\u6CD5\u6253\u5F00 Skill \u6587\u4EF6\u3002", cause);
4390
4652
  }
@@ -4796,9 +5058,9 @@ async function scanExternalSkillPortability(options) {
4796
5058
  }
4797
5059
 
4798
5060
  // packages/cli-core/src/push/preflight.ts
4799
- import { createHash as createHash5 } from "node:crypto";
4800
- import { lstat as lstat8, open as open4, readdir as readdir5, realpath as realpath5 } from "node:fs/promises";
4801
- import { isAbsolute as isAbsolute3, join as join9, relative as relative2, resolve as resolve14, sep as sep2, win32 as win323 } from "node:path";
5061
+ import { createHash as createHash6 } from "node:crypto";
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";
4802
5064
 
4803
5065
  // packages/cli-core/src/push/errors.ts
4804
5066
  var PushPreflightError = class extends Error {
@@ -4896,7 +5158,7 @@ function error(options) {
4896
5158
  throw new PushPreflightError(options);
4897
5159
  }
4898
5160
  function sha256(value) {
4899
- return `sha256:${createHash5("sha256").update(value).digest("hex")}`;
5161
+ return `sha256:${createHash6("sha256").update(value).digest("hex")}`;
4900
5162
  }
4901
5163
  function positiveLimit(value, name, hardMaximum) {
4902
5164
  if (!Number.isSafeInteger(value) || value < 1 || value > hardMaximum) {
@@ -4986,10 +5248,10 @@ function normalizeBookletPath(value) {
4986
5248
  return normalized;
4987
5249
  }
4988
5250
  async function canonicalProjectRoot(projectRoot) {
4989
- const absolute = resolve14(projectRoot);
5251
+ const absolute = resolve15(projectRoot);
4990
5252
  let entry;
4991
5253
  try {
4992
- entry = await lstat8(absolute);
5254
+ entry = await lstat9(absolute);
4993
5255
  } catch (cause) {
4994
5256
  error({
4995
5257
  code: "PUSH_PROJECT_INVALID",
@@ -5017,10 +5279,10 @@ async function canonicalProjectRoot(projectRoot) {
5017
5279
  }
5018
5280
  }
5019
5281
  async function captureConfigWithinLimit(projectRoot, maxFileBytes, filename) {
5020
- const path = join9(projectRoot, filename);
5282
+ const path = join11(projectRoot, filename);
5021
5283
  let entry;
5022
5284
  try {
5023
- entry = await lstat8(path);
5285
+ entry = await lstat9(path);
5024
5286
  } catch (cause) {
5025
5287
  error({
5026
5288
  code: "PUSH_CONFIG_INVALID",
@@ -5127,7 +5389,7 @@ function sameFileIdentity(left, right) {
5127
5389
  return left.dev === right.dev && left.ino === right.ino && left.size === right.size && left.mtimeMs === right.mtimeMs;
5128
5390
  }
5129
5391
  async function hashRegularFile(options) {
5130
- const handle = await open4(options.absolutePath, "r").catch((cause) => error({
5392
+ const handle = await open5(options.absolutePath, "r").catch((cause) => error({
5131
5393
  code: "PUSH_PROJECT_INVALID",
5132
5394
  path: options.portablePath,
5133
5395
  message: `\u65E0\u6CD5\u8BFB\u53D6\u63D0\u4EA4\u6587\u4EF6\uFF1A${options.portablePath}`,
@@ -5142,7 +5404,7 @@ async function hashRegularFile(options) {
5142
5404
  message: `\u751F\u6210\u6E05\u5355\u65F6\u6587\u4EF6\u53D1\u751F\u53D8\u5316\uFF1A${options.portablePath}`
5143
5405
  });
5144
5406
  }
5145
- const hash = createHash5("sha256");
5407
+ const hash = createHash6("sha256");
5146
5408
  const captured = [];
5147
5409
  const buffer = Buffer.allocUnsafe(READ_BUFFER_BYTES);
5148
5410
  let bytes = 0;
@@ -5220,10 +5482,10 @@ async function createManifest(options) {
5220
5482
  sensitiveEntriesExcluded += 1;
5221
5483
  continue;
5222
5484
  }
5223
- const absolutePath = join9(directory, name);
5485
+ const absolutePath = join11(directory, name);
5224
5486
  let entry;
5225
5487
  try {
5226
- entry = await lstat8(absolutePath);
5488
+ entry = await lstat9(absolutePath);
5227
5489
  } catch (cause) {
5228
5490
  error({
5229
5491
  code: "PUSH_FILE_CHANGED",
@@ -5472,8 +5734,8 @@ async function assertCapturedConfigStable(options) {
5472
5734
  }
5473
5735
  let current;
5474
5736
  try {
5475
- const path = join9(options.projectRoot, options.filename);
5476
- const entry = await lstat8(path);
5737
+ const path = join11(options.projectRoot, options.filename);
5738
+ const entry = await lstat9(path);
5477
5739
  if (!entry.isFile() || entry.isSymbolicLink()) {
5478
5740
  error({
5479
5741
  code: "PUSH_FILE_CHANGED",
@@ -5556,14 +5818,15 @@ async function createPushPreflight(options) {
5556
5818
  maxFileBytes: limits.maxFileBytes
5557
5819
  });
5558
5820
  const config = parseCapturedProject(agentEntry);
5559
- if (config.datasets?.length) {
5821
+ if (config.datasets?.length || config.model !== void 0) {
5560
5822
  try {
5561
- await validateRuntimeDatasets(projectRoot, config.datasets);
5823
+ if (config.datasets?.length) await validateRuntimeDatasets(projectRoot, config.datasets);
5824
+ await validateRuntimeModel(projectRoot, config.model);
5562
5825
  } catch (cause) {
5563
5826
  error({
5564
5827
  code: "PUSH_CONFIG_INVALID",
5565
5828
  path: BUDDY_AGENT_FILENAME,
5566
- 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)}`,
5567
5830
  cause
5568
5831
  });
5569
5832
  }
@@ -5607,16 +5870,16 @@ async function createPushPreflight(options) {
5607
5870
  }
5608
5871
 
5609
5872
  // packages/cli-core/src/push/bundle.ts
5610
- import { createHash as createHash6 } from "node:crypto";
5611
- import { lstat as lstat9, readFile as readFile8, realpath as realpath6 } from "node:fs/promises";
5612
- import { join as join10, relative as relative3, sep as sep3, win32 as win324 } from "node:path";
5873
+ import { createHash as createHash7 } from "node:crypto";
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";
5613
5876
  import { Writable } from "node:stream";
5614
5877
  import { pipeline } from "node:stream/promises";
5615
5878
  import { createGzip } from "node:zlib";
5616
5879
  import { pack } from "tar-stream";
5617
5880
  var MEDIA_TYPE = "application/gzip";
5618
5881
  function digest(bytes) {
5619
- return `sha256:${createHash6("sha256").update(bytes).digest("hex")}`;
5882
+ return `sha256:${createHash7("sha256").update(bytes).digest("hex")}`;
5620
5883
  }
5621
5884
  function changed(path, message, cause) {
5622
5885
  throw new PushPreflightError({
@@ -5631,15 +5894,15 @@ function inside(root, target) {
5631
5894
  return path === "" || path !== ".." && !path.startsWith(`..${sep3}`) && !path.startsWith("/") && !win324.isAbsolute(path);
5632
5895
  }
5633
5896
  async function capture(root, file2) {
5634
- const absolute = join10(root, ...file2.path.split("/"));
5897
+ const absolute = join12(root, ...file2.path.split("/"));
5635
5898
  try {
5636
- const entry = await lstat9(absolute);
5899
+ const entry = await lstat10(absolute);
5637
5900
  if (!entry.isFile() || entry.isSymbolicLink() || entry.size !== file2.bytes) {
5638
5901
  changed(file2.path, `\u63D0\u4EA4\u524D\u6587\u4EF6\u53D1\u751F\u53D8\u5316\uFF1A${file2.path}`);
5639
5902
  }
5640
5903
  const canonical = await realpath6(absolute);
5641
5904
  if (!inside(root, canonical)) changed(file2.path, `\u63D0\u4EA4\u6587\u4EF6\u8D8A\u8FC7\u9879\u76EE\u6839\u76EE\u5F55\uFF1A${file2.path}`);
5642
- const contents = await readFile8(absolute);
5905
+ const contents = await readFile10(absolute);
5643
5906
  if (contents.byteLength !== file2.bytes || digest(contents) !== file2.digest) {
5644
5907
  changed(file2.path, `\u63D0\u4EA4\u524D\u6587\u4EF6\u5185\u5BB9\u53D1\u751F\u53D8\u5316\uFF1A${file2.path}`);
5645
5908
  }
@@ -5665,7 +5928,7 @@ async function createPushSourceBundle(plan) {
5665
5928
  schemaVersion: "1",
5666
5929
  files: files.map((file2) => ({ path: file2.path, bytes: file2.bytes, digest: file2.digest }))
5667
5930
  });
5668
- const calculatedBundleDigest = `sha256:${createHash6("sha256").update(`buddy-push-bundle-v1\0${descriptor}`).digest("hex")}`;
5931
+ const calculatedBundleDigest = `sha256:${createHash7("sha256").update(`buddy-push-bundle-v1\0${descriptor}`).digest("hex")}`;
5669
5932
  if (calculatedBundleDigest !== plan.bundleDigest) {
5670
5933
  changed(plan.projectRoot, "\u63D0\u4EA4\u6E05\u5355\u8EAB\u4EFD\u5728\u6253\u5305\u524D\u53D1\u751F\u53D8\u5316\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C push");
5671
5934
  }
@@ -5720,25 +5983,29 @@ var HELP2 = `\u642D\u642D Developer Platform CLI
5720
5983
 
5721
5984
  \u7528\u6CD5:
5722
5985
  buddy-cli
5986
+ buddy-cli --version [--json]
5987
+ buddy-cli update [--check] [--json]
5723
5988
  buddy-cli init
5724
5989
  buddy-cli init --mode create --directory <\u9879\u76EE\u76EE\u5F55> --name <\u540D\u79F0> --tagline <\u4E00\u53E5\u8BDD\u4ECB\u7ECD> --intro <\u5B8C\u6574\u4ECB\u7ECD> [--buddy-id <\u5DF2\u6709\u642D\u5B50 ID>]
5725
5990
  buddy-cli init --mode direct --directory <\u9879\u76EE\u76EE\u5F55> --name <\u540D\u79F0> --tagline <\u4E00\u53E5\u8BDD\u4ECB\u7ECD> --intro <\u5B8C\u6574\u4ECB\u7ECD> [--buddy-id <\u5DF2\u6709\u642D\u5B50 ID>]
5726
5991
  buddy-cli dev [--app-server <URL>] [--directory <\u9879\u76EE\u76EE\u5F55>]
5727
5992
  buddy-cli login | logout | push | status
5728
- buddy-cli avatar (--url <\u56FE\u7247\u5730\u5740> | --clear) [--directory <\u9879\u76EE\u76EE\u5F55> | --buddy-id <\u642D\u5B50 ID>]
5729
- buddy-cli models [--json]
5993
+ buddy-cli avatar (--file <\u56FE\u7247\u6587\u4EF6> | --clear) [--directory <\u9879\u76EE\u76EE\u5F55> | --buddy-id <\u642D\u5B50 ID>]
5994
+ buddy-cli models [--directory <\u9879\u76EE\u76EE\u5F55>] [--json]
5730
5995
  buddy-cli widgets sync | check | verify
5731
5996
  buddy-cli datasets [--directory <\u9879\u76EE\u76EE\u5F55>] [--json]
5732
5997
  buddy-cli preview [--app-server <URL>] [--directory <\u9879\u76EE\u76EE\u5F55>]
5733
5998
  buddy-cli help
5734
5999
 
5735
6000
  \u547D\u4EE4:
6001
+ --version \u67E5\u770B\u5F53\u524D\u8FD0\u884C\u7684 CLI \u7248\u672C\uFF08\u65E0\u9700\u8054\u7F51\u6216\u767B\u5F55\uFF09
6002
+ update \u68C0\u67E5 npm \u6700\u65B0\u7248\u672C\u6216\u66F4\u65B0\u5168\u5C40 CLI\uFF08\u65E0\u9700\u767B\u5F55\u6216 Agent \u5DE5\u7A0B\uFF09
5736
6003
  init \u521B\u5EFA\u6216\u6062\u590D\u642D\u5B50\uFF0C\u51C6\u5907\u5B98\u65B9 Runtime \u5DE5\u7A0B\u6216 Creator \u624B\u518C
5737
6004
  dev \u542F\u52A8\u5B98\u65B9 Runtime \u5E76\u8FDE\u63A5 DEV App Server
5738
6005
  login \u901A\u8FC7\u6D4F\u89C8\u5668\u767B\u5F55\u642D\u642D\u8D26\u53F7
5739
6006
  logout \u9000\u51FA\u642D\u642D\u5F00\u53D1\u8005\u8D26\u53F7\u5E76\u6E05\u9664\u672C\u673A\u767B\u5F55\u72B6\u6001
5740
- models \u67E5\u770B CLI \u5185\u7F6E\u6A21\u578B ID\uFF08\u65E0\u9700\u767B\u5F55\u3001\u8054\u7F51\u6216 Agent \u5DE5\u7A0B\uFF09
5741
- 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
5742
6009
  push \u4E0A\u4F20 Agent \u5DE5\u7A0B\u548C commit\uFF0C\u63D0\u4EA4\u5E73\u53F0\u5BA1\u6838
5743
6010
  status \u67E5\u8BE2\u642D\u5B50\u7684\u8D44\u6599\u3001\u4EE3\u7801\u3001\u8FD0\u884C\u4E0E\u53D1\u5E03\u72B6\u6001
5744
6011
  avatar \u8BBE\u7F6E\u6216\u6E05\u9664\u642D\u5B50\u5934\u50CF\uFF0C\u4FDD\u7559\u5176\u4ED6\u4E91\u7AEF\u8D44\u6599
@@ -5947,7 +6214,7 @@ function defaultProjectDirectory(name) {
5947
6214
  return `./${folder}`;
5948
6215
  }
5949
6216
  async function initializeProjectRoute(route, args, io, options, application) {
5950
- const cwd = resolve15(options.cwd ?? process.cwd());
6217
+ const cwd = resolve16(options.cwd ?? process.cwd());
5951
6218
  const { name, tagline, intro } = application;
5952
6219
  const directoryInput = await textAnswer(
5953
6220
  io,
@@ -5956,7 +6223,7 @@ async function initializeProjectRoute(route, args, io, options, application) {
5956
6223
  "\u9879\u76EE\u76EE\u5F55\uFF08\u7A7A\u76EE\u5F55\u6216\u5DF2\u6709\u642D\u642D\u5DE5\u7A0B\uFF09",
5957
6224
  defaultProjectDirectory(name)
5958
6225
  );
5959
- const rootDirectory = resolve15(cwd, directoryInput);
6226
+ const rootDirectory = resolve16(cwd, directoryInput);
5960
6227
  await assertInitializableBuddyTarget(rootDirectory);
5961
6228
  const initializationTarget = { directory: rootDirectory, kind: "new" };
5962
6229
  const initializationPlan = options.initializeProject ? void 0 : await planBuddyProjectInitialization(initializationTarget);
@@ -6000,7 +6267,7 @@ async function initializeProjectRoute(route, args, io, options, application) {
6000
6267
  }
6001
6268
  async function runRoute(route, args, io, options) {
6002
6269
  if (!io.canPrompt) assertNonInteractiveProjectArguments(route, args);
6003
- const cwd = resolve15(options.cwd ?? process.cwd());
6270
+ const cwd = resolve16(options.cwd ?? process.cwd());
6004
6271
  const name = await textAnswer(io, args.name, "--name", "\u642D\u5B50\u540D\u79F0", void 0, BUDDY_PROFILE_TEXT_LIMITS.name);
6005
6272
  const tagline = await textAnswer(
6006
6273
  io,
@@ -6028,7 +6295,7 @@ async function runRoute(route, args, io, options) {
6028
6295
  "\u9879\u76EE\u76EE\u5F55",
6029
6296
  defaultProjectDirectory(name)
6030
6297
  );
6031
- const rootDirectory = resolve15(cwd, directoryInput);
6298
+ const rootDirectory = resolve16(cwd, directoryInput);
6032
6299
  await assertInitializableBuddyTarget(rootDirectory);
6033
6300
  const plan = await planBuddyDraftInitialization(rootDirectory);
6034
6301
  const existingBuddyId = plan.existingManifest?.buddyId;
@@ -6062,11 +6329,11 @@ async function runRoute(route, args, io, options) {
6062
6329
  return { ...result, route: "create", draft, buddyId };
6063
6330
  }
6064
6331
  async function resumeProjectArguments(args, cwd, options) {
6065
- const root = resolve15(cwd, args.directory?.trim() || ".");
6332
+ const root = resolve16(cwd, args.directory?.trim() || ".");
6066
6333
  await assertInitializableBuddyTarget(root);
6067
6334
  let entry;
6068
6335
  try {
6069
- entry = await lstat10(join11(root, "buddy.agent.json"));
6336
+ entry = await lstat11(join13(root, "buddy.agent.json"));
6070
6337
  } catch (cause) {
6071
6338
  if (cause.code === "ENOENT") return;
6072
6339
  throw cause;
@@ -6095,7 +6362,7 @@ async function runBuddyCli(args, io, options = {}) {
6095
6362
  try {
6096
6363
  const [command, ...rest] = args;
6097
6364
  if (!command) {
6098
- const cwd = resolve15(options.cwd ?? process.cwd());
6365
+ const cwd = resolve16(options.cwd ?? process.cwd());
6099
6366
  let projectRoot;
6100
6367
  try {
6101
6368
  projectRoot = await findBuddyProjectRoot(cwd);
@@ -6123,13 +6390,13 @@ async function runBuddyCli(args, io, options = {}) {
6123
6390
  io.write(HELP2);
6124
6391
  return { exitCode: 0 };
6125
6392
  }
6126
- if (command === "models") return runModelsCommand(rest, io);
6393
+ if (command === "models") return await runModelsCommand(rest, io, options.cwd ?? process.cwd(), options.runtimeCatalog);
6127
6394
  if (command === "widgets") return await runWidgetsCommand(rest, io, options.cwd ?? process.cwd());
6128
6395
  if (command === "preview") {
6129
6396
  return options.preview?.(rest, io) ?? failure("preview \u5BBF\u4E3B\u672A\u914D\u7F6E", io, true);
6130
6397
  }
6131
6398
  if (command === "datasets") {
6132
- return await runDatasetsCommand(rest, io, options.cwd ?? process.cwd());
6399
+ return await runDatasetsCommand(rest, io, options.cwd ?? process.cwd(), options.runtimeCatalog);
6133
6400
  }
6134
6401
  if (command === "dev") {
6135
6402
  return await runDevCommand(rest, io, {
@@ -6151,11 +6418,11 @@ async function runBuddyCli(args, io, options = {}) {
6151
6418
  }
6152
6419
  let route = routeFromMode(parsed.mode);
6153
6420
  if (route === void 0 && !io.canPrompt) requireModeForNonInteractive();
6154
- const cwd = resolve15(options.cwd ?? process.cwd());
6421
+ const cwd = resolve16(options.cwd ?? process.cwd());
6155
6422
  await assertInitializableBuddyTarget(cwd);
6156
6423
  if (parsed.directory !== void 0) {
6157
6424
  if (!parsed.directory.trim()) throw new CliUsageError("--directory \u4E0D\u80FD\u4E3A\u7A7A");
6158
- await assertInitializableBuddyTarget(resolve15(cwd, parsed.directory));
6425
+ await assertInitializableBuddyTarget(resolve16(cwd, parsed.directory));
6159
6426
  }
6160
6427
  await authenticate(options);
6161
6428
  await resumeProjectArguments(parsed, cwd, options);
@@ -6308,6 +6575,7 @@ export {
6308
6575
  isAbortLike,
6309
6576
  isSafeProjectRelativePath,
6310
6577
  isWindowsReservedPathSegment,
6578
+ latestRuntimeTemplate,
6311
6579
  normalizePlatformUrl,
6312
6580
  openExternalUrl,
6313
6581
  parseBuddyAgentConfig,