gigaspec 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/.cursorrules +12 -0
- package/.env.example +4 -0
- package/AGENT.md +114 -0
- package/ARCHITECTURE.md +71 -0
- package/CLAUDE.md +6 -0
- package/DEPLOYMENT.md +70 -0
- package/ENVIRONMENT.md +40 -0
- package/EXAMPLE.md +390 -0
- package/GETTING_STARTED.md +153 -0
- package/IMPLEMENTATION_SUMMARY.md +261 -0
- package/LICENSE +201 -0
- package/PLAN.md +37 -0
- package/README.md +286 -0
- package/SETUP.md +64 -0
- package/STATE.md +53 -0
- package/WORKFLOW.md +41 -0
- package/bin/gigaspec.js +459 -0
- package/bin/mcp-server.js +393 -0
- package/lib/ai-workflow.js +423 -0
- package/lib/framework.js +970 -0
- package/lib/index.js +19 -0
- package/lib/templates.js +1034 -0
- package/logo.svg +55 -0
- package/package.json +46 -0
- package/prompts/fix.md +2 -0
- package/prompts/implement.md +2 -0
- package/prompts/plan.md +2 -0
- package/prompts/verify.md +2 -0
package/lib/framework.js
ADDED
|
@@ -0,0 +1,970 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gigaspec AI Collaboration Framework
|
|
3
|
+
*
|
|
4
|
+
* This framework provides structure for AI assistants to:
|
|
5
|
+
* 1. Analyze project requirements
|
|
6
|
+
* 2. Ask clarifying questions
|
|
7
|
+
* 3. Make intelligent recommendations
|
|
8
|
+
* 4. Generate complete specifications
|
|
9
|
+
*
|
|
10
|
+
* The AI does the thinking. This framework provides the structure.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const fs = require('fs-extra');
|
|
14
|
+
const path = require('path');
|
|
15
|
+
const templates = require('./templates');
|
|
16
|
+
|
|
17
|
+
// Inquirer is ESM-only in v9+, so we need dynamic import
|
|
18
|
+
let inquirer;
|
|
19
|
+
async function getInquirer() {
|
|
20
|
+
if (!inquirer) {
|
|
21
|
+
const mod = await import('inquirer');
|
|
22
|
+
inquirer = mod.default;
|
|
23
|
+
}
|
|
24
|
+
return inquirer;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// ============================================================================
|
|
28
|
+
// ANALYSIS PROMPTS - For LLM to analyze requirements
|
|
29
|
+
// ============================================================================
|
|
30
|
+
|
|
31
|
+
const ANALYSIS_PROMPT = `You are a Staff+ Engineer and Technical Architect.
|
|
32
|
+
Your task is to analyze a project description and make intelligent technical decisions.
|
|
33
|
+
|
|
34
|
+
PROJECT DESCRIPTION:
|
|
35
|
+
{{DESCRIPTION}}
|
|
36
|
+
|
|
37
|
+
{{CONTEXT}}
|
|
38
|
+
|
|
39
|
+
Analyze this project deeply. Consider:
|
|
40
|
+
|
|
41
|
+
1. WHAT is being built? (Core functionality, user flows)
|
|
42
|
+
2. WHO are the users? (End users, admins, scale)
|
|
43
|
+
3. WHAT are the constraints? (Performance, security, compliance)
|
|
44
|
+
4. WHAT are the integrations? (External APIs, services)
|
|
45
|
+
5. WHAT is the timeline and team size?
|
|
46
|
+
|
|
47
|
+
Based on your analysis, answer these questions:
|
|
48
|
+
|
|
49
|
+
--- ANALYSIS ---
|
|
50
|
+
|
|
51
|
+
Core Purpose: [What is the fundamental problem being solved?]
|
|
52
|
+
|
|
53
|
+
User Types: [Who will use this? How many?]
|
|
54
|
+
|
|
55
|
+
Key Features: [What are the 3-5 most important features?]
|
|
56
|
+
|
|
57
|
+
Technical Challenges: [What will be hardest to build?]
|
|
58
|
+
|
|
59
|
+
Scale Expectations: [How many users? What traffic?]
|
|
60
|
+
|
|
61
|
+
--- TECHNICAL DECISIONS ---
|
|
62
|
+
|
|
63
|
+
Recommended Stack: [Language/Framework with specific version]
|
|
64
|
+
Why: [Explain your reasoning based on the analysis]
|
|
65
|
+
|
|
66
|
+
Alternative Stacks: [2 other options with pros/cons]
|
|
67
|
+
|
|
68
|
+
Database: [Which database and why]
|
|
69
|
+
|
|
70
|
+
Cache Strategy: [What to cache and how]
|
|
71
|
+
|
|
72
|
+
External Services: [What 3rd party services are needed?]
|
|
73
|
+
|
|
74
|
+
Deployment Platform: [Where to deploy and why]
|
|
75
|
+
|
|
76
|
+
--- QUESTIONS FOR USER ---
|
|
77
|
+
|
|
78
|
+
What questions do you have that would help you make better recommendations?
|
|
79
|
+
List 3-5 specific questions.
|
|
80
|
+
|
|
81
|
+
--- CONFIDENCE ---
|
|
82
|
+
|
|
83
|
+
How confident are you in these recommendations? (High/Medium/Low)
|
|
84
|
+
What information would increase your confidence?
|
|
85
|
+
`;
|
|
86
|
+
|
|
87
|
+
const QUESTION_ANSWER_PROMPT = `You previously analyzed this project:
|
|
88
|
+
|
|
89
|
+
{{DESCRIPTION}}
|
|
90
|
+
|
|
91
|
+
And asked these questions:
|
|
92
|
+
{{QUESTIONS}}
|
|
93
|
+
|
|
94
|
+
The user has answered:
|
|
95
|
+
{{ANSWERS}}
|
|
96
|
+
|
|
97
|
+
Based on these answers, refine your technical recommendations:
|
|
98
|
+
|
|
99
|
+
--- REFINED ANALYSIS ---
|
|
100
|
+
[Update your analysis with new information]
|
|
101
|
+
|
|
102
|
+
--- FINAL TECHNICAL STACK ---
|
|
103
|
+
Stack: [Final decision with version]
|
|
104
|
+
Frontend: [If applicable]
|
|
105
|
+
Database: [Final decision]
|
|
106
|
+
Cache: [Final decision]
|
|
107
|
+
Services: [List of external services]
|
|
108
|
+
Deployment: [Final platform]
|
|
109
|
+
|
|
110
|
+
--- RATIONALE ---
|
|
111
|
+
[Explain why you made these specific choices]
|
|
112
|
+
|
|
113
|
+
--- TIMELINE BREAKDOWN ---
|
|
114
|
+
[Break down {{WEEKS}} weeks into phases with milestones]
|
|
115
|
+
|
|
116
|
+
--- RISKS & MITIGATION ---
|
|
117
|
+
[What could go wrong and how to prevent it]
|
|
118
|
+
`;
|
|
119
|
+
|
|
120
|
+
// ============================================================================
|
|
121
|
+
// INTERACTIVE QUESTIONS
|
|
122
|
+
// ============================================================================
|
|
123
|
+
|
|
124
|
+
const PROJECT_QUESTIONS = [
|
|
125
|
+
{
|
|
126
|
+
type: 'input',
|
|
127
|
+
name: 'name',
|
|
128
|
+
message: '📛 Project name:',
|
|
129
|
+
default: 'MyProject',
|
|
130
|
+
validate: (input) => input.trim().length > 0 || 'Project name is required'
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
type: 'input',
|
|
134
|
+
name: 'description',
|
|
135
|
+
message: '📝 Brief description:',
|
|
136
|
+
default: (answers) => `${answers.name} - A new software project`
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
type: 'list',
|
|
140
|
+
name: 'team',
|
|
141
|
+
message: '👥 Team size:',
|
|
142
|
+
choices: ['Solo (1)', 'Small (2-5)', 'Medium (6-10)', 'Large (10+)'],
|
|
143
|
+
default: 'Small (2-5)'
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
type: 'list',
|
|
147
|
+
name: 'weeks',
|
|
148
|
+
message: '⏱️ Timeline:',
|
|
149
|
+
choices: ['4 weeks', '8 weeks', '12 weeks', '16 weeks', '20+ weeks'],
|
|
150
|
+
default: '12 weeks'
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
type: 'input',
|
|
154
|
+
name: 'targetUsers',
|
|
155
|
+
message: '🎯 Target users (e.g., "students", "developers", "small businesses"):',
|
|
156
|
+
default: 'general users'
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
type: 'confirm',
|
|
160
|
+
name: 'needsRealtime',
|
|
161
|
+
message: '⚡ Does this need real-time features (chat, live updates)?',
|
|
162
|
+
default: false
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
type: 'confirm',
|
|
166
|
+
name: 'needsAuth',
|
|
167
|
+
message: '🔐 Does this need user authentication?',
|
|
168
|
+
default: true
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
type: 'confirm',
|
|
172
|
+
name: 'needsPayments',
|
|
173
|
+
message: '💳 Does this need payment processing?',
|
|
174
|
+
default: false
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
type: 'list',
|
|
178
|
+
name: 'scale',
|
|
179
|
+
message: '📈 Expected scale at launch:',
|
|
180
|
+
choices: ['< 100 users', '100 - 1,000 users', '1,000 - 10,000 users', '10,000+ users'],
|
|
181
|
+
default: '100 - 1,000 users'
|
|
182
|
+
}
|
|
183
|
+
];
|
|
184
|
+
|
|
185
|
+
const STACK_QUESTIONS = [
|
|
186
|
+
{
|
|
187
|
+
type: 'list',
|
|
188
|
+
name: 'stack',
|
|
189
|
+
message: '🛠️ Backend stack:',
|
|
190
|
+
choices: [
|
|
191
|
+
'Node.js/Express',
|
|
192
|
+
'Node.js/NestJS',
|
|
193
|
+
'Python/FastAPI',
|
|
194
|
+
'Python/Django',
|
|
195
|
+
'Elixir/Phoenix',
|
|
196
|
+
'Go/Gin',
|
|
197
|
+
'Ruby on Rails',
|
|
198
|
+
'Java/Spring Boot',
|
|
199
|
+
'Other'
|
|
200
|
+
],
|
|
201
|
+
default: 'Node.js/Express'
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
type: 'list',
|
|
205
|
+
name: 'frontend',
|
|
206
|
+
message: '🎨 Frontend:',
|
|
207
|
+
choices: [
|
|
208
|
+
'React/Next.js',
|
|
209
|
+
'React/Vite',
|
|
210
|
+
'Vue/Nuxt',
|
|
211
|
+
'Vue/Vite',
|
|
212
|
+
'Svelte/SvelteKit',
|
|
213
|
+
'Angular',
|
|
214
|
+
'HTMX + Templates',
|
|
215
|
+
'React Native',
|
|
216
|
+
'Flutter',
|
|
217
|
+
'None (API only)'
|
|
218
|
+
],
|
|
219
|
+
default: 'React/Next.js'
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
type: 'list',
|
|
223
|
+
name: 'database',
|
|
224
|
+
message: '💾 Database:',
|
|
225
|
+
choices: [
|
|
226
|
+
'PostgreSQL',
|
|
227
|
+
'MySQL',
|
|
228
|
+
'MongoDB',
|
|
229
|
+
'SQLite',
|
|
230
|
+
'Supabase',
|
|
231
|
+
'Firebase',
|
|
232
|
+
'DynamoDB'
|
|
233
|
+
],
|
|
234
|
+
default: 'PostgreSQL'
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
type: 'list',
|
|
238
|
+
name: 'cache',
|
|
239
|
+
message: '⚡ Cache:',
|
|
240
|
+
choices: [
|
|
241
|
+
'Redis',
|
|
242
|
+
'Memcached',
|
|
243
|
+
'None needed'
|
|
244
|
+
],
|
|
245
|
+
default: 'Redis'
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
type: 'list',
|
|
249
|
+
name: 'deployment',
|
|
250
|
+
message: '🚀 Deployment platform:',
|
|
251
|
+
choices: [
|
|
252
|
+
'Vercel',
|
|
253
|
+
'Railway',
|
|
254
|
+
'Fly.io',
|
|
255
|
+
'AWS',
|
|
256
|
+
'Google Cloud',
|
|
257
|
+
'Azure',
|
|
258
|
+
'DigitalOcean',
|
|
259
|
+
'Heroku',
|
|
260
|
+
'Self-hosted'
|
|
261
|
+
],
|
|
262
|
+
default: 'Railway'
|
|
263
|
+
}
|
|
264
|
+
];
|
|
265
|
+
|
|
266
|
+
// ============================================================================
|
|
267
|
+
// FRAMEWORK API
|
|
268
|
+
// ============================================================================
|
|
269
|
+
|
|
270
|
+
class GigaspecFramework {
|
|
271
|
+
constructor(options = {}) {
|
|
272
|
+
this.outputDir = options.outputDir || '.';
|
|
273
|
+
this.verbose = options.verbose || false;
|
|
274
|
+
this.jsonMode = options.jsonMode || false;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Output data (text or JSON based on mode)
|
|
279
|
+
*/
|
|
280
|
+
output(data) {
|
|
281
|
+
if (this.jsonMode) {
|
|
282
|
+
return data;
|
|
283
|
+
}
|
|
284
|
+
return data;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Step 1: Create analysis prompt for LLM
|
|
289
|
+
* The AI uses this to analyze requirements
|
|
290
|
+
*/
|
|
291
|
+
createAnalysisPrompt(description, context = {}) {
|
|
292
|
+
let prompt = ANALYSIS_PROMPT
|
|
293
|
+
.replace('{{DESCRIPTION}}', description)
|
|
294
|
+
.replace('{{WEEKS}}', context.weeks || '12');
|
|
295
|
+
|
|
296
|
+
if (context.previousAnalysis) {
|
|
297
|
+
prompt = prompt.replace(
|
|
298
|
+
'{{CONTEXT}}',
|
|
299
|
+
`\nPREVIOUS ANALYSIS:\n${context.previousAnalysis}\n`
|
|
300
|
+
);
|
|
301
|
+
} else {
|
|
302
|
+
prompt = prompt.replace('{{CONTEXT}}', '');
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
return prompt;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Step 2: Create question-answer prompt for LLM
|
|
310
|
+
* After AI asks questions, user answers, AI refines recommendations
|
|
311
|
+
*/
|
|
312
|
+
createRefinementPrompt(description, questions, answers, weeks = 12) {
|
|
313
|
+
return QUESTION_ANSWER_PROMPT
|
|
314
|
+
.replace('{{DESCRIPTION}}', description)
|
|
315
|
+
.replace('{{QUESTIONS}}', questions.map((q, i) => `${i + 1}. ${q}`).join('\n'))
|
|
316
|
+
.replace('{{ANSWERS}}', answers.map((a, i) => `${i + 1}. ${a}`).join('\n'))
|
|
317
|
+
.replace('{{WEEKS}}', weeks);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Step 3: Parse AI analysis output
|
|
322
|
+
* Extract structured data from LLM response
|
|
323
|
+
*/
|
|
324
|
+
parseAnalysis(aiResponse) {
|
|
325
|
+
const sections = this._extractSections(aiResponse);
|
|
326
|
+
|
|
327
|
+
return {
|
|
328
|
+
analysis: {
|
|
329
|
+
corePurpose: sections['Core Purpose'] || '',
|
|
330
|
+
userTypes: sections['User Types'] || '',
|
|
331
|
+
keyFeatures: sections['Key Features'] || '',
|
|
332
|
+
technicalChallenges: sections['Technical Challenges'] || '',
|
|
333
|
+
scaleExpectations: sections['Scale Expectations'] || ''
|
|
334
|
+
},
|
|
335
|
+
recommendations: {
|
|
336
|
+
stack: this._extractValue(sections['Recommended Stack']),
|
|
337
|
+
stackReasoning: sections['Why'] || '',
|
|
338
|
+
alternatives: sections['Alternative Stacks'] || '',
|
|
339
|
+
database: this._extractValue(sections['Database']),
|
|
340
|
+
cache: this._extractValue(sections['Cache Strategy']),
|
|
341
|
+
services: this._extractList(sections['External Services']),
|
|
342
|
+
deployment: this._extractValue(sections['Deployment Platform'])
|
|
343
|
+
},
|
|
344
|
+
questions: this._extractList(sections['Questions for User']),
|
|
345
|
+
confidence: this._extractValue(sections['Confidence'])
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Step 4: Parse refined recommendations
|
|
351
|
+
*/
|
|
352
|
+
parseRefinement(aiResponse) {
|
|
353
|
+
const sections = this._extractSections(aiResponse);
|
|
354
|
+
|
|
355
|
+
return {
|
|
356
|
+
stack: this._extractValue(sections['Stack']),
|
|
357
|
+
frontend: this._extractValue(sections['Frontend']),
|
|
358
|
+
database: this._extractValue(sections['Database']),
|
|
359
|
+
cache: this._extractValue(sections['Cache']),
|
|
360
|
+
services: this._extractList(sections['Services']),
|
|
361
|
+
deployment: this._extractValue(sections['Deployment']),
|
|
362
|
+
rationale: sections['Rationale'] || '',
|
|
363
|
+
timeline: this._extractPhases(sections['Timeline Breakdown']),
|
|
364
|
+
risks: sections['Risks & Mitigation'] || ''
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Step 5: Interactive project setup
|
|
370
|
+
* Asks user questions to gather requirements
|
|
371
|
+
*/
|
|
372
|
+
async interactiveSetup() {
|
|
373
|
+
const inq = await getInquirer();
|
|
374
|
+
|
|
375
|
+
// Step 1: Project basics
|
|
376
|
+
const basics = await inq.prompt(PROJECT_QUESTIONS);
|
|
377
|
+
|
|
378
|
+
// Parse weeks from selection
|
|
379
|
+
const weeksMatch = basics.weeks.match(/(\d+)/);
|
|
380
|
+
const weeks = weeksMatch ? parseInt(weeksMatch[1]) : 12;
|
|
381
|
+
|
|
382
|
+
// Step 2: Stack selection (or AI recommendation)
|
|
383
|
+
const useAI = await inq.prompt([{
|
|
384
|
+
type: 'confirm',
|
|
385
|
+
name: 'useAI',
|
|
386
|
+
message: '🤖 Would you like AI to recommend the tech stack based on your requirements?',
|
|
387
|
+
default: true
|
|
388
|
+
}]);
|
|
389
|
+
|
|
390
|
+
let stackConfig;
|
|
391
|
+
|
|
392
|
+
if (useAI.useAI) {
|
|
393
|
+
// Return partial config for AI analysis
|
|
394
|
+
return {
|
|
395
|
+
mode: 'ai_analysis',
|
|
396
|
+
config: {
|
|
397
|
+
name: basics.name,
|
|
398
|
+
description: basics.description,
|
|
399
|
+
team: basics.team,
|
|
400
|
+
weeks: weeks,
|
|
401
|
+
targetUsers: basics.targetUsers,
|
|
402
|
+
needsRealtime: basics.needsRealtime,
|
|
403
|
+
needsAuth: basics.needsAuth,
|
|
404
|
+
needsPayments: basics.needsPayments,
|
|
405
|
+
scale: basics.scale
|
|
406
|
+
}
|
|
407
|
+
};
|
|
408
|
+
} else {
|
|
409
|
+
// Manual stack selection
|
|
410
|
+
stackConfig = await inq.prompt(STACK_QUESTIONS);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// Step 3: Additional services
|
|
414
|
+
const services = [];
|
|
415
|
+
if (basics.needsAuth) services.push('Authentication (Clerk/Auth0)');
|
|
416
|
+
if (basics.needsPayments) services.push('Stripe (payments)');
|
|
417
|
+
|
|
418
|
+
const additionalServices = await inq.prompt([{
|
|
419
|
+
type: 'checkbox',
|
|
420
|
+
name: 'extras',
|
|
421
|
+
message: '📦 Additional services:',
|
|
422
|
+
choices: [
|
|
423
|
+
'Email (SendGrid/Resend)',
|
|
424
|
+
'File Storage (S3/R2)',
|
|
425
|
+
'Analytics (PostHog/Amplitude)',
|
|
426
|
+
'Error Tracking (Sentry)',
|
|
427
|
+
'Search (Algolia/Meilisearch)',
|
|
428
|
+
'CMS (Sanity/Strapi)',
|
|
429
|
+
'Real-time (Pusher/Ably)'
|
|
430
|
+
]
|
|
431
|
+
}]);
|
|
432
|
+
|
|
433
|
+
services.push(...additionalServices.extras);
|
|
434
|
+
|
|
435
|
+
return {
|
|
436
|
+
mode: 'complete',
|
|
437
|
+
config: {
|
|
438
|
+
name: basics.name,
|
|
439
|
+
description: basics.description,
|
|
440
|
+
team: basics.team,
|
|
441
|
+
weeks: weeks,
|
|
442
|
+
stack: stackConfig?.stack || 'Node.js/Express',
|
|
443
|
+
frontend: stackConfig?.frontend || 'React/Next.js',
|
|
444
|
+
database: stackConfig?.database || 'PostgreSQL',
|
|
445
|
+
cache: stackConfig?.cache || 'Redis',
|
|
446
|
+
deployment: stackConfig?.deployment || 'Railway',
|
|
447
|
+
services: services,
|
|
448
|
+
requirements: {
|
|
449
|
+
targetUsers: basics.targetUsers,
|
|
450
|
+
needsRealtime: basics.needsRealtime,
|
|
451
|
+
needsAuth: basics.needsAuth,
|
|
452
|
+
needsPayments: basics.needsPayments,
|
|
453
|
+
scale: basics.scale
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Step 6: Generate all specification files
|
|
461
|
+
* Uses AI's recommendations to generate docs
|
|
462
|
+
*/
|
|
463
|
+
async generate(config) {
|
|
464
|
+
const outputDir = path.resolve(this.outputDir);
|
|
465
|
+
await fs.ensureDir(outputDir);
|
|
466
|
+
|
|
467
|
+
const files = [];
|
|
468
|
+
const docs = [
|
|
469
|
+
{ name: 'AGENT.md', template: 'agent' },
|
|
470
|
+
{ name: 'ARCHITECTURE.md', template: 'architecture' },
|
|
471
|
+
{ name: 'PLAN.md', template: 'plan' },
|
|
472
|
+
{ name: 'STATE.md', template: 'state' },
|
|
473
|
+
{ name: 'WORKFLOW.md', template: 'workflow' },
|
|
474
|
+
{ name: 'SETUP.md', template: 'setup' },
|
|
475
|
+
{ name: 'DEPLOYMENT.md', template: 'deployment' },
|
|
476
|
+
{ name: 'ENVIRONMENT.md', template: 'environment' },
|
|
477
|
+
{ name: 'GETTING_STARTED.md', template: 'gettingStarted' }
|
|
478
|
+
];
|
|
479
|
+
|
|
480
|
+
for (const doc of docs) {
|
|
481
|
+
const content = templates[doc.template](config);
|
|
482
|
+
const filePath = path.join(outputDir, doc.name);
|
|
483
|
+
await fs.writeFile(filePath, content);
|
|
484
|
+
files.push(doc.name);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// Generate infrastructure
|
|
488
|
+
await this._generateInfrastructure(outputDir, config);
|
|
489
|
+
|
|
490
|
+
return { files, outputDir };
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* Create structured output for AI assistant
|
|
495
|
+
*/
|
|
496
|
+
createStructuredOutput(analysis, recommendations, config) {
|
|
497
|
+
return {
|
|
498
|
+
version: '4.0.0',
|
|
499
|
+
generatedAt: new Date().toISOString(),
|
|
500
|
+
|
|
501
|
+
project: {
|
|
502
|
+
name: config.name,
|
|
503
|
+
description: config.description,
|
|
504
|
+
team: config.team,
|
|
505
|
+
weeks: config.weeks
|
|
506
|
+
},
|
|
507
|
+
|
|
508
|
+
analysis: analysis,
|
|
509
|
+
|
|
510
|
+
recommendations: {
|
|
511
|
+
stack: recommendations.stack,
|
|
512
|
+
frontend: recommendations.frontend,
|
|
513
|
+
database: recommendations.database,
|
|
514
|
+
cache: recommendations.cache,
|
|
515
|
+
services: recommendations.services,
|
|
516
|
+
deployment: recommendations.deployment,
|
|
517
|
+
rationale: recommendations.rationale
|
|
518
|
+
},
|
|
519
|
+
|
|
520
|
+
timeline: recommendations.timeline,
|
|
521
|
+
|
|
522
|
+
risks: recommendations.risks,
|
|
523
|
+
|
|
524
|
+
nextSteps: [
|
|
525
|
+
'Review AI analysis and recommendations',
|
|
526
|
+
'Approve or modify technical stack',
|
|
527
|
+
'Generate specification files',
|
|
528
|
+
'Begin development following PLAN.md'
|
|
529
|
+
]
|
|
530
|
+
};
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
// ============================================================================
|
|
534
|
+
// PRIVATE HELPERS
|
|
535
|
+
// ============================================================================
|
|
536
|
+
|
|
537
|
+
_extractSections(text) {
|
|
538
|
+
const sections = {};
|
|
539
|
+
const lines = text.split('\n');
|
|
540
|
+
let currentSection = null;
|
|
541
|
+
let currentContent = [];
|
|
542
|
+
|
|
543
|
+
for (const line of lines) {
|
|
544
|
+
// Match section headers like "--- Section Name ---" or "-- Section Name --"
|
|
545
|
+
const sectionMatch = line.match(/^---\s*([^-][^\n-]*?)\s*---$/);
|
|
546
|
+
|
|
547
|
+
if (sectionMatch) {
|
|
548
|
+
if (currentSection) {
|
|
549
|
+
sections[currentSection] = currentContent.join('\n').trim();
|
|
550
|
+
}
|
|
551
|
+
currentSection = sectionMatch[1].trim();
|
|
552
|
+
currentContent = [];
|
|
553
|
+
} else if (currentSection && line.trim()) {
|
|
554
|
+
currentContent.push(line);
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
if (currentSection) {
|
|
559
|
+
sections[currentSection] = currentContent.join('\n').trim();
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
return sections;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
_extractValue(text) {
|
|
566
|
+
if (!text) return '';
|
|
567
|
+
// Extract value after colon or first line
|
|
568
|
+
const match = text.match(/:\s*(.+)/);
|
|
569
|
+
return match ? match[1].trim() : text.split('\n')[0].trim();
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
_extractList(text) {
|
|
573
|
+
if (!text) return [];
|
|
574
|
+
return text
|
|
575
|
+
.split('\n')
|
|
576
|
+
.map(line => line.replace(/^[-*\d.\s]+/, '').trim())
|
|
577
|
+
.filter(line => line.length > 0);
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
_extractPhases(text) {
|
|
581
|
+
if (!text) return [];
|
|
582
|
+
const phases = [];
|
|
583
|
+
const lines = text.split('\n');
|
|
584
|
+
|
|
585
|
+
for (const line of lines) {
|
|
586
|
+
const phaseMatch = line.match(/Phase\s*\d+.*?:\s*(.+)/i);
|
|
587
|
+
if (phaseMatch) {
|
|
588
|
+
phases.push(phaseMatch[1].trim());
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
return phases;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
async _generateInfrastructure(outputDir, config) {
|
|
596
|
+
// Create directories
|
|
597
|
+
await fs.ensureDir(path.join(outputDir, 'scripts'));
|
|
598
|
+
await fs.ensureDir(path.join(outputDir, '.hooks'));
|
|
599
|
+
await fs.ensureDir(path.join(outputDir, '.github', 'workflows'));
|
|
600
|
+
await fs.ensureDir(path.join(outputDir, 'prompts'));
|
|
601
|
+
|
|
602
|
+
// Validate script
|
|
603
|
+
await fs.writeFile(
|
|
604
|
+
path.join(outputDir, 'scripts', 'validate-state.sh'),
|
|
605
|
+
`#!/bin/bash\nset -e\nif [ ! -f "STATE.md" ]; then\n echo "❌ STATE.md not found"\n exit 1\nfi\necho "✅ STATE.md valid"\n`,
|
|
606
|
+
{ mode: 0o755 }
|
|
607
|
+
);
|
|
608
|
+
|
|
609
|
+
// Pre-commit hook
|
|
610
|
+
await fs.writeFile(
|
|
611
|
+
path.join(outputDir, '.hooks', 'pre-commit'),
|
|
612
|
+
`#!/bin/bash\necho "🔍 Running checks..."\nif [ -f "scripts/validate-state.sh" ]; then\n ./scripts/validate-state.sh\nfi\necho "✅ Checks passed"\n`,
|
|
613
|
+
{ mode: 0o755 }
|
|
614
|
+
);
|
|
615
|
+
|
|
616
|
+
// GitHub Actions
|
|
617
|
+
await fs.writeFile(
|
|
618
|
+
path.join(outputDir, '.github', 'workflows', 'ai-compliance.yml'),
|
|
619
|
+
`name: Spec Validation\non: [push, pull_request]\njobs:\n validate:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v3\n - run: ./scripts/validate-state.sh\n`
|
|
620
|
+
);
|
|
621
|
+
|
|
622
|
+
// Prompts
|
|
623
|
+
const prompts = {
|
|
624
|
+
'plan.md': '# Planning Protocol\nRead STATE.md → Identify critical path → Output: Assessment → Chunks → Checklist',
|
|
625
|
+
'implement.md': '# Implementation Protocol\nPhase A: Interface → Phase B: Logic → Phase C: Fault tolerance',
|
|
626
|
+
'verify.md': '# Verification Protocol\nStatic analysis → Tests → AGENT.md compliance',
|
|
627
|
+
'fix.md': '# Fix Protocol\nInput: Violation + Code → Output: Before/After diff'
|
|
628
|
+
};
|
|
629
|
+
|
|
630
|
+
for (const [name, content] of Object.entries(prompts)) {
|
|
631
|
+
await fs.writeFile(path.join(outputDir, 'prompts', name), content);
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
// .cursorrules
|
|
635
|
+
await fs.writeFile(
|
|
636
|
+
path.join(outputDir, '.cursorrules'),
|
|
637
|
+
`# ${config.name} - Cursor Rules\n## ALWAYS\n1. Read STATE.md first\n2. Check AGENT.md constraints\n3. Max 10 lines per function\n## NEVER\n1. Skip verification\n2. Update STATE.md without CONFIRMED\n## COMMANDS\n- "Familiarize yourself" - Read all docs\n- "CONTINUE" - Next task from STATE.md\n- "STATUS" - Current state\n`
|
|
638
|
+
);
|
|
639
|
+
|
|
640
|
+
// CLAUDE.md
|
|
641
|
+
await fs.writeFile(
|
|
642
|
+
path.join(outputDir, 'CLAUDE.md'),
|
|
643
|
+
`# ${config.name} - Claude Code Guide\n## Session Start\n1. Read STATE.md completely\n2. Check AGENT.md constraints\n3. Identify next task\n## Stack: ${config.stack}\n`
|
|
644
|
+
);
|
|
645
|
+
|
|
646
|
+
// .env.example
|
|
647
|
+
await fs.writeFile(
|
|
648
|
+
path.join(outputDir, '.env.example'),
|
|
649
|
+
`# ${config.name} Environment\nDATABASE_URL=postgresql://user:pass@localhost:5432/${config.name.toLowerCase().replace(/\s+/g, '_')}\nSECRET_KEY_BASE=change_in_production\nPORT=4000\n`
|
|
650
|
+
);
|
|
651
|
+
|
|
652
|
+
// .gitignore
|
|
653
|
+
await fs.writeFile(
|
|
654
|
+
path.join(outputDir, '.gitignore'),
|
|
655
|
+
`.ai-temp/\n.env\n.env.local\n.DS_Store\nnode_modules/\n_build/\ndist/\n`
|
|
656
|
+
);
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
// ============================================================================
|
|
661
|
+
// CLI COMMANDS
|
|
662
|
+
// ============================================================================
|
|
663
|
+
|
|
664
|
+
async function initCommand(options, brand) {
|
|
665
|
+
const framework = new GigaspecFramework({
|
|
666
|
+
outputDir: options.output,
|
|
667
|
+
jsonMode: options.json
|
|
668
|
+
});
|
|
669
|
+
|
|
670
|
+
// JSON mode: skip branding, output structured data
|
|
671
|
+
if (!options.json) {
|
|
672
|
+
brand.title();
|
|
673
|
+
brand.header('Gigaspec - AI Collaboration Framework');
|
|
674
|
+
brand.footer();
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
let config;
|
|
678
|
+
let result;
|
|
679
|
+
|
|
680
|
+
// Mode 1: Non-interactive with stack provided (highest priority)
|
|
681
|
+
if (options.stack) {
|
|
682
|
+
if (!options.json) {
|
|
683
|
+
brand.step(1, 3, 'Using provided stack configuration');
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
config = {
|
|
687
|
+
name: options.name || 'MyProject',
|
|
688
|
+
description: options.description || `${options.name || 'MyProject'} - A new software project`,
|
|
689
|
+
stack: options.stack,
|
|
690
|
+
frontend: options.frontend || 'React/Next.js',
|
|
691
|
+
database: options.database || 'PostgreSQL',
|
|
692
|
+
cache: options.cache || 'Redis',
|
|
693
|
+
services: options.services ? options.services.split(',') : [],
|
|
694
|
+
deployment: options.deploy || 'Railway',
|
|
695
|
+
weeks: parseInt(options.weeks) || 12,
|
|
696
|
+
team: options.team || '2-5'
|
|
697
|
+
};
|
|
698
|
+
}
|
|
699
|
+
// Mode 2: Non-interactive with defaults (--yes)
|
|
700
|
+
else if (options.yes) {
|
|
701
|
+
if (!options.json) {
|
|
702
|
+
brand.step(1, 3, 'Using default configuration');
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
config = {
|
|
706
|
+
name: options.name || 'MyProject',
|
|
707
|
+
description: options.description || `${options.name || 'MyProject'} - A new software project`,
|
|
708
|
+
stack: 'Node.js/Express',
|
|
709
|
+
frontend: 'React/Next.js',
|
|
710
|
+
database: 'PostgreSQL',
|
|
711
|
+
cache: 'Redis',
|
|
712
|
+
services: [],
|
|
713
|
+
deployment: 'Railway',
|
|
714
|
+
weeks: parseInt(options.weeks) || 12,
|
|
715
|
+
team: options.team || '2-5'
|
|
716
|
+
};
|
|
717
|
+
}
|
|
718
|
+
// Mode 3: JSON mode with description only (for AI consumption)
|
|
719
|
+
else if (options.json && options.description) {
|
|
720
|
+
const analysisPrompt = framework.createAnalysisPrompt(options.description, {
|
|
721
|
+
weeks: options.weeks || '12'
|
|
722
|
+
});
|
|
723
|
+
|
|
724
|
+
result = {
|
|
725
|
+
status: 'analysis_required',
|
|
726
|
+
message: 'AI analysis needed',
|
|
727
|
+
prompt: analysisPrompt,
|
|
728
|
+
nextSteps: [
|
|
729
|
+
'Analyze the project requirements',
|
|
730
|
+
'Ask clarifying questions',
|
|
731
|
+
'Recommend technical stack',
|
|
732
|
+
'Run: gigaspec generate --config <config>'
|
|
733
|
+
]
|
|
734
|
+
};
|
|
735
|
+
|
|
736
|
+
console.log(JSON.stringify(result, null, 2));
|
|
737
|
+
return result;
|
|
738
|
+
}
|
|
739
|
+
// Mode 4: No stack provided - show help
|
|
740
|
+
else if (!options.json && !options.name) {
|
|
741
|
+
// User ran 'gigaspec init' with no options
|
|
742
|
+
// Header already shown above, just show help
|
|
743
|
+
console.log('\n' + brand.bold('🤔 No stack specified!'));
|
|
744
|
+
console.log('\nHere are your options:\n');
|
|
745
|
+
|
|
746
|
+
console.log(brand.cyan('Option 1: Interactive Wizard (Recommended)'));
|
|
747
|
+
console.log(' gigaspec wizard');
|
|
748
|
+
console.log(' → Answer questions, get AI stack recommendation\n');
|
|
749
|
+
|
|
750
|
+
console.log(brand.cyan('Option 2: Analyze First'));
|
|
751
|
+
console.log(' gigaspec analyze "Your project idea" --json');
|
|
752
|
+
console.log(' → Give prompt to AI assistant for stack recommendation');
|
|
753
|
+
console.log(' → Then: gigaspec init --name "MyApp" --stack "RecommendedStack"\n');
|
|
754
|
+
|
|
755
|
+
console.log(brand.cyan('Option 3: Use Defaults'));
|
|
756
|
+
console.log(' gigaspec init --name "MyApp" --yes');
|
|
757
|
+
console.log(' → Uses Node.js/Express with defaults\n');
|
|
758
|
+
|
|
759
|
+
console.log(brand.cyan('Option 4: Specify Stack'));
|
|
760
|
+
console.log(' gigaspec init --name "MyApp" --stack "Node.js/Next.js"');
|
|
761
|
+
console.log(' → Common stacks: Node.js/Next.js, Python/FastAPI, Elixir/Phoenix\n');
|
|
762
|
+
|
|
763
|
+
console.log(brand.bold('💡 Tip:'));
|
|
764
|
+
console.log('If you\'re unsure about your stack, use Option 1 or 2!\n');
|
|
765
|
+
|
|
766
|
+
return { status: 'help_shown' };
|
|
767
|
+
}
|
|
768
|
+
// Mode 5: Interactive mode (has name but no stack/yes)
|
|
769
|
+
else if (!options.json) {
|
|
770
|
+
brand.step(1, 3, 'Interactive project setup');
|
|
771
|
+
|
|
772
|
+
const setup = await framework.interactiveSetup();
|
|
773
|
+
|
|
774
|
+
if (setup.mode === 'ai_analysis') {
|
|
775
|
+
// Generate analysis prompt for AI
|
|
776
|
+
const description = `${setup.config.name}: ${setup.config.description}
|
|
777
|
+
Target users: ${setup.config.targetUsers}
|
|
778
|
+
Needs realtime: ${setup.config.needsRealtime}
|
|
779
|
+
Needs auth: ${setup.config.needsAuth}
|
|
780
|
+
Needs payments: ${setup.config.needsPayments}
|
|
781
|
+
Expected scale: ${setup.config.scale}`;
|
|
782
|
+
|
|
783
|
+
const analysisPrompt = framework.createAnalysisPrompt(description, {
|
|
784
|
+
weeks: setup.config.weeks
|
|
785
|
+
});
|
|
786
|
+
|
|
787
|
+
// Save prompt
|
|
788
|
+
const promptPath = path.join(options.output, '.ai-temp');
|
|
789
|
+
await fs.ensureDir(promptPath);
|
|
790
|
+
await fs.writeFile(
|
|
791
|
+
path.join(promptPath, 'analysis-prompt.txt'),
|
|
792
|
+
analysisPrompt
|
|
793
|
+
);
|
|
794
|
+
|
|
795
|
+
brand.step(2, 3, 'AI analysis required');
|
|
796
|
+
console.log(`\n ${brand.infoColor('Analysis prompt saved to:')} .ai-temp/analysis-prompt.txt`);
|
|
797
|
+
console.log(`\n ${brand.warnColor('Next:')} Provide this prompt to your AI assistant`);
|
|
798
|
+
console.log(` ${brand.infoColor('The AI will analyze and recommend a technical stack')}`);
|
|
799
|
+
console.log(`\n ${brand.infoColor('After AI analysis, run:')}`);
|
|
800
|
+
console.log(` ${brand.cyan('gigaspec generate --config .ai-temp/config.json')}`);
|
|
801
|
+
|
|
802
|
+
// Save partial config for later
|
|
803
|
+
await fs.writeFile(
|
|
804
|
+
path.join(promptPath, 'project-config.json'),
|
|
805
|
+
JSON.stringify(setup.config, null, 2)
|
|
806
|
+
);
|
|
807
|
+
|
|
808
|
+
return {
|
|
809
|
+
status: 'awaiting_ai_analysis',
|
|
810
|
+
config: setup.config,
|
|
811
|
+
promptPath: '.ai-temp/analysis-prompt.txt'
|
|
812
|
+
};
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
config = setup.config;
|
|
816
|
+
}
|
|
817
|
+
// Mode 5: JSON mode without description (error)
|
|
818
|
+
else {
|
|
819
|
+
const error = {
|
|
820
|
+
status: 'error',
|
|
821
|
+
message: 'JSON mode requires either --stack, --yes, or --description for analysis'
|
|
822
|
+
};
|
|
823
|
+
console.log(JSON.stringify(error, null, 2));
|
|
824
|
+
throw new Error(error.message);
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
// Generate files
|
|
828
|
+
if (!options.json) {
|
|
829
|
+
brand.step(3, 3, 'Generating specification files');
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
const genResult = await framework.generate(config);
|
|
833
|
+
|
|
834
|
+
if (options.json) {
|
|
835
|
+
result = {
|
|
836
|
+
status: 'success',
|
|
837
|
+
message: 'Specification framework ready',
|
|
838
|
+
files: genResult.files,
|
|
839
|
+
config: config
|
|
840
|
+
};
|
|
841
|
+
console.log(JSON.stringify(result, null, 2));
|
|
842
|
+
} else {
|
|
843
|
+
brand.divider();
|
|
844
|
+
brand.success('Specification framework ready!');
|
|
845
|
+
brand.divider();
|
|
846
|
+
|
|
847
|
+
console.log('\n' + brand.bold('📁 Generated Files:'));
|
|
848
|
+
genResult.files.forEach(f => console.log(` ${brand.successColor('✓')} ${f}`));
|
|
849
|
+
|
|
850
|
+
console.log('\n' + brand.bold('⭐ START HERE:'));
|
|
851
|
+
console.log(` ${brand.cyan('GETTING_STARTED.md')} - Your step-by-step guide`);
|
|
852
|
+
|
|
853
|
+
console.log('\n' + brand.bold('🤖 For AI Assistants:'));
|
|
854
|
+
console.log(` 1. Read ${brand.cyan('AGENT.md')} for coding standards`);
|
|
855
|
+
console.log(` 2. Check ${brand.cyan('STATE.md')} for current status`);
|
|
856
|
+
console.log(` 3. Run ${brand.cyan('gigaspec status')} to check progress`);
|
|
857
|
+
|
|
858
|
+
console.log('\n' + brand.bold('🚀 Quick Commands:'));
|
|
859
|
+
console.log(` ${brand.cyan('gigaspec status')} - Check what to do next`);
|
|
860
|
+
console.log(` ${brand.cyan('cat STATE.md')} - View current status`);
|
|
861
|
+
console.log(` ${brand.cyan('cat GETTING_STARTED.md')} - Read the full guide`);
|
|
862
|
+
|
|
863
|
+
console.log('\n' + brand.bold('💡 Next Step:'));
|
|
864
|
+
console.log(` Run ${brand.cyan('gigaspec status')} to see your first task!`);
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
return { files: genResult.files, config };
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
async function analyzeCommand(description, options, brand) {
|
|
871
|
+
const framework = new GigaspecFramework({ jsonMode: options.json });
|
|
872
|
+
|
|
873
|
+
const prompt = framework.createAnalysisPrompt(description, {
|
|
874
|
+
weeks: options.weeks || '12'
|
|
875
|
+
});
|
|
876
|
+
|
|
877
|
+
if (options.json) {
|
|
878
|
+
console.log(JSON.stringify({
|
|
879
|
+
status: 'success',
|
|
880
|
+
prompt,
|
|
881
|
+
metadata: {
|
|
882
|
+
description,
|
|
883
|
+
weeks: options.weeks || '12',
|
|
884
|
+
generatedAt: new Date().toISOString()
|
|
885
|
+
}
|
|
886
|
+
}, null, 2));
|
|
887
|
+
} else {
|
|
888
|
+
console.log(prompt);
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
async function generateCommand(options, brand) {
|
|
893
|
+
const framework = new GigaspecFramework({
|
|
894
|
+
outputDir: options.output,
|
|
895
|
+
jsonMode: options.json
|
|
896
|
+
});
|
|
897
|
+
|
|
898
|
+
// Load config from file or options
|
|
899
|
+
let config;
|
|
900
|
+
if (options.config) {
|
|
901
|
+
try {
|
|
902
|
+
config = await fs.readJson(options.config);
|
|
903
|
+
// Ensure all required fields have defaults
|
|
904
|
+
config.name = config.name || 'MyProject';
|
|
905
|
+
config.description = config.description || `${config.name} - A new software project`;
|
|
906
|
+
config.stack = config.stack || 'Node.js/Express';
|
|
907
|
+
config.frontend = config.frontend || 'React/Next.js';
|
|
908
|
+
config.database = config.database || 'PostgreSQL';
|
|
909
|
+
config.cache = config.cache || 'Redis';
|
|
910
|
+
config.services = config.services || [];
|
|
911
|
+
config.deployment = config.deployment || 'Railway';
|
|
912
|
+
config.weeks = config.weeks || 12;
|
|
913
|
+
} catch (err) {
|
|
914
|
+
const error = {
|
|
915
|
+
status: 'error',
|
|
916
|
+
message: `Failed to load config: ${err.message}`
|
|
917
|
+
};
|
|
918
|
+
if (options.json) {
|
|
919
|
+
console.log(JSON.stringify(error, null, 2));
|
|
920
|
+
} else {
|
|
921
|
+
brand.error(error.message);
|
|
922
|
+
}
|
|
923
|
+
process.exit(1);
|
|
924
|
+
return; // For tests that mock process.exit
|
|
925
|
+
}
|
|
926
|
+
} else {
|
|
927
|
+
config = {
|
|
928
|
+
name: options.name || 'MyProject',
|
|
929
|
+
description: options.description || `${options.name || 'MyProject'} - A new software project`,
|
|
930
|
+
stack: options.stack || 'Node.js/Express',
|
|
931
|
+
frontend: options.frontend || 'React/Next.js',
|
|
932
|
+
database: options.database || 'PostgreSQL',
|
|
933
|
+
cache: options.cache || 'Redis',
|
|
934
|
+
services: options.services ? options.services.split(',') : [],
|
|
935
|
+
deployment: options.deploy || 'Railway',
|
|
936
|
+
weeks: parseInt(options.weeks) || 12
|
|
937
|
+
};
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
if (!options.json) {
|
|
941
|
+
brand.step(1, 1, 'Generating specification files');
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
const result = await framework.generate(config);
|
|
945
|
+
|
|
946
|
+
if (options.json) {
|
|
947
|
+
console.log(JSON.stringify({
|
|
948
|
+
status: 'success',
|
|
949
|
+
files: result.files,
|
|
950
|
+
config,
|
|
951
|
+
generatedAt: new Date().toISOString()
|
|
952
|
+
}, null, 2));
|
|
953
|
+
} else {
|
|
954
|
+
brand.divider();
|
|
955
|
+
brand.success('Files generated!');
|
|
956
|
+
brand.divider();
|
|
957
|
+
result.files.forEach(f => console.log(` ${brand.successColor('✓')} ${f}`));
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
module.exports = {
|
|
962
|
+
GigaspecFramework,
|
|
963
|
+
initCommand,
|
|
964
|
+
analyzeCommand,
|
|
965
|
+
generateCommand,
|
|
966
|
+
ANALYSIS_PROMPT,
|
|
967
|
+
QUESTION_ANSWER_PROMPT,
|
|
968
|
+
PROJECT_QUESTIONS,
|
|
969
|
+
STACK_QUESTIONS
|
|
970
|
+
};
|