@dptech-corp/bohr-cli 2.6.19 → 2.6.21
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 +23 -0
- package/package.json +11 -7
- package/postinstall.js +145 -0
package/CHANGELOG.md
CHANGED
|
@@ -15,6 +15,29 @@
|
|
|
15
15
|
|
|
16
16
|
## [Unreleased]
|
|
17
17
|
|
|
18
|
+
## [2.6.21] - 2026-08-13
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
|
|
22
|
+
- `bohr job log` 与 `bohr job download` 恢复接受 Bohr ID 位置参数;位置参数可重复,也可与现有 `--id/-i` 混用,旧脚本无需改写即可继续下载日志和结果文件。`job log/download/kill/terminate` 共用的 ID 解析现在会在请求前拒绝 `0` 和负数。
|
|
23
|
+
|
|
24
|
+
## [2.6.20] - 2026-08-13
|
|
25
|
+
|
|
26
|
+
### Added
|
|
27
|
+
|
|
28
|
+
- `bohr wenyon` 子命令对所有用户开放,不再需要 entitlements 权限。
|
|
29
|
+
- `npm install -g @dptech-corp/bohr-cli` 现在通过 postinstall 自动下载对应平台的 wenyon-cli(external 变体),无需额外操作。
|
|
30
|
+
- `bohr auth login` 成功后自动写入 `~/.vouch/state.json`,wenyon-cli 认证无缝衔接。
|
|
31
|
+
- `bohr auth logout` 同时清理 wenyon 认证状态。
|
|
32
|
+
- `bohr wenyon` 调用前自动检测并刷新过期的 wenyon token。
|
|
33
|
+
- wenyon-cli 下载新增 SHA256 校验。
|
|
34
|
+
- 新增独立安装脚本 `scripts/install.sh`(Linux/macOS)和 `scripts/install.ps1`(Windows)。
|
|
35
|
+
|
|
36
|
+
### Changed
|
|
37
|
+
|
|
38
|
+
- wenyon-cli 下载改用 `variant=external` 参数获取外部版产物。
|
|
39
|
+
- wenyon 平台检测扩展支持 windows-amd64 和 windows-arm64。
|
|
40
|
+
|
|
18
41
|
## [2.6.19] - 2026-08-13
|
|
19
42
|
|
|
20
43
|
### Breaking
|
package/package.json
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dptech-corp/bohr-cli",
|
|
3
|
-
"version": "2.6.
|
|
3
|
+
"version": "2.6.21",
|
|
4
4
|
"description": "CLI tool for Bohrium scientific computing platform",
|
|
5
5
|
"bin": {
|
|
6
6
|
"bohr": "run.js"
|
|
7
7
|
},
|
|
8
|
+
"scripts": {
|
|
9
|
+
"postinstall": "node postinstall.js"
|
|
10
|
+
},
|
|
8
11
|
"keywords": [
|
|
9
12
|
"bohrium",
|
|
10
13
|
"scientific-computing",
|
|
@@ -25,14 +28,15 @@
|
|
|
25
28
|
],
|
|
26
29
|
"files": [
|
|
27
30
|
"run.js",
|
|
31
|
+
"postinstall.js",
|
|
28
32
|
"CHANGELOG.md"
|
|
29
33
|
],
|
|
30
34
|
"optionalDependencies": {
|
|
31
|
-
"@dptech-corp/bohr-cli-darwin-arm64": "2.6.
|
|
32
|
-
"@dptech-corp/bohr-cli-darwin-amd64": "2.6.
|
|
33
|
-
"@dptech-corp/bohr-cli-linux-amd64": "2.6.
|
|
34
|
-
"@dptech-corp/bohr-cli-linux-arm64": "2.6.
|
|
35
|
-
"@dptech-corp/bohr-cli-windows-amd64": "2.6.
|
|
36
|
-
"@dptech-corp/bohr-cli-windows-arm64": "2.6.
|
|
35
|
+
"@dptech-corp/bohr-cli-darwin-arm64": "2.6.21",
|
|
36
|
+
"@dptech-corp/bohr-cli-darwin-amd64": "2.6.21",
|
|
37
|
+
"@dptech-corp/bohr-cli-linux-amd64": "2.6.21",
|
|
38
|
+
"@dptech-corp/bohr-cli-linux-arm64": "2.6.21",
|
|
39
|
+
"@dptech-corp/bohr-cli-windows-amd64": "2.6.21",
|
|
40
|
+
"@dptech-corp/bohr-cli-windows-arm64": "2.6.21"
|
|
37
41
|
}
|
|
38
42
|
}
|
package/postinstall.js
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* postinstall: downloads wenyon-cli (external) for the current platform.
|
|
4
|
+
* Runs after `npm install -g @dptech-corp/bohr-cli`.
|
|
5
|
+
* Failure is non-fatal — bohr-cli works without wenyon, and `bohr tools install wenyon`
|
|
6
|
+
* can retry later.
|
|
7
|
+
*/
|
|
8
|
+
const https = require("https");
|
|
9
|
+
const http = require("http");
|
|
10
|
+
const fs = require("fs");
|
|
11
|
+
const path = require("path");
|
|
12
|
+
const os = require("os");
|
|
13
|
+
const crypto = require("crypto");
|
|
14
|
+
|
|
15
|
+
const WENYON_SERVER = "https://wenyon.dp.tech";
|
|
16
|
+
const INSTALL_DIR = path.join(os.homedir(), ".bohr", "tools", "wenyon", "current");
|
|
17
|
+
|
|
18
|
+
function getPlatform() {
|
|
19
|
+
const p = os.platform();
|
|
20
|
+
const a = os.arch();
|
|
21
|
+
const platformMap = { darwin: "darwin", linux: "linux", win32: "windows" };
|
|
22
|
+
const archMap = { x64: "amd64", arm64: "arm64" };
|
|
23
|
+
const mp = platformMap[p];
|
|
24
|
+
const ma = archMap[a];
|
|
25
|
+
if (!mp || !ma) return null;
|
|
26
|
+
return `${mp}-${ma}`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function get(url) {
|
|
30
|
+
return new Promise((resolve, reject) => {
|
|
31
|
+
const mod = url.startsWith("https") ? https : http;
|
|
32
|
+
mod.get(url, { headers: { "User-Agent": "bohr-cli-postinstall" } }, (res) => {
|
|
33
|
+
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
34
|
+
return resolve(get(res.headers.location));
|
|
35
|
+
}
|
|
36
|
+
if (res.statusCode !== 200) {
|
|
37
|
+
res.resume();
|
|
38
|
+
return reject(new Error(`HTTP ${res.statusCode} from ${url}`));
|
|
39
|
+
}
|
|
40
|
+
const chunks = [];
|
|
41
|
+
res.on("data", (c) => chunks.push(c));
|
|
42
|
+
res.on("end", () => resolve(Buffer.concat(chunks)));
|
|
43
|
+
res.on("error", reject);
|
|
44
|
+
}).on("error", reject);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function downloadToFile(url, dest, timeoutMs = 300000) {
|
|
49
|
+
return new Promise((resolve, reject) => {
|
|
50
|
+
const mod = url.startsWith("https") ? https : http;
|
|
51
|
+
const follow = (u) => {
|
|
52
|
+
const req = mod.get(u, { headers: { "User-Agent": "bohr-cli-postinstall" }, timeout: timeoutMs }, (res) => {
|
|
53
|
+
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
54
|
+
res.resume();
|
|
55
|
+
return follow(res.headers.location);
|
|
56
|
+
}
|
|
57
|
+
if (res.statusCode !== 200) {
|
|
58
|
+
res.resume();
|
|
59
|
+
return reject(new Error(`HTTP ${res.statusCode}`));
|
|
60
|
+
}
|
|
61
|
+
const file = fs.createWriteStream(dest);
|
|
62
|
+
const hash = crypto.createHash("sha256");
|
|
63
|
+
res.on("data", (chunk) => {
|
|
64
|
+
file.write(chunk);
|
|
65
|
+
hash.update(chunk);
|
|
66
|
+
});
|
|
67
|
+
res.on("end", () => {
|
|
68
|
+
file.end(() => resolve(hash.digest("hex")));
|
|
69
|
+
});
|
|
70
|
+
res.on("error", (e) => { file.close(); reject(e); });
|
|
71
|
+
});
|
|
72
|
+
req.on("error", reject);
|
|
73
|
+
req.on("timeout", () => { req.destroy(); reject(new Error("download timed out")); });
|
|
74
|
+
};
|
|
75
|
+
follow(url);
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async function main() {
|
|
80
|
+
const platform = getPlatform();
|
|
81
|
+
if (!platform) {
|
|
82
|
+
// Unsupported platform for wenyon — skip silently
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const metaUrl = `${WENYON_SERVER}/cli/releases/latest/download?platform=${platform}&variant=external`;
|
|
87
|
+
|
|
88
|
+
let meta;
|
|
89
|
+
try {
|
|
90
|
+
const buf = await get(metaUrl);
|
|
91
|
+
meta = JSON.parse(buf.toString());
|
|
92
|
+
} catch (e) {
|
|
93
|
+
console.error(`[postinstall] wenyon-cli: could not fetch release info (${e.message}), skipping`);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (!meta.url) {
|
|
98
|
+
console.error("[postinstall] wenyon-cli: no download URL in release response, skipping");
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Check if already installed and up-to-date
|
|
103
|
+
const ext = platform.startsWith("windows") ? ".exe" : "";
|
|
104
|
+
const destPath = path.join(INSTALL_DIR, `wenyon-cli${ext}`);
|
|
105
|
+
|
|
106
|
+
if (fs.existsSync(destPath) && meta.version) {
|
|
107
|
+
try {
|
|
108
|
+
const { execFileSync } = require("child_process");
|
|
109
|
+
const out = execFileSync(destPath, ["version"], { encoding: "utf8", timeout: 5000 });
|
|
110
|
+
if (out.includes(meta.version)) {
|
|
111
|
+
console.log(`[postinstall] wenyon-cli ${meta.version} already installed`);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
} catch (_) {
|
|
115
|
+
// version check failed, proceed with install
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
console.log(`[postinstall] Installing wenyon-cli ${meta.version || ""} (${platform})...`);
|
|
120
|
+
|
|
121
|
+
fs.mkdirSync(INSTALL_DIR, { recursive: true });
|
|
122
|
+
|
|
123
|
+
const tmpPath = destPath + ".tmp";
|
|
124
|
+
try {
|
|
125
|
+
const actualHash = await downloadToFile(meta.url, tmpPath);
|
|
126
|
+
|
|
127
|
+
if (meta.sha256 && actualHash !== meta.sha256) {
|
|
128
|
+
fs.unlinkSync(tmpPath);
|
|
129
|
+
console.error(`[postinstall] wenyon-cli: SHA256 mismatch (expected ${meta.sha256}, got ${actualHash}), skipping`);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
fs.chmodSync(tmpPath, 0o755);
|
|
134
|
+
fs.renameSync(tmpPath, destPath);
|
|
135
|
+
console.log(`[postinstall] wenyon-cli ${meta.version || ""} installed to ${destPath}`);
|
|
136
|
+
} catch (e) {
|
|
137
|
+
try { fs.unlinkSync(tmpPath); } catch (_) {}
|
|
138
|
+
console.error(`[postinstall] wenyon-cli: download failed (${e.message}), skipping`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
main().catch((e) => {
|
|
143
|
+
// postinstall failures must not break npm install
|
|
144
|
+
console.error(`[postinstall] wenyon-cli: ${e.message}`);
|
|
145
|
+
});
|