gencode-ai 0.1.1 → 0.1.3

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 (287) hide show
  1. package/.gencode/settings.local.json +7 -0
  2. package/CLAUDE.md +86 -0
  3. package/README.md +13 -16
  4. package/dist/agent/agent.d.ts +50 -1
  5. package/dist/agent/agent.d.ts.map +1 -1
  6. package/dist/agent/agent.js +96 -16
  7. package/dist/agent/agent.js.map +1 -1
  8. package/dist/agent/index.d.ts +1 -0
  9. package/dist/agent/index.d.ts.map +1 -1
  10. package/dist/agent/types.d.ts +14 -1
  11. package/dist/agent/types.d.ts.map +1 -1
  12. package/dist/cli/components/App.d.ts +8 -1
  13. package/dist/cli/components/App.d.ts.map +1 -1
  14. package/dist/cli/components/App.js +266 -29
  15. package/dist/cli/components/App.js.map +1 -1
  16. package/dist/cli/components/CommandSuggestions.d.ts.map +1 -1
  17. package/dist/cli/components/CommandSuggestions.js +2 -0
  18. package/dist/cli/components/CommandSuggestions.js.map +1 -1
  19. package/dist/cli/components/Header.d.ts +1 -1
  20. package/dist/cli/components/Header.d.ts.map +1 -1
  21. package/dist/cli/components/Header.js +4 -6
  22. package/dist/cli/components/Header.js.map +1 -1
  23. package/dist/cli/components/Logo.d.ts +1 -0
  24. package/dist/cli/components/Logo.d.ts.map +1 -1
  25. package/dist/cli/components/Logo.js +16 -3
  26. package/dist/cli/components/Logo.js.map +1 -1
  27. package/dist/cli/components/Messages.d.ts +4 -4
  28. package/dist/cli/components/Messages.d.ts.map +1 -1
  29. package/dist/cli/components/Messages.js +66 -23
  30. package/dist/cli/components/Messages.js.map +1 -1
  31. package/dist/cli/components/PermissionPrompt.d.ts +60 -0
  32. package/dist/cli/components/PermissionPrompt.d.ts.map +1 -0
  33. package/dist/cli/components/PermissionPrompt.js +192 -0
  34. package/dist/cli/components/PermissionPrompt.js.map +1 -0
  35. package/dist/cli/components/ProviderManager.js +3 -3
  36. package/dist/cli/components/ProviderManager.js.map +1 -1
  37. package/dist/cli/components/QuestionPrompt.d.ts +23 -0
  38. package/dist/cli/components/QuestionPrompt.d.ts.map +1 -0
  39. package/dist/cli/components/QuestionPrompt.js +231 -0
  40. package/dist/cli/components/QuestionPrompt.js.map +1 -0
  41. package/dist/cli/components/Spinner.d.ts +7 -2
  42. package/dist/cli/components/Spinner.d.ts.map +1 -1
  43. package/dist/cli/components/Spinner.js +116 -25
  44. package/dist/cli/components/Spinner.js.map +1 -1
  45. package/dist/cli/components/TodoList.d.ts +7 -0
  46. package/dist/cli/components/TodoList.d.ts.map +1 -0
  47. package/dist/cli/components/TodoList.js +34 -0
  48. package/dist/cli/components/TodoList.js.map +1 -0
  49. package/dist/cli/components/index.d.ts +2 -0
  50. package/dist/cli/components/index.d.ts.map +1 -1
  51. package/dist/cli/components/index.js +2 -0
  52. package/dist/cli/components/index.js.map +1 -1
  53. package/dist/cli/components/theme.d.ts +7 -0
  54. package/dist/cli/components/theme.d.ts.map +1 -1
  55. package/dist/cli/components/theme.js +11 -1
  56. package/dist/cli/components/theme.js.map +1 -1
  57. package/dist/cli/index.js +47 -7
  58. package/dist/cli/index.js.map +1 -1
  59. package/dist/config/index.d.ts +13 -4
  60. package/dist/config/index.d.ts.map +1 -1
  61. package/dist/config/index.js +18 -3
  62. package/dist/config/index.js.map +1 -1
  63. package/dist/config/levels.d.ts +49 -0
  64. package/dist/config/levels.d.ts.map +1 -0
  65. package/dist/config/levels.js +222 -0
  66. package/dist/config/levels.js.map +1 -0
  67. package/dist/config/loader.d.ts +46 -0
  68. package/dist/config/loader.d.ts.map +1 -0
  69. package/dist/config/loader.js +153 -0
  70. package/dist/config/loader.js.map +1 -0
  71. package/dist/config/manager.d.ts +115 -15
  72. package/dist/config/manager.d.ts.map +1 -1
  73. package/dist/config/manager.js +260 -34
  74. package/dist/config/manager.js.map +1 -1
  75. package/dist/config/manager.test.d.ts +5 -0
  76. package/dist/config/manager.test.d.ts.map +1 -0
  77. package/dist/config/manager.test.js +192 -0
  78. package/dist/config/manager.test.js.map +1 -0
  79. package/dist/config/merger.d.ts +56 -0
  80. package/dist/config/merger.d.ts.map +1 -0
  81. package/dist/config/merger.js +177 -0
  82. package/dist/config/merger.js.map +1 -0
  83. package/dist/config/test-utils.d.ts +24 -0
  84. package/dist/config/test-utils.d.ts.map +1 -0
  85. package/dist/config/test-utils.js +55 -0
  86. package/dist/config/test-utils.js.map +1 -0
  87. package/dist/config/types.d.ts +78 -9
  88. package/dist/config/types.d.ts.map +1 -1
  89. package/dist/config/types.js +52 -2
  90. package/dist/config/types.js.map +1 -1
  91. package/dist/memory/import-resolver.d.ts +46 -0
  92. package/dist/memory/import-resolver.d.ts.map +1 -0
  93. package/dist/memory/import-resolver.js +117 -0
  94. package/dist/memory/import-resolver.js.map +1 -0
  95. package/dist/memory/index.d.ts +7 -6
  96. package/dist/memory/index.d.ts.map +1 -1
  97. package/dist/memory/index.js +7 -5
  98. package/dist/memory/index.js.map +1 -1
  99. package/dist/memory/init-prompt.d.ts +22 -0
  100. package/dist/memory/init-prompt.d.ts.map +1 -0
  101. package/dist/memory/init-prompt.js +103 -0
  102. package/dist/memory/init-prompt.js.map +1 -0
  103. package/dist/memory/memory-manager.d.ts +119 -0
  104. package/dist/memory/memory-manager.d.ts.map +1 -0
  105. package/dist/memory/memory-manager.js +587 -0
  106. package/dist/memory/memory-manager.js.map +1 -0
  107. package/dist/memory/rules-parser.d.ts +38 -0
  108. package/dist/memory/rules-parser.d.ts.map +1 -0
  109. package/dist/memory/rules-parser.js +69 -0
  110. package/dist/memory/rules-parser.js.map +1 -0
  111. package/dist/memory/test-utils.d.ts +20 -0
  112. package/dist/memory/test-utils.d.ts.map +1 -0
  113. package/dist/memory/test-utils.js +44 -0
  114. package/dist/memory/test-utils.js.map +1 -0
  115. package/dist/memory/types.d.ts +70 -63
  116. package/dist/memory/types.d.ts.map +1 -1
  117. package/dist/memory/types.js +42 -2
  118. package/dist/memory/types.js.map +1 -1
  119. package/dist/permissions/audit.d.ts +82 -0
  120. package/dist/permissions/audit.d.ts.map +1 -0
  121. package/dist/permissions/audit.js +229 -0
  122. package/dist/permissions/audit.js.map +1 -0
  123. package/dist/permissions/index.d.ts +11 -1
  124. package/dist/permissions/index.d.ts.map +1 -1
  125. package/dist/permissions/index.js +15 -0
  126. package/dist/permissions/index.js.map +1 -1
  127. package/dist/permissions/manager.d.ts +149 -13
  128. package/dist/permissions/manager.d.ts.map +1 -1
  129. package/dist/permissions/manager.js +480 -35
  130. package/dist/permissions/manager.js.map +1 -1
  131. package/dist/permissions/manager.test.d.ts +5 -0
  132. package/dist/permissions/manager.test.d.ts.map +1 -0
  133. package/dist/permissions/manager.test.js +213 -0
  134. package/dist/permissions/manager.test.js.map +1 -0
  135. package/dist/permissions/persistence.d.ts +74 -0
  136. package/dist/permissions/persistence.d.ts.map +1 -0
  137. package/dist/permissions/persistence.js +248 -0
  138. package/dist/permissions/persistence.js.map +1 -0
  139. package/dist/permissions/persistence.test.d.ts +5 -0
  140. package/dist/permissions/persistence.test.d.ts.map +1 -0
  141. package/dist/permissions/persistence.test.js +171 -0
  142. package/dist/permissions/persistence.test.js.map +1 -0
  143. package/dist/permissions/prompt-matcher.d.ts +64 -0
  144. package/dist/permissions/prompt-matcher.d.ts.map +1 -0
  145. package/dist/permissions/prompt-matcher.js +415 -0
  146. package/dist/permissions/prompt-matcher.js.map +1 -0
  147. package/dist/permissions/prompt-matcher.test.d.ts +5 -0
  148. package/dist/permissions/prompt-matcher.test.d.ts.map +1 -0
  149. package/dist/permissions/prompt-matcher.test.js +107 -0
  150. package/dist/permissions/prompt-matcher.test.js.map +1 -0
  151. package/dist/permissions/types.d.ts +157 -0
  152. package/dist/permissions/types.d.ts.map +1 -1
  153. package/dist/permissions/types.js +45 -8
  154. package/dist/permissions/types.js.map +1 -1
  155. package/dist/prompts/index.d.ts +92 -0
  156. package/dist/prompts/index.d.ts.map +1 -0
  157. package/dist/prompts/index.js +241 -0
  158. package/dist/prompts/index.js.map +1 -0
  159. package/dist/tools/builtin/ask-user.d.ts +64 -0
  160. package/dist/tools/builtin/ask-user.d.ts.map +1 -0
  161. package/dist/tools/builtin/ask-user.js +148 -0
  162. package/dist/tools/builtin/ask-user.js.map +1 -0
  163. package/dist/tools/builtin/bash.d.ts.map +1 -1
  164. package/dist/tools/builtin/bash.js +2 -1
  165. package/dist/tools/builtin/bash.js.map +1 -1
  166. package/dist/tools/builtin/edit.d.ts.map +1 -1
  167. package/dist/tools/builtin/edit.js +2 -1
  168. package/dist/tools/builtin/edit.js.map +1 -1
  169. package/dist/tools/builtin/glob.d.ts.map +1 -1
  170. package/dist/tools/builtin/glob.js +2 -1
  171. package/dist/tools/builtin/glob.js.map +1 -1
  172. package/dist/tools/builtin/grep.d.ts.map +1 -1
  173. package/dist/tools/builtin/grep.js +2 -1
  174. package/dist/tools/builtin/grep.js.map +1 -1
  175. package/dist/tools/builtin/read.d.ts.map +1 -1
  176. package/dist/tools/builtin/read.js +2 -1
  177. package/dist/tools/builtin/read.js.map +1 -1
  178. package/dist/tools/builtin/todowrite.d.ts +15 -0
  179. package/dist/tools/builtin/todowrite.d.ts.map +1 -0
  180. package/dist/tools/builtin/todowrite.js +88 -0
  181. package/dist/tools/builtin/todowrite.js.map +1 -0
  182. package/dist/tools/builtin/webfetch.d.ts.map +1 -1
  183. package/dist/tools/builtin/webfetch.js +2 -5
  184. package/dist/tools/builtin/webfetch.js.map +1 -1
  185. package/dist/tools/builtin/websearch.d.ts.map +1 -1
  186. package/dist/tools/builtin/websearch.js +2 -16
  187. package/dist/tools/builtin/websearch.js.map +1 -1
  188. package/dist/tools/builtin/write.d.ts.map +1 -1
  189. package/dist/tools/builtin/write.js +2 -1
  190. package/dist/tools/builtin/write.js.map +1 -1
  191. package/dist/tools/index.d.ts +19 -0
  192. package/dist/tools/index.d.ts.map +1 -1
  193. package/dist/tools/index.js +8 -0
  194. package/dist/tools/index.js.map +1 -1
  195. package/dist/tools/types.d.ts +39 -0
  196. package/dist/tools/types.d.ts.map +1 -1
  197. package/dist/tools/types.js +8 -0
  198. package/dist/tools/types.js.map +1 -1
  199. package/docs/config-system-comparison.md +707 -0
  200. package/docs/memory-system.md +238 -0
  201. package/docs/permissions.md +368 -0
  202. package/docs/proposals/0005-todo-system.md +350 -85
  203. package/docs/proposals/0006-memory-system.md +11 -10
  204. package/docs/proposals/0012-ask-user-question.md +1007 -207
  205. package/docs/proposals/0023-permission-enhancements.md +61 -2
  206. package/docs/proposals/0041-configuration-system.md +33 -2
  207. package/docs/proposals/0042-prompt-optimization.md +866 -0
  208. package/docs/proposals/README.md +7 -6
  209. package/examples/test-ask-user.ts +167 -0
  210. package/jest.config.js +26 -0
  211. package/package.json +8 -2
  212. package/src/agent/agent.ts +130 -16
  213. package/src/agent/index.ts +1 -0
  214. package/src/agent/types.ts +13 -1
  215. package/src/cli/components/App.tsx +362 -37
  216. package/src/cli/components/CommandSuggestions.tsx +2 -0
  217. package/src/cli/components/Header.tsx +11 -17
  218. package/src/cli/components/Logo.tsx +76 -9
  219. package/src/cli/components/Messages.tsx +104 -41
  220. package/src/cli/components/PermissionPrompt.tsx +388 -0
  221. package/src/cli/components/ProviderManager.tsx +5 -5
  222. package/src/cli/components/QuestionPrompt.tsx +462 -0
  223. package/src/cli/components/Spinner.tsx +138 -25
  224. package/src/cli/components/TodoList.tsx +54 -0
  225. package/src/cli/components/index.ts +7 -0
  226. package/src/cli/components/theme.ts +11 -1
  227. package/src/cli/index.tsx +54 -6
  228. package/src/config/index.ts +78 -4
  229. package/src/config/levels.test.ts +163 -0
  230. package/src/config/levels.ts +285 -0
  231. package/src/config/loader.test.ts +120 -0
  232. package/src/config/loader.ts +178 -0
  233. package/src/config/manager.test.ts +215 -0
  234. package/src/config/manager.ts +328 -40
  235. package/src/config/merger.test.ts +360 -0
  236. package/src/config/merger.ts +221 -0
  237. package/src/config/test-utils.ts +79 -0
  238. package/src/config/types.ts +152 -9
  239. package/src/memory/import-resolver.test.ts +117 -0
  240. package/src/memory/import-resolver.ts +149 -0
  241. package/src/memory/index.ts +11 -0
  242. package/src/memory/init-prompt.ts +113 -0
  243. package/src/memory/memory-manager.test.ts +198 -0
  244. package/src/memory/memory-manager.ts +716 -0
  245. package/src/memory/rules-parser.test.ts +182 -0
  246. package/src/memory/rules-parser.ts +82 -0
  247. package/src/memory/test-utils.ts +60 -0
  248. package/src/memory/types.ts +119 -0
  249. package/src/permissions/audit.ts +284 -0
  250. package/src/permissions/index.ts +20 -1
  251. package/src/permissions/manager.test.ts +260 -0
  252. package/src/permissions/manager.ts +592 -40
  253. package/src/permissions/persistence.test.ts +220 -0
  254. package/src/permissions/persistence.ts +301 -0
  255. package/src/permissions/prompt-matcher.test.ts +213 -0
  256. package/src/permissions/prompt-matcher.ts +472 -0
  257. package/src/permissions/types.ts +238 -8
  258. package/src/prompts/index.test.ts +279 -0
  259. package/src/prompts/index.ts +306 -0
  260. package/src/prompts/system/anthropic.txt +29 -0
  261. package/src/prompts/system/base.txt +166 -0
  262. package/src/prompts/system/gemini.txt +35 -0
  263. package/src/prompts/system/generic.txt +128 -0
  264. package/src/prompts/system/openai.txt +29 -0
  265. package/src/prompts/tools/ask-user.txt +110 -0
  266. package/src/prompts/tools/bash.txt +60 -0
  267. package/src/prompts/tools/edit.txt +29 -0
  268. package/src/prompts/tools/glob.txt +35 -0
  269. package/src/prompts/tools/grep.txt +43 -0
  270. package/src/prompts/tools/read.txt +22 -0
  271. package/src/prompts/tools/todowrite.txt +71 -0
  272. package/src/prompts/tools/webfetch.txt +34 -0
  273. package/src/prompts/tools/websearch.txt +41 -0
  274. package/src/prompts/tools/write.txt +23 -0
  275. package/src/tools/builtin/ask-user.ts +185 -0
  276. package/src/tools/builtin/bash.ts +2 -1
  277. package/src/tools/builtin/edit.ts +2 -1
  278. package/src/tools/builtin/glob.ts +2 -1
  279. package/src/tools/builtin/grep.ts +2 -1
  280. package/src/tools/builtin/read.ts +2 -1
  281. package/src/tools/builtin/todowrite.ts +102 -0
  282. package/src/tools/builtin/webfetch.ts +2 -5
  283. package/src/tools/builtin/websearch.ts +2 -16
  284. package/src/tools/builtin/write.ts +2 -1
  285. package/src/tools/index.ts +19 -0
  286. package/src/tools/types.ts +30 -0
  287. package/tsconfig.json +1 -1
