@kosuke-ai/cli 0.0.56 → 0.0.57

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/dist/index.d.ts +2 -0
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +82 -3
  4. package/dist/index.js.map +1 -1
  5. package/dist/kosuke/commands/analyse.d.ts.map +1 -1
  6. package/dist/kosuke/commands/analyse.js +42 -11
  7. package/dist/kosuke/commands/analyse.js.map +1 -1
  8. package/dist/kosuke/commands/build.d.ts.map +1 -1
  9. package/dist/kosuke/commands/build.js +4 -3
  10. package/dist/kosuke/commands/build.js.map +1 -1
  11. package/dist/kosuke/commands/fix.d.ts +21 -0
  12. package/dist/kosuke/commands/fix.d.ts.map +1 -0
  13. package/dist/kosuke/commands/fix.js +256 -0
  14. package/dist/kosuke/commands/fix.js.map +1 -0
  15. package/dist/kosuke/commands/getcode.d.ts.map +1 -1
  16. package/dist/kosuke/commands/getcode.js +33 -6
  17. package/dist/kosuke/commands/getcode.js.map +1 -1
  18. package/dist/kosuke/commands/lint.d.ts.map +1 -1
  19. package/dist/kosuke/commands/lint.js +25 -4
  20. package/dist/kosuke/commands/lint.js.map +1 -1
  21. package/dist/kosuke/commands/plan.d.ts +2 -2
  22. package/dist/kosuke/commands/plan.d.ts.map +1 -1
  23. package/dist/kosuke/commands/plan.js +98 -44
  24. package/dist/kosuke/commands/plan.js.map +1 -1
  25. package/dist/kosuke/commands/sync-rules.d.ts.map +1 -1
  26. package/dist/kosuke/commands/sync-rules.js +39 -4
  27. package/dist/kosuke/commands/sync-rules.js.map +1 -1
  28. package/dist/kosuke/commands/tickets.d.ts +6 -6
  29. package/dist/kosuke/commands/tickets.d.ts.map +1 -1
  30. package/dist/kosuke/commands/tickets.js +593 -216
  31. package/dist/kosuke/commands/tickets.js.map +1 -1
  32. package/dist/kosuke/commands/validate-tickets.d.ts +23 -0
  33. package/dist/kosuke/commands/validate-tickets.d.ts.map +1 -0
  34. package/dist/kosuke/commands/validate-tickets.js +360 -0
  35. package/dist/kosuke/commands/validate-tickets.js.map +1 -0
  36. package/dist/kosuke/types.d.ts +97 -27
  37. package/dist/kosuke/types.d.ts.map +1 -1
  38. package/dist/kosuke/utils/claude-agent.d.ts +0 -5
  39. package/dist/kosuke/utils/claude-agent.d.ts.map +1 -1
  40. package/dist/kosuke/utils/claude-agent.js +1 -117
  41. package/dist/kosuke/utils/claude-agent.js.map +1 -1
  42. package/dist/kosuke/utils/json-parser.d.ts +14 -0
  43. package/dist/kosuke/utils/json-parser.d.ts.map +1 -0
  44. package/dist/kosuke/utils/json-parser.js +40 -0
  45. package/dist/kosuke/utils/json-parser.js.map +1 -0
  46. package/dist/kosuke/utils/logger.d.ts +1 -1
  47. package/dist/kosuke/utils/logger.d.ts.map +1 -1
  48. package/dist/kosuke/utils/logger.js.map +1 -1
  49. package/dist/kosuke/utils/tickets-manager.d.ts +3 -33
  50. package/dist/kosuke/utils/tickets-manager.d.ts.map +1 -1
  51. package/dist/kosuke/utils/tickets-manager.js +12 -237
  52. package/dist/kosuke/utils/tickets-manager.js.map +1 -1
  53. package/dist/lib.d.ts +32 -24
  54. package/dist/lib.d.ts.map +1 -1
  55. package/dist/lib.js +29 -20
  56. package/dist/lib.js.map +1 -1
  57. package/dist/package.json +1 -1
  58. package/package.json +1 -1
@@ -10,16 +10,16 @@
10
10
  * SCAFFOLD MODE (--scaffold flag):
11
11
  * SCAFFOLD BATCH (template adaptation):
12
12
  * 1. SCAFFOLD-SCHEMA-1 (ONE ticket for ALL database infrastructure changes)
13
- * 2. SCAFFOLD-BACKEND-X → SCAFFOLD-FRONTEND-X → SCAFFOLD-WEB-TEST-X (feature-by-feature)
13
+ * 2. SCAFFOLD-BACKEND-X → SCAFFOLD-FRONTEND-X → SCAFFOLD-TEST-X (feature-by-feature)
14
14
  *
15
15
  * LOGIC BATCH (business functionality):
16
16
  * 1. LOGIC-SCHEMA-1 (ONE ticket for ALL business entities)
17
- * 2. LOGIC-BACKEND-X → LOGIC-FRONTEND-X → LOGIC-WEB-TEST-X (feature-by-feature)
17
+ * 2. LOGIC-BACKEND-X → LOGIC-FRONTEND-X → LOGIC-TEST-X (feature-by-feature)
18
18
  *
19
19
  * LOGIC-ONLY MODE (default):
20
20
  * Only generates LOGIC tickets for new features
21
21
  * 1. LOGIC-SCHEMA-1 (ONE ticket for ALL business entities)
22
- * 2. LOGIC-BACKEND-X → LOGIC-FRONTEND-X → LOGIC-WEB-TEST-X (feature-by-feature)
22
+ * 2. LOGIC-BACKEND-X → LOGIC-FRONTEND-X → LOGIC-TEST-X (feature-by-feature)
23
23
  *
24
24
  * Workflow:
25
25
  * 1. Claude Code Agent explores codebase and generates tickets
@@ -31,11 +31,14 @@
31
31
  * kosuke tickets --scaffold # Scaffold + logic from docs.md
32
32
  * kosuke tickets --path=custom.md # Custom requirements file
33
33
  */
34
- import { existsSync, readFileSync, statSync } from 'fs';
34
+ import { existsSync, readFileSync, statSync, writeFileSync } from 'fs';
35
35
  import { join, resolve } from 'path';
36
- import { formatCostBreakdown, runAgent } from '../utils/claude-agent.js';
36
+ import { formatCostBreakdown, runAgentStream } from '../utils/claude-agent.js';
37
+ import { extractTicketsJSON } from '../utils/json-parser.js';
37
38
  import { logger, setupCancellationHandler } from '../utils/logger.js';
38
- import { parseTickets, processAndWriteTickets } from '../utils/tickets-manager.js';
39
+ import { displayTicketsSummary, loadTicketsFile, writeTicketsFile, } from '../utils/tickets-manager.js';
40
+ import { fixCoreStream } from './fix.js';
41
+ import { validateTicketsCoreStream } from './validate-tickets.js';
39
42
  /**
40
43
  * Build unified system prompt for comprehensive ticket generation
41
44
  */
@@ -53,32 +56,57 @@ Scaffold tickets should:
53
56
  - 🎨 CUSTOMIZE infrastructure (landing page, email templates, branding, navigation)
54
57
 
55
58
  Examples of SCAFFOLD tickets:
56
- - "Remove organization/multi-tenancy support from auth"
57
- - "Simplify billing to single tier (remove pro/business tiers)"
59
+ - "Remove organization/multi-tenancy support from auth (backend + frontend)"
60
+ - "Simplify billing to single tier (backend + frontend)"
58
61
  - "Customize landing page for [specific use case]"
59
62
  - "Remove landing page entirely (internal tool)"
60
- - "Update email templates for [brand name]"
63
+ - "Update email templates and backend handlers for [brand name]"
61
64
 
62
65
  **SCAFFOLD Ticket Ordering - CRITICAL:**
