@my-life-buddies/cli 0.4.0 → 0.6.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/README.md CHANGED
@@ -2,13 +2,13 @@
2
2
 
3
3
  这份说明按一次开发过程展开:登记搭子,准备工程,在本地预览,然后上传程序包。所有搭子统一使用 `@my-life-buddies/buddy-runtime`,业务能力通过 Prompt、`src/buddy-options.mjs` 和 Tool 实现。
4
4
 
5
- 工程模板已锁定公共 npm 的 Runtime `0.10.0`,本批接口变化与联调范围见 [Runtime 集成说明](../../docs/runtime-integration.md)。
5
+ 工程模板已锁定公共 npm 的 Runtime `0.11.0`,本批接口变化与联调范围见 [Runtime 集成说明](../../docs/runtime-integration.md)。
6
6
 
7
7
  ## 准备 CLI 和平台地址
8
8
 
9
9
  目前只支持 macOS,要求 Node.js 24 或更新版本。
10
10
 
11
- 当前 CLI 工程版本为 `0.4.0`,发布到公共 Registry `https://registry.npmjs.org/`。已有仓库源码时,在仓库根目录运行:
11
+ 当前 CLI 工程版本为 `0.6.0`,发布到公共 Registry `https://registry.npmjs.org/`。已有仓库源码时,在仓库根目录运行:
12
12
 
13
13
  ```bash
14
14
  npm install
@@ -55,6 +55,7 @@ CLI 会把换取到的会话保存到 macOS Keychain。有效会话会复用,
55
55
  | `init` | 目标目录可以是空目录或已有官方工程 | 登记或恢复云端身份,准备本地文件 |
56
56
  | `dev`、`preview`、`push` | 需要有效清单和完整工程文件 | 运行、调试或打包该工程 |
57
57
  | `status` | 需要含 `buddyId` 的 `buddy.agent.json` | 查询该搭子的云端状态;创作尚未完成时也可使用 |
58
+ | `avatar` | 从工程读取身份,或用 `--buddy-id` 指定 | 设置图片 URL 或清除搭子头像,保留其他资料;无需 Runtime |
58
59
  | `datasets` | 需要工程和安装好的 Runtime,无需登录 | 读取 Runtime 的全部数据集;支持 `--directory`、`--json` |
59
60
 
60
61
  项目命令可从工程子目录向上定位配置,也可用 `--directory` 指定工程。普通目录不会被悄悄初始化;已有官方工程可用 `init --mode direct` 补齐缺失的模板文件,已有文件不会被覆盖。
@@ -153,10 +154,15 @@ import { BuddyServer } from "@my-life-buddies/buddy-runtime";
153
154
  import createBuddyOptions from "./src/buddy-options.mjs";
154
155
 
155
156
  const config = JSON.parse(readFileSync(new URL("./buddy.agent.json", import.meta.url), "utf8"));
156
- await BuddyServer.start({ dataRequirements: config.datasets ?? [], buddy: createBuddyOptions });
157
+ await BuddyServer.start({
158
+ buddyId: process.env.BUDDY_ID,
159
+ token: process.env.BUDDY_TOKEN,
160
+ dataRequirements: config.datasets ?? [],
161
+ buddy: createBuddyOptions,
162
+ });
157
163
  ```
158
164
 
159
- 工程在 `package.json` 声明准确 Runtime 版本,锁文件固定依赖;上传不包含 `node_modules` 或 Runtime 打包副本,部署执行同一份 `npm start`。模板及锁文件使用 Runtime `0.10.0`,安装验收直接从公共 npm 安装,不替换依赖。
165
+ 工程在 `package.json` 声明准确 Runtime 版本,锁文件固定依赖;上传不包含 `node_modules` 或 Runtime 打包副本,部署执行同一份 `npm start`。模板及锁文件使用 Runtime `0.11.0`,安装验收直接从公共 npm 安装,不替换依赖。
160
166
 
161
167
  ## 想法还模糊时,先梳理需求
162
168
 
@@ -211,6 +217,25 @@ Creator 例外保留首次创作背景快照,用于接续同一作品;恢复
211
217
 
212
218
  这些规则通过 CLI 帮助、命令输出和 Creator 的 `HANDOFF.md` 交给 Coding Agent;CLI 不会在 `init` 内自动执行采访、编写业务代码或批量调用模型。重试创作时复用当前接续说明和作品,不覆盖开发者修改的文件。已有完整工程无需重新初始化,可从更新后的 CLI 帮助和 `preview` 输出读取交接规则。