@@ -1,193 +1,720 @@
1
1
  # Proposal: AskUserQuestion Tool
2
2
 
3
3
  - **Proposal ID**: 0012
4
- - **Author**: mycode team
5
- - **Status**: Draft
4
+ - **Author**: gencode team
5
+ - **Status**: Implemented
6
6
  - **Created**: 2025-01-15
7
- - **Updated**: 2025-01-15
7
+ - **Updated**: 2025-01-16
8
+ - **Implemented**: 2025-01-16
8
9
 
9
10
  ## Summary
10
11
 
11
12
  Implement an AskUserQuestion tool that allows the agent to pause execution and present structured questions to the user with predefined options. This enables gathering user preferences, clarifying ambiguous instructions, and making decisions during task execution.
12
13
 
13
- ## Motivation
14
+ ## Problem Analysis
14
15
 
15
- Currently, mycode has no structured way for the agent to ask clarifying questions. This leads to:
16
+ ### Current Limitations
16
17
 
17
- 1. **Assumptions**: Agent guesses when requirements are unclear
18
- 2. **Wasted work**: Wrong assumptions lead to redoing work
19
- 3. **Poor UX**: Unstructured questions mixed with output
20
- 4. **No multi-select**: Can't gather multiple preferences at once
21
- 5. **No defaults**: Can't recommend options to users
18
+ Without a structured questioning mechanism, the agent faces several challenges:
22
19
 
