@dptech-corp/bohr-cli 2.6.19-preview.597 → 2.6.20
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 +19 -0
- package/package.json +11 -7
- package/postinstall.js +145 -0
package/CHANGELOG.md
CHANGED
|
@@ -15,6 +15,25 @@
|
|
|
15
15
|
|
|
16
16
|
## [Unreleased]
|
|
17
17
|
|
|
18
|
+
## [2.6.20] - 2026-08-13
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
- `bohr wenyon` 子命令对所有用户开放,不再需要 entitlements 权限。
|
|
23
|
+
- `npm install -g @dptech-corp/bohr-cli` 现在通过 postinstall 自动下载对应平台的 wenyon-cli(external 变体),无需额外操作。
|
|
24
|
+
- `bohr auth login` 成功后自动写入 `~/.vouch/state.json`,wenyon-cli 认证无缝衔接。
|
|
25
|
+
- `bohr auth logout` 同时清理 wenyon 认证状态。
|
|
26
|
+
- `bohr wenyon` 调用前自动检测并刷新过期的 wenyon token。
|
|
27
|
+
- wenyon-cli 下载新增 SHA256 校验。
|
|
28
|
+
- 新增独立安装脚本 `scripts/install.sh`(Linux/macOS)和 `scripts/install.ps1`(Windows)。
|
|
29
|
+
|
|
30
|
+
### Changed
|
|
31
|
+
|
|
32
|
+
- wenyon-cli 下载改用 `variant=external` 参数获取外部版产物。
|
|
33
|
+
- wenyon 平台检测扩展支持 windows-amd64 和 windows-arm64。
|
|
34
|
+
|
|
35
|
+
## [2.6.19] - 2026-08-13
|
|
36
|
+
|
|
18
37
|
### Breaking
|
|
19
38
|
|
|
20
39
|
- **`bohr file` 的远端路径改为由 `personal/` 或 `share/` 前缀唯一决定空间**。改前:多数子命令会把任意路径直接发给后端,并可能用 `--project-id` 或 `--space` 推断空间;改后:个人盘只接受 `--project-id 0`,共享盘要求正数 `--project-id`,非法前缀、除 `file list` 外的根目录操作和跨空间复制/移动会在请求前报错,省略 `file list` 路径或传 `/` 均表示个人盘根目录。调用方需给路径补上对应空间前缀,并为 `share/...` 传正整数 `--project-id`。
|
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.20",
|
|
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-
|
|
32
|
-
"@dptech-corp/bohr-cli-darwin-
|
|
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.20",
|
|
36
|
+
"@dptech-corp/bohr-cli-darwin-amd64": "2.6.20",
|
|
37
|
+
"@dptech-corp/bohr-cli-linux-amd64": "2.6.20",
|
|
38
|
+
"@dptech-corp/bohr-cli-linux-arm64": "2.6.20",
|
|
39
|
+
"@dptech-corp/bohr-cli-windows-amd64": "2.6.20",
|
|
40
|
+
"@dptech-corp/bohr-cli-windows-arm64": "2.6.20"
|
|
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
|
+
});
|