wiggum-cli 0.1.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 +341 -0
- package/bin/ralph.js +8 -0
- package/dist/ai/enhancer.d.ts +100 -0
- package/dist/ai/enhancer.d.ts.map +1 -0
- package/dist/ai/enhancer.js +233 -0
- package/dist/ai/enhancer.js.map +1 -0
- package/dist/ai/index.d.ts +8 -0
- package/dist/ai/index.d.ts.map +1 -0
- package/dist/ai/index.js +11 -0
- package/dist/ai/index.js.map +1 -0
- package/dist/ai/prompts.d.ts +26 -0
- package/dist/ai/prompts.d.ts.map +1 -0
- package/dist/ai/prompts.js +201 -0
- package/dist/ai/prompts.js.map +1 -0
- package/dist/ai/providers.d.ts +35 -0
- package/dist/ai/providers.d.ts.map +1 -0
- package/dist/ai/providers.js +104 -0
- package/dist/ai/providers.js.map +1 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +196 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/init.d.ts +16 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +124 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/monitor.d.ts +17 -0
- package/dist/commands/monitor.d.ts.map +1 -0
- package/dist/commands/monitor.js +342 -0
- package/dist/commands/monitor.js.map +1 -0
- package/dist/commands/new.d.ts +19 -0
- package/dist/commands/new.d.ts.map +1 -0
- package/dist/commands/new.js +272 -0
- package/dist/commands/new.js.map +1 -0
- package/dist/commands/run.d.ts +16 -0
- package/dist/commands/run.d.ts.map +1 -0
- package/dist/commands/run.js +175 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/generator/config.d.ts +59 -0
- package/dist/generator/config.d.ts.map +1 -0
- package/dist/generator/config.js +68 -0
- package/dist/generator/config.js.map +1 -0
- package/dist/generator/index.d.ts +64 -0
- package/dist/generator/index.d.ts.map +1 -0
- package/dist/generator/index.js +147 -0
- package/dist/generator/index.js.map +1 -0
- package/dist/generator/templates.d.ts +70 -0
- package/dist/generator/templates.d.ts.map +1 -0
- package/dist/generator/templates.js +296 -0
- package/dist/generator/templates.js.map +1 -0
- package/dist/generator/writer.d.ts +93 -0
- package/dist/generator/writer.d.ts.map +1 -0
- package/dist/generator/writer.js +213 -0
- package/dist/generator/writer.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/scanner/detectors/core/framework.d.ts +11 -0
- package/dist/scanner/detectors/core/framework.d.ts.map +1 -0
- package/dist/scanner/detectors/core/framework.js +275 -0
- package/dist/scanner/detectors/core/framework.js.map +1 -0
- package/dist/scanner/detectors/core/packageManager.d.ts +11 -0
- package/dist/scanner/detectors/core/packageManager.d.ts.map +1 -0
- package/dist/scanner/detectors/core/packageManager.js +74 -0
- package/dist/scanner/detectors/core/packageManager.js.map +1 -0
- package/dist/scanner/detectors/core/styling.d.ts +12 -0
- package/dist/scanner/detectors/core/styling.d.ts.map +1 -0
- package/dist/scanner/detectors/core/styling.js +230 -0
- package/dist/scanner/detectors/core/styling.js.map +1 -0
- package/dist/scanner/detectors/core/testing.d.ts +12 -0
- package/dist/scanner/detectors/core/testing.d.ts.map +1 -0
- package/dist/scanner/detectors/core/testing.js +190 -0
- package/dist/scanner/detectors/core/testing.js.map +1 -0
- package/dist/scanner/detectors/data/api.d.ts +12 -0
- package/dist/scanner/detectors/data/api.d.ts.map +1 -0
- package/dist/scanner/detectors/data/api.js +261 -0
- package/dist/scanner/detectors/data/api.js.map +1 -0
- package/dist/scanner/detectors/data/database.d.ts +12 -0
- package/dist/scanner/detectors/data/database.d.ts.map +1 -0
- package/dist/scanner/detectors/data/database.js +213 -0
- package/dist/scanner/detectors/data/database.js.map +1 -0
- package/dist/scanner/detectors/data/orm.d.ts +12 -0
- package/dist/scanner/detectors/data/orm.d.ts.map +1 -0
- package/dist/scanner/detectors/data/orm.js +160 -0
- package/dist/scanner/detectors/data/orm.js.map +1 -0
- package/dist/scanner/detectors/frontend/formHandling.d.ts +12 -0
- package/dist/scanner/detectors/frontend/formHandling.d.ts.map +1 -0
- package/dist/scanner/detectors/frontend/formHandling.js +211 -0
- package/dist/scanner/detectors/frontend/formHandling.js.map +1 -0
- package/dist/scanner/detectors/frontend/stateManagement.d.ts +12 -0
- package/dist/scanner/detectors/frontend/stateManagement.d.ts.map +1 -0
- package/dist/scanner/detectors/frontend/stateManagement.js +221 -0
- package/dist/scanner/detectors/frontend/stateManagement.js.map +1 -0
- package/dist/scanner/detectors/frontend/uiComponents.d.ts +12 -0
- package/dist/scanner/detectors/frontend/uiComponents.d.ts.map +1 -0
- package/dist/scanner/detectors/frontend/uiComponents.js +285 -0
- package/dist/scanner/detectors/frontend/uiComponents.js.map +1 -0
- package/dist/scanner/detectors/infra/deployment.d.ts +12 -0
- package/dist/scanner/detectors/infra/deployment.d.ts.map +1 -0
- package/dist/scanner/detectors/infra/deployment.js +301 -0
- package/dist/scanner/detectors/infra/deployment.js.map +1 -0
- package/dist/scanner/detectors/infra/monorepo.d.ts +12 -0
- package/dist/scanner/detectors/infra/monorepo.d.ts.map +1 -0
- package/dist/scanner/detectors/infra/monorepo.js +219 -0
- package/dist/scanner/detectors/infra/monorepo.js.map +1 -0
- package/dist/scanner/detectors/mcp/mcpProject.d.ts +12 -0
- package/dist/scanner/detectors/mcp/mcpProject.d.ts.map +1 -0
- package/dist/scanner/detectors/mcp/mcpProject.js +154 -0
- package/dist/scanner/detectors/mcp/mcpProject.js.map +1 -0
- package/dist/scanner/detectors/mcp/mcpServers.d.ts +17 -0
- package/dist/scanner/detectors/mcp/mcpServers.d.ts.map +1 -0
- package/dist/scanner/detectors/mcp/mcpServers.js +193 -0
- package/dist/scanner/detectors/mcp/mcpServers.js.map +1 -0
- package/dist/scanner/detectors/services/analytics.d.ts +12 -0
- package/dist/scanner/detectors/services/analytics.d.ts.map +1 -0
- package/dist/scanner/detectors/services/analytics.js +236 -0
- package/dist/scanner/detectors/services/analytics.js.map +1 -0
- package/dist/scanner/detectors/services/auth.d.ts +12 -0
- package/dist/scanner/detectors/services/auth.d.ts.map +1 -0
- package/dist/scanner/detectors/services/auth.js +217 -0
- package/dist/scanner/detectors/services/auth.js.map +1 -0
- package/dist/scanner/detectors/services/email.d.ts +12 -0
- package/dist/scanner/detectors/services/email.d.ts.map +1 -0
- package/dist/scanner/detectors/services/email.js +211 -0
- package/dist/scanner/detectors/services/email.js.map +1 -0
- package/dist/scanner/detectors/services/payments.d.ts +12 -0
- package/dist/scanner/detectors/services/payments.d.ts.map +1 -0
- package/dist/scanner/detectors/services/payments.js +185 -0
- package/dist/scanner/detectors/services/payments.js.map +1 -0
- package/dist/scanner/detectors/utils.d.ts +160 -0
- package/dist/scanner/detectors/utils.d.ts.map +1 -0
- package/dist/scanner/detectors/utils.js +222 -0
- package/dist/scanner/detectors/utils.js.map +1 -0
- package/dist/scanner/index.d.ts +42 -0
- package/dist/scanner/index.d.ts.map +1 -0
- package/dist/scanner/index.js +282 -0
- package/dist/scanner/index.js.map +1 -0
- package/dist/scanner/registry.d.ts +43 -0
- package/dist/scanner/registry.d.ts.map +1 -0
- package/dist/scanner/registry.js +243 -0
- package/dist/scanner/registry.js.map +1 -0
- package/dist/scanner/types.d.ts +112 -0
- package/dist/scanner/types.d.ts.map +1 -0
- package/dist/scanner/types.js +6 -0
- package/dist/scanner/types.js.map +1 -0
- package/dist/templates/config/ralph.config.js.tmpl +38 -0
- package/dist/templates/guides/AGENTS.md.tmpl +100 -0
- package/dist/templates/guides/FRONTEND.md.tmpl +523 -0
- package/dist/templates/guides/PERFORMANCE.md.tmpl +264 -0
- package/dist/templates/guides/SECURITY.md.tmpl +100 -0
- package/dist/templates/prompts/PROMPT.md.tmpl +77 -0
- package/dist/templates/prompts/PROMPT_e2e.md.tmpl +234 -0
- package/dist/templates/prompts/PROMPT_feature.md.tmpl +83 -0
- package/dist/templates/prompts/PROMPT_review.md.tmpl +167 -0
- package/dist/templates/prompts/PROMPT_verify.md.tmpl +72 -0
- package/dist/templates/root/.gitignore.tmpl +5 -0
- package/dist/templates/root/LEARNINGS.md.tmpl +24 -0
- package/dist/templates/root/README.md.tmpl +61 -0
- package/dist/templates/scripts/feature-loop.sh.tmpl +267 -0
- package/dist/templates/scripts/loop.sh.tmpl +59 -0
- package/dist/templates/scripts/ralph-monitor.sh.tmpl +244 -0
- package/dist/templates/specs/README.md.tmpl +57 -0
- package/dist/templates/specs/_example.md.tmpl +71 -0
- package/dist/utils/config.d.ts +95 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +148 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/header.d.ts +5 -0
- package/dist/utils/header.d.ts.map +1 -0
- package/dist/utils/header.js +15 -0
- package/dist/utils/header.js.map +1 -0
- package/dist/utils/logger.d.ts +11 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +24 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +44 -0
- package/src/ai/enhancer.ts +350 -0
- package/src/ai/index.ts +38 -0
- package/src/ai/prompts.ts +217 -0
- package/src/ai/providers.ts +136 -0
- package/src/cli.ts +255 -0
- package/src/commands/init.ts +149 -0
- package/src/commands/monitor.ts +412 -0
- package/src/commands/new.ts +312 -0
- package/src/commands/run.ts +214 -0
- package/src/generator/config.ts +116 -0
- package/src/generator/index.ts +227 -0
- package/src/generator/templates.ts +412 -0
- package/src/generator/writer.ts +293 -0
- package/src/index.ts +41 -0
- package/src/scanner/detectors/core/framework.ts +332 -0
- package/src/scanner/detectors/core/packageManager.ts +91 -0
- package/src/scanner/detectors/core/styling.ts +261 -0
- package/src/scanner/detectors/core/testing.ts +221 -0
- package/src/scanner/detectors/data/api.ts +303 -0
- package/src/scanner/detectors/data/database.ts +245 -0
- package/src/scanner/detectors/data/orm.ts +180 -0
- package/src/scanner/detectors/frontend/formHandling.ts +244 -0
- package/src/scanner/detectors/frontend/stateManagement.ts +261 -0
- package/src/scanner/detectors/frontend/uiComponents.ts +328 -0
- package/src/scanner/detectors/infra/deployment.ts +343 -0
- package/src/scanner/detectors/infra/monorepo.ts +251 -0
- package/src/scanner/detectors/mcp/mcpProject.ts +176 -0
- package/src/scanner/detectors/mcp/mcpServers.ts +237 -0
- package/src/scanner/detectors/services/analytics.ts +273 -0
- package/src/scanner/detectors/services/auth.ts +254 -0
- package/src/scanner/detectors/services/email.ts +244 -0
- package/src/scanner/detectors/services/payments.ts +213 -0
- package/src/scanner/detectors/utils.ts +251 -0
- package/src/scanner/index.ts +354 -0
- package/src/scanner/registry.ts +301 -0
- package/src/scanner/types.ts +152 -0
- package/src/templates/config/ralph.config.js.tmpl +38 -0
- package/src/templates/guides/AGENTS.md.tmpl +100 -0
- package/src/templates/guides/FRONTEND.md.tmpl +523 -0
- package/src/templates/guides/PERFORMANCE.md.tmpl +264 -0
- package/src/templates/guides/SECURITY.md.tmpl +100 -0
- package/src/templates/prompts/PROMPT.md.tmpl +77 -0
- package/src/templates/prompts/PROMPT_e2e.md.tmpl +234 -0
- package/src/templates/prompts/PROMPT_feature.md.tmpl +83 -0
- package/src/templates/prompts/PROMPT_review.md.tmpl +167 -0
- package/src/templates/prompts/PROMPT_verify.md.tmpl +72 -0
- package/src/templates/root/.gitignore.tmpl +5 -0
- package/src/templates/root/LEARNINGS.md.tmpl +24 -0
- package/src/templates/root/README.md.tmpl +61 -0
- package/src/templates/scripts/feature-loop.sh.tmpl +267 -0
- package/src/templates/scripts/loop.sh.tmpl +59 -0
- package/src/templates/scripts/ralph-monitor.sh.tmpl +244 -0
- package/src/templates/specs/README.md.tmpl +57 -0
- package/src/templates/specs/_example.md.tmpl +71 -0
- package/src/utils/config.ts +221 -0
- package/src/utils/header.ts +15 -0
- package/src/utils/logger.ts +28 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Analysis Prompts
|
|
3
|
+
* Defines prompts for codebase analysis and enhancement
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { ScanResult, DetectedStack } from '../scanner/types.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Format the detected stack for inclusion in prompts
|
|
10
|
+
*/
|
|
11
|
+
export function formatStackForPrompt(stack: DetectedStack): string {
|
|
12
|
+
const sections: string[] = [];
|
|
13
|
+
|
|
14
|
+
// Core
|
|
15
|
+
if (stack.framework) {
|
|
16
|
+
const variant = stack.framework.variant ? ` (${stack.framework.variant})` : '';
|
|
17
|
+
sections.push(`Framework: ${stack.framework.name}${variant}`);
|
|
18
|
+
}
|
|
19
|
+
if (stack.packageManager) {
|
|
20
|
+
sections.push(`Package Manager: ${stack.packageManager.name}`);
|
|
21
|
+
}
|
|
22
|
+
if (stack.testing?.unit) {
|
|
23
|
+
sections.push(`Unit Testing: ${stack.testing.unit.name}`);
|
|
24
|
+
}
|
|
25
|
+
if (stack.testing?.e2e) {
|
|
26
|
+
sections.push(`E2E Testing: ${stack.testing.e2e.name}`);
|
|
27
|
+
}
|
|
28
|
+
if (stack.styling) {
|
|
29
|
+
sections.push(`Styling: ${stack.styling.name}`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Data Layer
|
|
33
|
+
if (stack.database) {
|
|
34
|
+
sections.push(`Database: ${stack.database.name}`);
|
|
35
|
+
}
|
|
36
|
+
if (stack.orm) {
|
|
37
|
+
sections.push(`ORM: ${stack.orm.name}`);
|
|
38
|
+
}
|
|
39
|
+
if (stack.api && stack.api.length > 0) {
|
|
40
|
+
sections.push(`API Patterns: ${stack.api.map(a => a.name).join(', ')}`);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Frontend
|
|
44
|
+
if (stack.stateManagement) {
|
|
45
|
+
sections.push(`State Management: ${stack.stateManagement.name}`);
|
|
46
|
+
}
|
|
47
|
+
if (stack.uiComponents && stack.uiComponents.length > 0) {
|
|
48
|
+
sections.push(`UI Components: ${stack.uiComponents.map(u => u.name).join(', ')}`);
|
|
49
|
+
}
|
|
50
|
+
if (stack.formHandling && stack.formHandling.length > 0) {
|
|
51
|
+
sections.push(`Form Handling: ${stack.formHandling.map(f => f.name).join(', ')}`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Services
|
|
55
|
+
if (stack.auth) {
|
|
56
|
+
sections.push(`Auth: ${stack.auth.name}`);
|
|
57
|
+
}
|
|
58
|
+
if (stack.analytics && stack.analytics.length > 0) {
|
|
59
|
+
sections.push(`Analytics: ${stack.analytics.map(a => a.name).join(', ')}`);
|
|
60
|
+
}
|
|
61
|
+
if (stack.payments) {
|
|
62
|
+
sections.push(`Payments: ${stack.payments.name}`);
|
|
63
|
+
}
|
|
64
|
+
if (stack.email) {
|
|
65
|
+
sections.push(`Email: ${stack.email.name}`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Infrastructure
|
|
69
|
+
if (stack.deployment && stack.deployment.length > 0) {
|
|
70
|
+
sections.push(`Deployment: ${stack.deployment.map(d => d.name).join(', ')}`);
|
|
71
|
+
}
|
|
72
|
+
if (stack.monorepo) {
|
|
73
|
+
sections.push(`Monorepo: ${stack.monorepo.name}`);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// MCP
|
|
77
|
+
if (stack.mcp) {
|
|
78
|
+
if (stack.mcp.isProject) {
|
|
79
|
+
sections.push('MCP: This is an MCP server project');
|
|
80
|
+
}
|
|
81
|
+
if (stack.mcp.detected && stack.mcp.detected.length > 0) {
|
|
82
|
+
sections.push(`MCP Servers: ${stack.mcp.detected.map(m => m.name).join(', ')}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return sections.join('\n');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* System prompt for codebase analysis
|
|
91
|
+
*/
|
|
92
|
+
export const SYSTEM_PROMPT = `You are an expert software architect analyzing a codebase to provide insights for AI-assisted development.
|
|
93
|
+
|
|
94
|
+
Your role is to:
|
|
95
|
+
1. Analyze the detected tech stack and provide deeper insights
|
|
96
|
+
2. Identify architectural patterns and coding conventions
|
|
97
|
+
3. Suggest improvements to the detection results
|
|
98
|
+
4. Recommend MCP servers that would benefit this project
|
|
99
|
+
5. Generate custom prompt suggestions for AI coding assistants
|
|
100
|
+
|
|
101
|
+
Be concise and actionable. Focus on practical insights that help developers work more effectively with AI tools.
|
|
102
|
+
|
|
103
|
+
Respond in valid JSON format only.`;
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Create the codebase analysis prompt
|
|
107
|
+
*/
|
|
108
|
+
export function createAnalysisPrompt(scanResult: ScanResult): string {
|
|
109
|
+
const stackInfo = formatStackForPrompt(scanResult.stack);
|
|
110
|
+
|
|
111
|
+
return `Analyze this codebase and provide enhanced insights.
|
|
112
|
+
|
|
113
|
+
Project Root: ${scanResult.projectRoot}
|
|
114
|
+
|
|
115
|
+
Detected Stack:
|
|
116
|
+
${stackInfo || 'No technologies detected'}
|
|
117
|
+
|
|
118
|
+
Based on this stack, provide analysis in the following JSON format:
|
|
119
|
+
{
|
|
120
|
+
"frameworkInsights": {
|
|
121
|
+
"variant": "more specific variant if detectable (e.g., 'app-router', 'pages-router', 'spa', 'ssr')",
|
|
122
|
+
"confidence": "high/medium/low",
|
|
123
|
+
"notes": "any additional observations about framework usage"
|
|
124
|
+
},
|
|
125
|
+
"architecturalPatterns": [
|
|
126
|
+
{
|
|
127
|
+
"pattern": "pattern name",
|
|
128
|
+
"confidence": "high/medium/low",
|
|
129
|
+
"evidence": "why you think this pattern is used"
|
|
130
|
+
}
|
|
131
|
+
],
|
|
132
|
+
"codingConventions": [
|
|
133
|
+
{
|
|
134
|
+
"convention": "convention name",
|
|
135
|
+
"suggestion": "how to follow this convention"
|
|
136
|
+
}
|
|
137
|
+
],
|
|
138
|
+
"recommendedMcpServers": [
|
|
139
|
+
{
|
|
140
|
+
"name": "server name",
|
|
141
|
+
"reason": "why this would be useful"
|
|
142
|
+
}
|
|
143
|
+
],
|
|
144
|
+
"customPromptSuggestions": [
|
|
145
|
+
"Specific prompt suggestions tailored to this codebase"
|
|
146
|
+
],
|
|
147
|
+
"additionalDetections": {
|
|
148
|
+
"possibleMissed": ["technologies that might be in use but weren't detected"],
|
|
149
|
+
"refinements": ["suggestions to improve existing detections"]
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
Only include sections where you have meaningful insights. Keep responses focused and actionable.`;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Prompt for validating and improving scanner results
|
|
158
|
+
*/
|
|
159
|
+
export function createValidationPrompt(scanResult: ScanResult): string {
|
|
160
|
+
const stackInfo = formatStackForPrompt(scanResult.stack);
|
|
161
|
+
|
|
162
|
+
return `Review and validate these scanner detection results for accuracy.
|
|
163
|
+
|
|
164
|
+
Detected Stack:
|
|
165
|
+
${stackInfo || 'No technologies detected'}
|
|
166
|
+
|
|
167
|
+
For each detection, assess if it seems accurate based on common project patterns.
|
|
168
|
+
Identify any likely false positives or missing detections.
|
|
169
|
+
|
|
170
|
+
Respond in JSON format:
|
|
171
|
+
{
|
|
172
|
+
"validations": [
|
|
173
|
+
{
|
|
174
|
+
"technology": "name",
|
|
175
|
+
"status": "confirmed/uncertain/likely-false-positive",
|
|
176
|
+
"notes": "explanation if uncertain or false positive"
|
|
177
|
+
}
|
|
178
|
+
],
|
|
179
|
+
"likelyMissed": [
|
|
180
|
+
{
|
|
181
|
+
"technology": "name",
|
|
182
|
+
"reason": "why this might be in use"
|
|
183
|
+
}
|
|
184
|
+
]
|
|
185
|
+
}`;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Prompt for generating stack-specific recommendations
|
|
190
|
+
*/
|
|
191
|
+
export function createRecommendationsPrompt(scanResult: ScanResult): string {
|
|
192
|
+
const stackInfo = formatStackForPrompt(scanResult.stack);
|
|
193
|
+
|
|
194
|
+
return `Based on this tech stack, provide specific recommendations for AI-assisted development.
|
|
195
|
+
|
|
196
|
+
Detected Stack:
|
|
197
|
+
${stackInfo || 'No technologies detected'}
|
|
198
|
+
|
|
199
|
+
Provide recommendations in JSON format:
|
|
200
|
+
{
|
|
201
|
+
"mcpServers": [
|
|
202
|
+
{
|
|
203
|
+
"name": "server identifier",
|
|
204
|
+
"priority": "high/medium/low",
|
|
205
|
+
"reason": "why this is recommended"
|
|
206
|
+
}
|
|
207
|
+
],
|
|
208
|
+
"aiToolingTips": [
|
|
209
|
+
"Tips for working with AI tools on this codebase"
|
|
210
|
+
],
|
|
211
|
+
"contextSuggestions": [
|
|
212
|
+
"Important context an AI should know about this stack"
|
|
213
|
+
]
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
Focus on practical, actionable recommendations.`;
|
|
217
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Provider Configuration
|
|
3
|
+
* Configures AI providers (Anthropic, OpenAI, OpenRouter) for the enhancer
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { createAnthropic } from '@ai-sdk/anthropic';
|
|
7
|
+
import { createOpenAI } from '@ai-sdk/openai';
|
|
8
|
+
import type { LanguageModel } from 'ai';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Supported AI providers
|
|
12
|
+
*/
|
|
13
|
+
export type AIProvider = 'anthropic' | 'openai' | 'openrouter';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Provider configuration result
|
|
17
|
+
*/
|
|
18
|
+
export interface ProviderConfig {
|
|
19
|
+
model: LanguageModel;
|
|
20
|
+
provider: AIProvider;
|
|
21
|
+
modelId: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Environment variable names for each provider
|
|
26
|
+
*/
|
|
27
|
+
const API_KEY_ENV_VARS: Record<AIProvider, string> = {
|
|
28
|
+
anthropic: 'ANTHROPIC_API_KEY',
|
|
29
|
+
openai: 'OPENAI_API_KEY',
|
|
30
|
+
openrouter: 'OPENROUTER_API_KEY',
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Default models for each provider
|
|
35
|
+
* Using fast/cost-effective models for speed
|
|
36
|
+
*/
|
|
37
|
+
const DEFAULT_MODELS: Record<AIProvider, string> = {
|
|
38
|
+
anthropic: 'claude-sonnet-4-20250514',
|
|
39
|
+
openai: 'gpt-4o-mini',
|
|
40
|
+
openrouter: 'anthropic/claude-3.5-sonnet',
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Check if an API key is available for a provider
|
|
45
|
+
*/
|
|
46
|
+
export function hasApiKey(provider: AIProvider): boolean {
|
|
47
|
+
const envVar = API_KEY_ENV_VARS[provider];
|
|
48
|
+
return !!process.env[envVar];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Get the API key for a provider
|
|
53
|
+
* @throws Error if API key is not set
|
|
54
|
+
*/
|
|
55
|
+
function getApiKey(provider: AIProvider): string {
|
|
56
|
+
const envVar = API_KEY_ENV_VARS[provider];
|
|
57
|
+
const apiKey = process.env[envVar];
|
|
58
|
+
|
|
59
|
+
if (!apiKey) {
|
|
60
|
+
throw new Error(
|
|
61
|
+
`API key not found. Set ${envVar} environment variable to use ${provider} provider.`
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return apiKey;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Get a configured AI model for the specified provider
|
|
70
|
+
*/
|
|
71
|
+
export function getModel(provider: AIProvider = 'anthropic'): ProviderConfig {
|
|
72
|
+
const modelId = DEFAULT_MODELS[provider];
|
|
73
|
+
|
|
74
|
+
switch (provider) {
|
|
75
|
+
case 'anthropic': {
|
|
76
|
+
const anthropic = createAnthropic({
|
|
77
|
+
apiKey: getApiKey('anthropic'),
|
|
78
|
+
});
|
|
79
|
+
return {
|
|
80
|
+
model: anthropic(modelId),
|
|
81
|
+
provider,
|
|
82
|
+
modelId,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
case 'openai': {
|
|
87
|
+
const openai = createOpenAI({
|
|
88
|
+
apiKey: getApiKey('openai'),
|
|
89
|
+
});
|
|
90
|
+
return {
|
|
91
|
+
model: openai(modelId),
|
|
92
|
+
provider,
|
|
93
|
+
modelId,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
case 'openrouter': {
|
|
98
|
+
// OpenRouter uses OpenAI-compatible API
|
|
99
|
+
const openrouter = createOpenAI({
|
|
100
|
+
apiKey: getApiKey('openrouter'),
|
|
101
|
+
baseURL: 'https://openrouter.ai/api/v1',
|
|
102
|
+
});
|
|
103
|
+
return {
|
|
104
|
+
model: openrouter(modelId),
|
|
105
|
+
provider,
|
|
106
|
+
modelId,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
default:
|
|
111
|
+
throw new Error(`Unknown provider: ${provider}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Get the first available provider with an API key
|
|
117
|
+
* Checks in order: anthropic, openai, openrouter
|
|
118
|
+
*/
|
|
119
|
+
export function getAvailableProvider(): AIProvider | null {
|
|
120
|
+
const providers: AIProvider[] = ['anthropic', 'openai', 'openrouter'];
|
|
121
|
+
|
|
122
|
+
for (const provider of providers) {
|
|
123
|
+
if (hasApiKey(provider)) {
|
|
124
|
+
return provider;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Get the environment variable name for a provider's API key
|
|
133
|
+
*/
|
|
134
|
+
export function getApiKeyEnvVar(provider: AIProvider): string {
|
|
135
|
+
return API_KEY_ENV_VARS[provider];
|
|
136
|
+
}
|
package/src/cli.ts
ADDED
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { displayHeader } from './utils/header.js';
|
|
3
|
+
import { initCommand } from './commands/init.js';
|
|
4
|
+
import { runCommand, type RunOptions } from './commands/run.js';
|
|
5
|
+
import { monitorCommand, type MonitorOptions } from './commands/monitor.js';
|
|
6
|
+
import { newCommand, type NewOptions } from './commands/new.js';
|
|
7
|
+
import { logger } from './utils/logger.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Set up and configure the CLI
|
|
11
|
+
*/
|
|
12
|
+
export function createCli(): Command {
|
|
13
|
+
const program = new Command();
|
|
14
|
+
|
|
15
|
+
program
|
|
16
|
+
.name('ralph')
|
|
17
|
+
.description(
|
|
18
|
+
'AI-powered feature development loop CLI.\n\n' +
|
|
19
|
+
'Ralph auto-detects your tech stack and generates an intelligent\n' +
|
|
20
|
+
'development environment for AI-driven feature implementation.'
|
|
21
|
+
)
|
|
22
|
+
.version('0.1.0')
|
|
23
|
+
.hook('preAction', () => {
|
|
24
|
+
displayHeader();
|
|
25
|
+
})
|
|
26
|
+
.addHelpText(
|
|
27
|
+
'after',
|
|
28
|
+
`
|
|
29
|
+
Examples:
|
|
30
|
+
$ ralph init Initialize Ralph in your project
|
|
31
|
+
$ ralph init --ai Initialize with AI-enhanced analysis
|
|
32
|
+
$ ralph new my-feature Create a new feature specification
|
|
33
|
+
$ ralph run my-feature Run the feature development loop
|
|
34
|
+
$ ralph monitor my-feature Monitor progress in real-time
|
|
35
|
+
|
|
36
|
+
Documentation:
|
|
37
|
+
https://github.com/your-org/ralph-cli#readme
|
|
38
|
+
`
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
// ralph init
|
|
42
|
+
program
|
|
43
|
+
.command('init')
|
|
44
|
+
.description(
|
|
45
|
+
'Initialize Ralph in the current project.\n\n' +
|
|
46
|
+
'Scans your codebase to detect the tech stack (framework, testing,\n' +
|
|
47
|
+
'database, auth, etc.) and generates configuration files in .ralph/'
|
|
48
|
+
)
|
|
49
|
+
.option('--ai', 'Enable AI-enhanced analysis for deeper project insights')
|
|
50
|
+
.option(
|
|
51
|
+
'--provider <name>',
|
|
52
|
+
'AI provider to use (anthropic, openai, openrouter)',
|
|
53
|
+
'anthropic'
|
|
54
|
+
)
|
|
55
|
+
.option('-y, --yes', 'Accept defaults and skip all confirmation prompts')
|
|
56
|
+
.addHelpText(
|
|
57
|
+
'after',
|
|
58
|
+
`
|
|
59
|
+
Examples:
|
|
60
|
+
$ ralph init Basic initialization
|
|
61
|
+
$ ralph init --ai With AI-enhanced analysis (Anthropic)
|
|
62
|
+
$ ralph init --ai --provider openai With OpenAI provider
|
|
63
|
+
$ ralph init --yes Non-interactive mode
|
|
64
|
+
|
|
65
|
+
Environment Variables:
|
|
66
|
+
ANTHROPIC_API_KEY Required for --ai with anthropic provider
|
|
67
|
+
OPENAI_API_KEY Required for --ai with openai provider
|
|
68
|
+
OPENROUTER_API_KEY Required for --ai with openrouter provider
|
|
69
|
+
`
|
|
70
|
+
)
|
|
71
|
+
.action(async (options) => {
|
|
72
|
+
try {
|
|
73
|
+
await initCommand(options);
|
|
74
|
+
} catch (error) {
|
|
75
|
+
handleCommandError(error);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// ralph run <feature>
|
|
80
|
+
program
|
|
81
|
+
.command('run <feature>')
|
|
82
|
+
.description(
|
|
83
|
+
'Run the feature development loop for a specific feature.\n\n' +
|
|
84
|
+
'Executes the AI-driven implementation workflow using the feature\n' +
|
|
85
|
+
'spec in .ralph/specs/<feature>.md'
|
|
86
|
+
)
|
|
87
|
+
.option(
|
|
88
|
+
'--worktree',
|
|
89
|
+
'Use git worktree for isolation (enables parallel execution of multiple features)'
|
|
90
|
+
)
|
|
91
|
+
.option(
|
|
92
|
+
'--resume',
|
|
93
|
+
'Resume an interrupted loop (reuses existing branch and worktree)'
|
|
94
|
+
)
|
|
95
|
+
.option(
|
|
96
|
+
'--model <model>',
|
|
97
|
+
'Claude model to use for implementation (opus, sonnet)'
|
|
98
|
+
)
|
|
99
|
+
.option(
|
|
100
|
+
'--max-iterations <n>',
|
|
101
|
+
'Maximum number of implementation iterations (default: 50)',
|
|
102
|
+
parseInt
|
|
103
|
+
)
|
|
104
|
+
.option(
|
|
105
|
+
'--max-e2e-attempts <n>',
|
|
106
|
+
'Maximum E2E test retry attempts before giving up (default: 3)',
|
|
107
|
+
parseInt
|
|
108
|
+
)
|
|
109
|
+
.addHelpText(
|
|
110
|
+
'after',
|
|
111
|
+
`
|
|
112
|
+
Examples:
|
|
113
|
+
$ ralph run user-auth Run the user-auth feature
|
|
114
|
+
$ ralph run payment --worktree Run in isolated worktree
|
|
115
|
+
$ ralph run payment --resume Resume interrupted session
|
|
116
|
+
$ ralph run my-feature --model opus Use Claude Opus model
|
|
117
|
+
$ ralph run my-feature --max-iterations 30 --max-e2e-attempts 5
|
|
118
|
+
|
|
119
|
+
Notes:
|
|
120
|
+
- Create a feature spec first with: ralph new <feature>
|
|
121
|
+
- The spec file should be at: .ralph/specs/<feature>.md
|
|
122
|
+
- Use --worktree to run multiple features in parallel
|
|
123
|
+
`
|
|
124
|
+
)
|
|
125
|
+
.action(async (feature: string, options) => {
|
|
126
|
+
try {
|
|
127
|
+
const runOptions: RunOptions = {
|
|
128
|
+
worktree: options.worktree,
|
|
129
|
+
resume: options.resume,
|
|
130
|
+
model: options.model,
|
|
131
|
+
maxIterations: options.maxIterations,
|
|
132
|
+
maxE2eAttempts: options.maxE2eAttempts,
|
|
133
|
+
};
|
|
134
|
+
await runCommand(feature, runOptions);
|
|
135
|
+
} catch (error) {
|
|
136
|
+
handleCommandError(error);
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// ralph monitor <feature>
|
|
141
|
+
program
|
|
142
|
+
.command('monitor <feature>')
|
|
143
|
+
.description(
|
|
144
|
+
'Launch the monitoring dashboard for a feature.\n\n' +
|
|
145
|
+
'Displays real-time progress including iteration count, phase,\n' +
|
|
146
|
+
'task completion, token usage, and E2E test status.'
|
|
147
|
+
)
|
|
148
|
+
.option(
|
|
149
|
+
'--bash',
|
|
150
|
+
'Use the bash script monitor instead of the built-in dashboard'
|
|
151
|
+
)
|
|
152
|
+
.option('--python', 'Use the Python TUI monitor (if available)')
|
|
153
|
+
.option(
|
|
154
|
+
'--interval <seconds>',
|
|
155
|
+
'Dashboard refresh interval in seconds (default: 5)',
|
|
156
|
+
parseInt,
|
|
157
|
+
5
|
|
158
|
+
)
|
|
159
|
+
.addHelpText(
|
|
160
|
+
'after',
|
|
161
|
+
`
|
|
162
|
+
Examples:
|
|
163
|
+
$ ralph monitor my-feature Monitor with built-in dashboard
|
|
164
|
+
$ ralph monitor my-feature --interval 2 Refresh every 2 seconds
|
|
165
|
+
$ ralph monitor my-feature --bash Use bash script monitor
|
|
166
|
+
|
|
167
|
+
Dashboard Shows:
|
|
168
|
+
- Current phase (Planning, Implementation, E2E Testing, etc.)
|
|
169
|
+
- Iteration progress
|
|
170
|
+
- Task completion status
|
|
171
|
+
- Token usage (input/output)
|
|
172
|
+
- Git branch information
|
|
173
|
+
`
|
|
174
|
+
)
|
|
175
|
+
.action(async (feature: string, options) => {
|
|
176
|
+
try {
|
|
177
|
+
const monitorOptions: MonitorOptions = {
|
|
178
|
+
bash: options.bash,
|
|
179
|
+
python: options.python,
|
|
180
|
+
interval: options.interval,
|
|
181
|
+
};
|
|
182
|
+
await monitorCommand(feature, monitorOptions);
|
|
183
|
+
} catch (error) {
|
|
184
|
+
handleCommandError(error);
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
// ralph new <feature>
|
|
189
|
+
program
|
|
190
|
+
.command('new <feature>')
|
|
191
|
+
.description(
|
|
192
|
+
'Create a new feature specification from template.\n\n' +
|
|
193
|
+
'Generates a markdown spec file with sections for requirements,\n' +
|
|
194
|
+
'acceptance criteria, technical notes, and more.'
|
|
195
|
+
)
|
|
196
|
+
.option('-e, --edit', 'Open the spec in your editor after creation')
|
|
197
|
+
.option(
|
|
198
|
+
'--editor <editor>',
|
|
199
|
+
'Editor command to use (defaults to $EDITOR or "code")'
|
|
200
|
+
)
|
|
201
|
+
.option('-y, --yes', 'Skip confirmation prompts')
|
|
202
|
+
.option('-f, --force', 'Overwrite existing spec file without prompting')
|
|
203
|
+
.addHelpText(
|
|
204
|
+
'after',
|
|
205
|
+
`
|
|
206
|
+
Examples:
|
|
207
|
+
$ ralph new user-dashboard Create spec with prompts
|
|
208
|
+
$ ralph new user-dashboard --edit Create and open in editor
|
|
209
|
+
$ ralph new user-dashboard -e --editor vim Open in vim
|
|
210
|
+
$ ralph new user-dashboard --yes Skip confirmations
|
|
211
|
+
$ ralph new user-dashboard --force Overwrite if exists
|
|
212
|
+
|
|
213
|
+
Output:
|
|
214
|
+
Creates: .ralph/specs/<feature>.md
|
|
215
|
+
|
|
216
|
+
Template includes sections for:
|
|
217
|
+
- Purpose and user stories
|
|
218
|
+
- Functional and non-functional requirements
|
|
219
|
+
- Technical notes and dependencies
|
|
220
|
+
- Visual requirements (for UI features)
|
|
221
|
+
- API endpoints
|
|
222
|
+
- Acceptance criteria
|
|
223
|
+
`
|
|
224
|
+
)
|
|
225
|
+
.action(async (feature: string, options) => {
|
|
226
|
+
try {
|
|
227
|
+
const newOptions: NewOptions = {
|
|
228
|
+
edit: options.edit,
|
|
229
|
+
editor: options.editor,
|
|
230
|
+
yes: options.yes,
|
|
231
|
+
force: options.force,
|
|
232
|
+
};
|
|
233
|
+
await newCommand(feature, newOptions);
|
|
234
|
+
} catch (error) {
|
|
235
|
+
handleCommandError(error);
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
return program;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Handle command errors with user-friendly output
|
|
244
|
+
*/
|
|
245
|
+
function handleCommandError(error: unknown): void {
|
|
246
|
+
if (error instanceof Error) {
|
|
247
|
+
logger.error(error.message);
|
|
248
|
+
if (process.env.DEBUG) {
|
|
249
|
+
console.error(error.stack);
|
|
250
|
+
}
|
|
251
|
+
} else {
|
|
252
|
+
logger.error(String(error));
|
|
253
|
+
}
|
|
254
|
+
process.exit(1);
|
|
255
|
+
}
|