@dptech-corp/bohr-cli 2.6.1 → 2.6.3

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/CHANGELOG.md CHANGED
@@ -14,6 +14,31 @@
14
14
 
15
15
  ## [Unreleased]
16
16
 
17
+ ## [2.6.3] - 2026-08-08
18
+
19
+ ### Added
20
+
21
+ - **npm 包新增 README,并公告存量用户升级路径**。npm 页面此前没有任何说明文字,而 2.6.2 修复的自更新缺陷有一个无法由代码解决的死角:2.6.1 及以下版本跑的是各自内置的旧更新器,`bohr update` 在这些版本上必然失败,修复永远送不到他们手里。README 置顶写明:存量用户需手动执行一次 `npm install -g @dptech-corp/bohr-cli@latest`,此后即可恢复 `bohr update` 自更新。同时附安装说明、快速开始与文档入口。
22
+
23
+ ### Breaking
24
+
25
+ - **`bohr image pull` 不再接受非 Bohrium registry 的镜像地址**。改前:地址改写是一句无校验的 `strings.Replace(addr, "registry.dp.tech", …)`,地址里没有这段就原样放行——于是 `bohr image pull ubuntu:22.04` 会先登录 Bohrium registry、再从 **Docker Hub** 把镜像拉下来,并报告成功;命令做的事和它的名字不是一回事。改后:只接受 `registry.dp.tech/`、`registry.bohrium.dp.tech/`、`registry-test.bohrium.dp.tech/` 开头的地址,其余返回 `VALIDATION_FAILED` 并在 `hint.command` 里给出对应的 `docker pull` 命令。调用方要怎么改:拉非 Bohrium 镜像直接用 `docker pull`,本命令只负责 Bohrium 镜像。
26
+
27
+ ### Fixed
28
+
29
+ - **`bohr image pull` 缺参数时不再返回退出码 0**。改前:不带地址时打印两行提示后 `return nil`,退出码 0、无信封——Agent 会把「忘了传参」读成「镜像已经在本地了」。现在返回 `VALIDATION_FAILED` 信封、非零退出码,并在 `hint` 里给出完整示例命令。
30
+ - **`bohr image pull` 全链路改为信封输出**。改前:成功、无 AccessKey、docker 失败、超时四个出口全是 `fmt.Println` 纯文本,`-o json` 完全无效;无 AccessKey 时是一句裸文本加退出码 1,而同一目录下的 `bohr image list` 对同一种情况返回 `AUTH_REQUIRED` 信封加退出码 2。现在四个出口都是信封:成功回 `{image, requested, registry}`;无 AccessKey 回 `AUTH_REQUIRED`(退出码 2,与其余命令一致);本机没有 docker 回 `PRECONDITION_FAILED` 并说明本命令依赖本地 Docker daemon;超时回 `UPSTREAM_TIMEOUT`、`retryable=true`,保留原有的「先查 `docker images` 和 `df -h`」说明。Docker 自身的进度输出改走 stderr,因此 `-o json` 时 stdout 只有一个信封,不再被进度条污染。
31
+ - **修复 test 环境用户被静默指向生产 registry**。改前:registry 选择比对的是 `host == "https://openapi.test.dp.tech"`,而 `config.GetHost()` 是白名单,只可能返回 `open.bohrium.com` / `open.test.bohrium.com` / localhost / 生产默认值,`internal/migration` 还专门把那个旧 host 改写掉——该分支不可达。后果是 test 环境用户拿到生产 registry,用 test AccessKey 登录必然失败且看不出原因。现在按实际可返回的 host 选择 `registry-test.bohrium.dp.tech`。
32
+ - **`bohr image pull` 补齐文档**。此前全仓 `grep "image pull"` 只命中它自己的源文件,任何文档、SKILL、reference 里都没有,用户与 Agent 无从知道这条路存在。`docs/zh/image.md` 新增完整章节(用途、前置条件、参数、失败码与退出码对照),中英文 usage-guide 的镜像段同步补上一行。文档写明了两条容易踩的前提:需要本机 Docker daemon(因此不适用于 Agent / 沙箱 / CI),以及拉取是同步的、全局 `--wait` 对它不起作用。
33
+ - **`bohr schemas errors` 与 `bohr schemas get error.v1` 补上 `UPSTREAM_TIMEOUT` 与 `PRECONDITION_FAILED`,并新增两者的一致性校验**。两个码此前已经在发、也已经各自有退出码映射,却不在这份清单里——一个查不到的错误码,调用方只能靠猜。更要紧的是这两份清单各自手工维护:只补其中一份,CLI 就会自相矛盾——发出一个「自己的错误目录说合法、自己的已发布 schema 判非法」的码,拿真实失败信封去校验会挂在一个正确的信封上。现在两份都补齐,并加了双向校验测试(该包此前零测试)。注:`envelope.Error.ExitCode` 是同一批事实的第三份手工副本,把三者收敛成一份注册表需要改动已发布产物与所有发码的命令,留作后续。
34
+ - **`bohr image pull --dry-run --timeout 0` 不再静默通过**。`--timeout` 的校验此前紧挨着它的使用点,位于 dry-run 分支之后,于是 dry-run 会正常打印计划、对非法的时限只字不提。校验已移到其余入参校验处。
35
+ - **`bohr image pull` 在本机缺少 docker 时补 `error.subtype = docker_not_found`**。`PRECONDITION_FAILED` 命名的是一类失败,subtype 才说清是哪个前置条件,调用方不必解析文案。
36
+ - **`bohr update` 在 2.6.0 分包之后恢复可用**。2.6.0 把六个平台二进制从主包拆进按平台分的子包,`internal/update` 没有跟着改:暂存校验无条件要求主包里存在 `bin/bohr-<goos>-<goarch>`,而 2.6.x 主包已经没有 `bin/` 了,于是升级在暂存阶段就以一句裸 Go 错误失败;装了 2.6.x 之后反方向也断——运行中的二进制位于子包,包名比对必然不等于主包,于是掉进 `installStandalone`,那条路用的是同一个暂存校验。现在所有需要二进制的地方都**先查再用**,胖包与分包两种形态都认。
37
+ 一并修掉的是分包给版本库带来的第二处断裂,它不会自己暴露:`npm install` 会把平台子包**提升**为主包的兄弟目录(实测 npm 10.9.4;评测机上则是嵌套——由 npm 决定,不由发布物决定),而版本库只搬主包,子包随暂存目录一起被删。只放宽暂存校验的话,升级会照常改完软链,再由激活校验发现跑起来的是**全局残留的上一个版本**的二进制,然后回滚——失败点从「任何改动之前」挪到「改动之后」。现在子包会先被移入主包内部,每个版本目录自包含。
38
+ - **`bohr update` 失败改出信封**。改前:失败是一条裸 Go 错误字符串写 stderr,`-o json` 下同样没有信封(无 `error.code`、无 `hint`),而自更新恰恰是调用方最需要能判读的一条路。现在统一为 `PRECONDITION_FAILED` 信封(Windows 上的「不支持事务式自更新」为 `NOT_IMPLEMENTED`),带 `error.subtype` 区分具体前置条件,`hint.command` 一律给出可执行的 `npm install -g @dptech-corp/bohr-cli@<版本>`。
39
+ - **`bohr update --check` 不再引导用户去跑一条在本平台跑不通的命令**。改前:只要有新版就无条件打印 `Run 'bohr update' to install.`,包括 Windows——那里的自更新从来就没实现过。现在 `--check` 与 `update` 结论一致:能自更新才推荐 `bohr update`,否则直接给出对应的 `npm install -g` 命令。
40
+ - **分包后取不到平台子包时 `bohr` 改出信封**。npm 跳过可选依赖时退出码是 0,所以「装完了但跑不起来」此前只表现为 `npm/run.js` 打的三行纯文本;`--omit=optional`、旧版 npm、pnpm 全局装都会走到这里,而这是调用方能碰到的最早一个出口。现在两个出口(子包缺失、平台架构不受支持)都产出 `PRECONDITION_FAILED` 信封并写 stdout,`error.subtype` 分别为 `platform_package_missing` 与 `platform_unsupported`,仍保留「npm 没装上当前平台的可选依赖」这句归因。同时修正退出码透传:子进程被信号杀死时 `e.status` 为 `null`,旧写法 `e.status || 1` 会把它退成 1;现在有退出码就原样透出(实测 `CONFIRMATION_REQUIRED` 的 10 正确透传),被信号杀死则退 `128+signal`。
41
+
17
42
  ## [2.6.1] - 2026-08-07