23
- A structured question tool enables clear, efficient user interaction.
20
+ ```
21
+ ┌─────────────────────────────────────────────────────────────────────────────┐
22
+ │ PROBLEM SCENARIOS │
23
+ ├─────────────────────────────────────────────────────────────────────────────┤
24
+ │ │
25
+ │ Scenario 1: Ambiguous Requirements │
26
+ │ ┌───────────────────────────────────────────────────────────────────────┐ │
27
+ │ │ User: "Add authentication to my app" │ │
28
+ │ │ │ │
29
+ │ │ Agent's dilemma: │ │
30
+ │ │ ├── OAuth 2.0? JWT? Session-based? │ │
31
+ │ │ ├── Which providers? Google? GitHub? Email/Password? │ │
32
+ │ │ └── Store in database? External service? │ │
33
+ │ │ │ │
34
+ │ │ Current behavior: Agent GUESSES → Wrong choice → Rework required │ │
35
+ │ └───────────────────────────────────────────────────────────────────────┘ │
36
+ │ │
37
+ │ Scenario 2: Multiple Valid Approaches │
38
+ │ ┌───────────────────────────────────────────────────────────────────────┐ │
39
+ │ │ User: "Optimize database queries" │ │
40
+ │ │ │ │
41
+ │ │ Options available: │ │
42
+ │ │ ├── Add indexes (fastest, minimal code change) │ │
43
+ │ │ ├── Denormalize tables (faster reads, more storage) │ │
44
+ │ │ ├── Add caching layer (best for hot data) │ │
45
+ │ │ └── Query restructuring (most maintainable) │ │
46
+ │ │ │ │
47
+ │ │ Current behavior: Agent picks one → User wanted different approach │ │
48
+ │ └───────────────────────────────────────────────────────────────────────┘ │
49
+ │ │
50
+ │ Scenario 3: User Preference Required │
51
+ │ ┌───────────────────────────────────────────────────────────────────────┐ │
52
+ │ │ User: "Set up testing framework" │ │
53
+ │ │ │ │
54
+ │ │ User preferences matter: │ │
55
+ │ │ ├── Jest vs Vitest vs Mocha │ │
56
+ │ │ ├── Component testing? E2E testing? │ │
57
+ │ │ └── Coverage thresholds? │ │
58
+ │ │ │ │
59
+ │ │ Current behavior: Unstructured text questions lost in output │ │
60
+ │ └───────────────────────────────────────────────────────────────────────┘ │
61
+ │ │
62
+ └─────────────────────────────────────────────────────────────────────────────┘
63
+ ```
24
64
 
25
- ## Claude Code Reference
65
+ ### Root Causes
66
+
67
+ 1. **No Structured Input Mechanism**: Agent can only receive plain text, no way to present choices
68
+ 2. **Execution Cannot Pause**: Once started, agent runs to completion without checkpoints
69
+ 3. **No UI for Multi-Select**: Cannot gather multiple preferences efficiently
70
+ 4. **Questions Mixed with Output**: Important questions get lost in long responses
71
+
72
+ ## Value Proposition
73
+
74
+ ### Quantified Benefits
75
+
76
+ ```
77
+ ┌─────────────────────────────────────────────────────────────────────────────┐
78
+ │ VALUE METRICS │
79
+ ├─────────────────────────────────────────────────────────────────────────────┤
80
+ │ │
81
+ │ ┌─────────────────────┐ ┌─────────────────────┐ │
82
+ │ │ WITHOUT TOOL │ │ WITH TOOL │ │
83
+ │ ├─────────────────────┤ ├─────────────────────┤ │
84
+ │ │ Rework Rate: ~40% │ → │ Rework Rate: ~5% │ ↓ 87% reduction │
85
+ │ │ Avg Iterations: 3-4 │ → │ Avg Iterations: 1-2 │ ↓ 50% faster │
86
+ │ │ User Satisfaction: │ → │ User Satisfaction: │ │
87
+ │ │ Medium │ │ High │ ↑ Clear expectations │
88
+ │ └─────────────────────┘ └─────────────────────┘ │
89
+ │ │
90
+ │ Key Improvements: │
91
+ │ ┌───────────────────────────────────────────────────────────────────────┐ │
92
+ │ │ 1. CLARITY │ Structured options eliminate ambiguity │ │
93
+ │ │ 2. EFFICIENCY │ Get preferences upfront, not after failure │ │
94
+ │ │ 3. USER CONTROL │ Users drive decisions, not agent assumptions │ │
95
+ │ │ 4. TRANSPARENCY │ Clear what agent is asking and why │ │
96
+ │ │ 5. MULTI-SELECT │ Gather multiple preferences in one interaction │ │
97
+ │ └───────────────────────────────────────────────────────────────────────┘ │
98
+ │ │
99
+ └─────────────────────────────────────────────────────────────────────────────┘
100
+ ```
101
+
102
+ ### Use Case Coverage
103
+
104
+ | Use Case | Without Tool | With Tool |
105
+ |----------|-------------|-----------|
106
+ | Technology choices | Guess → Fix | Ask → Correct first time |
107
+ | Configuration options | Default → Override | Present options → Match preference |
108
+ | Approach selection | Pick one → Iterate | Present trade-offs → User decides |
109
+ | Multi-feature enablement | Ask one-by-one | Multi-select in one prompt |
110
+
111
+ ## Architecture Flow
112
+
113
+ ### Execution Flow Diagram
114
+
115
+ ```
116
+ ┌─────────────────────────────────────────────────────────────────────────────┐
117
+ │ ASKUSERQUESTION EXECUTION FLOW │
118
+ └─────────────────────────────────────────────────────────────────────────────┘
119
+
120
+ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐
121
+ │ Agent │────▶│ Detects │────▶│ Calls │────▶│ Tool │
122
+ │ Running │ │ Ambiguity │ │ AskUser │ │ Execution │
123
+ └────────────┘ └────────────┘ └────────────┘ └────────────┘
124
+
125
+
126
+ ┌─────────────────────────────────────────────────────────────────────────────┐
127
+ │ TOOL EXECUTION │
128
+ │ ┌─────────────────────────────────────────────────────────────────────┐ │
129
+ │ │ 1. Validate input (1-4 questions, 2-4 options each) │ │
130
+ │ │ 2. Emit special event: { type: 'ask_user', questions: [...] } │ │
131
+ │ │ 3. Block execution - wait for user response │ │
132
+ │ │ 4. Return structured answers to agent │ │
133
+ │ └─────────────────────────────────────────────────────────────────────┘ │
134
+ └─────────────────────────────────────────────────────────────────────────────┘
135
+
136
+
137
+ ┌─────────────────────────────────────────────────────────────────────────────┐
138
+ │ CLI LAYER │
139
+ │ ┌─────────────────────────────────────────────────────────────────────┐ │
140
+ │ │ QuestionPrompt UI │ │
141
+ │ │ │ │
142
+ │ │ ┌─ Database ─────────────────────────────────┐ │ │
143
+ │ │ │ Which database should we use? │ │ │
144
+ │ │ │ │ │ │
145
+ │ │ │ > ○ PostgreSQL (Recommended) │ ← Arrow keys │ │
146
+ │ │ │ Relational DB with rich features │ to navigate │ │
147
+ │ │ │ │ │ │
148
+ │ │ │ ○ MongoDB │ │ │
149
+ │ │ │ Document-based NoSQL database │ │ │
150
+ │ │ │ │ │ │
151
+ │ │ │ ○ SQLite │ │ │
152
+ │ │ │ Lightweight embedded database │ │ │
153
+ │ │ │ │ │ │
154
+ │ │ │ ○ Other │ ← Always available │ │
155
+ │ │ │ Provide custom input │ │ │
156
+ │ │ └────────────────────────────────────────────┘ │ │
157
+ │ │ │ │
158
+ │ │ [Enter] Select [↑↓] Navigate [Space] Toggle (multi-select) │ │
159
+ │ └─────────────────────────────────────────────────────────────────────┘ │
160
+ └─────────────────────────────────────────────────────────────────────────────┘
161
+
162
+
163
+ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐
164
+ │ User │────▶│ Answer │────▶│ Tool │────▶│ Agent │
165
+ │ Selects │ │ Collected │ │ Returns │ │ Continues │
166
+ └────────────┘ └────────────┘ └────────────┘ └────────────┘
167
+ ```
168
+
169
+ ### Component Interaction
170
+
171
+ ```
172
+ ┌─────────────────────────────────────────────────────────────────────────────┐
173
+ │ COMPONENT ARCHITECTURE │
174
+ └─────────────────────────────────────────────────────────────────────────────┘
175
+
176
+ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
177
+ │ Agent Loop │ │ AskUserQuestion│ │ CLI App │
178
+ │ (agent.ts) │ │ Tool │ │ (App.tsx) │
179
+ ├──────────────────┤ ├──────────────────┤ ├──────────────────┤
180
+ │ │ │ │ │ │
181
+ │ run() { │ │ execute() { │ │ [QuestionState] │
182
+ │ for event │───────▶│ validate() │───────▶│ ↓ │
183
+ │ of stream: │ │ return { │ │ <QuestionPrompt>│
184
+ │ ... │ │ type: 'ask' │ │ ↓ │
185
+ │ } │◀───────│ promise │◀───────│ onAnswer() │
186
+ │ │ │ } │ │ │
187
+ └──────────────────┘ └──────────────────┘ └──────────────────┘
188
+ │ │ │
189
+ │ │ │
190
+ ▼ ▼ ▼
191
+ ┌──────────────────────────────────────────────────────────────────────────────┐
192
+ │ EVENT FLOW │
193
+ │ │
194
+ │ Agent Tool CLI │
195
+ │ │ │ │ │
196
+ │ │──── tool_use ─────────▶│ │ │
197
+ │ │ │──── ask_user ──────────▶│ │
198
+ │ │ │ (questions) │ │
199
+ │ │ │ │── Display UI │
200
+ │ │ │ │ │
201
+ │ │ │◀─── answers ────────────│ │
202
+ │ │◀─── tool_result ───────│ │ │
203
+ │ │ (formatted) │ │ │
204
+ │ │ │ │ │
205
+ │ ▼ ▼ ▼ │
206
+ └──────────────────────────────────────────────────────────────────────────────┘
207
+ ```
208
+
209
+ ## Usage Examples
210
+
211
+ ### Example 1: Technology Choice
212
+
213
+ ```typescript
214
+ // Agent detects need to set up database
215
+ // Instead of guessing, asks user:
26
216
 
27
- Claude Code's AskUserQuestion tool provides rich interactive questioning:
217
+ AskUserQuestion({
218
+ questions: [{
219
+ question: "Which database should we use for this project?",
220
+ header: "Database",
221
+ options: [
222
+ { label: "PostgreSQL (Recommended)", description: "Robust relational DB, great for complex queries" },
223
+ { label: "MongoDB", description: "Document DB, flexible schema for rapid development" },
224
+ { label: "SQLite", description: "Embedded DB, zero configuration, good for small apps" }
225
+ ],
226
+ multiSelect: false
227
+ }]
228
+ })
229
+
230
+ // User selects: PostgreSQL
231
+ // Agent proceeds with PostgreSQL setup
232
+ ```
233
+
234
+ **CLI Display:**
235
+ ```
236
+ ┌─ Database ─────────────────────────────────────────────────────────────────┐
237
+ │ Which database should we use for this project? │
238
+ │ │
239
+ │ > ○ PostgreSQL (Recommended) │
240
+ │ Robust relational DB, great for complex queries │
241
+ │ │
242
+ │ ○ MongoDB │
243
+ │ Document DB, flexible schema for rapid development │
244
+ │ │
245
+ │ ○ SQLite │
246
+ │ Embedded DB, zero configuration, good for small apps │
247
+ │ │
248
+ │ ○ Other │
249
+ │ Provide custom input │
250
+ └─────────────────────────────────────────────────────────────────────────────┘
251
+ ```
252
+
253
+ ### Example 2: Multi-Select Features
28
254
 
