ccraft 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/bin/claude-craft.js +85 -0
- package/package.json +39 -0
- package/src/commands/auth.js +43 -0
- package/src/commands/create.js +543 -0
- package/src/commands/install.js +480 -0
- package/src/commands/logout.js +24 -0
- package/src/commands/update.js +339 -0
- package/src/constants.js +299 -0
- package/src/generators/directories.js +30 -0
- package/src/generators/metadata.js +57 -0
- package/src/generators/security.js +39 -0
- package/src/prompts/gather.js +308 -0
- package/src/ui/brand.js +62 -0
- package/src/ui/cards.js +179 -0
- package/src/ui/format.js +55 -0
- package/src/ui/phase-header.js +20 -0
- package/src/ui/prompts.js +56 -0
- package/src/ui/tables.js +89 -0
- package/src/ui/tasks.js +258 -0
- package/src/ui/theme.js +83 -0
- package/src/utils/analysis-cache.js +519 -0
- package/src/utils/api-client.js +253 -0
- package/src/utils/api-file-writer.js +197 -0
- package/src/utils/bootstrap-runner.js +148 -0
- package/src/utils/claude-analyzer.js +255 -0
- package/src/utils/claude-optimizer.js +341 -0
- package/src/utils/claude-rewriter.js +553 -0
- package/src/utils/claude-scorer.js +101 -0
- package/src/utils/description-analyzer.js +116 -0
- package/src/utils/detect-project.js +1276 -0
- package/src/utils/existing-setup.js +341 -0
- package/src/utils/file-writer.js +64 -0
- package/src/utils/json-extract.js +56 -0
- package/src/utils/logger.js +27 -0
- package/src/utils/mcp-setup.js +461 -0
- package/src/utils/preflight.js +112 -0
- package/src/utils/prompt-api-key.js +59 -0
- package/src/utils/run-claude.js +152 -0
- package/src/utils/security.js +82 -0
- package/src/utils/toolkit-rule-generator.js +364 -0
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Update command — re-analyzes the project, compares to the last install snapshot,
|
|
3
|
+
* calls /api/update to get delta components, and installs only what's new.
|
|
4
|
+
*
|
|
5
|
+
* Flow:
|
|
6
|
+
* 1. Load stored user profile + analysis from .claude/.claude-craft/
|
|
7
|
+
* 2. Re-run project analysis (detectProject + analyzeWithClaude)
|
|
8
|
+
* 3. Extract installed relative paths from manifest
|
|
9
|
+
* 4. Call /api/update — server returns only new/unlocked components
|
|
10
|
+
* 5. Show change summary + new component counts
|
|
11
|
+
* 6. Confirm, write files, merge manifest
|
|
12
|
+
*/
|
|
13
|
+
import { resolve, sep } from 'path';
|
|
14
|
+
import chalk from 'chalk';
|
|
15
|
+
import ora from 'ora';
|
|
16
|
+
import { detectProject } from '../utils/detect-project.js';
|
|
17
|
+
import { analyzeWithClaude } from '../utils/claude-analyzer.js';
|
|
18
|
+
import {
|
|
19
|
+
readUserProfile,
|
|
20
|
+
readPermanentAnalysis,
|
|
21
|
+
readInstalledManifest,
|
|
22
|
+
mergePermanentManifest,
|
|
23
|
+
} from '../utils/analysis-cache.js';
|
|
24
|
+
import { callUpdate, ApiError } from '../utils/api-client.js';
|
|
25
|
+
import { runPreflight } from '../utils/preflight.js';
|
|
26
|
+
import { writeApiFiles, buildFileList } from '../utils/api-file-writer.js';
|
|
27
|
+
import { colors, icons } from '../ui/theme.js';
|
|
28
|
+
import { dotPad } from '../ui/format.js';
|
|
29
|
+
import { renderFileResults } from '../ui/tables.js';
|
|
30
|
+
import { themedConfirm } from '../ui/prompts.js';
|
|
31
|
+
import * as logger from '../utils/logger.js';
|
|
32
|
+
|
|
33
|
+
// ── Helpers ──────────────────────────────────────────────────────────────────
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Extract normalized relative paths from the installed manifest.
|
|
37
|
+
* Strips the targetDir prefix so paths are relative (e.g. ".claude/agents/orchestrator.md").
|
|
38
|
+
*/
|
|
39
|
+
function extractRelativePaths(manifest, targetDir) {
|
|
40
|
+
if (!manifest?.files) return [];
|
|
41
|
+
|
|
42
|
+
const prefix = targetDir.endsWith(sep) ? targetDir : targetDir + sep;
|
|
43
|
+
// Also handle forward-slash variant on Windows
|
|
44
|
+
const prefixFwd = prefix.replace(/\\/g, '/');
|
|
45
|
+
|
|
46
|
+
return manifest.files
|
|
47
|
+
.map((f) => {
|
|
48
|
+
let p = (f.relativePath || '').replace(/\\/g, '/');
|
|
49
|
+
if (p.startsWith(prefixFwd)) p = p.slice(prefixFwd.length);
|
|
50
|
+
return p;
|
|
51
|
+
})
|
|
52
|
+
.filter(Boolean);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Render the detected stack changes to the console.
|
|
57
|
+
*/
|
|
58
|
+
function renderChanges(changes, currentAnalysis) {
|
|
59
|
+
const { addedFrameworks, removedFrameworks, addedLanguages, addedSubprojects,
|
|
60
|
+
testFrameworkChanged, packageManagerChanged, hasChanges } = changes;
|
|
61
|
+
|
|
62
|
+
if (!hasChanges) {
|
|
63
|
+
console.log(chalk.dim(' No stack changes detected since last install.'));
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
console.log(chalk.bold(' Stack changes'));
|
|
68
|
+
console.log();
|
|
69
|
+
|
|
70
|
+
if (addedFrameworks.length > 0) {
|
|
71
|
+
for (const fw of addedFrameworks) {
|
|
72
|
+
console.log(` ${icons.plus} ${colors.success(fw)} ${chalk.dim('(new framework)')}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (removedFrameworks.length > 0) {
|
|
76
|
+
for (const fw of removedFrameworks) {
|
|
77
|
+
console.log(` ${chalk.dim('─')} ${chalk.dim(fw)} ${chalk.dim('(removed)')}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (addedLanguages.length > 0) {
|
|
81
|
+
for (const lang of addedLanguages) {
|
|
82
|
+
console.log(` ${icons.plus} ${colors.success(lang)} ${chalk.dim('(new language)')}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (addedSubprojects.length > 0) {
|
|
86
|
+
for (const sub of addedSubprojects) {
|
|
87
|
+
console.log(` ${icons.plus} ${colors.success(sub)} ${chalk.dim('(new subproject)')}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (testFrameworkChanged && currentAnalysis.testFramework) {
|
|
91
|
+
console.log(
|
|
92
|
+
` ${icons.plus} ${colors.success(currentAnalysis.testFramework)} ${chalk.dim('(test framework detected)')}`,
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
if (packageManagerChanged) {
|
|
96
|
+
console.log(
|
|
97
|
+
` ${icons.tilde} ${colors.warning('package manager changed')} ${chalk.dim(`→ ${currentAnalysis.packageManager}`)}`,
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Render the delta component counts.
|
|
104
|
+
*/
|
|
105
|
+
function renderDeltaSummary(delta) {
|
|
106
|
+
const total = Object.values(delta).reduce((s, n) => s + n, 0);
|
|
107
|
+
if (total === 0) {
|
|
108
|
+
console.log(chalk.dim(' No new components to install.'));
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
console.log(chalk.bold(` New components: ${colors.success(String(total))}`));
|
|
113
|
+
const entries = Object.entries(delta).filter(([, n]) => n > 0);
|
|
114
|
+
for (const [cat, count] of entries) {
|
|
115
|
+
console.log(chalk.dim(` ${dotPad(cat, colors.success(String(count)))}`));
|
|
116
|
+
}
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// ── Main command ─────────────────────────────────────────────────────────────
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* @param {object} options - { dir, yes }
|
|
124
|
+
*/
|
|
125
|
+
export async function runUpdate(options = {}) {
|
|
126
|
+
try {
|
|
127
|
+
const targetDir = resolve(options.dir || process.cwd());
|
|
128
|
+
|
|
129
|
+
// ── Pre-flight checks (Claude Code + project marker + API key + server)
|
|
130
|
+
await runPreflight({
|
|
131
|
+
interactive: !options.yes,
|
|
132
|
+
requireClaude: true,
|
|
133
|
+
requireCraftProject: true,
|
|
134
|
+
targetDir,
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// ── Guard: must have a previous install ───────────────────────────
|
|
138
|
+
const storedProfile = readUserProfile(targetDir);
|
|
139
|
+
const previousAnalysis = readPermanentAnalysis(targetDir);
|
|
140
|
+
const installedManifest = readInstalledManifest(targetDir);
|
|
141
|
+
|
|
142
|
+
if (!storedProfile) {
|
|
143
|
+
logger.error(
|
|
144
|
+
'No stored user profile found. Re-run: ' + chalk.bold('claude-craft install') +
|
|
145
|
+
' to rebuild the profile cache.',
|
|
146
|
+
);
|
|
147
|
+
process.exit(1);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (!previousAnalysis) {
|
|
151
|
+
logger.error(
|
|
152
|
+
'No stored project analysis found. Re-run: ' + chalk.bold('claude-craft install') +
|
|
153
|
+
' to rebuild the analysis cache.',
|
|
154
|
+
);
|
|
155
|
+
process.exit(1);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
console.log(chalk.bold(' claude-craft update'));
|
|
159
|
+
console.log(chalk.dim(' Re-analyzing project and checking for new components...'));
|
|
160
|
+
console.log();
|
|
161
|
+
|
|
162
|
+
// ── Phase 1: Re-analyze project ───────────────────────────────────
|
|
163
|
+
let currentProjectInfo;
|
|
164
|
+
let fsDetected;
|
|
165
|
+
|
|
166
|
+
const spinner = ora('Analyzing project...').start();
|
|
167
|
+
try {
|
|
168
|
+
fsDetected = await detectProject(targetDir);
|
|
169
|
+
|
|
170
|
+
let claudeAnalysis = null;
|
|
171
|
+
try {
|
|
172
|
+
const result = await analyzeWithClaude(targetDir);
|
|
173
|
+
claudeAnalysis = result.analysis;
|
|
174
|
+
} catch {
|
|
175
|
+
// Claude unavailable — fall back to filesystem detection only
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (claudeAnalysis) {
|
|
179
|
+
currentProjectInfo = {
|
|
180
|
+
name: claudeAnalysis.name || fsDetected.name || previousAnalysis.name || 'my-project',
|
|
181
|
+
description: claudeAnalysis.description || fsDetected.description || '',
|
|
182
|
+
projectType: claudeAnalysis.projectType || fsDetected.projectType || 'monolith',
|
|
183
|
+
languages: claudeAnalysis.languages?.length ? claudeAnalysis.languages : fsDetected.languages,
|
|
184
|
+
frameworks: claudeAnalysis.frameworks?.length ? claudeAnalysis.frameworks : fsDetected.frameworks,
|
|
185
|
+
codeStyle: claudeAnalysis.codeStyle?.length ? claudeAnalysis.codeStyle : fsDetected.codeStyle,
|
|
186
|
+
cicd: claudeAnalysis.cicd?.length ? claudeAnalysis.cicd : fsDetected.cicd,
|
|
187
|
+
subprojects: claudeAnalysis.subprojects?.length ? claudeAnalysis.subprojects : fsDetected.subprojects,
|
|
188
|
+
architecture: claudeAnalysis.architecture || '',
|
|
189
|
+
buildCommands: claudeAnalysis.buildCommands || {},
|
|
190
|
+
complexity: claudeAnalysis.complexity ?? 0.5,
|
|
191
|
+
metrics: claudeAnalysis.metrics || null,
|
|
192
|
+
entryPoints: claudeAnalysis.entryPoints || [],
|
|
193
|
+
coreModules: claudeAnalysis.coreModules || [],
|
|
194
|
+
testFramework: claudeAnalysis.testFramework || '',
|
|
195
|
+
packageManager: claudeAnalysis.packageManager || fsDetected.packageManager || '',
|
|
196
|
+
languageDistribution: claudeAnalysis.languageDistribution || fsDetected.languageDistribution || null,
|
|
197
|
+
};
|
|
198
|
+
} else {
|
|
199
|
+
currentProjectInfo = {
|
|
200
|
+
name: fsDetected.name || previousAnalysis.name || 'my-project',
|
|
201
|
+
description: fsDetected.description || '',
|
|
202
|
+
projectType: fsDetected.projectType || 'monolith',
|
|
203
|
+
languages: fsDetected.languages?.length ? fsDetected.languages : previousAnalysis.languages,
|
|
204
|
+
frameworks: fsDetected.frameworks,
|
|
205
|
+
codeStyle: fsDetected.codeStyle,
|
|
206
|
+
cicd: fsDetected.cicd,
|
|
207
|
+
subprojects: fsDetected.subprojects,
|
|
208
|
+
architecture: '',
|
|
209
|
+
buildCommands: {},
|
|
210
|
+
complexity: 0.5,
|
|
211
|
+
metrics: null,
|
|
212
|
+
entryPoints: [],
|
|
213
|
+
coreModules: [],
|
|
214
|
+
testFramework: '',
|
|
215
|
+
packageManager: fsDetected.packageManager || '',
|
|
216
|
+
languageDistribution: fsDetected.languageDistribution || null,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
spinner.succeed('Project analyzed.');
|
|
221
|
+
} catch (err) {
|
|
222
|
+
spinner.fail('Analysis failed: ' + err.message);
|
|
223
|
+
process.exit(1);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// ── Phase 2: Build installed path list ────────────────────────────
|
|
227
|
+
const installedRelativePaths = extractRelativePaths(installedManifest, targetDir);
|
|
228
|
+
|
|
229
|
+
// ── Phase 3: Call /api/update ─────────────────────────────────────
|
|
230
|
+
const spinner2 = ora('Checking for new components...').start();
|
|
231
|
+
let updateResponse;
|
|
232
|
+
try {
|
|
233
|
+
updateResponse = await callUpdate(
|
|
234
|
+
storedProfile,
|
|
235
|
+
currentProjectInfo,
|
|
236
|
+
previousAnalysis,
|
|
237
|
+
installedRelativePaths,
|
|
238
|
+
);
|
|
239
|
+
spinner2.succeed('Server responded.');
|
|
240
|
+
} catch (err) {
|
|
241
|
+
spinner2.fail('Server request failed.');
|
|
242
|
+
if (err instanceof ApiError) {
|
|
243
|
+
logger.error(err.message);
|
|
244
|
+
process.exit(1);
|
|
245
|
+
}
|
|
246
|
+
throw err;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const { changes, summary } = updateResponse;
|
|
250
|
+
|
|
251
|
+
// ── Display results ───────────────────────────────────────────────
|
|
252
|
+
console.log();
|
|
253
|
+
renderChanges(changes, currentProjectInfo);
|
|
254
|
+
console.log();
|
|
255
|
+
|
|
256
|
+
const hasNewComponents = renderDeltaSummary(summary?.delta || {});
|
|
257
|
+
|
|
258
|
+
if (!changes.hasChanges && !hasNewComponents) {
|
|
259
|
+
console.log();
|
|
260
|
+
logger.success('Already up to date. Nothing to install.');
|
|
261
|
+
console.log();
|
|
262
|
+
process.exit(0);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (!hasNewComponents) {
|
|
266
|
+
console.log();
|
|
267
|
+
logger.success('Stack changes noted — no new components needed.');
|
|
268
|
+
console.log();
|
|
269
|
+
process.exit(0);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// ── Confirm + install ─────────────────────────────────────────────
|
|
273
|
+
console.log();
|
|
274
|
+
|
|
275
|
+
let proceed = true;
|
|
276
|
+
if (!options.yes) {
|
|
277
|
+
proceed = await themedConfirm({ message: 'Install new components?', default: true });
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
if (!proceed) {
|
|
281
|
+
console.log();
|
|
282
|
+
logger.info('Cancelled.');
|
|
283
|
+
process.exit(0);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// ── Write new files ───────────────────────────────────────────────
|
|
287
|
+
const filesToWrite = buildFileList(updateResponse, null);
|
|
288
|
+
|
|
289
|
+
if (filesToWrite.length === 0) {
|
|
290
|
+
console.log();
|
|
291
|
+
logger.success('No files to write. Already up to date.');
|
|
292
|
+
process.exit(0);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const writeSpinner = ora('Writing new components...').start();
|
|
296
|
+
let results;
|
|
297
|
+
try {
|
|
298
|
+
results = await writeApiFiles(filesToWrite, targetDir, {
|
|
299
|
+
force: true,
|
|
300
|
+
selectedMcpIds: [],
|
|
301
|
+
detected: { ...fsDetected, ...currentProjectInfo },
|
|
302
|
+
});
|
|
303
|
+
writeSpinner.succeed('Components installed.');
|
|
304
|
+
} catch (err) {
|
|
305
|
+
writeSpinner.fail('Write failed: ' + err.message);
|
|
306
|
+
throw err;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// ── Display written files ─────────────────────────────────────────
|
|
310
|
+
console.log();
|
|
311
|
+
renderFileResults(results);
|
|
312
|
+
|
|
313
|
+
// ── Update manifest ───────────────────────────────────────────────
|
|
314
|
+
try {
|
|
315
|
+
mergePermanentManifest(targetDir, results, filesToWrite);
|
|
316
|
+
} catch (err) {
|
|
317
|
+
logger.debug(`Manifest merge failed: ${err.message}`);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
console.log();
|
|
321
|
+
logger.success('Done! New components installed.');
|
|
322
|
+
console.log();
|
|
323
|
+
} catch (err) {
|
|
324
|
+
if (
|
|
325
|
+
err &&
|
|
326
|
+
(err.name === 'ExitPromptError' ||
|
|
327
|
+
err.constructor?.name === 'ExitPromptError' ||
|
|
328
|
+
err.message?.includes('User force closed'))
|
|
329
|
+
) {
|
|
330
|
+
console.log();
|
|
331
|
+
logger.info('Cancelled.');
|
|
332
|
+
process.exit(0);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
console.log();
|
|
336
|
+
logger.error(err.message || String(err));
|
|
337
|
+
process.exit(1);
|
|
338
|
+
}
|
|
339
|
+
}
|
package/src/constants.js
ADDED
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
import { readFileSync } from 'fs';
|
|
2
|
+
import { fileURLToPath } from 'url';
|
|
3
|
+
import { dirname, join } from 'path';
|
|
4
|
+
|
|
5
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = dirname(__filename);
|
|
7
|
+
const pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf8'));
|
|
8
|
+
|
|
9
|
+
export const VERSION = pkg.version;
|
|
10
|
+
export const TOOL_NAME = 'claude-craft';
|
|
11
|
+
|
|
12
|
+
// ── Step 1: User roles & intents ──────────────────────────────────────
|
|
13
|
+
|
|
14
|
+
export const ROLES = [
|
|
15
|
+
{
|
|
16
|
+
name: 'Developer',
|
|
17
|
+
value: 'developer',
|
|
18
|
+
description: 'Build and ship software across the stack',
|
|
19
|
+
children: [
|
|
20
|
+
{ name: 'Web', value: 'web', description: 'Frontend and backend development' },
|
|
21
|
+
{ name: 'Mobile', value: 'mobile', description: 'iOS, Android, and cross-platform apps' },
|
|
22
|
+
{ name: 'Game', value: 'game', description: 'Game engines, rendering, and gameplay' },
|
|
23
|
+
{ name: 'Blockchain', value: 'blockchain', description: 'Smart contracts, DApps, and Web3' },
|
|
24
|
+
{ name: 'Embedded', value: 'embedded', description: 'Firmware, IoT, and low-level systems' },
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
{ name: 'DevOps', value: 'devops', description: 'Infrastructure, CI/CD, and deployment pipelines' },
|
|
28
|
+
{
|
|
29
|
+
name: 'Data & Analytics',
|
|
30
|
+
value: 'data-analytics',
|
|
31
|
+
description: 'Data pipelines, analysis, ML, and visualization',
|
|
32
|
+
children: [
|
|
33
|
+
{ name: 'Data Scientist', value: 'data-scientist', description: 'ML models, experiments, and research' },
|
|
34
|
+
{ name: 'Data Engineer', value: 'data-engineer', description: 'Pipelines, ETL, and data infrastructure' },
|
|
35
|
+
{ name: 'Data Analyst', value: 'data-analyst', description: 'Queries, dashboards, and reporting' },
|
|
36
|
+
],
|
|
37
|
+
},
|
|
38
|
+
{ name: 'Quality Assurance', value: 'qa', description: 'Testing strategy, automation, and quality gates' },
|
|
39
|
+
{ name: 'Cybersecurity', value: 'cybersecurity', description: 'Security audits, vulnerability analysis, hardening' },
|
|
40
|
+
{ name: 'Product & Design', value: 'product-design', description: 'Product specs, design systems, UX workflows' },
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
export const ROLE_DISPLAY_NAMES = {
|
|
44
|
+
web: 'Web Developer',
|
|
45
|
+
mobile: 'Mobile Developer',
|
|
46
|
+
game: 'Game Developer',
|
|
47
|
+
blockchain: 'Blockchain Developer',
|
|
48
|
+
embedded: 'Embedded Developer',
|
|
49
|
+
devops: 'DevOps / Infrastructure',
|
|
50
|
+
'data-scientist': 'Data Scientist',
|
|
51
|
+
'data-engineer': 'Data Engineer',
|
|
52
|
+
'data-analyst': 'Data Analyst',
|
|
53
|
+
qa: 'Quality Assurance',
|
|
54
|
+
cybersecurity: 'Cybersecurity',
|
|
55
|
+
'product-design': 'Product & Design',
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export const INTENTS = [
|
|
59
|
+
{ name: 'Implementing new features', value: 'implementing', description: 'Build features from specs, tickets, or ideas' },
|
|
60
|
+
{ name: 'Debugging & troubleshooting', value: 'debugging', description: 'Track down bugs, analyze stack traces, fix issues' },
|
|
61
|
+
{ name: 'Refactoring & cleanup', value: 'refactoring', description: 'Improve code structure without changing behavior' },
|
|
62
|
+
{ name: 'Writing documentation', value: 'documentation', description: 'READMEs, API docs, architecture decisions' },
|
|
63
|
+
{ name: 'Testing & QA', value: 'testing', description: 'Unit, integration, and e2e tests' },
|
|
64
|
+
{ name: 'Code review', value: 'reviewing', description: 'Review PRs, suggest improvements, catch issues' },
|
|
65
|
+
];
|
|
66
|
+
|
|
67
|
+
// ── Source control platforms ─────────────────────────────────────────
|
|
68
|
+
|
|
69
|
+
export const SOURCE_CONTROLS = [
|
|
70
|
+
{ name: 'GitHub', value: 'github', description: 'GitHub.com or GitHub Enterprise' },
|
|
71
|
+
{ name: 'GitLab', value: 'gitlab', description: 'GitLab.com or self-hosted' },
|
|
72
|
+
{ name: 'Bitbucket', value: 'bitbucket', description: 'Bitbucket Cloud or Data Center' },
|
|
73
|
+
{ name: 'Azure DevOps', value: 'azure-devops', description: 'Azure Repos and Pipelines' },
|
|
74
|
+
{ name: 'None / Git only', value: 'none', description: 'Local git without a hosting platform' },
|
|
75
|
+
];
|
|
76
|
+
|
|
77
|
+
// ── Document & project management tools ─────────────────────────────
|
|
78
|
+
|
|
79
|
+
export const DOCUMENT_TOOLS = [
|
|
80
|
+
{ name: 'None', value: 'none' },
|
|
81
|
+
{ name: 'Notion', value: 'notion' },
|
|
82
|
+
{ name: 'Linear', value: 'linear' },
|
|
83
|
+
{ name: 'Google Docs', value: 'google-docs' },
|
|
84
|
+
{ name: 'Confluence', value: 'confluence' },
|
|
85
|
+
{ name: 'Jira', value: 'jira' },
|
|
86
|
+
{ name: 'Azure DevOps', value: 'azure-devops' },
|
|
87
|
+
{ name: 'ClickUp', value: 'clickup' },
|
|
88
|
+
{ name: 'Asana', value: 'asana' },
|
|
89
|
+
{ name: 'Shortcut', value: 'shortcut' },
|
|
90
|
+
{ name: 'Monday.com', value: 'monday' },
|
|
91
|
+
{ name: 'YouTrack', value: 'youtrack' },
|
|
92
|
+
{ name: 'Trello', value: 'trello' },
|
|
93
|
+
{ name: 'Todoist', value: 'todoist' },
|
|
94
|
+
{ name: 'Plane', value: 'plane' },
|
|
95
|
+
{ name: 'Other', value: 'other' },
|
|
96
|
+
];
|
|
97
|
+
|
|
98
|
+
// ── Step 2: Project types ─────────────────────────────────────────────
|
|
99
|
+
|
|
100
|
+
export const PROJECT_TYPES = [
|
|
101
|
+
{ name: 'Monorepo (multiple packages/apps)', value: 'monorepo' },
|
|
102
|
+
{ name: 'Microservices', value: 'microservice' },
|
|
103
|
+
{ name: 'Monolith', value: 'monolith' },
|
|
104
|
+
{ name: 'Library / Package', value: 'library' },
|
|
105
|
+
{ name: 'CLI Tool', value: 'cli' },
|
|
106
|
+
{ name: 'Other / Unknown', value: 'other' },
|
|
107
|
+
];
|
|
108
|
+
|
|
109
|
+
// ── Languages & Frameworks ────────────────────────────────────────────
|
|
110
|
+
|
|
111
|
+
export const SUPPORTED_LANGUAGES = [
|
|
112
|
+
'JavaScript',
|
|
113
|
+
'TypeScript',
|
|
114
|
+
'Python',
|
|
115
|
+
'Go',
|
|
116
|
+
'Rust',
|
|
117
|
+
'Java',
|
|
118
|
+
'C#',
|
|
119
|
+
'Ruby',
|
|
120
|
+
'PHP',
|
|
121
|
+
'Swift',
|
|
122
|
+
'Kotlin',
|
|
123
|
+
'Dart',
|
|
124
|
+
'SQL',
|
|
125
|
+
'Solidity',
|
|
126
|
+
'C',
|
|
127
|
+
'C++',
|
|
128
|
+
];
|
|
129
|
+
|
|
130
|
+
export const SUPPORTED_FRAMEWORKS = [
|
|
131
|
+
// Web frameworks
|
|
132
|
+
'Next.js',
|
|
133
|
+
'React',
|
|
134
|
+
'Vue',
|
|
135
|
+
'Angular',
|
|
136
|
+
'Express',
|
|
137
|
+
'Fastify',
|
|
138
|
+
'Django',
|
|
139
|
+
'Flask',
|
|
140
|
+
'FastAPI',
|
|
141
|
+
'Gin',
|
|
142
|
+
'Echo',
|
|
143
|
+
'Actix',
|
|
144
|
+
'Spring Boot',
|
|
145
|
+
'ASP.NET Core',
|
|
146
|
+
'Rails',
|
|
147
|
+
'Laravel',
|
|
148
|
+
'Tailwind CSS',
|
|
149
|
+
// Expanded web frameworks
|
|
150
|
+
'SvelteKit',
|
|
151
|
+
'Nuxt',
|
|
152
|
+
'Astro',
|
|
153
|
+
'Gatsby',
|
|
154
|
+
'NestJS',
|
|
155
|
+
'Remix',
|
|
156
|
+
'Socket.io',
|
|
157
|
+
// Desktop / Mobile
|
|
158
|
+
'Electron',
|
|
159
|
+
'React Native',
|
|
160
|
+
'Expo',
|
|
161
|
+
'Tauri',
|
|
162
|
+
'Flutter',
|
|
163
|
+
// Blockchain
|
|
164
|
+
'Hardhat',
|
|
165
|
+
'Foundry',
|
|
166
|
+
'Web3',
|
|
167
|
+
// Data / AI
|
|
168
|
+
'GraphQL',
|
|
169
|
+
'LangChain',
|
|
170
|
+
'OpenAI SDK',
|
|
171
|
+
'PyTorch',
|
|
172
|
+
'TensorFlow',
|
|
173
|
+
'scikit-learn',
|
|
174
|
+
'Streamlit',
|
|
175
|
+
'Airflow',
|
|
176
|
+
'Pandas',
|
|
177
|
+
'Pydantic',
|
|
178
|
+
'Hugging Face',
|
|
179
|
+
// Game
|
|
180
|
+
'Phaser',
|
|
181
|
+
'Three.js',
|
|
182
|
+
'Unity',
|
|
183
|
+
'Godot',
|
|
184
|
+
'Babylon.js',
|
|
185
|
+
// ORM / DB
|
|
186
|
+
'Prisma',
|
|
187
|
+
'Drizzle',
|
|
188
|
+
// Go frameworks
|
|
189
|
+
'Go API',
|
|
190
|
+
'Cobra',
|
|
191
|
+
'Fiber',
|
|
192
|
+
// Rust frameworks
|
|
193
|
+
'Tokio',
|
|
194
|
+
'Axum',
|
|
195
|
+
'Warp',
|
|
196
|
+
'Clap',
|
|
197
|
+
// Infrastructure
|
|
198
|
+
'Terraform',
|
|
199
|
+
'Serverless Framework',
|
|
200
|
+
// Static sites
|
|
201
|
+
'Hugo',
|
|
202
|
+
'Jekyll',
|
|
203
|
+
'Docusaurus',
|
|
204
|
+
// Mobile / Desktop (extended)
|
|
205
|
+
'Jetpack Compose',
|
|
206
|
+
'.NET MAUI',
|
|
207
|
+
// Data
|
|
208
|
+
'dbt',
|
|
209
|
+
'Dash',
|
|
210
|
+
// AI (extended)
|
|
211
|
+
'LlamaIndex',
|
|
212
|
+
'Vercel AI SDK',
|
|
213
|
+
// Testing
|
|
214
|
+
'Playwright',
|
|
215
|
+
// Bot
|
|
216
|
+
'Discord.js',
|
|
217
|
+
// .NET variants
|
|
218
|
+
'Razor',
|
|
219
|
+
'Blazor',
|
|
220
|
+
'Graphene',
|
|
221
|
+
'HotChocolate',
|
|
222
|
+
'SignalR',
|
|
223
|
+
// CMS / E-commerce
|
|
224
|
+
'WordPress',
|
|
225
|
+
'Shopify',
|
|
226
|
+
// Other
|
|
227
|
+
'Single-SPA',
|
|
228
|
+
'CLI Framework',
|
|
229
|
+
'Scrapy',
|
|
230
|
+
'Browser Extension',
|
|
231
|
+
// C / C++ build systems
|
|
232
|
+
'CMake',
|
|
233
|
+
'Meson',
|
|
234
|
+
'Bazel',
|
|
235
|
+
// C / C++ GUI
|
|
236
|
+
'Qt',
|
|
237
|
+
'GTK',
|
|
238
|
+
'wxWidgets',
|
|
239
|
+
'Dear ImGui',
|
|
240
|
+
// C / C++ multimedia / game
|
|
241
|
+
'SDL',
|
|
242
|
+
'SFML',
|
|
243
|
+
'Unreal Engine',
|
|
244
|
+
// C / C++ web / networking
|
|
245
|
+
'Boost',
|
|
246
|
+
'Drogon',
|
|
247
|
+
'Crow',
|
|
248
|
+
'gRPC',
|
|
249
|
+
// C / C++ embedded / IoT
|
|
250
|
+
'FreeRTOS',
|
|
251
|
+
'ESP-IDF',
|
|
252
|
+
'Zephyr',
|
|
253
|
+
// C / C++ ML / vision
|
|
254
|
+
'OpenCV',
|
|
255
|
+
// C / C++ testing
|
|
256
|
+
'Google Test',
|
|
257
|
+
'Catch2',
|
|
258
|
+
];
|
|
259
|
+
|
|
260
|
+
// ── Components (now auto-selected by scoring) ─────────────────────────
|
|
261
|
+
|
|
262
|
+
export const COMPONENTS = [
|
|
263
|
+
{ name: 'CLAUDE.md', value: 'claude-md', checked: true },
|
|
264
|
+
{ name: 'Agents (.claude/agents/)', value: 'agents', checked: true },
|
|
265
|
+
{ name: 'Rules (.claude/rules/)', value: 'rules', checked: true },
|
|
266
|
+
{ name: 'Hooks (.claude/settings.json)', value: 'hooks', checked: true },
|
|
267
|
+
{ name: 'Skills (.claude/skills/)', value: 'skills', checked: true },
|
|
268
|
+
{ name: 'Commands (.claude/commands/)', value: 'commands', checked: true },
|
|
269
|
+
{ name: 'MCP Servers (.claude/settings.json)', value: 'mcps', checked: true },
|
|
270
|
+
{ name: 'Workflows (.claude/workflows/)', value: 'workflows', checked: true },
|
|
271
|
+
{ name: 'User Guide', value: 'user-guide', checked: true },
|
|
272
|
+
];
|
|
273
|
+
|
|
274
|
+
export const PRESET_ALIASES = {
|
|
275
|
+
nextjs: { frameworks: ['Next.js'], languages: ['TypeScript'] },
|
|
276
|
+
'go-api': { frameworks: ['Go API'], languages: ['Go'] },
|
|
277
|
+
python: { frameworks: [], languages: ['Python'] },
|
|
278
|
+
rust: { frameworks: [], languages: ['Rust'] },
|
|
279
|
+
aspnet: { frameworks: ['ASP.NET Core'], languages: ['C#'] },
|
|
280
|
+
cmake: { frameworks: ['CMake'], languages: ['C++'] },
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
// ── Security defaults ─────────────────────────────────────────────────
|
|
284
|
+
|
|
285
|
+
// ── Component types ──────────────────────────────────────────────────
|
|
286
|
+
|
|
287
|
+
export const COMPONENT_TYPES = {
|
|
288
|
+
CORE: 'core',
|
|
289
|
+
OPTIONAL: 'optional',
|
|
290
|
+
PLUGIN: 'plugin',
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
export const SENSITIVE_PATTERNS = [
|
|
294
|
+
'.env', '.env.*', '*.pem', '*.key', '*.cert',
|
|
295
|
+
'credentials.json', 'secrets.yaml', 'secrets.yml',
|
|
296
|
+
'*.secret', 'id_rsa', 'id_ed25519',
|
|
297
|
+
'.aws/credentials', '.gcp/credentials.json',
|
|
298
|
+
'serviceAccountKey.json', 'firebase-adminsdk*.json',
|
|
299
|
+
];
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { join } from 'path';
|
|
2
|
+
import { ensureDir, outputFile } from 'fs-extra/esm';
|
|
3
|
+
import { pathExists } from 'fs-extra/esm';
|
|
4
|
+
|
|
5
|
+
const directories = [
|
|
6
|
+
'.claude/scripts',
|
|
7
|
+
'.claude/mcps',
|
|
8
|
+
'.claude/workflows',
|
|
9
|
+
];
|
|
10
|
+
|
|
11
|
+
export async function generate(config, targetDir, opts = {}) {
|
|
12
|
+
const results = [];
|
|
13
|
+
|
|
14
|
+
for (const dir of directories) {
|
|
15
|
+
const dirPath = join(targetDir, dir);
|
|
16
|
+
await ensureDir(dirPath);
|
|
17
|
+
|
|
18
|
+
const gitkeepPath = join(dirPath, '.gitkeep');
|
|
19
|
+
const exists = await pathExists(gitkeepPath);
|
|
20
|
+
|
|
21
|
+
if (!exists) {
|
|
22
|
+
await outputFile(gitkeepPath, '');
|
|
23
|
+
results.push({ path: gitkeepPath, status: 'created' });
|
|
24
|
+
} else {
|
|
25
|
+
results.push({ path: gitkeepPath, status: 'exists' });
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return results;
|
|
30
|
+
}
|