@dptech-corp/bohr-cli 2.6.43 → 2.6.46

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
@@ -16,6 +16,31 @@
16
16
 
17
17
  ## [Unreleased]
18
18
 
19
+ ## [2.6.46] - 2026-08-24
20
+
21
+ ### Added
22
+
23
+ - **`bohr config set openapi_host` 支持 UAT 环境**:白名单新增 `https://open.uat.bohrium.com`。
24
+
25
+ ### Fixed
26
+
27
+ - **companion 扩展生命周期修复**:配套扩展的发现与管理在特定条件下失效,现已修正。
28
+ - **CI 发布构建 strip 符号表**:六平台二进制缩小约 30%,解决 artifact 超限。
29
+
30
+ ## [2.6.45] - 未发布(版本号跳过)
31
+
32
+ CI artifact 超限导致发布失败,变更随 2.6.46 发出。
33
+
34
+ ## [2.6.44] - 2026-08-24
35
+
36
+ ### Fixed
37
+
38
+ - **`job list`、`job_group list` 与 notebook 六条命令补回机读输出的 `meta.request_id`**:此前重建信封时丢失,出问题无 ID 可追。
39
+ - **不发请求的命令不再编造 `meta.request_id`**:2.6.43 只把字段改可选,六条命令仍在编;dry run 也不再报。
40
+ - **`billing recharge`、`dataset create`、`sandbox template delete` 的机读输出补上 `meta`**:此前完全没有。
41
+ - **配套扩展可完整管理**:CLI 或 npm 安装的 trisol/wenyon 现可被 list/info/verify/pin/remove 识别;remove 需 `--yes`。
42
+
43
+
19
44
  ## [2.6.43] - 2026-08-23
20
45
 
21
46
  ### Breaking
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dptech-corp/bohr-cli",
3
- "version": "2.6.43",
3
+ "version": "2.6.46",
4
4
  "description": "CLI tool for Bohrium scientific computing platform",
5
5
  "bin": {
6
6
  "bohr": "run.js"
@@ -32,11 +32,11 @@
32
32
  "CHANGELOG.md"
33
33
  ],
34
34
  "optionalDependencies": {
35
- "@dptech-corp/bohr-cli-darwin-arm64": "2.6.43",
36
- "@dptech-corp/bohr-cli-darwin-amd64": "2.6.43",
37
- "@dptech-corp/bohr-cli-linux-amd64": "2.6.43",
38
- "@dptech-corp/bohr-cli-linux-arm64": "2.6.43",
39
- "@dptech-corp/bohr-cli-windows-amd64": "2.6.43",
40
- "@dptech-corp/bohr-cli-windows-arm64": "2.6.43"
35
+ "@dptech-corp/bohr-cli-darwin-arm64": "2.6.46",
36
+ "@dptech-corp/bohr-cli-darwin-amd64": "2.6.46",
37
+ "@dptech-corp/bohr-cli-linux-amd64": "2.6.46",
38
+ "@dptech-corp/bohr-cli-linux-arm64": "2.6.46",
39
+ "@dptech-corp/bohr-cli-windows-amd64": "2.6.46",
40
+ "@dptech-corp/bohr-cli-windows-arm64": "2.6.46"
41
41
  }
42
42
  }
package/postinstall.js CHANGED
@@ -14,13 +14,73 @@ const os = require("os");
14
14
  const crypto = require("crypto");
15
15
 
16
16
  const WENYON_SERVER = "https://wenyon.dp.tech";
17
- const INSTALL_DIR = path.join(os.homedir(), ".bohr", "tools", "wenyon", "current");
17
+ const WENYON_ROOT = path.join(os.homedir(), ".bohr", "tools", "wenyon");
18
+ const INSTALL_DIR = path.join(WENYON_ROOT, "current");
18
19
 
19
20
  // trisol is installed from the trisol manifest protocol (trisol-manifest).
20
21
  // BOHR_TRISOL_SERVER / BOHR_TRISOL_CHANNEL let a dev build point at a non-prod
21
22
  // env (e.g. https://trisol-dev.dp.tech + channel dev).