63
66
  1. SCAFFOLD-SCHEMA-1 (ONE ticket for ALL database infrastructure changes, auto-validated)
64
- 2. SCAFFOLD-BACKEND-X SCAFFOLD-FRONTEND-X SCAFFOLD-WEB-TEST-X (feature-by-feature)
65
- 3. Each feature follows: backend frontend test pattern
66
-
67
- **SCAFFOLD Web Tests Must Validate:**
68
- - Authentication flow works without removed features (e.g., no org selection)
69
- - Navigation doesn't have broken links after removing pages
70
- - Landing page renders correctly with new branding
71
- - Signup flow works with simplified structure
72
- - Settings pages work without removed sections (e.g., billing removed)
73
- - Any customized templates (emails, landing) render correctly
67
+ 2. SCAFFOLD-REFACTOR-1, SCAFFOLD-REFACTOR-2, etc (each refactor touches BOTH backend + frontend)
68
+ 3. SCAFFOLD-TEST-1 through SCAFFOLD-TEST-5 (5 separate test tickets at the end)
69
+
70
+ **SCAFFOLD Test Structure (5 MANDATORY tickets):**
71
+ Create exactly 5 test tickets to validate all scaffold changes:
72
+
73
+ 1. **SCAFFOLD-TEST-1: Auth flow validation**
74
+ - Sign up without removed features (no org selection)
75
+ - Sign in flow works correctly
76
+ - Session management works
77
+ - No references to removed auth features
78
+
79
+ 2. **SCAFFOLD-TEST-2: Navigation validation**
80
+ - All navigation links work
81
+ - No broken routes from removed pages
82
+ - Settings navigation updated
83
+ - No 404 errors from removed features
84
+
85
+ 3. **SCAFFOLD-TEST-3: Landing page validation**
86
+ - Landing page renders with new branding
87
+ - Search/filter UI works
88
+ - CTAs function correctly
89
+ - No template/SaaS references
90
+
91
+ 4. **SCAFFOLD-TEST-4: Removed features validation**
92
+ - Billing pages removed (no /billing routes)
93
+ - Organization pages removed (no /org routes)
94
+ - Tasks/orders removed (no /tasks or /orders routes)
95
+ - Verify removed features are truly gone
96
+
97
+ 5. **SCAFFOLD-TEST-5: Settings and profile validation**
98
+ - Settings page loads without removed sections
99
+ - Profile updates work
100
+ - Email preferences work
101
+ - No billing or org settings visible
74
102
  `
75
103
  : '';
76
104
  const webTestGuidance = noTest
77
105
  ? ''
78
106
  : `
79
- **WEB TEST TICKETS - Playwright MCP E2E Tests:**
107
+ **TEST TICKETS - Playwright MCP E2E Tests:**
80
108
 
81
- Web test tickets are executed by Playwright MCP with Claude AI and must follow these guidelines:
109
+ Test tickets are executed by Playwright MCP with Claude AI and must follow these guidelines:
82
110
 
83
111
  **Test User Discovery:**
84
112
  1. **ALWAYS read seed files** to find test user credentials:
@@ -121,10 +149,10 @@ Each web test ticket MUST include:
121
149
  5. Click "Verify" button
122
150
  6. Expected: Redirected to dashboard/main app
123
151
 
124
- **Example Web Test Ticket:**
152
+ **Example Test Ticket:**
125
153
 