213
219
 
220
+ ## 修改搭子的头像
221
+
222
+ 先准备可访问的图片地址,在搭子工程中执行:
223
+
224
+ ```bash
225
+ buddy-cli avatar --url "https://images.example.com/my-buddy.png"
226
+ buddy-cli avatar --clear
227
+ ```
228
+
229
+ `--url` 与 `--clear` 二选一。支持 HTTP(S) 图片地址和平台已有的 `/media/...` 地址;本地文件上传不在本次能力内,CLI 不下载或检查远端图片内容。
230
+
231
+ 命令默认向上寻找 `buddy.agent.json`,也可用 `--directory ./my-buddy` 指定工程。创作阶段只有身份清单时也能使用,不需要安装 Runtime。在工程外管理已有搭子时,直接指定平台 ID:
232
+
233
+ ```bash
234
+ buddy-cli avatar --buddy-id b_example --url "https://images.example.com/my-buddy.png"
235
+ ```
236
+
237
+ `--buddy-id` 和 `--directory` 不能同时使用。命令复用 CLI 登录态,由 Server 校验搭子归属;执行后立即更新云端头像。CLI 先读取最新资料,只替换 `avatar`,再通过 `PUT /cli/buddies/:id/meta` 提交完整资料,保留名称、介绍、标签及扩展字段。清除头像提交 `avatar: null`。头像不写入本地配置,不需要 `push` 或重新发布程序包,`buddy-cli status` 可查看已设置的头像地址。
238
+
214
239
  ## 为这个搭子选一个模型
215
240
 
216
241
  ```bash
@@ -250,7 +275,7 @@ CLI 本地列出 `kimi-k2.6`、`kimi-k3`、`deepseek-v4-flash`、`deepseek-v4-pr
250
275
  }