22
23
  const TRISOL_SERVER = process.env.BOHR_TRISOL_SERVER || "https://trisol.dp.tech";
23
- const TRISOL_INSTALL_DIR = path.join(os.homedir(), ".bohr", "tools", "trisol", "current");
24
+ const TRISOL_ROOT = path.join(os.homedir(), ".bohr", "tools", "trisol");
25
+ const TRISOL_INSTALL_DIR = path.join(TRISOL_ROOT, "current");
26
+
27
+ function readPinnedHash(toolRoot) {
28
+ const manifestPath = path.join(toolRoot, "manifest.yaml");
29
+ try {
30
+ const text = fs.readFileSync(manifestPath, "utf8");
31
+ try {
32
+ return JSON.parse(text).pinned_hash || "";
33
+ } catch (_) {
34
+ const match = text.match(/^pinned_hash:\s*(?:"([^"]*)"|'([^']*)'|(\S*))\s*$/m);
35
+ return match ? (match[1] || match[2] || match[3] || "") : "";
36
+ }
37
+ } catch (_) {
38
+ return "";
39
+ }
40
+ }
41
+
42
+ function writeManagedManifest(toolRoot, { name, version, executable, sha256, pinnedHash = "" }) {
43
+ const manifest = {
44
+ name,
45
+ version: version || "",
46
+ description: "Managed companion CLI installed by bohr",
47
+ binary: path.join("current", executable),
48
+ scopes: [],
49
+ trust: "community",
50
+ billing: "none",
51
+ signature: "",
52
+ public_key: "",
53
+ sha256,
54
+ pinned_hash: pinnedHash,
55
+ };
56
+ fs.mkdirSync(toolRoot, { recursive: true });
57
+ const manifestPath = path.join(toolRoot, "manifest.yaml");
58
+ const temporaryPath = `${manifestPath}.${process.pid}.tmp`;
59
+ fs.writeFileSync(temporaryPath, `${JSON.stringify(manifest, null, 2)}\n`, { mode: 0o600 });
60
+ try {
61
+ try {
62
+ fs.renameSync(temporaryPath, manifestPath);
63
+ } catch (error) {
64
+ if (process.platform !== "win32" || !["EEXIST", "EPERM"].includes(error.code)) {
65
+ throw error;
66
+ }
67
+ fs.rmSync(manifestPath, { force: true });
68
+ fs.renameSync(temporaryPath, manifestPath);
69
+ }
70
+ } finally {
71
+ fs.rmSync(temporaryPath, { force: true });
72
+ }
73
+ }
74
+
75
+ function hashFile(filePath) {
76
+ return new Promise((resolve, reject) => {
77
+ const hash = crypto.createHash("sha256");
78
+ const input = fs.createReadStream(filePath);
79
+ input.on("data", (chunk) => hash.update(chunk));
80
+ input.on("end", () => resolve(hash.digest("hex")));
81
+ input.on("error", reject);
82
+ });
83
+ }
24
84
 
