claudekit-cli 3.39.3-dev.2 → 3.39.3-dev.3

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.
Files changed (3) hide show
  1. package/bin/ck.js +21 -159
  2. package/dist/index.js +7 -88
  3. package/package.json +1 -10
package/bin/ck.js CHANGED
@@ -1,12 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  /**
4
- * Wrapper script that detects platform and executes the correct binary.
5
- * Falls back to Node.js execution if binary fails (e.g., Alpine/musl).
6
- * This is the entry point that NPM symlinks to when installing globally.
4
+ * CLI entry point runs dist/index.js via Bun (preferred) or Node.js (fallback).
5
+ * This is the file NPM symlinks to when installing globally.
7
6
  */
8
7
 
9
- import { execSync, spawn, spawnSync } from "node:child_process";
8
+ import { execSync, spawnSync } from "node:child_process";
10
9
  import { existsSync, readFileSync } from "node:fs";
11
10
  import { dirname, join } from "node:path";
12
11
  import { fileURLToPath, pathToFileURL } from "node:url";
@@ -24,7 +23,7 @@ const checkNodeVersion = () => {
24
23
 
25
24
  if (major < minMajor || (major === minMajor && minor < minMinor)) {
26
25
  console.error(
27
- `❌ Node.js ${MIN_NODE_VERSION.join(".")}+ is required. Current version: ${process.versions.node}`,
26
+ `[X] Node.js ${MIN_NODE_VERSION.join(".")}+ is required. Current version: ${process.versions.node}`,
28
27
  );
29
28
  console.error(" Please upgrade Node.js: https://nodejs.org/");
30
29
  process.exit(1);
@@ -36,10 +35,6 @@ checkNodeVersion();
36
35
 
37
36
  const __dirname = dirname(fileURLToPath(import.meta.url));
38
37
 
39
- // Detect platform and architecture
40
- const platform = process.platform;
41
- const arch = process.arch;
42
-
43
38
  /**
44
39
  * Extract error message safely with type guard
45
40
  */
@@ -49,9 +44,8 @@ const getErrorMessage = (err) => {
49
44
 
50
45
  /**
51
46
  * Check if bun runtime is available on the system.
52
- * Used to run dist/index.js with bun when no platform binary exists (e.g., dev releases).
53
47
  * dist/index.js may contain bun-specific imports (bun:sqlite) that Node.js can't handle.
54
- * Result is cached to avoid repeated execSync calls across fallback paths.
48
+ * Result is cached to avoid repeated execSync calls.
55
49
  */
56
50
  let _bunAvailable = undefined;
57
51
  const hasBun = () => {
@@ -78,35 +72,12 @@ const readInstalledPackageVersion = () => {
78
72
  return _installedVersion;
79
73
  };
80
74
 
81
- const isExpectedBunOnlyRelease = () => {
75
+ const isDevPrerelease = () => {
82
76
  const version = readInstalledPackageVersion();
83
77
  return typeof version === "string" && /-dev\.\d+$/i.test(version);
84
78
  };
85
79
 
86
- const shouldWarnForBunFallback = () => !isExpectedBunOnlyRelease();
87
- const RUNTIME_FATAL_SIGNALS = new Set(["SIGABRT", "SIGBUS", "SIGILL", "SIGSEGV", "SIGTRAP"]);
88
-
89
- const handleRuntimeSignalExit = (signal, sourceLabel) => {
90
- if (!signal) return;
91
- if (!RUNTIME_FATAL_SIGNALS.has(signal)) {
92
- process.kill(process.pid, signal);
93
- return;
94
- }
95
-
96
- console.error(`❌ ${sourceLabel} crashed with ${signal}`);
97
- if (signal === "SIGILL") {
98
- console.error(
99
- "This usually means the bundled executable requires newer CPU instructions than this machine provides.",
100
- );
101
- console.error(
102
- "On Linux x64, install a release that includes the baseline-compatible binary build.",
103
- );
104
- } else {
105
- console.error("The bundled executable crashed before ClaudeKit could finish starting.");
106
- }
107
- console.error("If this persists, report it at: https://github.com/mrgoonie/claudekit-cli/issues");
108
- process.exit(1);
109
- };
80
+ const shouldWarnForBunFallback = () => !isDevPrerelease();
110
81
 
111
82
  /**
112
83
  * Run CLI via bun runtime. Preferred over Node.js when dist/index.js contains
@@ -123,7 +94,7 @@ const runWithBun = (showWarning = false) => {
123
94
  throw new Error("Compiled distribution not found. This may indicate a packaging issue.");
124
95
  }
125
96
  if (showWarning) {
126
- console.error("⚠️ Native binary not found, using bun runtime");
97
+ console.error("[i] Using bun runtime");
127
98
  }
128
99
  const result = spawnSync("bun", [distPath, ...process.argv.slice(2)], {
129
100
  stdio: "inherit",
@@ -134,16 +105,14 @@ const runWithBun = (showWarning = false) => {
134
105
  return false;
135
106
  }
136
107
  if (result.signal) {
137
- handleRuntimeSignalExit(result.signal, "Bun runtime");
108
+ process.kill(process.pid, result.signal);
138
109
  }
139
110
  process.exit(result.status || 0);
140
111
  };
141
112
 
142
113
  /**
143
114
  * Run CLI via Node.js as last-resort fallback (slower, no bun: protocol support).
144
- * The imported dist/index.js handles its own process lifecycle via the cac CLI framework.
145
115
  * @param {boolean} showWarning - Whether to show fallback warning message
146
- * @throws {Error} If dist/index.js is missing or fails to load
147
116
  */
148
117
  const runWithNode = async (showWarning = false) => {
149
118
  const distPath = join(__dirname, "..", "dist", "index.js");
@@ -151,10 +120,8 @@ const runWithNode = async (showWarning = false) => {
151
120
  throw new Error("Compiled distribution not found. This may indicate a packaging issue.");
152
121
  }
153
122
  if (showWarning) {
154
- console.error("⚠️ Native binary failed, using Node.js fallback (slower startup)");
123
+ console.error("[i] Using Node.js runtime (slower startup)");
155
124
  }
156
- // The CLI module handles process.exit() internally after command execution
157
- // Convert to file:// URL for cross-platform ESM compatibility (Windows paths require this)
158
125
  const distUrl = pathToFileURL(distPath).href;
159
126
  try {
160
127
  await import(distUrl);
@@ -164,117 +131,31 @@ const runWithNode = async (showWarning = false) => {
164
131
  };
165
132
 
166
133
  /**
167
- * Map platform/arch to binary filename
134
+ * Main execution — try Bun first, fall back to Node.js
168
135
  */
169
- const getBinaryPath = () => {
170
- const binaryMap = {
171
- "darwin-arm64": "ck-darwin-arm64",
172
- "darwin-x64": "ck-darwin-x64",
173
- "linux-x64": "ck-linux-x64",
174
- "win32-x64": "ck-win32-x64.exe",
175
- };
176
-
177
- const key = `${platform}-${arch}`;
178
- const binaryName = binaryMap[key];
179
-
180
- if (!binaryName) {
181
- // Unsupported platform - try Node.js fallback
182
- return null;
183
- }
184
-
185
- return join(__dirname, binaryName);
186
- };
187
-
188
- /**
189
- * Execute binary with fallback to Node.js on failure.
190
- * Uses Promise-based approach to avoid race conditions between error and exit events.
191
- *
192
- * Note: This Promise intentionally never rejects - all error paths call process.exit()
193
- * directly since this is a CLI entry point. The Promise is used purely for async flow
194
- * control and race condition prevention, not for error propagation.
195
- *
196
- * @param {string} binaryPath - Path to the platform-specific binary
197
- * @returns {Promise<void>} Resolves when fallback completes (binary exit calls process.exit directly)
198
- */
199
- const runBinary = (binaryPath) => {
200
- return new Promise((resolve) => {
201
- const child = spawn(binaryPath, process.argv.slice(2), {
202
- stdio: "inherit",
203
- windowsHide: true,
204
- });
205
-
206
- let errorOccurred = false;
207
-
208
- child.on("error", async (err) => {
209
- // Binary execution failed (e.g., ENOENT on Alpine/musl due to missing glibc)
210
- // Fall back to bun (exits process on success), then Node.js
211
- errorOccurred = true;
212
- if (hasBun()) {
213
- // runWithBun calls process.exit() on success — won't return here
214
- runWithBun(true);
215
- }
216
- try {
217
- await runWithNode(true);
218
- resolve();
219
- } catch (fallbackErr) {
220
- const fallbackMsg = getErrorMessage(fallbackErr);
221
- console.error(`❌ Binary failed: ${getErrorMessage(err)}`);
222
- console.error(`❌ Fallback also failed: ${fallbackMsg}`);
223
- if (fallbackMsg.includes("bun:") || fallbackMsg.includes("Received protocol")) {
224
- console.error("");
225
- console.error("This version of ClaudeKit CLI requires the bun runtime.");
226
- console.error("Install bun: curl -fsSL https://bun.sh/install | bash");
227
- console.error("Or switch to stable: npm install -g claudekit-cli@latest");
228
- } else {
229
- console.error(
230
- "Please report this issue at: https://github.com/mrgoonie/claudekit-cli/issues",
231
- );
232
- }
233
- process.exit(1);
234
- }
235
- });
236
-
237
- child.on("exit", (code, signal) => {
238
- // Don't handle exit if error handler is managing fallback
239
- if (errorOccurred) return;
240
-
241
- if (signal) {
242
- handleRuntimeSignalExit(signal, "Native binary");
243
- return;
244
- }
245
- // Use exitCode instead of exit() for proper handle cleanup on Windows
246
- // This prevents libuv assertion failures on Node.js 23.x/24.x/25.x
247
- // See: https://github.com/nodejs/node/issues/56645
248
- process.exitCode = code || 0;
249
- resolve();
250
- });
251
- });
252
- };
136
+ const main = async () => {
137
+ const showBunWarning = shouldWarnForBunFallback();
253
138
 
254
- /**
255
- * Handle fallback execution: try bun first (handles bun: imports), then Node.js.
256
- * @param {string} errorPrefix - Prefix for error message if all fallbacks fail
257
- * @param {boolean} showIssueLink - Whether to show issue reporting link
258
- */
259
- const handleFallback = async (errorPrefix, showIssueLink = false, showBunWarning = true) => {
260
139
  // Prefer bun — dist/index.js may contain bun-specific imports (bun:sqlite)
261
- // runWithBun calls process.exit() on success — won't return here
262
140
  if (hasBun()) {
263
- runWithBun(showBunWarning);
141
+ const bunOk = runWithBun(false);
142
+ if (!bunOk && showBunWarning) {
143
+ console.error("[i] Bun spawn failed, falling back to Node.js");
144
+ }
264
145
  }
146
+
265
147
  // Last resort: Node.js (works for stable builds without bun: imports)
266
148
  try {
267
- await runWithNode();
149
+ await runWithNode(showBunWarning);
268
150
  } catch (err) {
269
151
  const errMsg = getErrorMessage(err);
270
- console.error(`❌ ${errorPrefix}: ${errMsg}`);
271
- // Detect bun-specific import failures and guide user to install bun
152
+ console.error(`[X] Failed to run CLI: ${errMsg}`);
272
153
  if (errMsg.includes("bun:") || errMsg.includes("Received protocol")) {
273
154
  console.error("");
274
155
  console.error("This version of ClaudeKit CLI requires the bun runtime.");
275
156
  console.error("Install bun: curl -fsSL https://bun.sh/install | bash");
276
157
  console.error("Or switch to stable: npm install -g claudekit-cli@latest");
277
- } else if (showIssueLink) {
158
+ } else {
278
159
  console.error(
279
160
  "Please report this issue at: https://github.com/mrgoonie/claudekit-cli/issues",
280
161
  );
@@ -283,23 +164,4 @@ const handleFallback = async (errorPrefix, showIssueLink = false, showBunWarning
283
164
  }
284
165
  };
285
166
 
286
- /**
287
- * Main execution - determine which path to take
288
- */
289
- const main = async () => {
290
- const binaryPath = getBinaryPath();
291
- const showBunWarning = shouldWarnForBunFallback();
292
-
293
- if (!binaryPath) {
294
- // No binary for this platform - use Node.js fallback
295
- await handleFallback("Failed to run CLI", false, showBunWarning);
296
- } else if (!existsSync(binaryPath)) {
297
- // Binary should exist but doesn't - try fallback
298
- await handleFallback("Binary not found and fallback failed", true, showBunWarning);
299
- } else {
300
- // Execute the binary (handles its own fallback on error)
301
- await runBinary(binaryPath);
302
- }
303
- };
304
-
305
167
  main();
package/dist/index.js CHANGED
@@ -57245,7 +57245,7 @@ var package_default;
57245
57245
  var init_package = __esm(() => {
57246
57246
  package_default = {
57247
57247
  name: "claudekit-cli",
57248
- version: "3.39.3-dev.2",
57248
+ version: "3.39.3-dev.3",
57249
57249
  description: "CLI tool for bootstrapping and updating ClaudeKit projects",
57250
57250
  type: "module",
57251
57251
  repository: {
@@ -57261,10 +57261,6 @@ var init_package = __esm(() => {
57261
57261
  },
57262
57262
  files: [
57263
57263
  "bin/ck.js",
57264
- "bin/ck-linux-x64",
57265
- "bin/ck-darwin-arm64",
57266
- "bin/ck-darwin-x64",
57267
- "bin/ck-win32-x64.exe",
57268
57264
  "dist/index.js",
57269
57265
  "dist/ui/"
57270
57266
  ],
@@ -57274,12 +57270,7 @@ var init_package = __esm(() => {
57274
57270
  "ui:build": "cd src/ui && bun install --silent && bun run build",
57275
57271
  "ui:dev": "cd src/ui && bun run dev",
57276
57272
  build: `bun build src/index.ts --outdir dist --target node --external @octokit/rest && node -e "const fs=require('fs'),f='dist/index.js',c=fs.readFileSync(f,'utf-8');fs.writeFileSync(f,c.replace(/^#!.*\\n\\/\\/ @bun\\n/,''))"`,
57277
- compile: "bun run ui:build && bun run scripts/compile-binary.ts",
57278
- "compile:binary": "bun run ui:build && bun run scripts/compile-binary.ts --outfile bin/ck && cp bin/ck /usr/local/bin/ck && echo '✅ Installed globally: /usr/local/bin/ck'",
57279
- "compile:binaries": "node scripts/build-all-binaries.js",
57280
- "check-version-sync": "node scripts/check-binary-version-sync.js",
57281
57273
  "verify:package": "node scripts/prepublish-check.js",
57282
- "build:platform-binaries": "bun run scripts/build-platform-binaries.js",
57283
57274
  test: "bun test",
57284
57275
  "test:integration": "CK_RUN_CLI_INTEGRATION=1 bun test tests/integration/cli.test.ts",
57285
57276
  "test:watch": "bun test --watch",
@@ -59682,65 +59673,8 @@ var init_routes = __esm(() => {
59682
59673
 
59683
59674
  // src/domains/web-server/static-server.ts
59684
59675
  import { existsSync as existsSync40 } from "node:fs";
59685
- import { dirname as dirname18, extname as extname4, join as join50, resolve as resolve13 } from "node:path";
59676
+ import { dirname as dirname18, join as join50, resolve as resolve13 } from "node:path";
59686
59677
  import { fileURLToPath as fileURLToPath2 } from "node:url";
59687
- function tryServeFromEmbedded(app) {
59688
- if (typeof globalThis.Bun === "undefined" || !globalThis.Bun.embeddedFiles?.length) {
59689
- return false;
59690
- }
59691
- let prefix = "";
59692
- for (const blob of globalThis.Bun.embeddedFiles) {
59693
- const name = blob.name;
59694
- if (name === "index.html" || name.endsWith("/index.html")) {
59695
- prefix = name.replace("index.html", "");
59696
- break;
59697
- }
59698
- }
59699
- const fileMap = new Map;
59700
- let indexBlob = null;
59701
- for (const blob of globalThis.Bun.embeddedFiles) {
59702
- const rawName = blob.name;
59703
- const name = prefix && rawName.startsWith(prefix) ? rawName.slice(prefix.length) : rawName;
59704
- fileMap.set(name, blob);
59705
- if (name === "index.html") {
59706
- indexBlob = blob;
59707
- }
59708
- }
59709
- if (!indexBlob) {
59710
- logger.debug("Embedded files found but no index.html — skipping embedded serving");
59711
- return false;
59712
- }
59713
- logger.debug(`Serving UI from ${fileMap.size} embedded files`);
59714
- app.use(async (req, res, next) => {
59715
- if (req.path.startsWith("/api/") || req.path === "/ws" || req.path.startsWith("/ws/")) {
59716
- return next();
59717
- }
59718
- const reqPath = req.path.replace(/^\//, "");
59719
- if (reqPath.includes("..") || reqPath.includes("\x00")) {
59720
- return next();
59721
- }
59722
- const blob = fileMap.get(reqPath);
59723
- if (blob) {
59724
- const ext = extname4(reqPath);
59725
- const contentType = blob.type || MIME_FALLBACK[ext] || "application/octet-stream";
59726
- res.setHeader("Content-Type", contentType);
59727
- const cacheControl = ext === ".html" ? "no-cache" : "public, max-age=31536000, immutable";
59728
- res.setHeader("Cache-Control", cacheControl);
59729
- res.send(Buffer.from(await blob.arrayBuffer()));
59730
- return;
59731
- }
59732
- const hasExt = req.path.match(/\.(js|css|ico|png|jpg|svg|woff2?)$/);
59733
- if (!hasExt && indexBlob) {
59734
- const contentType = indexBlob.type || "text/html";
59735
- res.setHeader("Content-Type", contentType);
59736
- res.setHeader("Cache-Control", "no-cache");
59737
- res.send(Buffer.from(await indexBlob.arrayBuffer()));
59738
- return;
59739
- }
59740
- return next();
59741
- });
59742
- return true;
59743
- }
59744
59678
  function addRuntimeUiCandidate(candidates, runtimePath) {
59745
59679
  if (!runtimePath) {
59746
59680
  return;
@@ -59755,7 +59689,6 @@ function addRuntimeUiCandidate(candidates, runtimePath) {
59755
59689
  }
59756
59690
  function resolveUiDistPath() {
59757
59691
  const candidates = new Set;
59758
- addRuntimeUiCandidate(candidates, process.execPath);
59759
59692
  addRuntimeUiCandidate(candidates, process.argv[1]);
59760
59693
  candidates.add(join50(__dirname3, "ui"));
59761
59694
  candidates.add(join50(process.cwd(), "dist", "ui"));
@@ -59768,9 +59701,6 @@ function resolveUiDistPath() {
59768
59701
  return Array.from(candidates)[0] ?? join50(process.cwd(), "dist", "ui");
59769
59702
  }
59770
59703
  function serveStatic(app) {
59771
- if (tryServeFromEmbedded(app)) {
59772
- return;
59773
- }
59774
59704
  const uiDistPath = resolveUiDistPath();
59775
59705
  if (!existsSync40(uiDistPath)) {
59776
59706
  logger.warning(`UI dist not found at ${uiDistPath}. Run 'bun run ui:build' first.`);
@@ -59808,22 +59738,11 @@ function serveStatic(app) {
59808
59738
  });
59809
59739
  logger.debug(`Serving static files from ${uiDistPath}`);
59810
59740
  }
59811
- var import_express, __dirname3, MIME_FALLBACK;
59741
+ var import_express, __dirname3;
59812
59742
  var init_static_server = __esm(() => {
59813
59743
  init_logger();
59814
59744
  import_express = __toESM(require_express2(), 1);
59815
59745
  __dirname3 = dirname18(fileURLToPath2(import.meta.url));
59816
- MIME_FALLBACK = {
59817
- ".html": "text/html",
59818
- ".js": "application/javascript",
59819
- ".css": "text/css",
59820
- ".json": "application/json",
59821
- ".svg": "image/svg+xml",
59822
- ".png": "image/png",
59823
- ".ico": "image/x-icon",
59824
- ".woff2": "font/woff2",
59825
- ".woff": "font/woff"
59826
- };
59827
59746
  });
59828
59747
 
59829
59748
  // node_modules/ws/lib/constants.js
@@ -95974,7 +95893,7 @@ import { join as join108 } from "node:path";
95974
95893
  init_logger();
95975
95894
  import { readFile as readFile47, readdir as readdir30, writeFile as writeFile28 } from "node:fs/promises";
95976
95895
  import { platform as platform12 } from "node:os";
95977
- import { extname as extname6, join as join107 } from "node:path";
95896
+ import { extname as extname5, join as join107 } from "node:path";
95978
95897
  var IS_WINDOWS2 = platform12() === "win32";
95979
95898
  function getOpenCodeGlobalPath() {
95980
95899
  return "$HOME/.config/opencode/";
@@ -96025,7 +95944,7 @@ function transformOpenCodeContent(content) {
96025
95944
  return { transformed, changes };
96026
95945
  }
96027
95946
  function shouldTransformFile2(filename) {
96028
- const ext2 = extname6(filename).toLowerCase();
95947
+ const ext2 = extname5(filename).toLowerCase();
96029
95948
  return TRANSFORMABLE_EXTENSIONS2.has(ext2);
96030
95949
  }
96031
95950
  async function transformPathsForGlobalOpenCode(directory, options2 = {}) {
@@ -97606,7 +97525,7 @@ async function transformFolderPaths(extractDir, folders, options2 = {}) {
97606
97525
  init_logger();
97607
97526
  import { readFile as readFile51, readdir as readdir33, writeFile as writeFile32 } from "node:fs/promises";
97608
97527
  import { platform as platform13 } from "node:os";
97609
- import { extname as extname7, join as join115 } from "node:path";
97528
+ import { extname as extname6, join as join115 } from "node:path";
97610
97529
  var IS_WINDOWS3 = platform13() === "win32";
97611
97530
  var HOME_PREFIX = IS_WINDOWS3 ? "%USERPROFILE%" : "$HOME";
97612
97531
  function getHomeDirPrefix() {
@@ -97706,7 +97625,7 @@ function transformContent(content) {
97706
97625
  return { transformed, changes };
97707
97626
  }
97708
97627
  function shouldTransformFile3(filename) {
97709
- const ext2 = extname7(filename).toLowerCase();
97628
+ const ext2 = extname6(filename).toLowerCase();
97710
97629
  const basename16 = filename.split("/").pop() || filename;
97711
97630
  return TRANSFORMABLE_EXTENSIONS3.has(ext2) || ALWAYS_TRANSFORM_FILES.has(basename16);
97712
97631
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudekit-cli",
3
- "version": "3.39.3-dev.2",
3
+ "version": "3.39.3-dev.3",
4
4
  "description": "CLI tool for bootstrapping and updating ClaudeKit projects",
5
5
  "type": "module",
6
6
  "repository": {
@@ -16,10 +16,6 @@
16
16
  },
17
17
  "files": [
18
18
  "bin/ck.js",
19
- "bin/ck-linux-x64",
20
- "bin/ck-darwin-arm64",
21
- "bin/ck-darwin-x64",
22
- "bin/ck-win32-x64.exe",
23
19
  "dist/index.js",
24
20
  "dist/ui/"
25
21
  ],
@@ -29,12 +25,7 @@
29
25
  "ui:build": "cd src/ui && bun install --silent && bun run build",
30
26
  "ui:dev": "cd src/ui && bun run dev",
31
27
  "build": "bun build src/index.ts --outdir dist --target node --external @octokit/rest && node -e \"const fs=require('fs'),f='dist/index.js',c=fs.readFileSync(f,'utf-8');fs.writeFileSync(f,c.replace(/^#!.*\\n\\/\\/ @bun\\n/,''))\"",
32
- "compile": "bun run ui:build && bun run scripts/compile-binary.ts",
33
- "compile:binary": "bun run ui:build && bun run scripts/compile-binary.ts --outfile bin/ck && cp bin/ck /usr/local/bin/ck && echo '✅ Installed globally: /usr/local/bin/ck'",
34
- "compile:binaries": "node scripts/build-all-binaries.js",
35
- "check-version-sync": "node scripts/check-binary-version-sync.js",
36
28
  "verify:package": "node scripts/prepublish-check.js",
37
- "build:platform-binaries": "bun run scripts/build-platform-binaries.js",
38
29
  "test": "bun test",
39
30
  "test:integration": "CK_RUN_CLI_INTEGRATION=1 bun test tests/integration/cli.test.ts",
40
31
  "test:watch": "bun test --watch",