@kosuke-ai/cli 0.0.57 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (263) hide show
  1. package/README.md +31 -448
  2. package/dist/commands/auth.js +117 -0
  3. package/dist/generated/commands/deploy/cancel.js +17 -0
  4. package/dist/generated/commands/deploy/messages.js +17 -0
  5. package/dist/generated/commands/deploy/run.js +60 -0
  6. package/dist/generated/commands/index.js +132 -0
  7. package/dist/generated/commands/preview/get.js +25 -0
  8. package/dist/generated/commands/preview/health.js +25 -0
  9. package/dist/generated/commands/preview/reset.js +27 -0
  10. package/dist/generated/commands/preview/share-create.js +36 -0
  11. package/dist/generated/commands/preview/share-delete.js +26 -0
  12. package/dist/generated/commands/preview/share-get.js +26 -0
  13. package/dist/generated/commands/preview/shared.js +17 -0
  14. package/dist/generated/commands/projects/create.js +37 -0
  15. package/dist/generated/commands/projects/delete.js +17 -0
  16. package/dist/generated/commands/projects/env-vars-add.js +21 -0
  17. package/dist/generated/commands/projects/env-vars-remove.js +21 -0
  18. package/dist/generated/commands/projects/get.js +17 -0
  19. package/dist/generated/commands/projects/list.js +15 -0
  20. package/dist/generated/commands/projects/services-add.js +87 -0
  21. package/dist/generated/commands/projects/services-list.js +18 -0
  22. package/dist/generated/commands/projects/services-remove.js +19 -0
  23. package/dist/generated/commands/projects/services-update.js +81 -0
  24. package/dist/generated/commands/projects/settings-get.js +18 -0
  25. package/dist/generated/commands/projects/settings-import.js +91 -0
  26. package/dist/generated/commands/projects/settings-update.js +77 -0
  27. package/dist/generated/commands/projects/skills.js +35 -0
  28. package/dist/generated/commands/projects/update.js +27 -0
  29. package/dist/generated/commands/sessions/activate.js +18 -0
  30. package/dist/generated/commands/sessions/checklist-generate.js +19 -0
  31. package/dist/generated/commands/sessions/checklist-get.js +19 -0
  32. package/dist/generated/commands/sessions/comments-add.js +63 -0
  33. package/dist/generated/commands/sessions/comments-delete.js +20 -0
  34. package/dist/generated/commands/sessions/comments-list.js +19 -0
  35. package/dist/generated/commands/sessions/comments-update.js +23 -0
  36. package/dist/generated/commands/sessions/create.js +126 -0
  37. package/dist/generated/commands/sessions/delete.js +18 -0
  38. package/dist/generated/commands/sessions/diff-files.js +19 -0
  39. package/dist/generated/commands/sessions/diff-patch.js +86 -0
  40. package/dist/generated/commands/sessions/edit-prompt.js +59 -0
  41. package/dist/generated/commands/sessions/files-get.js +27 -0
  42. package/dist/generated/commands/sessions/files-list.js +19 -0
  43. package/dist/generated/commands/sessions/files-write.js +41 -0
  44. package/dist/generated/commands/sessions/get.js +18 -0
  45. package/dist/generated/commands/sessions/git-commit-message.js +19 -0
  46. package/dist/generated/commands/sessions/git-commit.js +29 -0
  47. package/dist/generated/commands/sessions/git-push.js +19 -0
  48. package/dist/generated/commands/sessions/git-state.js +19 -0
  49. package/dist/generated/commands/sessions/jobs-cancel.js +20 -0
  50. package/dist/generated/commands/sessions/jobs-get.js +20 -0
  51. package/dist/generated/commands/sessions/list.js +81 -0
  52. package/dist/generated/commands/sessions/messages.js +18 -0
  53. package/dist/generated/commands/sessions/search.js +23 -0
  54. package/dist/generated/commands/sessions/send.js +98 -0
  55. package/dist/generated/commands/sessions/update.js +72 -0
  56. package/dist/generated/commands/workspaces/access-status.js +29 -0
  57. package/dist/generated/commands/workspaces/ai-provider-get.js +18 -0
  58. package/dist/generated/commands/workspaces/ai-provider-remove.js +42 -0
  59. package/dist/generated/commands/workspaces/ai-provider-set.js +21 -0
  60. package/dist/generated/commands/workspaces/credits.js +17 -0
  61. package/dist/generated/commands/workspaces/get.js +17 -0
  62. package/dist/generated/commands/workspaces/getting-started-get.js +18 -0
  63. package/dist/generated/commands/workspaces/getting-started-update.js +32 -0
  64. package/dist/generated/commands/workspaces/list.js +15 -0
  65. package/dist/generated/commands/workspaces/members.js +25 -0
  66. package/dist/generated/commands/workspaces/sandbox-limit.js +17 -0
  67. package/dist/generated/commands/workspaces/stop-sandboxes.js +27 -0
  68. package/dist/generated/commands/workspaces/usage.js +32 -0
  69. package/dist/index.js +5 -595
  70. package/dist/program.js +46 -0
  71. package/dist/runtime/attach.js +139 -0
  72. package/dist/runtime/attachments.js +58 -0
  73. package/dist/runtime/client.js +12 -0
  74. package/dist/runtime/config.js +49 -0
  75. package/dist/runtime/credentials.js +24 -0
  76. package/dist/runtime/descriptor.js +7 -0
  77. package/dist/runtime/invoke.js +152 -0
  78. package/dist/runtime/runtime.js +41 -0
  79. package/dist/runtime/version.js +5 -0
  80. package/openapi.json +5222 -0
  81. package/package.json +21 -79
  82. package/LICENSE +0 -21
  83. package/claude.costs.json +0 -34
  84. package/dist/__tests__/utils/file-discovery.test.d.ts +0 -5
  85. package/dist/__tests__/utils/file-discovery.test.d.ts.map +0 -1
  86. package/dist/__tests__/utils/file-discovery.test.js +0 -51
  87. package/dist/__tests__/utils/file-discovery.test.js.map +0 -1
  88. package/dist/__tests__/utils/logger-nologs.test.d.ts +0 -5
  89. package/dist/__tests__/utils/logger-nologs.test.d.ts.map +0 -1
  90. package/dist/__tests__/utils/logger-nologs.test.js +0 -34
  91. package/dist/__tests__/utils/logger-nologs.test.js.map +0 -1
  92. package/dist/__tests__/utils/logger.test.d.ts +0 -5
  93. package/dist/__tests__/utils/logger.test.d.ts.map +0 -1
  94. package/dist/__tests__/utils/logger.test.js +0 -243
  95. package/dist/__tests__/utils/logger.test.js.map +0 -1
  96. package/dist/__tests__/utils/validator.test.d.ts +0 -5
  97. package/dist/__tests__/utils/validator.test.d.ts.map +0 -1
  98. package/dist/__tests__/utils/validator.test.js +0 -206
  99. package/dist/__tests__/utils/validator.test.js.map +0 -1
  100. package/dist/index.d.ts +0 -37
  101. package/dist/index.d.ts.map +0 -1
  102. package/dist/index.js.map +0 -1
  103. package/dist/kosuke/commands/analyse.d.ts +0 -15
  104. package/dist/kosuke/commands/analyse.d.ts.map +0 -1
  105. package/dist/kosuke/commands/analyse.js +0 -304
  106. package/dist/kosuke/commands/analyse.js.map +0 -1
  107. package/dist/kosuke/commands/build.d.ts +0 -35
  108. package/dist/kosuke/commands/build.d.ts.map +0 -1
  109. package/dist/kosuke/commands/build.js +0 -660
  110. package/dist/kosuke/commands/build.js.map +0 -1
  111. package/dist/kosuke/commands/fix.d.ts +0 -21
  112. package/dist/kosuke/commands/fix.d.ts.map +0 -1
  113. package/dist/kosuke/commands/fix.js +0 -256
  114. package/dist/kosuke/commands/fix.js.map +0 -1
  115. package/dist/kosuke/commands/getcode.d.ts +0 -29
  116. package/dist/kosuke/commands/getcode.d.ts.map +0 -1
  117. package/dist/kosuke/commands/getcode.js +0 -248
  118. package/dist/kosuke/commands/getcode.js.map +0 -1
  119. package/dist/kosuke/commands/lint.d.ts +0 -21
  120. package/dist/kosuke/commands/lint.d.ts.map +0 -1
  121. package/dist/kosuke/commands/lint.js +0 -342
  122. package/dist/kosuke/commands/lint.js.map +0 -1
  123. package/dist/kosuke/commands/migrate.d.ts +0 -38
  124. package/dist/kosuke/commands/migrate.d.ts.map +0 -1
  125. package/dist/kosuke/commands/migrate.js +0 -284
  126. package/dist/kosuke/commands/migrate.js.map +0 -1
  127. package/dist/kosuke/commands/plan.d.ts +0 -28
  128. package/dist/kosuke/commands/plan.d.ts.map +0 -1
  129. package/dist/kosuke/commands/plan.js +0 -684
  130. package/dist/kosuke/commands/plan.js.map +0 -1
  131. package/dist/kosuke/commands/requirements.d.ts +0 -52
  132. package/dist/kosuke/commands/requirements.d.ts.map +0 -1
  133. package/dist/kosuke/commands/requirements.js +0 -615
  134. package/dist/kosuke/commands/requirements.js.map +0 -1
  135. package/dist/kosuke/commands/review.d.ts +0 -26
  136. package/dist/kosuke/commands/review.d.ts.map +0 -1
  137. package/dist/kosuke/commands/review.js +0 -303
  138. package/dist/kosuke/commands/review.js.map +0 -1
  139. package/dist/kosuke/commands/serve.d.ts +0 -9
  140. package/dist/kosuke/commands/serve.d.ts.map +0 -1
  141. package/dist/kosuke/commands/serve.js +0 -17
  142. package/dist/kosuke/commands/serve.js.map +0 -1
  143. package/dist/kosuke/commands/ship.d.ts +0 -37
  144. package/dist/kosuke/commands/ship.d.ts.map +0 -1
  145. package/dist/kosuke/commands/ship.js +0 -375
  146. package/dist/kosuke/commands/ship.js.map +0 -1
  147. package/dist/kosuke/commands/sync-rules.d.ts +0 -9
  148. package/dist/kosuke/commands/sync-rules.d.ts.map +0 -1
  149. package/dist/kosuke/commands/sync-rules.js +0 -414
  150. package/dist/kosuke/commands/sync-rules.js.map +0 -1
  151. package/dist/kosuke/commands/test.d.ts +0 -42
  152. package/dist/kosuke/commands/test.d.ts.map +0 -1
  153. package/dist/kosuke/commands/test.js +0 -540
  154. package/dist/kosuke/commands/test.js.map +0 -1
  155. package/dist/kosuke/commands/tickets.d.ts +0 -43
  156. package/dist/kosuke/commands/tickets.d.ts.map +0 -1
  157. package/dist/kosuke/commands/tickets.js +0 -876
  158. package/dist/kosuke/commands/tickets.js.map +0 -1
  159. package/dist/kosuke/commands/validate-tickets.d.ts +0 -23
  160. package/dist/kosuke/commands/validate-tickets.d.ts.map +0 -1
  161. package/dist/kosuke/commands/validate-tickets.js +0 -360
  162. package/dist/kosuke/commands/validate-tickets.js.map +0 -1
  163. package/dist/kosuke/serve/middleware/error-handler.d.ts +0 -14
  164. package/dist/kosuke/serve/middleware/error-handler.d.ts.map +0 -1
  165. package/dist/kosuke/serve/middleware/error-handler.js +0 -42
  166. package/dist/kosuke/serve/middleware/error-handler.js.map +0 -1
  167. package/dist/kosuke/serve/middleware/validation.d.ts +0 -13
  168. package/dist/kosuke/serve/middleware/validation.d.ts.map +0 -1
  169. package/dist/kosuke/serve/middleware/validation.js +0 -38
  170. package/dist/kosuke/serve/middleware/validation.js.map +0 -1
  171. package/dist/kosuke/serve/routes/build.d.ts +0 -6
  172. package/dist/kosuke/serve/routes/build.d.ts.map +0 -1
  173. package/dist/kosuke/serve/routes/build.js +0 -226
  174. package/dist/kosuke/serve/routes/build.js.map +0 -1
  175. package/dist/kosuke/serve/routes/health.d.ts +0 -6
  176. package/dist/kosuke/serve/routes/health.d.ts.map +0 -1
  177. package/dist/kosuke/serve/routes/health.js +0 -11
  178. package/dist/kosuke/serve/routes/health.js.map +0 -1
  179. package/dist/kosuke/serve/routes/plan.d.ts +0 -6
  180. package/dist/kosuke/serve/routes/plan.d.ts.map +0 -1
  181. package/dist/kosuke/serve/routes/plan.js +0 -106
  182. package/dist/kosuke/serve/routes/plan.js.map +0 -1
  183. package/dist/kosuke/serve/server.d.ts +0 -16
  184. package/dist/kosuke/serve/server.d.ts.map +0 -1
  185. package/dist/kosuke/serve/server.js +0 -67
  186. package/dist/kosuke/serve/server.js.map +0 -1
  187. package/dist/kosuke/serve/validation/build.d.ts +0 -41
  188. package/dist/kosuke/serve/validation/build.d.ts.map +0 -1
  189. package/dist/kosuke/serve/validation/build.js +0 -20
  190. package/dist/kosuke/serve/validation/build.js.map +0 -1
  191. package/dist/kosuke/serve/validation/plan.d.ts +0 -26
  192. package/dist/kosuke/serve/validation/plan.d.ts.map +0 -1
  193. package/dist/kosuke/serve/validation/plan.js +0 -15
  194. package/dist/kosuke/serve/validation/plan.js.map +0 -1
  195. package/dist/kosuke/types.d.ts +0 -539
  196. package/dist/kosuke/types.d.ts.map +0 -1
  197. package/dist/kosuke/types.js +0 -5
  198. package/dist/kosuke/types.js.map +0 -1
  199. package/dist/kosuke/utils/batch-creator.d.ts +0 -14
  200. package/dist/kosuke/utils/batch-creator.d.ts.map +0 -1
  201. package/dist/kosuke/utils/batch-creator.js +0 -76
  202. package/dist/kosuke/utils/batch-creator.js.map +0 -1
  203. package/dist/kosuke/utils/claude-agent.d.ts +0 -140
  204. package/dist/kosuke/utils/claude-agent.d.ts.map +0 -1
  205. package/dist/kosuke/utils/claude-agent.js +0 -388
  206. package/dist/kosuke/utils/claude-agent.js.map +0 -1
  207. package/dist/kosuke/utils/constants.d.ts +0 -40
  208. package/dist/kosuke/utils/constants.d.ts.map +0 -1
  209. package/dist/kosuke/utils/constants.js +0 -54
  210. package/dist/kosuke/utils/constants.js.map +0 -1
  211. package/dist/kosuke/utils/file-discovery.d.ts +0 -15
  212. package/dist/kosuke/utils/file-discovery.d.ts.map +0 -1
  213. package/dist/kosuke/utils/file-discovery.js +0 -80
  214. package/dist/kosuke/utils/file-discovery.js.map +0 -1
  215. package/dist/kosuke/utils/git.d.ts +0 -41
  216. package/dist/kosuke/utils/git.d.ts.map +0 -1
  217. package/dist/kosuke/utils/git.js +0 -145
  218. package/dist/kosuke/utils/git.js.map +0 -1
  219. package/dist/kosuke/utils/github.d.ts +0 -17
  220. package/dist/kosuke/utils/github.d.ts.map +0 -1
  221. package/dist/kosuke/utils/github.js +0 -22
  222. package/dist/kosuke/utils/github.js.map +0 -1
  223. package/dist/kosuke/utils/interactive-input.d.ts +0 -22
  224. package/dist/kosuke/utils/interactive-input.d.ts.map +0 -1
  225. package/dist/kosuke/utils/interactive-input.js +0 -124
  226. package/dist/kosuke/utils/interactive-input.js.map +0 -1
  227. package/dist/kosuke/utils/json-parser.d.ts +0 -14
  228. package/dist/kosuke/utils/json-parser.d.ts.map +0 -1
  229. package/dist/kosuke/utils/json-parser.js +0 -40
  230. package/dist/kosuke/utils/json-parser.js.map +0 -1
  231. package/dist/kosuke/utils/logger.d.ts +0 -161
  232. package/dist/kosuke/utils/logger.d.ts.map +0 -1
  233. package/dist/kosuke/utils/logger.js +0 -234
  234. package/dist/kosuke/utils/logger.js.map +0 -1
  235. package/dist/kosuke/utils/playwright-mcp-client.d.ts +0 -46
  236. package/dist/kosuke/utils/playwright-mcp-client.d.ts.map +0 -1
  237. package/dist/kosuke/utils/playwright-mcp-client.js +0 -135
  238. package/dist/kosuke/utils/playwright-mcp-client.js.map +0 -1
  239. package/dist/kosuke/utils/pr-orchestrator.d.ts +0 -49
  240. package/dist/kosuke/utils/pr-orchestrator.d.ts.map +0 -1
  241. package/dist/kosuke/utils/pr-orchestrator.js +0 -154
  242. package/dist/kosuke/utils/pr-orchestrator.js.map +0 -1
  243. package/dist/kosuke/utils/repository-manager.d.ts +0 -13
  244. package/dist/kosuke/utils/repository-manager.d.ts.map +0 -1
  245. package/dist/kosuke/utils/repository-manager.js +0 -94
  246. package/dist/kosuke/utils/repository-manager.js.map +0 -1
  247. package/dist/kosuke/utils/repository-resolver.d.ts +0 -12
  248. package/dist/kosuke/utils/repository-resolver.d.ts.map +0 -1
  249. package/dist/kosuke/utils/repository-resolver.js +0 -186
  250. package/dist/kosuke/utils/repository-resolver.js.map +0 -1
  251. package/dist/kosuke/utils/tickets-manager.d.ts +0 -34
  252. package/dist/kosuke/utils/tickets-manager.d.ts.map +0 -1
  253. package/dist/kosuke/utils/tickets-manager.js +0 -106
  254. package/dist/kosuke/utils/tickets-manager.js.map +0 -1
  255. package/dist/kosuke/utils/validator.d.ts +0 -45
  256. package/dist/kosuke/utils/validator.d.ts.map +0 -1
  257. package/dist/kosuke/utils/validator.js +0 -248
  258. package/dist/kosuke/utils/validator.js.map +0 -1
  259. package/dist/lib.d.ts +0 -104
  260. package/dist/lib.d.ts.map +0 -1
  261. package/dist/lib.js +0 -104
  262. package/dist/lib.js.map +0 -1
  263. package/dist/package.json +0 -99