25
85
  function getPlatform() {
26
86
  const p = os.platform();
@@ -113,29 +173,39 @@ async function installTrisol() {
113
173
  const ext = osName === "windows" ? ".exe" : "";
114
174
  const destPath = path.join(TRISOL_INSTALL_DIR, `trisol${ext}`);
115
175
 
116
- // Skip re-download when the installed binary already matches this version.
176
+ let expectedHash;
177
+ try {
178
+ const buf = await get(shaURL);
179
+ expectedHash = buf.toString().trim().split(/\s+/)[0];
180
+ } catch (e) {
181
+ console.error(`[postinstall] trisol: could not fetch sha256 (${e.message}), skipping`);
182
+ return;
183
+ }
184
+
185
+ // Retain an existing binary only when both its reported version and its
186
+ // publisher-provided hash match. This also repairs metadata omitted by older
187
+ // postinstall versions without treating the local file as its own authority.
117
188
  if (fs.existsSync(destPath)) {
118
189
  try {
119
190
  const { execFileSync } = require("child_process");
120
191
  const out = execFileSync(destPath, ["version"], { encoding: "utf8", timeout: 5000 });
121
- if (out.includes(version)) {
192
+ const localHash = await hashFile(destPath);
193
+ if (out.includes(version) && localHash === expectedHash) {
194
+ writeManagedManifest(TRISOL_ROOT, {
195
+ name: "trisol",
196
+ version,
197
+ executable: `trisol${ext}`,
198
+ sha256: localHash,
199
+ pinnedHash: readPinnedHash(TRISOL_ROOT),
200
+ });
122
201
  console.log(`[postinstall] trisol ${version} already installed`);
123
202
  return;
124
203
  }
125
204
  } catch (_) {
126
- // version check failed, proceed with install
205
+ // version/hash check failed, proceed with install
127
206
  }
128
207
  }
129
208
 
130
- let expectedHash;
131
- try {
132
- const buf = await get(shaURL);
133
- expectedHash = buf.toString().trim().split(/\s+/)[0];
134
- } catch (e) {
135
- console.error(`[postinstall] trisol: could not fetch sha256 (${e.message}), skipping`);
136
- return;
137
- }
138
-
139
209
  console.log(`[postinstall] Installing trisol ${version} (${platform}, variant=bohrium)...`);
140
210
  fs.mkdirSync(TRISOL_INSTALL_DIR, { recursive: true });
141
211
  const tmpPath = destPath + ".tmp";
@@ -148,6 +218,12 @@ async function installTrisol() {
148
218
  }
149
219
  fs.chmodSync(tmpPath, 0o755);
150
220
  fs.renameSync(tmpPath, destPath);
221
+ writeManagedManifest(TRISOL_ROOT, {
222
+ name: "trisol",
223
+ version,
224
+ executable: `trisol${ext}`,
225
+ sha256: actualHash,
226
+ });
151
227
  console.log(`[postinstall] trisol ${version} installed to ${destPath}`);
152
228
  } catch (e) {
153
229
  try { fs.unlinkSync(tmpPath); } catch (_) {}
@@ -185,7 +261,15 @@ async function main() {
185
261
  try {
186
262
  const { execFileSync } = require("child_process");
187
263
  const out = execFileSync(destPath, ["version"], { encoding: "utf8", timeout: 5000 });
188
- if (out.includes(meta.version)) {
264
+ const localHash = await hashFile(destPath);
265
+ if (out.includes(meta.version) && (!meta.sha256 || localHash === meta.sha256)) {
266
+ writeManagedManifest(WENYON_ROOT, {
267
+ name: "wenyon",
268
+ version: meta.version,
269
+ executable: `wenyon-cli${ext}`,
270
+ sha256: localHash,
271
+ pinnedHash: readPinnedHash(WENYON_ROOT),
272
+ });
189
273
  console.log(`[postinstall] wenyon-cli ${meta.version} already installed`);
190
274
  return;
191
275
  }
@@ -210,6 +294,12 @@ async function main() {
210
294
 
211
295
  fs.chmodSync(tmpPath, 0o755);
212
296
  fs.renameSync(tmpPath, destPath);
297
+ writeManagedManifest(WENYON_ROOT, {
298
+ name: "wenyon",
299
+ version: meta.version,
300
+ executable: `wenyon-cli${ext}`,
301
+ sha256: actualHash,
302
+ });
213
303
  console.log(`[postinstall] wenyon-cli ${meta.version || ""} installed to ${destPath}`);
214
304
  } catch (e) {
215
305
  try { fs.unlinkSync(tmpPath); } catch (_) {}
@@ -217,7 +307,11 @@ async function main() {
217
307
  }
218
308
  }
219
309
 
220
- main().catch((e) => {
221
- // postinstall failures must not break npm install
222
- console.error(`[postinstall] wenyon-cli: ${e.message}`);
223
- });
310
+ if (require.main === module) {
311
+ main().catch((e) => {
312
+ // postinstall failures must not break npm install
313
+ console.error(`[postinstall] wenyon-cli: ${e.message}`);
314
+ });
315
+ }
316
+
317
+ module.exports = { readPinnedHash, writeManagedManifest };