29
- ### Tool Definition
30
255
  ```typescript
256
+ // Agent setting up a new React project
257
+ // Asks about features to enable:
258
+
259
+ AskUserQuestion({
260
+ questions: [{
261
+ question: "Which features should we enable?",
262
+ header: "Features",
263
+ options: [
264
+ { label: "TypeScript", description: "Type safety and better IDE support" },
265
+ { label: "ESLint + Prettier", description: "Code linting and formatting" },
266
+ { label: "Testing (Vitest)", description: "Unit and component testing" },
267
+ { label: "Tailwind CSS", description: "Utility-first CSS framework" }
268
+ ],
269
+ multiSelect: true
270
+ }]
271
+ })
272
+
273
+ // User selects: TypeScript, ESLint + Prettier, Tailwind CSS
274
+ // Agent sets up project with selected features
275
+ ```
276
+
277
+ **CLI Display:**
278
+ ```
279
+ ┌─ Features ─────────────────────────────────────────────────────────────────┐
280
+ │ Which features should we enable? (Select multiple with Space) │
281
+ │ │
282
+ │ ☑ TypeScript │
283
+ │ Type safety and better IDE support │
284
+ │ │
285
+ │ ☑ ESLint + Prettier │
286
+ │ Code linting and formatting │
287
+ │ │
288
+ │ ☐ Testing (Vitest) │
289
+ │ Unit and component testing │
290
+ │ │
291
+ │ > ☑ Tailwind CSS │
292
+ │ Utility-first CSS framework │
293
+ └─────────────────────────────────────────────────────────────────────────────┘
294
+ ```
295
+
296
+ ### Example 3: Multiple Questions
297
+
298
+ ```typescript
299
+ // Agent implementing authentication system
300
+ // Needs multiple decisions:
301
+
31
302
  AskUserQuestion({
32
303
  questions: [
33
304
  {
34
- question: "Which database should we use?",
35
- header: "Database", // Short label (max 12 chars)
305
+ question: "Which authentication method should we use?",
306
+ header: "Auth Method",
36
307
  options: [
37
- { label: "PostgreSQL (Recommended)", description: "Relational DB with rich features" },
38
- { label: "MongoDB", description: "Document-based NoSQL database" },
39
- { label: "SQLite", description: "Lightweight embedded database" }
308
+ { label: "OAuth 2.0 (Recommended)", description: "Industry standard, supports social login" },
309
+ { label: "JWT", description: "Stateless tokens, good for APIs" },
310
+ { label: "Session-based", description: "Traditional cookie sessions" }
40
311
  ],
41
312
  multiSelect: false
313
+ },
314
+ {
315
+ question: "Which OAuth providers should we support?",
316
+ header: "Providers",
317
+ options: [
318
+ { label: "Google", description: "Most widely used" },
319
+ { label: "GitHub", description: "Popular for developer tools" },
320
+ { label: "Microsoft", description: "Enterprise integration" },
321
+ { label: "Apple", description: "Required for iOS apps" }
322
+ ],
323
+ multiSelect: true
42
324
  }
43
325
  ]
44
326
  })
327
+
328
+ // User selects: OAuth 2.0, Google + GitHub
329
+ // Agent implements OAuth with Google and GitHub providers
45
330
  ```
46
331
 
47
- ### Key Features
48
- - 1-4 questions per invocation
49
- - 2-4 options per question
50
- - Automatic "Other" option for custom input
51
- - Multi-select support
52
- - Short headers for chips/tags
53
- - Descriptions for each option
54
- - Recommended options (first position + label suffix)
332
+ ### Example 4: Custom "Other" Input
55
333
 
56
- ### Example Usage
334
+ ```typescript
335
+ AskUserQuestion({
336
+ questions: [{
337
+ question: "Which package manager do you prefer?",
338
+ header: "Package Mgr",
339
+ options: [
340
+ { label: "npm", description: "Default Node.js package manager" },
341
+ { label: "pnpm (Recommended)", description: "Fast, efficient disk space usage" },
342
+ { label: "yarn", description: "Alternative with workspaces support" }
343
+ ],
344
+ multiSelect: false
345
+ }]
346
+ })
347
+
348
+ // User selects: Other
349
+ // CLI prompts: "Please specify:"
350
+ // User types: "bun"
351
+ // Agent proceeds with bun as package manager
57
352
  ```
58
- Agent: Before implementing authentication, I need to clarify some details.
59
353
 
60
- [AskUserQuestion:
61
- Q1: "Which authentication method should we use?"
62
- - OAuth 2.0 (Recommended) - Industry standard, supports social login
63
- - JWT - Stateless tokens, good for APIs
64
- - Session-based - Traditional cookie sessions
354
+ ## Claude Code Reference
65
355
 
66
- Q2: "Which user storage should we use?"
67
- - PostgreSQL (Recommended) - Your existing database
68
- - Firebase Auth - Managed auth service
69
- ]
356
+ Claude Code's AskUserQuestion tool provides rich interactive questioning with these specifications:
70
357
 
71
- User selects: OAuth 2.0, PostgreSQL
358
+ ### Parameter Schema (from Claude Code)
72
359
 
73
- Agent: Great! I'll implement OAuth 2.0 authentication with PostgreSQL storage.
360
+ ```typescript
361
+ interface AskUserQuestionTool {
362
+ questions: Question[]; // Required: 1-4 questions
363
+ answers?: Record<string, string>; // User responses collected
364
+ metadata?: { // Optional analytics
365
+ source?: string; // e.g., "remember" for /remember command
366
+ };
367
+ }
368
+
369
+ interface Question {
370
+ question: string; // Complete question text (required)
371
+ header: string; // Very short label, max 12 chars (required)
372
+ multiSelect: boolean; // Allow multiple selections (required)
373
+ options: Option[]; // 2-4 choices (required)
374
+ }
375
+
376
+ interface Option {
377
+ label: string; // Display text, 1-5 words (required)
378
+ description: string; // Choice explanation (required)
379
+ }
74
380
  ```
