cc-starter 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.
- package/LICENSE +21 -0
- package/README.md +149 -0
- package/bin/cc-starter.js +55 -0
- package/lib/constants.js +32 -0
- package/lib/detect.js +109 -0
- package/lib/plugins.js +74 -0
- package/lib/scaffold.js +261 -0
- package/lib/wizard.js +99 -0
- package/package.json +30 -0
- package/template/CLAUDE.md.hbs +44 -0
- package/template/claude/commands/kickstart.md +16 -0
- package/template/claude/memory/MEMORY.md +11 -0
- package/template/claude/project/README.md +7 -0
- package/template/claude/reference/README.md +7 -0
- package/template/claude/rules/01-general.md +36 -0
- package/template/claude/rules/02-code-standards.md +23 -0
- package/template/claude/rules/03-dev-ops.md +20 -0
- package/template/claude/settings.json +4 -0
- package/template/scripts/stats/cocomo.js +178 -0
- package/template/scripts/stats/project-report.js +640 -0
- package/template/scripts/stats/vibe-code.js +533 -0
- package/template/scripts/stats/vibe-stats.js +249 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Lars Fanter
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# cc-starter
|
|
2
|
+
|
|
3
|
+
**Claude Code Project Kickstart** — One command to set up Claude Code like a pro.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/cc-starter)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## The Problem
|
|
11
|
+
|
|
12
|
+
> You open Claude Code on a new project and start from scratch. No rules, no memory, no structure. Every session you re-explain the same things. You read entire files when you only need the types. You have no idea what your project costs.
|
|
13
|
+
|
|
14
|
+
## The Solution
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npx cc-starter
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
One command. Interactive wizard. Full setup in 30 seconds.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 📦 What You Get
|
|
25
|
+
|
|
26
|
+
| What | Description |
|
|
27
|
+
|------|-------------|
|
|
28
|
+
| `.claude/rules/` | Battle-tested working rules (task tracking, verification, git discipline) |
|
|
29
|
+
| `.claude/memory/` | Persistent memory system — Claude remembers across sessions |
|
|
30
|
+
| `CLAUDE.md` | Auto-generated project overview with detected tech stack |
|
|
31
|
+
| `scripts/stats/vibe-code.js` | Token-saving extraction tool (types, tree, imports, functions) |
|
|
32
|
+
| `scripts/stats/vibe-stats.js` | Track and measure your token savings |
|
|
33
|
+
| `scripts/stats/cocomo.js` | COCOMO-II project cost estimation |
|
|
34
|
+
| `scripts/stats/project-report.js` | Visual HTML statistics report |
|
|
35
|
+
| Plugin presets | One-click installation of best Claude Code plugins |
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 🔥 Token Savings — The Killer Feature
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
Traditional: Read entire 500-line file → ~2,000 tokens
|
|
43
|
+
cc-starter: Extract only types and signatures → ~200 tokens
|
|
44
|
+
|
|
45
|
+
That's 90% savings per file read. Over a session, that's thousands of tokens.
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Instead of Claude reading entire files, `vibe-code.js` extracts only what matters:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
node scripts/stats/vibe-code.js types src/api.ts # Just the interfaces
|
|
52
|
+
node scripts/stats/vibe-code.js tree src/ # Directory overview
|
|
53
|
+
node scripts/stats/vibe-code.js imports src/app.tsx # Dependency graph
|
|
54
|
+
node scripts/stats/vibe-code.js functions lib/utils.ts # Function signatures
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## 📊 COCOMO Estimation
|
|
60
|
+
|
|
61
|
+
Know what your project is worth — before the client asks.
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
COCOMO-II Project Estimation
|
|
65
|
+
════════════════════════════════
|
|
66
|
+
|
|
67
|
+
Lines of Code:
|
|
68
|
+
TypeScript 32,450
|
|
69
|
+
CSS 4,210
|
|
70
|
+
─────────────────────────
|
|
71
|
+
Total 36,660
|
|
72
|
+
|
|
73
|
+
Estimation (Semi-Detached):
|
|
74
|
+
Effort: 9.8 Person-Months
|
|
75
|
+
Schedule: 5.9 Months
|
|
76
|
+
Team Size: 1.7 Developers
|
|
77
|
+
Cost: €47,040 (at €80/h)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## 🔌 Plugin Presets
|
|
83
|
+
|
|
84
|
+
| Preset | Plugins | Best For |
|
|
85
|
+
|--------|---------|----------|
|
|
86
|
+
| Minimal | superpowers | Solo devs, getting started |
|
|
87
|
+
| Standard | + feature-dev, pr-review-toolkit | Most projects |
|
|
88
|
+
| Full | + frontend-design, ui-ux-pro-max | Frontend-heavy projects |
|
|
89
|
+
| Custom | Pick your own | Power users |
|
|
90
|
+
|
|
91
|
+
Plugins are installed via `claude mcp add` — no manual config needed.
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## 🚀 Installation
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
# New project
|
|
99
|
+
mkdir my-app && cd my-app
|
|
100
|
+
npx cc-starter
|
|
101
|
+
|
|
102
|
+
# Existing project
|
|
103
|
+
cd my-existing-project
|
|
104
|
+
npx cc-starter
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
**Requirements:** Node.js 18+, Claude Code CLI (optional, for plugin installation)
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## ⚔️ Comparison
|
|
112
|
+
|
|
113
|
+
| Feature | cc-starter | TheDecipherist | serpro69 | cloudnative-co |
|
|
114
|
+
|---------|:---:|:---:|:---:|:---:|
|
|
115
|
+
| Token-saving scripts | ✅ | ❌ | ❌ | ❌ |
|
|
116
|
+
| COCOMO estimation | ✅ | ❌ | ❌ | ❌ |
|
|
117
|
+
| HTML project report | ✅ | ❌ | ❌ | ❌ |
|
|
118
|
+
| Interactive wizard | ✅ | ✅ | ❌ | ✅ |
|
|
119
|
+
| Plugin installation | ✅ | ❌ | ❌ | ❌ |
|
|
120
|
+
| Memory system | ✅ | ❌ | ❌ | ❌ |
|
|
121
|
+
| Tech stack detection | ✅ | ❌ | ❌ | ✅ |
|
|
122
|
+
| Zero dependencies in output | ✅ | ✅ | ❌ | ✅ |
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## 🔍 How It Works
|
|
127
|
+
|
|
128
|
+
```
|
|
129
|
+
npx cc-starter
|
|
130
|
+
├─ Detect tech stack (TypeScript, Next.js, ...)
|
|
131
|
+
├─ Interactive wizard (name, rate, plugins)
|
|
132
|
+
├─ Scaffold .claude/ + scripts/ + CLAUDE.md
|
|
133
|
+
├─ Install selected plugins
|
|
134
|
+
└─ Ready to code!
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
The wizard detects your project's language, framework, and package manager — then generates a tailored `CLAUDE.md` and rule set. All output files are plain text with zero runtime dependencies.
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## 🤝 Contributing
|
|
142
|
+
|
|
143
|
+
PRs welcome. See [LICENSE](LICENSE) for details.
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Author
|
|
148
|
+
|
|
149
|
+
Built by [Lars Fanter](https://www.linkedin.com/in/larsfanter/) — from real-world experience building production apps with Claude Code.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { detect } from '../lib/detect.js';
|
|
5
|
+
import { wizard } from '../lib/wizard.js';
|
|
6
|
+
import { scaffold } from '../lib/scaffold.js';
|
|
7
|
+
import { installPlugins } from '../lib/plugins.js';
|
|
8
|
+
|
|
9
|
+
async function main() {
|
|
10
|
+
// 1. Banner
|
|
11
|
+
console.log(chalk.cyan.bold(`
|
|
12
|
+
╔═══════════════════════════════════════╗
|
|
13
|
+
║ cc-starter v1.0.0 ║
|
|
14
|
+
║ Claude Code Project Kickstart ║
|
|
15
|
+
╚═══════════════════════════════════════╝
|
|
16
|
+
`));
|
|
17
|
+
|
|
18
|
+
// 2. Auto-detect tech stack
|
|
19
|
+
console.log(chalk.dim(' Detecting tech stack...'));
|
|
20
|
+
const techStack = detect(process.cwd());
|
|
21
|
+
|
|
22
|
+
if (techStack.languages.length > 0 || techStack.frameworks.length > 0) {
|
|
23
|
+
const detected = [...techStack.languages, ...techStack.frameworks].join(', ');
|
|
24
|
+
console.log(chalk.green(` ✓ Found: ${detected}\n`));
|
|
25
|
+
} else {
|
|
26
|
+
console.log(chalk.dim(' No specific tech stack detected (empty or new project)\n'));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// 3. Interactive wizard
|
|
30
|
+
const config = await wizard(techStack);
|
|
31
|
+
|
|
32
|
+
// 4. Scaffold files
|
|
33
|
+
console.log(chalk.cyan('\n Scaffolding project...\n'));
|
|
34
|
+
const result = await scaffold(config);
|
|
35
|
+
|
|
36
|
+
// 5. Install plugins
|
|
37
|
+
await installPlugins(config.plugins);
|
|
38
|
+
|
|
39
|
+
// 6. Summary
|
|
40
|
+
console.log(chalk.green.bold(`
|
|
41
|
+
══════════════════════════════════════════
|
|
42
|
+
Done! Run 'claude' to start coding.
|
|
43
|
+
|
|
44
|
+
Quick commands:
|
|
45
|
+
node scripts/stats/cocomo.js → Project cost estimate
|
|
46
|
+
node scripts/stats/vibe-code.js help → Token-saving tools
|
|
47
|
+
node scripts/stats/project-report.js → HTML statistics
|
|
48
|
+
══════════════════════════════════════════
|
|
49
|
+
`));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
main().catch(err => {
|
|
53
|
+
console.error(chalk.red(`\n Error: ${err.message}\n`));
|
|
54
|
+
process.exit(1);
|
|
55
|
+
});
|
package/lib/constants.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export const PLUGIN_PRESETS = {
|
|
2
|
+
minimal: [
|
|
3
|
+
{ name: 'superpowers', source: 'superpowers-marketplace', desc: 'TDD, debugging, plans, brainstorming' }
|
|
4
|
+
],
|
|
5
|
+
standard: [
|
|
6
|
+
{ name: 'superpowers', source: 'superpowers-marketplace', desc: 'TDD, debugging, plans, brainstorming' },
|
|
7
|
+
{ name: 'feature-dev', source: 'claude-code-plugins', desc: 'Code explorer, architect, reviewer agents' },
|
|
8
|
+
{ name: 'pr-review-toolkit', source: 'claude-code-plugins', desc: 'PR reviews, silent-failure-hunter, type analyzer' }
|
|
9
|
+
],
|
|
10
|
+
full: [
|
|
11
|
+
{ name: 'superpowers', source: 'superpowers-marketplace', desc: 'TDD, debugging, plans, brainstorming' },
|
|
12
|
+
{ name: 'feature-dev', source: 'claude-code-plugins', desc: 'Code explorer, architect, reviewer agents' },
|
|
13
|
+
{ name: 'pr-review-toolkit', source: 'claude-code-plugins', desc: 'PR reviews, silent-failure-hunter, type analyzer' },
|
|
14
|
+
{ name: 'frontend-design', source: 'claude-code-plugins', desc: 'UI/UX design skill for frontend projects' },
|
|
15
|
+
{ name: 'ui-ux-pro-max', source: 'ui-ux-pro-max-skill', desc: 'AI design intelligence — 67 UI styles, 161 color palettes, 57 font pairings' }
|
|
16
|
+
]
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const ALL_PLUGINS = [
|
|
20
|
+
{ name: 'superpowers', source: 'superpowers-marketplace', desc: 'TDD, debugging, plans, brainstorming' },
|
|
21
|
+
{ name: 'feature-dev', source: 'claude-code-plugins', desc: 'Code explorer, architect, reviewer agents' },
|
|
22
|
+
{ name: 'pr-review-toolkit', source: 'claude-code-plugins', desc: 'PR reviews, silent-failure-hunter, type analyzer' },
|
|
23
|
+
{ name: 'frontend-design', source: 'claude-code-plugins', desc: 'UI/UX design skill for frontend projects' },
|
|
24
|
+
{ name: 'ui-ux-pro-max', source: 'ui-ux-pro-max-skill', desc: 'AI design intelligence — 67 UI styles, 161 color palettes, 57 font pairings' }
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
export const REPORT_STYLES = {
|
|
28
|
+
minimal: { label: 'Minimal — zero dependencies, plain HTML with CSS bars', packages: [] },
|
|
29
|
+
fancy: { label: 'Fancy — visual charts via chart.js CDN (no npm install needed)', packages: [] }
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const DEFAULT_HOURLY_RATE = 80;
|
package/lib/detect.js
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Detect programming languages and frameworks in the given directory.
|
|
6
|
+
* @param {string} cwd - Directory to analyze
|
|
7
|
+
* @returns {{ languages: string[], frameworks: string[], raw: object }}
|
|
8
|
+
*/
|
|
9
|
+
export function detect(cwd) {
|
|
10
|
+
const languages = [];
|
|
11
|
+
const frameworks = [];
|
|
12
|
+
const raw = { files: [], packageJson: null, requirements: null, pyproject: null };
|
|
13
|
+
|
|
14
|
+
const exists = (file) => {
|
|
15
|
+
try { return fs.existsSync(path.join(cwd, file)); } catch { return false; }
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const globMatch = (ext) => {
|
|
19
|
+
try {
|
|
20
|
+
const entries = fs.readdirSync(cwd);
|
|
21
|
+
return entries.some((e) => e.endsWith(ext));
|
|
22
|
+
} catch { return false; }
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const readJson = (file) => {
|
|
26
|
+
try { return JSON.parse(fs.readFileSync(path.join(cwd, file), 'utf-8')); } catch { return null; }
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const readText = (file) => {
|
|
30
|
+
try { return fs.readFileSync(path.join(cwd, file), 'utf-8'); } catch { return null; }
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// ── Language detection ──────────────────────────────────────────────
|
|
34
|
+
|
|
35
|
+
const pkg = readJson('package.json');
|
|
36
|
+
if (pkg) raw.packageJson = pkg;
|
|
37
|
+
|
|
38
|
+
if (pkg || globMatch('.ts')) {
|
|
39
|
+
const hasTs = pkg?.devDependencies?.typescript || pkg?.dependencies?.typescript || globMatch('.ts');
|
|
40
|
+
languages.push(hasTs ? 'TypeScript' : 'JavaScript');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const hasPython = exists('requirements.txt') || exists('pyproject.toml') || exists('setup.py');
|
|
44
|
+
if (hasPython) languages.push('Python');
|
|
45
|
+
|
|
46
|
+
if (exists('go.mod')) languages.push('Go');
|
|
47
|
+
if (exists('Cargo.toml')) languages.push('Rust');
|
|
48
|
+
if (exists('pom.xml') || exists('build.gradle') || exists('build.gradle.kts')) languages.push('Java');
|
|
49
|
+
if (globMatch('.csproj') || globMatch('.sln')) languages.push('C# / .NET');
|
|
50
|
+
if (exists('Gemfile')) languages.push('Ruby');
|
|
51
|
+
if (exists('composer.json')) languages.push('PHP');
|
|
52
|
+
|
|
53
|
+
// ── Framework detection (Node / package.json) ──────────────────────
|
|
54
|
+
|
|
55
|
+
if (pkg) {
|
|
56
|
+
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
57
|
+
|
|
58
|
+
const nodeFw = [
|
|
59
|
+
['next', 'Next.js'],
|
|
60
|
+
['react', 'React'],
|
|
61
|
+
['vue', 'Vue'],
|
|
62
|
+
['@angular/core', 'Angular'],
|
|
63
|
+
['svelte', 'Svelte'],
|
|
64
|
+
['express', 'Express'],
|
|
65
|
+
['fastify', 'Fastify'],
|
|
66
|
+
['tailwindcss', 'Tailwind CSS'],
|
|
67
|
+
['prisma', 'Prisma'],
|
|
68
|
+
['drizzle-orm', 'Drizzle'],
|
|
69
|
+
['@supabase/supabase-js','Supabase'],
|
|
70
|
+
['mongoose', 'MongoDB'],
|
|
71
|
+
];
|
|
72
|
+
|
|
73
|
+
for (const [dep, name] of nodeFw) {
|
|
74
|
+
if (allDeps[dep]) frameworks.push(name);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// ── Framework detection (Python) ───────────────────────────────────
|
|
79
|
+
|
|
80
|
+
if (hasPython) {
|
|
81
|
+
const reqTxt = readText('requirements.txt');
|
|
82
|
+
const pyproject = readText('pyproject.toml');
|
|
83
|
+
if (reqTxt) raw.requirements = reqTxt;
|
|
84
|
+
if (pyproject) raw.pyproject = pyproject;
|
|
85
|
+
|
|
86
|
+
const pythonSource = [reqTxt, pyproject].filter(Boolean).join('\n').toLowerCase();
|
|
87
|
+
|
|
88
|
+
const pyFw = [
|
|
89
|
+
['fastapi', 'FastAPI'],
|
|
90
|
+
['django', 'Django'],
|
|
91
|
+
['flask', 'Flask'],
|
|
92
|
+
];
|
|
93
|
+
|
|
94
|
+
for (const [pkg, name] of pyFw) {
|
|
95
|
+
if (pythonSource.includes(pkg)) frameworks.push(name);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// ── Collect notable files for raw output ───────────────────────────
|
|
100
|
+
|
|
101
|
+
const notable = [
|
|
102
|
+
'package.json', 'tsconfig.json', 'requirements.txt', 'pyproject.toml',
|
|
103
|
+
'setup.py', 'go.mod', 'Cargo.toml', 'pom.xml', 'build.gradle',
|
|
104
|
+
'build.gradle.kts', 'Gemfile', 'composer.json',
|
|
105
|
+
];
|
|
106
|
+
raw.files = notable.filter(exists);
|
|
107
|
+
|
|
108
|
+
return { languages, frameworks, raw };
|
|
109
|
+
}
|
package/lib/plugins.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { execSync } from 'node:child_process';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Check whether the `claude` CLI is available on this machine.
|
|
6
|
+
* @returns {boolean}
|
|
7
|
+
*/
|
|
8
|
+
function isClaudeAvailable() {
|
|
9
|
+
try {
|
|
10
|
+
execSync('claude --version', { stdio: 'ignore', timeout: 10000 });
|
|
11
|
+
return true;
|
|
12
|
+
} catch {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Install Claude Code plugins.
|
|
19
|
+
*
|
|
20
|
+
* - If no plugins are selected, prints a dim note and returns.
|
|
21
|
+
* - If the `claude` CLI is not found, prints manual-install instructions.
|
|
22
|
+
* - Otherwise attempts `claude plugins add` for each plugin, falling back
|
|
23
|
+
* to manual instructions on failure.
|
|
24
|
+
*
|
|
25
|
+
* @param {Array<{ name: string, source: string }>} plugins
|
|
26
|
+
*/
|
|
27
|
+
export async function installPlugins(plugins) {
|
|
28
|
+
if (!plugins || plugins.length === 0) {
|
|
29
|
+
console.log(chalk.dim(' No plugins selected.'));
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// ── Pre-flight: is the CLI installed? ─────────────────────────────
|
|
34
|
+
|
|
35
|
+
if (!isClaudeAvailable()) {
|
|
36
|
+
console.log(chalk.yellow('\n ⚠ Claude Code CLI not found. Skipping plugin installation.'));
|
|
37
|
+
console.log(chalk.dim(' Install Claude Code first: https://claude.ai/download'));
|
|
38
|
+
console.log(chalk.dim(' Then install plugins manually:\n'));
|
|
39
|
+
for (const p of plugins) {
|
|
40
|
+
console.log(chalk.dim(` claude plugins add ${p.name}@${p.source}`));
|
|
41
|
+
}
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// ── Install each plugin ───────────────────────────────────────────
|
|
46
|
+
|
|
47
|
+
console.log(chalk.cyan('\n Installing plugins...\n'));
|
|
48
|
+
|
|
49
|
+
let installed = 0;
|
|
50
|
+
let failed = 0;
|
|
51
|
+
|
|
52
|
+
for (const plugin of plugins) {
|
|
53
|
+
const ref = `${plugin.name}@${plugin.source}`;
|
|
54
|
+
try {
|
|
55
|
+
console.log(chalk.dim(` Installing ${plugin.name}...`));
|
|
56
|
+
execSync(`claude plugins add ${ref}`, {
|
|
57
|
+
stdio: 'inherit',
|
|
58
|
+
timeout: 30000,
|
|
59
|
+
});
|
|
60
|
+
console.log(chalk.green(` ✓ ${plugin.name} installed`));
|
|
61
|
+
installed++;
|
|
62
|
+
} catch {
|
|
63
|
+
console.log(chalk.yellow(` ⚠ ${plugin.name} — manual install needed:`));
|
|
64
|
+
console.log(chalk.dim(` claude plugins add ${ref}`));
|
|
65
|
+
failed++;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// ── Summary ───────────────────────────────────────────────────────
|
|
70
|
+
|
|
71
|
+
console.log('');
|
|
72
|
+
if (installed > 0) console.log(chalk.green(` ${installed} plugin(s) installed`));
|
|
73
|
+
if (failed > 0) console.log(chalk.yellow(` ${failed} plugin(s) need manual installation`));
|
|
74
|
+
}
|