251
276
  ```
252
277
 
253
- 完整选项以工程目录运行 `buddy-cli datasets` 的输出为准;脚本可加 `--json`。目录由安装的 Runtime 提供,Runtime 0.10.0 包含 HealthKit 与小红书两类,共 10 项。
278
+ 完整选项以工程目录运行 `buddy-cli datasets` 的输出为准;脚本可加 `--json`。目录由安装的 Runtime 提供,Runtime 0.11.0 包含 HealthKit 与小红书两类,共 10 项。
254
279
 
255
280
  CLI 校验声明,并把清单原样放入源码包。服务端从包中解析申请清单、绑定版本,以及 App 展示和取得用户授权的流程仍需接入;当前 CLI 不会额外调用接口修改平台权限。工程中的声明不代表用户已经授权,也不会自动启用查询工具。
256
281
 
@@ -329,8 +354,8 @@ CLI 不提供 `release`、`publish`、`disable`、`enable` 或 `unpublish`。最
329
354
 
330
355
  | 环境变量 | 作用 |
331
356
  | --- | --- |
332
- | `MLB_BUDDY_ID` | 平台部署的搭子身份,须与工程匹配 |
333
- | `MLB_BUDDY_TOKEN` | 连接 MLB 的 Buddy 凭据 |
357
+ | `BUDDY_ID` | 平台部署的搭子身份,须与工程匹配 |
358
+ | `BUDDY_TOKEN` | 连接 MLB 的 Buddy 凭据 |
334
359
  | `MLB_GATEWAY_URL` | 平台网关,由部署环境显式注入;未设置时沿用 Runtime 的默认地址 |
335
360
 
336
361
  这些值由部署环境提供,不写入提审包。云端安装工程声明的 Runtime 和业务依赖,执行 `npm start`,不需要安装 CLI。Runtime 主动连接网关事件流。
@@ -361,6 +386,6 @@ buddy-cli datasets --directory ./my-buddy --json
361
386
 
362
387
  目录直接来自当前工程 Runtime 的 `DATA_ACCESS_CAPABILITIES`,包括 ID、名称、来源和 Schema 版本。普通输出供开发者阅读,JSON 返回 `runtimeVersion` 和 `datasets` 数组供脚本处理。命令不登录、不启动搭子、不申请权限,也不修改配置;从子目录运行会向上找到工程。
363
388
 
364
- 开发者将实际选择的 ID 和用途写进 `buddy.agent.json.datasets`。JSON Schema 检查形状与用途;DEV 和非空数据声明的上传预检按工程安装的 Runtime 检查 ID。目录缺失、依赖未安装或版本不匹配时明确报错。Runtime 0.10.0 有 10 项,但单次数据查询仍最多 8 项。
389
+ 开发者将实际选择的 ID 和用途写进 `buddy.agent.json.datasets`。JSON Schema 检查形状与用途;DEV 和非空数据声明的上传预检按工程安装的 Runtime 检查 ID。目录缺失、依赖未安装或版本不匹配时明确报错。Runtime 0.11.0 有 10 项,但单次数据查询仍最多 8 项。
365
390
 
366
391
  Preview 文本发送采用 App WebSocket 的 `messages` 数组,并校验逐项回执。`ask_question` 的全部选项以文字显示,开发者直接回复选择;权限卡提示到搭搭 App 处理,浏览器不模拟系统授权。
package/dist/bin/core.js CHANGED
@@ -17,7 +17,7 @@ function runModelsCommand(args, io) {
17
17
  } else if (args.length === 1 && args[0] === "--json") {
18
18
  io.write(JSON.stringify({ models: MODEL_IDS }, null, 2));
19
19
  } else if (args.length === 0) {
20
- io.write("CLI \u5185\u7F6E\u6A21\u578B\u76EE\u5F55\uFF08Runtime 0.10.0\uFF09\uFF1A");
20
+ io.write("CLI \u5185\u7F6E\u6A21\u578B\u76EE\u5F55\uFF08Runtime 0.11.0\uFF09\uFF1A");
21
21
  for (const id of MODEL_IDS) io.write(`- ${id}`);
22
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
23
  } else {
@@ -176,8 +176,8 @@ const config = JSON.parse(readFileSync(new URL("./buddy.agent.json", import.meta
176
176
  if (!config || config.schemaVersion !== 1 || typeof config.buddyId !== "string" || !config.buddyId) {
177
177
  throw new Error("buddy.agent.json is not a complete Buddy project");
178
178
  }
179
- if (process.env.MLB_BUDDY_ID && process.env.MLB_BUDDY_ID !== config.buddyId) {
180
- throw new Error("MLB_BUDDY_ID does not match buddy.agent.json");
179
+ if (process.env.BUDDY_ID && process.env.BUDDY_ID !== config.buddyId) {
180
+ throw new Error("BUDDY_ID does not match buddy.agent.json");
181
181
  }
182
182
  const lifecycle = new AbortController();
183
183
  const stop = () => lifecycle.abort();
@@ -186,6 +186,8 @@ process.on("SIGTERM", stop);
186
186
  let runtime;
187
187
  try {
188
188
  runtime = await BuddyServer.start({
189
+ buddyId: process.env.BUDDY_ID,
190
+ token: process.env.BUDDY_TOKEN,
189
191
  dataRequirements: config.datasets ?? [],
190
192
  buddy: createBuddyOptions,
191
193
  });
@@ -1430,7 +1432,7 @@ Creator \u8DEF\u7EBF\u987B\u7B49\u56DB\u518C\u3001\u5C0F\u6302\u4EF6\u6E05\u5355
1430
1432
  | \u56DE\u7B54\u65F6\u9700\u8981\u53C2\u8003\u7684\u5386\u53F2\u3001\u8BA1\u5212\u548C\u72B6\u6001 | Runtime \u4F1A\u4ECE MLB \u91CD\u5EFA\u4F1A\u8BDD\u5386\u53F2\uFF1B\u957F\u671F\u8BA1\u5212\u548C\u7ED3\u6784\u5316\u72B6\u6001\u4E0D\u80FD\u53EA\u4F9D\u8D56\u5B83\u4E00\u76F4\u7559\u5728\u6700\u8FD1\u804A\u5929\u91CC\u3002\u6309\u9700\u6C42\u4F7F\u7528 Memory\u3001\u6388\u6743\u6570\u636E\u6216\u4E1A\u52A1 Tool\uFF0C\u4E0D\u8981\u627F\u8BFA\u9ED8\u8BA4\u914D\u7F6E\u5DF2\u7ECF\u8986\u76D6\u3002 |
1431
1433
  | \u6A21\u578B\u548C\u5E73\u53F0\u8D44\u6E90 | \u5DF2\u786E\u5B9A\u7684\u6A21\u578B\u76F4\u63A5\u6CBF\u7528\uFF1B\u672A\u6307\u5B9A\u65F6\u67E5\u8BE2 \`buddy-cli models\`\uFF0C\u6838\u5BF9\u53EF\u7528\u6027\u5E76\u91C7\u7528\u6EE1\u8DB3\u9700\u6C42\u7684\u9009\u62E9\uFF0C\u4E0D\u9ED8\u8BA4\u518D\u95EE\u4E00\u8F6E\u9009\u578B\u95EE\u9898\uFF0C\u4E5F\u4E0D\u7F16\u9020\u4EF7\u683C\u6216\u80FD\u529B\u3002\u6A21\u677F\u628A\u914D\u7F6E\u4E2D\u7684\u6A21\u578B\u4EA4\u7ED9 \`initialState.model\`\uFF1B\u81EA\u5B9A\u4E49\u5DE5\u5382\u4E5F\u53EF\u6309\u4F1A\u8BDD\u9009\u62E9\u53D7\u652F\u6301\u6A21\u578B\uFF1B\u4F1A\u4EA7\u751F\u65B0\u7684\u8D39\u7528\u3001\u6570\u636E\u4F7F\u7528\u6216\u6743\u9650\u8FB9\u754C\u65F6\u5148\u786E\u8BA4\u3002 |
1432
1434
 
1433
- \`src/buddy-options.mjs\` \u662F\u6BCF\u573A\u4F1A\u8BDD\u7684\u4E1A\u52A1\u88C5\u914D\u5165\u53E3\uFF0C\u5BFC\u51FA \`createBuddyOptions(conversation)\`\uFF0C\u8FD4\u56DE \`initialState\`\u3001\u5728 \`initialState.tools\` \u6CE8\u518C\u7684\u4E1A\u52A1\u53CA\u5E73\u53F0\u5DE5\u5177\u548C\u53EF\u9009\u56DE\u5408\u94A9\u5B50\u3002\`start.mjs\` \u4ECE \`./src/buddy-options.mjs\` \u5BFC\u5165\u5DE5\u5382\u5E76\u4F20\u7ED9 \`BuddyServer.start({ dataRequirements: config.datasets ?? [], buddy: createBuddyOptions })\`\uFF1B\u7EC4\u88C5\u5668\u8BFB\u53D6 \`buddy.agent.json.model\`\uFF0C\u7701\u7565\u65F6\u7528 \`kimi-k2.6\`\uFF0C\u653E\u5165 \`initialState.model\`\uFF1B\u7528 \`new URL("../agent.md", import.meta.url)\` \u8BFB\u53D6\u6839\u76EE\u5F55 Prompt\u3002\u9ED8\u8BA4\u6A21\u677F\u53EA\u662F\u8D77\u70B9\uFF0C\u53EA\u6539\u8BF4\u660E\u4E0D\u7B49\u4E8E\u6539\u53D8\u4E86\u4FDD\u5B58\u3001\u67E5\u8BE2\u6216\u5904\u7406\u903B\u8F91\u3002
1435
+ \`src/buddy-options.mjs\` \u662F\u6BCF\u573A\u4F1A\u8BDD\u7684\u4E1A\u52A1\u88C5\u914D\u5165\u53E3\uFF0C\u5BFC\u51FA \`createBuddyOptions(conversation)\`\uFF0C\u8FD4\u56DE \`initialState\`\u3001\u5728 \`initialState.tools\` \u6CE8\u518C\u7684\u4E1A\u52A1\u53CA\u5E73\u53F0\u5DE5\u5177\u548C\u53EF\u9009\u56DE\u5408\u94A9\u5B50\u3002\`start.mjs\` \u4ECE \`./src/buddy-options.mjs\` \u5BFC\u5165\u5DE5\u5382\u5E76\u4F20\u7ED9 \`BuddyServer.start({ buddyId: process.env.BUDDY_ID, token: process.env.BUDDY_TOKEN, dataRequirements: config.datasets ?? [], buddy: createBuddyOptions })\`\uFF1B\u7EC4\u88C5\u5668\u8BFB\u53D6 \`buddy.agent.json.model\`\uFF0C\u7701\u7565\u65F6\u7528 \`kimi-k2.6\`\uFF0C\u653E\u5165 \`initialState.model\`\uFF1B\u7528 \`new URL("../agent.md", import.meta.url)\` \u8BFB\u53D6\u6839\u76EE\u5F55 Prompt\u3002\u9ED8\u8BA4\u6A21\u677F\u53EA\u662F\u8D77\u70B9\uFF0C\u53EA\u6539\u8BF4\u660E\u4E0D\u7B49\u4E8E\u6539\u53D8\u4E86\u4FDD\u5B58\u3001\u67E5\u8BE2\u6216\u5904\u7406\u903B\u8F91\u3002
1434
1436
 
1435
1437
  ### \u6309\u76EE\u5F55\u804C\u8D23\u7EC4\u7EC7\u5B9E\u73B0
1436
1438
 
@@ -1460,11 +1462,11 @@ Tool \u548C Hook \u662F Runtime \u7684\u6269\u5C55\u70B9\uFF1BService \u53EA\u66
1460
1462
 
1461
1463
  \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
1462
1464
 
1463
- \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.10.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
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
1464
1466
 
1465
1467
  \`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
1466
1468
 
1467
- \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.10.0\u3002
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
1468
1470
 
1469
1471
  \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
1470
1472
 
@@ -1738,8 +1740,10 @@ function validateBuddyMeta(meta2) {
1738
1740
  invalidRequest(`meta.${key} \u5FC5\u987B\u4E3A\u4E0D\u8D85\u8FC7 ${limit} \u5B57\u7684\u5B57\u7B26\u4E32\u6216 null`);
1739
1741
  }
1740
1742
  }
1741
- if (meta2.avatar != null) {
1742
- const value = meta2.avatar;
1743
+ if (meta2.avatar !== void 0) validateBuddyAvatar(meta2.avatar);
1744
+ }
1745
+ function validateBuddyAvatar(value) {
1746
+ if (value !== null) {
1743
1747
  let valid = false;
1744
1748
  if (typeof value === "string" && value.length > 0 && value.length <= 2048 && !/[\s\u0000-\u001f]/u.test(value)) {
1745
1749
  valid = /^\/media\/[A-Za-z0-9_.-]+$/u.test(value);
@@ -1751,7 +1755,7 @@ function validateBuddyMeta(meta2) {
1751
1755
  }
1752
1756
  }
1753
1757
  }
1754
- if (!valid) invalidRequest("meta.avatar \u5FC5\u987B\u4E3A\u5408\u6CD5\u56FE\u7247\u5730\u5740\u6216 null");
1758
+ if (!valid) invalidRequest("avatar \u5FC5\u987B\u4E3A\u5408\u6CD5\u56FE\u7247\u5730\u5740\u6216 null");
1755
1759
  }
1756
1760
  }
1757
1761
 
@@ -2046,8 +2050,8 @@ function buildAgentEnvironment(options) {
2046
2050
  });
2047
2051
  }
2048
2052
  environment.BUDDY_ENV = "dev";
2049
- environment.MLB_BUDDY_ID = safeOpaqueValue(options.buddyId, "Buddy ID");
2050
- environment.MLB_BUDDY_TOKEN = safeOpaqueValue(options.buddyToken, "Buddy token");
2053
+ environment.BUDDY_ID = safeOpaqueValue(options.buddyId, "Buddy ID");
2054
+ environment.BUDDY_TOKEN = safeOpaqueValue(options.buddyToken, "Buddy token");
2051
2055
  environment.MLB_GATEWAY_URL = gateway.href;
2052
2056
  return environment;
2053
2057
  }
@@ -3106,6 +3110,7 @@ function meta(value, path) {
3106
3110
  const tagline = optionalText(source.tagline, `${path}.tagline`);
3107
3111
  const intro = optionalText(source.intro, `${path}.intro`, true);
3108
3112
  return Object.freeze({
3113
+ ...source,
3109
3114
  ...name === void 0 ? {} : { name },
3110
3115
  ...avatar === void 0 ? {} : { avatar },
3111
3116
  ...tagline === void 0 ? {} : { tagline },
@@ -3817,7 +3822,11 @@ var HELP = Object.freeze({
3817
3822
  login: "\u7528\u6CD5: buddy-cli login",
3818
3823
  logout: "\u7528\u6CD5: buddy-cli logout",
3819
3824
  push: "\u7528\u6CD5: buddy-cli push [--directory <\u9879\u76EE\u76EE\u5F55>] [--commit <\u672C\u6B21\u6539\u52A8\u8BF4\u660E>]",
3820
- status: "\u7528\u6CD5: buddy-cli status [--directory <\u9879\u76EE\u76EE\u5F55>]"
3825
+ 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>]
3827
+ \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
3829
+ \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`
3821
3830
  });