18
43
 
19
44
  ### Changed
package/README.md ADDED
@@ -0,0 +1,45 @@
1
+ # @dptech-corp/bohr-cli
2
+
3
+ Bohrium 科学计算平台的命令行工具,可执行文件名为 `bohr`。
4
+
5
+ ## ⚠️ 2.6.1 及以下版本用户请手动升级一次
6
+
7
+ 从 2.6.0 起,本包改为按平台拆分分发(全局安装体积从约 193MB 降至约 33MB)。受此影响,**2.6.1 及以下版本内置的 `bohr update` 无法完成自动升级**(会报错退出,不影响已装版本的正常使用)。请执行一次手动升级:
8
+
9
+ ```bash
10
+ npm install -g @dptech-corp/bohr-cli@latest
11
+ ```
12
+
13
+ 升级后 `bohr version` 显示 2.6.2 或更高即成功。2.6.2 起自更新已适配新包结构,后续版本可继续用 `bohr update` 升级。
14
+
15
+ 如安装缓慢或拿不到最新版(镜像源同步延迟),可指定官方源:
16
+
17
+ ```bash
18
+ npm install -g @dptech-corp/bohr-cli@latest --registry https://registry.npmjs.org
19
+ ```
20
+
21
+ ## 安装
22
+
23
+ ```bash
24
+ npm install -g @dptech-corp/bohr-cli
25
+ ```
26
+
27
+ 支持 macOS / Linux / Windows 的 x64 与 arm64。安装时通过 `optionalDependencies` 只下载当前平台对应的二进制子包。
28
+
29
+ ## 快速开始
30
+
31
+ ```bash
32
+ bohr auth login # 登录 Bohrium 账号
33
+ bohr --help # 查看全部命令
34
+ bohr version # 查看当前版本
35
+ bohr update # 自更新到最新版(2.6.2 及以上)
36
+ ```
37
+
38
+ ## 文档与变更记录
39
+
40
+ - 使用文档:https://docs.bohrium.com
41
+ - 变更记录:随包附带的 `CHANGELOG.md`(npm 包页面 Code 标签页内可直接查看)
42
+
43
+ ## License
44
+
45
+ MIT © DP Technology
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dptech-corp/bohr-cli",
3
- "version": "2.6.1",
3
+ "version": "2.6.3",
4
4
  "description": "CLI tool for Bohrium scientific computing platform",
