@my-life-buddies/cli 0.21.0 → 0.22.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 +19 -43
- package/dist/bin/buddy.js +83 -35
- package/dist/bin/buddy.js.map +4 -4
- package/dist/bin/core.js +491 -524
- package/dist/bin/core.js.map +4 -4
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
这份说明按一次开发过程展开:登记搭子,准备工程,在本地预览,然后上传程序包。所有搭子统一使用 `@my-life-buddies/buddy-runtime`,业务能力通过 Prompt、`src/buddy-options.mjs` 和 Tool 实现。
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
新建工程动态查询公共 npm 的最新稳定版 Runtime,并写入准确版本与锁文件;查询或锁文件生成失败时停止,不回退旧版本。版本选择与联调范围见 [Runtime 集成说明](../../docs/runtime-integration.md)。
|
|
8
8
|
|
|
9
9
|
## 准备 CLI 和平台地址
|
|
10
10
|
|
|
@@ -49,7 +49,7 @@ buddy-cli update
|
|
|
49
49
|
|
|
50
50
|
从 CLI 0.17.0 起,每条正常命令(含 `guide` 和无参数入口)先查询公共 npm `latest`,当前版本落后时自动更新,并由新版执行原命令。无需手动先运行 `update`,等待当前命令完成即可。更新发生在创建工程、领取凭据、启动 DEV 或上传之前;保留参数、工作目录、终端输入输出和退出状态,一次调用最多自动切换一次。版本相同或更高时继续执行,不降级;已经运行的 DEV 不因新版本发布而中断。
|
|
51
51
|
|
|
52
|
-
全局安装更新当前 npm 环境中对应的 CLI;源码、`npm link`、项目内安装和 `npx` 自动下载准确版本到 `~/.cache/buddy-cli/updates/releases/`,从缓存运行,不改写原安装或工程依赖。并发更新共用安装锁。手动 `update` 仍只用于 npm 全局安装。查询最多等待 10
|
|
52
|
+
全局安装更新当前 npm 环境中对应的 CLI;源码、`npm link`、项目内安装和 `npx` 自动下载准确版本到 `~/.cache/buddy-cli/updates/releases/`,从缓存运行,不改写原安装或工程依赖。并发更新共用安装锁。手动 `update` 仍只用于 npm 全局安装。查询最多等待 10 秒,安装(含重试)最多等待 180 秒。安装通过 `--prefer-online` 刷新 npm 版本缓存;找不到版本(`ETARGET`)时最多重试一次,始终安装本次自检查到的准确版本。仍失败时说明 npm 的具体原因,不展示日志路径,也不修改用户的 npm 配置或清空缓存;失败或取消时停止原业务命令,不回退旧版。帮助、各命令 `--help`、`--version` 和应急清理命令 `dev stop` 不联网更新。自动更新进度写入 stderr,不混入业务命令的 stdout 或 JSON;更新失败时 `--json` 返回 `code=CLI_UPDATE_FAILED` 和 `error`。
|
|
53
53
|
|
|
54
54
|
更新只针对 CLI,已有工程的 Runtime 依赖、锁文件和业务适配仍需另行修改与验证。旧 CLI 不会自动获得自检能力,需要先用 npm 安装命令升级一次。
|
|
55
55
|
|
|
@@ -71,17 +71,17 @@ npm run verify:package
|
|
|
71
71
|
npm publish --workspace @my-life-buddies/cli
|
|
72
72
|
```
|
|
73
73
|
|
|
74
|
-
|
|
74
|
+
`main` 构建正式的 `@my-life-buddies/cli@latest`,只包含 `buddy-cli` 命令。`publishConfig` 明确指定 `latest`、公共 npm 和 `public` 访问级别;构建会拒绝预发布版本。正式发布必须从 main 重新构建,不可将测试产物直接改挂 latest。Core 和 Preview 保留 monorepo 开发边界并标记为 `private`,构建时合入 CLI 的内部模块;Preview 页面和工程模板资源进入 CLI 包;Creator 与 Avatar Skill 使用时独立加载。安装不会请求 `@buddy/cli-core` 或 `@buddy/preview`。第三方运行依赖按正常 npm dependencies 安装,构建工具 esbuild 不进入安装依赖。根工作区和 Web 同样保持 `private`。
|
|
75
75
|
|
|
76
76
|
版本维护:每批修改 CLI 发布内容时递增一次版本,默认 patch;根包和内部工作区版本、依赖引用、锁文件一起更新。Agent 工程自己的项目版本独立。升级 Runtime 时同步模板依赖与模板锁文件,并运行独立安装验收。
|
|
77
77
|
|
|
78
|
-
CLI
|
|
78
|
+
正式版 CLI 固定连接 ECS Test `https://47.116.168.81`,无需配置地址:
|
|
79
79
|
|
|
80
80
|
```bash
|
|
81
81
|
buddy-cli login
|
|
82
82
|
```
|
|
83
83
|
|
|
84
|
-
|
|
84
|
+
这是实际的 ECS Test 环境,使用 HTTPS;不能改为其他平台或本机网关。手机 App 需要连接同一环境。
|
|
85
85
|
|
|
86
86
|
CLI 会打开搭搭创作者平台网页完成登录和授权。浏览器已有有效 Cookie 时,页面直接显示当前账号,开发者确认后即可返回终端;没有登录时,先在同一网页完成短信登录,再确认授权。CLI 不读取浏览器 Cookie,也拿不到短信验证码,只通过本机回调收到一次性授权码,再换取自己的会话。
|
|
87
87
|
|
|
@@ -337,9 +337,9 @@ buddy-cli meta update --buddy-id b_example --name "川大厨" --avatar ./avatar.
|
|
|
337
337
|
buddy-cli models
|
|
338
338
|
```
|
|
339
339
|
|
|
340
|
-
|
|
340
|
+
不必先创建工程。无论是否在工程内,CLI 每次查询公共 npm latest,把对应 Runtime 缓存到 `~/.cache/buddy-cli/runtimes/<版本>` 并读取枚举;同版本复用缓存,不修改工程依赖。查询或下载失败时明确报错,不把旧缓存称为最新版。两个目录命令的 `--json` 返回 `source`(固定为 `npm`)、`runtimeVersion`、目录,以及 `projectRuntimeVersion`、`latestRuntimeVersion`、`versionStatus`、`adaptationRequired`。版本状态为 `no_project`、`unconfigured`、`current`、`update_available` 或 `project_ahead`;没有准确工程版本时返回 `null`,工程未锁定版本或版本与 npm latest 不一致时需要适配。提示输出到 stderr,stdout 保持纯 JSON。
|
|
341
341
|
|
|
342
|
-
在已有工程执行 `buddy-cli`、`init` 或打开 `preview`
|
|
342
|
+
在已有工程执行 `buddy-cli`、`init` 或打开 `preview` 时检查更新并提示适配,但允许继续编辑工程。正式包中,`dev`、Preview 中每次启动 DEV、文件自动重载,以及 `push` 必须联网查询 npm 最新稳定版,工程声明及实际安装版本必须与本次查询结果完全一致;不接受旧版、超前版、预发布版或范围依赖。查询失败即停止,不使用缓存冒充最新,也没有跳过检查参数。已有 npm 锁文件需与目标版本一致,push 还会按本次查询结果校验实际上传快照及其中的 npm 锁文件。失败信息包含原因和适配提示,CLI 不自动修改工程依赖、模型或数据权限。修复后重新启动;自动重载失败后保存文件可重试。帮助、登录、status、meta 和兼容命令 avatar 不查询 Runtime。
|
|
343
343
|
|
|
344
344
|
此限制由本版 CLI 执行,不修改服务端策略或已部署进程;直接运行工程 `npm start`、旧 CLI 或服务端发布入口不受本版 CLI 检查约束。
|
|
345
345
|
|
|
@@ -433,45 +433,21 @@ Preview 展示平台对话记录、发送与流式输出耗时、会话状态和
|
|
|
433
433
|
|
|
434
434
|
保存代码、提示词、资料或 Widget 后,CLI 会合并连续修改并自动重启 Runtime;可能中断当前回复。已有 Widget 数据保留,Schema 变更不会自动迁移旧数据。原聊天历史从 MLB 读取,不因浏览器刷新就另建一份;服务端数据的保留期限不由 CLI 决定。
|
|
435
435
|
|
|
436
|
-
###
|
|
436
|
+
### 正式包的平台与 Runtime
|
|
437
437
|
|
|
438
|
-
|
|
438
|
+
正式包固定连接 ECS Test:`https://47.116.168.81`,后台为 `https://47.116.168.81/developer/`。无需手动设置 `MLB_GATEWAY_URL`,也不询问开发或发布环境。
|
|
439
439
|
|
|
440
|
-
|
|
440
|
+
- 登录、API、凭据领取、预览与上传均使用固定目标;CLI 将该网关及开发 Token 写入工程 `.env` 给 Runtime 使用。
|
|
441
|
+
- `--app-server`、`--developer-web` 仅接受同一固定目标,兼容已有后台连接指令,不能切换环境。
|
|
442
|
+
- `MLB_GATEWAY_URL`、`BUDDY_APP_SERVER_URL`、`BUDDY_DEV_APP_SERVER_URL`、`BUDDY_DEVELOPER_WEB_URL` 任一冲突都会报错;显式正确参数不能掩盖其他冲突配置。按提示移除终端及 shell 配置里的旧值,重新打开 Coding Agent 或终端后重试。
|
|
443
|
+
- 创建或恢复工程、读取或修改工程资料、预览、DEV 和上传都会检查工程 `.env`。其他环境工程请使用对应 CLI;迁移到公共平台需在新目录重新登记搭子后复制业务代码,不复制 `.env`、buddyId 或凭据。`--refresh-token` 仅刷新同一环境的开发凭据。
|
|
444
|
+
- 登录态按平台 origin 保存,开发 Token 与本地实例锁继续按平台和搭子隔离。不读取旧的无平台归属登录记录。CLI 地址限制不代替 Server 的账号、归属及凭据环境校验。
|
|
441
445
|
|
|
442
|
-
|
|
443
|
-
buddy-cli login
|
|
444
|
-
buddy-cli dev --refresh-token
|
|
445
|
-
# 或连接后台,再在页面中启动 DEV:
|
|
446
|
-
buddy-cli preview --refresh-token
|
|
447
|
-
```
|
|
448
|
-
|
|
449
|
-
DEV 启动前会从阿里云平台重新领取已有开发 Token,并更新 `.env` 的 `MLB_GATEWAY_URL`;保留 `package.json.buddyId`、业务变量和注释,不另建搭子。`preview --refresh-token` 在页面实际启动 DEV 时写入配置。工程 Runtime 和锁文件仍须按 CLI 提示升级至 npm 最新稳定版;直接运行 `npm start` 的工程也需更新旧网关环境变量,显式配置会覆盖 Runtime 默认值。
|
|
450
|
-
|
|
451
|
-
### 什么时候需要另一个服务地址
|
|
452
|
-
|
|
453
|
-
CLI 与 Runtime 共用 `MLB_GATEWAY_URL`。需要连接其他平台时,在运行 CLI 的终端设置平台提供的地址(仅协议、域名和可选端口,不加 `/cli` 或 `/developer`):
|
|
454
|
-
|
|
455
|
-
```bash
|
|
456
|
-
export MLB_GATEWAY_URL=https://platform.example
|
|
457
|
-
buddy-cli login
|
|
458
|
-
buddy-cli preview
|
|
459
|
-
```
|
|
460
|
-
|
|
461
|
-
将示例地址替换成实际平台地址。设置在当前终端及其子进程中生效;要在新终端保留,可加入已有的 shell 启动配置。Coding Agent 执行 CLI 的进程同样需要继承这个变量;图形应用未必继承另一个终端中的设置。无需新增 `config.json`、工程平台字段或另一份 npm 包。平台地址不影响 CLI 自动更新、Runtime 和 Skill 从公共 npm 下载。
|
|
462
|
-
|
|
463
|
-
| 命令 | 地址优先级(从高到低) |
|
|
464
|
-
| --- | --- |
|
|
465
|
-
| `login`、`init`、`logout`、`meta`、`push`、`status` | `MLB_GATEWAY_URL` → 旧地址配置 → 默认 test |
|
|
466
|
-
| `dev`、`preview`(包括 `dev stop`) | `--app-server` → `MLB_GATEWAY_URL` → 旧地址配置 → 默认 test |
|
|
467
|
-
|
|
468
|
-
旧配置只在未设置 `MLB_GATEWAY_URL` 时兼容:账号和上传命令依次读取 `BUDDY_APP_SERVER_URL`、`BUDDY_DEV_APP_SERVER_URL`;`dev`、`preview` 顺序相反。新配置只需设置 `MLB_GATEWAY_URL`,它会统一覆盖这两种旧变量。空值、错误地址和跨平台的后台地址会报错,不静默回退。远程平台要求 HTTPS;本机 loopback 允许 HTTP。
|
|
469
|
-
|
|
470
|
-
CLI 根据选定地址打开 `/developer/` 网页、访问 MLB API,并在启动 DEV 时把该地址和开发 Token 写入工程 `.env`。Runtime 通过 Node 加载 `.env` 中的 `MLB_GATEWAY_URL`。CLI 本身不自动加载项目 `.env` 或读取 shell 启动文件来选平台,因此 `login` 和新建工程也能在工程外使用。修改变量仅影响后续命令,不会让正在运行的预览中途切换。
|
|
446
|
+
临时保留同一 ECS 的旧入口迁移:`http://47.116.168.81:8788` 和 `http://47.116.168.81` 转为 HTTPS。启动 DEV 时校验归属,取得实例锁后更新 `.env`,保留业务配置与注释;失败不改文件。正式推广完成后可移除此兼容分支。
|
|
471
447
|
|
|
472
|
-
|
|
448
|
+
`models`、`datasets` 和新建工程动态查询公共 npm 的 Runtime `latest`,只接受正式版本;新工程固定准确版本与锁文件。DEV、自动重载及 push 要求工程声明、实际安装和锁文件与本次最新正式版一致;不提供 `--runtime-version` 或测试版选择,不自动修改已有依赖。CLI 与 Runtime 的版本号无需一致。Runtime 发布者须在 ECS Test 支持对应能力后才更新 `latest`。
|
|
473
449
|
|
|
474
|
-
|
|
450
|
+
正式 CLI 自动更新也只查询 `latest`;若该标签误指向预发布版本,停止并提示发布者修正,不跨到测试渠道。
|
|
475
451
|
|
|
476
452
|
## 上传程序包,不等于发布
|
|
477
453
|
|
|
@@ -530,7 +506,7 @@ buddy-cli datasets
|
|
|
530
506
|
buddy-cli datasets --directory ./my-buddy --json
|
|
531
507
|
```
|
|
532
508
|
|
|
533
|
-
|
|
509
|
+
正式包的目录来自 npm 最新稳定版 Runtime 的 `DATA_ACCESS_CAPABILITIES`,包括 ID、名称、来源和 Schema 版本。JSON 返回版本信息、适配状态和 `datasets` 数组(字段见上方模型目录说明)。命令不登录、不启动搭子、不申请权限,也不修改配置;从子目录运行会向上找到工程。每次都需要联网检查 latest,下载失败时明确报错,不把旧缓存称为最新版。
|
|
534
510
|
|
|
535
511
|
开发者将实际选择的 ID 和用途写进 `data-access.json.requirements`。JSON Schema 检查形状与用途;DEV 和上传预检按工程安装的 Runtime 检查所选模型与非空数据声明。目录缺失、依赖未安装或版本不匹配时明确报错。Runtime 0.12.2 有 10 项,但单次数据查询仍最多 8 项。
|
|
536
512
|
|
|
@@ -570,4 +546,4 @@ Runtime 0.19.0 支持在 `schema.json.openTargets` 声明入口。业务通过 `
|
|
|
570
546
|
|
|
571
547
|
## CLI 0.20:MLB 统一提供服务
|
|
572
548
|
|
|
573
|
-
|
|
549
|
+
正式包入口固定与 ECS Test 网页同源,使用 HTTPS。CLI 的一次性浏览器授权走 `/cli/web/authorizations`、`/cli/web/exchange`,预览连接走 `/cli/preview/*`。不调用独立 Web 服务,不支持地址覆盖;预览不触发上传或发布。
|
package/dist/bin/buddy.js
CHANGED
|
@@ -9,6 +9,7 @@ import { dirname as dirname2 } from "node:path";
|
|
|
9
9
|
import { createInterface } from "node:readline/promises";
|
|
10
10
|
import {
|
|
11
11
|
PromptCancelledError,
|
|
12
|
+
resolvePlatformUrl as resolvePlatformUrl2,
|
|
12
13
|
runBuddyCli
|
|
13
14
|
} from "./core.js";
|
|
14
15
|
|
|
@@ -69,6 +70,7 @@ import {
|
|
|
69
70
|
CloudAuthenticator,
|
|
70
71
|
BuddyDevError,
|
|
71
72
|
checkRuntimeUpdate,
|
|
73
|
+
checkProjectGateway,
|
|
72
74
|
DEFAULT_MLB_TEST_URL,
|
|
73
75
|
HttpDeveloperPlatformClient,
|
|
74
76
|
LoopbackBrowserLoginAdapter,
|
|
@@ -103,12 +105,14 @@ var PREVIEW_COMMAND_HELP = `\u7528\u6CD5:
|
|
|
103
105
|
--no-open \u4EC5\u7528\u4E8E\u540E\u53F0\u9884\u89C8\uFF1B\u76F4\u63A5\u6267\u884C preview \u4ECD\u81EA\u52A8\u6253\u5F00\u540E\u53F0\u3002
|
|
104
106
|
--local \u662F\u540E\u53F0\u4E0D\u53EF\u7528\u65F6\u7684\u72EC\u7ACB\u672C\u5730\u9884\u89C8\u5907\u7528\u5165\u53E3\uFF0C--port \u4EC5\u4E0E --local \u4E00\u8D77\u4F7F\u7528\u3002
|
|
105
107
|
\u4FDD\u6301\u7EC8\u7AEF\u8FD0\u884C\uFF1BCtrl+C \u6216\u5173\u95ED\u7EC8\u7AEF\u4F1A\u505C\u6B62 DEV \u5E76\u65AD\u5F00\u8FDE\u63A5\uFF0C\u5237\u65B0\u540E\u53F0\u4E0D\u4F1A\u81EA\u52A8\u542F\u52A8 DEV\u3002
|
|
108
|
+
DEV \u5931\u8D25\u5148\u67E5\u770B\u5177\u4F53\u9519\u8BEF\u548C\u8FD0\u884C\u65E5\u5FD7\uFF1B\u5347\u7EA7 CLI \u540E\u9000\u51FA\u65E7 preview \u8FDB\u7A0B\u5E76\u91CD\u65B0\u8FDE\u63A5\uFF0C\u518D\u542F\u52A8 DEV\u3002
|
|
106
109
|
\u540E\u53F0\u53EF\u5F3A\u5236\u65AD\u8FDE\uFF1B\u672C\u673A\u505C\u6B62\u672A\u786E\u8BA4\u65F6\uFF0C\u5728\u539F\u5DE5\u7A0B\u76EE\u5F55\u6267\u884C buddy-cli dev stop\u3002\u8BE5\u547D\u4EE4\u4E0D\u91CD\u8FDE\u3001\u4E0D\u91CD\u542F\u3002
|
|
107
110
|
\u672A\u914D\u7F6E\u5730\u5740\u65F6\u8FDE\u63A5 MLB \u6D4B\u8BD5\u73AF\u5883 ${DEFAULT_MLB_TEST_URL}\uFF08HTTPS\uFF09\u3002
|
|
108
|
-
|
|
111
|
+
\u6B63\u5F0F\u7248\u56FA\u5B9A\u8FDE\u63A5 ECS Test\uFF1B\u5730\u5740\u53C2\u6570\u53EA\u6821\u9A8C\u56FA\u5B9A\u76EE\u6807\uFF0C\u4E0D\u80FD\u5207\u6362\u5E73\u53F0\u3002Runtime \u7F51\u5173\u7531 CLI \u6CE8\u5165\u3002
|
|
109
112
|
CLI \u7EDF\u4E00\u542F\u52A8\u5E76\u7BA1\u7406\u5DE5\u7A0B\u4E2D\u7684\u5B98\u65B9 Runtime\uFF1B\u6BCF\u6B21\u542F\u52A8\u6216\u91CD\u8F7D\u5FC5\u987B\u901A\u8FC7 npm \u6700\u65B0\u7A33\u5B9A\u7248\u68C0\u67E5\u3002
|
|
110
113
|
\u8EAB\u4EFD\u8BFB\u53D6 package.json.buddyId\uFF1B.env \u4FDD\u5B58 Token\uFF0C\u542F\u52A8\u524D\u5411 Server \u6821\u9A8C\u6240\u5C5E\u642D\u5B50\u3002
|
|
111
|
-
|
|
114
|
+
\u8FDE\u63A5\u524D\u81EA\u68C0 .env \u7F51\u5173\uFF1B\u5DF2\u77E5\u65E7 ECS \u5730\u5740\u5728\u542F\u52A8 DEV \u65F6\u6821\u9A8C\u5F52\u5C5E\u5E76\u81EA\u52A8\u66F4\u65B0\uFF0C\u4E0D\u540C\u5E73\u53F0\u4ECD\u9700\u660E\u786E\u786E\u8BA4\u3002
|
|
115
|
+
--refresh-token \u91CD\u65B0\u9886\u53D6\u5DF2\u6709\u5F00\u53D1 Token\uFF0C\u66F4\u65B0\u540C\u4E00\u73AF\u5883\u7684\u5DE5\u7A0B .env\uFF1B\u4E0D\u80FD\u5207\u6362\u5E73\u53F0\uFF0C\u4E0D\u4F1A\u751F\u6210\u65B0\u5BC6\u94A5\u3002
|
|
112
116
|
Widget \u6D88\u606F\u5361\u7247\u4FDD\u7559\u6307\u5B9A\u8BB0\u5F55\u7684\u6253\u5F00\u76EE\u6807\uFF0C\u5C0F\u6302\u4EF6\u5217\u8868\u6253\u5F00\u9ED8\u8BA4\u89C6\u56FE\u3002
|
|
113
117
|
\u6A21\u62DF\u5668\u4F7F\u7528\u5F53\u524D\u5F00\u53D1\u8005\u8D26\u53F7\u8BBF\u95EE <buddyId>-dev \u8C03\u8BD5\u5206\u8EAB\u3002`;
|
|
114
118
|
function valueAfter(args, index, flag) {
|
|
@@ -251,7 +255,7 @@ var BuddyPlatformHost = class {
|
|
|
251
255
|
baseUrl,
|
|
252
256
|
token: async () => (await session.token({ signal: this.#signal })).accessToken
|
|
253
257
|
}),
|
|
254
|
-
runtimeUpdate: { ...this.#runtimeUpdate, env: this.#env
|
|
258
|
+
runtimeUpdate: { ...this.#runtimeUpdate, env: this.#env },
|
|
255
259
|
preparePush
|
|
256
260
|
};
|
|
257
261
|
}
|
|
@@ -280,12 +284,13 @@ var BuddyPlatformHost = class {
|
|
|
280
284
|
return { exitCode: 0, route: "preview" };
|
|
281
285
|
}
|
|
282
286
|
const projectRoot = await requireBuddyAgentProjectRoot(resolve(process.cwd(), parsed.directory));
|
|
283
|
-
const baseUrl = resolvePlatformUrl({ env: this.#env, override: parsed.appServer
|
|
287
|
+
const baseUrl = resolvePlatformUrl({ env: this.#env, override: parsed.appServer });
|
|
284
288
|
const manifest = await readBuddyProjectManifest(projectRoot);
|
|
285
289
|
if (parsed.buddyId && parsed.buddyId !== manifest.buddyId) throw new Error(`\u5F53\u524D\u5DE5\u7A0B\u5C5E\u4E8E ${manifest.buddyId}\uFF0C\u8FDE\u63A5\u6307\u4EE4\u8981\u6C42 ${parsed.buddyId}\uFF1B\u8BF7\u5728\u6B63\u786E\u642D\u5B50\u7684\u5DE5\u7A0B\u76EE\u5F55\u6267\u884C\u3002`);
|
|
286
290
|
const webUrl = resolveDeveloperWebUrl(baseUrl, parsed.developerWeb ?? this.#env.BUDDY_DEVELOPER_WEB_URL);
|
|
287
291
|
const signal = this.#signal ?? new AbortController().signal;
|
|
288
|
-
await
|
|
292
|
+
await checkProjectGateway(projectRoot, baseUrl, { report: (message) => io.write(message) });
|
|
293
|
+
await checkRuntimeUpdate(projectRoot, (message) => io.writeError(message), { ...this.#runtimeUpdate, signal, env: this.#env });
|
|
289
294
|
const session = this.#session(baseUrl, webUrl);
|
|
290
295
|
await session.token({ signal });
|
|
291
296
|
const starter = this.#previewStarter(baseUrl, manifest.buddyId, session, parsed.refreshToken ?? false);
|
|
@@ -356,10 +361,10 @@ var BuddyPlatformHost = class {
|
|
|
356
361
|
const handle = await starter.start({
|
|
357
362
|
projectRoot,
|
|
358
363
|
signal,
|
|
359
|
-
runtimeUpdate: { ...this.#runtimeUpdate, env: this.#env
|
|
364
|
+
runtimeUpdate: { ...this.#runtimeUpdate, env: this.#env },
|
|
360
365
|
onError(error) {
|
|
361
366
|
logs.flush();
|
|
362
|
-
let message = error.message;
|
|
367
|
+
let message = error.publicMessage ?? error.message;
|
|
363
368
|
for (const secret of secrets) if (secret) message = message.split(secret).join("[REDACTED]");
|
|
364
369
|
reloadError = { code: error.code, message: message.replace(/[\u0000-\u001f\u007f]/gu, " ").slice(0, 512) };
|
|
365
370
|
},
|
|
@@ -423,6 +428,7 @@ var BuddyPlatformHost = class {
|
|
|
423
428
|
return resolvePlatformUrl({ env: this.#env });
|
|
424
429
|
}
|
|
425
430
|
#session(baseUrl, webUrl) {
|
|
431
|
+
resolvePlatformUrl({ env: this.#env, override: baseUrl.href });
|
|
426
432
|
const developerWebUrl = resolveDeveloperWebUrl(baseUrl, webUrl ?? this.#env.BUDDY_DEVELOPER_WEB_URL);
|
|
427
433
|
const key = baseUrl.origin;
|
|
428
434
|
let session = this.#sessions.get(key);
|
|
@@ -495,10 +501,54 @@ async function withUpdateLock(path, signal, action) {
|
|
|
495
501
|
}
|
|
496
502
|
}
|
|
497
503
|
|
|
504
|
+
// apps/cli/src/npm-update-install.ts
|
|
505
|
+
import { stripVTControlCharacters as stripVTControlCharacters2 } from "node:util";
|
|
506
|
+
function redact(text) {
|
|
507
|
+
return text.replace(/https?:\/\/[^\s<>"']+/giu, (value) => {
|
|
508
|
+
try {
|
|
509
|
+
const url = new URL(value);
|
|
510
|
+
url.username = "";
|
|
511
|
+
url.password = "";
|
|
512
|
+
url.search = "";
|
|
513
|
+
url.hash = "";
|
|
514
|
+
return url.toString();
|
|
515
|
+
} catch {
|
|
516
|
+
return "[URL]";
|
|
517
|
+
}
|
|
518
|
+
}).replace(/\bBearer\s+\S+/giu, "Bearer [REDACTED]").replace(/\b(?:_authToken|_auth|token|password|authorization)\s*[:=]\s*\S+/giu, "[REDACTED]").replace(/\bnpm_[A-Za-z0-9]+/gu, "[REDACTED]");
|
|
519
|
+
}
|
|
520
|
+
function npmFailure(cause) {
|
|
521
|
+
const error = cause;
|
|
522
|
+
const stderr2 = stripVTControlCharacters2(typeof error?.stderr === "string" ? error.stderr.slice(-32768) : "");
|
|
523
|
+
const lines = stderr2.split(/\r?\n/u).map((line) => line.match(/^npm (?:error|ERR!)\s+(.*)$/u)?.[1]).filter((line) => !!line);
|
|
524
|
+
const code = lines.map((line) => line.match(/^code\s+(E[A-Z0-9_]+)\b/u)?.[1]).find(Boolean) ?? (typeof error?.code === "string" && /^E[A-Z0-9_]+$/u.test(error.code) ? error.code : error?.killed ? "ETIMEDOUT" : "UNKNOWN");
|
|
525
|
+
const reason = lines.filter((line) => !/^(?:code |A complete log |A complete log can|Log files |In most cases|If you |Note:)/u.test(line) && !/debug[^\r\n]*\.log\s*$/u.test(line)).slice(0, 3).map(redact).join(" ").slice(0, 700);
|
|
526
|
+
return { code, reason };
|
|
527
|
+
}
|
|
528
|
+
async function installCliWithNpm(args, settings, runNpm) {
|
|
529
|
+
const deadline = Date.now() + settings.timeout;
|
|
530
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
531
|
+
settings.signal?.throwIfAborted();
|
|
532
|
+
try {
|
|
533
|
+
const timeout = deadline - Date.now();
|
|
534
|
+
if (timeout <= 0) throw Object.assign(new Error("install timeout"), { code: "ETIMEDOUT" });
|
|
535
|
+
await runNpm([...args, "--prefer-online"], { ...settings, timeout });
|
|
536
|
+
return;
|
|
537
|
+
} catch (cause) {
|
|
538
|
+
settings.signal?.throwIfAborted();
|
|
539
|
+
const { code, reason } = npmFailure(cause);
|
|
540
|
+
if (code === "ETARGET" && attempt === 0 && Date.now() < deadline) continue;
|
|
541
|
+
const hint = code === "ETARGET" ? `npm \u5C1A\u672A\u63D0\u4F9B\u6240\u9700\u7248\u672C\uFF1B${attempt > 0 ? "\u5DF2\u8054\u7F51\u5237\u65B0\u5E76\u91CD\u8BD5\u4E00\u6B21" : "\u8054\u7F51\u5237\u65B0\u540E\u4ECD\u627E\u4E0D\u5230\u8BE5\u7248\u672C"}\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002` : code === "EACCES" || code === "EPERM" ? "\u8BF7\u68C0\u67E5 npm \u5B89\u88C5\u76EE\u5F55\u548C\u7F13\u5B58\u76EE\u5F55\u7684\u5199\u5165\u6743\u9650\u3002" : code === "EBADENGINE" ? "\u8BF7\u68C0\u67E5 Node.js \u7248\u672C\u662F\u5426\u6EE1\u8DB3\u5305\u7684\u8981\u6C42\u3002" : ["ENOTFOUND", "ECONNRESET", "ECONNREFUSED", "ETIMEDOUT", "EAI_AGAIN"].includes(code) ? "\u8BF7\u68C0\u67E5\u5230 npm \u7684\u7F51\u7EDC\u8FDE\u63A5\u540E\u91CD\u8BD5\u3002" : "\u8BF7\u6839\u636E\u4EE5\u4E0A\u539F\u56E0\u5904\u7406\u540E\u91CD\u8BD5\u3002";
|
|
542
|
+
throw new Error(`npm \u5B89\u88C5\u672A\u5B8C\u6210\uFF08${code}\uFF09\u3002${reason ? `${reason}
|
|
543
|
+
` : ""}${hint}`);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
|
|
498
548
|
// apps/cli/src/self-update.ts
|
|
499
549
|
var PACKAGE = "@my-life-buddies/cli";
|
|
500
550
|
var REGISTRY = "https://registry.npmjs.org/";
|
|
501
|
-
var MANUAL_UPDATE = `npm install --global ${PACKAGE}@latest --registry=${REGISTRY}`;
|
|
551
|
+
var MANUAL_UPDATE = `npm install --global ${PACKAGE}@latest --registry=${REGISTRY} --prefer-online`;
|
|
502
552
|
var execute = promisify(execFile);
|
|
503
553
|
var HELP = `\u7528\u6CD5:
|
|
504
554
|
buddy-cli --version [--json]
|
|
@@ -511,6 +561,7 @@ var HELP = `\u7528\u6CD5:
|
|
|
511
561
|
|
|
512
562
|
\u65E0\u9700\u767B\u5F55\u642D\u642D\u8D26\u53F7\uFF0C\u4E5F\u65E0\u9700\u8FDB\u5165\u642D\u5B50\u5DE5\u7A0B\u3002
|
|
513
563
|
\u6B63\u5E38\u547D\u4EE4\uFF08\u542B guide\uFF09\u4F1A\u5148\u8054\u7F51\u81EA\u68C0\uFF0C\u81EA\u52A8\u66F4\u65B0\u540E\u7531\u65B0\u7248\u7EE7\u7EED\u6267\u884C\uFF1B\u7B49\u5F85\u5B8C\u6210\u5373\u53EF\u3002
|
|
564
|
+
\u5B89\u88C5\u4E3B\u52A8\u5237\u65B0 npm \u7248\u672C\u7F13\u5B58\uFF0C\u627E\u4E0D\u5230\u7248\u672C\uFF08ETARGET\uFF09\u65F6\u6700\u591A\u91CD\u8BD5\u4E00\u6B21\uFF1B\u5931\u8D25\u8BF4\u660E\u5177\u4F53\u539F\u56E0\u3002
|
|
514
565
|
--help\u3001\u5404\u547D\u4EE4 --help \u4E0E --version \u79BB\u7EBF\u53EF\u7528\uFF1B\u67E5\u8BE2\u6216\u66F4\u65B0\u5931\u8D25\u65F6\u505C\u6B62\u4E1A\u52A1\u64CD\u4F5C\u3002
|
|
515
566
|
update \u7528\u4E8E\u5355\u72EC\u66F4\u65B0\u5F53\u524D npm \u5168\u5C40\u5B89\u88C5\u7684 CLI\uFF0C\u4E0D\u4FEE\u6539\u642D\u5B50\u5DE5\u7A0B\u7684 Runtime \u4F9D\u8D56\u3002
|
|
516
567
|
\u5DF2\u7ECF\u662F\u6700\u65B0\u7248\u6216\u5F53\u524D\u7248\u672C\u66F4\u9AD8\u65F6\u4E0D\u5B89\u88C5\u3001\u4E0D\u964D\u7EA7\u3002
|
|
@@ -558,7 +609,7 @@ async function latestVersion(options) {
|
|
|
558
609
|
if (!response.ok) throw new Error(`npm \u8FD4\u56DE HTTP ${response.status}`);
|
|
559
610
|
const metadata = await response.json();
|
|
560
611
|
if (metadata?.name !== PACKAGE) throw new Error("npm \u8FD4\u56DE\u7684\u5305\u540D\u4E0D\u5339\u914D");
|
|
561
|
-
parseVersion(metadata.version);
|
|
612
|
+
if (parseVersion(metadata.version).length !== 3) throw new Error("npm latest \u6307\u5411\u4E86\u6D4B\u8BD5\u7248\uFF0C\u6B63\u5F0F CLI \u4E0D\u4F1A\u8DE8\u6E20\u9053\u66F4\u65B0\uFF1B\u8BF7\u8054\u7CFB\u53D1\u5E03\u8005\u4FEE\u6B63 latest \u6807\u7B7E");
|
|
562
613
|
return metadata.version;
|
|
563
614
|
} catch (cause) {
|
|
564
615
|
if (options.signal?.aborted) throw new Error("\u64CD\u4F5C\u5DF2\u53D6\u6D88\u3002");
|
|
@@ -586,7 +637,7 @@ async function installUpdate(version, options) {
|
|
|
586
637
|
if (current.name === PACKAGE && current.version === version) return;
|
|
587
638
|
if (current.name === PACKAGE && compareVersions(current.version, version) > 0) throw new Error("\u53E6\u4E00\u4E2A\u8FDB\u7A0B\u5DF2\u5B89\u88C5\u66F4\u65B0\u7684 CLI\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C\u547D\u4EE4\u3002");
|
|
588
639
|
try {
|
|
589
|
-
await
|
|
640
|
+
await installCliWithNpm([
|
|
590
641
|
"install",
|
|
591
642
|
"--global",
|
|
592
643
|
`${PACKAGE}@${version}`,
|
|
@@ -597,11 +648,11 @@ async function installUpdate(version, options) {
|
|
|
597
648
|
"--engine-strict",
|
|
598
649
|
"--no-audit",
|
|
599
650
|
"--no-fund"
|
|
600
|
-
], { ...settings, timeout: 18e4 });
|
|
651
|
+
], { ...settings, timeout: 18e4 }, runNpm);
|
|
601
652
|
} catch (cause) {
|
|
602
653
|
if (options.signal?.aborted) throw new Error("\u66F4\u65B0\u5DF2\u53D6\u6D88\uFF0C\u8BF7\u8FD0\u884C buddy-cli --version \u68C0\u67E5\u5B89\u88C5\u72B6\u6001\u3002");
|
|
603
|
-
|
|
604
|
-
|
|
654
|
+
throw new Error(`${cause instanceof Error ? cause.message : "npm \u5B89\u88C5\u672A\u5B8C\u6210\u3002"}
|
|
655
|
+
\u4E5F\u53EF\u624B\u52A8\u5B89\u88C5\uFF1A${MANUAL_UPDATE}`);
|
|
605
656
|
}
|
|
606
657
|
const installed = JSON.parse(await readFile(join2(installedRoot, "package.json"), "utf8"));
|
|
607
658
|
if (installed.name !== PACKAGE || installed.version !== version) {
|
|
@@ -729,26 +780,22 @@ async function prepareLatest(version, options) {
|
|
|
729
780
|
const temporary = await mkdtemp(join3(cache, "releases", ".install-"));
|
|
730
781
|
try {
|
|
731
782
|
await writeFile2(join3(temporary, "package.json"), JSON.stringify({ private: true }));
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
} catch (cause) {
|
|
749
|
-
const code = cause && typeof cause === "object" && "code" in cause ? String(cause.code) : "unknown";
|
|
750
|
-
throw new Error(`\u65B0\u7248 CLI \u7F13\u5B58\u5B89\u88C5\u5931\u8D25\uFF08${code}\uFF09\uFF0C\u8BF7\u68C0\u67E5\u7F51\u7EDC\u3001Node.js \u7248\u672C\u548C\u76EE\u5F55\u6743\u9650\u540E\u91CD\u8BD5\u3002`);
|
|
751
|
-
}
|
|
783
|
+
await installCliWithNpm(
|
|
784
|
+
[
|
|
785
|
+
"install",
|
|
786
|
+
"--prefix",
|
|
787
|
+
temporary,
|
|
788
|
+
"--save-exact",
|
|
789
|
+
`${PACKAGE2}@${version}`,
|
|
790
|
+
`--registry=${REGISTRY2}`,
|
|
791
|
+
`--@my-life-buddies:registry=${REGISTRY2}`,
|
|
792
|
+
"--engine-strict",
|
|
793
|
+
"--no-audit",
|
|
794
|
+
"--no-fund"
|
|
795
|
+
],
|
|
796
|
+
{ cwd: temporary, signal: options.signal, timeout: 18e4 },
|
|
797
|
+
runNpm
|
|
798
|
+
);
|
|
752
799
|
await checkedEntry(join3(temporary, "node_modules", PACKAGE2), version);
|
|
753
800
|
options.signal?.throwIfAborted();
|
|
754
801
|
await rm2(destination, { recursive: true, force: true });
|
|
@@ -912,12 +959,13 @@ try {
|
|
|
912
959
|
const command = args[0];
|
|
913
960
|
let platformHost;
|
|
914
961
|
const host = () => platformHost ??= new BuddyPlatformHost({ signal: lifecycle.signal });
|
|
962
|
+
const offlineHelp = !command ? false : ["help", "--help", "-h"].includes(command) || args.includes("--help") || args.includes("-h");
|
|
963
|
+
if (maintenance === void 0 && !offlineHelp) resolvePlatformUrl2();
|
|
915
964
|
const result = maintenance ?? await runBuddyCli(args, terminal, {
|
|
916
965
|
runtimeCatalog: { signal: lifecycle.signal },
|
|
917
|
-
scaffoldPlatformAgent: (root, name
|
|
966
|
+
scaffoldPlatformAgent: (root, name) => scaffoldPlatformAgent(root, name, {
|
|
918
967
|
resolveDependencies: (template) => latestRuntimeTemplate(template, {
|
|
919
968
|
signal: lifecycle.signal,
|
|
920
|
-
runtimeVersion,
|
|
921
969
|
report: (message) => terminal.write(message)
|
|
922
970
|
})
|
|
923
971
|
}),
|