@guandata/guancli 1.0.61 → 1.0.62

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
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## @guandata/guancli 1.0.62 - 2026-09-19
4
+
5
+ - 安装包按平台拆分:主包只保留启动器、Skill 与文档,原生程序由同版本的 `@guandata/guancli-<平台>-<架构>` 可选依赖提供,安装时只下载当前系统的一份,安装命令与 CLI 行为不变。
6
+ - 平台包缺失或主包与平台包版本不一致时给出可操作提示;新增 `pack:all`、`verify:platforms` 与自动选包/注册表门禁,发布前校验五个平台包。
7
+
3
8
  ## @guandata/guancli 1.0.61 - 2026-09-18
4
9
 
5
10
  - 指标取数不再静默忽略无效筛选与排序字段:`--dim`、`--filter`、`--sort-asc`/`--sort-desc` 都按指标详情中的字段校验,未命中返回 `METRIC_UNSUPPORTED_DIMENSION`;结构化 `--filter-json`/`--filter-file` 在解析阶段返回 `FILTER_UNKNOWN_FIELD`,不会透传未知字段。
package/README.md CHANGED
@@ -10,6 +10,8 @@ npm install -g --foreground-scripts @guandata/guancli
10
10
 
11
11
  > 全局安装/升级时会通过 postinstall 自动执行一次 `guancli install-skill` 刷新 AI skill。`--foreground-scripts` 用于显示明确的成功、失败或跳过结果;失败时按提示手动运行 `guancli install-skill`。CI 等无需 skill 的环境可设 `GUAN_SKIP_INSTALL_SKILL=1` 跳过。
12
12
 
13
+ 安装包会通过 npm `optionalDependencies` 自动选择当前系统的原生二进制。不要使用 `--omit=optional` 或 `optional=false`;企业 npm 镜像也需要同步对应的 `@guandata/guancli-<平台>-<架构>` 包。若平台包缺失,CLI 会显示对应包名和重新安装方法。
14
+
13
15
  也可以直接使用:
14
16
 
