@vibecheckai/cli 3.9.0 → 4.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/README.md +1 -1
- package/bin/runners/context/generators/cursor-enhanced.js +99 -13
- package/bin/runners/lib/unified-cli-output.js +16 -0
- package/bin/runners/runCI.js +353 -0
- package/bin/runners/runCheckpoint.js +2 -2
- package/mcp-server/.eslintrc.json +24 -0
- package/mcp-server/README.md +425 -135
- package/mcp-server/SPEC.md +583 -0
- package/mcp-server/configs/README.md +172 -0
- package/mcp-server/configs/claude-desktop-pro.json +31 -0
- package/mcp-server/configs/claude-desktop-with-workspace.json +25 -0
- package/mcp-server/configs/claude-desktop.json +19 -0
- package/mcp-server/configs/cursor-mcp.json +21 -0
- package/mcp-server/configs/windsurf-mcp.json +17 -0
- package/mcp-server/mcp-config.example.json +9 -0
- package/mcp-server/package.json +49 -34
- package/mcp-server/src/cli.ts +185 -0
- package/mcp-server/src/index.ts +85 -0
- package/mcp-server/src/server.ts +1933 -0
- package/mcp-server/src/services/cache-service.ts +466 -0
- package/mcp-server/src/services/cli-service.ts +345 -0
- package/mcp-server/src/services/context-manager.ts +717 -0
- package/mcp-server/src/services/firewall-service.ts +662 -0
- package/mcp-server/src/services/git-service.ts +671 -0
- package/mcp-server/src/services/index.ts +52 -0
- package/mcp-server/src/services/prompt-builder-service.ts +1031 -0
- package/mcp-server/src/services/session-service.ts +550 -0
- package/mcp-server/src/services/tier-service.ts +470 -0
- package/mcp-server/src/types.ts +351 -0
- package/mcp-server/tsconfig.json +16 -27
- package/package.json +6 -6
- package/mcp-server/.guardrail/audit/audit.log.jsonl +0 -2
- package/mcp-server/.specs/architecture.mdc +0 -90
- package/mcp-server/.specs/security.mdc +0 -30
- package/mcp-server/HARDENING_SUMMARY.md +0 -299
- package/mcp-server/agent-checkpoint.js +0 -364
- package/mcp-server/agent-firewall-interceptor.js +0 -500
- package/mcp-server/architect-tools.js +0 -707
- package/mcp-server/audit-mcp.js +0 -206
- package/mcp-server/authority-tools.js +0 -569
- package/mcp-server/codebase-architect-tools.js +0 -838
- package/mcp-server/conductor/conflict-resolver.js +0 -588
- package/mcp-server/conductor/execution-planner.js +0 -544
- package/mcp-server/conductor/index.js +0 -377
- package/mcp-server/conductor/lock-manager.js +0 -615
- package/mcp-server/conductor/request-queue.js +0 -550
- package/mcp-server/conductor/session-manager.js +0 -500
- package/mcp-server/conductor/tools.js +0 -510
- package/mcp-server/consolidated-tools.js +0 -1170
- package/mcp-server/deprecation-middleware.js +0 -282
- package/mcp-server/handlers/index.ts +0 -15
- package/mcp-server/handlers/tool-handler.ts +0 -593
- package/mcp-server/hygiene-tools.js +0 -428
- package/mcp-server/index-v1.js +0 -698
- package/mcp-server/index.js +0 -2940
- package/mcp-server/intelligence-tools.js +0 -664
- package/mcp-server/intent-drift-tools.js +0 -873
- package/mcp-server/intent-firewall-interceptor.js +0 -529
- package/mcp-server/lib/api-client.cjs +0 -13
- package/mcp-server/lib/cache-wrapper.cjs +0 -383
- package/mcp-server/lib/error-envelope.js +0 -138
- package/mcp-server/lib/executor.ts +0 -499
- package/mcp-server/lib/index.ts +0 -29
- package/mcp-server/lib/logger.cjs +0 -30
- package/mcp-server/lib/rate-limiter.js +0 -166
- package/mcp-server/lib/sandbox.test.ts +0 -519
- package/mcp-server/lib/sandbox.ts +0 -395
- package/mcp-server/lib/types.ts +0 -267
- package/mcp-server/logger.js +0 -173
- package/mcp-server/manifest.json +0 -473
- package/mcp-server/mdc-generator.js +0 -298
- package/mcp-server/premium-tools.js +0 -1275
- package/mcp-server/proof-tools.js +0 -571
- package/mcp-server/registry/tool-registry.js +0 -586
- package/mcp-server/registry/tools.json +0 -619
- package/mcp-server/registry.test.ts +0 -340
- package/mcp-server/test-mcp.js +0 -108
- package/mcp-server/test-tools.js +0 -36
- package/mcp-server/tests/tier-gating.test.js +0 -297
- package/mcp-server/tier-auth.js +0 -767
- package/mcp-server/tools/index.js +0 -72
- package/mcp-server/tools-reorganized.ts +0 -244
- package/mcp-server/tools-v3.js +0 -1004
- package/mcp-server/truth-context.js +0 -622
- package/mcp-server/truth-firewall-tools.js +0 -2183
- package/mcp-server/vibecheck-2.0-tools.js +0 -761
- package/mcp-server/vibecheck-mcp-server-3.2.0.tgz +0 -0
- package/mcp-server/vibecheck-tools.js +0 -1075
|
@@ -0,0 +1,1031 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt Builder Service for MCP Server
|
|
3
|
+
* Provides intelligent prompt templates and building functionality
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import * as fs from 'fs';
|
|
7
|
+
import * as path from 'path';
|
|
8
|
+
import type {
|
|
9
|
+
PromptTemplate,
|
|
10
|
+
PromptCategory,
|
|
11
|
+
ContextQuestion,
|
|
12
|
+
WorkspaceContext,
|
|
13
|
+
BuiltPrompt,
|
|
14
|
+
PromptQuality,
|
|
15
|
+
SmartSuggestion,
|
|
16
|
+
} from '../types.js';
|
|
17
|
+
|
|
18
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
19
|
+
// Smart Variables
|
|
20
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
21
|
+
|
|
22
|
+
const SMART_VARIABLES: Record<string, (ctx: WorkspaceContext) => string> = {
|
|
23
|
+
'{{PROJECT_NAME}}': ctx => ctx.projectName,
|
|
24
|
+
'{{FRAMEWORK}}': ctx => ctx.framework,
|
|
25
|
+
'{{LANGUAGE}}': ctx => ctx.language === 'typescript' ? 'TypeScript' : 'JavaScript',
|
|
26
|
+
'{{PACKAGE_MANAGER}}': ctx => ctx.packageManager,
|
|
27
|
+
'{{DATABASE}}': ctx => {
|
|
28
|
+
if (ctx.hasSupabase) return 'Supabase';
|
|
29
|
+
if (ctx.hasPrisma && ctx.hasPostgres) return 'PostgreSQL with Prisma';
|
|
30
|
+
if (ctx.hasDrizzle) return 'Drizzle ORM';
|
|
31
|
+
if (ctx.hasMongoDB) return 'MongoDB';
|
|
32
|
+
if (ctx.hasFirebase) return 'Firebase';
|
|
33
|
+
return 'PostgreSQL';
|
|
34
|
+
},
|
|
35
|
+
'{{AUTH_LIBRARY}}': ctx => {
|
|
36
|
+
if (ctx.hasClerk) return 'Clerk';
|
|
37
|
+
if (ctx.hasNextAuth || ctx.hasAuthJs) return 'NextAuth.js / Auth.js';
|
|
38
|
+
if (ctx.hasSupabase) return 'Supabase Auth';
|
|
39
|
+
if (ctx.hasFirebase) return 'Firebase Auth';
|
|
40
|
+
return 'NextAuth.js';
|
|
41
|
+
},
|
|
42
|
+
'{{UI_LIBRARY}}': ctx => {
|
|
43
|
+
if (ctx.hasShadcn) return 'shadcn/ui';
|
|
44
|
+
if (ctx.hasRadix) return 'Radix UI';
|
|
45
|
+
if (ctx.hasTailwind) return 'Tailwind CSS';
|
|
46
|
+
return 'Tailwind CSS';
|
|
47
|
+
},
|
|
48
|
+
'{{TEST_FRAMEWORK}}': ctx => ctx.testFramework || 'Vitest',
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
52
|
+
// Prompt Templates (Subset for MCP - Full set available)
|
|
53
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
54
|
+
|
|
55
|
+
const PROMPT_TEMPLATES: PromptTemplate[] = [
|
|
56
|
+
// Authentication
|
|
57
|
+
{
|
|
58
|
+
id: 'auth-oauth',
|
|
59
|
+
name: 'OAuth Login (Google, GitHub, etc.)',
|
|
60
|
+
category: 'authentication',
|
|
61
|
+
description: 'Social login with multiple OAuth providers',
|
|
62
|
+
icon: '🔐',
|
|
63
|
+
keywords: ['login', 'signin', 'oauth', 'google', 'github', 'auth', 'authentication', 'social login'],
|
|
64
|
+
popularity: 100,
|
|
65
|
+
contextQuestions: [
|
|
66
|
+
{
|
|
67
|
+
id: 'providers',
|
|
68
|
+
label: 'OAuth Providers',
|
|
69
|
+
placeholder: 'Select providers to integrate',
|
|
70
|
+
type: 'multiselect',
|
|
71
|
+
options: [
|
|
72
|
+
{ label: 'Google', value: 'google', default: true },
|
|
73
|
+
{ label: 'GitHub', value: 'github', default: true },
|
|
74
|
+
{ label: 'Discord', value: 'discord' },
|
|
75
|
+
{ label: 'Apple', value: 'apple' },
|
|
76
|
+
],
|
|
77
|
+
required: true,
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
id: 'authLibrary',
|
|
81
|
+
label: 'Auth Library',
|
|
82
|
+
placeholder: 'Select authentication library',
|
|
83
|
+
type: 'select',
|
|
84
|
+
options: [
|
|
85
|
+
{ label: 'NextAuth.js / Auth.js', value: 'nextauth', default: true },
|
|
86
|
+
{ label: 'Clerk', value: 'clerk' },
|
|
87
|
+
{ label: 'Supabase Auth', value: 'supabase' },
|
|
88
|
+
],
|
|
89
|
+
required: true,
|
|
90
|
+
},
|
|
91
|
+
],
|
|
92
|
+
outputSections: ['Plan', 'Files', 'Code', 'Env Variables', 'Provider Setup', 'Test Checklist'],
|
|
93
|
+
template: `You are a senior full-stack engineer. IMPLEMENT a production-ready authentication system with **{{providers}}** OAuth.
|
|
94
|
+
|
|
95
|
+
## Project Context
|
|
96
|
+
- **Framework**: {{frontend}}
|
|
97
|
+
- **Backend**: {{backend}}
|
|
98
|
+
- **Database**: {{database}}
|
|
99
|
+
- **Auth Library**: {{authLibrary}}
|
|
100
|
+
- **TypeScript**: {{typescript}}
|
|
101
|
+
|
|
102
|
+
## Requirements
|
|
103
|
+
1. **Login Page** at \`/login\` with provider buttons
|
|
104
|
+
2. **Auth Callbacks** for each provider
|
|
105
|
+
3. **Session Management** with secure cookies
|
|
106
|
+
4. **Protected Routes** middleware
|
|
107
|
+
5. **Sign Out** functionality
|
|
108
|
+
|
|
109
|
+
## Output Format
|
|
110
|
+
A) Plan (10 bullets max)
|
|
111
|
+
B) Files to create
|
|
112
|
+
C) Complete code for each file
|
|
113
|
+
D) Environment variables
|
|
114
|
+
E) Provider setup guide
|
|
115
|
+
F) Testing checklist`,
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
// API Development
|
|
119
|
+
{
|
|
120
|
+
id: 'api-rest-crud',
|
|
121
|
+
name: 'REST API with CRUD',
|
|
122
|
+
category: 'api',
|
|
123
|
+
description: 'Full CRUD API with validation and error handling',
|
|
124
|
+
icon: '🔌',
|
|
125
|
+
keywords: ['api', 'rest', 'crud', 'endpoint', 'route', 'backend'],
|
|
126
|
+
popularity: 90,
|
|
127
|
+
contextQuestions: [
|
|
128
|
+
{
|
|
129
|
+
id: 'resource',
|
|
130
|
+
label: 'Resource Name',
|
|
131
|
+
placeholder: 'e.g., users, products, posts',
|
|
132
|
+
type: 'text',
|
|
133
|
+
required: true,
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
id: 'operations',
|
|
137
|
+
label: 'Operations',
|
|
138
|
+
placeholder: 'Select CRUD operations',
|
|
139
|
+
type: 'multiselect',
|
|
140
|
+
options: [
|
|
141
|
+
{ label: 'Create (POST)', value: 'create', default: true },
|
|
142
|
+
{ label: 'Read One (GET /:id)', value: 'read-one', default: true },
|
|
143
|
+
{ label: 'Read All (GET /)', value: 'read-all', default: true },
|
|
144
|
+
{ label: 'Update (PATCH)', value: 'update', default: true },
|
|
145
|
+
{ label: 'Delete (DELETE)', value: 'delete', default: true },
|
|
146
|
+
{ label: 'Pagination', value: 'pagination', default: true },
|
|
147
|
+
],
|
|
148
|
+
required: true,
|
|
149
|
+
},
|
|
150
|
+
],
|
|
151
|
+
outputSections: ['Plan', 'Schema', 'Routes', 'Validation', 'Code', 'Tests'],
|
|
152
|
+
template: `You are a senior backend engineer. IMPLEMENT a production-ready REST API for **{{resource}}**.
|
|
153
|
+
|
|
154
|
+
## Context
|
|
155
|
+
- **Backend**: {{backend}}
|
|
156
|
+
- **Database**: {{database}}
|
|
157
|
+
- **Validation**: Zod
|
|
158
|
+
- **TypeScript**: {{typescript}}
|
|
159
|
+
|
|
160
|
+
## Endpoints
|
|
161
|
+
POST /api/{{resource}} # Create
|
|
162
|
+
GET /api/{{resource}} # List (paginated)
|
|
163
|
+
GET /api/{{resource}}/:id # Get by ID
|
|
164
|
+
PATCH /api/{{resource}}/:id # Update
|
|
165
|
+
DELETE /api/{{resource}}/:id # Delete
|
|
166
|
+
|
|
167
|
+
## Output Format
|
|
168
|
+
A) Plan (10 bullets)
|
|
169
|
+
B) Database schema
|
|
170
|
+
C) Zod validation schemas
|
|
171
|
+
D) Route handlers (complete code)
|
|
172
|
+
E) Error handling
|
|
173
|
+
F) Test examples`,
|
|
174
|
+
},
|
|
175
|
+
|
|
176
|
+
// Frontend Component
|
|
177
|
+
{
|
|
178
|
+
id: 'frontend-component',
|
|
179
|
+
name: 'React Component',
|
|
180
|
+
category: 'frontend',
|
|
181
|
+
description: 'Production-ready React component with variants',
|
|
182
|
+
icon: '⚛️',
|
|
183
|
+
keywords: ['react', 'component', 'ui', 'frontend', 'tsx'],
|
|
184
|
+
popularity: 95,
|
|
185
|
+
contextQuestions: [
|
|
186
|
+
{
|
|
187
|
+
id: 'componentName',
|
|
188
|
+
label: 'Component Name',
|
|
189
|
+
placeholder: 'e.g., DataTable, Modal, Sidebar',
|
|
190
|
+
type: 'text',
|
|
191
|
+
required: true,
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
id: 'componentType',
|
|
195
|
+
label: 'Component Type',
|
|
196
|
+
placeholder: 'Select component type',
|
|
197
|
+
type: 'select',
|
|
198
|
+
options: [
|
|
199
|
+
{ label: 'UI Component', value: 'ui', default: true },
|
|
200
|
+
{ label: 'Layout', value: 'layout' },
|
|
201
|
+
{ label: 'Form', value: 'form' },
|
|
202
|
+
{ label: 'Data Display', value: 'data' },
|
|
203
|
+
],
|
|
204
|
+
required: true,
|
|
205
|
+
},
|
|
206
|
+
],
|
|
207
|
+
outputSections: ['Plan', 'API Design', 'Code', 'Variants', 'Usage', 'Tests'],
|
|
208
|
+
template: `You are a senior frontend engineer. IMPLEMENT a production-ready React component: **{{componentName}}**.
|
|
209
|
+
|
|
210
|
+
## Context
|
|
211
|
+
- **Framework**: {{frontend}}
|
|
212
|
+
- **Styling**: {{styling}}
|
|
213
|
+
- **TypeScript**: {{typescript}}
|
|
214
|
+
|
|
215
|
+
## Requirements
|
|
216
|
+
1. **TypeScript** with comprehensive props interface
|
|
217
|
+
2. **Accessible** with proper ARIA attributes
|
|
218
|
+
3. **Composable** using forwardRef
|
|
219
|
+
4. **Dark mode** support
|
|
220
|
+
|
|
221
|
+
## Output Format
|
|
222
|
+
A) Props interface with JSDoc
|
|
223
|
+
B) Component implementation
|
|
224
|
+
C) Variant definitions
|
|
225
|
+
D) Usage examples
|
|
226
|
+
E) Tests`,
|
|
227
|
+
},
|
|
228
|
+
|
|
229
|
+
// Debugging
|
|
230
|
+
{
|
|
231
|
+
id: 'debug-error',
|
|
232
|
+
name: 'Debug Error',
|
|
233
|
+
category: 'debugging',
|
|
234
|
+
description: 'Systematic error diagnosis and fix',
|
|
235
|
+
icon: '🐛',
|
|
236
|
+
keywords: ['debug', 'error', 'bug', 'fix', 'troubleshoot'],
|
|
237
|
+
popularity: 90,
|
|
238
|
+
contextQuestions: [
|
|
239
|
+
{
|
|
240
|
+
id: 'errorMessage',
|
|
241
|
+
label: 'Error Message',
|
|
242
|
+
placeholder: 'Paste the error message or stack trace',
|
|
243
|
+
type: 'text',
|
|
244
|
+
required: true,
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
id: 'context',
|
|
248
|
+
label: 'When it occurs',
|
|
249
|
+
placeholder: 'Describe when the error happens',
|
|
250
|
+
type: 'text',
|
|
251
|
+
required: true,
|
|
252
|
+
},
|
|
253
|
+
],
|
|
254
|
+
outputSections: ['Analysis', 'Root Cause', 'Solution', 'Prevention', 'Testing'],
|
|
255
|
+
template: `You are a senior debugging specialist. DIAGNOSE and FIX this error:
|
|
256
|
+
|
|
257
|
+
## Error
|
|
258
|
+
\`\`\`
|
|
259
|
+
{{errorMessage}}
|
|
260
|
+
\`\`\`
|
|
261
|
+
|
|
262
|
+
## Context
|
|
263
|
+
- **When**: {{context}}
|
|
264
|
+
- **Stack**: {{frontend}} + {{backend}} + {{database}}
|
|
265
|
+
|
|
266
|
+
## Your Task
|
|
267
|
+
1. **Analyze** the error message and trace
|
|
268
|
+
2. **Identify** the root cause
|
|
269
|
+
3. **Provide** the exact fix (code, not explanation)
|
|
270
|
+
4. **Explain** why this happened
|
|
271
|
+
5. **Prevent** similar issues
|
|
272
|
+
|
|
273
|
+
## Output Format
|
|
274
|
+
A) Error Analysis
|
|
275
|
+
B) Root Cause
|
|
276
|
+
C) Solution (exact code fix)
|
|
277
|
+
D) Prevention strategy
|
|
278
|
+
E) Test to verify fix`,
|
|
279
|
+
},
|
|
280
|
+
|
|
281
|
+
// Testing
|
|
282
|
+
{
|
|
283
|
+
id: 'testing-unit',
|
|
284
|
+
name: 'Unit Tests',
|
|
285
|
+
category: 'testing',
|
|
286
|
+
description: 'Comprehensive unit tests with edge cases',
|
|
287
|
+
icon: '🧪',
|
|
288
|
+
keywords: ['test', 'unit', 'jest', 'vitest', 'testing'],
|
|
289
|
+
popularity: 80,
|
|
290
|
+
contextQuestions: [
|
|
291
|
+
{
|
|
292
|
+
id: 'target',
|
|
293
|
+
label: 'Code to Test',
|
|
294
|
+
placeholder: 'Describe the function/component',
|
|
295
|
+
type: 'text',
|
|
296
|
+
required: true,
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
id: 'framework',
|
|
300
|
+
label: 'Test Framework',
|
|
301
|
+
placeholder: 'Select framework',
|
|
302
|
+
type: 'select',
|
|
303
|
+
options: [
|
|
304
|
+
{ label: 'Vitest', value: 'vitest', default: true },
|
|
305
|
+
{ label: 'Jest', value: 'jest' },
|
|
306
|
+
],
|
|
307
|
+
required: true,
|
|
308
|
+
},
|
|
309
|
+
],
|
|
310
|
+
outputSections: ['Test Plan', 'Tests', 'Mocks', 'Coverage'],
|
|
311
|
+
template: `You are a senior QA engineer. WRITE comprehensive unit tests for: **{{target}}**.
|
|
312
|
+
|
|
313
|
+
## Context
|
|
314
|
+
- **Framework**: {{framework}}
|
|
315
|
+
|
|
316
|
+
## Test Categories
|
|
317
|
+
1. **Happy Path** - Normal expected flows
|
|
318
|
+
2. **Edge Cases** - Empty, null, max values
|
|
319
|
+
3. **Error Cases** - Invalid inputs, failures
|
|
320
|
+
|
|
321
|
+
## Requirements
|
|
322
|
+
1. **AAA pattern**: Arrange, Act, Assert
|
|
323
|
+
2. **Isolated tests** - Each test independent
|
|
324
|
+
3. **80%+ coverage** target
|
|
325
|
+
|
|
326
|
+
## Output Format
|
|
327
|
+
A) Test plan
|
|
328
|
+
B) Complete test files
|
|
329
|
+
C) Mock implementations
|
|
330
|
+
D) Coverage notes`,
|
|
331
|
+
},
|
|
332
|
+
|
|
333
|
+
// Database
|
|
334
|
+
{
|
|
335
|
+
id: 'database-schema',
|
|
336
|
+
name: 'Database Schema Design',
|
|
337
|
+
category: 'database',
|
|
338
|
+
description: 'Complete schema with relationships and indexes',
|
|
339
|
+
icon: '🗄️',
|
|
340
|
+
keywords: ['database', 'schema', 'model', 'table', 'migration', 'prisma'],
|
|
341
|
+
popularity: 85,
|
|
342
|
+
contextQuestions: [
|
|
343
|
+
{
|
|
344
|
+
id: 'domain',
|
|
345
|
+
label: 'Domain/Feature',
|
|
346
|
+
placeholder: 'e.g., e-commerce, blog, SaaS',
|
|
347
|
+
type: 'text',
|
|
348
|
+
required: true,
|
|
349
|
+
},
|
|
350
|
+
{
|
|
351
|
+
id: 'entities',
|
|
352
|
+
label: 'Main Entities',
|
|
353
|
+
placeholder: 'e.g., users, products, orders',
|
|
354
|
+
type: 'text',
|
|
355
|
+
required: true,
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
id: 'orm',
|
|
359
|
+
label: 'ORM',
|
|
360
|
+
placeholder: 'Select ORM',
|
|
361
|
+
type: 'select',
|
|
362
|
+
options: [
|
|
363
|
+
{ label: 'Prisma', value: 'prisma', default: true },
|
|
364
|
+
{ label: 'Drizzle ORM', value: 'drizzle' },
|
|
365
|
+
],
|
|
366
|
+
required: true,
|
|
367
|
+
},
|
|
368
|
+
],
|
|
369
|
+
outputSections: ['Plan', 'ERD', 'Schema', 'Migrations', 'Seeds', 'Queries'],
|
|
370
|
+
template: `You are a senior database architect. DESIGN and IMPLEMENT a schema for **{{domain}}**.
|
|
371
|
+
|
|
372
|
+
## Context
|
|
373
|
+
- **Database**: {{database}}
|
|
374
|
+
- **ORM**: {{orm}}
|
|
375
|
+
- **Entities**: {{entities}}
|
|
376
|
+
|
|
377
|
+
## Requirements
|
|
378
|
+
1. **Normalized** (3NF minimum)
|
|
379
|
+
2. **Proper relationships** with foreign keys
|
|
380
|
+
3. **Strategic indexes** for common queries
|
|
381
|
+
|
|
382
|
+
## Output Format
|
|
383
|
+
A) Plan with design decisions
|
|
384
|
+
B) ERD diagram (Mermaid)
|
|
385
|
+
C) Complete schema file
|
|
386
|
+
D) Migration files
|
|
387
|
+
E) Seed data
|
|
388
|
+
F) Example queries`,
|
|
389
|
+
},
|
|
390
|
+
|
|
391
|
+
// General Feature
|
|
392
|
+
{
|
|
393
|
+
id: 'general-feature',
|
|
394
|
+
name: 'Implement Feature',
|
|
395
|
+
category: 'general',
|
|
396
|
+
description: 'Build any feature with best practices',
|
|
397
|
+
icon: '✨',
|
|
398
|
+
keywords: ['feature', 'implement', 'build', 'create', 'add'],
|
|
399
|
+
popularity: 100,
|
|
400
|
+
contextQuestions: [
|
|
401
|
+
{
|
|
402
|
+
id: 'feature',
|
|
403
|
+
label: 'Feature Description',
|
|
404
|
+
placeholder: 'Describe what you want to build',
|
|
405
|
+
type: 'text',
|
|
406
|
+
required: true,
|
|
407
|
+
},
|
|
408
|
+
{
|
|
409
|
+
id: 'acceptance',
|
|
410
|
+
label: 'Acceptance Criteria',
|
|
411
|
+
placeholder: 'What defines "done"?',
|
|
412
|
+
type: 'text',
|
|
413
|
+
required: false,
|
|
414
|
+
},
|
|
415
|
+
],
|
|
416
|
+
outputSections: ['Plan', 'Files', 'Code', 'Tests', 'Documentation'],
|
|
417
|
+
template: `You are a senior full-stack engineer. IMPLEMENT: **{{feature}}**.
|
|
418
|
+
|
|
419
|
+
## Context
|
|
420
|
+
- **Frontend**: {{frontend}}
|
|
421
|
+
- **Backend**: {{backend}}
|
|
422
|
+
- **Database**: {{database}}
|
|
423
|
+
- **TypeScript**: {{typescript}}
|
|
424
|
+
|
|
425
|
+
{{#if acceptance}}
|
|
426
|
+
## Acceptance Criteria
|
|
427
|
+
{{acceptance}}
|
|
428
|
+
{{/if}}
|
|
429
|
+
|
|
430
|
+
## Requirements
|
|
431
|
+
1. **Production-ready** code
|
|
432
|
+
2. **Type-safe** with TypeScript
|
|
433
|
+
3. **Error handling** for all edge cases
|
|
434
|
+
4. **File-by-file** implementation
|
|
435
|
+
|
|
436
|
+
## Output Format
|
|
437
|
+
A) Plan (10 bullets max)
|
|
438
|
+
B) Files to create
|
|
439
|
+
C) Complete code for each file
|
|
440
|
+
D) Tests
|
|
441
|
+
E) Usage example`,
|
|
442
|
+
},
|
|
443
|
+
|
|
444
|
+
// AI Integration
|
|
445
|
+
{
|
|
446
|
+
id: 'ai-integration',
|
|
447
|
+
name: 'AI Integration',
|
|
448
|
+
category: 'ai-ml',
|
|
449
|
+
description: 'Integrate OpenAI, Anthropic, or other AI APIs',
|
|
450
|
+
icon: '🤖',
|
|
451
|
+
keywords: ['ai', 'openai', 'gpt', 'claude', 'anthropic', 'llm'],
|
|
452
|
+
popularity: 85,
|
|
453
|
+
isNew: true,
|
|
454
|
+
contextQuestions: [
|
|
455
|
+
{
|
|
456
|
+
id: 'provider',
|
|
457
|
+
label: 'AI Provider',
|
|
458
|
+
placeholder: 'Select provider',
|
|
459
|
+
type: 'select',
|
|
460
|
+
options: [
|
|
461
|
+
{ label: 'OpenAI (GPT-4)', value: 'openai', default: true },
|
|
462
|
+
{ label: 'Anthropic (Claude)', value: 'anthropic' },
|
|
463
|
+
{ label: 'Vercel AI SDK', value: 'vercel-ai' },
|
|
464
|
+
],
|
|
465
|
+
required: true,
|
|
466
|
+
},
|
|
467
|
+
{
|
|
468
|
+
id: 'useCase',
|
|
469
|
+
label: 'Use Case',
|
|
470
|
+
placeholder: 'Select use case',
|
|
471
|
+
type: 'select',
|
|
472
|
+
options: [
|
|
473
|
+
{ label: 'Chat interface', value: 'chat', default: true },
|
|
474
|
+
{ label: 'Text generation', value: 'generation' },
|
|
475
|
+
{ label: 'Embeddings/RAG', value: 'embeddings' },
|
|
476
|
+
],
|
|
477
|
+
required: true,
|
|
478
|
+
},
|
|
479
|
+
],
|
|
480
|
+
outputSections: ['Plan', 'API Setup', 'Client', 'UI', 'Code', 'Error Handling'],
|
|
481
|
+
template: `You are a senior AI engineer. IMPLEMENT **{{useCase}}** with **{{provider}}**.
|
|
482
|
+
|
|
483
|
+
## Context
|
|
484
|
+
- **Framework**: {{frontend}}
|
|
485
|
+
- **Provider**: {{provider}}
|
|
486
|
+
|
|
487
|
+
## Requirements
|
|
488
|
+
1. **Type-safe** API integration
|
|
489
|
+
2. **Streaming** support (if chat)
|
|
490
|
+
3. **Error handling** with retries
|
|
491
|
+
4. **Secure** API key handling
|
|
492
|
+
|
|
493
|
+
## Output Format
|
|
494
|
+
A) Plan
|
|
495
|
+
B) API client setup
|
|
496
|
+
C) React hooks/components
|
|
497
|
+
D) UI implementation
|
|
498
|
+
E) Error handling
|
|
499
|
+
F) Usage examples`,
|
|
500
|
+
},
|
|
501
|
+
|
|
502
|
+
// Deployment
|
|
503
|
+
{
|
|
504
|
+
id: 'deployment-docker',
|
|
505
|
+
name: 'Docker Setup',
|
|
506
|
+
category: 'deployment',
|
|
507
|
+
description: 'Optimized Docker for dev and production',
|
|
508
|
+
icon: '🐳',
|
|
509
|
+
keywords: ['docker', 'container', 'dockerfile', 'compose', 'deployment'],
|
|
510
|
+
popularity: 80,
|
|
511
|
+
contextQuestions: [
|
|
512
|
+
{
|
|
513
|
+
id: 'appType',
|
|
514
|
+
label: 'Application Type',
|
|
515
|
+
placeholder: 'Select app type',
|
|
516
|
+
type: 'select',
|
|
517
|
+
options: [
|
|
518
|
+
{ label: 'Next.js', value: 'nextjs', default: true },
|
|
519
|
+
{ label: 'Node.js', value: 'node' },
|
|
520
|
+
{ label: 'Python', value: 'python' },
|
|
521
|
+
],
|
|
522
|
+
required: true,
|
|
523
|
+
},
|
|
524
|
+
],
|
|
525
|
+
outputSections: ['Plan', 'Dockerfile', 'Compose Dev', 'Compose Prod', 'Scripts'],
|
|
526
|
+
template: `You are a senior DevOps engineer. CREATE Docker configuration for **{{appType}}**.
|
|
527
|
+
|
|
528
|
+
## Requirements
|
|
529
|
+
1. **Multi-stage build** for minimal production image
|
|
530
|
+
2. **Non-root user** in production
|
|
531
|
+
3. **.dockerignore** to exclude unnecessary files
|
|
532
|
+
4. **Health checks** for all services
|
|
533
|
+
|
|
534
|
+
## Output Format
|
|
535
|
+
A) Plan
|
|
536
|
+
B) Dockerfile (optimized)
|
|
537
|
+
C) docker-compose.yml (dev)
|
|
538
|
+
D) docker-compose.prod.yml
|
|
539
|
+
E) .dockerignore
|
|
540
|
+
F) Common commands`,
|
|
541
|
+
},
|
|
542
|
+
|
|
543
|
+
// Security
|
|
544
|
+
{
|
|
545
|
+
id: 'security-audit',
|
|
546
|
+
name: 'Security Audit',
|
|
547
|
+
category: 'security',
|
|
548
|
+
description: 'Comprehensive security review',
|
|
549
|
+
icon: '🛡️',
|
|
550
|
+
keywords: ['security', 'audit', 'vulnerability', 'penetration', 'secure'],
|
|
551
|
+
popularity: 75,
|
|
552
|
+
contextQuestions: [
|
|
553
|
+
{
|
|
554
|
+
id: 'scope',
|
|
555
|
+
label: 'Audit Scope',
|
|
556
|
+
placeholder: 'What to audit',
|
|
557
|
+
type: 'multiselect',
|
|
558
|
+
options: [
|
|
559
|
+
{ label: 'Authentication', value: 'auth', default: true },
|
|
560
|
+
{ label: 'Authorization', value: 'authz', default: true },
|
|
561
|
+
{ label: 'API Security', value: 'api', default: true },
|
|
562
|
+
{ label: 'Data Validation', value: 'validation' },
|
|
563
|
+
{ label: 'Dependencies', value: 'deps' },
|
|
564
|
+
],
|
|
565
|
+
required: true,
|
|
566
|
+
},
|
|
567
|
+
],
|
|
568
|
+
outputSections: ['Summary', 'Findings', 'Risk Matrix', 'Remediation', 'Checklist'],
|
|
569
|
+
template: `You are a senior security engineer. CONDUCT a security audit.
|
|
570
|
+
|
|
571
|
+
## Scope
|
|
572
|
+
{{scope}}
|
|
573
|
+
|
|
574
|
+
## Framework
|
|
575
|
+
- **Frontend**: {{frontend}}
|
|
576
|
+
- **Backend**: {{backend}}
|
|
577
|
+
- **Database**: {{database}}
|
|
578
|
+
|
|
579
|
+
## Audit Areas
|
|
580
|
+
1. Authentication mechanisms
|
|
581
|
+
2. Authorization controls
|
|
582
|
+
3. Input validation
|
|
583
|
+
4. Output encoding
|
|
584
|
+
5. Session management
|
|
585
|
+
6. Error handling
|
|
586
|
+
7. Dependency vulnerabilities
|
|
587
|
+
|
|
588
|
+
## Output Format
|
|
589
|
+
A) Executive summary
|
|
590
|
+
B) Detailed findings with severity
|
|
591
|
+
C) Risk matrix
|
|
592
|
+
D) Remediation steps (prioritized)
|
|
593
|
+
E) Security checklist`,
|
|
594
|
+
},
|
|
595
|
+
];
|
|
596
|
+
|
|
597
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
598
|
+
// Prompt Quality Analyzer
|
|
599
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
600
|
+
|
|
601
|
+
function analyzePromptQuality(prompt: string, template: PromptTemplate): PromptQuality {
|
|
602
|
+
const suggestions: string[] = [];
|
|
603
|
+
|
|
604
|
+
// Completeness
|
|
605
|
+
let completeness = 0;
|
|
606
|
+
const expectedSections = template.outputSections.length;
|
|
607
|
+
const foundSections = template.outputSections.filter(s =>
|
|
608
|
+
prompt.toLowerCase().includes(s.toLowerCase())
|
|
609
|
+
).length;
|
|
610
|
+
completeness = Math.round((foundSections / expectedSections) * 100);
|
|
611
|
+
|
|
612
|
+
// Specificity
|
|
613
|
+
let specificity = 50;
|
|
614
|
+
if (prompt.includes('```')) specificity += 15;
|
|
615
|
+
if (prompt.includes('.env')) specificity += 10;
|
|
616
|
+
if (prompt.match(/\d+/)) specificity += 10;
|
|
617
|
+
if (prompt.includes('TypeScript')) specificity += 10;
|
|
618
|
+
specificity = Math.min(specificity, 100);
|
|
619
|
+
|
|
620
|
+
// Clarity
|
|
621
|
+
let clarity = 70;
|
|
622
|
+
const wordCount = prompt.split(/\s+/).length;
|
|
623
|
+
if (wordCount > 500) clarity += 10;
|
|
624
|
+
if (wordCount > 1000) clarity += 10;
|
|
625
|
+
if (prompt.includes('## ')) clarity += 10;
|
|
626
|
+
clarity = Math.min(clarity, 100);
|
|
627
|
+
|
|
628
|
+
const score = Math.round((completeness + specificity + clarity) / 3);
|
|
629
|
+
|
|
630
|
+
if (completeness < 80) {
|
|
631
|
+
suggestions.push('Add more output sections for comprehensive results');
|
|
632
|
+
}
|
|
633
|
+
if (specificity < 70) {
|
|
634
|
+
suggestions.push('Include more specific requirements (versions, exact paths)');
|
|
635
|
+
}
|
|
636
|
+
if (clarity < 80) {
|
|
637
|
+
suggestions.push('Consider adding code examples or format specifications');
|
|
638
|
+
}
|
|
639
|
+
if (!prompt.includes('TypeScript')) {
|
|
640
|
+
suggestions.push('Specify TypeScript requirement for type safety');
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
return { score, completeness, specificity, clarity, suggestions };
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
647
|
+
// Service Implementation
|
|
648
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
649
|
+
|
|
650
|
+
export class PromptBuilderService {
|
|
651
|
+
private workspacePath: string;
|
|
652
|
+
private cachedContext: WorkspaceContext | null = null;
|
|
653
|
+
|
|
654
|
+
constructor(workspacePath?: string) {
|
|
655
|
+
this.workspacePath = workspacePath || process.cwd();
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
/**
|
|
659
|
+
* Get all templates sorted by popularity
|
|
660
|
+
*/
|
|
661
|
+
getTemplates(): PromptTemplate[] {
|
|
662
|
+
return PROMPT_TEMPLATES.sort((a, b) => (b.popularity || 0) - (a.popularity || 0));
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
/**
|
|
666
|
+
* Get templates by category
|
|
667
|
+
*/
|
|
668
|
+
getTemplatesByCategory(category: PromptCategory): PromptTemplate[] {
|
|
669
|
+
return PROMPT_TEMPLATES.filter(t => t.category === category);
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
/**
|
|
673
|
+
* Get all categories with counts
|
|
674
|
+
*/
|
|
675
|
+
getCategories(): { category: PromptCategory; count: number; icon: string }[] {
|
|
676
|
+
const categoryMeta: Record<PromptCategory, { icon: string; order: number }> = {
|
|
677
|
+
authentication: { icon: '🔐', order: 1 },
|
|
678
|
+
api: { icon: '🔌', order: 2 },
|
|
679
|
+
frontend: { icon: '⚛️', order: 3 },
|
|
680
|
+
database: { icon: '🗄️', order: 4 },
|
|
681
|
+
testing: { icon: '🧪', order: 5 },
|
|
682
|
+
deployment: { icon: '🚀', order: 6 },
|
|
683
|
+
debugging: { icon: '🐛', order: 7 },
|
|
684
|
+
performance: { icon: '⚡', order: 8 },
|
|
685
|
+
refactoring: { icon: '♻️', order: 9 },
|
|
686
|
+
security: { icon: '🛡️', order: 10 },
|
|
687
|
+
'ai-ml': { icon: '🤖', order: 11 },
|
|
688
|
+
mobile: { icon: '📱', order: 12 },
|
|
689
|
+
backend: { icon: '⚙️', order: 13 },
|
|
690
|
+
documentation: { icon: '📚', order: 14 },
|
|
691
|
+
general: { icon: '✨', order: 15 },
|
|
692
|
+
};
|
|
693
|
+
|
|
694
|
+
const counts = new Map<PromptCategory, number>();
|
|
695
|
+
for (const template of PROMPT_TEMPLATES) {
|
|
696
|
+
counts.set(template.category, (counts.get(template.category) || 0) + 1);
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
return Array.from(counts.entries())
|
|
700
|
+
.map(([category, count]) => ({
|
|
701
|
+
category,
|
|
702
|
+
count,
|
|
703
|
+
icon: categoryMeta[category]?.icon || '📁',
|
|
704
|
+
}))
|
|
705
|
+
.sort((a, b) => (categoryMeta[a.category]?.order || 99) - (categoryMeta[b.category]?.order || 99));
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
/**
|
|
709
|
+
* Get a specific template by ID
|
|
710
|
+
*/
|
|
711
|
+
getTemplate(id: string): PromptTemplate | undefined {
|
|
712
|
+
return PROMPT_TEMPLATES.find(t => t.id === id);
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
/**
|
|
716
|
+
* Detect best template from user input
|
|
717
|
+
*/
|
|
718
|
+
detectTemplate(input: string): PromptTemplate | null {
|
|
719
|
+
const normalizedInput = input.toLowerCase();
|
|
720
|
+
let bestMatch: PromptTemplate | null = null;
|
|
721
|
+
let bestScore = 0;
|
|
722
|
+
|
|
723
|
+
for (const template of PROMPT_TEMPLATES) {
|
|
724
|
+
let score = 0;
|
|
725
|
+
|
|
726
|
+
for (const keyword of template.keywords) {
|
|
727
|
+
if (normalizedInput.includes(keyword)) {
|
|
728
|
+
score += keyword.length * 2;
|
|
729
|
+
if (new RegExp(`\\b${keyword}\\b`).test(normalizedInput)) {
|
|
730
|
+
score += 5;
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
score += (template.popularity || 0) / 20;
|
|
736
|
+
|
|
737
|
+
if (score > bestScore) {
|
|
738
|
+
bestScore = score;
|
|
739
|
+
bestMatch = template;
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
return bestScore > 8 ? bestMatch : null;
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
/**
|
|
747
|
+
* Detect workspace context from project files
|
|
748
|
+
*/
|
|
749
|
+
async detectWorkspaceContext(): Promise<WorkspaceContext> {
|
|
750
|
+
if (this.cachedContext) {
|
|
751
|
+
return this.cachedContext;
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
const context: WorkspaceContext = {
|
|
755
|
+
projectName: path.basename(this.workspacePath),
|
|
756
|
+
hasTypeScript: false,
|
|
757
|
+
hasNextJs: false,
|
|
758
|
+
hasReact: false,
|
|
759
|
+
hasVue: false,
|
|
760
|
+
hasSvelte: false,
|
|
761
|
+
hasAngular: false,
|
|
762
|
+
hasVite: false,
|
|
763
|
+
hasExpress: false,
|
|
764
|
+
hasFastify: false,
|
|
765
|
+
hasNestJs: false,
|
|
766
|
+
hasPrisma: false,
|
|
767
|
+
hasDrizzle: false,
|
|
768
|
+
hasMongoDB: false,
|
|
769
|
+
hasPostgres: false,
|
|
770
|
+
hasSupabase: false,
|
|
771
|
+
hasFirebase: false,
|
|
772
|
+
hasClerk: false,
|
|
773
|
+
hasNextAuth: false,
|
|
774
|
+
hasAuthJs: false,
|
|
775
|
+
hasTailwind: false,
|
|
776
|
+
hasShadcn: false,
|
|
777
|
+
hasRadix: false,
|
|
778
|
+
packageManager: 'npm',
|
|
779
|
+
framework: 'unknown',
|
|
780
|
+
language: 'javascript',
|
|
781
|
+
testFramework: null,
|
|
782
|
+
hasDocker: false,
|
|
783
|
+
hasGit: false,
|
|
784
|
+
hasTurbo: false,
|
|
785
|
+
isMonorepo: false,
|
|
786
|
+
};
|
|
787
|
+
|
|
788
|
+
// Check package.json
|
|
789
|
+
const packageJsonPath = path.join(this.workspacePath, 'package.json');
|
|
790
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
791
|
+
try {
|
|
792
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
|
793
|
+
const allDeps = { ...packageJson.dependencies, ...packageJson.devDependencies };
|
|
794
|
+
|
|
795
|
+
context.hasTypeScript = !!allDeps.typescript;
|
|
796
|
+
context.hasNextJs = !!allDeps.next;
|
|
797
|
+
context.hasReact = !!allDeps.react;
|
|
798
|
+
context.hasVue = !!allDeps.vue;
|
|
799
|
+
context.hasSvelte = !!allDeps.svelte;
|
|
800
|
+
context.hasAngular = !!allDeps['@angular/core'];
|
|
801
|
+
context.hasVite = !!allDeps.vite;
|
|
802
|
+
context.hasExpress = !!allDeps.express;
|
|
803
|
+
context.hasFastify = !!allDeps.fastify;
|
|
804
|
+
context.hasNestJs = !!allDeps['@nestjs/core'];
|
|
805
|
+
|
|
806
|
+
context.hasPrisma = !!allDeps['@prisma/client'] || !!allDeps.prisma;
|
|
807
|
+
context.hasDrizzle = !!allDeps['drizzle-orm'];
|
|
808
|
+
context.hasMongoDB = !!allDeps.mongoose || !!allDeps.mongodb;
|
|
809
|
+
context.hasPostgres = !!allDeps.pg || !!allDeps['@vercel/postgres'];
|
|
810
|
+
context.hasSupabase = !!allDeps['@supabase/supabase-js'];
|
|
811
|
+
context.hasFirebase = !!allDeps.firebase || !!allDeps['firebase-admin'];
|
|
812
|
+
|
|
813
|
+
context.hasClerk = !!allDeps['@clerk/nextjs'] || !!allDeps['@clerk/clerk-react'];
|
|
814
|
+
context.hasNextAuth = !!allDeps['next-auth'];
|
|
815
|
+
context.hasAuthJs = !!allDeps['@auth/core'];
|
|
816
|
+
|
|
817
|
+
context.hasTailwind = !!allDeps.tailwindcss;
|
|
818
|
+
context.hasShadcn = fs.existsSync(path.join(this.workspacePath, 'components.json'));
|
|
819
|
+
context.hasRadix = Object.keys(allDeps).some(k => k.startsWith('@radix-ui'));
|
|
820
|
+
|
|
821
|
+
context.hasTurbo = !!allDeps.turbo;
|
|
822
|
+
context.isMonorepo = fs.existsSync(path.join(this.workspacePath, 'pnpm-workspace.yaml')) ||
|
|
823
|
+
!!packageJson.workspaces;
|
|
824
|
+
|
|
825
|
+
context.language = context.hasTypeScript ? 'typescript' : 'javascript';
|
|
826
|
+
|
|
827
|
+
if (allDeps.vitest) context.testFramework = 'vitest';
|
|
828
|
+
else if (allDeps.jest) context.testFramework = 'jest';
|
|
829
|
+
else if (allDeps['@playwright/test']) context.testFramework = 'playwright';
|
|
830
|
+
|
|
831
|
+
if (context.hasNextJs) context.framework = 'Next.js';
|
|
832
|
+
else if (context.hasVite && context.hasReact) context.framework = 'React + Vite';
|
|
833
|
+
else if (context.hasNestJs) context.framework = 'NestJS';
|
|
834
|
+
else if (context.hasFastify) context.framework = 'Fastify';
|
|
835
|
+
else if (context.hasExpress) context.framework = 'Express';
|
|
836
|
+
else if (context.hasVue) context.framework = 'Vue';
|
|
837
|
+
else if (context.hasSvelte) context.framework = 'SvelteKit';
|
|
838
|
+
else if (context.hasReact) context.framework = 'React';
|
|
839
|
+
} catch {
|
|
840
|
+
// Ignore parse errors
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
// Package manager detection
|
|
845
|
+
if (fs.existsSync(path.join(this.workspacePath, 'bun.lockb'))) context.packageManager = 'bun';
|
|
846
|
+
else if (fs.existsSync(path.join(this.workspacePath, 'pnpm-lock.yaml'))) context.packageManager = 'pnpm';
|
|
847
|
+
else if (fs.existsSync(path.join(this.workspacePath, 'yarn.lock'))) context.packageManager = 'yarn';
|
|
848
|
+
|
|
849
|
+
context.hasDocker = fs.existsSync(path.join(this.workspacePath, 'Dockerfile')) ||
|
|
850
|
+
fs.existsSync(path.join(this.workspacePath, 'docker-compose.yml'));
|
|
851
|
+
context.hasGit = fs.existsSync(path.join(this.workspacePath, '.git'));
|
|
852
|
+
|
|
853
|
+
this.cachedContext = context;
|
|
854
|
+
return context;
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
/**
|
|
858
|
+
* Build a prompt from template and answers
|
|
859
|
+
*/
|
|
860
|
+
async buildPrompt(
|
|
861
|
+
templateId: string,
|
|
862
|
+
userInput: string,
|
|
863
|
+
answers: Record<string, string | string[]>
|
|
864
|
+
): Promise<BuiltPrompt | null> {
|
|
865
|
+
const template = this.getTemplate(templateId);
|
|
866
|
+
if (!template) {
|
|
867
|
+
return null;
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
const workspaceContext = await this.detectWorkspaceContext();
|
|
871
|
+
|
|
872
|
+
// Build context from workspace and answers
|
|
873
|
+
const context: Record<string, string> = {
|
|
874
|
+
appType: 'Web app',
|
|
875
|
+
frontend: this.detectFrontend(workspaceContext),
|
|
876
|
+
backend: this.detectBackend(workspaceContext),
|
|
877
|
+
database: this.detectDatabase(workspaceContext),
|
|
878
|
+
typescript: workspaceContext.hasTypeScript ? 'yes' : 'no',
|
|
879
|
+
language: workspaceContext.language,
|
|
880
|
+
styling: workspaceContext.hasTailwind ? 'Tailwind CSS' : 'CSS',
|
|
881
|
+
baseUrl: 'http://localhost:3000',
|
|
882
|
+
};
|
|
883
|
+
|
|
884
|
+
// Add answers
|
|
885
|
+
for (const [key, value] of Object.entries(answers)) {
|
|
886
|
+
if (Array.isArray(value)) {
|
|
887
|
+
context[key] = value.join(', ');
|
|
888
|
+
context[`${key}List`] = value.map((v, i) => `${i + 1}. ${v}`).join('\n');
|
|
889
|
+
} else {
|
|
890
|
+
context[key] = value;
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
// Process template
|
|
895
|
+
let expandedPrompt = template.template;
|
|
896
|
+
|
|
897
|
+
// Replace smart variables
|
|
898
|
+
for (const [variable, resolver] of Object.entries(SMART_VARIABLES)) {
|
|
899
|
+
expandedPrompt = expandedPrompt.replace(new RegExp(variable.replace(/[{}]/g, '\\$&'), 'g'), resolver(workspaceContext));
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
// Replace {{variable}}
|
|
903
|
+
expandedPrompt = expandedPrompt.replace(/\{\{(\w+)\}\}/g, (_, key) => {
|
|
904
|
+
return context[key] || `[${key}]`;
|
|
905
|
+
});
|
|
906
|
+
|
|
907
|
+
// Handle {{#if variable}} ... {{/if}}
|
|
908
|
+
expandedPrompt = expandedPrompt.replace(
|
|
909
|
+
/\{\{#if (\w+)\}\}([\s\S]*?)\{\{\/if\}\}/g,
|
|
910
|
+
(_, key, content) => context[key] ? content : ''
|
|
911
|
+
);
|
|
912
|
+
|
|
913
|
+
// Clean up whitespace
|
|
914
|
+
expandedPrompt = expandedPrompt.replace(/\n{3,}/g, '\n\n').trim();
|
|
915
|
+
|
|
916
|
+
// Analyze quality
|
|
917
|
+
const quality = analyzePromptQuality(expandedPrompt, template);
|
|
918
|
+
|
|
919
|
+
const builtPrompt: BuiltPrompt = {
|
|
920
|
+
id: this.generateId(),
|
|
921
|
+
timestamp: new Date().toISOString(),
|
|
922
|
+
originalInput: userInput,
|
|
923
|
+
category: template.category,
|
|
924
|
+
templateId: template.id,
|
|
925
|
+
expandedPrompt,
|
|
926
|
+
context,
|
|
927
|
+
quality,
|
|
928
|
+
};
|
|
929
|
+
|
|
930
|
+
return builtPrompt;
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
/**
|
|
934
|
+
* Get smart suggestions based on input
|
|
935
|
+
*/
|
|
936
|
+
getSmartSuggestions(input: string): SmartSuggestion[] {
|
|
937
|
+
const suggestions: SmartSuggestion[] = [];
|
|
938
|
+
const inputLower = input.toLowerCase();
|
|
939
|
+
|
|
940
|
+
// Detect template from input
|
|
941
|
+
const detectedTemplate = this.detectTemplate(input);
|
|
942
|
+
if (detectedTemplate) {
|
|
943
|
+
suggestions.push({
|
|
944
|
+
type: 'template',
|
|
945
|
+
title: detectedTemplate.name,
|
|
946
|
+
description: detectedTemplate.description,
|
|
947
|
+
action: 'selectTemplate',
|
|
948
|
+
data: detectedTemplate.id,
|
|
949
|
+
});
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
// Enhancement suggestions
|
|
953
|
+
if (input && input.length > 20) {
|
|
954
|
+
if (!inputLower.includes('typescript')) {
|
|
955
|
+
suggestions.push({
|
|
956
|
+
type: 'enhancement',
|
|
957
|
+
title: 'Add TypeScript',
|
|
958
|
+
description: 'Specify TypeScript for better type safety',
|
|
959
|
+
action: 'enhance',
|
|
960
|
+
data: 'typescript',
|
|
961
|
+
});
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
if (!inputLower.includes('test')) {
|
|
965
|
+
suggestions.push({
|
|
966
|
+
type: 'enhancement',
|
|
967
|
+
title: 'Include Tests',
|
|
968
|
+
description: 'Add unit or integration tests',
|
|
969
|
+
action: 'enhance',
|
|
970
|
+
data: 'tests',
|
|
971
|
+
});
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
if (!inputLower.includes('error')) {
|
|
975
|
+
suggestions.push({
|
|
976
|
+
type: 'enhancement',
|
|
977
|
+
title: 'Add Error Handling',
|
|
978
|
+
description: 'Include comprehensive error handling',
|
|
979
|
+
action: 'enhance',
|
|
980
|
+
data: 'error-handling',
|
|
981
|
+
});
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
return suggestions;
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
/**
|
|
989
|
+
* Set workspace path
|
|
990
|
+
*/
|
|
991
|
+
setWorkspacePath(workspacePath: string): void {
|
|
992
|
+
this.workspacePath = workspacePath;
|
|
993
|
+
this.cachedContext = null; // Clear cache
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
997
|
+
// Private Methods
|
|
998
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
999
|
+
|
|
1000
|
+
private detectFrontend(ctx: WorkspaceContext): string {
|
|
1001
|
+
if (ctx.hasNextJs) return 'Next.js App Router';
|
|
1002
|
+
if (ctx.hasVite && ctx.hasReact) return 'React + Vite';
|
|
1003
|
+
if (ctx.hasVue) return 'Vue 3';
|
|
1004
|
+
if (ctx.hasSvelte) return 'SvelteKit';
|
|
1005
|
+
if (ctx.hasReact) return 'React';
|
|
1006
|
+
return 'Next.js App Router';
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
private detectBackend(ctx: WorkspaceContext): string {
|
|
1010
|
+
if (ctx.hasNextJs) return 'Next.js API Routes';
|
|
1011
|
+
if (ctx.hasNestJs) return 'NestJS';
|
|
1012
|
+
if (ctx.hasFastify) return 'Fastify';
|
|
1013
|
+
if (ctx.hasExpress) return 'Express';
|
|
1014
|
+
return 'Next.js API Routes';
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
private detectDatabase(ctx: WorkspaceContext): string {
|
|
1018
|
+
if (ctx.hasSupabase) return 'Supabase (PostgreSQL)';
|
|
1019
|
+
if (ctx.hasFirebase) return 'Firebase';
|
|
1020
|
+
if (ctx.hasPrisma && ctx.hasPostgres) return 'PostgreSQL + Prisma';
|
|
1021
|
+
if (ctx.hasDrizzle) return 'Drizzle ORM';
|
|
1022
|
+
if (ctx.hasPrisma) return 'Prisma';
|
|
1023
|
+
if (ctx.hasMongoDB) return 'MongoDB';
|
|
1024
|
+
if (ctx.hasPostgres) return 'PostgreSQL';
|
|
1025
|
+
return 'PostgreSQL + Prisma';
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
private generateId(): string {
|
|
1029
|
+
return `pb_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
1030
|
+
}
|
|
1031
|
+
}
|