@kosuke-ai/cli 0.0.39 → 0.0.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +41 -26
- package/dist/index.js.map +1 -1
- package/dist/kosuke/commands/build.d.ts.map +1 -1
- package/dist/kosuke/commands/build.js +30 -13
- package/dist/kosuke/commands/build.js.map +1 -1
- package/dist/kosuke/commands/migrate.d.ts +33 -0
- package/dist/kosuke/commands/migrate.d.ts.map +1 -0
- package/dist/kosuke/commands/migrate.js +196 -0
- package/dist/kosuke/commands/migrate.js.map +1 -0
- package/dist/kosuke/commands/ship.d.ts.map +1 -1
- package/dist/kosuke/commands/ship.js +4 -9
- package/dist/kosuke/commands/ship.js.map +1 -1
- package/dist/kosuke/commands/test.d.ts +6 -9
- package/dist/kosuke/commands/test.d.ts.map +1 -1
- package/dist/kosuke/commands/test.js +65 -169
- package/dist/kosuke/commands/test.js.map +1 -1
- package/dist/kosuke/commands/tickets.d.ts +21 -22
- package/dist/kosuke/commands/tickets.d.ts.map +1 -1
- package/dist/kosuke/commands/tickets.js +548 -673
- package/dist/kosuke/commands/tickets.js.map +1 -1
- package/dist/kosuke/types.d.ts +23 -14
- package/dist/kosuke/types.d.ts.map +1 -1
- package/dist/kosuke/utils/logger.d.ts +1 -1
- package/dist/kosuke/utils/logger.d.ts.map +1 -1
- package/dist/kosuke/utils/prompt-generator.d.ts +0 -4
- package/dist/kosuke/utils/prompt-generator.d.ts.map +1 -1
- package/dist/kosuke/utils/prompt-generator.js +0 -25
- package/dist/kosuke/utils/prompt-generator.js.map +1 -1
- package/dist/kosuke/utils/test-runner.d.ts.map +1 -1
- package/dist/kosuke/utils/test-runner.js +3 -5
- package/dist/kosuke/utils/test-runner.js.map +1 -1
- package/dist/lib.d.ts +2 -1
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +1 -0
- package/dist/lib.js.map +1 -1
- package/dist/package.json +1 -1
- package/package.json +1 -1
|
@@ -1,518 +1,337 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Tickets command - Generate tickets from requirements document
|
|
3
3
|
*
|
|
4
|
-
* This command analyzes a requirements document
|
|
5
|
-
* structured tickets with test coverage:
|
|
4
|
+
* This command analyzes a requirements document and generates structured tickets:
|
|
6
5
|
*
|
|
7
|
-
* SCAFFOLD
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* 4. Frontend scaffold (UI infrastructure)
|
|
12
|
-
* 5. Web tests (validate scaffold E2E)
|
|
6
|
+
* SCAFFOLD MODE (--scaffold flag):
|
|
7
|
+
* SCAFFOLD BATCH (template adaptation):
|
|
8
|
+
* 1. SCAFFOLD-SCHEMA-1 (ONE ticket for ALL database infrastructure changes)
|
|
9
|
+
* 2. SCAFFOLD-BACKEND-X → SCAFFOLD-FRONTEND-X → SCAFFOLD-WEB-TEST-X (feature-by-feature)
|
|
13
10
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* 3. Backend logic (business API)
|
|
18
|
-
* 4. Frontend logic (business UI)
|
|
19
|
-
* 5. Web tests (validate logic E2E)
|
|
11
|
+
* LOGIC BATCH (business functionality):
|
|
12
|
+
* 1. LOGIC-SCHEMA-1 (ONE ticket for ALL business entities)
|
|
13
|
+
* 2. LOGIC-BACKEND-X → LOGIC-FRONTEND-X → LOGIC-WEB-TEST-X (feature-by-feature)
|
|
20
14
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
15
|
+
* LOGIC-ONLY MODE (default):
|
|
16
|
+
* Only generates LOGIC tickets for new features
|
|
17
|
+
* 1. LOGIC-SCHEMA-1 (ONE ticket for ALL business entities)
|
|
18
|
+
* 2. LOGIC-BACKEND-X → LOGIC-FRONTEND-X → LOGIC-WEB-TEST-X (feature-by-feature)
|
|
23
19
|
*
|
|
24
|
-
*
|
|
20
|
+
* Workflow:
|
|
21
|
+
* 1. Claude Code Agent explores codebase and generates tickets
|
|
22
|
+
* 2. Review step validates and fixes ticket structure
|
|
23
|
+
* 3. Outputs validated tickets.json
|
|
25
24
|
*
|
|
26
25
|
* Usage:
|
|
27
|
-
* kosuke tickets #
|
|
26
|
+
* kosuke tickets # Logic-only mode, use docs.md
|
|
27
|
+
* kosuke tickets --scaffold # Scaffold + logic mode
|
|
28
28
|
* kosuke tickets --path=custom.md # Custom requirements file
|
|
29
|
-
* kosuke tickets --
|
|
30
|
-
* kosuke tickets --directory=./
|
|
31
|
-
* kosuke tickets --dir=./my-app --path=docs/spec.md # Custom directory and requirements path
|
|
29
|
+
* kosuke tickets --prompt="Add dark mode" # Inline requirements
|
|
30
|
+
* kosuke tickets --directory=./my-app # Analyze specific directory
|
|
32
31
|
*/
|
|
33
32
|
import { existsSync, readFileSync, statSync, writeFileSync } from 'fs';
|
|
34
33
|
import { join, resolve } from 'path';
|
|
35
34
|
import { formatCostBreakdown, runAgent } from '../utils/claude-agent.js';
|
|
36
35
|
import { logger, setupCancellationHandler } from '../utils/logger.js';
|
|
37
36
|
/**
|
|
38
|
-
*
|
|
37
|
+
* Build unified system prompt for comprehensive ticket generation
|
|
39
38
|
*/
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
function buildTicketPrompt(requirementsContent, projectPath, isScaffoldMode) {
|
|
40
|
+
const scaffoldGuidance = isScaffoldMode
|
|
41
|
+
? `
|
|
42
|
+
**SCAFFOLD TICKETS - Template Adaptation ONLY:**
|
|
43
|
+
|
|
44
|
+
These tickets focus on removing, changing, or customizing the Kosuke Template baseline.
|
|
45
|
+
DO NOT add new business logic or features from requirements here.
|
|
46
|
+
|
|
47
|
+
Scaffold tickets should:
|
|
48
|
+
- ❌ REMOVE unused template features (e.g., organizations, billing, multi-tenancy)
|
|
49
|
+
- 🔄 CHANGE existing features (e.g., swap Better Auth for Clerk, simplify billing)
|
|
50
|
+
- 🎨 CUSTOMIZE infrastructure (landing page, email templates, branding, navigation)
|
|
51
|
+
|
|
52
|
+
Examples of SCAFFOLD tickets:
|
|
53
|
+
- "Remove organization/multi-tenancy support from auth"
|
|
54
|
+
- "Simplify billing to single tier (remove pro/business tiers)"
|
|
55
|
+
- "Customize landing page for [specific use case]"
|
|
56
|
+
- "Remove landing page entirely (internal tool)"
|
|
57
|
+
- "Update email templates for [brand name]"
|
|
58
|
+
|
|
59
|
+
**SCAFFOLD Ticket Ordering - CRITICAL:**
|
|
60
|
+
1. SCAFFOLD-SCHEMA-1 (ONE ticket for ALL database infrastructure changes, auto-validated)
|
|
61
|
+
2. SCAFFOLD-BACKEND-X → SCAFFOLD-FRONTEND-X → SCAFFOLD-WEB-TEST-X (feature-by-feature)
|
|
62
|
+
3. Each feature follows: backend → frontend → test pattern
|
|
63
|
+
|
|
64
|
+
**SCAFFOLD Web Tests Must Validate:**
|
|
65
|
+
- Authentication flow works without removed features (e.g., no org selection)
|
|
66
|
+
- Navigation doesn't have broken links after removing pages
|
|
67
|
+
- Landing page renders correctly with new branding
|
|
68
|
+
- Signup flow works with simplified structure
|
|
69
|
+
- Settings pages work without removed sections (e.g., billing removed)
|
|
70
|
+
- Any customized templates (emails, landing) render correctly
|
|
71
|
+
`
|
|
72
|
+
: '';
|
|
73
|
+
const webTestGuidance = `
|
|
74
|
+
**WEB TEST TICKETS - Stagehand Agent E2E Tests:**
|
|
75
|
+
|
|
76
|
+
Web test tickets are executed by Stagehand agent and must follow these guidelines:
|
|
77
|
+
|
|
78
|
+
**Test User Discovery:**
|
|
79
|
+
1. **ALWAYS read seed files** to find test user credentials:
|
|
80
|
+
- Look for files: lib/db/seed.ts, src/lib/db/seed.ts
|
|
81
|
+
- Pattern: Any email ending with "+kosuke_test@example.com" uses OTP code "424242"
|
|
82
|
+
- Example: john+kosuke_test@example.com → OTP: 424242
|
|
83
|
+
- Include all discovered test users in ticket description
|
|
84
|
+
|
|
85
|
+
**Ticket Structure Requirements:**
|
|
86
|
+
Each web test ticket MUST include:
|
|
87
|
+
|
|
88
|
+
1. **Test User Credentials** (at the top)
|
|
89
|
+
- List all test users with their emails
|
|
90
|
+
- Document OTP code (424242)
|
|
91
|
+
- Specify user roles if applicable (admin, regular user, etc.)
|
|
92
|
+
|
|
93
|
+
2. **Test Steps** (numbered, detailed natural language)
|
|
94
|
+
- Navigation instructions ("Navigate to /sign-in")
|
|
95
|
+
- User interactions ("Click button labeled 'New Task'")
|
|
96
|
+
- Input actions ("Enter 'Test Task' in title field")
|
|
97
|
+
- Expected outcomes after each step ("Expected: Task appears in list")
|
|
98
|
+
- Use CLEAR element descriptions (button text, labels, placeholders)
|
|
99
|
+
- Use relative paths only (e.g., /sign-in, /tasks) - base URL provided as test argument
|
|
100
|
+
|
|
101
|
+
3. **Acceptance Criteria**
|
|
102
|
+
- Final expected state
|
|
103
|
+
- Data validation points
|
|
104
|
+
- User feedback confirmation
|
|
105
|
+
|
|
106
|
+
**Stagehand Best Practices:**
|
|
107
|
+
- Use natural language, NOT code
|
|
108
|
+
- Be SPECIFIC about element identification (button text, input labels, exact URLs)
|
|
109
|
+
- Include EXPECTED OUTCOMES after each major action
|
|
110
|
+
- Combine related flows into ONE ticket (signup → create → invite = 1 ticket)
|
|
111
|
+
- Authentication steps MUST be explicit:
|
|
112
|
+
1. Navigate to /sign-in
|
|
113
|
+
2. Enter email: {test_user}+kosuke_test@example.com
|
|
114
|
+
3. Click "Send Code" button
|
|
115
|
+
4. Enter OTP: 424242
|
|
116
|
+
5. Click "Verify" button
|
|
117
|
+
6. Expected: Redirected to dashboard/main app
|
|
118
|
+
|
|
119
|
+
**Example Web Test Ticket:**
|
|
43
120
|
|
|
44
|
-
|
|
45
|
-
|
|
121
|
+
{
|
|
122
|
+
"id": "LOGIC-WEB-TEST-1",
|
|
123
|
+
"title": "E2E: User signup and create first task",
|
|
124
|
+
"description": "**Test User Credentials:**\\n- Email: john+kosuke_test@example.com\\n- OTP Code: 424242\\n\\n**Test Steps:**\\n\\n1. **Sign in with test user**\\n - Navigate to /sign-in\\n - Enter email: john+kosuke_test@example.com\\n - Click button labeled 'Send Code'\\n - Enter OTP code: 424242\\n - Click button labeled 'Verify'\\n - Expected: Redirected to /tasks\\n\\n2. **Create new task**\\n - Click button with text 'New Task'\\n - Enter 'My First Task' in the Title field\\n - Select 'High' from Priority dropdown\\n - Click 'Create Task' button\\n - Expected: Task appears in task list\\n - Expected: Success message shown\\n\\n3. **Verify task persistence**\\n - Refresh the page\\n - Expected: Task 'My First Task' still visible\\n - Expected: Priority shows 'High'\\n\\n**Acceptance Criteria:**\\n- User successfully authenticates with OTP\\n- Task is created and visible\\n- Task persists after page refresh\\n- UI shows appropriate feedback",
|
|
125
|
+
"type": "test",
|
|
126
|
+
"estimatedEffort": 4,
|
|
127
|
+
"status": "Todo",
|
|
128
|
+
"category": "tasks"
|
|
129
|
+
}`;
|
|
130
|
+
return `You are an expert software architect generating implementation tickets.
|
|
46
131
|
|
|
47
|
-
**Requirements:**
|
|
132
|
+
**Requirements Document:**
|
|
48
133
|
${requirementsContent}
|
|
49
134
|
|
|
50
|
-
**Context:**
|
|
135
|
+
**Project Context:**
|
|
51
136
|
You have access to the project directory at: ${projectPath}
|
|
52
|
-
Explore the codebase to understand the existing architecture and tech stack.
|
|
53
|
-
|
|
54
|
-
**Analysis Criteria:**
|
|
55
|
-
|
|
56
|
-
**Schema (Database):**
|
|
57
|
-
- New tables, columns, or relationships
|
|
58
|
-
- Changes to existing database structure
|
|
59
|
-
- Data model modifications
|
|
60
|
-
- Examples: "Add comments to posts", "Track user preferences", "Store session data"
|
|
61
|
-
|
|
62
|
-
**Backend (API):**
|
|
63
|
-
- New API endpoints or business logic
|
|
64
|
-
- Changes to existing endpoints
|
|
65
|
-
- Server-side processing or validation
|
|
66
|
-
- Integration with external services
|
|
67
|
-
- Examples: "Export data to CSV", "Send email notifications", "Process payments"
|
|
68
|
-
|
|
69
|
-
**Frontend (UI):**
|
|
70
|
-
- New pages, components, or user interactions
|
|
71
|
-
- Changes to existing UI
|
|
72
|
-
- User-facing features
|
|
73
|
-
- Examples: "Add dark mode toggle", "Create dashboard", "Build user profile page"
|
|
74
|
-
|
|
75
|
-
**Important:**
|
|
76
|
-
- Simple UI changes (styling, layout) typically DON'T need backend or schema changes
|
|
77
|
-
- Features involving data persistence ALWAYS need schema + backend + frontend
|
|
78
|
-
- API-only features (webhooks, cron jobs) may not need frontend changes
|
|
79
|
-
- Be precise - only include layers that are actually needed
|
|
80
137
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
{
|
|
84
|
-
"needsSchema": boolean,
|
|
85
|
-
"needsBackend": boolean,
|
|
86
|
-
"needsFrontend": boolean,
|
|
87
|
-
"reasoning": "Brief explanation of why each layer is or isn't needed"
|
|
88
|
-
}
|
|
138
|
+
${scaffoldGuidance}
|
|
139
|
+
${webTestGuidance}
|
|
89
140
|
|
|
90
|
-
|
|
91
|
-
const agentResult = await runAgent('Analyze requirements and determine needed layers', {
|
|
92
|
-
systemPrompt,
|
|
93
|
-
cwd: projectPath,
|
|
94
|
-
maxTurns: 15,
|
|
95
|
-
verbosity: 'minimal',
|
|
96
|
-
});
|
|
97
|
-
// Parse response
|
|
98
|
-
try {
|
|
99
|
-
const jsonMatch = agentResult.response.match(/\{[\s\S]*\}/);
|
|
100
|
-
if (!jsonMatch) {
|
|
101
|
-
throw new Error('No JSON found in analysis response');
|
|
102
|
-
}
|
|
103
|
-
const analysis = JSON.parse(jsonMatch[0]);
|
|
104
|
-
// Validate structure
|
|
105
|
-
if (typeof analysis.needsSchema !== 'boolean' ||
|
|
106
|
-
typeof analysis.needsBackend !== 'boolean' ||
|
|
107
|
-
typeof analysis.needsFrontend !== 'boolean' ||
|
|
108
|
-
typeof analysis.reasoning !== 'string') {
|
|
109
|
-
throw new Error('Invalid analysis structure');
|
|
110
|
-
}
|
|
111
|
-
return analysis;
|
|
112
|
-
}
|
|
113
|
-
catch (error) {
|
|
114
|
-
console.error('❌ Failed to parse layer analysis:', error);
|
|
115
|
-
console.error('Raw response:', agentResult.response.substring(0, 500));
|
|
116
|
-
throw new Error(`Failed to analyze required layers: ${error instanceof Error ? error.message : String(error)}`);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
/**
|
|
120
|
-
* Build system prompt for DB test ticket generation
|
|
121
|
-
*/
|
|
122
|
-
function buildDBTestPrompt(batchType, requirementsContent, projectPath, previousSchemaTickets) {
|
|
123
|
-
const ticketId = batchType === 'scaffold' ? 'DB-TEST-1' : 'DB-TEST-2';
|
|
124
|
-
const schemaTicketsContext = previousSchemaTickets
|
|
125
|
-
.map((t) => `**${t.id}: ${t.title}**\n${t.description}`)
|
|
126
|
-
.join('\n\n');
|
|
127
|
-
return `You are an expert QA engineer generating database validation test tickets.
|
|
128
|
-
|
|
129
|
-
**Your Task:**
|
|
130
|
-
Generate ONE database test ticket to validate the schema implementation from the tickets below.
|
|
141
|
+
**LOGIC TICKETS - Business Functionality:**
|
|
131
142
|
|
|
132
|
-
|
|
133
|
-
${schemaTicketsContext}
|
|
143
|
+
These tickets implement the actual features and requirements from the document.
|
|
134
144
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
3. Create a test ticket that checks those tables exist
|
|
145
|
+
Logic tickets should:
|
|
146
|
+
- 🗄️ Create schema for business entities (tasks, projects, posts, etc.)
|
|
147
|
+
- ⚙️ Build backend APIs for business features
|
|
148
|
+
- 🎨 Create frontend UI for business features
|
|
140
149
|
|
|
141
|
-
**
|
|
142
|
-
- Do NOT explore the codebase
|
|
143
|
-
- Do NOT look at existing schema files
|
|
144
|
-
- ONLY use the schema tickets above to determine what tables to validate
|
|
145
|
-
- The test should verify that the tables described in those tickets exist
|
|
150
|
+
**LOGIC Ticket Ordering - CRITICAL RULES:**
|
|
146
151
|
|
|
147
|
-
**
|
|
148
|
-
-
|
|
149
|
-
-
|
|
150
|
-
-
|
|
151
|
-
* List of tables to validate (extracted from schema tickets above)
|
|
152
|
-
* What to check: verify all tables exist
|
|
153
|
-
* Success criteria: all tables from schema tickets exist in database
|
|
154
|
-
- type: "db-test"
|
|
155
|
-
- estimatedEffort: 1-3 (these are simple validation tests)
|
|
156
|
-
- status: "Todo"
|
|
157
|
-
- category: "database-validation"
|
|
158
|
-
|
|
159
|
-
**Output Format:**
|
|
160
|
-
Return ONLY a valid JSON array with ONE ticket. No markdown, no code blocks, just raw JSON.
|
|
161
|
-
|
|
162
|
-
Example:
|
|
163
|
-
[
|
|
164
|
-
{
|
|
165
|
-
"id": "DB-TEST-1",
|
|
166
|
-
"title": "Validate scaffold database schema",
|
|
167
|
-
"description": "Verify that the scaffold schema has been correctly implemented based on SCHEMA-SCAFFOLD-1:\\n\\nTables to validate:\\n- users\\n- user_subscriptions\\n- notifications\\n\\nValidation checks:\\n- Verify all tables exist\\n- Check table names are correct\\n\\nAcceptance Criteria:\\n- All tables from SCHEMA-SCAFFOLD-1 exist in database\\n- No schema errors",
|
|
168
|
-
"type": "db-test",
|
|
169
|
-
"estimatedEffort": 2,
|
|
170
|
-
"status": "Todo",
|
|
171
|
-
"category": "database-validation"
|
|
172
|
-
}
|
|
173
|
-
]
|
|
174
|
-
|
|
175
|
-
**Critical Instructions:**
|
|
176
|
-
1. Analyze the schema tickets above to extract table names
|
|
177
|
-
2. Generate a focused test ticket that validates those specific tables exist
|
|
178
|
-
3. Reference the schema ticket IDs in the description
|
|
179
|
-
4. Keep descriptions clear and actionable
|
|
180
|
-
5. Return ONLY valid JSON - no explanations, no markdown formatting`;
|
|
181
|
-
}
|
|
182
|
-
/**
|
|
183
|
-
* Build system prompt for Web test ticket generation
|
|
184
|
-
*/
|
|
185
|
-
function buildWebTestPrompt(batchType, requirementsContent, projectPath, previousImplementationTickets, startingNumber) {
|
|
186
|
-
const backendTicketsContext = previousImplementationTickets.backend
|
|
187
|
-
.map((t) => `**${t.id}: ${t.title}**\n${t.description}`)
|
|
188
|
-
.join('\n\n');
|
|
189
|
-
const frontendTicketsContext = previousImplementationTickets.frontend
|
|
190
|
-
.map((t) => `**${t.id}: ${t.title}**\n${t.description}`)
|
|
191
|
-
.join('\n\n');
|
|
192
|
-
return `You are an expert QA engineer generating end-to-end web test tickets.
|
|
193
|
-
|
|
194
|
-
**Your Task:**
|
|
195
|
-
Generate web test tickets to validate the implementation from the backend and frontend tickets below.
|
|
196
|
-
|
|
197
|
-
**Backend Tickets to Validate:**
|
|
198
|
-
${backendTicketsContext || 'No backend tickets for this batch'}
|
|
199
|
-
|
|
200
|
-
**Frontend Tickets to Validate:**
|
|
201
|
-
${frontendTicketsContext || 'No frontend tickets for this batch'}
|
|
202
|
-
|
|
203
|
-
**Web Test Ticket Goals:**
|
|
204
|
-
Based on the implementation tickets above, create tests that validate those features work end-to-end:
|
|
205
|
-
1. Analyze the backend and frontend tickets to understand what features were implemented
|
|
206
|
-
2. Create test tickets that verify those features work correctly in the browser
|
|
207
|
-
3. Focus on user-facing functionality and complete user flows
|
|
208
|
-
|
|
209
|
-
**IMPORTANT:**
|
|
210
|
-
- Do NOT explore the codebase
|
|
211
|
-
- Do NOT look at existing frontend implementation
|
|
212
|
-
- ONLY use the implementation tickets above to determine what to test
|
|
213
|
-
- The tests should verify that the features described in those tickets work end-to-end
|
|
214
|
-
|
|
215
|
-
Let Claude decide granularity based on complexity - could be:
|
|
216
|
-
- One test per major user flow
|
|
217
|
-
- One test covering multiple related features
|
|
218
|
-
- Multiple tests for complex features
|
|
219
|
-
|
|
220
|
-
**Ticket Structure:**
|
|
221
|
-
Each ticket must have:
|
|
222
|
-
- id: "WEB-TEST-${startingNumber}", "WEB-TEST-${startingNumber + 1}", etc. (sequential)
|
|
223
|
-
- title: Clear description of what is being tested
|
|
224
|
-
- description: Detailed test plan with:
|
|
225
|
-
* Reference to implementation tickets being tested
|
|
226
|
-
* User flow to test
|
|
227
|
-
* Steps to execute
|
|
228
|
-
* Expected outcomes (based on implementation tickets)
|
|
229
|
-
* Success criteria
|
|
230
|
-
- type: "web-test"
|
|
231
|
-
- estimatedEffort: number (1-10 based on test complexity)
|
|
232
|
-
- status: "Todo"
|
|
233
|
-
- category: feature name being tested
|
|
152
|
+
**RULE 1: ONLY ONE LOGIC-SCHEMA-1 ticket**
|
|
153
|
+
- Combine ALL business entities into ONE schema ticket
|
|
154
|
+
- ❌ WRONG: LOGIC-SCHEMA-1, LOGIC-SCHEMA-2, LOGIC-SCHEMA-3
|
|
155
|
+
- ✅ CORRECT: LOGIC-SCHEMA-1 (all entities: properties, inquiries, favorites, etc.)
|
|
234
156
|
|
|
235
|
-
**
|
|
236
|
-
|
|
157
|
+
**RULE 2: Feature-by-Feature Pattern (STRICT)**
|
|
158
|
+
After schema, each feature MUST follow: backend → frontend → test
|
|
237
159
|
|
|
238
|
-
Example:
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
"status": "Todo",
|
|
247
|
-
"category": "authentication"
|
|
248
|
-
}
|
|
249
|
-
]
|
|
160
|
+
Example with 2 features:
|
|
161
|
+
1. LOGIC-SCHEMA-1 (ALL schemas combined)
|
|
162
|
+
2. LOGIC-BACKEND-1 (feature 1 backend)
|
|
163
|
+
3. LOGIC-FRONTEND-1 (feature 1 frontend)
|
|
164
|
+
4. LOGIC-WEB-TEST-1 (feature 1 test)
|
|
165
|
+
5. LOGIC-BACKEND-2 (feature 2 backend)
|
|
166
|
+
6. LOGIC-FRONTEND-2 (feature 2 frontend)
|
|
167
|
+
7. LOGIC-WEB-TEST-2 (feature 2 test)
|
|
250
168
|
|
|
251
|
-
**
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
3. Reference the implementation ticket IDs in test descriptions
|
|
255
|
-
4. Focus on end-to-end user flows that span backend + frontend
|
|
256
|
-
5. Make descriptions detailed with clear steps
|
|
257
|
-
6. Return ONLY valid JSON - no explanations, no markdown formatting
|
|
258
|
-
7. Ensure ticket IDs are sequential starting from WEB-TEST-${startingNumber}`;
|
|
259
|
-
}
|
|
260
|
-
/**
|
|
261
|
-
* Build system prompt for ticket generation with integrated analysis
|
|
262
|
-
*/
|
|
263
|
-
function buildTicketGenerationPrompt(phase, ticketType, requirementsContent, projectPath, isScaffoldMode, previousTickets) {
|
|
264
|
-
// Handle test tickets differently
|
|
265
|
-
if (phase === 'db-test') {
|
|
266
|
-
return buildDBTestPrompt(ticketType, requirementsContent, projectPath, previousTickets?.schema || []);
|
|
267
|
-
}
|
|
268
|
-
if (phase === 'web-test') {
|
|
269
|
-
const startingNumber = previousTickets?.webTestStartNumber || 1;
|
|
270
|
-
return buildWebTestPrompt(ticketType, requirementsContent, projectPath, {
|
|
271
|
-
backend: previousTickets?.backend || [],
|
|
272
|
-
frontend: previousTickets?.frontend || [],
|
|
273
|
-
}, startingNumber);
|
|
274
|
-
}
|
|
275
|
-
const phaseTypeKey = `${phase}_${ticketType}`;
|
|
276
|
-
const phaseInstructions = {
|
|
277
|
-
schema_scaffold: `
|
|
278
|
-
**GENERATE: ONE DATABASE SCHEMA SCAFFOLD TICKET**
|
|
279
|
-
|
|
280
|
-
This ticket should handle infrastructure/setup database changes based on the analysis:
|
|
281
|
-
- Modifications to auth tables (if organizations needed or removed)
|
|
282
|
-
- Billing/subscription tables (if changed or removed)
|
|
283
|
-
- Email verification/notification tables
|
|
284
|
-
- Any template baseline schema adjustments
|
|
285
|
-
|
|
286
|
-
**Key Focus:**
|
|
287
|
-
- What needs to be REMOVED from template (e.g., organization tables if not needed)
|
|
288
|
-
- What needs to be ADDED for infrastructure (e.g., organization support if needed)
|
|
289
|
-
- Updates to existing template tables for new requirements
|
|
290
|
-
|
|
291
|
-
Ticket ID: SCHEMA-SCAFFOLD-1
|
|
292
|
-
`,
|
|
293
|
-
schema_logic: `
|
|
294
|
-
**GENERATE: ONE DATABASE SCHEMA BUSINESS LOGIC TICKET**
|
|
295
|
-
|
|
296
|
-
This ticket should handle core business domain tables based on the analysis:
|
|
297
|
-
- Main application entities (e.g., tasks, projects, posts, campaigns)
|
|
298
|
-
- Business-specific relationships
|
|
299
|
-
- Domain-specific fields and constraints
|
|
300
|
-
- Application data models
|
|
301
|
-
|
|
302
|
-
**Key Focus:**
|
|
303
|
-
- Core business entities unique to this application
|
|
304
|
-
- Relationships between business entities
|
|
305
|
-
- NOT infrastructure tables (auth, billing, etc.)
|
|
306
|
-
|
|
307
|
-
Ticket ID: SCHEMA-LOGIC-1
|
|
308
|
-
`,
|
|
309
|
-
backend_scaffold: `
|
|
310
|
-
**GENERATE: BACKEND SCAFFOLD TICKETS**
|
|
311
|
-
|
|
312
|
-
Generate tickets for infrastructure/setup backend changes:
|
|
313
|
-
- Auth modifications (add/remove organization support, change providers)
|
|
314
|
-
- Billing API changes (remove Stripe, add different tiers, etc.)
|
|
315
|
-
- Email template setup (create transactional email templates)
|
|
316
|
-
- Landing page API routes (if needed)
|
|
317
|
-
- Third-party integrations setup
|
|
318
|
-
|
|
319
|
-
**Granularity:**
|
|
320
|
-
- ONE ticket per infrastructure area (auth, billing, email, landing)
|
|
321
|
-
- Let Claude decide granularity based on complexity
|
|
322
|
-
- Each ticket should be independently implementable
|
|
323
|
-
|
|
324
|
-
Ticket IDs: BACKEND-SCAFFOLD-1, BACKEND-SCAFFOLD-2, etc. (sequential)
|
|
325
|
-
`,
|
|
326
|
-
backend_logic: `
|
|
327
|
-
**GENERATE: BACKEND BUSINESS LOGIC TICKETS**
|
|
328
|
-
|
|
329
|
-
Generate tickets for core application backend features:
|
|
330
|
-
- API endpoints for business entities
|
|
331
|
-
- Service layer logic
|
|
332
|
-
- Business rules and validation
|
|
333
|
-
- Application-specific data processing
|
|
334
|
-
- Feature-specific integrations
|
|
335
|
-
|
|
336
|
-
**Granularity:**
|
|
337
|
-
- ONE ticket per feature/module
|
|
338
|
-
- Let Claude decide granularity based on complexity
|
|
339
|
-
- Each ticket should be independently implementable
|
|
340
|
-
|
|
341
|
-
Ticket IDs: BACKEND-LOGIC-1, BACKEND-LOGIC-2, etc. (sequential)
|
|
342
|
-
`,
|
|
343
|
-
frontend_scaffold: `
|
|
344
|
-
**GENERATE: FRONTEND SCAFFOLD TICKETS**
|
|
345
|
-
|
|
346
|
-
Generate tickets for infrastructure/setup frontend changes:
|
|
347
|
-
- Auth UI modifications (add/remove organization switcher, change auth flow)
|
|
348
|
-
- Billing UI changes (subscription management, pricing page updates)
|
|
349
|
-
- Landing page customization
|
|
350
|
-
- Email template previews
|
|
351
|
-
- Navigation/layout updates for infrastructure changes
|
|
352
|
-
|
|
353
|
-
**Granularity:**
|
|
354
|
-
- ONE ticket per infrastructure area
|
|
355
|
-
- Let Claude decide granularity based on complexity
|
|
356
|
-
- Each ticket should be independently implementable
|
|
357
|
-
|
|
358
|
-
Ticket IDs: FRONTEND-SCAFFOLD-1, FRONTEND-SCAFFOLD-2, etc. (sequential)
|
|
359
|
-
`,
|
|
360
|
-
frontend_logic: `
|
|
361
|
-
**GENERATE: FRONTEND BUSINESS LOGIC TICKETS**
|
|
362
|
-
|
|
363
|
-
Generate tickets for core application frontend features:
|
|
364
|
-
- Application-specific pages
|
|
365
|
-
- Feature-specific UI components
|
|
366
|
-
- Business logic forms
|
|
367
|
-
- User workflows
|
|
368
|
-
- Application state management
|
|
369
|
-
|
|
370
|
-
**Granularity:**
|
|
371
|
-
- ONE ticket per PAGE or major feature
|
|
372
|
-
- Let Claude decide granularity based on complexity
|
|
373
|
-
- Each ticket should cover all components and functionality for that area
|
|
374
|
-
|
|
375
|
-
Ticket IDs: FRONTEND-LOGIC-1, FRONTEND-LOGIC-2, etc. (sequential)
|
|
376
|
-
`,
|
|
377
|
-
};
|
|
378
|
-
const categoryGuidance = ticketType === 'scaffold'
|
|
379
|
-
? `
|
|
380
|
-
**Category Assignment:**
|
|
381
|
-
Assign appropriate category to each ticket:
|
|
382
|
-
- "auth" - Authentication and authorization changes
|
|
383
|
-
- "billing" - Payment and subscription changes
|
|
384
|
-
- "email" - Transactional email setup
|
|
385
|
-
- "landing" - Public marketing pages
|
|
386
|
-
- "infrastructure" - General setup/configuration
|
|
387
|
-
`
|
|
388
|
-
: `
|
|
389
|
-
**Category Assignment:**
|
|
390
|
-
Assign appropriate category based on business domain:
|
|
391
|
-
- Use the main entity name (e.g., "tasks", "projects", "campaigns")
|
|
392
|
-
- Or use feature name (e.g., "user-management", "notifications", "analytics")
|
|
393
|
-
- Keep categories consistent across related tickets
|
|
394
|
-
`;
|
|
395
|
-
const contextualGuidance = isScaffoldMode
|
|
396
|
-
? `
|
|
397
|
-
**Kosuke Template Baseline (what the template already includes):**
|
|
398
|
-
- **Authentication**: Better Auth with Email OTP
|
|
399
|
-
- **User Model**: Individual users (no organizations/multi-tenancy by default)
|
|
400
|
-
- **Billing**: Stripe with subscription tiers (free, pro, business)
|
|
401
|
-
- **Email**: Resend for transactional emails
|
|
402
|
-
- **Landing Page**: Basic marketing site with pricing
|
|
403
|
-
- **Database**: PostgreSQL with Drizzle ORM
|
|
404
|
-
- **Stack**: Next.js 15, React 19, TypeScript, Tailwind, Shadcn UI
|
|
405
|
-
|
|
406
|
-
**Analysis Instructions:**
|
|
407
|
-
Before generating tickets, analyze the requirements to understand:
|
|
408
|
-
1. **Auth**: Does it need organizations/multi-tenancy? Different auth provider?
|
|
409
|
-
2. **Billing**: Keep Stripe? Remove billing entirely? Different tiers?
|
|
410
|
-
3. **Email**: What transactional emails are needed? Custom templates?
|
|
411
|
-
4. **Landing**: Customize marketing pages? Remove landing page?
|
|
412
|
-
5. **Core Domain**: What are the main business entities and workflows?
|
|
413
|
-
|
|
414
|
-
For SCAFFOLD tickets:
|
|
415
|
-
- Identify what needs to be REMOVED from template (if not needed)
|
|
416
|
-
- Identify what needs to be ADDED to template (if needed)
|
|
417
|
-
- Identify what needs to be CUSTOMIZED (landing page, email templates, etc.)
|
|
418
|
-
|
|
419
|
-
For LOGIC tickets:
|
|
420
|
-
- Focus on core business functionality
|
|
421
|
-
- Implement application-specific features
|
|
422
|
-
- Build domain models and workflows
|
|
423
|
-
`
|
|
424
|
-
: `
|
|
425
|
-
**Project Context:**
|
|
426
|
-
Explore the codebase to understand:
|
|
427
|
-
- Tech stack and framework versions (Next.js, React, etc.)
|
|
428
|
-
- Existing architecture patterns (App Router, API routes, etc.)
|
|
429
|
-
- Database schema structure and ORM (Drizzle, Prisma, etc.)
|
|
430
|
-
- API route patterns and conventions
|
|
431
|
-
- UI component library and styling approach
|
|
432
|
-
- Testing framework and patterns
|
|
433
|
-
- Authentication system (if any)
|
|
434
|
-
- State management approach
|
|
169
|
+
**RULE 3: Do NOT group by type**
|
|
170
|
+
❌ WRONG: All backends, then all frontends, then all tests
|
|
171
|
+
✅ CORRECT: Feature-by-feature (backend → frontend → test per feature)
|
|
435
172
|
|
|
436
|
-
**
|
|
437
|
-
-
|
|
438
|
-
-
|
|
439
|
-
-
|
|
440
|
-
-
|
|
441
|
-
- Follow the project's architectural decisions
|
|
442
|
-
- Maintain consistency with existing code quality standards
|
|
443
|
-
`;
|
|
444
|
-
return `You are an expert software architect generating implementation tickets for ${isScaffoldMode ? 'a Kosuke Template project' : 'an existing project'}.
|
|
173
|
+
**Ticket Granularity:**
|
|
174
|
+
- Schema: EXACTLY ONE ticket for LOGIC batch (combines ALL entities)
|
|
175
|
+
- Backend: Let complexity decide (could be 1-5 tickets per batch)
|
|
176
|
+
- Frontend: Let complexity decide (could be 1-5 tickets per batch)
|
|
177
|
+
- Web Tests: 1 test per major user flow (matches feature grouping)
|
|
445
178
|
|
|
446
179
|
**Your Task:**
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
180
|
+
1. **Explore the codebase** using read_file, grep, codebase_search to understand:
|
|
181
|
+
- Current tech stack and framework versions
|
|
182
|
+
- Existing architecture patterns
|
|
183
|
+
- Database schema structure
|
|
184
|
+
- API route patterns
|
|
185
|
+
- UI component library and styling
|
|
186
|
+
${isScaffoldMode ? ' - What template features are currently present\n - What needs to be removed, changed, or customized' : ''}
|
|
187
|
+
|
|
188
|
+
2. **Discover test users** for web testing:
|
|
189
|
+
- Read seed files: lib/db/seed.ts, src/lib/db/seed.ts (use read_file or grep)
|
|
190
|
+
- Look for test user pattern: {name}+kosuke_test@example.com
|
|
191
|
+
- Document all test users found (email addresses)
|
|
192
|
+
- Note: All test users use OTP code 424242 for Better Auth
|
|
193
|
+
- Include test user credentials in ALL web test tickets
|
|
194
|
+
|
|
195
|
+
3. **Analyze requirements** to determine:
|
|
196
|
+
- Which layers are needed (schema/backend/frontend)
|
|
197
|
+
- How to break down features into logical batches
|
|
198
|
+
- What user flows need E2E web tests
|
|
199
|
+
|
|
200
|
+
4. **Generate ALL tickets** in the correct order:
|
|
201
|
+
${isScaffoldMode ? ' - SCAFFOLD batch first (template adaptation)\n - LOGIC batches second (business features)' : ' - LOGIC batches only (business features)'}
|
|
202
|
+
- Follow the ticket ordering structure above
|
|
203
|
+
- Schema tickets are automatically validated during build (no separate test tickets needed)
|
|
204
|
+
- For web tests: Include test user credentials, detailed steps, and expected outcomes
|
|
458
205
|
|
|
459
206
|
**Ticket Structure:**
|
|
460
207
|
Each ticket must be a JSON object with:
|
|
461
|
-
- id: string (e.g., "SCHEMA-
|
|
208
|
+
- id: string (e.g., "SCAFFOLD-SCHEMA-1", "LOGIC-BACKEND-2", "SCAFFOLD-WEB-TEST-1")
|
|
462
209
|
- title: string (clear, concise title)
|
|
463
210
|
- description: string (detailed description with acceptance criteria)
|
|
464
|
-
- type: "
|
|
211
|
+
- type: "schema" | "backend" | "frontend" | "test"
|
|
465
212
|
- estimatedEffort: number (1-10, where 1=very easy, 10=very complex)
|
|
466
|
-
- status: "Todo"
|
|
467
|
-
- category: string (
|
|
468
|
-
${categoryGuidance}
|
|
213
|
+
- status: "Todo"
|
|
214
|
+
- category: string (e.g., "auth", "billing", "user-management", "tasks")
|
|
469
215
|
|
|
470
216
|
**Output Format:**
|
|
471
|
-
Return ONLY a valid JSON array of tickets. No markdown, no code blocks, just raw JSON.
|
|
217
|
+
Return ONLY a valid JSON array of ALL tickets in the correct order. No markdown, no code blocks, just raw JSON.
|
|
472
218
|
|
|
473
|
-
Example:
|
|
219
|
+
Example (Full Ordering Structure - Scaffold Mode):
|
|
474
220
|
[
|
|
475
221
|
{
|
|
476
|
-
"id": "
|
|
477
|
-
"title": "Remove
|
|
478
|
-
"description": "Remove multi-tenancy/organization features from
|
|
479
|
-
"type": "
|
|
480
|
-
"estimatedEffort":
|
|
222
|
+
"id": "SCAFFOLD-SCHEMA-1",
|
|
223
|
+
"title": "Remove organizations and simplify auth schema",
|
|
224
|
+
"description": "Remove multi-tenancy/organization features from database:\\n- Drop organization tables\\n- Remove org foreign keys from users table\\n- Simplify schema to individual users only\\n\\nAcceptance Criteria:\\n- Organization tables removed\\n- User table simplified\\n- Migrations validated automatically\\n- No schema errors",
|
|
225
|
+
"type": "schema",
|
|
226
|
+
"estimatedEffort": 5,
|
|
227
|
+
"status": "Todo",
|
|
228
|
+
"category": "auth"
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
"id": "SCAFFOLD-BACKEND-1",
|
|
232
|
+
"title": "Remove organization tRPC routers",
|
|
233
|
+
"description": "Remove organization-related backend logic:\\n- Delete lib/trpc/routers/organizations.ts\\n- Remove from main appRouter\\n- Clean up organization schemas\\n\\nAcceptance Criteria:\\n- Organization routers removed\\n- AppRouter compiles without errors\\n- Type safety maintained",
|
|
234
|
+
"type": "backend",
|
|
235
|
+
"estimatedEffort": 4,
|
|
236
|
+
"status": "Todo",
|
|
237
|
+
"category": "auth"
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
"id": "SCAFFOLD-FRONTEND-1",
|
|
241
|
+
"title": "Remove organization pages and navigation",
|
|
242
|
+
"description": "Remove organization-related UI:\\n- Delete app/(logged-in)/org/[slug]/ directory\\n- Remove org switcher from navigation\\n- Simplify layout without org context\\n\\nAcceptance Criteria:\\n- Organization pages removed\\n- Navigation simplified\\n- No broken links",
|
|
243
|
+
"type": "frontend",
|
|
244
|
+
"estimatedEffort": 5,
|
|
481
245
|
"status": "Todo",
|
|
482
246
|
"category": "auth"
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
"id": "SCAFFOLD-WEB-TEST-1",
|
|
250
|
+
"title": "E2E: Validate simplified auth flow",
|
|
251
|
+
"description": "**Test User Credentials:**\\n- Email: john+kosuke_test@example.com\\n- OTP Code: 424242\\n\\n**Test Steps:**\\n\\n1. **Sign up without org selection**\\n - Navigate to /sign-up\\n - Enter email: newuser+kosuke_test@example.com\\n - Click 'Send Code' button\\n - Enter OTP: 424242\\n - Click 'Verify'\\n - Expected: Redirected directly to app (no org setup)\\n\\n2. **Verify navigation**\\n - Expected: No org switcher visible\\n - Expected: All navigation links work\\n\\n**Acceptance Criteria:**\\n- Auth works without org selection\\n- No broken navigation links\\n- No references to removed features",
|
|
252
|
+
"type": "test",
|
|
253
|
+
"estimatedEffort": 4,
|
|
254
|
+
"status": "Todo",
|
|
255
|
+
"category": "auth"
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
"id": "LOGIC-SCHEMA-1",
|
|
259
|
+
"title": "Create tasks schema",
|
|
260
|
+
"description": "Create database schema for tasks feature:\\n- Create taskStatusEnum: 'todo', 'in_progress', 'done'\\n- Create tasks table with userId foreign key\\n- Export inferred types\\n\\nAcceptance Criteria:\\n- Tasks table created\\n- Enums defined at database level\\n- Migrations validated automatically\\n- No schema errors",
|
|
261
|
+
"type": "schema",
|
|
262
|
+
"estimatedEffort": 4,
|
|
263
|
+
"status": "Todo",
|
|
264
|
+
"category": "tasks"
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
"id": "LOGIC-BACKEND-1",
|
|
268
|
+
"title": "Create tasks tRPC router",
|
|
269
|
+
"description": "Create backend API for tasks:\\n- Create lib/trpc/schemas/tasks.ts\\n- Create lib/trpc/routers/tasks.ts\\n- Implement CRUD operations (list, get, create, update, delete)\\n- Server-side filtering and pagination\\n\\nAcceptance Criteria:\\n- All CRUD operations work\\n- Authorization enforced\\n- Type-safe implementation",
|
|
270
|
+
"type": "backend",
|
|
271
|
+
"estimatedEffort": 6,
|
|
272
|
+
"status": "Todo",
|
|
273
|
+
"category": "tasks"
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
"id": "LOGIC-FRONTEND-1",
|
|
277
|
+
"title": "Create tasks page with list and filters",
|
|
278
|
+
"description": "Create tasks management UI:\\n- Create app/(logged-in)/tasks/page.tsx\\n- Task list with filters (status, search)\\n- Add new task button\\n- Task cards with edit/delete actions\\n\\nAcceptance Criteria:\\n- Task list displays correctly\\n- Filters work server-side\\n- CRUD operations functional\\n- Responsive design",
|
|
279
|
+
"type": "frontend",
|
|
280
|
+
"estimatedEffort": 7,
|
|
281
|
+
"status": "Todo",
|
|
282
|
+
"category": "tasks"
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
"id": "LOGIC-WEB-TEST-1",
|
|
286
|
+
"title": "E2E: User creates and manages tasks",
|
|
287
|
+
"description": "**Test User Credentials:**\\n- Email: john+kosuke_test@example.com\\n- OTP Code: 424242\\n\\n**Test Steps:**\\n\\n1. **Sign in**\\n - Navigate to /sign-in\\n - Enter email: john+kosuke_test@example.com\\n - Click 'Send Code' button\\n - Enter OTP: 424242\\n - Click 'Verify'\\n - Expected: Redirected to /tasks\\n\\n2. **Create task**\\n - Click 'New Task' button\\n - Enter title: 'Test Task'\\n - Select status: 'Todo'\\n - Click 'Create'\\n - Expected: Task appears in list\\n - Expected: Success toast shown\\n\\n3. **Update task**\\n - Click on task\\n - Change status to 'Done'\\n - Expected: Status updates immediately\\n\\n4. **Delete task**\\n - Click delete button\\n - Confirm in dialog\\n - Expected: Task removed from list\\n\\n**Acceptance Criteria:**\\n- User authenticates successfully\\n- Task CRUD operations work\\n- UI provides appropriate feedback",
|
|
288
|
+
"type": "test",
|
|
289
|
+
"estimatedEffort": 5,
|
|
290
|
+
"status": "Todo",
|
|
291
|
+
"category": "tasks"
|
|
483
292
|
}
|
|
484
293
|
]
|
|
485
294
|
|
|
486
295
|
**Critical Instructions:**
|
|
487
|
-
1.
|
|
488
|
-
2.
|
|
489
|
-
3.
|
|
490
|
-
4.
|
|
491
|
-
5.
|
|
492
|
-
6.
|
|
493
|
-
7.
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
296
|
+
1. Explore the project directory thoroughly before generating tickets
|
|
297
|
+
2. ${isScaffoldMode ? 'For SCAFFOLD: Focus on template adaptation ONLY (remove/change/customize) + MUST create SCAFFOLD-WEB-TEST tickets' : ''}
|
|
298
|
+
3. For LOGIC: Focus on business features from requirements
|
|
299
|
+
4. **IMPORTANT**: Read seed files (lib/db/seed.ts or src/lib/db/seed.ts) to discover test users
|
|
300
|
+
5. **SCHEMA TICKETS**: No separate test tickets needed - validation happens automatically during build
|
|
301
|
+
6. ${isScaffoldMode ? '**SCAFFOLD-WEB-TEST TICKETS ARE MANDATORY**: Test that removed features are gone, navigation works, landing page updated, auth flow simplified' : ''}
|
|
302
|
+
7. **WEB TESTS MUST INCLUDE**:
|
|
303
|
+
- Test user credentials at the top
|
|
304
|
+
- Clear numbered steps with natural language
|
|
305
|
+
- Expected outcomes after each step
|
|
306
|
+
- Specific element descriptions (button text, labels, URLs)
|
|
307
|
+
- Complete user flows in one ticket (signup → create → invite = 1 ticket)
|
|
308
|
+
8. Follow the exact ticket ordering structure
|
|
309
|
+
9. Make descriptions detailed with clear acceptance criteria
|
|
310
|
+
10. Return ONLY valid JSON - no explanations, no markdown
|
|
311
|
+
11. Ensure sequential ticket IDs match the ordering structure
|
|
312
|
+
|
|
313
|
+
Begin by:
|
|
314
|
+
1. Reading seed files to discover test users
|
|
315
|
+
2. Exploring the project directory structure
|
|
316
|
+
3. Generating ALL tickets in the correct order with test user info in web tests
|
|
317
|
+
${isScaffoldMode ? '4. IMPORTANT: Create SCAFFOLD-WEB-TEST tickets to validate template changes work correctly' : ''}.`;
|
|
499
318
|
}
|
|
500
319
|
/**
|
|
501
|
-
* Parse tickets from Claude's response
|
|
320
|
+
* Parse all tickets from Claude's response
|
|
502
321
|
*/
|
|
503
|
-
function
|
|
322
|
+
function parseAllTickets(response) {
|
|
504
323
|
try {
|
|
505
324
|
// Extract JSON from response (in case Claude includes extra text)
|
|
506
325
|
const jsonMatch = response.match(/\[[\s\S]*\]/);
|
|
507
326
|
if (!jsonMatch) {
|
|
508
|
-
throw new Error(
|
|
327
|
+
throw new Error('No JSON array found in response');
|
|
509
328
|
}
|
|
510
329
|
const tickets = JSON.parse(jsonMatch[0]);
|
|
511
330
|
// Validate tickets
|
|
512
331
|
if (!Array.isArray(tickets)) {
|
|
513
332
|
throw new Error(`Expected array of tickets, got ${typeof tickets}`);
|
|
514
333
|
}
|
|
515
|
-
const validTypes = ['
|
|
334
|
+
const validTypes = ['schema', 'backend', 'frontend', 'test'];
|
|
516
335
|
for (const ticket of tickets) {
|
|
517
336
|
if (!ticket.id || !ticket.title || !ticket.description) {
|
|
518
337
|
throw new Error(`Invalid ticket structure: ${JSON.stringify(ticket)}`);
|
|
@@ -532,82 +351,194 @@ function parseTicketsFromResponse(response, phase, ticketType) {
|
|
|
532
351
|
return tickets;
|
|
533
352
|
}
|
|
534
353
|
catch (error) {
|
|
535
|
-
console.error(
|
|
354
|
+
console.error('\n❌ Failed to parse tickets from response:');
|
|
536
355
|
console.error(`Raw response:\n${response.substring(0, 500)}...\n`);
|
|
537
|
-
throw new Error(`Failed to parse
|
|
356
|
+
throw new Error(`Failed to parse tickets: ${error instanceof Error ? error.message : String(error)}`);
|
|
538
357
|
}
|
|
539
358
|
}
|
|
540
359
|
/**
|
|
541
|
-
*
|
|
360
|
+
* Build review and fix prompt for ticket validation
|
|
542
361
|
*/
|
|
543
|
-
function
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
362
|
+
function buildReviewAndFixPrompt(initialTickets, requirementsContent, isScaffoldMode) {
|
|
363
|
+
return `You are a ticket validation and correction expert.
|
|
364
|
+
|
|
365
|
+
**Original Requirements:**
|
|
366
|
+
${requirementsContent}
|
|
367
|
+
|
|
368
|
+
**Generated Tickets to Review:**
|
|
369
|
+
${JSON.stringify(initialTickets, null, 2)}
|
|
370
|
+
|
|
371
|
+
**Your Task: VALIDATE AND FIX the tickets according to these STRICT RULES:**
|
|
372
|
+
|
|
373
|
+
**RULE 1: ONE Schema Ticket Per Batch (CRITICAL)**
|
|
374
|
+
- Each batch (SCAFFOLD, LOGIC) must have EXACTLY ONE schema ticket
|
|
375
|
+
- ❌ WRONG: LOGIC-SCHEMA-1, LOGIC-SCHEMA-2, LOGIC-SCHEMA-3
|
|
376
|
+
- ✅ CORRECT: LOGIC-SCHEMA-1 (combines ALL business entities in one ticket)
|
|
377
|
+
- Same for SCAFFOLD-SCHEMA-1 (combines ALL infrastructure schema changes)
|
|
378
|
+
|
|
379
|
+
**RULE 2: Feature-by-Feature Ordering (STRICT)**
|
|
380
|
+
Each feature MUST follow this exact pattern:
|
|
381
|
+
1. Backend ticket
|
|
382
|
+
2. Frontend ticket
|
|
383
|
+
3. Test ticket
|
|
384
|
+
|
|
385
|
+
Example for 2 features:
|
|
386
|
+
[
|
|
387
|
+
{ "id": "LOGIC-SCHEMA-1", ... }, // ONE schema for all
|
|
388
|
+
{ "id": "LOGIC-BACKEND-1", ... }, // Feature 1 backend
|
|
389
|
+
{ "id": "LOGIC-FRONTEND-1", ... }, // Feature 1 frontend
|
|
390
|
+
{ "id": "LOGIC-WEB-TEST-1", ... }, // Feature 1 test
|
|
391
|
+
{ "id": "LOGIC-BACKEND-2", ... }, // Feature 2 backend
|
|
392
|
+
{ "id": "LOGIC-FRONTEND-2", ... }, // Feature 2 frontend
|
|
393
|
+
{ "id": "LOGIC-WEB-TEST-2", ... } // Feature 2 test
|
|
394
|
+
]
|
|
395
|
+
|
|
396
|
+
**RULE 3: Sequential Numbering**
|
|
397
|
+
- After combining schemas, renumber all tickets sequentially
|
|
398
|
+
- LOGIC-BACKEND-1, LOGIC-BACKEND-2, LOGIC-BACKEND-3 (sequential)
|
|
399
|
+
- LOGIC-FRONTEND-1, LOGIC-FRONTEND-2, LOGIC-FRONTEND-3 (sequential)
|
|
400
|
+
- LOGIC-WEB-TEST-1, LOGIC-WEB-TEST-2, LOGIC-WEB-TEST-3 (sequential)
|
|
401
|
+
|
|
402
|
+
**RULE 4: Test Tickets Must Include Credentials**
|
|
403
|
+
- Every WEB-TEST ticket MUST start with test user credentials
|
|
404
|
+
- Format: "**Test User Credentials:**\\n- Email: user+kosuke_test@example.com\\n- OTP Code: 424242"
|
|
405
|
+
|
|
406
|
+
**AUTOMATIC FIXES TO APPLY:**
|
|
407
|
+
|
|
408
|
+
1. **Combine Schema Tickets:**
|
|
409
|
+
- If multiple LOGIC-SCHEMA-X tickets exist, merge into ONE LOGIC-SCHEMA-1
|
|
410
|
+
- Combine all table definitions, enums, and types into single ticket
|
|
411
|
+
- Update description to include ALL schemas
|
|
412
|
+
- Same for SCAFFOLD-SCHEMA-X tickets
|
|
413
|
+
- Preserve all schema details from original tickets
|
|
414
|
+
|
|
415
|
+
2. **Reorder Tickets by Feature:**
|
|
416
|
+
- Group related backend/frontend/test tickets together
|
|
417
|
+
- Enforce: backend → frontend → test pattern for each feature
|
|
418
|
+
- Do NOT group all backends, then all frontends, then all tests
|
|
419
|
+
- Each feature is a cohesive unit (backend + frontend + test)
|
|
420
|
+
|
|
421
|
+
3. **Renumber Ticket IDs:**
|
|
422
|
+
- After combining/reordering, ensure sequential IDs
|
|
423
|
+
- Update ticket IDs to match new order
|
|
424
|
+
- Example: If LOGIC-BACKEND-3 becomes first backend, rename to LOGIC-BACKEND-1
|
|
425
|
+
|
|
426
|
+
4. **Validate Test User Info:**
|
|
427
|
+
- Ensure all WEB-TEST tickets have credentials at top of description
|
|
428
|
+
- If missing, add placeholder credentials
|
|
429
|
+
|
|
430
|
+
**ORDERING EXAMPLES:**
|
|
431
|
+
|
|
432
|
+
${isScaffoldMode
|
|
433
|
+
? `**Scaffold Mode (with both SCAFFOLD and LOGIC):**
|
|
434
|
+
[
|
|
435
|
+
// SCAFFOLD batch
|
|
436
|
+
{ "id": "SCAFFOLD-SCHEMA-1" }, // ONE schema for all infrastructure
|
|
437
|
+
{ "id": "SCAFFOLD-BACKEND-1" }, // Infrastructure feature 1 backend
|
|
438
|
+
{ "id": "SCAFFOLD-FRONTEND-1" }, // Infrastructure feature 1 frontend
|
|
439
|
+
{ "id": "SCAFFOLD-WEB-TEST-1" }, // Infrastructure feature 1 test
|
|
440
|
+
{ "id": "SCAFFOLD-BACKEND-2" }, // Infrastructure feature 2 backend
|
|
441
|
+
{ "id": "SCAFFOLD-FRONTEND-2" }, // Infrastructure feature 2 frontend
|
|
442
|
+
|
|
443
|
+
// LOGIC batch
|
|
444
|
+
{ "id": "LOGIC-SCHEMA-1" }, // ONE schema for all business
|
|
445
|
+
{ "id": "LOGIC-BACKEND-1" }, // Business feature 1 backend
|
|
446
|
+
{ "id": "LOGIC-FRONTEND-1" }, // Business feature 1 frontend
|
|
447
|
+
{ "id": "LOGIC-WEB-TEST-1" }, // Business feature 1 test
|
|
448
|
+
{ "id": "LOGIC-BACKEND-2" }, // Business feature 2 backend
|
|
449
|
+
{ "id": "LOGIC-FRONTEND-2" }, // Business feature 2 frontend
|
|
450
|
+
{ "id": "LOGIC-WEB-TEST-2" } // Business feature 2 test
|
|
451
|
+
]`
|
|
452
|
+
: `**Logic-Only Mode:**
|
|
453
|
+
[
|
|
454
|
+
{ "id": "LOGIC-SCHEMA-1" }, // ONE schema for all business
|
|
455
|
+
{ "id": "LOGIC-BACKEND-1" }, // Feature 1 backend
|
|
456
|
+
{ "id": "LOGIC-FRONTEND-1" }, // Feature 1 frontend
|
|
457
|
+
{ "id": "LOGIC-WEB-TEST-1" }, // Feature 1 test
|
|
458
|
+
{ "id": "LOGIC-BACKEND-2" }, // Feature 2 backend
|
|
459
|
+
{ "id": "LOGIC-FRONTEND-2" }, // Feature 2 frontend
|
|
460
|
+
{ "id": "LOGIC-WEB-TEST-2" } // Feature 2 test
|
|
461
|
+
]`}
|
|
462
|
+
|
|
463
|
+
**OUTPUT FORMAT:**
|
|
464
|
+
Return ONLY a valid JSON object with this exact structure:
|
|
465
|
+
{
|
|
466
|
+
"validationIssues": [
|
|
467
|
+
"Issue 1 found and fixed",
|
|
468
|
+
"Issue 2 found and fixed"
|
|
469
|
+
],
|
|
470
|
+
"fixedTickets": [
|
|
471
|
+
{ /* all ticket objects in corrected order */ }
|
|
472
|
+
]
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
**CRITICAL INSTRUCTIONS:**
|
|
476
|
+
- Return ONLY valid JSON (no markdown, no code blocks, no explanations)
|
|
477
|
+
- fixedTickets array must contain ALL tickets (not just changed ones)
|
|
478
|
+
- Preserve all ticket content (descriptions, acceptance criteria, effort, category)
|
|
479
|
+
- Only fix structure, ordering, and numbering issues
|
|
480
|
+
- If no issues found, return empty validationIssues array with original tickets
|
|
481
|
+
- Ensure sequential numbering matches the new order
|
|
482
|
+
|
|
483
|
+
Begin validation and fixing now.`;
|
|
550
484
|
}
|
|
551
485
|
/**
|
|
552
|
-
*
|
|
486
|
+
* Review and fix tickets with Claude
|
|
553
487
|
*/
|
|
554
|
-
async function
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
scaffold: '🏗️',
|
|
564
|
-
logic: '💡',
|
|
565
|
-
'db-test': '🧪',
|
|
566
|
-
'web-test': '🌐',
|
|
567
|
-
};
|
|
568
|
-
const phaseName = {
|
|
569
|
-
schema: 'Schema',
|
|
570
|
-
backend: 'Backend',
|
|
571
|
-
frontend: 'Frontend',
|
|
572
|
-
'db-test': 'DB Test',
|
|
573
|
-
'web-test': 'Web Test',
|
|
574
|
-
};
|
|
575
|
-
const typeName = {
|
|
576
|
-
scaffold: 'Scaffold',
|
|
577
|
-
logic: 'Logic',
|
|
578
|
-
'db-test': 'DB Test',
|
|
579
|
-
'web-test': 'Web Test',
|
|
580
|
-
};
|
|
581
|
-
console.log(`\n${'='.repeat(60)}`);
|
|
582
|
-
console.log(`${phaseEmoji[phase]} ${typeEmoji[ticketType]} ${phaseName[phase]} ${typeName[ticketType]} Tickets`);
|
|
583
|
-
console.log(`${'='.repeat(60)}\n`);
|
|
584
|
-
const systemPrompt = buildTicketGenerationPrompt(phase, ticketType, requirementsContent, projectPath, isScaffoldMode, previousTickets);
|
|
585
|
-
const agentResult = await runAgent(`Generate ${phaseName[phase]} ${typeName[ticketType]} tickets from the requirements.`, {
|
|
586
|
-
systemPrompt,
|
|
488
|
+
async function reviewAndFixTickets(initialTickets, requirementsContent, isScaffoldMode, projectPath) {
|
|
489
|
+
console.log(`\n${'='.repeat(80)}`);
|
|
490
|
+
console.log('🔍 Reviewing and Validating Tickets');
|
|
491
|
+
console.log(`${'='.repeat(80)}\n`);
|
|
492
|
+
const reviewPrompt = buildReviewAndFixPrompt(initialTickets, requirementsContent, isScaffoldMode);
|
|
493
|
+
const reviewResult = await runAgent('Review and fix generated tickets', {
|
|
494
|
+
systemPrompt: reviewPrompt,
|
|
495
|
+
maxTurns: 20,
|
|
496
|
+
verbosity: 'minimal',
|
|
587
497
|
cwd: projectPath,
|
|
588
|
-
maxTurns: 25,
|
|
589
|
-
verbosity: 'normal',
|
|
590
|
-
captureConversation: true,
|
|
591
498
|
});
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
499
|
+
try {
|
|
500
|
+
// Parse review result
|
|
501
|
+
const jsonMatch = reviewResult.response.match(/\{[\s\S]*"fixedTickets"[\s\S]*\}/);
|
|
502
|
+
if (!jsonMatch) {
|
|
503
|
+
throw new Error('No valid review result found in response');
|
|
504
|
+
}
|
|
505
|
+
const parsed = JSON.parse(jsonMatch[0]);
|
|
506
|
+
if (!parsed.fixedTickets || !Array.isArray(parsed.fixedTickets)) {
|
|
507
|
+
throw new Error('Invalid review result: fixedTickets must be an array');
|
|
508
|
+
}
|
|
509
|
+
// Validate fixed tickets
|
|
510
|
+
const validTypes = ['schema', 'backend', 'frontend', 'test'];
|
|
511
|
+
for (const ticket of parsed.fixedTickets) {
|
|
512
|
+
if (!ticket.id || !ticket.title || !ticket.description || !ticket.type) {
|
|
513
|
+
throw new Error(`Invalid ticket structure in review result: ${JSON.stringify(ticket)}`);
|
|
514
|
+
}
|
|
515
|
+
if (!validTypes.includes(ticket.type)) {
|
|
516
|
+
throw new Error(`Invalid type in reviewed ticket ${ticket.id}: ${ticket.type}`);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
return parsed;
|
|
520
|
+
}
|
|
521
|
+
catch (error) {
|
|
522
|
+
console.error('\n❌ Review step failed to parse or validate tickets');
|
|
523
|
+
console.error('Error:', error);
|
|
524
|
+
console.error('\nReview response (first 1000 chars):', reviewResult.response.substring(0, 1000));
|
|
525
|
+
throw new Error(`Ticket review and validation failed. Please check the review prompt and try again.\n` +
|
|
526
|
+
`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
/**
|
|
530
|
+
* Write tickets to output file
|
|
531
|
+
*/
|
|
532
|
+
function writeTicketsToFile(outputPath, tickets) {
|
|
533
|
+
const outputData = {
|
|
534
|
+
generatedAt: new Date().toISOString(),
|
|
535
|
+
totalTickets: tickets.length,
|
|
603
536
|
tickets,
|
|
604
|
-
tokensUsed: agentResult.tokensUsed,
|
|
605
|
-
cost: agentResult.cost,
|
|
606
|
-
conversationMessages: agentResult.conversationMessages || [],
|
|
607
537
|
};
|
|
538
|
+
writeFileSync(outputPath, JSON.stringify(outputData, null, 2), 'utf-8');
|
|
608
539
|
}
|
|
609
540
|
/**
|
|
610
|
-
* Core tickets logic
|
|
541
|
+
* Core tickets logic - Simplified to single agent call
|
|
611
542
|
*/
|
|
612
543
|
export async function ticketsCore(options) {
|
|
613
544
|
const { directory, scaffold = false } = options;
|
|
@@ -624,7 +555,7 @@ export async function ticketsCore(options) {
|
|
|
624
555
|
throw new Error(`Path is not a directory: ${projectPath}\n` + `Please provide a valid directory path.`);
|
|
625
556
|
}
|
|
626
557
|
console.log(`📁 Using project directory: ${projectPath}`);
|
|
627
|
-
console.log(`🏗️ Mode: ${isScaffoldMode ? 'Scaffold (
|
|
558
|
+
console.log(`🏗️ Mode: ${isScaffoldMode ? 'Scaffold (template adaptation + business logic)' : 'Logic-only (business features)'}\n`);
|
|
628
559
|
// 2. Get requirements content (from prompt or file)
|
|
629
560
|
let requirementsContent;
|
|
630
561
|
if (options.prompt && options.path) {
|
|
@@ -659,143 +590,90 @@ export async function ticketsCore(options) {
|
|
|
659
590
|
requirementsContent = readFileSync(requirementsPath, 'utf-8');
|
|
660
591
|
console.log(`📄 Loaded ${defaultPath} (${requirementsContent.length} characters)\n`);
|
|
661
592
|
}
|
|
662
|
-
// 3. Determine output path
|
|
593
|
+
// 3. Determine output path
|
|
663
594
|
const outputFilename = options.output || 'tickets.json';
|
|
664
595
|
const outputPath = join(projectPath, outputFilename);
|
|
665
|
-
// 4.
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
totalCacheReadTokens += result.tokensUsed.cacheRead;
|
|
692
|
-
totalCost += result.cost;
|
|
693
|
-
allConversationMessages.push(...result.conversationMessages);
|
|
694
|
-
};
|
|
695
|
-
// ==================== SCAFFOLD MODE ====================
|
|
696
|
-
if (isScaffoldMode) {
|
|
697
|
-
console.log('\n' + '='.repeat(80));
|
|
698
|
-
console.log('🏗️ SCAFFOLD BATCH - Infrastructure Setup');
|
|
699
|
-
console.log('='.repeat(80));
|
|
700
|
-
// Track batch tickets for test generation
|
|
701
|
-
let batchSchemaTickets = [];
|
|
702
|
-
let batchBackendTickets = [];
|
|
703
|
-
let batchFrontendTickets = [];
|
|
704
|
-
// 1. Schema Scaffold
|
|
705
|
-
const schemaScaffoldResult = await generatePhaseTickets('schema', 'scaffold', requirementsContent, projectPath, outputPath, allTickets, isScaffoldMode);
|
|
706
|
-
addMetrics(schemaScaffoldResult);
|
|
707
|
-
batchSchemaTickets = schemaScaffoldResult.tickets;
|
|
708
|
-
// 2. DB Test (validate scaffold schema)
|
|
709
|
-
addMetrics(await generatePhaseTickets('db-test', 'scaffold', requirementsContent, projectPath, outputPath, allTickets, isScaffoldMode, { schema: batchSchemaTickets }));
|
|
710
|
-
// 3. Backend Scaffold
|
|
711
|
-
const backendScaffoldResult = await generatePhaseTickets('backend', 'scaffold', requirementsContent, projectPath, outputPath, allTickets, isScaffoldMode);
|
|
712
|
-
addMetrics(backendScaffoldResult);
|
|
713
|
-
batchBackendTickets = backendScaffoldResult.tickets;
|
|
714
|
-
// 4. Frontend Scaffold
|
|
715
|
-
const frontendScaffoldResult = await generatePhaseTickets('frontend', 'scaffold', requirementsContent, projectPath, outputPath, allTickets, isScaffoldMode);
|
|
716
|
-
addMetrics(frontendScaffoldResult);
|
|
717
|
-
batchFrontendTickets = frontendScaffoldResult.tickets;
|
|
718
|
-
// 5. Web Tests (validate scaffold E2E)
|
|
719
|
-
addMetrics(await generatePhaseTickets('web-test', 'scaffold', requirementsContent, projectPath, outputPath, allTickets, isScaffoldMode, {
|
|
720
|
-
backend: batchBackendTickets,
|
|
721
|
-
frontend: batchFrontendTickets,
|
|
722
|
-
webTestStartNumber: 1,
|
|
723
|
-
}));
|
|
724
|
-
// ==================== LOGIC BATCH ====================
|
|
725
|
-
console.log('\n' + '='.repeat(80));
|
|
726
|
-
console.log('💡 LOGIC BATCH - Business Functionality');
|
|
727
|
-
console.log('='.repeat(80));
|
|
728
|
-
// Reset batch tracking for logic
|
|
729
|
-
batchSchemaTickets = [];
|
|
730
|
-
batchBackendTickets = [];
|
|
731
|
-
batchFrontendTickets = [];
|
|
732
|
-
// 1. Schema Logic
|
|
733
|
-
const schemaLogicResult = await generatePhaseTickets('schema', 'logic', requirementsContent, projectPath, outputPath, allTickets, isScaffoldMode);
|
|
734
|
-
addMetrics(schemaLogicResult);
|
|
735
|
-
batchSchemaTickets = schemaLogicResult.tickets;
|
|
736
|
-
// 2. DB Test (validate logic schema)
|
|
737
|
-
addMetrics(await generatePhaseTickets('db-test', 'logic', requirementsContent, projectPath, outputPath, allTickets, isScaffoldMode, { schema: batchSchemaTickets }));
|
|
738
|
-
// 3. Backend Logic
|
|
739
|
-
const backendLogicResult = await generatePhaseTickets('backend', 'logic', requirementsContent, projectPath, outputPath, allTickets, isScaffoldMode);
|
|
740
|
-
addMetrics(backendLogicResult);
|
|
741
|
-
batchBackendTickets = backendLogicResult.tickets;
|
|
742
|
-
// 4. Frontend Logic
|
|
743
|
-
const frontendLogicResult = await generatePhaseTickets('frontend', 'logic', requirementsContent, projectPath, outputPath, allTickets, isScaffoldMode);
|
|
744
|
-
addMetrics(frontendLogicResult);
|
|
745
|
-
batchFrontendTickets = frontendLogicResult.tickets;
|
|
746
|
-
// 5. Web Tests (validate logic E2E)
|
|
747
|
-
const currentWebTestCount = allTickets.filter((t) => t.id.startsWith('WEB-TEST-')).length;
|
|
748
|
-
addMetrics(await generatePhaseTickets('web-test', 'logic', requirementsContent, projectPath, outputPath, allTickets, isScaffoldMode, {
|
|
749
|
-
backend: batchBackendTickets,
|
|
750
|
-
frontend: batchFrontendTickets,
|
|
751
|
-
webTestStartNumber: currentWebTestCount + 1,
|
|
752
|
-
}));
|
|
596
|
+
// 4. Generate ALL tickets in a single comprehensive agent call
|
|
597
|
+
console.log(`\n${'='.repeat(80)}`);
|
|
598
|
+
console.log('🎯 Generating Tickets with Claude Code Agent');
|
|
599
|
+
console.log(`${'='.repeat(80)}\n`);
|
|
600
|
+
const systemPrompt = buildTicketPrompt(requirementsContent, projectPath, isScaffoldMode);
|
|
601
|
+
const agentResult = await runAgent('Generate all tickets from requirements', {
|
|
602
|
+
systemPrompt,
|
|
603
|
+
cwd: projectPath,
|
|
604
|
+
maxTurns: 40, // Give Claude enough turns to explore codebase and generate all tickets
|
|
605
|
+
verbosity: 'normal',
|
|
606
|
+
captureConversation: true,
|
|
607
|
+
});
|
|
608
|
+
// 5. Parse initial tickets
|
|
609
|
+
const initialTickets = parseAllTickets(agentResult.response);
|
|
610
|
+
console.log(`\n✅ Initial generation: ${initialTickets.length} tickets created`);
|
|
611
|
+
// 6. Review and fix tickets
|
|
612
|
+
const reviewResult = await reviewAndFixTickets(initialTickets, requirementsContent, isScaffoldMode, projectPath);
|
|
613
|
+
// Display what was fixed
|
|
614
|
+
if (reviewResult.validationIssues.length > 0) {
|
|
615
|
+
console.log(`\n${'='.repeat(80)}`);
|
|
616
|
+
console.log('🔧 Validation Issues Found and Fixed:');
|
|
617
|
+
console.log(`${'='.repeat(80)}`);
|
|
618
|
+
reviewResult.validationIssues.forEach((issue, idx) => {
|
|
619
|
+
console.log(` ${idx + 1}. ${issue}`);
|
|
620
|
+
});
|
|
621
|
+
console.log();
|
|
753
622
|
}
|
|
754
623
|
else {
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
}
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
624
|
+
console.log('\n✅ No validation issues found - tickets are correctly structured\n');
|
|
625
|
+
}
|
|
626
|
+
const allTickets = reviewResult.fixedTickets;
|
|
627
|
+
// 8. Display tickets by batch (scaffold vs logic based on ID) and by type
|
|
628
|
+
const scaffoldTickets = allTickets.filter((t) => t.id.toUpperCase().startsWith('SCAFFOLD-'));
|
|
629
|
+
const logicTickets = allTickets.filter((t) => t.id.toUpperCase().startsWith('LOGIC-'));
|
|
630
|
+
const testTickets = allTickets.filter((t) => t.type === 'test');
|
|
631
|
+
if (scaffoldTickets.length > 0) {
|
|
632
|
+
console.log(`\n${'='.repeat(60)}`);
|
|
633
|
+
console.log('🏗️ SCAFFOLD Tickets (Template Adaptation)');
|
|
634
|
+
console.log(`${'='.repeat(60)}`);
|
|
635
|
+
scaffoldTickets.forEach((ticket) => {
|
|
636
|
+
const emoji = ticket.type === 'schema'
|
|
637
|
+
? '🗄️'
|
|
638
|
+
: ticket.type === 'backend'
|
|
639
|
+
? '⚙️'
|
|
640
|
+
: ticket.type === 'frontend'
|
|
641
|
+
? '🎨'
|
|
642
|
+
: '🌐'; // test type
|
|
643
|
+
console.log(` ${emoji} ${ticket.id}: ${ticket.title} (Effort: ${ticket.estimatedEffort}/10${ticket.category ? `, Category: ${ticket.category}` : ''})`);
|
|
644
|
+
});
|
|
645
|
+
}
|
|
646
|
+
if (logicTickets.length > 0) {
|
|
647
|
+
console.log(`\n${'='.repeat(60)}`);
|
|
648
|
+
console.log('💡 LOGIC Tickets (Business Functionality)');
|
|
649
|
+
console.log(`${'='.repeat(60)}`);
|
|
650
|
+
logicTickets.forEach((ticket) => {
|
|
651
|
+
const emoji = ticket.type === 'schema'
|
|
652
|
+
? '🗄️'
|
|
653
|
+
: ticket.type === 'backend'
|
|
654
|
+
? '⚙️'
|
|
655
|
+
: ticket.type === 'frontend'
|
|
656
|
+
? '🎨'
|
|
657
|
+
: '🌐'; // test type
|
|
658
|
+
console.log(` ${emoji} ${ticket.id}: ${ticket.title} (Effort: ${ticket.estimatedEffort}/10${ticket.category ? `, Category: ${ticket.category}` : ''})`);
|
|
659
|
+
});
|
|
660
|
+
}
|
|
661
|
+
if (testTickets.length > 0) {
|
|
662
|
+
console.log(`\n${'='.repeat(60)}`);
|
|
663
|
+
console.log('🧪 TEST Tickets (E2E Validation)');
|
|
664
|
+
console.log(`${'='.repeat(60)}`);
|
|
665
|
+
testTickets.forEach((ticket) => {
|
|
666
|
+
console.log(` 🌐 ${ticket.id}: ${ticket.title} (Effort: ${ticket.estimatedEffort}/10)`);
|
|
667
|
+
});
|
|
793
668
|
}
|
|
794
|
-
//
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
const
|
|
669
|
+
// 9. Write tickets to file
|
|
670
|
+
writeTicketsToFile(outputPath, allTickets);
|
|
671
|
+
console.log(`\n💾 Tickets saved to: ${outputPath}`);
|
|
672
|
+
// 10. Separate tickets by phase for compatibility with existing result structure
|
|
673
|
+
const schemaTickets = allTickets.filter((t) => t.type === 'schema');
|
|
674
|
+
const backendTickets = allTickets.filter((t) => t.type === 'backend');
|
|
675
|
+
const frontendTickets = allTickets.filter((t) => t.type === 'frontend');
|
|
676
|
+
// testTickets already declared above for display
|
|
799
677
|
return {
|
|
800
678
|
schemaTickets,
|
|
801
679
|
backendTickets,
|
|
@@ -803,14 +681,9 @@ export async function ticketsCore(options) {
|
|
|
803
681
|
testTickets,
|
|
804
682
|
totalTickets: allTickets.length,
|
|
805
683
|
projectPath,
|
|
806
|
-
tokensUsed:
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
cacheCreation: totalCacheCreationTokens,
|
|
810
|
-
cacheRead: totalCacheReadTokens,
|
|
811
|
-
},
|
|
812
|
-
cost: totalCost,
|
|
813
|
-
conversationMessages: allConversationMessages,
|
|
684
|
+
tokensUsed: agentResult.tokensUsed,
|
|
685
|
+
cost: agentResult.cost,
|
|
686
|
+
conversationMessages: agentResult.conversationMessages || [],
|
|
814
687
|
};
|
|
815
688
|
}
|
|
816
689
|
/**
|
|
@@ -832,35 +705,37 @@ export async function ticketsCommand(options) {
|
|
|
832
705
|
// Track metrics
|
|
833
706
|
logger.trackTokens(logContext, result.tokensUsed);
|
|
834
707
|
logContext.conversationMessages = result.conversationMessages;
|
|
835
|
-
//
|
|
708
|
+
// Get all tickets by batch (scaffold vs logic)
|
|
836
709
|
const scaffoldTickets = [
|
|
837
710
|
...result.schemaTickets,
|
|
838
711
|
...result.backendTickets,
|
|
839
712
|
...result.frontendTickets,
|
|
840
|
-
|
|
713
|
+
...result.testTickets,
|
|
714
|
+
].filter((t) => t.id.toUpperCase().startsWith('SCAFFOLD-'));
|
|
841
715
|
const logicTickets = [
|
|
842
716
|
...result.schemaTickets,
|
|
843
717
|
...result.backendTickets,
|
|
844
718
|
...result.frontendTickets,
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
console.log(`\n${'='.repeat(
|
|
719
|
+
...result.testTickets,
|
|
720
|
+
].filter((t) => t.id.toUpperCase().startsWith('LOGIC-'));
|
|
721
|
+
// Display summary
|
|
722
|
+
console.log(`\n${'='.repeat(80)}`);
|
|
849
723
|
console.log('📊 Ticket Generation Summary');
|
|
850
|
-
console.log(`${'='.repeat(
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
724
|
+
console.log(`${'='.repeat(80)}`);
|
|
725
|
+
if (scaffoldTickets.length > 0) {
|
|
726
|
+
console.log(`\n🏗️ Scaffold Tickets (Template Adaptation): ${scaffoldTickets.length}`);
|
|
727
|
+
console.log(` 🗄️ Schema: ${result.schemaTickets.filter((t) => t.id.toUpperCase().startsWith('SCAFFOLD-')).length} (auto-validated)`);
|
|
728
|
+
console.log(` ⚙️ Backend: ${result.backendTickets.filter((t) => t.id.toUpperCase().startsWith('SCAFFOLD-')).length}`);
|
|
729
|
+
console.log(` 🎨 Frontend: ${result.frontendTickets.filter((t) => t.id.toUpperCase().startsWith('SCAFFOLD-')).length}`);
|
|
730
|
+
console.log(` 🧪 Tests: ${result.testTickets.filter((t) => t.id.toUpperCase().startsWith('SCAFFOLD-')).length}`);
|
|
731
|
+
}
|
|
855
732
|
console.log(`\n💡 Logic Tickets (Business Functionality): ${logicTickets.length}`);
|
|
856
|
-
console.log(` 🗄️ Schema: ${result.schemaTickets.filter((t) => t.
|
|
857
|
-
console.log(` ⚙️ Backend: ${result.backendTickets.filter((t) => t.
|
|
858
|
-
console.log(` 🎨 Frontend: ${result.frontendTickets.filter((t) => t.
|
|
859
|
-
console.log(
|
|
860
|
-
console.log(` 🧪 Database Tests: ${dbTestTickets.length}`);
|
|
861
|
-
console.log(` 🌐 Web Tests: ${webTestTickets.length}`);
|
|
733
|
+
console.log(` 🗄️ Schema: ${result.schemaTickets.filter((t) => t.id.toUpperCase().startsWith('LOGIC-')).length} (auto-validated)`);
|
|
734
|
+
console.log(` ⚙️ Backend: ${result.backendTickets.filter((t) => t.id.toUpperCase().startsWith('LOGIC-')).length}`);
|
|
735
|
+
console.log(` 🎨 Frontend: ${result.frontendTickets.filter((t) => t.id.toUpperCase().startsWith('LOGIC-')).length}`);
|
|
736
|
+
console.log(` 🧪 Tests: ${result.testTickets.filter((t) => t.id.toUpperCase().startsWith('LOGIC-')).length}`);
|
|
862
737
|
console.log(`\n📝 Total Tickets: ${result.totalTickets}`);
|
|
863
|
-
console.log(`${'='.repeat(
|
|
738
|
+
console.log(`${'='.repeat(80)}\n`);
|
|
864
739
|
// Display cost breakdown
|
|
865
740
|
const costBreakdown = formatCostBreakdown({
|
|
866
741
|
cost: result.cost,
|
|
@@ -870,7 +745,7 @@ export async function ticketsCommand(options) {
|
|
|
870
745
|
filesReferenced: new Set(),
|
|
871
746
|
});
|
|
872
747
|
console.log(`💰 Total Cost: ${costBreakdown}\n`);
|
|
873
|
-
// Final confirmation
|
|
748
|
+
// Final confirmation
|
|
874
749
|
const outputFilename = options.output || 'tickets.json';
|
|
875
750
|
const outputPath = join(result.projectPath, outputFilename);
|
|
876
751
|
console.log(`✅ All tickets saved to: ${outputPath}\n`);
|