@@ -1,684 +0,0 @@
1
- /**
2
- * Plan command - AI-driven ticket planning from feature/bug descriptions
3
- *
4
- * This command takes a prompt describing a feature or bug and an existing codebase,
5
- * asks clarification questions (non-technical, user-focused), and generates tickets.json
6
- * that can be processed by the build command.
7
- *
8
- * Features:
9
- * - Analyzes existing codebase to understand patterns
10
- * - Asks AI-generated clarification questions (non-technical)
11
- * - Auto-detects ticket types (SCHEMA-, BACKEND-, FRONTEND-, TEST-)
12
- * - Generates tickets.json compatible with build command
13
- *
14
- * Usage:
15
- * kosuke plan --prompt="Add dark mode toggle" --directory=./my-project
16
- * kosuke plan --prompt="Fix login timeout bug" --dir=./app
17
- * kosuke plan --prompt="Add notes feature" --no-test # Skip TEST tickets
18
- */
19
- import { existsSync, mkdirSync, statSync } from 'fs';
20
- import { join, resolve } from 'path';
21
- import { formatCostBreakdown, logAssistantMessage, logToolUsage, runAgentStream, } from '../utils/claude-agent.js';
22
- import { askQuestion } from '../utils/interactive-input.js';
23
- import { extractTicketsJSON } from '../utils/json-parser.js';
24
- import { logger, setupCancellationHandler } from '../utils/logger.js';
25
- import { writeTicketsFile } from '../utils/tickets-manager.js';
26
- /**
27
- * Sort tickets by processing order (feature-by-feature)
28
- * Plan command only generates PLAN- prefixed tickets
29
- */
30
- function sortTicketsByOrder(tickets) {
31
- return [...tickets].sort((a, b) => {
32
- const getPhaseOrder = (id) => {
33
- const upper = id.toUpperCase();
34
- // PLAN batch: schema → engine → backend → frontend → test
35
- if (upper.startsWith('PLAN-SCHEMA-'))
36
- return 1;
37
- if (upper.startsWith('PLAN-ENGINE-'))
38
- return 2;
39
- if (upper.startsWith('PLAN-BACKEND-'))
40
- return 3;
41
- if (upper.startsWith('PLAN-FRONTEND-'))
42
- return 4;
43
- if (upper.startsWith('PLAN-TEST-'))
44
- return 5;
45
- return 6; // Any other ticket types (shouldn't happen)
46
- };
47
- return getPhaseOrder(a.id) - getPhaseOrder(b.id);
48
- });
49
- }
50
- /**
51
- * Generate timestamp-based tickets path in tickets/ folder
52
- * Creates the tickets/ folder if it doesn't exist
53
- */
54
- function generateTicketsPath(cwd) {
55
- const ticketsDir = join(cwd, 'tickets');
56
- // Create tickets folder if it doesn't exist
57
- if (!existsSync(ticketsDir)) {
58
- mkdirSync(ticketsDir, { recursive: true });
59
- }
60
- // Generate timestamp: YYYY-MM-DD-HH-mm-ss
61
- const now = new Date();
62
- const timestamp = now
63
- .toISOString()
64
- .replace(/[T:]/g, '-')
65
- .replace(/\.\d{3}Z$/, '');
66
- return join(ticketsDir, `${timestamp}.tickets.json`);
67
- }
68
- /**
69
- * Build system prompt for plan command
70
- *
71
- * Two-phase workflow:
72
- * - Phase 1: Ask clarification questions (non-technical, user-focused)
73
- * - Phase 2: Generate tickets via write_tickets tool
74
- *
75
- * @param noTest - If true, exclude TEST tickets from generation
76
- */
77
- function buildPlanSystemPrompt(noTest = false) {
78
- const testGuidelines = noTest
79
- ? ''
80
- : `
81
-
82
- **E2E Test Tickets:**
83
- - Find test users in seed files (\`lib/db/seed.ts\`)
84
- - Pattern: \`*+kosuke_test@example.com\` → OTP: \`424242\`
85
- - Required: Test credentials, numbered steps, clear element descriptions, acceptance criteria`;
86
- return `# ROLE: TICKET PLANNER
87
-
88
- **YOUR PRIMARY OBJECTIVE:** Create implementation tickets that developers will use to build the feature. You analyze requirements and break them into structured, actionable tickets.
89
-
90
- **Your Workflow:**
91
-
92
- **Phase 1:** Ask clarification questions (non-technical, user-focused)
93
- **Phase 2:** Output raw JSON tickets array
94
-
95
- **Critical Rules:**
96
- - NEVER start implementation - you only create tickets
97
- - NEVER create/edit files, install packages, or use Task tool
98
- - ALWAYS explore codebase (Read/Grep/Glob) to understand patterns before asking questions
99
- - YOU decide technical implementation details based on existing codebase
100
-
101
- ## Phase 1: Ask Clarification Questions
102
-
103
- When a user describes a feature request, analyze the codebase (Read/Grep/Glob) to understand existing patterns, then ask **ONLY business/UX questions** (not technical implementation questions).
104
-
105
- **Your first response MUST use this exact format:**
106
-
107
- ---
108
- ## Understanding Your Request
109
- [Brief business summary - what the user wants to achieve, NOT implementation details]
110
-
111
- ## Clarification Questions
112
-
113
- For each clarification needed, provide BOTH a question AND a recommended approach:
114
-
115
- 1. **[Topic]**
116
- - Question: [Non-technical user question]
117
- - 💡 Recommendation: [Default choice that simplifies scope]
118
-
119
- 2. **[Topic]**
120
- - Question: [Non-technical user question]
121
- - 💡 Recommendation: [Default choice that simplifies scope]
122
-
123
- (Add as many questions as needed)
124
-
125
- **Quick Response Option:** You can reply "go for recommendations" to accept all recommended approaches at once.
126
- ---
127
-
128
- **ALLOWED QUESTIONS (User/Business Focus):**
129
- - What data to show/hide, empty state behavior
130
- - Error messages users see
131
- - Permission rules (who can do what)
132
- - User workflow and steps
133
-
134
- **FORBIDDEN QUESTIONS (Technical - YOU decide these):**
135
- - Which library to use (jsPDF, PDFKit, etc.)
136
- - Backend vs client-side generation
137
- - API design (REST, tRPC, GraphQL)
138
- - Database queries or ORM choice
139
- - Component structure or styling
140
- - Performance optimization techniques
141
-
142
- **YOU decide all technical choices** based on existing codebase patterns.
143
-
144
- **Language Reminders:**
145
- - ⚠️ NEVER say: "I'll implement", "Let me build", "Now I'll create the files"
146
- - ✅ INSTEAD say: "I'll create tickets for", "The tickets will include"
147
-
148
- ## Phase 2: Generate Tickets
149
-
150
- Once the user answers questions OR says "go for recommendations", immediately output a raw JSON array of tickets.
151
-
152
- **Critical:**
153
- - DO NOT say "Now I'll implement" or show "Implementation Plan" - you're creating TICKETS, not implementing
154
- - DO NOT read more files after Phase 1 completes
155
- - Your ENTIRE response = JSON array (no markdown wrapping, no explanations)
156
- - Output starts with "[" and ends with "]"
157
-
158
- **Required JSON Format:**
159
- [
160
- {
161
- "id": "PLAN-BACKEND-1",
162
- "title": "Add PDF export endpoint to orders router",
163
- "description": "Create tRPC endpoint that generates PDF.\\n\\n**Acceptance Criteria:**\\n- Accepts filter parameters\\n- Returns PDF file\\n- Respects filters",
164
- "type": "backend",
165
- "estimatedEffort": 5,
166
- "status": "Todo",
167
- "category": "orders"
168
- },
169
- {
170
- "id": "PLAN-FRONTEND-1",
171
- "title": "Add PDF export button to orders table",
172
- "description": "Add button to toolbar.\\n\\n**Acceptance Criteria:**\\n- Button visible\\n- Downloads PDF\\n- Shows loading state",
173
- "type": "frontend",
174
- "estimatedEffort": 4,
175
- "status": "Todo",
176
- "category": "orders"
177
- }${noTest
178
- ? ''
179
- : `,
180
- {
181
- "id": "PLAN-TEST-1",
182
- "title": "E2E: Test PDF export with filters",
183
- "description": "**Test User:** john+kosuke_test@example.com (OTP: 424242)\\n\\n**Steps:**\\n1. Sign in\\n2. Apply filters\\n3. Click PDF export\\n4. Verify download\\n\\n**Acceptance Criteria:**\\n- PDF downloads\\n- Contains filtered data",
184
- "type": "test",
185
- "estimatedEffort": 3,
186
- "status": "Todo",
187
- "category": "orders"
188
- }`}
189
- ]
190
-
191
- **CRITICAL - Exact Ticket ID Format (MUST MATCH):**
192
- - PLAN-SCHEMA-1, PLAN-SCHEMA-2, ... → type: "schema"
193
- - PLAN-ENGINE-1, PLAN-ENGINE-2, ... → type: "engine"
194
- - PLAN-BACKEND-1, PLAN-BACKEND-2, ... → type: "backend"
195
- - PLAN-FRONTEND-1, PLAN-FRONTEND-2, ... → type: "frontend"${noTest ? '' : '\n- PLAN-TEST-1, PLAN-TEST-2, ... → type: "test"'}
196
-
197
- **Required Fields (every ticket):**
198
- - id: Exact format above (e.g., "PLAN-TEST-1")
199
- - title: Short descriptive title
200
- - description: Details with **Acceptance Criteria:** section (use \\n for newlines)
201
- - type: MUST be one of: "schema", "engine", "backend", "frontend"${noTest ? '' : ', "test"'}
202
- - estimatedEffort: Integer from 1 to 10
203
- - status: ALWAYS "Todo"
204
- - category: Optional (e.g., "orders", "auth", "billing")
205
-
206
- **Dependency order:** SCHEMA → ENGINE → BACKEND → FRONTEND${noTest ? '' : ' → TEST'}
207
- ${testGuidelines}
208
-
209
- 🚨 **WHEN USER SAYS "go for recommendations" OR ANSWERS YOUR QUESTIONS:**
210
-
211
- YOU ARE NOW IN PHASE 2. EXPLORATION IS OVER.
212
-
213
- DO NOT:
214
- - Read more files
215
- - Search for packages
216
- - Say "Now I'll implement" or "Let me create"
217
- - Use Task tool
218
- - Show "Implementation Plan"
219
- - Add any text before or after the JSON
220
-
221
- IMMEDIATELY OUTPUT THE JSON ARRAY. Your ENTIRE response = JSON array starting with "[" and ending with "]".
222
-
223
- **Examples:**
224
-
225
- ❌ WRONG: \`Perfect! Now I'll implement... [shows implementation plan]\`
226
- ❌ WRONG: \`Great! I'll create the tickets. \\\`\\\`\\\`json [...] \\\`\\\`\\\`\` (markdown wrapping)
227
- ❌ WRONG: \`Now I'll update the files...\`
228
-
229
- ✅ CORRECT: \`[{"id": "PLAN-BACKEND-1", "title": "Add PDF export endpoint", ...}]\`
230
-
231
- Just the raw JSON array. No explanatory text. No markdown code fences. No "Now I'll implement" language.`;
232
- }
233
- /**
234
- * Shared setup for plan agent configuration
235
- */
236
- function createPlanAgentConfig(options) {
237
- const { prompt, directory, noTest = false, resume } = options;
238
- // Validate directory
239
- const cwd = directory ? resolve(directory) : process.cwd();
240
- if (!existsSync(cwd)) {
241
- return { error: `Directory not found: ${cwd}` };
242
- }
243
- const stats = statSync(cwd);
244
- if (!stats.isDirectory()) {
245
- return { error: `Path is not a directory: ${cwd}` };
246
- }
247
- const ticketsPath = generateTicketsPath(cwd);
248
- const systemPrompt = buildPlanSystemPrompt(noTest);
249
- const config = {
250
- systemPrompt,
251
- cwd,
252
- maxTurns: 40, // Increased for complex planning sessions with multiple files to analyze
253
- verbosity: 'verbose',
254
- permissionMode: 'bypassPermissions',
255
- // Restrict to read-only tools only
256
- // Block all code editing, execution, task management, and agent control tools
257
- disallowedTools: [
258
- 'Edit', // File editing
259
- 'Write', // File creation
260
- 'Delete', // File deletion
261
- 'NotebookEdit', // Notebook editing
262
- 'Bash', // Shell execution
263
- 'Task', // Sub-agent spawning (prevents implementation subtasks)
264
- 'TodoWrite', // Task management (implementation mode)
265
- 'ExitPlanMode', // Mode transitions
266
- ],
267
- ...(resume && { resume }),
268
- };
269
- return { config, ticketsPath, cwd, prompt };
270
- }
271
- /**
272
- * Plan core stream for server (async generator, no logging)
273
- */
274
- export async function* planCoreStream(options) {
275
- const setup = createPlanAgentConfig(options);
276
- if ('error' in setup) {
277
- yield {
278
- type: 'done',
279
- data: {
280
- status: 'error',
281
- ticketsFile: null,
282
- tokensUsed: { input: 0, output: 0, cacheCreation: 0, cacheRead: 0 },
283
- cost: 0,
284
- error: setup.error,
285
- },
286
- };
287
- return;
288
- }
289
- const { config, ticketsPath, prompt } = setup;
290
- try {
291
- const stream = runAgentStream(prompt, config);
292
- let sessionId;
293
- let fullResponse = '';
294
- let tokensUsed = { input: 0, output: 0, cacheCreation: 0, cacheRead: 0 };
295
- let cost = 0;
296
- // Yield events from stream
297
- for await (const event of stream) {
298
- if (event.type === 'message') {
299
- const claudeMessage = event.data;
300
- yield { type: 'message', data: claudeMessage };
301
- // Track session ID
302
- if (claudeMessage.session_id) {
303
- sessionId = claudeMessage.session_id;
304
- }
305
- // Accumulate response text and extract tool calls from assistant messages
306
- if (claudeMessage.type === 'assistant' && claudeMessage.message) {
307
- const msg = claudeMessage.message;
308
- if (msg.content && Array.isArray(msg.content)) {
309
- for (const block of msg.content) {
310
- if (block.type === 'text' && block.text) {
311
- fullResponse += block.text;
312
- }
313
- else if (block.type === 'tool_use' && block.name) {
314
- // Yield tool call event
315
- yield {
316
- type: 'tool_call',
317
- data: { name: block.name, input: block.input || {} },
318
- };
319
- }
320
- }
321
- }
322
- }
323
- }
324
- else if (event.type === 'agent_result') {
325
- // Use metrics from final result
326
- tokensUsed = event.data.tokensUsed;
327
- cost = event.data.cost;
328
- if (event.data.sessionId) {
329
- sessionId = event.data.sessionId;
330
- }
331
- }
332
- }
333
- // Try to parse tickets from response (Phase 2)
334
- try {
335
- const tickets = extractTicketsJSON(fullResponse);
336
- // If no tickets were parsed, this is Phase 1 (clarification questions)
337
- if (!tickets || tickets.length === 0) {
338
- yield {
339
- type: 'done',
340
- data: {
341
- status: 'input_required',
342
- ticketsFile: null,
343
- tokensUsed,
344
- cost,
345
- sessionId,
346
- },
347
- };
348
- return;
349
- }
350
- // Sort and write tickets (no validation, no summary in stream mode)
351
- const sortedTickets = sortTicketsByOrder(tickets);
352
- writeTicketsFile(ticketsPath, sortedTickets);
353
- yield {
354
- type: 'done',
355
- data: {
356
- status: 'success',
357
- ticketsFile: ticketsPath,
358
- tokensUsed,
359
- cost,
360
- sessionId,
361
- },
362
- };
363
- }
364
- catch (parseError) {
365
- const errorMsg = parseError instanceof Error ? parseError.message : String(parseError);
366
- // Check if this is a parse/validation error or just Phase 1
367
- if (errorMsg.includes('No JSON array found')) {
368
- // This is Phase 1 (clarification questions)
369
- yield {
370
- type: 'done',
371
- data: {
372
- status: 'input_required',
373
- ticketsFile: null,
374
- tokensUsed,
375
- cost,
376
- sessionId,
377
- },
378
- };
379
- }
380
- else {
381
- // Actual validation error
382
- yield {
383
- type: 'done',
384
- data: {
385
- status: 'error',
386
- ticketsFile: null,
387
- tokensUsed,
388
- cost: 0,
389
- error: errorMsg,
390
- },
391
- };
392
- }
393
- }
394
- }
395
- catch (error) {
396
- yield {
397
- type: 'done',
398
- data: {
399
- status: 'error',
400
- ticketsFile: null,
401
- tokensUsed: { input: 0, output: 0, cacheCreation: 0, cacheRead: 0 },
402
- cost: 0,
403
- error: error instanceof Error ? error.message : String(error),
404
- },
405
- };
406
- }
407
- }
408
- /**
409
- * Plan interactive session for CLI (single turn with logging)
410
- */
411
- async function planInteractiveSession(options) {
412
- const setup = createPlanAgentConfig(options);
413
- if ('error' in setup) {
414
- return {
415
- status: 'error',
416
- ticketsFile: null,
417
- tokensUsed: { input: 0, output: 0, cacheCreation: 0, cacheRead: 0 },
418
- cost: 0,
419
- error: setup.error,
420
- };
421
- }
422
- const { config, ticketsPath, prompt } = setup;
423
- try {
424
- console.log('\n🤔 Claude is analyzing...\n');
425
- // Run agent with streaming
426
- const stream = runAgentStream(prompt, config);
427
- let response = '';
428
- let tokensUsed = { input: 0, output: 0, cacheCreation: 0, cacheRead: 0 };
429
- let cost = 0;
430
- let sessionId;
431
- // Process stream
432
- const filesReferenced = new Set();
433
- for await (const event of stream) {
434
- if (event.type === 'message') {
435
- const message = event.data;
436
- if (message.type === 'assistant' && message.message?.content) {
437
- for (const block of message.message.content) {
438
- if (block.type === 'text' && block.text) {
439
- logAssistantMessage(block.text, 'verbose');
440
- }
441
- else if (block.type === 'tool_use' && block.name) {
442
- logToolUsage(block.name, block.input, filesReferenced);
443
- }
444
- }
445
- }
446
- }
447
- else if (event.type === 'agent_result') {
448
- response = event.data.response;
449
- tokensUsed = event.data.tokensUsed;
450
- cost = event.data.cost;
451
- sessionId = event.data.sessionId;
452
- }
453
- }
454
- // Display cost
455
- console.log('\n' + '─'.repeat(90));
456
- console.log(`💰 Cost: ${formatCostBreakdown({
457
- tokensUsed,
458
- cost,
459
- response: '',
460
- fixCount: 0,
461
- filesReferenced: new Set(),
462
- })}`);
463
- console.log('─'.repeat(90) + '\n');
464
- // Try to parse tickets from response (Phase 2)
465
- try {
466
- const tickets = extractTicketsJSON(response);
467
- // If no tickets were parsed, this is Phase 1 (clarification questions)
468
- if (!tickets || tickets.length === 0) {
469
- return {
470
- status: 'input_required',
471
- ticketsFile: null,
472
- tokensUsed,
473
- cost,
474
- sessionId,
475
- message: response,
476
- };
477
- }
478
- // Sort and write tickets (no validation, no summary)
479
- const sortedTickets = sortTicketsByOrder(tickets);
480
- writeTicketsFile(ticketsPath, sortedTickets);
481
- console.log(`\n✅ Successfully created ${tickets.length} tickets: ${ticketsPath}\n`);
482
- return {
483
- status: 'success',
484
- ticketsFile: ticketsPath,
485
- tokensUsed,
486
- cost,
487
- sessionId,
488
- message: response,
489
- };
490
- }
491
- catch (parseError) {
492
- const errorMsg = parseError instanceof Error ? parseError.message : String(parseError);
493
- // Check if this is a parse/validation error or just Phase 1
494
- if (errorMsg.includes('No JSON array found')) {
495
- // This is Phase 1 (clarification questions)
496
- return {
497
- status: 'input_required',
498
- ticketsFile: null,
499
- tokensUsed,
500
- cost,
501
- sessionId,
502
- message: response,
503
- };
504
- }
505
- // Actual validation error - show it
506
- console.error(`\n❌ Ticket validation failed: ${errorMsg}\n`);
507
- return {
508
- status: 'error',
509
- ticketsFile: null,
510
- tokensUsed,
511
- cost,
512
- error: errorMsg,
513
- };
514
- }
515
- }
516
- catch (error) {
517
- return {
518
- status: 'error',
519
- ticketsFile: null,
520
- tokensUsed: { input: 0, output: 0, cacheCreation: 0, cacheRead: 0 },
521
- cost: 0,
522
- error: error instanceof Error ? error.message : String(error),
523
- };
524
- }
525
- }
526
- /**
527
- * Main plan command (interactive CLI wrapper)
528
- */
529
- export async function planCommand(options) {
530
- // Initialize logging
531
- const logContext = logger.createContext('plan', { noLogs: options.noLogs ?? false });
532
- const cleanupHandler = setupCancellationHandler(logContext);
533
- try {
534
- // Validate environment
535
- if (!process.env.ANTHROPIC_API_KEY) {
536
- throw new Error('ANTHROPIC_API_KEY environment variable is required');
537
- }
538
- // Validate prompt
539
- if (!options.prompt) {
540
- throw new Error('Prompt is required. Use --prompt="Your feature or bug description"\n' +
541
- 'Example: kosuke plan --prompt="Add dark mode toggle" --directory=./my-project');
542
- }
543
- // Resolve directory
544
- const cwd = options.directory ? resolve(options.directory) : process.cwd();
545
- if (!existsSync(cwd)) {
546
- throw new Error(`Directory not found: ${cwd}`);
547
- }
548
- const stats = statSync(cwd);
549
- if (!stats.isDirectory()) {
550
- throw new Error(`Path is not a directory: ${cwd}`);
551
- }
552
- console.log(`
553
- ╔══════════════════════════════════════════════════════════════════════════════╗
554
- ║ Kosuke Plan - AI-Driven Ticket Planning ║
555
- ╚══════════════════════════════════════════════════════════════════════════════╝
556
- `);
557
- console.log('💡 This tool will help you create implementation tickets from your feature/bug description.\n');
558
- console.log('🤖 Claude will explore your codebase to understand patterns and conventions.\n');
559
- console.log('✨ Tip: Enter to submit, Ctrl+J for new lines.\n');
560
- console.log(`📁 Using project directory: ${cwd}\n`);
561
- // Set up Ctrl+C handler
562
- const handleSigInt = async () => {
563
- console.log('\n\n👋 Exiting planning session...\n');
564
- await logger.complete(logContext, 'cancelled');
565
- cleanupHandler();
566
- process.exit(0);
567
- };
568
- process.on('SIGINT', handleSigInt);
569
- let currentPrompt = options.prompt;
570
- let sessionId = options.resume;
571
- let totalInputTokens = 0;
572
- let totalOutputTokens = 0;
573
- let totalCacheCreationTokens = 0;
574
- let totalCacheReadTokens = 0;
575
- let totalCost = 0;
576
- try {
577
- // Interactive loop
578
- while (true) {
579
- const result = await planInteractiveSession({
580
- prompt: currentPrompt,
581
- directory: cwd,
582
- noTest: options.noTest,
583
- resume: sessionId,
584
- });
585
- // Track cumulative costs
586
- totalInputTokens += result.tokensUsed.input;
587
- totalOutputTokens += result.tokensUsed.output;
588
- totalCacheCreationTokens += result.tokensUsed.cacheCreation;
589
- totalCacheReadTokens += result.tokensUsed.cacheRead;
590
- totalCost += result.cost;
591
- sessionId = result.sessionId;
592
- if (result.status === 'success') {
593
- // Planning complete
594
- console.log('═'.repeat(90));
595
- console.log('📊 Total Session Cost:');
596
- console.log(`💰 ${formatCostBreakdown({
597
- tokensUsed: {
598
- input: totalInputTokens,
599
- output: totalOutputTokens,
600
- cacheCreation: totalCacheCreationTokens,
601
- cacheRead: totalCacheReadTokens,
602
- },
603
- cost: totalCost,
604
- response: '',
605
- fixCount: 0,
606
- filesReferenced: new Set(),
607
- })}`);
608
- console.log('═'.repeat(90));
609
- const relativeTicketsPath = result.ticketsFile.replace(cwd + '/', '');
610
- console.log('\n🎉 Planning complete!\n');
611
- console.log('💡 Next steps:');
612
- console.log(' - Review tickets: cat "' + result.ticketsFile + '"');
613
- console.log(' - Build tickets: kosuke build --directory="' +
614
- cwd +
615
- '" --tickets="' +
616
- relativeTicketsPath +
617
- '"');
618
- console.log(' - List all tickets: ls ' + join(cwd, 'tickets'));
619
- if (sessionId) {
620
- console.log(`\n💾 Session ID: ${sessionId}`);
621
- }
622
- logger.trackTokens(logContext, {
623
- input: totalInputTokens,
624
- output: totalOutputTokens,
625
- cacheCreation: totalCacheCreationTokens,
626
- cacheRead: totalCacheReadTokens,
627
- });
628
- await logger.complete(logContext, 'success');
629
- break;
630
- }
631
- else if (result.status === 'input_required') {
632
- // Ask for user response
633
- console.log('💬 Your response (type "exit" to quit):\n');
634
- const userResponse = await askQuestion('You: ');
635
- if (!userResponse) {
636
- console.log('\n⚠️ Empty response. Please provide an answer or type "exit".');
637
- continue;
638
- }
639
- if (userResponse.toLowerCase() === 'exit') {
640
- console.log('\n👋 Exiting planning session.\n');
641
- if (sessionId) {
642
- console.log('💾 Session ID (to resume later):');
643
- console.log(` ${sessionId}\n`);
644
- console.log(' Resume with: kosuke plan --prompt="continue" --resume=' + sessionId + '\n');
645
- }
646
- console.log('═'.repeat(90));
647
- console.log('📊 Session Cost:');
648
- console.log(`💰 ${formatCostBreakdown({
649
- tokensUsed: {
650
- input: totalInputTokens,
651
- output: totalOutputTokens,
652
- cacheCreation: totalCacheCreationTokens,
653
- cacheRead: totalCacheReadTokens,
654
- },
655
- cost: totalCost,
656
- response: '',
657
- fixCount: 0,
658
- filesReferenced: new Set(),
659
- })}`);
660
- console.log('═'.repeat(90) + '\n');
661
- await logger.complete(logContext, 'cancelled');
662
- break;
663
- }
664
- currentPrompt = userResponse;
665
- }
666
- else {
667
- // Error
668
- throw new Error(result.error || 'Unknown error during planning');
669
- }
670
- }
671
- }
672
- finally {
673
- process.removeListener('SIGINT', handleSigInt);
674
- }
675
- cleanupHandler();
676
- }
677
- catch (error) {
678
- console.error('\n❌ Plan command failed:', error);
679
- await logger.complete(logContext, 'error', error);
680
- cleanupHandler();
681
- throw error;
682
- }
683
- }
684
- //# sourceMappingURL=plan.js.map