@kaitranntt/ccs 2.4.3 → 2.4.5
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/README.md +29 -15
- package/README.vi.md +50 -7
- package/VERSION +1 -1
- package/bin/ccs.js +16 -109
- package/bin/claude-detector.js +5 -34
- package/bin/config-manager.js +8 -63
- package/bin/helpers.js +7 -23
- package/lib/ccs +107 -71
- package/lib/ccs.ps1 +210 -364
- package/package.json +13 -3
- package/scripts/bump-version.sh +136 -0
- package/scripts/check-executables.js +18 -0
- package/scripts/get-version.sh +16 -0
- package/scripts/postinstall.js +99 -0
- package/scripts/sync-version.js +15 -0
- package/scripts/worker.js +46 -0
- package/scripts/wrangler.toml +15 -0
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ Switch between Claude Sonnet 4.5 and GLM 4.6 instantly. Stop hitting rate limits
|
|
|
11
11
|
|
|
12
12
|
[](LICENSE)
|
|
13
13
|
[]()
|
|
14
|
-
[](https://www.npmjs.com/package/@kaitranntt/ccs)
|
|
15
15
|
[](https://claudekit.cc?ref=HMNKXOHN)
|
|
16
16
|
|
|
17
17
|
**Languages**: [English](README.md) | [Tiếng Việt](README.vi.md)
|
|
@@ -35,7 +35,7 @@ claude /login
|
|
|
35
35
|
|
|
36
36
|
**macOS / Linux / Windows**
|
|
37
37
|
```bash
|
|
38
|
-
npm install -g @
|
|
38
|
+
npm install -g @kaitranntt/ccs
|
|
39
39
|
```
|
|
40
40
|
|
|
41
41
|
Compatible with npm, yarn, pnpm, and bun package managers.
|
|
@@ -73,20 +73,22 @@ All major package managers are supported:
|
|
|
73
73
|
|
|
74
74
|
```bash
|
|
75
75
|
# npm (default)
|
|
76
|
-
npm install -g @
|
|
76
|
+
npm install -g @kaitranntt/ccs
|
|
77
77
|
|
|
78
78
|
# yarn
|
|
79
|
-
yarn global add @
|
|
79
|
+
yarn global add @kaitranntt/ccs
|
|
80
80
|
|
|
81
81
|
# pnpm (70% less disk space)
|
|
82
|
-
pnpm add -g @
|
|
82
|
+
pnpm add -g @kaitranntt/ccs
|
|
83
83
|
|
|
84
84
|
# bun (30x faster)
|
|
85
|
-
bun add -g @
|
|
85
|
+
bun add -g @kaitranntt/ccs
|
|
86
86
|
```
|
|
87
87
|
|
|
88
88
|
### Configuration (Auto-created)
|
|
89
89
|
|
|
90
|
+
**CCS automatically creates configuration during installation** (via npm postinstall script).
|
|
91
|
+
|
|
90
92
|
**~/.ccs/config.json**:
|
|
91
93
|
```json
|
|
92
94
|
{
|
|
@@ -106,7 +108,7 @@ export CCS_CLAUDE_PATH="/path/to/claude" # Unix
|
|
|
106
108
|
$env:CCS_CLAUDE_PATH = "D:\Tools\Claude\claude.exe" # Windows
|
|
107
109
|
```
|
|
108
110
|
|
|
109
|
-
**See [Troubleshooting Guide](./docs/troubleshooting.md#claude-cli-in-non-standard-location) for detailed setup instructions.**
|
|
111
|
+
**See [Troubleshooting Guide](./docs/en/troubleshooting.md#claude-cli-in-non-standard-location) for detailed setup instructions.**
|
|
110
112
|
|
|
111
113
|
---
|
|
112
114
|
|
|
@@ -233,7 +235,9 @@ ccs --uninstall # Remove CCS commands and skills from ~/.claude/
|
|
|
233
235
|
|
|
234
236
|
---
|
|
235
237
|
|
|
236
|
-
### 🗑️ Uninstall
|
|
238
|
+
### 🗑️ Official Uninstall
|
|
239
|
+
|
|
240
|
+
**The recommended way to completely remove CCS:**
|
|
237
241
|
|
|
238
242
|
**macOS / Linux**:
|
|
239
243
|
```bash
|
|
@@ -245,6 +249,16 @@ curl -fsSL ccs.kaitran.ca/uninstall | bash
|
|
|
245
249
|
irm ccs.kaitran.ca/uninstall | iex
|
|
246
250
|
```
|
|
247
251
|
|
|
252
|
+
> 💡 **Why use the official uninstaller?**
|
|
253
|
+
> - Removes all CCS files and configurations
|
|
254
|
+
> - Cleans up PATH modifications
|
|
255
|
+
> - Removes Claude CLI commands/skills
|
|
256
|
+
> - Handles edge cases we've tested
|
|
257
|
+
|
|
258
|
+
**Alternative methods** (if official uninstaller fails):
|
|
259
|
+
- **npm**: `npm uninstall -g @kaitranntt/ccs`
|
|
260
|
+
- **Manual**: See [troubleshooting guide](./docs/en/troubleshooting.md#manual-uninstall)
|
|
261
|
+
|
|
248
262
|
---
|
|
249
263
|
|
|
250
264
|
## 🎯 Philosophy
|
|
@@ -258,17 +272,17 @@ irm ccs.kaitran.ca/uninstall | iex
|
|
|
258
272
|
## 📖 Documentation
|
|
259
273
|
|
|
260
274
|
**Complete documentation in [docs/](./docs/)**:
|
|
261
|
-
- [Installation Guide](./docs/installation.md)
|
|
262
|
-
- [Configuration](./docs/configuration.md)
|
|
263
|
-
- [Usage Examples](./docs/usage.md)
|
|
264
|
-
- [Troubleshooting](./docs/troubleshooting.md)
|
|
265
|
-
- [Contributing](./docs/contributing.md)
|
|
275
|
+
- [Installation Guide](./docs/en/installation.md)
|
|
276
|
+
- [Configuration](./docs/en/configuration.md)
|
|
277
|
+
- [Usage Examples](./docs/en/usage.md)
|
|
278
|
+
- [Troubleshooting](./docs/en/troubleshooting.md)
|
|
279
|
+
- [Contributing](./docs/en/contributing.md)
|
|
266
280
|
|
|
267
281
|
---
|
|
268
282
|
|
|
269
283
|
## 🤝 Contributing
|
|
270
284
|
|
|
271
|
-
We welcome contributions! Please see our [Contributing Guide](./docs/contributing.md) for details.
|
|
285
|
+
We welcome contributions! Please see our [Contributing Guide](./docs/en/contributing.md) for details.
|
|
272
286
|
|
|
273
287
|
---
|
|
274
288
|
|
|
@@ -282,6 +296,6 @@ CCS is licensed under the [MIT License](LICENSE).
|
|
|
282
296
|
|
|
283
297
|
**Made with ❤️ for developers who hit rate limits too often**
|
|
284
298
|
|
|
285
|
-
[⭐ Star this repo](https://github.com/kaitranntt/ccs) | [🐛 Report issues](https://github.com/kaitranntt/ccs/issues) | [📖 Read docs](./docs/)
|
|
299
|
+
[⭐ Star this repo](https://github.com/kaitranntt/ccs) | [🐛 Report issues](https://github.com/kaitranntt/ccs/issues) | [📖 Read docs](./docs/en/)
|
|
286
300
|
|
|
287
301
|
</div>
|
package/README.vi.md
CHANGED
|
@@ -30,6 +30,17 @@ claude /login
|
|
|
30
30
|
|
|
31
31
|
### Phương Pháp Cài Đặt Chính
|
|
32
32
|
|
|
33
|
+
#### Option 1: npm Package (Được khuyến nghị)
|
|
34
|
+
|
|
35
|
+
**macOS / Linux / Windows**
|
|
36
|
+
```bash
|
|
37
|
+
npm install -g @kaitranntt/ccs
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Tương thích với các trình quản lý package npm, yarn, pnpm, và bun.
|
|
41
|
+
|
|
42
|
+
#### Option 2: Cài Đặt Trực Tiếp (Truyền thống)
|
|
43
|
+
|
|
33
44
|
**macOS / Linux**
|
|
34
45
|
```bash
|
|
35
46
|
curl -fsSL ccs.kaitran.ca/install | bash
|
|
@@ -55,8 +66,28 @@ ccs "Debug issue này"
|
|
|
55
66
|
ccs "Viết unit tests"
|
|
56
67
|
```
|
|
57
68
|
|
|
69
|
+
#### Package Manager Options
|
|
70
|
+
|
|
71
|
+
Tất cả các trình quản lý package chính đều được hỗ trợ:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
# npm (mặc định)
|
|
75
|
+
npm install -g @kaitranntt/ccs
|
|
76
|
+
|
|
77
|
+
# yarn
|
|
78
|
+
yarn global add @kaitranntt/ccs
|
|
79
|
+
|
|
80
|
+
# pnpm (ít hơn 70% dung lượng đĩa)
|
|
81
|
+
pnpm add -g @kaitranntt/ccs
|
|
82
|
+
|
|
83
|
+
# bun (nhanh hơn 30x)
|
|
84
|
+
bun add -g @kaitranntt/ccs
|
|
85
|
+
```
|
|
86
|
+
|
|
58
87
|
### Cấu Hình (Tự Tạo)
|
|
59
88
|
|
|
89
|
+
**CCS tự động tạo cấu hình trong quá trình cài đặt** (thông qua script postinstall của npm).
|
|
90
|
+
|
|
60
91
|
**~/.ccs/config.json**:
|
|
61
92
|
```json
|
|
62
93
|
{
|
|
@@ -203,7 +234,9 @@ ccs --uninstall # Gỡ bỏ lệnh và kỹ năng CCS khỏi ~/.claude/
|
|
|
203
234
|
|
|
204
235
|
---
|
|
205
236
|
|
|
206
|
-
### 🗑️ Gỡ Cài Đặt
|
|
237
|
+
### 🗑️ Gỡ Cài Đặt Chính Thức
|
|
238
|
+
|
|
239
|
+
**Cách được khuyến nghị để gỡ bỏ hoàn toàn CCS:**
|
|
207
240
|
|
|
208
241
|
**macOS / Linux**:
|
|
209
242
|
```bash
|
|
@@ -215,6 +248,16 @@ curl -fsSL ccs.kaitran.ca/uninstall | bash
|
|
|
215
248
|
irm ccs.kaitran.ca/uninstall | iex
|
|
216
249
|
```
|
|
217
250
|
|
|
251
|
+
> 💡 **Tại sao dùng uninstaller chính thức?**
|
|
252
|
+
> - Gỡ bỏ tất cả file và cấu hình CCS
|
|
253
|
+
> - Dọn dẹp PATH modifications
|
|
254
|
+
> - Gỡ bỏ commands/skills Claude CLI
|
|
255
|
+
> - Xử lý các trường hợp đặc biệt đã test
|
|
256
|
+
|
|
257
|
+
**Phương pháp thay thế** (nếu uninstaller chính thức thất bại):
|
|
258
|
+
- **npm**: `npm uninstall -g @kaitranntt/ccs`
|
|
259
|
+
- **Thủ công**: Xem [hướng dẫn khắc phục](./docs/vi/troubleshooting.vi.md#gỡ-cài-đặt-thủ-công)
|
|
260
|
+
|
|
218
261
|
---
|
|
219
262
|
|
|
220
263
|
## 🎯 Triết Lý
|
|
@@ -228,17 +271,17 @@ irm ccs.kaitran.ca/uninstall | iex
|
|
|
228
271
|
## 📖 Tài Liệu
|
|
229
272
|
|
|
230
273
|
**Tài liệu đầy đủ trong [docs/](./docs/)**:
|
|
231
|
-
- [Hướng dẫn Cài đặt](./docs/
|
|
232
|
-
- [Cấu hình](./docs/
|
|
233
|
-
- [Ví dụ Sử dụng](./docs/
|
|
234
|
-
- [Khắc phục Sự cố](./docs/
|
|
235
|
-
- [Đóng góp](./docs/
|
|
274
|
+
- [Hướng dẫn Cài đặt](./docs/installation.md)
|
|
275
|
+
- [Cấu hình](./docs/configuration.md)
|
|
276
|
+
- [Ví dụ Sử dụng](./docs/usage.md)
|
|
277
|
+
- [Khắc phục Sự cố](./docs/troubleshooting.md)
|
|
278
|
+
- [Đóng góp](./docs/contributing.md)
|
|
236
279
|
|
|
237
280
|
---
|
|
238
281
|
|
|
239
282
|
## 🤝 Đóng Góp
|
|
240
283
|
|
|
241
|
-
Chúng tôi chào mừng đóng góp!
|
|
284
|
+
Chúng tôi chào mừng đóng góp! Vui lòng xem [Hướng dẫn Đóng góp](./docs/contributing.md) để biết chi tiết.
|
|
242
285
|
|
|
243
286
|
---
|
|
244
287
|
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.4.
|
|
1
|
+
2.4.5
|
package/bin/ccs.js
CHANGED
|
@@ -4,35 +4,24 @@
|
|
|
4
4
|
const { spawn } = require('child_process');
|
|
5
5
|
const path = require('path');
|
|
6
6
|
const fs = require('fs');
|
|
7
|
-
const {
|
|
7
|
+
const { error } = require('./helpers');
|
|
8
8
|
const { detectClaudeCli, showClaudeNotFoundError } = require('./claude-detector');
|
|
9
9
|
const { getSettingsPath } = require('./config-manager');
|
|
10
10
|
|
|
11
11
|
// Version (sync with package.json)
|
|
12
12
|
const CCS_VERSION = require('../package.json').version;
|
|
13
13
|
|
|
14
|
-
//
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Helper: Escape arguments for shell execution to prevent security vulnerabilities
|
|
28
|
-
function escapeShellArg(arg) {
|
|
29
|
-
if (process.platform !== 'win32') {
|
|
30
|
-
// Unix-like systems: escape single quotes and wrap in single quotes
|
|
31
|
-
return "'" + arg.replace(/'/g, "'\"'\"'") + "'";
|
|
32
|
-
} else {
|
|
33
|
-
// Windows: escape double quotes and wrap in double quotes
|
|
34
|
-
return '"' + arg.replace(/"/g, '""') + '"';
|
|
35
|
-
}
|
|
14
|
+
// Execute Claude CLI with unified spawn logic
|
|
15
|
+
function execClaude(claudeCli, args) {
|
|
16
|
+
const child = spawn(claudeCli, args, { stdio: 'inherit', windowsHide: true });
|
|
17
|
+
child.on('exit', (code, signal) => {
|
|
18
|
+
if (signal) process.kill(process.pid, signal);
|
|
19
|
+
else process.exit(code || 0);
|
|
20
|
+
});
|
|
21
|
+
child.on('error', () => {
|
|
22
|
+
showClaudeNotFoundError();
|
|
23
|
+
process.exit(1);
|
|
24
|
+
});
|
|
36
25
|
}
|
|
37
26
|
|
|
38
27
|
// Special command handlers
|
|
@@ -51,39 +40,12 @@ function handleVersionCommand() {
|
|
|
51
40
|
|
|
52
41
|
function handleHelpCommand(remainingArgs) {
|
|
53
42
|
const claudeCli = detectClaudeCli();
|
|
54
|
-
|
|
55
|
-
// Check if claude was found
|
|
56
43
|
if (!claudeCli) {
|
|
57
44
|
showClaudeNotFoundError();
|
|
58
45
|
process.exit(1);
|
|
59
46
|
}
|
|
60
47
|
|
|
61
|
-
|
|
62
|
-
const spawnOpts = getSpawnOptions(claudeCli);
|
|
63
|
-
let claudeArgs, child;
|
|
64
|
-
|
|
65
|
-
if (spawnOpts.shell) {
|
|
66
|
-
// When shell is required, escape arguments properly
|
|
67
|
-
claudeArgs = [claudeCli, '--help', ...remainingArgs].map(escapeShellArg).join(' ');
|
|
68
|
-
child = spawn(claudeArgs, spawnOpts);
|
|
69
|
-
} else {
|
|
70
|
-
// When no shell needed, use arguments array directly
|
|
71
|
-
claudeArgs = ['--help', ...remainingArgs];
|
|
72
|
-
child = spawn(claudeCli, claudeArgs, spawnOpts);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
child.on('exit', (code, signal) => {
|
|
76
|
-
if (signal) {
|
|
77
|
-
process.kill(process.pid, signal);
|
|
78
|
-
} else {
|
|
79
|
-
process.exit(code || 0);
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
child.on('error', (err) => {
|
|
84
|
-
showClaudeNotFoundError();
|
|
85
|
-
process.exit(1);
|
|
86
|
-
});
|
|
48
|
+
execClaude(claudeCli, ['--help', ...remainingArgs]);
|
|
87
49
|
}
|
|
88
50
|
|
|
89
51
|
function handleInstallCommand() {
|
|
@@ -91,9 +53,7 @@ function handleInstallCommand() {
|
|
|
91
53
|
console.log('[Installing CCS Commands and Skills]');
|
|
92
54
|
console.log('Feature not yet implemented in Node.js standalone');
|
|
93
55
|
console.log('Use traditional installer for now:');
|
|
94
|
-
console.log(
|
|
95
|
-
? ' irm ccs.kaitran.ca/install | iex'
|
|
96
|
-
: ' curl -fsSL ccs.kaitran.ca/install | bash');
|
|
56
|
+
console.log(' curl -fsSL ccs.kaitran.ca/install | bash');
|
|
97
57
|
process.exit(0);
|
|
98
58
|
}
|
|
99
59
|
|
|
@@ -151,40 +111,12 @@ function main() {
|
|
|
151
111
|
// Special case: "default" profile just runs claude directly
|
|
152
112
|
if (profile === 'default') {
|
|
153
113
|
const claudeCli = detectClaudeCli();
|
|
154
|
-
|
|
155
|
-
// Check if claude was found
|
|
156
114
|
if (!claudeCli) {
|
|
157
115
|
showClaudeNotFoundError();
|
|
158
116
|
process.exit(1);
|
|
159
117
|
}
|
|
160
118
|
|
|
161
|
-
|
|
162
|
-
const spawnOpts = getSpawnOptions(claudeCli);
|
|
163
|
-
let claudeArgs, child;
|
|
164
|
-
|
|
165
|
-
if (spawnOpts.shell) {
|
|
166
|
-
// When shell is required, escape arguments properly
|
|
167
|
-
claudeArgs = [claudeCli, ...remainingArgs].map(escapeShellArg).join(' ');
|
|
168
|
-
child = spawn(claudeArgs, spawnOpts);
|
|
169
|
-
} else {
|
|
170
|
-
// When no shell needed, use arguments array directly
|
|
171
|
-
claudeArgs = remainingArgs;
|
|
172
|
-
child = spawn(claudeCli, claudeArgs, spawnOpts);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
child.on('exit', (code, signal) => {
|
|
176
|
-
if (signal) {
|
|
177
|
-
process.kill(process.pid, signal);
|
|
178
|
-
} else {
|
|
179
|
-
process.exit(code || 0);
|
|
180
|
-
}
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
child.on('error', (err) => {
|
|
184
|
-
showClaudeNotFoundError();
|
|
185
|
-
process.exit(1);
|
|
186
|
-
});
|
|
187
|
-
|
|
119
|
+
execClaude(claudeCli, remainingArgs);
|
|
188
120
|
return;
|
|
189
121
|
}
|
|
190
122
|
|
|
@@ -201,32 +133,7 @@ function main() {
|
|
|
201
133
|
}
|
|
202
134
|
|
|
203
135
|
// Execute claude with --settings
|
|
204
|
-
|
|
205
|
-
const spawnOpts = getSpawnOptions(claudeCli);
|
|
206
|
-
let claudeArgs, child;
|
|
207
|
-
|
|
208
|
-
if (spawnOpts.shell) {
|
|
209
|
-
// When shell is required, escape arguments properly
|
|
210
|
-
claudeArgs = [claudeCli, ...claudeArgsList].map(escapeShellArg).join(' ');
|
|
211
|
-
child = spawn(claudeArgs, spawnOpts);
|
|
212
|
-
} else {
|
|
213
|
-
// When no shell needed, use arguments array directly
|
|
214
|
-
claudeArgs = claudeArgsList;
|
|
215
|
-
child = spawn(claudeCli, claudeArgs, spawnOpts);
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
child.on('exit', (code, signal) => {
|
|
219
|
-
if (signal) {
|
|
220
|
-
process.kill(process.pid, signal);
|
|
221
|
-
} else {
|
|
222
|
-
process.exit(code || 0);
|
|
223
|
-
}
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
child.on('error', (err) => {
|
|
227
|
-
showClaudeNotFoundError();
|
|
228
|
-
process.exit(1);
|
|
229
|
-
});
|
|
136
|
+
execClaude(claudeCli, ['--settings', settingsPath, ...remainingArgs]);
|
|
230
137
|
}
|
|
231
138
|
|
|
232
139
|
// Run main
|
package/bin/claude-detector.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const { execSync } = require('child_process');
|
|
5
|
-
const {
|
|
5
|
+
const { expandPath } = require('./helpers');
|
|
6
6
|
|
|
7
7
|
// Detect Claude CLI executable
|
|
8
8
|
function detectClaudeCli() {
|
|
@@ -60,40 +60,11 @@ function detectClaudeCli() {
|
|
|
60
60
|
return null;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
// Show Claude not found error
|
|
63
|
+
// Show Claude not found error
|
|
64
64
|
function showClaudeNotFoundError() {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const errorMsg = `Claude CLI not found in PATH
|
|
69
|
-
|
|
70
|
-
CCS requires Claude CLI to be installed and available in your PATH.
|
|
71
|
-
|
|
72
|
-
[i] Diagnostic Info:
|
|
73
|
-
Platform: ${process.platform}
|
|
74
|
-
PATH directories: ${pathDirs.length}
|
|
75
|
-
Looking for: claude${isWindows ? '.exe' : ''}
|
|
76
|
-
|
|
77
|
-
Solutions:
|
|
78
|
-
1. Install Claude CLI:
|
|
79
|
-
https://docs.claude.com/en/docs/claude-code/installation
|
|
80
|
-
|
|
81
|
-
2. Verify installation:
|
|
82
|
-
${isWindows ? 'Get-Command claude' : 'command -v claude'}
|
|
83
|
-
|
|
84
|
-
3. If installed but not in PATH, add it:
|
|
85
|
-
# Find Claude installation
|
|
86
|
-
${isWindows ? 'where.exe claude' : 'which claude'}
|
|
87
|
-
|
|
88
|
-
# Or set custom path
|
|
89
|
-
${isWindows
|
|
90
|
-
? '$env:CCS_CLAUDE_PATH = \'C:\\path\\to\\claude.exe\''
|
|
91
|
-
: 'export CCS_CLAUDE_PATH=\'/path/to/claude\''
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
Restart your terminal after installation.`;
|
|
95
|
-
|
|
96
|
-
showError(errorMsg);
|
|
65
|
+
console.error('ERROR: Claude CLI not found in PATH');
|
|
66
|
+
console.error('Install from: https://docs.claude.com/en/docs/claude-code/installation');
|
|
67
|
+
process.exit(1);
|
|
97
68
|
}
|
|
98
69
|
|
|
99
70
|
module.exports = {
|
package/bin/config-manager.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const path = require('path');
|
|
5
5
|
const os = require('os');
|
|
6
|
-
const {
|
|
6
|
+
const { error, expandPath } = require('./helpers');
|
|
7
7
|
|
|
8
8
|
// Get config file path
|
|
9
9
|
function getConfigPath() {
|
|
@@ -16,24 +16,7 @@ function readConfig() {
|
|
|
16
16
|
|
|
17
17
|
// Check config exists
|
|
18
18
|
if (!fs.existsSync(configPath)) {
|
|
19
|
-
|
|
20
|
-
showError(`Config file not found: ${configPath}
|
|
21
|
-
|
|
22
|
-
Solutions:
|
|
23
|
-
1. Reinstall CCS:
|
|
24
|
-
${isWindows ? 'irm ccs.kaitran.ca/install | iex' : 'curl -fsSL ccs.kaitran.ca/install | bash'}
|
|
25
|
-
|
|
26
|
-
2. Or create config manually:
|
|
27
|
-
mkdir -p ~/.ccs
|
|
28
|
-
cat > ~/.ccs/config.json << 'EOF'
|
|
29
|
-
{
|
|
30
|
-
"profiles": {
|
|
31
|
-
"glm": "~/.ccs/glm.settings.json",
|
|
32
|
-
"default": "~/.claude/settings.json"
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
EOF`);
|
|
36
|
-
process.exit(1);
|
|
19
|
+
error(`Config file not found: ${configPath}`);
|
|
37
20
|
}
|
|
38
21
|
|
|
39
22
|
// Read and parse JSON
|
|
@@ -42,23 +25,12 @@ EOF`);
|
|
|
42
25
|
const configContent = fs.readFileSync(configPath, 'utf8');
|
|
43
26
|
config = JSON.parse(configContent);
|
|
44
27
|
} catch (e) {
|
|
45
|
-
|
|
46
|
-
showError(`Invalid JSON in ${configPath}
|
|
47
|
-
|
|
48
|
-
Fix the JSON syntax or reinstall:
|
|
49
|
-
${isWindows ? 'irm ccs.kaitran.ca/install | iex' : 'curl -fsSL ccs.kaitran.ca/install | bash'}`);
|
|
50
|
-
process.exit(1);
|
|
28
|
+
error(`Invalid JSON in ${configPath}: ${e.message}`);
|
|
51
29
|
}
|
|
52
30
|
|
|
53
31
|
// Validate config has profiles object
|
|
54
32
|
if (!config.profiles || typeof config.profiles !== 'object') {
|
|
55
|
-
|
|
56
|
-
showError(`Config must have 'profiles' object
|
|
57
|
-
|
|
58
|
-
See config.example.json for correct format
|
|
59
|
-
Or reinstall:
|
|
60
|
-
${isWindows ? 'irm ccs.kaitran.ca/install | iex' : 'curl -fsSL ccs.kaitran.ca/install | bash'}`);
|
|
61
|
-
process.exit(1);
|
|
33
|
+
error(`Config must have 'profiles' object in ${configPath}`);
|
|
62
34
|
}
|
|
63
35
|
|
|
64
36
|
return config;
|
|
@@ -68,24 +40,12 @@ Or reinstall:
|
|
|
68
40
|
function getSettingsPath(profile) {
|
|
69
41
|
const config = readConfig();
|
|
70
42
|
|
|
71
|
-
// Validate profile name
|
|
72
|
-
if (!validateProfileName(profile)) {
|
|
73
|
-
showError(`Invalid profile name: ${profile}
|
|
74
|
-
|
|
75
|
-
Use only alphanumeric characters, dash, or underscore.`);
|
|
76
|
-
process.exit(1);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
43
|
// Get settings path
|
|
80
44
|
const settingsPath = config.profiles[profile];
|
|
81
45
|
|
|
82
46
|
if (!settingsPath) {
|
|
83
|
-
const availableProfiles = Object.keys(config.profiles).
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
Available profiles:
|
|
87
|
-
${availableProfiles}`);
|
|
88
|
-
process.exit(1);
|
|
47
|
+
const availableProfiles = Object.keys(config.profiles).join(', ');
|
|
48
|
+
error(`Profile '${profile}' not found. Available: ${availableProfiles}`);
|
|
89
49
|
}
|
|
90
50
|
|
|
91
51
|
// Expand path
|
|
@@ -93,14 +53,7 @@ ${availableProfiles}`);
|
|
|
93
53
|
|
|
94
54
|
// Validate settings file exists
|
|
95
55
|
if (!fs.existsSync(expandedPath)) {
|
|
96
|
-
|
|
97
|
-
showError(`Settings file not found: ${expandedPath}
|
|
98
|
-
|
|
99
|
-
Solutions:
|
|
100
|
-
1. Create the settings file for profile '${profile}'
|
|
101
|
-
2. Update the path in ${getConfigPath()}
|
|
102
|
-
3. Or reinstall: ${isWindows ? 'irm ccs.kaitran.ca/install | iex' : 'curl -fsSL ccs.kaitran.ca/install | bash'}`);
|
|
103
|
-
process.exit(1);
|
|
56
|
+
error(`Settings file not found: ${expandedPath}`);
|
|
104
57
|
}
|
|
105
58
|
|
|
106
59
|
// Validate settings file is valid JSON
|
|
@@ -108,15 +61,7 @@ Solutions:
|
|
|
108
61
|
const settingsContent = fs.readFileSync(expandedPath, 'utf8');
|
|
109
62
|
JSON.parse(settingsContent);
|
|
110
63
|
} catch (e) {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
Details: ${e.message}
|
|
114
|
-
|
|
115
|
-
Solutions:
|
|
116
|
-
1. Validate JSON at https://jsonlint.com
|
|
117
|
-
2. Or reset to template: echo '{"env":{}}' > ${expandedPath}
|
|
118
|
-
3. Or reinstall CCS`);
|
|
119
|
-
process.exit(1);
|
|
64
|
+
error(`Invalid JSON in ${expandedPath}: ${e.message}`);
|
|
120
65
|
}
|
|
121
66
|
|
|
122
67
|
return expandedPath;
|
package/bin/helpers.js
CHANGED
|
@@ -15,15 +15,11 @@ const colors = useColors ? {
|
|
|
15
15
|
reset: '\x1b[0m'
|
|
16
16
|
} : { red: '', yellow: '', cyan: '', green: '', bold: '', reset: '' };
|
|
17
17
|
|
|
18
|
-
//
|
|
19
|
-
function
|
|
20
|
-
console.error(
|
|
21
|
-
console.error(
|
|
22
|
-
|
|
23
|
-
console.error(colors.red + colors.bold + '╚═════════════════════════════════════════════╝' + colors.reset);
|
|
24
|
-
console.error('');
|
|
25
|
-
console.error(colors.red + message + colors.reset);
|
|
26
|
-
console.error('');
|
|
18
|
+
// Simple error formatting
|
|
19
|
+
function error(message) {
|
|
20
|
+
console.error(`ERROR: ${message}`);
|
|
21
|
+
console.error('Try: npm install -g @kaitranntt/ccs --force');
|
|
22
|
+
process.exit(1);
|
|
27
23
|
}
|
|
28
24
|
|
|
29
25
|
// Path expansion (~ and env vars)
|
|
@@ -45,21 +41,9 @@ function expandPath(pathStr) {
|
|
|
45
41
|
return path.normalize(pathStr);
|
|
46
42
|
}
|
|
47
43
|
|
|
48
|
-
// Validate profile name (alphanumeric, dash, underscore only)
|
|
49
|
-
function validateProfileName(profile) {
|
|
50
|
-
return /^[a-zA-Z0-9_-]+$/.test(profile);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// Validate path safety (prevent injection)
|
|
54
|
-
function isPathSafe(pathStr) {
|
|
55
|
-
// Allow: alphanumeric, path separators, space, dash, underscore, dot, colon, tilde
|
|
56
|
-
return !/[;|&<>`$*?\[\]'"()]/.test(pathStr);
|
|
57
|
-
}
|
|
58
44
|
|
|
59
45
|
module.exports = {
|
|
60
46
|
colors,
|
|
61
|
-
|
|
62
|
-
expandPath
|
|
63
|
-
validateProfileName,
|
|
64
|
-
isPathSafe
|
|
47
|
+
error,
|
|
48
|
+
expandPath
|
|
65
49
|
};
|