@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.
Files changed (88) hide show
  1. package/README.md +1 -1
  2. package/bin/runners/context/generators/cursor-enhanced.js +99 -13
  3. package/bin/runners/lib/unified-cli-output.js +16 -0
  4. package/bin/runners/runCI.js +353 -0
  5. package/bin/runners/runCheckpoint.js +2 -2
  6. package/mcp-server/.eslintrc.json +24 -0
  7. package/mcp-server/README.md +425 -135
  8. package/mcp-server/SPEC.md +583 -0
  9. package/mcp-server/configs/README.md +172 -0
  10. package/mcp-server/configs/claude-desktop-pro.json +31 -0
  11. package/mcp-server/configs/claude-desktop-with-workspace.json +25 -0
  12. package/mcp-server/configs/claude-desktop.json +19 -0
  13. package/mcp-server/configs/cursor-mcp.json +21 -0
  14. package/mcp-server/configs/windsurf-mcp.json +17 -0
  15. package/mcp-server/mcp-config.example.json +9 -0
  16. package/mcp-server/package.json +49 -34
  17. package/mcp-server/src/cli.ts +185 -0
  18. package/mcp-server/src/index.ts +85 -0
  19. package/mcp-server/src/server.ts +1933 -0
  20. package/mcp-server/src/services/cache-service.ts +466 -0
  21. package/mcp-server/src/services/cli-service.ts +345 -0
  22. package/mcp-server/src/services/context-manager.ts +717 -0
  23. package/mcp-server/src/services/firewall-service.ts +662 -0
  24. package/mcp-server/src/services/git-service.ts +671 -0
  25. package/mcp-server/src/services/index.ts +52 -0
  26. package/mcp-server/src/services/prompt-builder-service.ts +1031 -0
  27. package/mcp-server/src/services/session-service.ts +550 -0
  28. package/mcp-server/src/services/tier-service.ts +470 -0
  29. package/mcp-server/src/types.ts +351 -0
  30. package/mcp-server/tsconfig.json +16 -27
  31. package/package.json +6 -6
  32. package/mcp-server/.guardrail/audit/audit.log.jsonl +0 -2
  33. package/mcp-server/.specs/architecture.mdc +0 -90
  34. package/mcp-server/.specs/security.mdc +0 -30
  35. package/mcp-server/HARDENING_SUMMARY.md +0 -299
  36. package/mcp-server/agent-checkpoint.js +0 -364
  37. package/mcp-server/agent-firewall-interceptor.js +0 -500
  38. package/mcp-server/architect-tools.js +0 -707
  39. package/mcp-server/audit-mcp.js +0 -206
  40. package/mcp-server/authority-tools.js +0 -569
  41. package/mcp-server/codebase-architect-tools.js +0 -838
  42. package/mcp-server/conductor/conflict-resolver.js +0 -588
  43. package/mcp-server/conductor/execution-planner.js +0 -544
  44. package/mcp-server/conductor/index.js +0 -377
  45. package/mcp-server/conductor/lock-manager.js +0 -615
  46. package/mcp-server/conductor/request-queue.js +0 -550
  47. package/mcp-server/conductor/session-manager.js +0 -500
  48. package/mcp-server/conductor/tools.js +0 -510
  49. package/mcp-server/consolidated-tools.js +0 -1170
  50. package/mcp-server/deprecation-middleware.js +0 -282
  51. package/mcp-server/handlers/index.ts +0 -15
  52. package/mcp-server/handlers/tool-handler.ts +0 -593
  53. package/mcp-server/hygiene-tools.js +0 -428
  54. package/mcp-server/index-v1.js +0 -698
  55. package/mcp-server/index.js +0 -2940
  56. package/mcp-server/intelligence-tools.js +0 -664
  57. package/mcp-server/intent-drift-tools.js +0 -873
  58. package/mcp-server/intent-firewall-interceptor.js +0 -529
  59. package/mcp-server/lib/api-client.cjs +0 -13
  60. package/mcp-server/lib/cache-wrapper.cjs +0 -383
  61. package/mcp-server/lib/error-envelope.js +0 -138
  62. package/mcp-server/lib/executor.ts +0 -499
  63. package/mcp-server/lib/index.ts +0 -29
  64. package/mcp-server/lib/logger.cjs +0 -30
  65. package/mcp-server/lib/rate-limiter.js +0 -166
  66. package/mcp-server/lib/sandbox.test.ts +0 -519
  67. package/mcp-server/lib/sandbox.ts +0 -395
  68. package/mcp-server/lib/types.ts +0 -267
  69. package/mcp-server/logger.js +0 -173
  70. package/mcp-server/manifest.json +0 -473
  71. package/mcp-server/mdc-generator.js +0 -298
  72. package/mcp-server/premium-tools.js +0 -1275
  73. package/mcp-server/proof-tools.js +0 -571
  74. package/mcp-server/registry/tool-registry.js +0 -586
  75. package/mcp-server/registry/tools.json +0 -619
  76. package/mcp-server/registry.test.ts +0 -340
  77. package/mcp-server/test-mcp.js +0 -108
  78. package/mcp-server/test-tools.js +0 -36
  79. package/mcp-server/tests/tier-gating.test.js +0 -297
  80. package/mcp-server/tier-auth.js +0 -767
  81. package/mcp-server/tools/index.js +0 -72
  82. package/mcp-server/tools-reorganized.ts +0 -244
  83. package/mcp-server/tools-v3.js +0 -1004
  84. package/mcp-server/truth-context.js +0 -622
  85. package/mcp-server/truth-firewall-tools.js +0 -2183
  86. package/mcp-server/vibecheck-2.0-tools.js +0 -761
  87. package/mcp-server/vibecheck-mcp-server-3.2.0.tgz +0 -0
  88. 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
+ }