75
381
 
382
+ ### Constraints
383
+
384
+ - Header text: maximum 12 characters
385
+ - Option label: 1-5 words maximum
386
+ - Options per question: minimum 2, maximum 4
387
+ - Questions per call: minimum 1, maximum 4
388
+ - `multiSelect` must be explicitly specified (not optional)
389
+ - "Other" option is auto-added, don't include manually
390
+ - Recommended option should be first with "(Recommended)" suffix
391
+
392
+ ### Usage Guidelines
393
+
394
+ From Claude Code's system prompt:
395
+ - Use when gathering preferences or clarifying ambiguous instructions
396
+ - Use `multiSelect: true` for non-mutually-exclusive options
397
+ - Put recommended option first with "(Recommended)" suffix
398
+ - In Plan Mode: use to clarify requirements BEFORE finalizing plan
399
+ - NOT for asking "Is my plan ready?" (use ExitPlanMode instead)
400
+
76
401
  ## Detailed Design
77
402
 
78
403
  ### API Design
79
404
 
80
405
  ```typescript
81
- // src/tools/ask-user/types.ts
82
- interface QuestionOption {
83
- label: string; // Display text (1-5 words)
84
- description: string; // Explanation of the option
85
- }
406
+ // src/tools/builtin/ask-user.ts
86
407
 
87
- interface Question {
88
- question: string; // The question to ask
89
- header: string; // Short label (max 12 chars)
90
- options: QuestionOption[]; // 2-4 options
91
- multiSelect: boolean; // Allow multiple selections
92
- }
408
+ import { z } from 'zod';
409
+ import type { Tool, ToolResult, ToolContext } from '../types.js';
93
410
 
94
- interface AskUserQuestionInput {
95
- questions: Question[]; // 1-4 questions
96
- }
411
+ // Zod Schemas
412
+ export const QuestionOptionSchema = z.object({
413
+ label: z.string().min(1).max(50).describe('Display text (1-5 words)'),
414
+ description: z.string().min(1).max(200).describe('Explanation of the option'),
415
+ });
416
+
417
+ export const QuestionSchema = z.object({
418
+ question: z.string().min(1).describe('The complete question to ask'),
419
+ header: z.string().min(1).max(12).describe('Short label (max 12 chars)'),
420
+ options: z.array(QuestionOptionSchema).min(2).max(4).describe('2-4 options'),
421
+ multiSelect: z.boolean().describe('Allow multiple selections'),
422
+ });
423
+
424
+ export const AskUserQuestionInputSchema = z.object({
425
+ questions: z.array(QuestionSchema).min(1).max(4).describe('1-4 questions'),
426
+ });
427
+
428
+ export type QuestionOption = z.infer<typeof QuestionOptionSchema>;
429
+ export type Question = z.infer<typeof QuestionSchema>;
430
+ export type AskUserQuestionInput = z.infer<typeof AskUserQuestionInputSchema>;
97
431
 
98
- interface QuestionAnswer {
432
+ // Answer types
433
+ export interface QuestionAnswer {
99
434
  question: string;
100
- selectedOptions: string[]; // Labels of selected options
101
- customInput?: string; // If "Other" was selected
435
+ header: string;
436
+ selectedOptions: string[]; // Labels of selected options
437
+ customInput?: string; // If "Other" was selected
102
438
  }
103
439
 
104
- interface AskUserQuestionOutput {
440
+ export interface AskUserQuestionResult {
105
441
  answers: QuestionAnswer[];
106
442
  }
107
443
  ```
108
444
 
445
+ ### Tool Implementation
446
+
109
447
  ```typescript
110
- // src/tools/ask-user/ask-user-tool.ts
111
- const askUserQuestionTool: Tool<AskUserQuestionInput> = {
448
+ // src/tools/builtin/ask-user.ts
449
+
450
+ export const askUserQuestionTool: Tool<AskUserQuestionInput> = {
112
451
  name: 'AskUserQuestion',
113
- description: `Ask the user structured questions during execution.
452
+ description: loadToolDescription('ask-user'),
453
+ parameters: AskUserQuestionInputSchema,
114
454
 
