@my-life-buddies/cli 0.5.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
@@ -8,7 +8,7 @@
8
8
 
9
9
  目前只支持 macOS,要求 Node.js 24 或更新版本。
10
10
 
11
- 当前 CLI 工程版本为 `0.5.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` 补齐缺失的模板文件,已有文件不会被覆盖。
@@ -216,6 +217,25 @@ Creator 例外保留首次创作背景快照,用于接续同一作品;恢复
216
217
 
217
218
  这些规则通过 CLI 帮助、命令输出和 Creator 的 `HANDOFF.md` 交给 Coding Agent;CLI 不会在 `init` 内自动执行采访、编写业务代码或批量调用模型。重试创作时复用当前接续说明和作品,不覆盖开发者修改的文件。已有完整工程无需重新初始化,可从更新后的 CLI 帮助和 `preview` 输出读取交接规则。
218
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
+
219
239
  ## 为这个搭子选一个模型
220
240
 
221
241
  ```bash
package/dist/bin/core.js CHANGED
@@ -1740,8 +1740,10 @@ function validateBuddyMeta(meta2) {
1740
1740
  invalidRequest(`meta.${key} \u5FC5\u987B\u4E3A\u4E0D\u8D85\u8FC7 ${limit} \u5B57\u7684\u5B57\u7B26\u4E32\u6216 null`);
1741
1741
  }
1742
1742
  }
1743
- if (meta2.avatar != null) {
1744
- const value = meta2.avatar;
1743
+ if (meta2.avatar !== void 0) validateBuddyAvatar(meta2.avatar);
1744
+ }
1745
+ function validateBuddyAvatar(value) {
1746
+ if (value !== null) {
1745
1747
  let valid = false;
1746
1748
  if (typeof value === "string" && value.length > 0 && value.length <= 2048 && !/[\s\u0000-\u001f]/u.test(value)) {
1747
1749
  valid = /^\/media\/[A-Za-z0-9_.-]+$/u.test(value);
@@ -1753,7 +1755,7 @@ function validateBuddyMeta(meta2) {
1753
1755
  }
1754
1756
  }
1755
1757
  }
1756
- 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");
1757
1759
  }
1758
1760
  }
1759
1761
 
@@ -3108,6 +3110,7 @@ function meta(value, path) {
3108
3110
  const tagline = optionalText(source.tagline, `${path}.tagline`);
3109
3111
  const intro = optionalText(source.intro, `${path}.intro`, true);
3110
3112
  return Object.freeze({
3113
+ ...source,
3111
3114
  ...name === void 0 ? {} : { name },
3112
3115
  ...avatar === void 0 ? {} : { avatar },
3113
3116
  ...tagline === void 0 ? {} : { tagline },
@@ -3819,7 +3822,11 @@ var HELP = Object.freeze({
3819
3822
  login: "\u7528\u6CD5: buddy-cli login",
3820
3823
  logout: "\u7528\u6CD5: buddy-cli logout",
3821
3824
  push: "\u7528\u6CD5: buddy-cli push [--directory <\u9879\u76EE\u76EE\u5F55>] [--commit <\u672C\u6B21\u6539\u52A8\u8BF4\u660E>]",
3822
- 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`
3823
3830
  });
3824
3831
  function parse2(args, command) {
3825
3832
  const values = /* @__PURE__ */ new Map();
@@ -3831,10 +3838,15 @@ function parse2(args, command) {
3831
3838
  help = true;
3832
3839
  continue;
3833
3840
  }
3834
- 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";
3835
3847
  if (!allowed) throw new CloudCommandUsageError(`\u672A\u77E5\u53C2\u6570 ${flag2}`);
3836
3848
  const value = args[index + 1];
3837
- 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`);
3838
3850
  if (values.has(flag2)) throw new CloudCommandUsageError(`${flag2} \u4E0D\u80FD\u91CD\u590D`);
3839
3851
  values.set(flag2, value);
3840
3852
  index += 1;
@@ -3881,6 +3893,7 @@ function printStatus(io, buddy2, packages) {
3881
3893
  io.write(`\u642D\u5B50\uFF1A${displayName}\uFF08${buddy2.id}\uFF09`);
3882
3894
  if (buddy2.meta?.tagline) io.write(`\u4E00\u53E5\u8BDD\u4ECB\u7ECD\uFF1A${buddy2.meta.tagline}`);
3883
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}`);
3884
3897
  io.write(`\u4EE3\u7801\uFF1A${buddy2.pushed ? "\u5DF2\u4E0A\u4F20" : "\u672A\u4E0A\u4F20"}`);
