claudeskill-cli 1.0.0

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 (5) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +552 -0
  3. package/bin/cs.js +187 -0
  4. package/dist/index.js +44985 -0
  5. package/package.json +91 -0
package/bin/cs.js ADDED
@@ -0,0 +1,187 @@
1
+ #!/usr/bin/env node
2
+
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.
7
+ */
8
+
9
+ import { spawn } from "node:child_process";
10
+ import { existsSync } from "node:fs";
11
+ import { dirname, join } from "node:path";
12
+ import { fileURLToPath, pathToFileURL } from "node:url";
13
+
14
+ // Minimum required Node.js version (major.minor)
15
+ const MIN_NODE_VERSION = [18, 0];
16
+
17
+ /**
18
+ * Check if the current Node.js version meets minimum requirements.
19
+ * Required because dependencies like ora@8 use ES2022+ features.
20
+ */
21
+ const checkNodeVersion = () => {
22
+ const [major, minor] = process.versions.node.split(".").map(Number);
23
+ const [minMajor, minMinor] = MIN_NODE_VERSION;
24
+
25
+ if (major < minMajor || (major === minMajor && minor < minMinor)) {
26
+ console.error(
27
+ `❌ Node.js ${MIN_NODE_VERSION.join(".")}+ is required. Current version: ${process.versions.node}`,
28
+ );
29
+ console.error(" Please upgrade Node.js: https://nodejs.org/");
30
+ process.exit(1);
31
+ }
32
+ };
33
+
34
+ // Check Node.js version before proceeding
35
+ checkNodeVersion();
36
+
37
+ const __dirname = dirname(fileURLToPath(import.meta.url));
38
+
39
+ // Detect platform and architecture
40
+ const platform = process.platform;
41
+ const arch = process.arch;
42
+
43
+ /**
44
+ * Extract error message safely with type guard
45
+ */
46
+ const getErrorMessage = (err) => {
47
+ return err instanceof Error ? err.message : String(err);
48
+ };
49
+
50
+ /**
51
+ * Run CLI via Node.js as fallback (slower but works on all platforms).
52
+ * The imported dist/index.js handles its own process lifecycle via the cac CLI framework.
53
+ * @param {boolean} showWarning - Whether to show fallback warning message
54
+ * @throws {Error} If dist/index.js is missing or fails to load
55
+ */
56
+ const runWithNode = async (showWarning = false) => {
57
+ const distPath = join(__dirname, "..", "dist", "index.js");
58
+ if (!existsSync(distPath)) {
59
+ throw new Error("Compiled distribution not found. This may indicate a packaging issue.");
60
+ }
61
+ if (showWarning) {
62
+ console.error("⚠️ Native binary failed, using Node.js fallback (slower startup)");
63
+ }
64
+ // The CLI module handles process.exit() internally after command execution
65
+ // Convert to file:// URL for cross-platform ESM compatibility (Windows paths require this)
66
+ const distUrl = pathToFileURL(distPath).href;
67
+ try {
68
+ await import(distUrl);
69
+ } catch (importErr) {
70
+ throw new Error(`Failed to load CLI module: ${getErrorMessage(importErr)}`);
71
+ }
72
+ };
73
+
74
+ /**
75
+ * Map platform/arch to binary filename
76
+ */
77
+ const getBinaryPath = () => {
78
+ const binaryMap = {
79
+ "darwin-arm64": "cs-darwin-arm64",
80
+ "darwin-x64": "cs-darwin-x64",
81
+ "linux-x64": "cs-linux-x64",
82
+ "win32-x64": "cs-win32-x64.exe",
83
+ };
84
+
85
+ const key = `${platform}-${arch}`;
86
+ const binaryName = binaryMap[key];
87
+
88
+ if (!binaryName) {
89
+ // Unsupported platform - try Node.js fallback
90
+ return null;
91
+ }
92
+
93
+ return join(__dirname, binaryName);
94
+ };
95
+
96
+ /**
97
+ * Execute binary with fallback to Node.js on failure.
98
+ * Uses Promise-based approach to avoid race conditions between error and exit events.
99
+ *
100
+ * Note: This Promise intentionally never rejects - all error paths call process.exit()
101
+ * directly since this is a CLI entry point. The Promise is used purely for async flow
102
+ * control and race condition prevention, not for error propagation.
103
+ *
104
+ * @param {string} binaryPath - Path to the platform-specific binary
105
+ * @returns {Promise<void>} Resolves when fallback completes (binary exit calls process.exit directly)
106
+ */
107
+ const runBinary = (binaryPath) => {
108
+ return new Promise((resolve) => {
109
+ const child = spawn(binaryPath, process.argv.slice(2), {
110
+ stdio: "inherit",
111
+ windowsHide: true,
112
+ });
113
+
114
+ let errorOccurred = false;
115
+
116
+ child.on("error", async (err) => {
117
+ // Binary execution failed (e.g., ENOENT on Alpine/musl due to missing glibc)
118
+ // Fall back to Node.js execution
119
+ errorOccurred = true;
120
+ try {
121
+ await runWithNode(true);
122
+ resolve();
123
+ } catch (fallbackErr) {
124
+ console.error(`❌ Binary failed: ${getErrorMessage(err)}`);
125
+ console.error(`❌ Fallback also failed: ${getErrorMessage(fallbackErr)}`);
126
+ console.error(
127
+ "Please report this issue at: https://github.com/luan-thnh/claudeskill-cli/issues",
128
+ );
129
+ process.exit(1);
130
+ }
131
+ });
132
+
133
+ child.on("exit", (code, signal) => {
134
+ // Don't handle exit if error handler is managing fallback
135
+ if (errorOccurred) return;
136
+
137
+ if (signal) {
138
+ process.kill(process.pid, signal);
139
+ return;
140
+ }
141
+ // Use exitCode instead of exit() for proper handle cleanup on Windows
142
+ // This prevents libuv assertion failures on Node.js 23.x/24.x/25.x
143
+ // See: https://github.com/nodejs/node/issues/56645
144
+ process.exitCode = code || 0;
145
+ resolve();
146
+ });
147
+ });
148
+ };
149
+
150
+ /**
151
+ * Handle fallback execution with error reporting
152
+ * @param {string} errorPrefix - Prefix for error message if fallback fails
153
+ * @param {boolean} showIssueLink - Whether to show issue reporting link
154
+ */
155
+ const handleFallback = async (errorPrefix, showIssueLink = false) => {
156
+ try {
157
+ await runWithNode();
158
+ } catch (err) {
159
+ console.error(`❌ ${errorPrefix}: ${getErrorMessage(err)}`);
160
+ if (showIssueLink) {
161
+ console.error(
162
+ "Please report this issue at: https://github.com/luan-thnh/claudeskill-cli/issues",
163
+ );
164
+ }
165
+ process.exit(1);
166
+ }
167
+ };
168
+
169
+ /**
170
+ * Main execution - determine which path to take
171
+ */
172
+ const main = async () => {
173
+ const binaryPath = getBinaryPath();
174
+
175
+ if (!binaryPath) {
176
+ // No binary for this platform - use Node.js fallback
177
+ await handleFallback("Failed to run CLI");
178
+ } else if (!existsSync(binaryPath)) {
179
+ // Binary should exist but doesn't - try fallback
180
+ await handleFallback("Binary not found and fallback failed", true);
181
+ } else {
182
+ // Execute the binary (handles its own fallback on error)
183
+ await runBinary(binaryPath);
184
+ }
185
+ };
186
+
187
+ main();