@clickzetta/cz-cli 0.3.50 → 0.3.52

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.
@@ -0,0 +1,209 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ const { execFileSync } = require("child_process");
5
+ const fs = require("fs");
6
+ const os = require("os");
7
+ const path = require("path");
8
+ const zlib = require("zlib");
9
+
10
+ const SUPPORTED_PACKAGES = new Set([
11
+ "darwin-arm64",
12
+ "darwin-x64",
13
+ "linux-arm64",
14
+ "linux-x64",
15
+ "win32-x64",
16
+ ]);
17
+ const DEFAULT_FALLBACK_ROOT = path.join(__dirname, "fallback");
18
+
19
+ function normalizeArch(arch = os.arch()) {
20
+ if (arch === "x64" || arch === "amd64") return "x64";
21
+ if (arch === "arm64" || arch === "aarch64") return "arm64";
22
+ return null;
23
+ }
24
+
25
+ function getPlatformSpec({
26
+ platform = os.platform(),
27
+ arch = os.arch(),
28
+ } = {}) {
29
+ const normalizedArch = normalizeArch(arch);
30
+ if (!normalizedArch) return null;
31
+ const packageTarget = `${platform}-${normalizedArch}`;
32
+ if (!SUPPORTED_PACKAGES.has(packageTarget)) return null;
33
+
34
+ return {
35
+ platform,
36
+ arch: normalizedArch,
37
+ binaryName: platform === "win32" ? "cz-cli.exe" : "cz-cli",
38
+ packageName: `@clickzetta/cz-cli-${packageTarget}`,
39
+ };
40
+ }
41
+
42
+ function resolvePackageDir(spec, resolve = require.resolve) {
43
+ try {
44
+ return path.dirname(resolve(`${spec.packageName}/package.json`));
45
+ } catch {
46
+ return null;
47
+ }
48
+ }
49
+
50
+ function resolveBinaryFromRoot(rootDir, spec, existsSync = fs.existsSync) {
51
+ if (!rootDir) return null;
52
+ const binPath = path.join(rootDir, spec.binaryName);
53
+ if (!existsSync(binPath)) return null;
54
+
55
+ return {
56
+ rootDir,
57
+ binPath,
58
+ };
59
+ }
60
+
61
+ function resolveInstalledBinary({
62
+ spec = getPlatformSpec(),
63
+ fallbackRoot = DEFAULT_FALLBACK_ROOT,
64
+ resolvePackageDirFn = resolvePackageDir,
65
+ existsSync = fs.existsSync,
66
+ } = {}) {
67
+ if (!spec) return null;
68
+
69
+ const packageDir = resolvePackageDirFn(spec);
70
+ const packaged = resolveBinaryFromRoot(packageDir ? path.join(packageDir, "bin") : null, spec, existsSync);
71
+ if (packaged) return { ...packaged, source: "package" };
72
+
73
+ const fallback = resolveBinaryFromRoot(path.join(fallbackRoot, `${spec.platform}-${spec.arch}`), spec, existsSync);
74
+ if (fallback) return { ...fallback, source: "fallback" };
75
+
76
+ return null;
77
+ }
78
+
79
+ function parseOctal(buffer, start, end) {
80
+ const value = buffer.toString("utf8", start, end).replace(/\0.*$/, "").trim();
81
+ if (!value) return 0;
82
+ return Number.parseInt(value, 8);
83
+ }
84
+
85
+ function sanitizeRelativePath(relativePath) {
86
+ const normalized = path.posix.normalize(relativePath).replace(/^\/+/, "");
87
+ if (!normalized || normalized.startsWith("../") || normalized === "..") return null;
88
+ return normalized;
89
+ }
90
+
91
+ function extractBinFromTarball(archivePath, destinationDir) {
92
+ const archive = zlib.gunzipSync(fs.readFileSync(archivePath));
93
+ const resolvedDestinationDir = path.resolve(destinationDir);
94
+ let offset = 0;
95
+
96
+ while (offset + 512 <= archive.length) {
97
+ const header = archive.subarray(offset, offset + 512);
98
+ if (header.every((byte) => byte === 0)) break;
99
+
100
+ const name = header.toString("utf8", 0, 100).replace(/\0.*$/, "");
101
+ const prefix = header.toString("utf8", 345, 500).replace(/\0.*$/, "");
102
+ const entryPath = sanitizeRelativePath(prefix ? `${prefix}/${name}` : name);
103
+ const type = String.fromCharCode(header[156] || 0);
104
+ const mode = parseOctal(header, 100, 108);
105
+ const size = parseOctal(header, 124, 136);
106
+ const dataStart = offset + 512;
107
+ const dataEnd = dataStart + size;
108
+ const relative = entryPath && entryPath.startsWith("package/bin/") ? sanitizeRelativePath(entryPath.slice(12)) : null;
109
+
110
+ if (relative) {
111
+ const targetPath = path.resolve(resolvedDestinationDir, relative);
112
+ if (!targetPath.startsWith(resolvedDestinationDir + path.sep) && targetPath !== resolvedDestinationDir) {
113
+ throw new Error(`Refusing to extract unsafe path: ${relative}`);
114
+ }
115
+
116
+ if (type === "5") {
117
+ fs.mkdirSync(targetPath, { recursive: true });
118
+ } else if (type === "\0" || type === "0") {
119
+ fs.mkdirSync(path.dirname(targetPath), { recursive: true });
120
+ fs.writeFileSync(targetPath, archive.subarray(dataStart, dataEnd));
121
+ if (process.platform !== "win32") fs.chmodSync(targetPath, mode || 0o755);
122
+ }
123
+ }
124
+
125
+ offset = dataStart + Math.ceil(size / 512) * 512;
126
+ }
127
+ }
128
+
129
+ async function installFromNpmRegistry({
130
+ packageName,
131
+ version,
132
+ destinationDir,
133
+ } = {}) {
134
+ const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), "cz-cli-npm-pack-"));
135
+
136
+ try {
137
+ const packed = execFileSync("npm", ["pack", `${packageName}@${version}`, "--silent"], {
138
+ cwd: tempRoot,
139
+ encoding: "utf-8",
140
+ stdio: ["ignore", "pipe", "pipe"],
141
+ })
142
+ .trim()
143
+ .split(/\r?\n/)
144
+ .filter(Boolean)
145
+ .pop();
146
+
147
+ if (!packed) throw new Error(`npm pack did not return a tarball name for ${packageName}@${version}`);
148
+
149
+ extractBinFromTarball(path.join(tempRoot, packed), destinationDir);
150
+ } catch (error) {
151
+ const detail =
152
+ error && typeof error === "object" && "stderr" in error && error.stderr
153
+ ? String(error.stderr).trim()
154
+ : error instanceof Error
155
+ ? error.message
156
+ : String(error);
157
+ throw new Error(`npm registry self-heal failed for ${packageName}@${version}: ${detail}`);
158
+ } finally {
159
+ fs.rmSync(tempRoot, { recursive: true, force: true });
160
+ }
161
+ }
162
+
163
+ async function ensureInstalledBinary({
164
+ spec = getPlatformSpec(),
165
+ version = "latest",
166
+ fallbackRoot = DEFAULT_FALLBACK_ROOT,
167
+ resolvePackageDir: resolvePackageDirOverride,
168
+ existsSync = fs.existsSync,
169
+ installFromNpmRegistry: installFromNpmRegistryOverride = installFromNpmRegistry,
170
+ } = {}) {
171
+ if (!spec) throw new Error(`Unsupported platform/arch: ${os.platform()}/${os.arch()}`);
172
+
173
+ const installed = resolveInstalledBinary({
174
+ spec,
175
+ fallbackRoot,
176
+ resolvePackageDirFn: resolvePackageDirOverride || resolvePackageDir,
177
+ existsSync,
178
+ });
179
+ if (installed) return installed;
180
+
181
+ const destinationDir = path.join(fallbackRoot, `${spec.platform}-${spec.arch}`);
182
+ fs.rmSync(destinationDir, { recursive: true, force: true });
183
+ fs.mkdirSync(destinationDir, { recursive: true });
184
+ await installFromNpmRegistryOverride({
185
+ packageName: spec.packageName,
186
+ version,
187
+ destinationDir,
188
+ binaryName: spec.binaryName,
189
+ });
190
+
191
+ const fallback = resolveInstalledBinary({
192
+ spec,
193
+ fallbackRoot,
194
+ resolvePackageDirFn: () => null,
195
+ existsSync,
196
+ });
197
+ if (fallback) return fallback;
198
+
199
+ throw new Error(
200
+ `Unable to install cz-cli binary for ${spec.platform}-${spec.arch} from package ${spec.packageName} or npm registry fallback.`,
201
+ );
202
+ }
203
+
204
+ module.exports = {
205
+ DEFAULT_FALLBACK_ROOT,
206
+ ensureInstalledBinary,
207
+ getPlatformSpec,
208
+ resolveInstalledBinary,
209
+ };
@@ -3,15 +3,13 @@
3
3
 