5
5
  "bin": {
6
6
  "bohr": "run.js"
@@ -28,11 +28,11 @@
28
28
  "CHANGELOG.md"
29
29
  ],
30
30
  "optionalDependencies": {
31
- "@dptech-corp/bohr-cli-darwin-arm64": "2.6.1",
32
- "@dptech-corp/bohr-cli-darwin-amd64": "2.6.1",
33
- "@dptech-corp/bohr-cli-linux-amd64": "2.6.1",
34
- "@dptech-corp/bohr-cli-linux-arm64": "2.6.1",
35
- "@dptech-corp/bohr-cli-windows-amd64": "2.6.1",
36
- "@dptech-corp/bohr-cli-windows-arm64": "2.6.1"
31
+ "@dptech-corp/bohr-cli-darwin-arm64": "2.6.3",
32
+ "@dptech-corp/bohr-cli-darwin-amd64": "2.6.3",
33
+ "@dptech-corp/bohr-cli-linux-amd64": "2.6.3",
34
+ "@dptech-corp/bohr-cli-linux-arm64": "2.6.3",
35
+ "@dptech-corp/bohr-cli-windows-amd64": "2.6.3",
36
+ "@dptech-corp/bohr-cli-windows-arm64": "2.6.3"
37
37
  }
38
38
  }
