@kaitranntt/ccs 2.4.0 → 2.4.1
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/VERSION +1 -1
- package/bin/ccs.js +4 -42
- package/bin/claude-detector.js +23 -121
- package/lib/ccs +1 -1
- package/lib/ccs.ps1 +1 -1
- package/package.json +1 -1
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.4.
|
|
1
|
+
2.4.1
|
package/bin/ccs.js
CHANGED
|
@@ -5,7 +5,7 @@ const { spawn } = require('child_process');
|
|
|
5
5
|
const path = require('path');
|
|
6
6
|
const fs = require('fs');
|
|
7
7
|
const { showError, colors } = require('./helpers');
|
|
8
|
-
const { detectClaudeCli,
|
|
8
|
+
const { detectClaudeCli, showClaudeNotFoundError } = require('./claude-detector');
|
|
9
9
|
const { getSettingsPath } = require('./config-manager');
|
|
10
10
|
|
|
11
11
|
// Version (sync with package.json)
|
|
@@ -26,21 +26,8 @@ function handleVersionCommand() {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
function handleHelpCommand(remainingArgs) {
|
|
29
|
-
// Detect and validate Claude CLI
|
|
30
29
|
const claudeCli = detectClaudeCli();
|
|
31
30
|
|
|
32
|
-
if (!claudeCli) {
|
|
33
|
-
showClaudeNotFoundError();
|
|
34
|
-
process.exit(1);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
try {
|
|
38
|
-
validateClaudeCli(claudeCli);
|
|
39
|
-
} catch (e) {
|
|
40
|
-
showError(e.message);
|
|
41
|
-
process.exit(1);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
31
|
// Execute claude --help
|
|
45
32
|
const child = spawn(claudeCli, ['--help', ...remainingArgs], { stdio: 'inherit' });
|
|
46
33
|
|
|
@@ -53,7 +40,7 @@ function handleHelpCommand(remainingArgs) {
|
|
|
53
40
|
});
|
|
54
41
|
|
|
55
42
|
child.on('error', (err) => {
|
|
56
|
-
|
|
43
|
+
showClaudeNotFoundError();
|
|
57
44
|
process.exit(1);
|
|
58
45
|
});
|
|
59
46
|
}
|
|
@@ -124,18 +111,6 @@ function main() {
|
|
|
124
111
|
if (profile === 'default') {
|
|
125
112
|
const claudeCli = detectClaudeCli();
|
|
126
113
|
|
|
127
|
-
if (!claudeCli) {
|
|
128
|
-
showClaudeNotFoundError();
|
|
129
|
-
process.exit(1);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
try {
|
|
133
|
-
validateClaudeCli(claudeCli);
|
|
134
|
-
} catch (e) {
|
|
135
|
-
showError(e.message);
|
|
136
|
-
process.exit(1);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
114
|
// Execute claude with args
|
|
140
115
|
const child = spawn(claudeCli, remainingArgs, { stdio: 'inherit' });
|
|
141
116
|
|
|
@@ -148,7 +123,7 @@ function main() {
|
|
|
148
123
|
});
|
|
149
124
|
|
|
150
125
|
child.on('error', (err) => {
|
|
151
|
-
|
|
126
|
+
showClaudeNotFoundError();
|
|
152
127
|
process.exit(1);
|
|
153
128
|
});
|
|
154
129
|
|
|
@@ -161,19 +136,6 @@ function main() {
|
|
|
161
136
|
// Detect Claude CLI
|
|
162
137
|
const claudeCli = detectClaudeCli();
|
|
163
138
|
|
|
164
|
-
if (!claudeCli) {
|
|
165
|
-
showClaudeNotFoundError();
|
|
166
|
-
process.exit(1);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// Validate Claude CLI path
|
|
170
|
-
try {
|
|
171
|
-
validateClaudeCli(claudeCli);
|
|
172
|
-
} catch (e) {
|
|
173
|
-
showError(e.message);
|
|
174
|
-
process.exit(1);
|
|
175
|
-
}
|
|
176
|
-
|
|
177
139
|
// Execute claude with --settings
|
|
178
140
|
const claudeArgs = ['--settings', settingsPath, ...remainingArgs];
|
|
179
141
|
const child = spawn(claudeCli, claudeArgs, { stdio: 'inherit' });
|
|
@@ -187,7 +149,7 @@ function main() {
|
|
|
187
149
|
});
|
|
188
150
|
|
|
189
151
|
child.on('error', (err) => {
|
|
190
|
-
|
|
152
|
+
showClaudeNotFoundError();
|
|
191
153
|
process.exit(1);
|
|
192
154
|
});
|
|
193
155
|
}
|
package/bin/claude-detector.js
CHANGED
|
@@ -1,156 +1,58 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const fs = require('fs');
|
|
4
|
-
const
|
|
5
|
-
const { execSync } = require('child_process');
|
|
6
|
-
const { showError, expandPath, isPathSafe } = require('./helpers');
|
|
4
|
+
const { showError, expandPath } = require('./helpers');
|
|
7
5
|
|
|
8
6
|
// Detect Claude CLI executable
|
|
9
7
|
function detectClaudeCli() {
|
|
10
|
-
// Priority 1: CCS_CLAUDE_PATH environment variable
|
|
8
|
+
// Priority 1: CCS_CLAUDE_PATH environment variable (if user wants custom path)
|
|
11
9
|
if (process.env.CCS_CLAUDE_PATH) {
|
|
12
10
|
const ccsPath = expandPath(process.env.CCS_CLAUDE_PATH);
|
|
13
|
-
|
|
11
|
+
// Basic validation: file exists
|
|
12
|
+
if (fs.existsSync(ccsPath)) {
|
|
14
13
|
return ccsPath;
|
|
15
14
|
}
|
|
16
|
-
// Invalid CCS_CLAUDE_PATH -
|
|
15
|
+
// Invalid CCS_CLAUDE_PATH - show warning and fall back to PATH
|
|
16
|
+
console.warn('[!] Warning: CCS_CLAUDE_PATH is set but file not found:', ccsPath);
|
|
17
|
+
console.warn(' Falling back to system PATH lookup...');
|
|
17
18
|
}
|
|
18
19
|
|
|
19
|
-
// Priority 2:
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
process.platform === 'win32' ? 'where claude' : 'which claude',
|
|
23
|
-
{ encoding: 'utf8', stdio: ['pipe', 'pipe', 'ignore'] }
|
|
24
|
-
).trim().split('\n')[0];
|
|
25
|
-
|
|
26
|
-
if (claudePath && fs.existsSync(claudePath)) {
|
|
27
|
-
return claudePath;
|
|
28
|
-
}
|
|
29
|
-
} catch (e) {
|
|
30
|
-
// Not in PATH, continue to common locations
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// Priority 3: Check common installation locations
|
|
34
|
-
const commonLocations = getCommonLocations();
|
|
35
|
-
|
|
36
|
-
for (const location of commonLocations) {
|
|
37
|
-
const expandedPath = expandPath(location);
|
|
38
|
-
if (fs.existsSync(expandedPath) && isExecutable(expandedPath)) {
|
|
39
|
-
return expandedPath;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Not found
|
|
44
|
-
return null;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// Get platform-specific common locations
|
|
48
|
-
function getCommonLocations() {
|
|
49
|
-
const home = require('os').homedir();
|
|
50
|
-
|
|
51
|
-
if (process.platform === 'win32') {
|
|
52
|
-
return [
|
|
53
|
-
path.join(process.env.LOCALAPPDATA || '', 'Claude', 'claude.exe'),
|
|
54
|
-
path.join(process.env.PROGRAMFILES || '', 'Claude', 'claude.exe'),
|
|
55
|
-
'C:\\Program Files\\Claude\\claude.exe',
|
|
56
|
-
'D:\\Program Files\\Claude\\claude.exe',
|
|
57
|
-
path.join(home, '.local', 'bin', 'claude.exe')
|
|
58
|
-
];
|
|
59
|
-
} else if (process.platform === 'darwin') {
|
|
60
|
-
return [
|
|
61
|
-
'/usr/local/bin/claude',
|
|
62
|
-
path.join(home, '.local/bin/claude'),
|
|
63
|
-
'/opt/homebrew/bin/claude'
|
|
64
|
-
];
|
|
65
|
-
} else {
|
|
66
|
-
return [
|
|
67
|
-
'/usr/local/bin/claude',
|
|
68
|
-
path.join(home, '.local/bin/claude'),
|
|
69
|
-
'/usr/bin/claude'
|
|
70
|
-
];
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// Check if file is executable
|
|
75
|
-
function isExecutable(filePath) {
|
|
76
|
-
try {
|
|
77
|
-
fs.accessSync(filePath, fs.constants.X_OK);
|
|
78
|
-
return true;
|
|
79
|
-
} catch (e) {
|
|
80
|
-
return false;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// Validate Claude CLI path
|
|
85
|
-
function validateClaudeCli(claudePath) {
|
|
86
|
-
// Check 1: Empty path
|
|
87
|
-
if (!claudePath) {
|
|
88
|
-
throw new Error('No path provided');
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// Check 2: File exists
|
|
92
|
-
if (!fs.existsSync(claudePath)) {
|
|
93
|
-
throw new Error(`File not found: ${claudePath}`);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// Check 3: Is regular file (not directory)
|
|
97
|
-
const stats = fs.statSync(claudePath);
|
|
98
|
-
if (!stats.isFile()) {
|
|
99
|
-
throw new Error(`Path is a directory: ${claudePath}`);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Check 4: Is executable
|
|
103
|
-
if (!isExecutable(claudePath)) {
|
|
104
|
-
throw new Error(`File is not executable: ${claudePath}\n\nTry: chmod +x ${claudePath}`);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// Check 5: Path safety (prevent injection)
|
|
108
|
-
if (!isPathSafe(claudePath)) {
|
|
109
|
-
throw new Error(`Path contains unsafe characters: ${claudePath}\n\nAllowed: alphanumeric, path separators, spaces, hyphens, underscores, dots`);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return true;
|
|
20
|
+
// Priority 2: Use 'claude' from PATH (trust the system)
|
|
21
|
+
// This is the standard case - if user installed Claude CLI, it's in their PATH
|
|
22
|
+
return 'claude';
|
|
113
23
|
}
|
|
114
24
|
|
|
115
25
|
// Show Claude not found error
|
|
116
26
|
function showClaudeNotFoundError() {
|
|
117
|
-
const envVarStatus = process.env.CCS_CLAUDE_PATH || '(not set)';
|
|
118
27
|
const isWindows = process.platform === 'win32';
|
|
119
28
|
|
|
120
|
-
const errorMsg = `Claude CLI not found
|
|
29
|
+
const errorMsg = `Claude CLI not found in PATH
|
|
121
30
|
|
|
122
|
-
|
|
123
|
-
- CCS_CLAUDE_PATH: ${envVarStatus}
|
|
124
|
-
- System PATH: not found
|
|
125
|
-
- Common locations: not found
|
|
31
|
+
CCS requires Claude CLI to be installed and available in your PATH.
|
|
126
32
|
|
|
127
33
|
Solutions:
|
|
128
|
-
1.
|
|
34
|
+
1. Install Claude CLI:
|
|
35
|
+
https://docs.claude.com/en/docs/claude-code/installation
|
|
129
36
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
: '# Find where Claude is installed\n sudo find / -name claude 2>/dev/null\n\n # Add to PATH\n export PATH="/path/to/claude/bin:$PATH"\n echo \'export PATH="/path/to/claude/bin:$PATH"\' >> ~/.bashrc\n source ~/.bashrc'
|
|
133
|
-
}
|
|
37
|
+
2. Verify installation:
|
|
38
|
+
${isWindows ? 'Get-Command claude' : 'command -v claude'}
|
|
134
39
|
|
|
135
|
-
|
|
40
|
+
3. If installed but not in PATH, add it:
|
|
41
|
+
# Find Claude installation
|
|
42
|
+
${isWindows ? 'where.exe claude' : 'which claude'}
|
|
136
43
|
|
|
44
|
+
# Or set custom path
|
|
137
45
|
${isWindows
|
|
138
|
-
? '$env:CCS_CLAUDE_PATH = \'
|
|
139
|
-
: 'export CCS_CLAUDE_PATH
|
|
46
|
+
? '$env:CCS_CLAUDE_PATH = \'C:\\path\\to\\claude.exe\''
|
|
47
|
+
: 'export CCS_CLAUDE_PATH=\'/path/to/claude\''
|
|
140
48
|
}
|
|
141
49
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
https://docs.claude.com/en/docs/claude-code/installation
|
|
145
|
-
|
|
146
|
-
Verify installation:
|
|
147
|
-
ccs --version`;
|
|
50
|
+
Restart your terminal after installation.`;
|
|
148
51
|
|
|
149
52
|
showError(errorMsg);
|
|
150
53
|
}
|
|
151
54
|
|
|
152
55
|
module.exports = {
|
|
153
56
|
detectClaudeCli,
|
|
154
|
-
validateClaudeCli,
|
|
155
57
|
showClaudeNotFoundError
|
|
156
58
|
};
|
package/lib/ccs
CHANGED
package/lib/ccs.ps1
CHANGED
|
@@ -72,7 +72,7 @@ Restart your terminal after installation.
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
# Version (updated by scripts/bump-version.sh)
|
|
75
|
-
$CcsVersion = "2.4.
|
|
75
|
+
$CcsVersion = "2.4.1"
|
|
76
76
|
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
77
77
|
|
|
78
78
|
# Installation function for commands and skills
|