@claudetools/cli 0.11.1 → 0.13.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/dist/onboard/claude-inference.d.ts +5 -0
- package/dist/onboard/claude-inference.d.ts.map +1 -1
- package/dist/onboard/claude-inference.js +12 -0
- package/dist/onboard/claude-inference.js.map +1 -1
- package/dist/onboard/docs-builder.d.ts.map +1 -1
- package/dist/onboard/docs-builder.js +12 -19
- package/dist/onboard/docs-builder.js.map +1 -1
- package/dist/onboard/index.d.ts.map +1 -1
- package/dist/onboard/index.js +217 -277
- package/dist/onboard/index.js.map +1 -1
- package/dist/onboard/questions.d.ts +5 -19
- package/dist/onboard/questions.d.ts.map +1 -1
- package/dist/onboard/questions.js +38 -370
- package/dist/onboard/questions.js.map +1 -1
- package/package.json +1 -1
package/dist/onboard/index.js
CHANGED
|
@@ -11,13 +11,10 @@ import { detectStack } from './stack-detector.js';
|
|
|
11
11
|
import { buildDocs } from './docs-builder.js';
|
|
12
12
|
import { buildAgentsMd, writeAgentsMd } from './agents-md-builder.js';
|
|
13
13
|
import { runInteractiveOnboarding } from './questions.js';
|
|
14
|
-
import { isClaudeCliAvailable,
|
|
15
|
-
//
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const empty = width - filled;
|
|
19
|
-
return chalk.cyan('█'.repeat(filled)) + chalk.dim('░'.repeat(empty));
|
|
20
|
-
}
|
|
14
|
+
import { isClaudeCliAvailable, runClaudeAnalysis } from './claude-inference.js';
|
|
15
|
+
// =============================================================================
|
|
16
|
+
// Main Onboarding Flow
|
|
17
|
+
// =============================================================================
|
|
21
18
|
/**
|
|
22
19
|
* Run the complete onboarding workflow
|
|
23
20
|
*/
|
|
@@ -33,351 +30,294 @@ export async function runOnboard(projectPath, options = {}) {
|
|
|
33
30
|
console.log(chalk.dim(` Project: ${chalk.white(projectName)}`));
|
|
34
31
|
console.log(chalk.dim(` Path: ${projectPath}`));
|
|
35
32
|
console.log('');
|
|
33
|
+
// ==========================================================================
|
|
36
34
|
// Phase 1: Stack Detection
|
|
37
|
-
|
|
35
|
+
// ==========================================================================
|
|
36
|
+
console.log(chalk.cyan(' ▸ Phase 1/4: Stack Detection'));
|
|
38
37
|
const stackSpinner = ora({ text: 'Scanning project files...', indent: 4 }).start();
|
|
39
38
|
const stack = detectStack(projectPath);
|
|
40
|
-
// Handle empty/new projects
|
|
41
39
|
if (stack.isEmpty) {
|
|
42
40
|
stackSpinner.warn(chalk.yellow('No project files detected'));
|
|
43
41
|
console.log('');
|
|
44
|
-
console.log(chalk.dim('
|
|
45
|
-
console.log(chalk.dim('
|
|
46
|
-
console.log(chalk.dim(' │ ') + chalk.yellow('No package.json, requirements.txt, go.mod,'));
|
|
47
|
-
console.log(chalk.dim(' │ ') + chalk.yellow('or Cargo.toml found.'));
|
|
48
|
-
console.log(chalk.dim(' │'));
|
|
49
|
-
console.log(chalk.dim(' │ ') + chalk.white('This appears to be a new or empty project.'));
|
|
50
|
-
console.log(chalk.dim(' │'));
|
|
51
|
-
console.log(chalk.dim(' └──────────────────────────────────────'));
|
|
52
|
-
console.log('');
|
|
53
|
-
const { continueEmpty } = await prompts({
|
|
54
|
-
type: 'confirm',
|
|
55
|
-
name: 'continueEmpty',
|
|
56
|
-
message: ' Continue with minimal setup for new project?',
|
|
57
|
-
initial: true,
|
|
58
|
-
});
|
|
59
|
-
if (!continueEmpty) {
|
|
60
|
-
console.log('');
|
|
61
|
-
console.log(chalk.dim(' Tip: Initialize your project first, then run onboarding:'));
|
|
62
|
-
console.log(chalk.dim(' • npm init / pnpm init / yarn init'));
|
|
63
|
-
console.log(chalk.dim(' • npx create-next-app'));
|
|
64
|
-
console.log(chalk.dim(' • pip init / poetry init'));
|
|
65
|
-
console.log(chalk.dim(' • go mod init'));
|
|
66
|
-
console.log(chalk.dim(' • cargo init'));
|
|
67
|
-
console.log('');
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
console.log(chalk.dim(' Proceeding with minimal setup...'));
|
|
42
|
+
console.log(chalk.dim(' This appears to be a new/empty project.'));
|
|
43
|
+
console.log(chalk.dim(' Initialize your project first (npm init, etc.)'));
|
|
71
44
|
console.log('');
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
stackSpinner.succeed(chalk.green('Stack detected'));
|
|
48
|
+
console.log('');
|
|
49
|
+
// ==========================================================================
|
|
50
|
+
// Phase 2: Quick Questions
|
|
51
|
+
// ==========================================================================
|
|
52
|
+
console.log(chalk.cyan(' ▸ Phase 2/4: Quick Questions'));
|
|
53
|
+
let answers = {};
|
|
54
|
+
if (!options.skipQuestions && !options.refresh) {
|
|
55
|
+
answers = await runInteractiveOnboarding(stack, { verbose: options.verbose });
|
|
72
56
|
}
|
|
73
57
|
else {
|
|
74
|
-
|
|
58
|
+
console.log(chalk.dim(' Skipping questions'));
|
|
75
59
|
console.log('');
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
if (stack.libraries.length > 0) {
|
|
85
|
-
const libCount = stack.libraries.length;
|
|
86
|
-
const topLibs = stack.libraries.slice(0, 5).map(l => l.name).join(', ');
|
|
87
|
-
console.log(chalk.dim(' │ ') + chalk.white(`Libraries: ${topLibs}${libCount > 5 ? ` (+${libCount - 5} more)` : ''}`));
|
|
88
|
-
}
|
|
89
|
-
if (stack.devTools.length > 0) {
|
|
90
|
-
console.log(chalk.dim(' │ ') + chalk.white(`Dev Tools: ${stack.devTools.map(t => t.name).join(', ')}`));
|
|
91
|
-
}
|
|
92
|
-
console.log(chalk.dim(' │'));
|
|
93
|
-
console.log(chalk.dim(' └─────────────────────────────────────'));
|
|
60
|
+
}
|
|
61
|
+
// ==========================================================================
|
|
62
|
+
// Phase 3: AI Analysis & Proposal
|
|
63
|
+
// ==========================================================================
|
|
64
|
+
console.log(chalk.cyan(' ▸ Phase 3/4: AI Analysis'));
|
|
65
|
+
const hasClaudeCli = isClaudeCliAvailable();
|
|
66
|
+
if (!hasClaudeCli) {
|
|
67
|
+
console.log(chalk.yellow(' Claude CLI not available - using detected stack'));
|
|
94
68
|
console.log('');
|
|
95
|
-
if (options.verbose) {
|
|
96
|
-
printStackDetails(stack);
|
|
97
|
-
}
|
|
98
69
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
70
|
+
else {
|
|
71
|
+
// AI analyzes and proposes
|
|
72
|
+
let proposal = await generateProposal(projectPath, stack, answers);
|
|
73
|
+
let approved = false;
|
|
74
|
+
while (!approved) {
|
|
75
|
+
// Display proposal
|
|
76
|
+
displayProposal(proposal);
|
|
77
|
+
// Ask for approval
|
|
78
|
+
const { decision } = await prompts({
|
|
79
|
+
type: 'select',
|
|
80
|
+
name: 'decision',
|
|
81
|
+
message: ' How does this look?',
|
|
82
|
+
choices: [
|
|
83
|
+
{ title: 'Looks good, proceed', value: 'approve' },
|
|
84
|
+
{ title: 'I have feedback', value: 'feedback' },
|
|
85
|
+
{ title: 'Skip AI analysis', value: 'skip' },
|
|
86
|
+
],
|
|
111
87
|
});
|
|
112
|
-
if (
|
|
113
|
-
|
|
88
|
+
if (decision === 'approve') {
|
|
89
|
+
approved = true;
|
|
90
|
+
console.log(chalk.green(' ✓ Approved'));
|
|
114
91
|
}
|
|
115
|
-
else {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
// Existing project - offer Claude analysis
|
|
121
|
-
const hasClaudeCli = isClaudeCliAvailable();
|
|
122
|
-
if (hasClaudeCli) {
|
|
123
|
-
console.log(chalk.dim(' Claude Code CLI detected'));
|
|
124
|
-
const { useClaudeAnalysis } = await prompts({
|
|
125
|
-
type: 'confirm',
|
|
126
|
-
name: 'useClaudeAnalysis',
|
|
127
|
-
message: ' Use AI to analyze codebase? (recommended)',
|
|
128
|
-
initial: true,
|
|
92
|
+
else if (decision === 'feedback') {
|
|
93
|
+
const { feedback } = await prompts({
|
|
94
|
+
type: 'text',
|
|
95
|
+
name: 'feedback',
|
|
96
|
+
message: ' What should be different?',
|
|
129
97
|
});
|
|
130
|
-
if (
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
'Reading project structure...',
|
|
137
|
-
'Analyzing architecture patterns...',
|
|
138
|
-
'Detecting conventions...',
|
|
139
|
-
'Identifying key components...',
|
|
140
|
-
'Generating insights...',
|
|
141
|
-
];
|
|
142
|
-
let stepIndex = 0;
|
|
143
|
-
const stepInterval = setInterval(() => {
|
|
144
|
-
stepIndex = (stepIndex + 1) % analysisSteps.length;
|
|
145
|
-
analysisSpinner.text = analysisSteps[stepIndex];
|
|
146
|
-
}, 3000);
|
|
147
|
-
try {
|
|
148
|
-
answers = await analyzeWithClaude(projectPath, stack);
|
|
149
|
-
clearInterval(stepInterval);
|
|
150
|
-
analysisSpinner.succeed(chalk.green('Codebase analysis complete'));
|
|
151
|
-
// Show what was discovered
|
|
152
|
-
if (answers.projectDescription) {
|
|
153
|
-
console.log('');
|
|
154
|
-
console.log(chalk.dim(' ┌─ Analysis Results ────────────────────'));
|
|
155
|
-
console.log(chalk.dim(' │'));
|
|
156
|
-
console.log(chalk.dim(' │ ') + chalk.white(answers.projectDescription.slice(0, 60) + (answers.projectDescription.length > 60 ? '...' : '')));
|
|
157
|
-
if (answers.architectureStyle) {
|
|
158
|
-
console.log(chalk.dim(' │ ') + chalk.dim('Architecture: ') + chalk.white(answers.architectureStyle));
|
|
159
|
-
}
|
|
160
|
-
console.log(chalk.dim(' │'));
|
|
161
|
-
console.log(chalk.dim(' └──────────────────────────────────────'));
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
catch (err) {
|
|
165
|
-
clearInterval(stepInterval);
|
|
166
|
-
analysisSpinner.fail(chalk.yellow('Analysis failed, using manual questions'));
|
|
167
|
-
answers = await runInteractiveOnboarding(stack, { verbose: options.verbose });
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
else {
|
|
171
|
-
answers = await runInteractiveOnboarding(stack, { verbose: options.verbose });
|
|
98
|
+
if (feedback && typeof feedback === 'string' && feedback.trim()) {
|
|
99
|
+
console.log('');
|
|
100
|
+
const refineSpinner = ora({ text: 'Refining proposal...', indent: 4 }).start();
|
|
101
|
+
proposal = await refineProposal(projectPath, stack, answers, proposal, feedback.trim());
|
|
102
|
+
refineSpinner.succeed('Updated proposal');
|
|
103
|
+
console.log('');
|
|
172
104
|
}
|
|
173
105
|
}
|
|
174
106
|
else {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
name: 'doInteractive',
|
|
179
|
-
message: ' Answer questions to improve documentation?',
|
|
180
|
-
initial: true,
|
|
181
|
-
});
|
|
182
|
-
if (doInteractive) {
|
|
183
|
-
answers = await runInteractiveOnboarding(stack, { verbose: options.verbose });
|
|
184
|
-
}
|
|
185
|
-
else {
|
|
186
|
-
console.log(chalk.dim(' Skipping - using defaults'));
|
|
187
|
-
}
|
|
107
|
+
// Skip
|
|
108
|
+
console.log(chalk.dim(' Using detected stack only'));
|
|
109
|
+
approved = true;
|
|
188
110
|
}
|
|
189
111
|
}
|
|
190
112
|
}
|
|
191
|
-
else {
|
|
192
|
-
console.log(chalk.dim(' Skipping analysis (refresh mode)'));
|
|
193
|
-
}
|
|
194
113
|
console.log('');
|
|
195
|
-
//
|
|
196
|
-
|
|
114
|
+
// ==========================================================================
|
|
115
|
+
// Phase 4: Build Documentation
|
|
116
|
+
// ==========================================================================
|
|
117
|
+
console.log(chalk.cyan(' ▸ Phase 4/4: Building Documentation'));
|
|
197
118
|
let generatedDocs = [];
|
|
198
119
|
if (!options.skipDocs) {
|
|
199
|
-
|
|
200
|
-
const useClaude = !stack.isEmpty && isClaudeCliAvailable();
|
|
201
|
-
let docsSpinner = null;
|
|
202
|
-
if (stack.isEmpty) {
|
|
203
|
-
console.log(chalk.dim(' Generating documentation templates for new project'));
|
|
204
|
-
console.log('');
|
|
205
|
-
docsSpinner = ora({
|
|
206
|
-
text: 'Creating documentation structure...',
|
|
207
|
-
indent: 4,
|
|
208
|
-
}).start();
|
|
209
|
-
}
|
|
210
|
-
else if (useClaude) {
|
|
211
|
-
console.log(chalk.dim(' Using AI to generate comprehensive documentation'));
|
|
212
|
-
console.log('');
|
|
213
|
-
docsSpinner = ora({
|
|
214
|
-
text: 'Preparing documentation structure...',
|
|
215
|
-
indent: 4,
|
|
216
|
-
}).start();
|
|
217
|
-
}
|
|
218
|
-
else {
|
|
219
|
-
docsSpinner = ora({
|
|
220
|
-
text: 'Generating documentation templates...',
|
|
221
|
-
indent: 4,
|
|
222
|
-
}).start();
|
|
223
|
-
}
|
|
120
|
+
const docsSpinner = ora({ text: 'Fetching documentation...', indent: 4 }).start();
|
|
224
121
|
try {
|
|
225
122
|
generatedDocs = await buildDocs(projectPath, projectName, stack, answers, {
|
|
226
123
|
verbose: options.verbose,
|
|
227
|
-
useClaudeInference:
|
|
124
|
+
useClaudeInference: hasClaudeCli,
|
|
228
125
|
onProgress: (message, current, total) => {
|
|
229
|
-
if (
|
|
230
|
-
const bar = progressBar(current, total);
|
|
126
|
+
if (current !== undefined && total !== undefined) {
|
|
231
127
|
const percent = Math.round((current / total) * 100);
|
|
232
|
-
docsSpinner.text = `${
|
|
128
|
+
docsSpinner.text = `${percent}% ${message}`;
|
|
233
129
|
}
|
|
234
|
-
else
|
|
130
|
+
else {
|
|
235
131
|
docsSpinner.text = message;
|
|
236
132
|
}
|
|
237
133
|
},
|
|
238
134
|
});
|
|
239
|
-
docsSpinner
|
|
240
|
-
// Show
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
const categories = {};
|
|
245
|
-
for (const doc of generatedDocs) {
|
|
246
|
-
const cat = doc.category || 'general';
|
|
247
|
-
categories[cat] = (categories[cat] || 0) + 1;
|
|
135
|
+
docsSpinner.succeed(chalk.green(`Generated ${generatedDocs.length} docs`));
|
|
136
|
+
// Show summary
|
|
137
|
+
const categories = new Set(generatedDocs.map(d => d.category).filter(Boolean));
|
|
138
|
+
if (categories.size > 0) {
|
|
139
|
+
console.log(chalk.dim(` Categories: ${[...categories].join(', ')}`));
|
|
248
140
|
}
|
|
249
|
-
for (const [category, count] of Object.entries(categories)) {
|
|
250
|
-
const icon = getCategoryIcon(category);
|
|
251
|
-
console.log(chalk.dim(' │ ') + icon + ' ' + chalk.white(`${category}/`) + chalk.dim(` (${count} files)`));
|
|
252
|
-
}
|
|
253
|
-
console.log(chalk.dim(' │'));
|
|
254
|
-
console.log(chalk.dim(' └──────────────────────────────────────'));
|
|
255
141
|
}
|
|
256
142
|
catch (err) {
|
|
257
|
-
docsSpinner
|
|
258
|
-
console.error(chalk.
|
|
143
|
+
docsSpinner.fail(chalk.red('Documentation failed'));
|
|
144
|
+
console.error(chalk.dim(` ${err instanceof Error ? err.message : String(err)}`));
|
|
259
145
|
}
|
|
260
146
|
}
|
|
261
147
|
else {
|
|
262
|
-
console.log(chalk.dim(' Skipping documentation
|
|
148
|
+
console.log(chalk.dim(' Skipping documentation'));
|
|
263
149
|
}
|
|
264
150
|
console.log('');
|
|
265
|
-
//
|
|
266
|
-
|
|
267
|
-
const agentsSpinner = ora({ text: 'Building AGENTS.md...', indent: 4 }).start();
|
|
151
|
+
// Build AGENTS.md
|
|
152
|
+
const agentsSpinner = ora({ text: 'Creating AGENTS.md...', indent: 4 }).start();
|
|
268
153
|
const agentsContent = buildAgentsMd(projectPath, stack, generatedDocs, answers);
|
|
269
154
|
writeAgentsMd(projectPath, agentsContent);
|
|
270
155
|
agentsSpinner.succeed(chalk.green('Created AGENTS.md'));
|
|
271
|
-
|
|
272
|
-
console.log('');
|
|
273
|
-
// Phase 5: Finalization
|
|
274
|
-
console.log(chalk.cyan(' ▸ Phase 5/5: Finalization'));
|
|
275
|
-
const finalSpinner = ora({ text: 'Finalizing setup...', indent: 4 }).start();
|
|
156
|
+
// Create CLAUDE.md pointer
|
|
276
157
|
createClaudeMdPointer(projectPath, projectName);
|
|
277
|
-
finalSpinner.succeed(chalk.green('Setup complete'));
|
|
278
158
|
console.log('');
|
|
279
|
-
//
|
|
159
|
+
// ==========================================================================
|
|
160
|
+
// Summary
|
|
161
|
+
// ==========================================================================
|
|
280
162
|
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
281
163
|
console.log(chalk.bold.green(' ╭─────────────────────────────────────╮'));
|
|
282
|
-
console.log(chalk.bold.green(' │') + chalk.bold.white('
|
|
164
|
+
console.log(chalk.bold.green(' │') + chalk.bold.white(' Setup Complete! ') + chalk.bold.green('│'));
|
|
283
165
|
console.log(chalk.bold.green(' ╰─────────────────────────────────────╯'));
|
|
284
166
|
console.log('');
|
|
285
167
|
console.log(chalk.dim(` Completed in ${elapsed}s`));
|
|
286
168
|
console.log('');
|
|
287
|
-
console.log(chalk.white('
|
|
288
|
-
console.log('');
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
console.log(chalk.cyan(' .claudetools/'));
|
|
292
|
-
console.log(chalk.dim(' └── docs/') + chalk.dim(' AI context documentation'));
|
|
293
|
-
console.log(chalk.dim(' ├── architecture/') + chalk.dim(' system design, data flow'));
|
|
294
|
-
console.log(chalk.dim(' ├── api/') + chalk.dim(' endpoints, schemas'));
|
|
295
|
-
console.log(chalk.dim(' ├── guides/') + chalk.dim(' getting started, workflow'));
|
|
296
|
-
console.log(chalk.dim(' ├── reference/') + chalk.dim(' config, env, deps'));
|
|
297
|
-
console.log(chalk.dim(' ├── patterns/') + chalk.dim(' coding standards'));
|
|
298
|
-
console.log(chalk.dim(' ├── testing/') + chalk.dim(' test strategy'));
|
|
299
|
-
console.log(chalk.dim(' ├── deployment/') + chalk.dim(' environments, CI/CD'));
|
|
300
|
-
console.log(chalk.dim(' └── decisions/') + chalk.dim(' ADRs'));
|
|
169
|
+
console.log(chalk.white(' Files created:'));
|
|
170
|
+
console.log(chalk.cyan(' AGENTS.md') + chalk.dim(' ─────── AI context'));
|
|
171
|
+
if (!options.skipDocs && generatedDocs.length > 0) {
|
|
172
|
+
console.log(chalk.cyan(' .claudetools/docs/') + chalk.dim(' ─ documentation'));
|
|
301
173
|
}
|
|
302
|
-
console.log(chalk.cyan(' .claude/CLAUDE.md') + chalk.dim(' ───── config pointer'));
|
|
303
174
|
console.log('');
|
|
304
|
-
console.log(chalk.dim('
|
|
305
|
-
console.log(chalk.dim(' • Review AGENTS.md for accuracy'));
|
|
306
|
-
console.log(chalk.dim(' • AI context in .claudetools/ is gitignored (regeneratable)'));
|
|
307
|
-
console.log(chalk.dim(' • Run `claudetools onboard --refresh` to update'));
|
|
175
|
+
console.log(chalk.dim(' Refresh: claudetools onboard --refresh'));
|
|
308
176
|
console.log('');
|
|
309
177
|
}
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
178
|
+
// =============================================================================
|
|
179
|
+
// Proposal Generation
|
|
180
|
+
// =============================================================================
|
|
181
|
+
async function generateProposal(projectPath, stack, answers) {
|
|
182
|
+
const spinner = ora({ text: 'Analyzing codebase...', indent: 4 }).start();
|
|
183
|
+
try {
|
|
184
|
+
const prompt = `Analyze this codebase and provide a brief stack summary.
|
|
185
|
+
|
|
186
|
+
User context:
|
|
187
|
+
${answers.projectDescription ? `- Project: ${answers.projectDescription}` : ''}
|
|
188
|
+
${answers.mainGoal ? `- Current focus: ${answers.mainGoal}` : ''}
|
|
189
|
+
${answers.additionalContext ? `- Notes: ${answers.additionalContext}` : ''}
|
|
190
|
+
|
|
191
|
+
Detected from package.json:
|
|
192
|
+
- Frameworks: ${stack.frameworks.map(f => f.name).join(', ') || 'none detected'}
|
|
193
|
+
- Libraries: ${stack.libraries.slice(0, 10).map(l => l.name).join(', ') || 'none detected'}
|
|
194
|
+
- Dev tools: ${stack.devTools.map(t => t.name).join(', ') || 'none detected'}
|
|
195
|
+
|
|
196
|
+
Respond in this exact JSON format:
|
|
197
|
+
{
|
|
198
|
+
"summary": "One sentence describing what this project is",
|
|
199
|
+
"frameworks": ["list", "of", "key", "frameworks"],
|
|
200
|
+
"libraries": ["list", "of", "important", "libraries"],
|
|
201
|
+
"devTools": ["list", "of", "dev", "tools"],
|
|
202
|
+
"architecture": "Brief architecture description",
|
|
203
|
+
"recommendations": ["suggestion 1", "suggestion 2"]
|
|
204
|
+
}`;
|
|
205
|
+
const result = await runClaudeAnalysis(projectPath, prompt, 60000);
|
|
206
|
+
spinner.stop();
|
|
207
|
+
if (result) {
|
|
208
|
+
// Try to parse JSON from response
|
|
209
|
+
const jsonMatch = result.match(/\{[\s\S]*\}/);
|
|
210
|
+
if (jsonMatch) {
|
|
211
|
+
try {
|
|
212
|
+
return JSON.parse(jsonMatch[0]);
|
|
213
|
+
}
|
|
214
|
+
catch {
|
|
215
|
+
// Fall through to default
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
catch {
|
|
221
|
+
spinner.stop();
|
|
222
|
+
}
|
|
223
|
+
// Default proposal from detected stack
|
|
224
|
+
return {
|
|
225
|
+
summary: answers.projectDescription || `${stack.primaryLanguage} project`,
|
|
226
|
+
frameworks: stack.frameworks.map(f => f.name),
|
|
227
|
+
libraries: stack.libraries.slice(0, 8).map(l => l.name),
|
|
228
|
+
devTools: stack.devTools.map(t => t.name),
|
|
229
|
+
architecture: 'Standard project structure',
|
|
230
|
+
recommendations: [],
|
|
321
231
|
};
|
|
322
|
-
return icons[category] || '📄';
|
|
323
232
|
}
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
233
|
+
async function refineProposal(projectPath, _stack, _answers, currentProposal, feedback) {
|
|
234
|
+
try {
|
|
235
|
+
const prompt = `Refine this stack proposal based on user feedback.
|
|
236
|
+
|
|
237
|
+
Current proposal:
|
|
238
|
+
${JSON.stringify(currentProposal, null, 2)}
|
|
239
|
+
|
|
240
|
+
User feedback: "${feedback}"
|
|
241
|
+
|
|
242
|
+
Provide updated proposal in same JSON format:
|
|
243
|
+
{
|
|
244
|
+
"summary": "...",
|
|
245
|
+
"frameworks": [...],
|
|
246
|
+
"libraries": [...],
|
|
247
|
+
"devTools": [...],
|
|
248
|
+
"architecture": "...",
|
|
249
|
+
"recommendations": [...]
|
|
250
|
+
}`;
|
|
251
|
+
const result = await runClaudeAnalysis(projectPath, prompt, 45000);
|
|
252
|
+
if (result) {
|
|
253
|
+
const jsonMatch = result.match(/\{[\s\S]*\}/);
|
|
254
|
+
if (jsonMatch) {
|
|
255
|
+
try {
|
|
256
|
+
return JSON.parse(jsonMatch[0]);
|
|
257
|
+
}
|
|
258
|
+
catch {
|
|
259
|
+
// Fall through
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
catch {
|
|
265
|
+
// Fall through
|
|
266
|
+
}
|
|
267
|
+
return currentProposal;
|
|
268
|
+
}
|
|
269
|
+
function displayProposal(proposal) {
|
|
270
|
+
console.log('');
|
|
271
|
+
console.log(chalk.dim(' ┌─ Proposed Configuration ────────────────'));
|
|
272
|
+
console.log(chalk.dim(' │'));
|
|
273
|
+
console.log(chalk.dim(' │ ') + chalk.white(proposal.summary));
|
|
274
|
+
console.log(chalk.dim(' │'));
|
|
275
|
+
if (proposal.frameworks.length > 0) {
|
|
276
|
+
console.log(chalk.dim(' │ ') + chalk.cyan('Frameworks: ') + proposal.frameworks.join(', '));
|
|
277
|
+
}
|
|
278
|
+
if (proposal.libraries.length > 0) {
|
|
279
|
+
console.log(chalk.dim(' │ ') + chalk.cyan('Libraries: ') + proposal.libraries.slice(0, 6).join(', ') +
|
|
280
|
+
(proposal.libraries.length > 6 ? ` (+${proposal.libraries.length - 6})` : ''));
|
|
281
|
+
}
|
|
282
|
+
if (proposal.devTools.length > 0) {
|
|
283
|
+
console.log(chalk.dim(' │ ') + chalk.cyan('Dev Tools: ') + proposal.devTools.join(', '));
|
|
284
|
+
}
|
|
285
|
+
if (proposal.architecture) {
|
|
286
|
+
console.log(chalk.dim(' │ ') + chalk.cyan('Architecture: ') + proposal.architecture);
|
|
287
|
+
}
|
|
288
|
+
if (proposal.recommendations.length > 0) {
|
|
289
|
+
console.log(chalk.dim(' │'));
|
|
290
|
+
console.log(chalk.dim(' │ ') + chalk.yellow('Recommendations:'));
|
|
291
|
+
for (const rec of proposal.recommendations.slice(0, 3)) {
|
|
292
|
+
console.log(chalk.dim(' │ ') + chalk.dim('• ') + rec);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
console.log(chalk.dim(' │'));
|
|
296
|
+
console.log(chalk.dim(' └──────────────────────────────────────────'));
|
|
297
|
+
console.log('');
|
|
298
|
+
}
|
|
299
|
+
// =============================================================================
|
|
300
|
+
// Helper Functions
|
|
301
|
+
// =============================================================================
|
|
327
302
|
function createClaudeMdPointer(projectPath, projectName) {
|
|
328
303
|
const claudeDir = join(projectPath, '.claude');
|
|
329
304
|
const claudeMdPath = join(claudeDir, 'CLAUDE.md');
|
|
330
|
-
// Create .claude directory if needed
|
|
331
305
|
if (!existsSync(claudeDir)) {
|
|
332
306
|
mkdirSync(claudeDir, { recursive: true });
|
|
333
307
|
}
|
|
334
|
-
// Check if CLAUDE.md already exists with custom content
|
|
335
308
|
if (existsSync(claudeMdPath)) {
|
|
336
309
|
const existing = readFileSync(claudeMdPath, 'utf-8');
|
|
337
|
-
// If it has substantial custom content, don't overwrite
|
|
338
310
|
if (existing.length > 500 && !existing.includes('See [AGENTS.md]')) {
|
|
339
|
-
|
|
340
|
-
return;
|
|
311
|
+
return; // Don't overwrite custom content
|
|
341
312
|
}
|
|
342
313
|
}
|
|
343
314
|
const content = `# ${projectName}
|
|
344
315
|
|
|
345
|
-
See [AGENTS.md](../AGENTS.md) for
|
|
346
|
-
|
|
347
|
-
## Quick Links
|
|
348
|
-
|
|
349
|
-
- Project docs: \`docs/\`
|
|
350
|
-
- Agent context: \`AGENTS.md\`
|
|
316
|
+
See [AGENTS.md](../AGENTS.md) for AI context.
|
|
351
317
|
|
|
352
318
|
---
|
|
353
|
-
|
|
354
|
-
*Generated by ClaudeTools. Refresh: \`claudetools onboard --refresh\`*
|
|
319
|
+
*Generated by ClaudeTools*
|
|
355
320
|
`;
|
|
356
321
|
writeFileSync(claudeMdPath, content);
|
|
357
322
|
}
|
|
358
|
-
/**
|
|
359
|
-
* Print detailed stack information
|
|
360
|
-
*/
|
|
361
|
-
function printStackDetails(stack) {
|
|
362
|
-
console.log(chalk.dim('\n Stack Details:'));
|
|
363
|
-
if (stack.frameworks.length > 0) {
|
|
364
|
-
console.log(chalk.dim(' Frameworks:'));
|
|
365
|
-
for (const fw of stack.frameworks) {
|
|
366
|
-
console.log(chalk.dim(` - ${fw.name} ${fw.version} (${fw.category})`));
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
if (stack.libraries.length > 0) {
|
|
370
|
-
console.log(chalk.dim(' Libraries:'));
|
|
371
|
-
for (const lib of stack.libraries) {
|
|
372
|
-
console.log(chalk.dim(` - ${lib.name} ${lib.version} (${lib.category})`));
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
if (stack.devTools.length > 0) {
|
|
376
|
-
console.log(chalk.dim(' Dev Tools:'));
|
|
377
|
-
for (const tool of stack.devTools) {
|
|
378
|
-
console.log(chalk.dim(` - ${tool.name} (${tool.category})`));
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
console.log('');
|
|
382
|
-
}
|
|
383
323
|
//# sourceMappingURL=index.js.map
|