@clickzetta/cz-cli 0.3.71 → 0.3.72

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/bin/platform.js CHANGED
@@ -16,6 +16,29 @@ const SUPPORTED_PACKAGES = new Set([
16
16
  ]);
17
17
  const DEFAULT_FALLBACK_ROOT = path.join(__dirname, "fallback");
18
18
 
19
+ function formatError(error) {
20
+ if (error && typeof error === "object" && "stderr" in error && error.stderr) {
21
+ return String(error.stderr).trim();
22
+ }
23
+
24
+ if (error instanceof Error) return error.message;
25
+ return String(error);
26
+ }
27
+
28
+ function getNpmInvocation(env = process.env) {
29
+ if (env.npm_execpath && path.isAbsolute(env.npm_execpath)) {
30
+ return {
31
+ command: process.execPath,
32
+ args: [env.npm_execpath],
33
+ };
34
+ }
35
+
36
+ return {
37
+ command: process.platform === "win32" ? "npm.cmd" : "npm",
38
+ args: [],
39
+ };
40
+ }
41
+
19
42
  function normalizeArch(arch = os.arch()) {
20
43
  if (arch === "x64" || arch === "amd64") return "x64";
21
44
  if (arch === "arm64" || arch === "aarch64") return "arm64";
@@ -39,14 +62,24 @@ function getPlatformSpec({
39
62
  };
40
63
  }
41
64
 
42
- function resolvePackageDir(spec, resolve = require.resolve) {
65
+ function resolvePackageDirDetailed(spec, resolve = require.resolve) {
43
66
  try {
44
- return path.dirname(resolve(`${spec.packageName}/package.json`));
45
- } catch {
46
- return null;
67
+ return {
68
+ packageDir: path.dirname(resolve(`${spec.packageName}/package.json`)),
69
+ error: null,
70
+ };
71
+ } catch (error) {
72
+ return {
73
+ packageDir: null,
74
+ error: formatError(error),
75
+ };
47
76
  }
48
77
  }
49
78
 
79
+ function resolvePackageDir(spec, resolve = require.resolve) {
80
+ return resolvePackageDirDetailed(spec, resolve).packageDir;
81
+ }
82
+
50
83
  function resolveBinaryFromRoot(rootDir, spec, existsSync = fs.existsSync) {
51
84
  if (!rootDir) return null;
52
85
  const binPath = path.join(rootDir, spec.binaryName);
@@ -76,6 +109,75 @@ function resolveInstalledBinary({
76
109
  return null;
77
110
  }
78
111
 
112
+ function inspectOptionalPackage({
113
+ spec,
114
+ version,
115
+ force = false,
116
+ resolvePackageDirFn,
117
+ existsSync = fs.existsSync,
118
+ readFileSync = fs.readFileSync,
119
+ } = {}) {
120
+ const issues = [];
121
+ const packageDirInfo = resolvePackageDirFn
122
+ ? { packageDir: resolvePackageDirFn(spec), error: null }
123
+ : resolvePackageDirDetailed(spec);
124
+
125
+ if (!packageDirInfo.packageDir) {
126
+ issues.push(
127
+ packageDirInfo.error
128
+ ? `Optional dependency ${spec.packageName} is not installed: ${packageDirInfo.error}`
129
+ : `Optional dependency ${spec.packageName} is not installed.`,
130
+ );
131
+ return {
132
+ issues,
133
+ packageDir: null,
134
+ packageJsonVersion: null,
135
+ packaged: null,
136
+ };
137
+ }
138
+
139
+ const packaged = resolveBinaryFromRoot(path.join(packageDirInfo.packageDir, "bin"), spec, existsSync);
140
+ if (!packaged) {
141
+ issues.push(
142
+ `Optional dependency ${spec.packageName} was resolved to ${packageDirInfo.packageDir}, but ${spec.binaryName} is missing from bin/.`,
143
+ );
144
+ }
145
+
146
+ const packageJsonPath = path.join(packageDirInfo.packageDir, "package.json");
147
+ try {
148
+ const packageJsonVersion = JSON.parse(readFileSync(packageJsonPath, "utf-8")).version;
149
+ if (force && packaged && packageJsonVersion !== version) {
150
+ issues.push(
151
+ `Optional dependency ${spec.packageName} version mismatch: found ${packageJsonVersion}, expected ${version}.`,
152
+ );
153
+ }
154
+
155
+ return {
156
+ issues,
157
+ packageDir: packageDirInfo.packageDir,
158
+ packageJsonVersion,
159
+ packaged,
160
+ };
161
+ } catch (error) {
162
+ issues.push(`Optional dependency ${spec.packageName} package.json could not be read: ${formatError(error)}`);
163
+ return {
164
+ issues,
165
+ packageDir: packageDirInfo.packageDir,
166
+ packageJsonVersion: null,
167
+ packaged,
168
+ };
169
+ }
170
+ }
171
+
172
+ function createInstallFailure(spec, details) {
173
+ return new Error(
174
+ [
175
+ `Unable to install cz-cli binary for ${spec.platform}-${spec.arch} from package ${spec.packageName}.`,
176
+ ...details.map((detail) => `- ${detail}`),
177
+ ].join("\n"),
178
+ );
179
+ }
180
+
79
181
  function parseOctal(buffer, start, end) {
80
182
  const value = buffer.toString("utf8", start, end).replace(/\0.*$/, "").trim();
81
183
  if (!value) return 0;
@@ -132,13 +234,14 @@ async function installFromNpmRegistry({
132
234
  destinationDir,
133
235
  } = {}) {
134
236
  const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), "cz-cli-npm-pack-"));
237
+ const npm = getNpmInvocation();
135
238
 
136
239
  const cleanEnv = Object.fromEntries(
137
240
  Object.entries(process.env).filter(([k]) => !k.startsWith("npm_")),
138
241
  );
139
242
 
140
243
  try {
141
- const packed = execFileSync("npm", ["pack", `${packageName}@${version}`, "--silent"], {
244
+ const packed = execFileSync(npm.command, [...npm.args, "pack", `${packageName}@${version}`, "--silent"], {
142
245
  cwd: tempRoot,
143
246
  encoding: "utf-8",
144
247
  env: cleanEnv,
@@ -153,13 +256,7 @@ async function installFromNpmRegistry({
153
256
 
154
257
  extractBinFromTarball(path.join(tempRoot, packed), destinationDir);
155
258
  } catch (error) {
156
- const detail =
157
- error && typeof error === "object" && "stderr" in error && error.stderr
158
- ? String(error.stderr).trim()
159
- : error instanceof Error
160
- ? error.message
161
- : String(error);
162
- throw new Error(`npm registry self-heal failed for ${packageName}@${version}: ${detail}`);
259
+ throw new Error(`npm registry self-heal failed for ${packageName}@${version}: ${formatError(error)}`);
163
260
  } finally {
164
261
  fs.rmSync(tempRoot, { recursive: true, force: true });
165
262
  }
@@ -176,43 +273,42 @@ async function ensureInstalledBinary({
176
273
  } = {}) {
177
274
  if (!spec) throw new Error(`Unsupported platform/arch: ${os.platform()}/${os.arch()}`);
178
275
 
179
- const resolveFn = resolvePackageDirOverride || resolvePackageDir;
276
+ const optionalPackage = inspectOptionalPackage({
277
+ spec,
278
+ version,
279
+ force,
280
+ resolvePackageDirFn: resolvePackageDirOverride,
281
+ existsSync,
282
+ });
180
283
 
181
284
  if (!force) {
182
- const installed = resolveInstalledBinary({
183
- spec,
184
- fallbackRoot,
185
- resolvePackageDirFn: resolveFn,
186
- existsSync,
187
- });
188
- if (installed) return installed;
285
+ if (optionalPackage.packaged) return { ...optionalPackage.packaged, source: "package" };
286
+
287
+ const fallback = resolveBinaryFromRoot(path.join(fallbackRoot, `${spec.platform}-${spec.arch}`), spec, existsSync);
288
+ if (fallback) return { ...fallback, source: "fallback" };
189
289
  }
190
290
 
191
291
  // When force is true, still prefer the optionalDependency package if its
192
292
  // version matches — avoids a nested npm pack call that can fail inside
193
293
  // postinstall (inherited npm env/lock conflicts).
194
- if (force) {
195
- const pkgDir = resolveFn(spec);
196
- if (pkgDir) {
197
- try {
198
- const pkgJson = JSON.parse(fs.readFileSync(path.join(pkgDir, "package.json"), "utf-8"));
199
- if (pkgJson.version === version) {
200
- const packaged = resolveBinaryFromRoot(path.join(pkgDir, "bin"), spec, existsSync);
201
- if (packaged) return { ...packaged, source: "package" };
202
- }
203
- } catch {}
204
- }
294
+ if (force && optionalPackage.packaged && optionalPackage.packageJsonVersion === version) {
295
+ return { ...optionalPackage.packaged, source: "package" };
205
296
  }
206
297
 
207
298
  const destinationDir = path.join(fallbackRoot, `${spec.platform}-${spec.arch}`);
208
299
  fs.rmSync(destinationDir, { recursive: true, force: true });
209
300
  fs.mkdirSync(destinationDir, { recursive: true });
210
- await installFromNpmRegistryOverride({
211
- packageName: spec.packageName,
212
- version,
213
- destinationDir,
214
- binaryName: spec.binaryName,
215
- });
301
+ let registryError = null;
302
+ try {
303
+ await installFromNpmRegistryOverride({
304
+ packageName: spec.packageName,
305
+ version,
306
+ destinationDir,
307
+ binaryName: spec.binaryName,
308
+ });
309
+ } catch (error) {
310
+ registryError = error;
311
+ }
216
312
 
217
313
  const fallback = resolveInstalledBinary({
218
314
  spec,
@@ -222,14 +318,18 @@ async function ensureInstalledBinary({
222
318
  });
223
319
  if (fallback) return fallback;
224
320
 
225
- throw new Error(
226
- `Unable to install cz-cli binary for ${spec.platform}-${spec.arch} from package ${spec.packageName} or npm registry fallback.`,
227
- );
321
+ const details = optionalPackage.issues.slice();
322
+ if (registryError) details.push(formatError(registryError));
323
+ else details.push(`npm registry self-heal completed, but ${spec.binaryName} was not extracted into ${destinationDir}.`);
324
+
325
+ throw createInstallFailure(spec, details);
228
326
  }
229
327
 
230
328
  module.exports = {
231
329
  DEFAULT_FALLBACK_ROOT,
232
330
  ensureInstalledBinary,
331
+ getNpmInvocation,
233
332
  getPlatformSpec,
333
+ inspectOptionalPackage,
234
334
  resolveInstalledBinary,
235
335
  };
@@ -155,7 +155,7 @@ async function main() {
155
155
 
156
156
  main().catch((error) => {
157
157
  process.stderr.write(
158
- `Failed to install cz-cli binary: ${error instanceof Error ? error.message : String(error)}\n`,
158
+ `Failed to install cz-cli binary:\n${error instanceof Error ? error.message : String(error)}\n`,
159
159
  );
160
160
  process.stderr.write("npm installed the launcher package, but the platform binary could not be prepared from npm.\n");
161
161
  process.stderr.write("Check npm config for omit=optional / optional=false and ensure npm registry access works.\n");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clickzetta/cz-cli",
3
- "version": "0.3.71",
3
+ "version": "0.3.72",
4
4
  "description": "AI-Agent-friendly CLI for ClickZetta Lakehouse",
5
5
  "bin": {
6
6
  "cz-cli": "bin/run.js",
@@ -13,11 +13,11 @@
13
13
  "bin/"
14
14
  ],
15
15
  "optionalDependencies": {
16
- "@clickzetta/cz-cli-darwin-arm64": "0.3.71",
17
- "@clickzetta/cz-cli-darwin-x64": "0.3.71",
18
- "@clickzetta/cz-cli-linux-arm64": "0.3.71",
19
- "@clickzetta/cz-cli-linux-x64": "0.3.71",
20
- "@clickzetta/cz-cli-win32-x64": "0.3.71"
16
+ "@clickzetta/cz-cli-darwin-arm64": "0.3.72",
17
+ "@clickzetta/cz-cli-darwin-x64": "0.3.72",
18
+ "@clickzetta/cz-cli-linux-arm64": "0.3.72",
19
+ "@clickzetta/cz-cli-linux-x64": "0.3.72",
20
+ "@clickzetta/cz-cli-win32-x64": "0.3.72"
21
21
  },
22
22
  "license": "MIT",
23
23
  "repository": {