4
4
  const { execFileSync } = require("child_process");
5
5
  const fs = require("fs");
6
- const path = require("path");
7
6
  const os = require("os");
7
+ const path = require("path");
8
+ const { DEFAULT_FALLBACK_ROOT, ensureInstalledBinary, getPlatformSpec } = require("./platform");
8
9
 
9
10
  const home = os.homedir();
10
- const platform = os.platform();
11
- const arch = os.arch() === "x64" ? "x64" : "arm64";
12
- const pkgName = `@clickzetta/cz-cli-${platform}-${arch}`;
13
- const binName = platform === "win32" ? "cz-cli.exe" : "cz-cli";
14
11
  const installFile = path.join(home, ".clickzetta", "install.json");
12
+ const version = JSON.parse(fs.readFileSync(path.join(__dirname, "..", "package.json"), "utf-8")).version;
15
13
 
16
14
  function detectPackageManager() {
17
15
  const userAgent = process.env.npm_config_user_agent || "";
@@ -22,17 +20,20 @@ function detectPackageManager() {
22
20
  return "npm";
23
21
  }
24
22
 
25
- try {
26
- const pkgDir = path.dirname(require.resolve(`${pkgName}/package.json`));
27
- const binPath = path.join(pkgDir, "bin", binName);
28
- const skillsSrc = path.join(pkgDir, "bin", "skills");
29
- if (!fs.existsSync(skillsSrc)) process.exit(0);
23
+ async function main() {
24
+ const spec = getPlatformSpec();
25
+ if (!spec) return;
30
26
 
31
- const skills = fs.readdirSync(skillsSrc).filter((name) =>
32
- fs.statSync(path.join(skillsSrc, name)).isDirectory()
33
- );
27
+ const installed = await ensureInstalledBinary({
28
+ spec,
29
+ version,
30
+ fallbackRoot: DEFAULT_FALLBACK_ROOT,
31
+ });
32
+ const skillsSrc = path.join(installed.rootDir, "skills");
33
+ const skills = fs.existsSync(skillsSrc)
34
+ ? fs.readdirSync(skillsSrc).filter((name) => fs.statSync(path.join(skillsSrc, name)).isDirectory())
35
+ : [];
34
36
 
35
- // 1. cz-cli skill → external agent directories (subagent registration)
36
37
  const agentDirs = [
37
38
  path.join(home, ".claude", "skills"),
38
39
  path.join(home, ".kiro", "skills"),
@@ -50,7 +51,6 @@ try {
50
51
  }
51
52
  }
52
53
 
53
- // Cleanup: fix cz-cli-v2 → cz-cli in existing skill files (bug introduced in 57a49fcdc)
54
54
  for (const dir of agentDirs) {
55
55
  const skillFile = path.join(dir, "cz-cli", "SKILL.md");
56
56
  try {
@@ -75,17 +75,17 @@ try {
75
75
  }
76
76
  }
77
77
 
78
- // 2. All other skills → ~/.clickzetta/skills/.builtin/ (cz-cli managed, safe to overwrite)
79
78
  const internalDest = path.join(home, ".clickzetta", "skills", ".builtin");
80
79
  fs.mkdirSync(internalDest, { recursive: true });
81
80
 
82
- // Migrate: remove legacy skills that were previously installed directly in ~/.clickzetta/skills/
83
81
  const legacyDir = path.join(home, ".clickzetta", "skills");
84
82
  for (const name of skills) {
85
83
  if (name === "cz-cli") continue;
86
84
  const legacy = path.join(legacyDir, name);
87
85
  if (fs.existsSync(legacy) && fs.statSync(legacy).isDirectory()) {
88
- try { fs.rmSync(legacy, { recursive: true, force: true }); } catch (e) {}
86
+ try {
87
+ fs.rmSync(legacy, { recursive: true, force: true });
88
+ } catch (e) {}
89
89
  }
90
90
  }
91
91
 
@@ -100,14 +100,14 @@ try {
100
100
  }
101
101
 
102
102
  try {
103
- execFileSync(binPath, [], {
103
+ execFileSync(installed.binPath, [], {
104
104
  stdio: "ignore",
105
105
  env: { ...process.env, CLICKZETTA_MIGRATE_PROFILES_ONLY: "1" },
106
106
  });
107
107
  } catch (e) {}
108
108
 
109
109
  try {
110
- const version = execFileSync(binPath, ["--version"], {
110
+ const binaryVersion = execFileSync(installed.binPath, ["--version"], {
111
111
  stdio: ["ignore", "pipe", "ignore"],
112
112
  encoding: "utf-8",
113
113
  env: process.env,
@@ -119,17 +119,24 @@ try {
119
119
  {
120
120
  version: 1,
121
121
  method: detectPackageManager(),
122
- installed_path: binPath,
122
+ installed_path: installed.binPath,
123
123
  channel: "latest",
124
- binary_version: version,
124
+ binary_version: binaryVersion,
125
125
  updated_at: new Date().toISOString(),
126
126
  },
127
127
  null,
128
- 2
128
+ 2,
129
129
  ) + "\n",
130
- "utf-8"
130
+ "utf-8",
131
131
  );
132
132
  } catch (e) {}
133
- } catch (e) {
134
- // Non-fatal: don't block npm install
135
133
  }
134
+
135
+ main().catch((error) => {
136
+ process.stderr.write(
137
+ `Failed to install cz-cli binary: ${error instanceof Error ? error.message : String(error)}\n`,
138
+ );
139
+ process.stderr.write("npm installed the launcher package, but the platform binary could not be prepared from npm.\n");
140
+ process.stderr.write("Check npm config for omit=optional / optional=false and ensure npm registry access works.\n");
141
+ process.exit(1);
142
+ });
package/bin/run.js CHANGED
@@ -2,22 +2,23 @@
2
2
  "use strict";
3
3
 
4
4
  const { execFileSync } = require("child_process");
5
- const path = require("path");
6
- const os = require("os");
5
+ const { DEFAULT_FALLBACK_ROOT, getPlatformSpec, resolveInstalledBinary } = require("./platform");
7
6
 
8
- const platform = os.platform();
9
- const arch = os.arch() === "x64" ? "x64" : "arm64";
10
- const pkgName = `@clickzetta/cz-cli-${platform}-${arch}`;
11
- const binName = platform === "win32" ? "cz-cli.exe" : "cz-cli";
7
+ const spec = getPlatformSpec();
12
8
 
13
9
  try {
14
- const pkgDir = path.dirname(require.resolve(`${pkgName}/package.json`));
15
- const binPath = path.join(pkgDir, "bin", binName);
16
- execFileSync(binPath, process.argv.slice(2), { stdio: "inherit", env: process.env });
10
+ const installed = resolveInstalledBinary({
11
+ spec,
12
+ fallbackRoot: DEFAULT_FALLBACK_ROOT,
13
+ });
14
+ if (!installed) throw new Error("missing binary");
15
+
16
+ execFileSync(installed.binPath, process.argv.slice(2), { stdio: "inherit", env: process.env });
17
17
  } catch (e) {
18
18
  if (e.status !== undefined) process.exit(e.status);
19
- console.error(`Error: Platform binary not found (${pkgName}).`);
20
- console.error(`Fix: npm install -g @clickzetta/cz-cli@latest`);
21
- console.error(`Or: curl -fsSL https://github.com/clickzetta/cz-cli/releases/latest/download/install.sh | sh`);
19
+ console.error(`Error: Platform binary not found (${spec ? spec.packageName : "unsupported-platform"}).`);
20
+ console.error("Fix: reinstall with npm so postinstall can repair the platform binary from npm registry");
21
+ console.error(" npm install -g @clickzetta/cz-cli@latest --ignore-scripts=false");
22
+ console.error("If this still fails, check npm config for omit=optional / optional=false and registry access.");
22
23
  process.exit(1);
23
24
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clickzetta/cz-cli",
3
- "version": "0.3.50",
3
+ "version": "0.3.52",
4
4
  "description": "AI-Agent-friendly CLI for ClickZetta Lakehouse",
5
5
  "bin": {
6
6
  "cz-cli": "bin/run.js"
@@ -12,11 +12,11 @@
12
12
  "bin/"
13
13
  ],
14
14
  "optionalDependencies": {
15
- "@clickzetta/cz-cli-darwin-arm64": "0.3.50",
16
- "@clickzetta/cz-cli-darwin-x64": "0.3.50",
17
- "@clickzetta/cz-cli-linux-arm64": "0.3.50",
18
- "@clickzetta/cz-cli-linux-x64": "0.3.50",
19
- "@clickzetta/cz-cli-win32-x64": "0.3.50"
15
+ "@clickzetta/cz-cli-darwin-arm64": "0.3.52",
16
+ "@clickzetta/cz-cli-darwin-x64": "0.3.52",
17
+ "@clickzetta/cz-cli-linux-arm64": "0.3.52",
18
+ "@clickzetta/cz-cli-linux-x64": "0.3.52",
19
+ "@clickzetta/cz-cli-win32-x64": "0.3.52"
20
20
  },
21
21
  "license": "MIT",
22
22
  "repository": {