package/run.js CHANGED
@@ -10,9 +10,38 @@ const platformMap = { darwin: "darwin", linux: "linux", win32: "windows" };
10
10
  const mappedArch = archMap[arch];
11
11
  const mappedPlatform = platformMap[platform];
12
12
 
13
+ // This launcher is the only thing in the main package, so its two failure
14
+ // exits are the first thing a caller can hit — before any Go code runs, and on
15
+ // the very first install. Emitting bare text here left `-o json` callers with
16
+ // nothing to branch on but English prose. Exit code 1 matches
17
+ // PRECONDITION_FAILED's mapping in internal/envelope.
18
+ const EXIT_PRECONDITION_FAILED = 1;
19
+
20
+ function failPrecondition(subtype, message, hintCommand) {
21
+ const envelope = {
22
+ ok: false,
23
+ error: {
24
+ code: "PRECONDITION_FAILED",
25
+ subtype,
26
+ http: 412,
27
+ message,
28
+ retryable: false,
29
+ hint: { action: "install_manually", command: hintCommand },
30
+ },
31
+ };
32
+ // stdout, like every other envelope: a caller that pipes stdout to a JSON
33
+ // parser must not have to also merge stderr to find out what happened.
34
+ process.stdout.write(JSON.stringify(envelope) + "\n");
35
+ process.exit(EXIT_PRECONDITION_FAILED);
36
+ }
37
+
13
38
  if (!mappedArch || !mappedPlatform) {
14
- console.error(`Unsupported platform: ${platform}-${arch}`);
15
- process.exit(1);
39
+ failPrecondition(
40
+ "platform_unsupported",
41
+ `bohr does not ship a binary for ${platform}-${arch}; supported targets are ` +
42
+ `darwin/linux/win32 on x64 or arm64`,
43
+ "npm view @dptech-corp/bohr-cli"
44
+ );
16
45
  }
17
46
 
18
47
  const ext = platform === "win32" ? ".exe" : "";
@@ -24,16 +53,31 @@ try {
24
53
  const pkgDir = path.dirname(require.resolve(`${pkgName}/package.json`));
25
54
  binaryPath = path.join(pkgDir, "bin", binaryName);
26
55
  } catch (e) {
27
- console.error(
28
- `Could not find platform package ${pkgName}.\n` +
29
- `This usually means npm failed to install the optional dependency for your platform.\n` +
30
- `Try: npm install -g @dptech-corp/bohr-cli --force`
56
+ // Keep naming the cause: npm reports success (exit 0) when it skips an
57
+ // optional dependency, so "install worked but bohr will not run" is a state
58
+ // the user has no other way to explain. --omit=optional, an old npm, and
59
+ // pnpm's global installs all land here.
60
+ failPrecondition(
61
+ "platform_package_missing",
62
+ `the platform package ${pkgName} is not installed; npm most likely skipped ` +
63
+ `the optional dependency for this platform (--omit=optional and some ` +
64
+ `package managers do this without reporting an error)`,
65
+ "npm install -g @dptech-corp/bohr-cli --force"
31
66
  );
32
- process.exit(1);
33
67
  }
34
68
 
35
69
  try {
36
70
  execFileSync(binaryPath, process.argv.slice(2), { stdio: "inherit" });
37
71
  } catch (e) {
38
- process.exit(e.status || 1);
72
+ // e.status is null when the child was killed by a signal; exiting 1 there
73
+ // would report an ordinary failure for a SIGINT. Exit codes are how the
74
+ // billing gate (10) and every other envelope code reach the caller, so this
75
+ // must pass through untouched when there is one.
76
+ if (typeof e.status === "number") {
77
+ process.exit(e.status);
78
+ }
79
+ if (e.signal) {
80
+ process.exit(128 + (os.constants.signals[e.signal] || 0));
81
+ }
82
+ process.exit(1);
39
83
  }