3822
3831
  function parse2(args, command) {
3823
3832
  const values = /* @__PURE__ */ new Map();
@@ -3829,10 +3838,15 @@ function parse2(args, command) {
3829
3838
  help = true;
3830
3839
  continue;
3831
3840
  }
3832
- const allowed = command === "push" ? flag2 === "--directory" || flag2 === "--commit" : command === "status" && flag2 === "--directory";
3841
+ if (command === "avatar" && flag2 === "--clear") {
3842
+ if (values.has(flag2)) throw new CloudCommandUsageError(`${flag2} \u4E0D\u80FD\u91CD\u590D`);
3843
+ values.set(flag2, "");
3844
+ continue;
3845
+ }
3846
+ const allowed = command === "push" ? flag2 === "--directory" || flag2 === "--commit" : command === "avatar" ? ["--directory", "--buddy-id", "--url"].includes(flag2) : command === "status" && flag2 === "--directory";
3833
3847
  if (!allowed) throw new CloudCommandUsageError(`\u672A\u77E5\u53C2\u6570 ${flag2}`);
3834
3848
  const value = args[index + 1];
3835
- if (value === void 0 || !value.trim()) throw new CloudCommandUsageError(`${flag2} \u7F3A\u5C11\u503C`);
3849
+ if (value === void 0 || !value.trim() || command === "avatar" && value.startsWith("--")) throw new CloudCommandUsageError(`${flag2} \u7F3A\u5C11\u503C`);
3836
3850
  if (values.has(flag2)) throw new CloudCommandUsageError(`${flag2} \u4E0D\u80FD\u91CD\u590D`);
3837
3851
  values.set(flag2, value);
3838
3852
  index += 1;
@@ -3879,6 +3893,7 @@ function printStatus(io, buddy2, packages) {
3879
3893
  io.write(`\u642D\u5B50\uFF1A${displayName}\uFF08${buddy2.id}\uFF09`);
3880
3894
  if (buddy2.meta?.tagline) io.write(`\u4E00\u53E5\u8BDD\u4ECB\u7ECD\uFF1A${buddy2.meta.tagline}`);
3881
3895
  if (buddy2.meta?.intro) io.write(`\u5B8C\u6574\u4ECB\u7ECD\uFF1A${buddy2.meta.intro}`);
3896
+ if (buddy2.meta?.avatar) io.write(`\u5934\u50CF\uFF1A${buddy2.meta.avatar}`);
3882
3897
  io.write(`\u4EE3\u7801\uFF1A${buddy2.pushed ? "\u5DF2\u4E0A\u4F20" : "\u672A\u4E0A\u4F20"}`);
3883
3898
  if (buddy2.version) io.write(`\u7EBF\u4E0A\u7248\u672C\uFF1A${buddy2.version}`);
3884
3899
  io.write(`\u8FD0\u884C\uFF1A${buddy2.online ? "\u5728\u7EBF" : "\u79BB\u7EBF"}`);
@@ -3939,6 +3954,39 @@ async function runPush(parsed, io, options) {
3939
3954
  io.write("\u672C\u6B21 push \u53EA\u63D0\u4EA4\u5BA1\u6838\uFF0C\u4E0D\u4F1A\u90E8\u7F72\u6216\u53D1\u5E03 Agent\u3002");
3940
3955
  return { exitCode: 0, buddyId: config.buddyId, version: receipt.version };
3941
3956
  }
3957
+ 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");
3960
+ }
3961
+ if (parsed.values.has("--buddy-id") && parsed.values.has("--directory")) {
3962
+ throw new CloudCommandUsageError("--buddy-id \u548C --directory \u4E0D\u80FD\u540C\u65F6\u4F7F\u7528");
3963
+ }
3964
+ const avatar = parsed.values.get("--url") ?? null;
3965
+ try {
3966
+ validateBuddyAvatar(avatar);
3967
+ } catch (error2) {
3968
+ throw new CloudCommandUsageError(error2 instanceof Error ? error2.message : "\u5934\u50CF\u5730\u5740\u65E0\u6548");
3969
+ }
3970
+ let id = parsed.values.get("--buddy-id");
3971
+ 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");
3972
+ if (id === void 0) {
3973
+ const root = await (options.resolveProjectRoot ?? requireBuddyProjectRoot)(requestedDirectory(options, parsed));
3974
+ id = (await (options.readManifest ?? readBuddyProjectManifest)(root)).buddyId;
3975
+ }
3976
+ if (options.mode === "local-mock") throw new CloudCommandUsageError("\u672C\u5730\u6A21\u62DF\u6A21\u5F0F\u4E0D\u4FEE\u6539\u4E91\u7AEF\u5934\u50CF\uFF0C\u8BF7\u8FDE\u63A5\u771F\u5B9E MLB Server");
3977
+ const { session, client } = dependencies(options);
3978
+ await session.token({ signal: options.signal });
3979
+ const current = await client.getBuddy({ id });
3980
+ 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) {
3983
+ 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
+ }
3985
+ 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}`);
3987
+ io.write("\u4E91\u7AEF\u8D44\u6599\u5DF2\u66F4\u65B0\uFF0C\u65E0\u9700 push \u6216\u91CD\u65B0\u53D1\u5E03\u7A0B\u5E8F\u5305\u3002");
3988
+ return { exitCode: 0, buddyId: id };
3989
+ }
3942
3990
  async function runCloudCommand(command, args, io, options = {}) {
3943
3991
  try {
3944
3992
  const parsed = parse2(args, command);
@@ -3955,6 +4003,7 @@ async function runCloudCommand(command, args, io, options = {}) {
3955
4003
  }
3956
4004
  if (command === "logout") return await runLogout(io, options);
3957
4005
  if (command === "push") return await runPush(parsed, io, options);
4006
+ if (command === "avatar") return await runAvatar(parsed, io, options);
3958
4007
  const root = await (options.resolveProjectRoot ?? requireBuddyProjectRoot)(requestedDirectory(options, parsed));
3959
4008
  const manifest = await (options.readManifest ?? readBuddyProjectManifest)(root);
3960
4009
  if (options.mode === "local-mock") {
@@ -5676,6 +5725,7 @@ var HELP2 = `\u642D\u642D Developer Platform CLI
5676
5725
  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>]