115
- Use this tool when you need to:
116
- 1. Gather user preferences or requirements
117
- 2. Clarify ambiguous instructions
118
- 3. Get decisions on implementation choices
119
- 4. Offer choices about direction
455
+ async execute(input, context): Promise<ToolResult> {
456
+ // Validation is handled by Zod schema
120
457
 
121
- Guidelines:
122
- - Use multiSelect: true for non-mutually-exclusive options
123
- - Put recommended option first with "(Recommended)" suffix
124
- - Keep headers short (max 12 chars)
125
- - Users can always select "Other" for custom input
126
- `,
127
- parameters: z.object({
128
- questions: z.array(z.object({
129
- question: z.string(),
130
- header: z.string().max(12),
131
- options: z.array(z.object({
132
- label: z.string(),
133
- description: z.string()
134
- })).min(2).max(4),
135
- multiSelect: z.boolean()
136
- })).min(1).max(4)
137
- }),
138
- execute: async (input, context) => { ... }
458
+ // The actual questioning is handled by the CLI layer
459
+ // Tool returns a special result that signals the agent loop
460
+ // to pause and wait for user input
461
+
462
+ // This is a placeholder - actual implementation requires
463
+ // integration with the agent loop and CLI
464
+ return {
465
+ success: true,
466
+ output: JSON.stringify({
467
+ type: 'ask_user_question',
468
+ questions: input.questions,
469
+ }),
470
+ metadata: {
471
+ title: 'AskUserQuestion',
472
+ subtitle: `${input.questions.length} question(s)`,
473
+ },
474
+ };
475
+ },
139
476
  };
140
477
  ```
141
478
 
142
- ### Implementation Approach
479
+ ### Extended ToolContext
480
+
481
+ ```typescript
482
+ // src/tools/types.ts - Extended
483
+
484
+ export interface ToolContext {
485
+ cwd: string;
486
+ abortSignal?: AbortSignal;
487
+
488
+ // New: User interaction callbacks
489
+ askUser?: (questions: Question[]) => Promise<QuestionAnswer[]>;
490
+ }
491
+ ```
143
492
 
144
- 1. **Tool Registration**: Add AskUserQuestion to tool registry
145
- 2. **UI Integration**: Create interactive question display
146
- 3. **Blocking Execution**: Tool blocks until user responds
147
- 4. **Answer Processing**: Return structured answers to agent
148
- 5. **Other Handling**: Support custom text input
493
+ ### Agent Loop Integration
149
494
 
150
495
  ```typescript
151
- // Question display and collection
152
- async function execute(input: AskUserQuestionInput, context: ToolContext): Promise<ToolResult> {
153
- const { promptUser } = context;
154
-
155
- const answers: QuestionAnswer[] = [];
156
-
157
- for (const question of input.questions) {
158
- // Display question with options
159
- const response = await promptUser({
160
- type: question.multiSelect ? 'multiselect' : 'select',
161
- message: question.question,
162
- choices: [
163
- ...question.options.map(opt => ({
164
- name: opt.label,
165
- message: opt.label,
166
- hint: opt.description
167
- })),
168
- { name: 'Other', message: 'Other (custom input)' }
169
- ]
170
- });
496
+ // src/agent/agent.ts - Modified tool execution
497
+
498
+ // In the tool execution section:
499
+ if (call.name === 'AskUserQuestion') {
500
+ // Special handling for AskUserQuestion
501
+ const input = call.input as AskUserQuestionInput;
502
+
503
+ // Emit special event for CLI to handle
504
+ yield {
505
+ type: 'ask_user',
506
+ id: call.id,
507
+ questions: input.questions
508
+ };
509
+
510
+ // Wait for response (this will be set by the CLI)
511
+ const answers = await this.waitForUserAnswers(call.id);
512
+
513
+ // Continue with answers as tool result
514
+ toolResults.push({
515
+ type: 'tool_result',
516
+ toolUseId: call.id,
517
+ content: formatAnswers(answers),
518
+ isError: false,
519
+ });
520
+ }
521
+ ```
522
+
523
+ ### New Agent Event Type
524
+
525
+ ```typescript
526
+ // src/agent/types.ts
527
+
528
+ export type AgentEvent =
529
+ | { type: 'text'; text: string }
530
+ | { type: 'tool_start'; id: string; name: string; input: unknown }
531
+ | { type: 'tool_result'; id: string; name: string; result: ToolResult }
532
+ | { type: 'ask_user'; id: string; questions: Question[] } // NEW
533
+ | { type: 'done'; text: string }
534
+ | { type: 'error'; error: Error };
535
+ ```
536
+
537
+ ### CLI Component
171
538
 
172
- let customInput: string | undefined;
173
- if (response.includes('Other')) {
174
- customInput = await promptUser({
175
- type: 'input',
176
- message: 'Please specify:'
177
- });
539
+ ```tsx
540
+ // src/cli/components/QuestionPrompt.tsx
541
+
542
+ import { useState } from 'react';
543
+ import { Box, Text, useInput } from 'ink';
544
+ import { colors } from './theme.js';
545
+ import type { Question, QuestionAnswer } from '../../tools/builtin/ask-user.js';
546
+
547
+ interface QuestionPromptProps {
548
+ questions: Question[];
549
+ onComplete: (answers: QuestionAnswer[]) => void;
550
+ }
551
+
552
+ export function QuestionPrompt({ questions, onComplete }: QuestionPromptProps) {
553
+ const [currentIndex, setCurrentIndex] = useState(0);
554
+ const [answers, setAnswers] = useState<QuestionAnswer[]>([]);
555
+ const [selectedOptions, setSelectedOptions] = useState<Set<string>>(new Set());
556
+ const [optionIndex, setOptionIndex] = useState(0);
557
+ const [showOtherInput, setShowOtherInput] = useState(false);
558
+ const [otherInput, setOtherInput] = useState('');
559
+
560
+ const currentQuestion = questions[currentIndex];
561
+ const optionsWithOther = [...currentQuestion.options, {
562
+ label: 'Other',
563
+ description: 'Provide custom input'
564
+ }];
565
+
566
+ useInput((input, key) => {
567
+ if (showOtherInput) {
568
+ // Handle text input for "Other"
569
+ if (key.return) {
570
+ finishQuestion([...selectedOptions, 'Other'], otherInput);
571
+ } else if (key.backspace) {
572
+ setOtherInput(prev => prev.slice(0, -1));
573
+ } else if (input && !key.ctrl) {
574
+ setOtherInput(prev => prev + input);
575
+ }
576
+ return;
178
577
  }
179
578
 
180
- answers.push({
181
- question: question.question,
182
- selectedOptions: response,
183
- customInput
579
+ if (key.upArrow) {
580
+ setOptionIndex(i => Math.max(0, i - 1));
581
+ } else if (key.downArrow) {
582
+ setOptionIndex(i => Math.min(optionsWithOther.length - 1, i + 1));
583
+ } else if (key.return) {
584
+ handleSelect();
585
+ } else if (input === ' ' && currentQuestion.multiSelect) {
586
+ toggleOption();
587
+ }
588
+ });
589
+
590
+ const toggleOption = () => {
591
+ const option = optionsWithOther[optionIndex];
592
+ setSelectedOptions(prev => {
593
+ const next = new Set(prev);
594
+ if (next.has(option.label)) {
595
+ next.delete(option.label);
596
+ } else {
597
+ next.add(option.label);
598
+ }
599
+ return next;
184
600
  });
185
- }
601
+ };
602
+
603
+ const handleSelect = () => {
604
+ const option = optionsWithOther[optionIndex];
186
605
 
187
- return {
188
- success: true,
189
- output: JSON.stringify({ answers })
606
+ if (currentQuestion.multiSelect) {
607
+ // Multi-select: Enter confirms all selections
608
+ if (selectedOptions.size === 0) {
609
+ toggleOption(); // Select current if none selected
610
+ }
611
+ if (selectedOptions.has('Other')) {
612
+ setShowOtherInput(true);
613
+ } else {
614
+ finishQuestion([...selectedOptions]);
615
+ }
616
+ } else {
617
+ // Single select
618
+ if (option.label === 'Other') {
619
+ setShowOtherInput(true);
620
+ } else {
621
+ finishQuestion([option.label]);
622
+ }
623
+ }
190
624
  };
625
+
626
+ const finishQuestion = (selected: string[], customInput?: string) => {
627
+ const answer: QuestionAnswer = {
628
+ question: currentQuestion.question,
629
+ header: currentQuestion.header,
630
+ selectedOptions: selected.filter(s => s !== 'Other'),
631
+ customInput,
632
+ };
633
+
634
+ const newAnswers = [...answers, answer];
635
+
636
+ if (currentIndex < questions.length - 1) {
637
+ setAnswers(newAnswers);
638
+ setCurrentIndex(i => i + 1);
639
+ setSelectedOptions(new Set());
640
+ setOptionIndex(0);
641
+ setShowOtherInput(false);
642
+ setOtherInput('');
643
+ } else {
644
+ onComplete(newAnswers);
645
+ }
646
+ };
647
+
648
+ return (
649
+ <Box flexDirection="column" marginTop={1}>
650
+ {/* Header */}
651
+ <Box>
652
+ <Text color={colors.primary}>─ {currentQuestion.header} </Text>
653
+ <Text color={colors.textMuted}>{'─'.repeat(50)}</Text>
654
+ </Box>
655
+
656
+ {/* Question */}
657
+ <Box marginTop={1}>
658
+ <Text>{currentQuestion.question}</Text>
659
+ {currentQuestion.multiSelect && (
660
+ <Text color={colors.textMuted}> (Select multiple with Space)</Text>
661
+ )}
662
+ </Box>
663
+
664
+ {/* Options */}
665
+ <Box flexDirection="column" marginTop={1} paddingLeft={2}>
666
+ {optionsWithOther.map((option, index) => {
667
+ const isSelected = index === optionIndex;
668
+ const isChecked = selectedOptions.has(option.label);
669
+ const checkbox = currentQuestion.multiSelect
670
+ ? (isChecked ? '☑' : '☐')
671
+ : (isSelected ? '>' : ' ');
672
+
673
+ return (
674
+ <Box key={option.label} flexDirection="column">
675
+ <Box>
676
+ <Text color={isSelected ? colors.primary : colors.textMuted}>
677
+ {checkbox}
678
+ </Text>
679
+ <Text color={isSelected ? colors.text : colors.textSecondary}>
680
+ {currentQuestion.multiSelect ? '' : (isSelected ? '○' : '○')} {option.label}
681
+ </Text>
682
+ </Box>
683
+ <Box paddingLeft={4}>
684
+ <Text color={colors.textMuted}>{option.description}</Text>
685
+ </Box>
686
+ </Box>
687
+ );
688
+ })}
689
+ </Box>
690
+
691
+ {/* Other input */}
692
+ {showOtherInput && (
693
+ <Box marginTop={1} paddingLeft={2}>
694
+ <Text color={colors.primary}>Please specify: </Text>
695
+ <Text>{otherInput}</Text>
696
+ <Text color={colors.textMuted}>_</Text>
697
+ </Box>
698
+ )}
699
+
700
+ {/* Progress indicator */}
701
+ {questions.length > 1 && (
702
+ <Box marginTop={1}>
703
+ <Text color={colors.textMuted}>
704
+ Question {currentIndex + 1} of {questions.length}
705
+ </Text>
706
+ </Box>
707
+ )}
708
+
709
+ {/* Help */}
710
+ <Box marginTop={1}>
711
+ <Text color={colors.textMuted}>
712
+ [Enter] Select [↑↓] Navigate
713
+ {currentQuestion.multiSelect && ' [Space] Toggle'}
714
+ </Text>
715
+ </Box>
716
+ </Box>
717
+ );
191
718
  }
192
719
  ```
193
720
 
@@ -195,123 +722,396 @@ async function execute(input: AskUserQuestionInput, context: ToolContext): Promi
195
722
 
196
723
  | File | Action | Description |
197
724
  |------|--------|-------------|
198
- | `src/tools/ask-user/types.ts` | Create | Question/answer type definitions |
199
- | `src/tools/ask-user/ask-user-tool.ts` | Create | AskUserQuestion tool implementation |
200
- | `src/tools/ask-user/index.ts` | Create | Module exports |
201
- | `src/tools/index.ts` | Modify | Register tool |
725
+ | `src/tools/builtin/ask-user.ts` | Create | AskUserQuestion tool implementation |
726
+ | `src/tools/types.ts` | Modify | Add AskUserQuestionInput schema |
727
+ | `src/tools/index.ts` | Modify | Register and export tool |
728
+ | `src/agent/types.ts` | Modify | Add `ask_user` event type |
729
+ | `src/agent/agent.ts` | Modify | Handle AskUserQuestion in tool loop |
202
730
  | `src/cli/components/QuestionPrompt.tsx` | Create | Question UI component |
731
+ | `src/cli/components/App.tsx` | Modify | Integrate QuestionPrompt |
732
+ | `src/prompts/tools/ask-user.txt` | Create | Tool description for LLM |
203
733
 
204
734
  ## User Experience
205
735
 
206
- ### Single Select Display
207
- ```
208
- ┌─ Database ─────────────────────────────────┐
209
- │ Which database should we use? │
210
- │ │
211
- │ ○ PostgreSQL (Recommended) │
212
- │ Relational DB with rich features │
213
- │ │
214
- MongoDB
215
- │ Document-based NoSQL database │
216
- │ │
217
- SQLite │
218
- Lightweight embedded database │
219
-
220
- Other
221
- Provide custom input
222
- └────────────────────────────────────────────┘
223
- ```
224
-
225
- ### Multi Select Display
226
- ```
227
- ┌─ Features ─────────────────────────────────┐
228
- Which features should we enable?
229
- (Select multiple with space)
230
-
231
- ☑ Dark mode
232
- Enable dark theme support
233
-
234
- ☐ Notifications
235
- Push notification support
236
-
237
- ☑ Offline mode
238
- Work without internet connection
239
- └────────────────────────────────────────────┘
736
+ ### Claude Code UI Alignment
737
+
738
+ Our implementation follows Claude Code's exact visual patterns for consistency and familiarity.
739
+
740
+ #### Visual Design Reference (Claude Code Style)
741
+
742
+ ```
743
+ ┌─────────────────────────────────────────────────────────────────────────────┐
744
+ CLAUDE CODE UI PATTERNS
745
+ └─────────────────────────────────────────────────────────────────────────────┘
746
+
747
+ 1. HEADER AS CHIP/TAG (max 12 chars)
748
+ ┌──────────────────────────────────────────────────────────────────────┐
749
+ ╭─────────────╮
750
+ │ Database │ ← Header displayed as colored chip/tag
751
+ ╰─────────────╯ │
752
+ └──────────────────────────────────────────────────────────────────────┘
753
+
754
+ 2. SINGLE-SELECT (Radio Buttons: ○ / ●)
755
+ ┌──────────────────────────────────────────────────────────────────────┐
756
+ │ │
757
+ │ Which database should we use? │
758
+
759
+ > PostgreSQL (Recommended)
760
+ Robust relational DB, great for complex queries
761
+
762
+ MongoDB
763
+ Document DB, flexible schema
764
+
765
+ SQLite
766
+ Lightweight embedded database
767
+
768
+ Other
769
+ │ Type something else... │
770
+ │ │
771
+ └──────────────────────────────────────────────────────────────────────┘
772
+
773
+ 3. MULTI-SELECT (Checkboxes: ☐ / ☑)
774
+ ┌──────────────────────────────────────────────────────────────────────┐
775
+ │ │
776
+ │ Which features should we enable? │
777
+ │ │
778
+ │ ☑ TypeScript │
779
+ │ Type safety and better IDE support │
780
+ │ │
781
+ │ > ☑ ESLint + Prettier │
782
+ │ Code linting and formatting │
783
+ │ │
784
+ │ ☐ Testing (Vitest) │
785
+ │ Unit and component testing │
786
+ │ │
787
+ │ ☑ Tailwind CSS │
788
+ │ Utility-first CSS framework │
789
+ │ │
790
+ └──────────────────────────────────────────────────────────────────────┘
791
+
792
+ 4. "OTHER" CUSTOM INPUT
793
+ ┌──────────────────────────────────────────────────────────────────────┐
794
+ │ │
795
+ │ Please specify: bun█ │
796
+ │ │
797
+ └──────────────────────────────────────────────────────────────────────┘
798
+
799
+ 5. KEYBOARD HINTS (footer)
800
+ ┌──────────────────────────────────────────────────────────────────────┐
801
+ │ ↑↓ navigate • enter select • space toggle • esc cancel │
802
+ └──────────────────────────────────────────────────────────────────────┘
803
+ ```
804
+
805
+ ### Color Scheme (theme.ts aligned)
806
+
807
+ | Element | Color | Hex Value | Usage |
808
+ |---------|-------|-----------|-------|
809
+ | Header chip | `primary` | `#818CF8` | Question header tag |
810
+ | Selected option | `text` | `#F1F5F9` | Currently focused option |
811
+ | Unselected option | `textSecondary` | `#94A3B8` | Other options |
812
+ | Description | `textMuted` | `#64748B` | Option descriptions |
813
+ | Radio/Checkbox | `primary` | `#818CF8` | Selection indicators |
814
+ | Recommended | `success` | `#34D399` | "(Recommended)" suffix |
815
+ | Custom input cursor | `primary` | `#818CF8` | Text input cursor |
816
+
817
+ ### Terminal Rendering
818
+
819
+ ```tsx
820
+ // Exact rendering matching Claude Code patterns
821
+
822
+ // Header as chip
823
+ <Box>
824
+ <Text color={colors.primary} bold>{'╭─'}</Text>
825
+ <Text color={colors.primary} bold backgroundColor="#1E293B">
826
+ {` ${header} `}
827
+ </Text>
828
+ <Text color={colors.primary} bold>{'─╮'}</Text>
829
+ </Box>
830
+
831
+ // Single-select option
832
+ <Box>
833
+ <Text color={isSelected ? colors.text : colors.textMuted}>
834
+ {isSelected ? '>' : ' '}
835
+ </Text>
836
+ <Text> </Text>
837
+ <Text color={colors.primary}>
838
+ {isChosen ? '●' : '○'}
839
+ </Text>
840
+ <Text color={isSelected ? colors.text : colors.textSecondary}>
841
+ {' '}{label}
842
+ </Text>
843
+ {isRecommended && (
844
+ <Text color={colors.success}> (Recommended)</Text>
845
+ )}
846
+ </Box>
847
+
848
+ // Multi-select option
849
+ <Box>
850
+ <Text color={isSelected ? colors.text : colors.textMuted}>
851
+ {isSelected ? '>' : ' '}
852
+ </Text>
853
+ <Text> </Text>
854
+ <Text color={colors.primary}>
855
+ {isChecked ? '☑' : '☐'}
856
+ </Text>
857
+ <Text color={isSelected ? colors.text : colors.textSecondary}>
858
+ {' '}{label}
859
+ </Text>
860
+ </Box>
861
+
862
+ // Description (indented)
863
+ <Box paddingLeft={4}>
864
+ <Text color={colors.textMuted}>{description}</Text>
865
+ </Box>
240
866
  ```
241
867
 
242
868
  ### Keyboard Navigation
243
- - `↑/↓` - Navigate options
244
- - `Space` - Toggle selection (multi-select)
245
- - `Enter` - Confirm selection
246
- - `Esc` - Cancel (if allowed)
247
869
 
248
- ### Answer Display
249
- After user answers:
870
+ | Key | Action | Context |
871
+ |-----|--------|---------|
872
+ | `↑` / `↓` | Navigate options | Always |
873
+ | `Enter` | Select current option | Single-select |
874
+ | `Enter` | Confirm all selections | Multi-select |
875
+ | `Space` | Toggle option on/off | Multi-select only |
876
+ | `Esc` | Cancel and dismiss | Optional |
877
+ | `1-4` | Quick select by number | Single-select |
878
+
879
+ ### Answer Confirmation Display
880
+
881
+ After user answers, show Claude Code style confirmation:
882
+
883
+ ```
884
+ ╭─ Database ─╮
885
+ │ ✔ PostgreSQL
886
+ ╰────────────╯
887
+
888
+ ╭─ Features ─╮
889
+ │ ✔ TypeScript
890
+ │ ✔ ESLint + Prettier
891
+ │ ✔ Tailwind CSS
892
+ ╰────────────╯
893
+ ```
894
+
895
+ Or simplified inline format:
896
+
250
897
  ```
251
- Database: PostgreSQL
252
- Features: Dark mode, Offline mode
898
+ Database: PostgreSQL
899
+ Features: TypeScript, ESLint + Prettier, Tailwind CSS
900
+ ```
901
+
902
+ ### Tool Result Format
903
+
904
+ The tool returns a structured format that the agent can parse:
253
905
 
254
- Continuing with implementation...
255
906
  ```
907
+ User answered the following questions:
256
908
 
257
- ## Alternatives Considered
909
+ 1. Database (Which database should we use for this project?)
910
+ Selected: PostgreSQL
258
911
 
259
- ### Alternative 1: Plain Text Questions
260
- Agent asks questions in regular output.
912
+ 2. Features (Which features should we enable?)
913
+ Selected: TypeScript, ESLint + Prettier, Tailwind CSS
261
914
 
262
- **Pros**: Simpler, no special UI
263
- **Cons**: No structure, easy to miss, no validation
264
- **Decision**: Rejected - Structured questions are clearer
915
+ Proceeding with user selections.
916
+ ```
265
917
 
266
- ### Alternative 2: Form-Based Input
267
- Complex form with multiple field types.
918
+ ### Progress Indicator (Multi-Question)
268
919
 
269
- **Pros**: More input flexibility
270
- **Cons**: Overcomplicated for most use cases
271
- **Decision**: Rejected - Options are sufficient for most needs
920
+ ```
921
+ ╭─ Auth Method ─╮ Question 1 of 2
922
+
923
+ │ Which authentication method should we use?
924
+
925
+ │ > ● OAuth 2.0 (Recommended)
926
+ │ Industry standard, supports social login
927
+
928
+ │ ○ JWT
929
+ │ Stateless tokens, good for APIs
930
+
931
+ │ ○ Session-based
932
+ │ Traditional cookie sessions
933
+
934
+ ╰────────────────────────────────────────────────────────────────────╯
935
+ ```
272
936
 
273
- ### Alternative 3: Always Allow Custom Input
274
- Every option is editable text.
937
+ ### Animation & Feedback
275
938
 
276
- **Pros**: Maximum flexibility
277
- **Cons**: Slower, more error-prone
278
- **Decision**: Rejected - "Other" option provides this when needed
939
+ | State | Visual Feedback |
940
+ |-------|-----------------|
941
+ | Navigating | Cursor (`>`) moves instantly |
942
+ | Selecting | Radio/checkbox toggles with color change |
943
+ | Confirming | Brief flash of `success` color |
944
+ | Error | Red border flash if validation fails |
945
+ | Timeout | Dim with warning message (if enabled) |
279
946
 
280
947
  ## Security Considerations
281
948
 
282
- 1. **Input Sanitization**: Validate user custom input
283
- 2. **Option Limits**: Enforce max questions and options
284
- 3. **Timeout**: Consider timeout for unresponsive users
285
- 4. **No Code Execution**: Custom input is text only
949
+ 1. **Input Sanitization**: Validate user custom input (max length, no control characters)
950
+ 2. **Option Limits**: Enforce max questions (4) and options (4) per call
951
+ 3. **Timeout**: Consider timeout for unresponsive users (configurable, default: none)
952
+ 4. **No Code Execution**: Custom input is text only, never evaluated
286
953
 
287
954
  ## Testing Strategy
288
955
 
289
- 1. **Unit Tests**:
290
- - Input validation
291
- - Option parsing
292
- - Answer formatting
956
+ ### Unit Tests
293
957
 
294
- 2. **Integration Tests**:
295
- - Tool registration
296
- - Agent flow with questions
297
- - Answer processing
958
+ ```typescript
959
+ // tests/tools/ask-user.test.ts
298
960
 
299
- 3. **Manual Testing**:
300
- - UI rendering
301
- - Keyboard navigation
302
- - Multi-select behavior
303
- - Custom input flow
961
+ describe('AskUserQuestion', () => {
962
+ test('validates question count (1-4)', () => {
963
+ // Test with 0, 1, 4, 5 questions
964
+ });
965
+
966
+ test('validates option count (2-4)', () => {
967
+ // Test with 1, 2, 4, 5 options
968
+ });
969
+
970
+ test('validates header length (max 12)', () => {
971
+ // Test with headers of various lengths
972
+ });
973
+
974
+ test('requires multiSelect to be explicit', () => {
975
+ // Ensure multiSelect is required
976
+ });
977
+ });
978
+ ```
979
+
980
+ ### Integration Tests
981
+
982
+ ```typescript
983
+ describe('AskUserQuestion Integration', () => {
984
+ test('pauses agent execution until answered', async () => {
985
+ // Verify agent waits for response
986
+ });
987
+
988
+ test('passes answers correctly to agent', async () => {
989
+ // Verify answer format and content
990
+ });
991
+
992
+ test('handles Other option with custom input', async () => {
993
+ // Test custom input flow
994
+ });
995
+ });
996
+ ```
997
+
998
+ ### Manual Testing Checklist
999
+
1000
+ - [ ] Single question, single select
1001
+ - [ ] Single question, multi-select
1002
+ - [ ] Multiple questions flow
1003
+ - [ ] "Other" option with custom input
1004
+ - [ ] Keyboard navigation (↑↓ Enter Space)
1005
+ - [ ] Cancel/Escape handling
1006
+ - [ ] Long option labels and descriptions
1007
+ - [ ] Answer display after completion
304
1008
 
305
1009
  ## Migration Path
306
1010
 
307
1011
  1. **Phase 1**: Core tool and basic select UI
308
1012
  2. **Phase 2**: Multi-select support
309
- 3. **Phase 3**: Enhanced UI with descriptions
1013
+ 3. **Phase 3**: Enhanced UI with descriptions and progress
310
1014
  4. **Phase 4**: Keyboard shortcuts and accessibility
311
1015
 
312
1016
  No breaking changes to existing functionality.
313
1017
 
1018
+ ## Implementation Notes
1019
+
1020
+ ### Files Created/Modified
1021
+
1022
+ | File | Action | Description |
1023
+ |------|--------|-------------|
1024
+ | `src/tools/builtin/ask-user.ts` | Created | Tool implementation with Zod schemas |
1025
+ | `src/tools/types.ts` | Modified | Added Question/QuestionAnswer interfaces to ToolContext |
1026
+ | `src/tools/index.ts` | Modified | Registered and exported askUserQuestionTool |
1027
+ | `src/agent/types.ts` | Modified | Added AgentEventAskUser type |
1028
+ | `src/agent/agent.ts` | Modified | Added askUserCallback and toolContext integration |
1029
+ | `src/agent/index.ts` | Modified | Exported AskUserCallback type |
1030
+ | `src/cli/components/QuestionPrompt.tsx` | Created | Question UI component with Claude Code style |
1031
+ | `src/cli/components/App.tsx` | Modified | Integrated QuestionPrompt and state management |
1032
+ | `src/cli/components/theme.ts` | Modified | Added new icons for checkboxes and chips |
1033
+ | `src/cli/components/index.ts` | Modified | Exported QuestionPrompt and AnswerDisplay |
1034
+ | `src/prompts/tools/ask-user.txt` | Created | Tool description for LLM |
1035
+
1036
+ ### Key Implementation Details
1037
+
1038
+ 1. **Callback-based architecture**: The tool uses a callback (`askUser`) injected via `ToolContext` to communicate with the CLI layer
1039
+ 2. **Promise-based async flow**: Questions block agent execution until user responds
1040
+ 3. **Claude Code UI alignment**: Uses radio buttons (○/●), checkboxes (☐/☑), chip headers, and matching color scheme
1041
+ 4. **Auto-added "Other" option**: Every question automatically includes an "Other" option for custom input
1042
+ 5. **Multi-select support**: Full support for both single-select and multi-select modes
1043
+
1044
+ ### Prompt Guidance (Critical for LLM Tool Usage)
1045
+
1046
+ The system prompt in `src/prompts/system/base.txt` includes explicit guidance with bad examples to ensure the LLM uses the tool instead of plain text:
1047
+
1048
+ ```
1049
+ CRITICAL: You MUST use the AskUserQuestion tool for ALL questions with choices.
1050
+ NEVER write numbered lists, bullet points, or "which do you prefer" questions as plain text.
1051
+
1052
+ ## Wrong - Plain Text Questions (DO NOT DO THIS)
1053
+
1054
+ <bad-example>
1055
+ user: Set up a new database
1056
+ assistant: I can set up a database for you. Which one would you prefer?
1057
+ 1. PostgreSQL - relational database
1058
+ 2. MongoDB - document database
1059
+ 3. SQLite - embedded database
1060
+ </bad-example>
1061
+
1062
+ ## Correct - Use AskUserQuestion Tool
1063
+
1064
+ <example>
1065
+ user: Set up a new database
1066
+ assistant: [uses AskUserQuestion tool with structured options]
1067
+ </example>
1068
+ ```
1069
+
1070
+ The tool description in `src/prompts/tools/ask-user.txt` reinforces this with explicit "WRONG" examples:
1071
+
1072
+ ```
1073
+ CRITICAL: You MUST use this tool for ANY question with 2+ choices.
1074
+ NEVER present options as plain text, numbered lists, or bullet points.
1075
+
1076
+ WRONG (never do this):
1077
+ - "Which do you prefer? 1. Option A 2. Option B"
1078
+ - "What type? - Web - CLI - API"
1079
+ - Writing any numbered or bulleted choices in your response
1080
+ ```
1081
+
1082
+ ## Theme Extensions
1083
+
1084
+ Add the following icons to `src/cli/components/theme.ts`:
1085
+
1086
+ ```typescript
1087
+ export const icons = {
1088
+ // ... existing icons ...
1089
+
1090
+ // AskUserQuestion specific
1091
+ checkbox: '☑', // Checked checkbox
1092
+ checkboxEmpty: '☐', // Empty checkbox
1093
+ chipLeft: '╭─', // Chip border left
1094
+ chipRight: '─╮', // Chip border right
1095
+ boxTop: '╭', // Box top corner
1096
+ boxBottom: '╰', // Box bottom corner
1097
+ boxVertical: '│', // Box vertical line
1098
+ };
1099
+ ```
1100
+
314
1101
  ## References
315
1102
 
316
- - [Claude Code AskUserQuestion Tool](https://code.claude.com/docs/en/tools)
317
- - [Inquirer.js](https://github.com/SBoudrias/Inquirer.js) (inspiration for UI)
1103
+ ### Primary Sources
1104
+ - [Claude Code AskUserQuestion Tool Guide](https://www.atcyrus.com/stories/claude-code-ask-user-question-tool-guide) - Comprehensive usage guide
1105
+ - [Claude Code System Prompts - AskUserQuestion](https://github.com/Piebald-AI/claude-code-system-prompts/blob/main/system-prompts/tool-description-askuserquestion.md) - Official tool description
1106
+ - [Internal Claude Code Tools Implementation](https://gist.github.com/bgauryy/0cdb9aa337d01ae5bd0c803943aa36bd) - Parameter schema reference
1107
+ - [Claude Docs - Handle User Input](https://platform.claude.com/docs/en/agent-sdk/user-input) - Agent SDK integration
1108
+
1109
+ ### UI/UX Research
1110
+ - [GitHub Issue #12609 - Interactive UI for AskUserQuestion](https://github.com/anthropics/claude-code/issues/12609) - VS Code extension UI proposal
1111
+ - [How Claude Code is Built - Pragmatic Engineer](https://newsletter.pragmaticengineer.com/p/how-claude-code-is-built) - Architecture insights
1112
+ - [SmartScope - AskUserQuestion Guide](https://smartscope.blog/en/generative-ai/claude/claude-code-askuserquestion-tool-guide/) - Usage patterns
1113
+
1114
+ ### Framework References
1115
+ - [Ink - React for CLIs](https://github.com/vadimdemedes/ink) - Terminal UI framework
1116
+ - [Inquirer.js](https://github.com/SBoudrias/Inquirer.js) - CLI prompt patterns
1117
+ - [ccexp](https://github.com/nyatinte/ccexp) - Claude Code config explorer (UI reference)