3885
3898
  if (buddy2.version) io.write(`\u7EBF\u4E0A\u7248\u672C\uFF1A${buddy2.version}`);
3886
3899
  io.write(`\u8FD0\u884C\uFF1A${buddy2.online ? "\u5728\u7EBF" : "\u79BB\u7EBF"}`);
@@ -3941,6 +3954,39 @@ async function runPush(parsed, io, options) {
3941
3954
  io.write("\u672C\u6B21 push \u53EA\u63D0\u4EA4\u5BA1\u6838\uFF0C\u4E0D\u4F1A\u90E8\u7F72\u6216\u53D1\u5E03 Agent\u3002");
3942
3955
  return { exitCode: 0, buddyId: config.buddyId, version: receipt.version };
3943
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
+ }
3944
3990
  async function runCloudCommand(command, args, io, options = {}) {
3945
3991
  try {
3946
3992
  const parsed = parse2(args, command);
@@ -3957,6 +4003,7 @@ async function runCloudCommand(command, args, io, options = {}) {
3957
4003
  }
3958
4004
  if (command === "logout") return await runLogout(io, options);
3959
4005
  if (command === "push") return await runPush(parsed, io, options);
4006
+ if (command === "avatar") return await runAvatar(parsed, io, options);
3960
4007
  const root = await (options.resolveProjectRoot ?? requireBuddyProjectRoot)(requestedDirectory(options, parsed));
3961
4008
  const manifest = await (options.readManifest ?? readBuddyProjectManifest)(root);
3962
4009
  if (options.mode === "local-mock") {
@@ -5678,6 +5725,7 @@ var HELP2 = `\u642D\u642D Developer Platform CLI
5678
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>]
5679
5726
  buddy-cli dev [--app-server <URL>] [--directory <\u9879\u76EE\u76EE\u5F55>]
5680
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>]
5681
5729
  buddy-cli models [--json]
5682
5730
  buddy-cli widgets sync | check | verify
5683
5731
  buddy-cli datasets [--directory <\u9879\u76EE\u76EE\u5F55>] [--json]
@@ -5693,6 +5741,7 @@ var HELP2 = `\u642D\u642D Developer Platform CLI
5693
5741
  datasets \u8BFB\u53D6\u5DE5\u7A0B Runtime \u63D0\u4F9B\u7684\u6570\u636E\u96C6\u76EE\u5F55\uFF08\u65E0\u9700\u767B\u5F55\uFF09
5694
5742
  push \u4E0A\u4F20 Agent \u5DE5\u7A0B\u548C commit\uFF0C\u63D0\u4EA4\u5E73\u53F0\u5BA1\u6838
5695
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
5696
5745
  preview \u6253\u5F00\u642D\u642D App \u79C1\u804A\u6A21\u62DF\u5668\u4E0E\u8C03\u8BD5\u9875\u9762
5697
5746
  help \u67E5\u770B\u5E2E\u52A9
5698
5747
 
@@ -6088,7 +6137,7 @@ async function runBuddyCli(args, io, options = {}) {
6088
6137
  ...options.dev
6089
6138
  });
6090
6139
  }
6091
- if (command === "login" || command === "logout" || command === "push" || command === "status") {
6140
+ if (command === "login" || command === "logout" || command === "push" || command === "status" || command === "avatar") {
6092
6141
  return await runCloudCommand(command, rest, io, {
6093
6142
  cwd: options.cwd,
6094
6143
  ...options.cloud