5677
5726
  buddy-cli dev [--app-server <URL>] [--directory <\u9879\u76EE\u76EE\u5F55>]
5678
5727
  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>]
5679
5729
  buddy-cli models [--json]
5680
5730
  buddy-cli widgets sync | check | verify
5681
5731
  buddy-cli datasets [--directory <\u9879\u76EE\u76EE\u5F55>] [--json]
@@ -5691,6 +5741,7 @@ var HELP2 = `\u642D\u642D Developer Platform CLI
5691
5741
  datasets \u8BFB\u53D6\u5DE5\u7A0B Runtime \u63D0\u4F9B\u7684\u6570\u636E\u96C6\u76EE\u5F55\uFF08\u65E0\u9700\u767B\u5F55\uFF09
5692
5742
  push \u4E0A\u4F20 Agent \u5DE5\u7A0B\u548C commit\uFF0C\u63D0\u4EA4\u5E73\u53F0\u5BA1\u6838
5693
5743
  status \u67E5\u8BE2\u642D\u5B50\u7684\u8D44\u6599\u3001\u4EE3\u7801\u3001\u8FD0\u884C\u4E0E\u53D1\u5E03\u72B6\u6001
5744
+ avatar \u8BBE\u7F6E\u6216\u6E05\u9664\u642D\u5B50\u5934\u50CF\uFF0C\u4FDD\u7559\u5176\u4ED6\u4E91\u7AEF\u8D44\u6599
5694
5745
  preview \u6253\u5F00\u642D\u642D App \u79C1\u804A\u6A21\u62DF\u5668\u4E0E\u8C03\u8BD5\u9875\u9762
5695
5746
  help \u67E5\u770B\u5E2E\u52A9
5696
5747
 
@@ -6086,7 +6137,7 @@ async function runBuddyCli(args, io, options = {}) {
6086
6137
  ...options.dev
6087
6138
  });
6088
6139
  }
6089
- if (command === "login" || command === "logout" || command === "push" || command === "status") {
6140
+ if (command === "login" || command === "logout" || command === "push" || command === "status" || command === "avatar") {
6090
6141
  return await runCloudCommand(command, rest, io, {
6091
6142
  cwd: options.cwd,
6092
6143
  ...options.cloud