15
17
  ```bash
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+
3
+ // Single source of truth for the optionalDependencies platform-package split.
4
+ // bin/run.js, scripts/build.js and the build/preflight tests all read this file
5
+ // so that the matrix, the package names and the embedded binary names can never
6
+ // drift apart.
7
+
8
+ const PACKAGE_PREFIX = "@guandata/guancli";
9
+ const CLI_NAME = "guancli";
10
+ const BINARY_NAMES = ["guancli"];
11
+
12
+ const PLATFORM_TARGETS = [
13
+ { platform: "darwin", arch: "arm64", suffix: "darwin-arm64", ext: "" },
14
+ { platform: "darwin", arch: "x64", suffix: "darwin-x64", ext: "" },
15
+ { platform: "linux", arch: "x64", suffix: "linux-x64", ext: "" },
16
+ { platform: "linux", arch: "arm64", suffix: "linux-arm64", ext: "" },
17
+ { platform: "win32", arch: "x64", suffix: "win32-x64", ext: ".exe" },
18
+ ].map((target) => ({
19
+ ...target,
20
+ key: `${target.platform}-${target.arch}`,
21
+ packageName: `${PACKAGE_PREFIX}-${target.suffix}`,
22
+ binaries: BINARY_NAMES.map((name) => `${name}${target.ext}`),
23
+ }));
24
+
25
+ function targetForRuntime(platform, arch) {
26
+ return PLATFORM_TARGETS.find(
27
+ (target) => target.platform === platform && target.arch === arch
28
+ );
29
+ }
30
+
31
+ function optionalDependencies(version) {
32
+ return Object.fromEntries(
33
+ PLATFORM_TARGETS.map((target) => [target.packageName, version])
34
+ );
35
+ }
36
+
37
+ module.exports = {
38
+ CLI_NAME,
39
+ PACKAGE_PREFIX,
40
+ BINARY_NAMES,
41
+ PLATFORM_TARGETS,
42
+ optionalDependencies,
43
+ targetForRuntime,
44
+ };
package/bin/run.js CHANGED
@@ -7,34 +7,79 @@ const path = require("path");
7
7
  const fs = require("fs");
8
8
  const os = require("os");
9
9
  const { createInstallChildEnv, reexecInstallCommand } = require("./install-env");
10
-
11
- const PLATFORM_MAP = {
12
- "darwin-arm64": "guancli-darwin-arm64",
13
- "darwin-x64": "guancli-darwin-x64",
14
- "linux-x64": "guancli-linux-x64",
15
- "linux-arm64": "guancli-linux-arm64",
16
- "win32-x64": "guancli-win32-x64.exe",
17
- };
18
-
19
- function getBinaryPath() {
20
- const key = `${process.platform}-${process.arch}`;
21
- const binaryName = PLATFORM_MAP[key];
22
- if (!binaryName) {
23
- console.error(
24
- `Unsupported platform: ${key}\nSupported: ${Object.keys(PLATFORM_MAP).join(", ")}`
10
+ const {
11
+ BINARY_NAMES,
12
+ PACKAGE_PREFIX,
13
+ PLATFORM_TARGETS,
14
+ targetForRuntime,
15
+ } = require("./platforms");
16
+
17
+ // The native binaries are delivered by per-platform optional dependencies, so
18
+ // an installation only downloads and unpacks the current OS/architecture.
19
+ function resolvePlatformBinaries(options = {}) {
20
+ const platform = options.platform || process.platform;
21
+ const arch = options.arch || process.arch;
22
+ const resolvePackage = options.resolvePackage || require.resolve;
23
+ const exists = options.exists || fs.existsSync;
24
+ const readJson =
25
+ options.readJson || ((filename) => JSON.parse(fs.readFileSync(filename, "utf8")));
26
+ const key = `${platform}-${arch}`;
27
+ const target = targetForRuntime(platform, arch);
28
+ if (!target) {
29
+ throw new Error(
30
+ `Unsupported platform: ${key}\nSupported: ${PLATFORM_TARGETS.map((item) => item.key).join(", ")}`
25
31
  );
26
- process.exit(1);
27
32
  }
28
33
 
29
- const binaryPath = path.join(__dirname, "..", "binaries", binaryName);
30
- if (!fs.existsSync(binaryPath)) {
31
- console.error(
32
- `Binary not found: ${binaryPath}\nRun 'npm run build' to compile binaries.`
33
- );
34
- process.exit(1);
34
+ try {
35
+ const packageJson = resolvePackage(`${target.packageName}/package.json`);
36
+ const platformVersion = readJson(packageJson).version;
37
+ const mainVersion = readJson(path.join(__dirname, "..", "package.json")).version;
38
+ if (platformVersion !== mainVersion) {
39
+ throw new Error(
40
+ `Platform package ${target.packageName} version ${platformVersion} does not match ` +
41
+ `${PACKAGE_PREFIX} ${mainVersion}. Reinstall ${PACKAGE_PREFIX}.`
42
+ );
43
+ }
44
+ const binDir = path.join(path.dirname(packageJson), "bin");
45
+ const binaryPaths = {};
46
+ for (const binary of target.binaries) {
47
+ const binaryPath = path.join(binDir, binary);
48
+ if (!exists(binaryPath)) {
49
+ throw new Error(
50
+ `Platform package ${target.packageName} is installed but its binary is missing: ${binaryPath}. ` +
51
+ `Reinstall ${PACKAGE_PREFIX}.`
52
+ );
53
+ }
54
+ binaryPaths[binary.replace(/\.exe$/, "")] = binaryPath;
55
+ }
56
+ return { target, binaryPaths };
57
+ } catch (err) {
58
+ if (err.message && err.message.startsWith("Platform package ")) throw err;
59
+
60
+ // Local development fallback. The generated directory is excluded from
61
+ // the published main package, so installed users always use the optional
62
+ // platform dependency above.
63
+ const localBinDir = path.join(__dirname, "..", "platforms", target.suffix, "bin");
64
+ const binaryPaths = {};
65
+ for (const binary of target.binaries) {
66
+ const binaryPath = path.join(localBinDir, binary);
67
+ if (!exists(binaryPath)) {
68
+ throw new Error(
69
+ `Missing optional platform package ${target.packageName} for ${key}.\n` +
70
+ `Reinstall without disabling optional dependencies:\n` +
71
+ ` npm install -g ${PACKAGE_PREFIX}\n` +
72
+ `If you used --omit=optional or optional=false, remove that setting first.`
73
+ );
74
+ }
75
+ binaryPaths[binary.replace(/\.exe$/, "")] = binaryPath;
76
+ }
77
+ return { target, binaryPaths };
35
78
  }
79
+ }
36
80
 
37
- return binaryPath;
81
+ function getBinaryPath(options = {}) {
82
+ return resolvePlatformBinaries(options).binaryPaths[BINARY_NAMES[0]];
38
83
  }
39
84
 
40
85
  function copyDirectory(src, dest) {
@@ -81,7 +126,7 @@ function installBuddySkills(pkgRoot, skill) {
81
126
  }
82
127
  }
83
128
 
84
- if (process.argv[2] === "version" && process.argv.length === 3) {
129
+ if (require.main === module && process.argv[2] === "version" && process.argv.length === 3) {
85
130
  const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, "..", "package.json"), "utf8"));
86
131
  console.log(pkg.version);
87
132
  process.exit(0);
@@ -111,7 +156,7 @@ function resolveNpxInvocation() {
111
156
  return { command: "npx", argsPrefix: [] };
112
157
  }
113
158
 
114
- if (process.argv[2] === "install-skill") {
159
+ if (require.main === module && process.argv[2] === "install-skill") {
115
160
  reexecInstallCommand(__filename, process.argv.slice(2));
116
161
  const pkgRoot = path.join(__dirname, "..");
117
162
  const extraArgs = process.argv.slice(3);
@@ -143,28 +188,38 @@ if (process.argv[2] === "install-skill") {
143
188
  process.exit(status);
144
189
  }
145
190
 
146
- const binary = getBinaryPath();
191
+ if (require.main === module) {
192
+ let binary;
193
+ try {
194
+ binary = getBinaryPath();
195
+ } catch (err) {
196
+ console.error(err.message);
197
+ process.exit(1);
198
+ }
147
199
 
148
- try {
149
- if (process.platform !== "win32") {
150
- fs.chmodSync(binary, 0o755);
200
+ try {
201
+ if (process.platform !== "win32") {
202
+ fs.chmodSync(binary, 0o755);
203
+ }
204
+ } catch (_) {
205
+ // chmod may fail in read-only environments
151
206
  }
152
- } catch (_) {
153
- // chmod may fail in read-only environments; binary might already be executable
154
- }
155
207
 
156
- if (process.platform === "win32") {
157
- try { execSync("chcp 65001", { stdio: "ignore" }); } catch (_) {}
158
- }
208
+ if (process.platform === "win32") {
209
+ try { execSync("chcp 65001", { stdio: "ignore" }); } catch (_) {}
210
+ }
159
211
 
160
- try {
161
- execFileSync(binary, process.argv.slice(2), {
162
- stdio: "inherit",
163
- env: { ...process.env, GUANCLI_PROG_NAME: "guancli" },
164
- });
165
- } catch (err) {
166
- if (err.status != null) {
167
- process.exit(err.status);
212
+ try {
213
+ execFileSync(binary, process.argv.slice(2), {
214
+ stdio: "inherit",
215
+ env: { ...process.env, GUANCLI_PROG_NAME: "guancli" },
216
+ });
217
+ } catch (err) {
218
+ if (err.status != null) {
219
+ process.exit(err.status);
220
+ }
221
+ throw err;
168
222
  }
169
- throw err;
170
223
  }
224
+
225
+ module.exports = { getBinaryPath, resolvePlatformBinaries };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@guandata/guancli",
3
- "version": "1.0.61",
3
+ "version": "1.0.62",
4
4
  "description": "观远 BI 命令行工具 - 通过 API 操作 ETL、数据集、页面、表单等资源,并提供 ChatBI 问数/洞察能力",
5
5
  "bin": {
6
6
  "guancli": "bin/run.js"
@@ -8,13 +8,17 @@
8
8
  "scripts": {
9
9
  "postinstall": "node bin/postinstall.js",
10
10
  "build": "node scripts/build.js && node scripts/sync-skill.js",
11
+ "pack:all": "node scripts/pack-all.js",
12
+ "test:build-script": "node scripts/platform-tests.js build && node scripts/platform-tests.js run",
13
+ "test:package-layout": "node scripts/platform-tests.js layout && node scripts/platform-tests.js install-smoke",
14
+ "test:auto-select": "node scripts/platform-tests.js auto-select",
15
+ "verify:platforms": "node scripts/verify-platforms.js",
11
16
  "changelog": "node ../../scripts/generate-release-changelog.js .",
12
17
  "check-changelog": "node ../../scripts/check-release-changelog.js .",
13
- "prepublishOnly": "npm run check-changelog && npm run build && node scripts/preflight.js"
18
+ "prepublishOnly": "npm run test:build-script && npm run check-changelog && npm run build && node scripts/preflight.js && npm run test:package-layout && npm run test:auto-select"
14
19
  },
15
20
  "files": [
16
21
  "bin/",
17
- "binaries/",
18
22
  "skills/",
19
23
  "CHANGELOG.md",
20
24
  "LICENSE",
@@ -37,8 +41,15 @@
37
41
  "engines": {
38
42
  "node": ">=14"
39
43
  },
44
+ "optionalDependencies": {
45
+ "@guandata/guancli-darwin-arm64": "1.0.62",
46
+ "@guandata/guancli-darwin-x64": "1.0.62",
47
+ "@guandata/guancli-linux-x64": "1.0.62",
48
+ "@guandata/guancli-linux-arm64": "1.0.62",
49
+ "@guandata/guancli-win32-x64": "1.0.62"
50
+ },
40
51
  "publishConfig": {
41
- "access": "public",
42
- "registry": "https://registry.npmjs.org/"
52
+ "registry": "https://registry.npmjs.org/",
53
+ "access": "public"
43
54
  }
44
55
  }
Binary file
Binary file
Binary file
Binary file
Binary file