gencode-ai 0.1.1 → 0.1.2

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