126
154
  {
127
- "id": "LOGIC-WEB-TEST-1",
155
+ "id": "LOGIC-TEST-1",
128
156
  "title": "E2E: User signup and create first task",
129
157
  "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",
130
158
  "type": "test",
@@ -153,29 +181,78 @@ Logic tickets should:
153
181
  - ⚙️ Build backend APIs for business features
154
182
  - 🎨 Create frontend UI for business features
155
183
 
156
- **LOGIC Ticket Ordering - CRITICAL RULES:**
157
-
158
- **RULE 1: ONLY ONE LOGIC-SCHEMA-1 ticket**
159
- - Combine ALL business entities into ONE schema ticket
160
- - ❌ WRONG: LOGIC-SCHEMA-1, LOGIC-SCHEMA-2, LOGIC-SCHEMA-3
161
- - ✅ CORRECT: LOGIC-SCHEMA-1 (all entities: properties, inquiries, favorites, etc.)
162
-
163
- **RULE 2: Feature-by-Feature Pattern (STRICT)**
164
- After schema, each feature MUST follow: engine → backend → frontend → test
184
+ Scaffold tickets (refactor type):
185
+ - 🔄 Each REFACTOR ticket should handle BOTH backend AND frontend changes together
186
+ - Don't split refactoring work across separate backend/frontend tickets
187
+ - Example: SCAFFOLD-REFACTOR-1 removes billing feature (database operations + API routes + UI pages)
165
188
 
166
- Example with 2 features:
167
- 1. LOGIC-SCHEMA-1 (ALL schemas combined)
168
- 2. LOGIC-ENGINE-1 (feature 1 engine)
169
- 3. LOGIC-BACKEND-1 (feature 1 backend)
170
- 4. LOGIC-FRONTEND-1 (feature 1 frontend)
171
- 5. LOGIC-WEB-TEST-1 (feature 1 test)
172
- 6. LOGIC-BACKEND-2 (feature 2 backend)
173
- 7. LOGIC-FRONTEND-2 (feature 2 frontend)
174
- 8. LOGIC-WEB-TEST-2 (feature 2 test)
189
+ **LOGIC Ticket Ordering - CRITICAL RULES:**
175
190
 
176
- **RULE 3: Do NOT group by type**
177
- WRONG: All backends, then all frontends, then all tests
178
- CORRECT: Feature-by-feature (backend frontend test per feature)
191
+ **RULE 1: LOGIC-SCHEMA-1 is MANDATORY and MUST be FIRST**
192
+ - The VERY FIRST LOGIC ticket MUST be LOGIC-SCHEMA-1
193
+ - This ticket combines ALL business entities into ONE schema ticket
194
+ - ❌ WRONG: Starting with LOGIC-BACKEND-1 (missing schema!)
195
+ - ❌ WRONG: LOGIC-SCHEMA-1, LOGIC-SCHEMA-2, LOGIC-SCHEMA-3 (only ONE schema ticket!)
196
+ - ✅ CORRECT: LOGIC-SCHEMA-1 (combines all database entities in one ticket)
197
+
198
+ **RULE 2: Feature-by-Feature Pattern (MANDATORY) - NEVER GROUP BY TYPE**
199
+
200
+ After LOGIC-SCHEMA-1, you MUST follow this STRICT pattern for EVERY feature:
201
+ **BACKEND → FRONTEND → TEST** (complete each feature before starting next)
202
+
203
+ ⚠️ **YOU WILL GENERATE TICKETS GROUPED BY TYPE IF YOU'RE NOT CAREFUL!**
204
+
205
+ The NATURAL INSTINCT is to group by type, but this is ABSOLUTELY FORBIDDEN:
206
+
207
+ ❌ **ABSOLUTELY FORBIDDEN - Grouping by Type (COMMON MISTAKE):**
208
+ LOGIC-SCHEMA-1 ← schema (correct)
209
+ LOGIC-BACKEND-1 ← properties backend
210
+ LOGIC-BACKEND-2 ← favorites backend ❌ STOP! This is type grouping!
211
+ LOGIC-BACKEND-3 ← inquiries backend ❌ All backends together is WRONG!
212
+ LOGIC-BACKEND-4 ← dashboard backend
213
+ LOGIC-FRONTEND-1 ← properties frontend ❌ All frontends grouped!
214
+ LOGIC-FRONTEND-2 ← favorites frontend
215
+ LOGIC-FRONTEND-3 ← inquiries frontend
216
+ LOGIC-FRONTEND-4 ← dashboard frontend
217
+ LOGIC-TEST-1 ← properties test ❌ All tests grouped!
218
+ LOGIC-TEST-2 ← favorites test
219
+ LOGIC-TEST-3 ← inquiries test
220
+
221
+ This is WRONG! All backends grouped together, then all frontends, then all tests.
222
+ THIS IS THE MOST COMMON MISTAKE - DO NOT MAKE IT!
223
+
224
+ ✅ **REQUIRED - Feature-by-Feature (ONE FEATURE AT A TIME):**
225
+ LOGIC-SCHEMA-1 (schemas for ALL features - ALWAYS FIRST)
226
+ LOGIC-BACKEND-1 (properties backend API) ← Feature 1 backend
227
+ LOGIC-FRONTEND-1 (properties frontend UI) ← Feature 1 frontend
228
+ LOGIC-TEST-1 (properties test) ← Feature 1 test ✓ Complete!
229
+ LOGIC-BACKEND-2 (favorites backend API) ← Feature 2 backend
230
+ LOGIC-FRONTEND-2 (favorites frontend UI) ← Feature 2 frontend
231
+ LOGIC-TEST-2 (favorites test) ← Feature 2 test ✓ Complete!
232
+ LOGIC-BACKEND-3 (inquiries backend API) ← Feature 3 backend
233
+ LOGIC-FRONTEND-3 (inquiries frontend UI) ← Feature 3 frontend
234
+ LOGIC-TEST-3 (inquiries test) ← Feature 3 test ✓ Complete!
235
+
236
+ This is CORRECT! Each feature completed (backend → frontend → test) before next feature.
237
+
238
+ **WHY THIS MATTERS:**
239
+ - Each complete feature can be developed and tested independently
240
+ - Clear progress tracking (3 features done vs 0 features done)
241
+ - Natural development workflow (build API, then UI, then test)
242
+ - Avoids having half-built features scattered across ticket list
243
+
244
+ **WHY Feature-by-Feature?**
245
+ - Each feature can be developed and tested independently
246
+ - Clear dependency chains (backend ready → build frontend → test both)
247
+ - Easier to track progress per feature
248
+ - Natural workflow for developers
249
+
250
+ **RULE 3: Engine tickets (optional, only if needed)**
251
+ If Python engine endpoints are needed, insert AFTER schema, BEFORE first backend:
252
+ 1. LOGIC-SCHEMA-1
253
+ 2. LOGIC-ENGINE-1 (if needed for complex algorithms)
254
+ 3. LOGIC-BACKEND-1 → LOGIC-FRONTEND-1 → LOGIC-TEST-1
255
+ 4. LOGIC-BACKEND-2 → LOGIC-FRONTEND-2 → LOGIC-TEST-2
179
256
 
180
257
  **Ticket Granularity:**
181
258
  - Schema: EXACTLY ONE ticket for LOGIC batch (combines ALL entities)
@@ -215,212 +292,497 @@ Example with 2 features:
215
292
  - **Use BACKEND (Next.js)** for: CRUD operations, auth logic, business rules, anything TypeScript handles well (90% of features)
216
293
  - **Use ENGINE (Python)** for: ML/AI, data science (numpy/pandas), complex algorithms, PDF/document parsing, image processing, or when Python libraries are required
217
294
 
218
- **Ticket Structure:**
295
+ **Ticket Structure (CRITICAL - CORRECT ID FORMAT REQUIRED):**
296
+
297
+ Each ticket MUST have an ID in the format: {BATCH}-{TYPE}-{NUMBER}
298
+ - Global sequential numbering within each batch
299
+ - ❌ WRONG: "SCAFFOLD-1", "SCAFFOLD-2", "LOGIC-1", "LOGIC-2"
300
+ - ✅ CORRECT: "SCAFFOLD-SCHEMA-1", "SCAFFOLD-REFACTOR-2", "LOGIC-BACKEND-1", "LOGIC-FRONTEND-2"
301
+
302
+ Valid ID patterns:
303
+ - SCAFFOLD batch: SCAFFOLD-SCHEMA-{n}, SCAFFOLD-REFACTOR-{n}, SCAFFOLD-TEST-{n}
304
+ - LOGIC batch: LOGIC-SCHEMA-{n}, LOGIC-ENGINE-{n}, LOGIC-BACKEND-{n}, LOGIC-FRONTEND-{n}, LOGIC-TEST-{n}
305
+
306
+ Examples with global numbering:
307
+ - [SCAFFOLD-SCHEMA-1, SCAFFOLD-REFACTOR-2, SCAFFOLD-REFACTOR-3, SCAFFOLD-TEST-4, SCAFFOLD-TEST-5]
308
+ - [LOGIC-SCHEMA-1, LOGIC-BACKEND-2, LOGIC-FRONTEND-3, LOGIC-TEST-4, LOGIC-BACKEND-5, LOGIC-FRONTEND-6]
309
+
219
310
  Each ticket must be a JSON object with:
220
- - id: string (e.g., "SCAFFOLD-SCHEMA-1", "LOGIC-ENGINE-1", "LOGIC-BACKEND-2", "SCAFFOLD-WEB-TEST-1")
311
+ - id: string (MUST include type: "SCAFFOLD-SCHEMA-1", "LOGIC-BACKEND-2", etc.)
221
312
  - title: string (clear, concise title)
222
313
  - description: string (detailed description with acceptance criteria)
223
- - type: "schema" | "engine" | "backend" | "frontend" | "test"
314
+ - type: "schema" | "refactor" | "engine" | "backend" | "frontend" | "test"
224
315
  - estimatedEffort: number (1-10, where 1=very easy, 10=very complex)
225
316
  - status: "Todo"
226
317
  - category: string (e.g., "auth", "billing", "user-management", "tasks")
227
318
 
319
+ **Type Guidelines:**
320
+ - "schema": Database schema changes only
321
+ - "refactor": Template adaptation (SCAFFOLD only) - touches BOTH backend + frontend
322
+ - "engine": Python engine endpoints (LOGIC only)
323
+ - "backend": Backend/API implementation (LOGIC only)
324
+ - "frontend": Frontend UI implementation (LOGIC only)
325
+ - "test": E2E web tests (both SCAFFOLD and LOGIC)
326
+
228
327
  **Output Format:**
229
328
  Return ONLY a valid JSON array of ALL tickets in the correct order. No markdown, no code blocks, just raw JSON.
230
329
 
231
- Example (Full Ordering Structure - Scaffold Mode):
330
+ Example (Full Ordering Structure - Scaffold Mode with 2 LOGIC features):
232
331
  [
233
332
  {
234
333
  "id": "SCAFFOLD-SCHEMA-1",
235
- "title": "Remove organizations and simplify auth schema",
236
- "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",
334
+ "title": "Remove unused template features from schema",
335
+ "description": "Remove template features from database:\\n- Drop unused tables\\n- Remove foreign keys from users table\\n- Simplify schema\\n\\nAcceptance Criteria:\\n- Unused tables removed\\n- Schema simplified\\n- Migrations validated automatically\\n- No schema errors",
237
336
  "type": "schema",
238
337
  "estimatedEffort": 5,
239
338
  "status": "Todo",
240
- "category": "auth"
339
+ "category": "cleanup"
241
340
  },
242
341
  {
243
- "id": "SCAFFOLD-BACKEND-1",
244
- "title": "Remove organization tRPC routers",
245
- "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",
246
- "type": "backend",
247
- "estimatedEffort": 4,
342
+ "id": "SCAFFOLD-REFACTOR-1",
343
+ "title": "Remove organization/multi-tenancy feature (backend + frontend)",
344
+ "description": "Remove organization feature from entire stack:\\n\\nBackend:\\n- Delete organization tRPC routers\\n- Remove org-related schemas\\n- Clean up auth middleware\\n\\nFrontend:\\n- Delete organization pages\\n- Remove org selection from signup\\n- Update navigation\\n- Simplify user settings\\n\\nAcceptance Criteria:\\n- All org-related code removed\\n- Auth flow works without orgs\\n- Navigation simplified\\n- No broken links or imports\\n- Type safety maintained",
345
+ "type": "refactor",
346
+ "estimatedEffort": 7,
248
347
  "status": "Todo",
249
- "category": "auth"
348
+ "category": "cleanup"
250
349
  },
251
350
  {
252
- "id": "SCAFFOLD-FRONTEND-1",
253
- "title": "Remove organization pages and navigation",
254
- "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",
255
- "type": "frontend",
256
- "estimatedEffort": 5,
351
+ "id": "SCAFFOLD-REFACTOR-2",
352
+ "title": "Simplify billing to single tier (backend + frontend)",
353
+ "description": "Simplify billing system:\\n\\nBackend:\\n- Remove tier logic from routers\\n- Simplify subscription schemas\\n- Update billing webhooks\\n\\nFrontend:\\n- Remove pricing page\\n- Simplify settings billing section\\n- Update subscription UI\\n\\nAcceptance Criteria:\\n- Single tier billing works\\n- No pro/business tier references\\n- Settings page simplified\\n- Webhooks handle new structure",
354
+ "type": "refactor",
355
+ "estimatedEffort": 6,
257
356
  "status": "Todo",
258
- "category": "auth"
357
+ "category": "billing"
259
358
  },
260
359
  {
261
- "id": "SCAFFOLD-WEB-TEST-1",
262
- "title": "E2E: Validate simplified auth flow",
263
- "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",
360
+ "id": "SCAFFOLD-TEST-1",
361
+ "title": "E2E: Auth flow validation",
362
+ "description": "**Test User Credentials:**\\n- Email: john+kosuke_test@example.com\\n- OTP Code: 424242\\n\\n**Test Steps:**\\n\\n1. **Sign up flow**\\n - Navigate to /sign-up\\n - Enter test email\\n - Enter OTP code\\n - Expected: Successful signup\\n\\n2. **Sign in flow**\\n - Navigate to /sign-in\\n - Enter test credentials\\n - Expected: Successful login\\n\\n**Acceptance Criteria:**\\n- Auth flows work correctly\\n- No errors in removed features",
264
363
  "type": "test",
265
- "estimatedEffort": 4,
364
+ "estimatedEffort": 3,
266
365
  "status": "Todo",
267
366
  "category": "auth"
268
367
  },
368
+ {
369
+ "id": "SCAFFOLD-TEST-2",
370
+ "title": "E2E: Navigation validation",
371
+ "description": "**Test Steps:**\\n\\n1. **Verify navigation**\\n - Check navigation structure\\n - Click each navigation link\\n - Expected: No 404 errors\\n\\n**Acceptance Criteria:**\\n- Navigation works correctly\\n- No broken links from removed features",
372
+ "type": "test",
373
+ "estimatedEffort": 2,
374
+ "status": "Todo",
375
+ "category": "navigation"
376
+ },
377
+ {
378
+ "id": "SCAFFOLD-TEST-3",
379
+ "title": "E2E: Landing page validation",
380
+ "description": "**Test Steps:**\\n\\n1. **Verify landing page**\\n - Navigate to /\\n - Check page content\\n - Test CTAs\\n\\n**Acceptance Criteria:**\\n- Landing page works\\n- All CTAs functional",
381
+ "type": "test",
382
+ "estimatedEffort": 2,
383
+ "status": "Todo",
384
+ "category": "landing"
385
+ },
386
+ {
387
+ "id": "SCAFFOLD-TEST-4",
388
+ "title": "E2E: Removed features validation",
389
+ "description": "**Test Steps:**\\n\\n1. **Verify removed routes**\\n - Try accessing removed routes\\n - Expected: 404 errors\\n\\n**Acceptance Criteria:**\\n- Removed features truly gone\\n- No accessible old routes",
390
+ "type": "test",
391
+ "estimatedEffort": 2,
392
+ "status": "Todo",
393
+ "category": "cleanup"
394
+ },
395
+ {
396
+ "id": "SCAFFOLD-TEST-5",
397
+ "title": "E2E: Settings validation",
398
+ "description": "**Test User Credentials:**\\n- Email: john+kosuke_test@example.com\\n- OTP Code: 424242\\n\\n**Test Steps:**\\n\\n1. **Access settings**\\n - Sign in as test user\\n - Navigate to /settings\\n - Test profile updates\\n\\n**Acceptance Criteria:**\\n- Settings work correctly\\n- Profile management functional",
399
+ "type": "test",
400
+ "estimatedEffort": 3,
401
+ "status": "Todo",
402
+ "category": "settings"
403
+ },
269
404
  {
270
405
  "id": "LOGIC-SCHEMA-1",
271
- "title": "Create tasks schema",
272
- "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",
406
+ "title": "Create database schema for business entities",
407
+ "description": "Create database schema for ALL business entities:\\n- Create enums for entity types\\n- Create main entity tables\\n- Create relationship tables\\n- Export inferred types\\n\\nAcceptance Criteria:\\n- All tables created\\n- Enums defined at database level\\n- Migrations validated automatically\\n- No schema errors",
273
408
  "type": "schema",
274
- "estimatedEffort": 4,
409
+ "estimatedEffort": 8,
275
410
  "status": "Todo",
276
- "category": "tasks"
411
+ "category": "schema"
277
412
  },
278
413
  {
279
414
  "id": "LOGIC-BACKEND-1",
280
- "title": "Create tasks tRPC router",
281
- "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",
415
+ "title": "Create feature A tRPC router",
416
+ "description": "Create backend API for feature A:\\n- Create schemas\\n- Create router\\n- Implement CRUD operations\\n- Server-side filtering and pagination\\n\\nAcceptance Criteria:\\n- All CRUD operations work\\n- Authorization enforced\\n- Type-safe implementation",
282
417
  "type": "backend",
283
- "estimatedEffort": 6,
418
+ "estimatedEffort": 7,
284
419
  "status": "Todo",
285
- "category": "tasks"
420
+ "category": "feature-a"
286
421
  },
287
422
  {
288
423
  "id": "LOGIC-FRONTEND-1",
289
- "title": "Create tasks page with list and filters",
290
- "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",
424
+ "title": "Create feature A UI",
425
+ "description": "Create UI for feature A:\\n- Create page components\\n- Add list view with filters\\n- Add search functionality\\n- Add pagination\\n\\nAcceptance Criteria:\\n- UI displays correctly\\n- Filters work server-side\\n- Search functional\\n- Responsive design",
291
426
  "type": "frontend",
292
- "estimatedEffort": 7,
427
+ "estimatedEffort": 8,
293
428
  "status": "Todo",
294
- "category": "tasks"
429
+ "category": "feature-a"
295
430
  },
296
431
  {
297
- "id": "LOGIC-WEB-TEST-1",
298
- "title": "E2E: User creates and manages tasks",
299
- "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",
432
+ "id": "LOGIC-TEST-1",
433
+ "title": "E2E: Feature A workflow",
434
+ "description": "**Test User Credentials:**\\n- Email: john+kosuke_test@example.com\\n- OTP Code: 424242\\n\\n**Test Steps:**\\n\\n1. **Test main workflow**\\n - Navigate to feature page\\n - Test CRUD operations\\n - Test filters and search\\n\\n**Acceptance Criteria:**\\n- All operations work\\n- UI behaves correctly",
300
435
  "type": "test",
436
+ "estimatedEffort": 4,
437
+ "status": "Todo",
438
+ "category": "feature-a"
439
+ },
440
+ {
441
+ "id": "LOGIC-BACKEND-2",
442
+ "title": "Create feature B tRPC router",
443
+ "description": "Create backend API for feature B:\\n- Create schemas\\n- Create router\\n- Implement operations\\n\\nAcceptance Criteria:\\n- Operations work\\n- Authorization enforced",
444
+ "type": "backend",
445
+ "estimatedEffort": 4,
446
+ "status": "Todo",
447
+ "category": "feature-b"
448
+ },
449
+ {
450
+ "id": "LOGIC-FRONTEND-2",
451
+ "title": "Create feature B UI",
452
+ "description": "Create UI for feature B:\\n- Create page components\\n- Add main functionality\\n\\nAcceptance Criteria:\\n- UI works correctly\\n- Responsive design",
453
+ "type": "frontend",
301
454
  "estimatedEffort": 5,
302
455
  "status": "Todo",
303
- "category": "tasks"
456
+ "category": "feature-b"
457
+ },
458
+ {
459
+ "id": "LOGIC-TEST-2",
460
+ "title": "E2E: Feature B workflow",
461
+ "description": "**Test User Credentials:**\\n- Email: john+kosuke_test@example.com\\n- OTP Code: 424242\\n\\n**Test Steps:**\\n\\n1. **Test feature B**\\n - Navigate to feature page\\n - Test main operations\\n\\n**Acceptance Criteria:**\\n- Operations work correctly",
462
+ "type": "test",
463
+ "estimatedEffort": 5,
464
+ "status": "Todo",
465
+ "category": "feature-b"
304
466
  }
305
467
  ]
306
468
 
307
469
  **Critical Instructions:**
308
- 1. Explore the project directory thoroughly before generating tickets
309
- 2. ${isScaffoldMode ? 'For SCAFFOLD: Focus on template adaptation ONLY (remove/change/customize) + MUST create SCAFFOLD-WEB-TEST tickets' : ''}
310
- 3. For LOGIC: Focus on business features from requirements
311
- 4. **IMPORTANT**: Read seed files (lib/db/seed.ts or src/lib/db/seed.ts) to discover test users
312
- 5. **SCHEMA TICKETS**: No separate test tickets needed - validation happens automatically during build
313
- 6. ${isScaffoldMode ? '**SCAFFOLD-WEB-TEST TICKETS ARE MANDATORY**: Test that removed features are gone, navigation works, landing page updated, auth flow simplified' : ''}
314
- 7. **WEB TESTS MUST INCLUDE**:
315
- - Test user credentials at the top
470
+
471
+ 1. **Explore the project directory thoroughly** before generating tickets
472
+ - Read seed files (lib/db/seed.ts or src/lib/db/seed.ts) to discover test users
473
+ - Understand current tech stack, architecture, database schema
474
+ ${isScaffoldMode ? '- Identify what template features need to be removed/changed/customized' : ''}
475
+
476
+ 2. **SCAFFOLD Tickets (if in scaffold mode):**
477
+ ${isScaffoldMode ? '- Focus on template adaptation ONLY (remove/change/customize)\n - Use REFACTOR type (not backend/frontend) - each ticket touches BOTH layers\n - MUST create exactly 5 SCAFFOLD-TEST tickets (numbered 1-5)\n - Tests validate: auth flow, navigation, landing page, removed features, settings' : '- Not applicable in logic-only mode'}
478
+
479
+ 3. **LOGIC Tickets (MANDATORY ordering - FEATURE-BY-FEATURE ONLY):**
480
+ - **FIRST TICKET MUST BE LOGIC-SCHEMA-1** (combines ALL business entities)
481
+ - After schema, follow STRICT feature-by-feature pattern for EVERY feature:
482
+ - LOGIC-BACKEND-1 → LOGIC-FRONTEND-1 → LOGIC-TEST-1 (complete feature 1)
483
+ - LOGIC-BACKEND-2 → LOGIC-FRONTEND-2 → LOGIC-TEST-2 (complete feature 2)
484
+ - LOGIC-BACKEND-3 → LOGIC-FRONTEND-3 → LOGIC-TEST-3 (complete feature 3)
485
+ - ❌ ABSOLUTELY FORBIDDEN: Grouping by type
486
+ - BACKEND-1, BACKEND-2, BACKEND-3, FRONTEND-1, FRONTEND-2 ← WRONG!
487
+ - ✅ REQUIRED: Complete each feature before next
488
+ - BACKEND-1, FRONTEND-1, TEST-1, BACKEND-2, FRONTEND-2, TEST-2 ← CORRECT!
489
+
490
+ 4. **Schema and Refactor Tickets:**
491
+ - SCAFFOLD-SCHEMA-1: ONE ticket for ALL infrastructure changes
492
+ - SCAFFOLD-REFACTOR-X: Each refactor ticket touches BOTH backend + frontend (don't split)
493
+ - LOGIC-SCHEMA-1: ONE ticket for ALL business entities (MANDATORY!)
494
+ - No separate test tickets needed for schema - validation is automatic
495
+
496
+ 5. **Test Tickets:**
497
+ - ${isScaffoldMode ? 'Exactly 5 SCAFFOLD-TEST tickets (mandatory)\n - ' : ''}One LOGIC-TEST per feature (matches frontend tickets)
498
+ - MUST include test user credentials at the top
316
499
  - Clear numbered steps with natural language
317
500
  - Expected outcomes after each step
318
501
  - Specific element descriptions (button text, labels, URLs)
319
- - Complete user flows in one ticket (signup → create → invite = 1 ticket)
320
- 8. Follow the exact ticket ordering structure
321
- 9. Make descriptions detailed with clear acceptance criteria
322
- 10. Return ONLY valid JSON - no explanations, no markdown
323
- 11. Ensure sequential ticket IDs match the ordering structure
324
-
325
- Begin by:
326
- 1. Reading seed files to discover test users
327
- 2. Exploring the project directory structure
328
- 3. Generating ALL tickets in the correct order with test user info in web tests
329
- ${isScaffoldMode ? '4. IMPORTANT: Create SCAFFOLD-WEB-TEST tickets to validate template changes work correctly' : ''}.`;
502
+
503
+ 6. **Ticket Quality:**
504
+ - Detailed descriptions with clear acceptance criteria
505
+ - Realistic effort estimates (1-10 scale)
506
+ - Proper categorization
507
+ - Sequential IDs matching ordering structure
508
+
509
+ 7. **Output Format:**
510
+ - Return ONLY valid JSON array
511
+ - No markdown, no code blocks, no explanations
512
+ - All tickets in correct order
513
+
514
+ **VALIDATION CHECKLIST before returning tickets:**
515
+
516
+ 🔴 **CRITICAL - VERIFY LOGIC TICKET ORDERING:**
517
+ Read through your LOGIC tickets. Are they in this pattern?
518
+ BACKEND-1, BACKEND-2, BACKEND-3, FRONTEND-1, FRONTEND-2, FRONTEND-3, TEST-1, TEST-2
519
+ If YES → YOU MADE THE GROUPING MISTAKE! Fix it now!
520
+
521
+ ✅ Correct pattern should be:
522
+ SCHEMA-1, BACKEND-1, FRONTEND-1, TEST-1, BACKEND-2, FRONTEND-2, TEST-2
523
+
524
+ Other checks:
525
+ - ✅ ALL ticket IDs follow {BATCH}-{TYPE}-{NUMBER} format (e.g., SCAFFOLD-SCHEMA-1, LOGIC-BACKEND-2)
526
+ - ✅ Global sequential numbering within each batch (no gaps, sequential: 1, 2, 3, 4...)
527
+ - ✅ ${isScaffoldMode ? 'SCAFFOLD-SCHEMA-1 is first scaffold ticket' : 'N/A for logic-only mode'}
528
+ - ✅ ${isScaffoldMode ? 'SCAFFOLD tickets use REFACTOR type (not backend/frontend split)' : 'N/A for logic-only mode'}
529
+ - ✅ ${isScaffoldMode ? 'Exactly 5 SCAFFOLD-TEST tickets (with proper IDs like SCAFFOLD-TEST-4, SCAFFOLD-TEST-5)' : 'N/A for logic-only mode'}
530
+ - ✅ LOGIC-SCHEMA-1 is first LOGIC ticket (MANDATORY!)
531
+ - ✅ LOGIC tickets are feature-by-feature (BACKEND-1 → FRONTEND-1 → TEST-1 → BACKEND-2 → FRONTEND-2 → TEST-2)
532
+ - ✅ NO grouping by type for LOGIC tickets (verify tickets are NOT: all backends, then frontends, then tests)
533
+ - ✅ Each web test includes test user credentials
534
+ - ✅ Ticket IDs match their type field (BACKEND ticket has BACKEND in ID, FRONTEND has FRONTEND in ID)
535
+
536
+ **CRITICAL REMINDERS:**
537
+
538
+ 1. **ID FORMAT (MOST IMPORTANT):**
539
+ - EVERY ticket ID MUST include the type: {BATCH}-{TYPE}-{NUMBER}
540
+ - ❌ WRONG: SCAFFOLD-1, SCAFFOLD-2, LOGIC-1, LOGIC-2
541
+ - ✅ CORRECT: SCAFFOLD-SCHEMA-1, SCAFFOLD-REFACTOR-2, LOGIC-BACKEND-1, LOGIC-FRONTEND-2
542
+
543
+ 2. **ORDERING:**
544
+ - LOGIC tickets MUST be feature-by-feature, NOT grouped by type!
545
+ - ❌ WRONG: BACKEND-1, BACKEND-2, BACKEND-3, FRONTEND-1, FRONTEND-2, FRONTEND-3
546
+ - ✅ CORRECT: BACKEND-1, FRONTEND-1, TEST-1, BACKEND-2, FRONTEND-2, TEST-2
547
+
548
+ Begin now:
549
+ 1. Read seed files to discover test users
550
+ 2. Explore project directory structure
551
+ 3. Generate ALL tickets with CORRECT ID format ({BATCH}-{TYPE}-{NUMBER})
552
+ 4. Follow STRICT feature-by-feature ordering (NEVER group by type!)`;
330
553
  }
331
554
  /**
332
- * Core tickets logic - Simplified to single agent call
555
+ * Core tickets logic - Streaming version (exported for programmatic use)
333
556
  */
334
- export async function ticketsCore(options) {
557
+ export async function* ticketsCoreStream(options) {
335
558
  const { directory, scaffold = false } = options;
336
559
  const isScaffoldMode = scaffold;
337
- // 1. Validate and resolve project directory
338
- const projectPath = directory ? resolve(directory) : process.cwd();
339
- if (!existsSync(projectPath)) {
340
- throw new Error(`Directory not found: ${projectPath}\n` +
341
- `Please provide a valid directory using --directory=<path>\n` +
342
- `Example: kosuke tickets --directory=./my-project`);
343
- }
344
- const stats = statSync(projectPath);
345
- if (!stats.isDirectory()) {
346
- throw new Error(`Path is not a directory: ${projectPath}\n` + `Please provide a valid directory path.`);
347
- }
348
- console.log(`📁 Using project directory: ${projectPath}`);
349
- console.log(`🏗️ Mode: ${isScaffoldMode ? 'Scaffold (template adaptation + business logic)' : 'Logic-only (business features)'}\n`);
350
- // 2. Get requirements content from file
351
- let requirementsContent;
352
- if (options.path) {
353
- const requirementsPath = join(projectPath, options.path);
354
- if (!existsSync(requirementsPath)) {
355
- throw new Error(`Requirements document not found: ${options.path}\n` +
356
- `Please provide a valid path using --path=<file>\n` +
357
- `Example: kosuke tickets --path=requirements.md`);
560
+ try {
561
+ // 1. Validate and resolve project directory
562
+ const projectPath = directory ? resolve(directory) : process.cwd();
563
+ if (!existsSync(projectPath)) {
564
+ yield {
565
+ type: 'done',
566
+ data: {
567
+ status: 'error',
568
+ ticketsFile: null,
569
+ totalTickets: 0,
570
+ tokensUsed: { input: 0, output: 0, cacheCreation: 0, cacheRead: 0 },
571
+ cost: 0,
572
+ error: `Directory not found: ${projectPath}\nPlease provide a valid directory using --directory=<path>\nExample: kosuke tickets --directory=./my-project`,
573
+ },
574
+ };
575
+ return;
358
576
  }
359
- requirementsContent = readFileSync(requirementsPath, 'utf-8');
360
- console.log(`📄 Loaded ${options.path} (${requirementsContent.length} characters)\n`);
361
- }
362
- else {
363
- // Default to docs.md if path not provided
364
- const defaultPath = 'docs.md';
365
- const requirementsPath = join(projectPath, defaultPath);
366
- if (!existsSync(requirementsPath)) {
367
- throw new Error('Requirements document not found. Use either:\n' +
368
- ' --path=requirements.md (custom file)\n' +
369
- ' Or create a docs.md file in the project directory\n\n' +
370
- 'For interactive ticket creation with questions, use:\n' +
371
- ' kosuke plan --prompt="Your feature description"');
577
+ const stats = statSync(projectPath);
578
+ if (!stats.isDirectory()) {
579
+ yield {
580
+ type: 'done',
581
+ data: {
582
+ status: 'error',
583
+ ticketsFile: null,
584
+ totalTickets: 0,
585
+ tokensUsed: { input: 0, output: 0, cacheCreation: 0, cacheRead: 0 },
586
+ cost: 0,
587
+ error: `Path is not a directory: ${projectPath}\nPlease provide a valid directory path.`,
588
+ },
589
+ };
590
+ return;
591
+ }
592
+ // 2. Get requirements content from file
593
+ let requirementsContent;
594
+ if (options.path) {
595
+ const requirementsPath = join(projectPath, options.path);
596
+ if (!existsSync(requirementsPath)) {
597
+ yield {
598
+ type: 'done',
599
+ data: {
600
+ status: 'error',
601
+ ticketsFile: null,
602
+ totalTickets: 0,
603
+ tokensUsed: { input: 0, output: 0, cacheCreation: 0, cacheRead: 0 },
604
+ cost: 0,
605
+ error: `Requirements document not found: ${options.path}\nPlease provide a valid path using --path=<file>\nExample: kosuke tickets --path=requirements.md`,
606
+ },
607
+ };
608
+ return;
609
+ }
610
+ requirementsContent = readFileSync(requirementsPath, 'utf-8');
611
+ }
612
+ else {
613
+ // Default to docs.md if path not provided
614
+ const defaultPath = 'docs.md';
615
+ const requirementsPath = join(projectPath, defaultPath);
616
+ if (!existsSync(requirementsPath)) {
617
+ yield {
618
+ type: 'done',
619
+ data: {
620
+ status: 'error',
621
+ ticketsFile: null,
622
+ totalTickets: 0,
623
+ tokensUsed: { input: 0, output: 0, cacheCreation: 0, cacheRead: 0 },
624
+ cost: 0,
625
+ error: 'Requirements document not found. Use either:\n --path=requirements.md (custom file)\n Or create a docs.md file in the project directory\n\nFor interactive ticket creation with questions, use:\n kosuke plan --prompt="Your feature description"',
626
+ },
627
+ };
628
+ return;
629
+ }
630
+ requirementsContent = readFileSync(requirementsPath, 'utf-8');
631
+ }
632
+ // 3. Determine output path
633
+ const outputFilename = options.output || 'tickets.json';
634
+ const outputPath = join(projectPath, outputFilename);
635
+ // 4. Generate ALL tickets in a single comprehensive agent call
636
+ const systemPrompt = buildTicketPrompt(requirementsContent, projectPath, isScaffoldMode, options.noTest ?? false);
637
+ const stream = runAgentStream('Generate all tickets from requirements', {
638
+ systemPrompt,
639
+ cwd: projectPath,
640
+ maxTurns: 40,
641
+ verbosity: 'normal',
642
+ captureConversation: true,
643
+ });
644
+ let fullResponse = '';
645
+ let tokensUsed = { input: 0, output: 0, cacheCreation: 0, cacheRead: 0 };
646
+ let cost = 0;
647
+ // Yield events from stream
648
+ for await (const event of stream) {
649
+ if (event.type === 'message') {
650
+ yield { type: 'message', data: event.data };
651
+ // Accumulate response text
652
+ const claudeMessage = event.data;
653
+ if (claudeMessage.type === 'assistant' && claudeMessage.message) {
654
+ const msg = claudeMessage.message;
655
+ if (msg.content && Array.isArray(msg.content)) {
656
+ for (const block of msg.content) {
657
+ if (block.type === 'text' && block.text) {
658
+ fullResponse += block.text;
659
+ }
660
+ else if (block.type === 'tool_use' && block.name) {
661
+ yield {
662
+ type: 'tool_call',
663
+ data: { name: block.name, input: block.input || {} },
664
+ };
665
+ }
666
+ }
667
+ }
668
+ }
669
+ }
670
+ else if (event.type === 'agent_result') {
671
+ tokensUsed = event.data.tokensUsed;
672
+ cost = event.data.cost;
673
+ }
674
+ }
675
+ // 5. Extract JSON from response (simple extraction)
676
+ let tickets = extractTicketsJSON(fullResponse);
677
+ // 6. If extraction failed, try to fix via Claude using fix stream
678
+ if (!tickets) {
679
+ // Write raw response to temporary file for fixing
680
+ const tempRawPath = outputPath.replace('.json', '.raw.txt');
681
+ writeFileSync(tempRawPath, fullResponse, 'utf-8');
682
+ try {
683
+ const fixStream = fixCoreStream({
684
+ format: 'json',
685
+ file: tempRawPath,
686
+ output: outputPath,
687
+ directory: projectPath,
688
+ noLogs: true,
689
+ });
690
+ let fixResult = null;
691
+ for await (const event of fixStream) {
692
+ if (event.type === 'done') {
693
+ fixResult = event.data;
694
+ }
695
+ }
696
+ if (!fixResult || fixResult.status === 'error') {
697
+ yield {
698
+ type: 'done',
699
+ data: {
700
+ status: 'error',
701
+ ticketsFile: null,
702
+ totalTickets: 0,
703
+ tokensUsed,
704
+ cost,
705
+ error: fixResult?.error || 'Failed to fix JSON extraction',
706
+ },
707
+ };
708
+ return;
709
+ }
710
+ // Load tickets from file (fix wrote them)
711
+ const fixedData = loadTicketsFile(outputPath);
712
+ tickets = fixedData.tickets;
713
+ }
714
+ finally {
715
+ // Clean up temporary file
716
+ const { unlinkSync } = await import('fs');
717
+ if (existsSync(tempRawPath)) {
718
+ unlinkSync(tempRawPath);
719
+ }
720
+ }
372
721
  }
373
- requirementsContent = readFileSync(requirementsPath, 'utf-8');
374
- console.log(`📄 Loaded ${defaultPath} (${requirementsContent.length} characters)\n`);
722
+ else {
723
+ // 7. Write raw tickets to file (before validation)
724
+ writeTicketsFile(outputPath, tickets);
725
+ }
726
+ // 8. Validate tickets file using validate-tickets stream
727
+ const validateStream = validateTicketsCoreStream({
728
+ tickets: outputPath,
729
+ directory: projectPath,
730
+ strict: false,
731
+ noLogs: false,
732
+ });
733
+ let validateResult = null;
734
+ for await (const event of validateStream) {
735
+ if (event.type === 'done') {
736
+ validateResult = event.data;
737
+ }
738
+ }
739
+ if (!validateResult || validateResult.status === 'error') {
740
+ yield {
741
+ type: 'done',
742
+ data: {
743
+ status: 'error',
744
+ ticketsFile: outputPath,
745
+ totalTickets: tickets?.length || 0,
746
+ tokensUsed,
747
+ cost,
748
+ error: validateResult?.error || 'Validation failed',
749
+ },
750
+ };
751
+ return;
752
+ }
753
+ // 9. Load validated tickets
754
+ const ticketsData = loadTicketsFile(outputPath);
755
+ const allTickets = ticketsData.tickets;
756
+ yield {
757
+ type: 'done',
758
+ data: {
759
+ status: 'success',
760
+ ticketsFile: outputPath,
761
+ totalTickets: allTickets.length,
762
+ tokensUsed,
763
+ cost,
764
+ },
765
+ };
375
766
  }
376
- // 3. Determine output path
377
- const outputFilename = options.output || 'tickets.json';
378
- const outputPath = join(projectPath, outputFilename);
379
- // 4. Generate ALL tickets in a single comprehensive agent call
380
- console.log(`\n${'='.repeat(80)}`);
381
- console.log('🎯 Generating Tickets with Claude Code Agent');
382
- console.log(`${'='.repeat(80)}\n`);
383
- const systemPrompt = buildTicketPrompt(requirementsContent, projectPath, isScaffoldMode, options.noTest ?? false);
384
- const agentResult = await runAgent('Generate all tickets from requirements', {
385
- systemPrompt,
386
- cwd: projectPath,
387
- maxTurns: 40, // Give Claude enough turns to explore codebase and generate all tickets
388
- verbosity: 'normal',
389
- captureConversation: true,
390
- });
391
- // 5. Parse initial tickets using shared utility
392
- const initialTickets = parseTickets(agentResult.response);
393
- console.log(`\n✅ Initial generation: ${initialTickets.length} tickets created`);
394
- // 6. Validate, fix, and write tickets using shared utility
395
- const { tickets: allTickets, validationIssues } = await processAndWriteTickets(initialTickets, outputPath, projectPath, { displaySummary: true });
396
- // Display additional info about validation
397
- if (validationIssues.length > 0) {
398
- console.log(`📝 ${validationIssues.length} issue(s) were automatically fixed`);
767
+ catch (error) {
768
+ yield {
769
+ type: 'done',
770
+ data: {
771
+ status: 'error',
772
+ ticketsFile: null,
773
+ totalTickets: 0,
774
+ tokensUsed: { input: 0, output: 0, cacheCreation: 0, cacheRead: 0 },
775
+ cost: 0,
776
+ error: error instanceof Error ? error.message : String(error),
777
+ },
778
+ };
399
779
  }
400
- // 10. Separate tickets by phase for compatibility with existing result structure
401
- const schemaTickets = allTickets.filter((t) => t.type === 'schema');
402
- const engineTickets = allTickets.filter((t) => t.type === 'engine');
403
- const backendTickets = allTickets.filter((t) => t.type === 'backend');
404
- const frontendTickets = allTickets.filter((t) => t.type === 'frontend');
405
- const testTickets = allTickets.filter((t) => t.type === 'test');
406
- return {
407
- schemaTickets,
408
- engineTickets,
409
- backendTickets,
410
- frontendTickets,
411
- testTickets,
412
- totalTickets: allTickets.length,
413
- projectPath,
414
- tokensUsed: agentResult.tokensUsed,
415
- cost: agentResult.cost,
416
- conversationMessages: agentResult.conversationMessages || [],
417
- };
418
780
  }
419
781
  /**
420
782
  * Main tickets command
421
783
  */
422
784
  export async function ticketsCommand(options) {
423
- const { noLogs = false } = options;
785
+ const { noLogs = false, directory, scaffold = false } = options;
424
786
  console.log('🎫 Starting Ticket Generation...\n');
425
787
  // Initialize logging context
426
788
  const logContext = logger.createContext('tickets', { noLogs });
@@ -430,59 +792,74 @@ export async function ticketsCommand(options) {
430
792
  if (!process.env.ANTHROPIC_API_KEY) {
431
793
  throw new Error('ANTHROPIC_API_KEY environment variable is required');
432
794
  }
433
- // Execute core logic
434
- const result = await ticketsCore(options);
795
+ // Resolve paths for display
796
+ const projectPath = directory ? resolve(directory) : process.cwd();
797
+ const isScaffoldMode = scaffold;
798
+ console.log(`📁 Using project directory: ${projectPath}`);
799
+ console.log(`🏗️ Mode: ${isScaffoldMode ? 'Scaffold (template adaptation + business logic)' : 'Logic-only (business features)'}\n`);
800
+ // Get requirements path for display
801
+ const requirementsPath = options.path
802
+ ? join(projectPath, options.path)
803
+ : join(projectPath, 'docs.md');
804
+ if (existsSync(requirementsPath)) {
805
+ const requirementsContent = readFileSync(requirementsPath, 'utf-8');
806
+ console.log(`📄 Loaded ${options.path || 'docs.md'} (${requirementsContent.length} characters)\n`);
807
+ }
808
+ console.log(`\n${'='.repeat(80)}`);
809
+ console.log('🎯 Generating Tickets with Claude Code Agent');
810
+ console.log(`${'='.repeat(80)}\n`);
811
+ // Consume stream
812
+ const stream = ticketsCoreStream(options);
813
+ let finalResult = null;
814
+ for await (const event of stream) {
815
+ if (event.type === 'done') {
816
+ finalResult = event.data;
817
+ }
818
+ // Messages are already logged by runAgentStream with verbosity
819
+ }
820
+ if (!finalResult || finalResult.status === 'error') {
821
+ throw new Error(finalResult?.error || 'Unknown error during ticket generation');
822
+ }
823
+ // Now TypeScript knows finalResult.status === 'success'
824
+ const { ticketsFile, totalTickets, tokensUsed, cost } = finalResult;
435
825
  // Track metrics
436
- logger.trackTokens(logContext, result.tokensUsed);
437
- logContext.conversationMessages = result.conversationMessages;
826
+ logger.trackTokens(logContext, tokensUsed);
827
+ // Load and display tickets summary
828
+ const ticketsData = loadTicketsFile(ticketsFile);
829
+ const allTickets = ticketsData.tickets;
830
+ displayTicketsSummary(allTickets);
438
831
  // Get all tickets by batch (scaffold vs logic)
439
- const scaffoldTickets = [
440
- ...result.schemaTickets,
441
- ...result.engineTickets,
442
- ...result.backendTickets,
443
- ...result.frontendTickets,
444
- ...result.testTickets,
445
- ].filter((t) => t.id.toUpperCase().startsWith('SCAFFOLD-'));
446
- const logicTickets = [
447
- ...result.schemaTickets,
448
- ...result.engineTickets,
449
- ...result.backendTickets,
450
- ...result.frontendTickets,
451
- ...result.testTickets,
452
- ].filter((t) => t.id.toUpperCase().startsWith('LOGIC-'));
832
+ const scaffoldTickets = allTickets.filter((t) => t.id.toUpperCase().startsWith('SCAFFOLD-'));
833
+ const logicTickets = allTickets.filter((t) => t.id.toUpperCase().startsWith('LOGIC-'));
453
834
  // Display summary
454
835
  console.log(`\n${'='.repeat(80)}`);
455
836
  console.log('📊 Ticket Generation Summary');
456
837
  console.log(`${'='.repeat(80)}`);
457
838
  if (scaffoldTickets.length > 0) {
458
839
  console.log(`\n🏗️ Scaffold Tickets (Template Adaptation): ${scaffoldTickets.length}`);
459
- console.log(` 🗄️ Schema: ${result.schemaTickets.filter((t) => t.id.toUpperCase().startsWith('SCAFFOLD-')).length} (auto-validated)`);
460
- console.log(` 🐍 Engine: ${result.engineTickets.filter((t) => t.id.toUpperCase().startsWith('SCAFFOLD-')).length} (auto-validated)`);
461
- console.log(` ⚙️ Backend: ${result.backendTickets.filter((t) => t.id.toUpperCase().startsWith('SCAFFOLD-')).length}`);
462
- console.log(` 🎨 Frontend: ${result.frontendTickets.filter((t) => t.id.toUpperCase().startsWith('SCAFFOLD-')).length}`);
463
- console.log(` 🧪 Tests: ${result.testTickets.filter((t) => t.id.toUpperCase().startsWith('SCAFFOLD-')).length}`);
840
+ console.log(` 🗄️ Schema: ${scaffoldTickets.filter((t) => t.type === 'schema').length} (auto-validated)`);
841
+ console.log(` 🔄 Refactor: ${scaffoldTickets.filter((t) => t.type === 'refactor').length} (backend + frontend)`);
842
+ console.log(` 🧪 Tests: ${scaffoldTickets.filter((t) => t.type === 'test').length}`);
464
843
  }
465
844
  console.log(`\n💡 Logic Tickets (Business Functionality): ${logicTickets.length}`);
466
- console.log(` 🗄️ Schema: ${result.schemaTickets.filter((t) => t.id.toUpperCase().startsWith('LOGIC-')).length} (auto-validated)`);
467
- console.log(` 🐍 Engine: ${result.engineTickets.filter((t) => t.id.toUpperCase().startsWith('LOGIC-')).length} (auto-validated)`);
468
- console.log(` ⚙️ Backend: ${result.backendTickets.filter((t) => t.id.toUpperCase().startsWith('LOGIC-')).length}`);
469
- console.log(` 🎨 Frontend: ${result.frontendTickets.filter((t) => t.id.toUpperCase().startsWith('LOGIC-')).length}`);
470
- console.log(` 🧪 Tests: ${result.testTickets.filter((t) => t.id.toUpperCase().startsWith('LOGIC-')).length}`);
471
- console.log(`\n📝 Total Tickets: ${result.totalTickets}`);
845
+ console.log(` 🗄️ Schema: ${logicTickets.filter((t) => t.type === 'schema').length} (auto-validated)`);
846
+ console.log(` 🐍 Engine: ${logicTickets.filter((t) => t.type === 'engine').length}`);
847
+ console.log(` ⚙️ Backend: ${logicTickets.filter((t) => t.type === 'backend').length}`);
848
+ console.log(` 🎨 Frontend: ${logicTickets.filter((t) => t.type === 'frontend').length}`);
849
+ console.log(` 🧪 Tests: ${logicTickets.filter((t) => t.type === 'test').length}`);
850
+ console.log(`\n📝 Total Tickets: ${totalTickets}`);
472
851
  console.log(`${'='.repeat(80)}\n`);
473
852
  // Display cost breakdown
474
853
  const costBreakdown = formatCostBreakdown({
475
- cost: result.cost,
476
- tokensUsed: result.tokensUsed,
854
+ cost,
855
+ tokensUsed,
477
856
  fixCount: 0,
478
857
  response: '',
479
858
  filesReferenced: new Set(),
480
859
  });
481
860
  console.log(`💰 Total Cost: ${costBreakdown}\n`);
482
861
  // Final confirmation
483
- const outputFilename = options.output || 'tickets.json';
484
- const outputPath = join(result.projectPath, outputFilename);
485
- console.log(`✅ All tickets saved to: ${outputPath}\n`);
862
+ console.log(`✅ All tickets saved to: ${ticketsFile}\n`);
486
863
  console.log('✅ Ticket generation completed successfully!');
487
864
  // Log successful execution
488
865
  await logger.complete(logContext, 'success');