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
@@ -16,19 +16,20 @@ This directory contains enhancement proposals for the gencode project. Each prop
16
16
 
17
17
  | ID | Title | Status |
18
18
  |----|-------|--------|
19
- | [0001](./0001-web-fetch-tool.md) | WebFetch Tool | Draft |
20
- | [0002](./0002-web-search-tool.md) | WebSearch Tool | Draft |
19
+ | [0001](./0001-web-fetch-tool.md) | WebFetch Tool | Implemented |
20
+ | [0002](./0002-web-search-tool.md) | WebSearch Tool | Implemented |
21
21
  | [0003](./0003-task-subagents.md) | Task Tool & Subagents | Draft |
22
22
  | [0004](./0004-plan-mode.md) | Plan Mode | Draft |
23
- | [0005](./0005-todo-system.md) | Todo System | Draft |
24
- | [0006](./0006-memory-system.md) | Memory System (MYCODE.md) | Draft |
23
+ | [0005](./0005-todo-system.md) | Todo System | Implemented |
24
+ | [0006](./0006-memory-system.md) | Memory System (MYCODE.md) | Implemented |
25
25
  | [0007](./0007-context-management.md) | Context Management | Draft |
26
26
  | [0008](./0008-checkpointing.md) | Checkpointing | Draft |
27
27
  | [0009](./0009-hooks-system.md) | Hooks System | Draft |
28
28
  | [0010](./0010-mcp-integration.md) | MCP Integration | Draft |
29
29
  | [0011](./0011-custom-commands.md) | Custom Commands | Draft |
30
- | [0012](./0012-ask-user-question.md) | AskUserQuestion Tool | Draft |
31
- | [0041](./0041-configuration-system.md) | Configuration System | Draft |
30
+ | [0012](./0012-ask-user-question.md) | AskUserQuestion Tool | Implemented |
31
+ | [0041](./0041-configuration-system.md) | Configuration System | Implemented |
32
+ | [0042](./0042-prompt-optimization.md) | Prompt System Optimization | Implemented |
32
33
 
33
34
  ### P2 Priority - Enhanced Features
34
35
 
@@ -0,0 +1,167 @@
1
+ /**
2
+ * Test script for AskUserQuestion tool
3
+ *
4
+ * Run with: npx tsx examples/test-ask-user.ts [mode]
5
+ *
6
+ * Modes:
7
+ * single - Single question, single select (default)
8
+ * multi - Single question, multi-select
9
+ * multiple - Multiple questions with review screen
10
+ */
11
+
12
+ import { render } from 'ink';
13
+ import React from 'react';
14
+ import { QuestionPrompt } from '../src/cli/components/QuestionPrompt.js';
15
+ import type { Question, QuestionAnswer } from '../src/tools/types.js';
16
+
17
+ // Test questions - matching Claude Code style
18
+ const testQuestions: Question[] = [
19
+ {
20
+ question: 'What type of database would you like to create?',
21
+ header: 'DB Type',
22
+ options: [
23
+ {
24
+ label: 'PostgreSQL',
25
+ description: 'Powerful open-source relational database with advanced features like JSON support and full-text search',
26
+ },
27
+ {
28
+ label: 'MySQL',
29
+ description: 'Popular relational database, great for web applications and general-purpose use',
30
+ },
31
+ {
32
+ label: 'SQLite',
33
+ description: 'Lightweight file-based database, perfect for local development or embedded applications',
34
+ },
35
+ {
36
+ label: 'MongoDB',
37
+ description: 'NoSQL document database for flexible schema and JSON-like documents',
38
+ },
39
+ ],
40
+ multiSelect: false,
41
+ },
42
+ ];
43
+
44
+ const testMultiSelectQuestions: Question[] = [
45
+ {
46
+ question: 'Which features should we enable for your project?',
47
+ header: 'Features',
48
+ options: [
49
+ {
50
+ label: 'TypeScript',
51
+ description: 'Type safety and better IDE support with static type checking',
52
+ },
53
+ {
54
+ label: 'ESLint + Prettier',
55
+ description: 'Code linting and automatic formatting for consistent code style',
56
+ },
57
+ {
58
+ label: 'Testing (Vitest)',
59
+ description: 'Fast unit testing framework with native ESM support',
60
+ },
61
+ {
62
+ label: 'Tailwind CSS',
63
+ description: 'Utility-first CSS framework for rapid UI development',
64
+ },
65
+ ],
66
+ multiSelect: true,
67
+ },
68
+ ];
69
+
70
+ const testMultipleQuestions: Question[] = [
71
+ {
72
+ question: 'What type of database would you like to create?',
73
+ header: 'DB Type',
74
+ options: [
75
+ {
76
+ label: 'PostgreSQL',
77
+ description: 'Powerful open-source relational database with advanced features like JSON support and full-text search',
78
+ },
79
+ {
80
+ label: 'MySQL',
81
+ description: 'Popular relational database, great for web applications and general-purpose use',
82
+ },
83
+ {
84
+ label: 'SQLite',
85
+ description: 'Lightweight file-based database, perfect for local development or embedded applications',
86
+ },
87
+ {
88
+ label: 'MongoDB',
89
+ description: 'NoSQL document database for flexible schema and JSON-like documents',
90
+ },
91
+ ],
92
+ multiSelect: false,
93
+ },
94
+ {
95
+ question: 'What is the primary purpose of this database?',
96
+ header: 'Purpose',
97
+ options: [
98
+ {
99
+ label: 'GenCode project',
100
+ description: 'Add database functionality to the GenCode AI assistant project',
101
+ },
102
+ {
103
+ label: 'New project',
104
+ description: 'Create a database for a separate new project',
105
+ },
106
+ {
107
+ label: 'Learning/Testing',
108
+ description: 'Set up a database for experimentation and learning',
109
+ },
110
+ ],
111
+ multiSelect: false,
112
+ },
113
+ ];
114
+
115
+ // Choose which test to run
116
+ const testMode = process.argv[2] || 'single';
117
+
118
+ let questions: Question[];
119
+ switch (testMode) {
120
+ case 'multi':
121
+ questions = testMultiSelectQuestions;
122
+ console.log('\n=== Testing Multi-Select Mode ===\n');
123
+ break;
124
+ case 'multiple':
125
+ questions = testMultipleQuestions;
126
+ console.log('\n=== Testing Multiple Questions with Review ===\n');
127
+ break;
128
+ default:
129
+ questions = testQuestions;
130
+ console.log('\n=== Testing Single-Select Mode ===\n');
131
+ }
132
+
133
+ function TestApp() {
134
+ const handleComplete = (answers: QuestionAnswer[]) => {
135
+ console.log('\n\n=== Answers Received ===');
136
+ answers.forEach((answer, i) => {
137
+ console.log(`\n${i + 1}. ${answer.header}`);
138
+ console.log(` Question: ${answer.question}`);
139
+ console.log(` Selected: ${answer.selectedOptions.join(', ') || '(none)'}`);
140
+ if (answer.customInput) {
141
+ console.log(` Custom: ${answer.customInput}`);
142
+ }
143
+ });
144
+ console.log('\n');
145
+ process.exit(0);
146
+ };
147
+
148
+ const handleCancel = () => {
149
+ console.log('\n\nCancelled by user\n');
150
+ process.exit(0);
151
+ };
152
+
153
+ return React.createElement(QuestionPrompt, {
154
+ questions,
155
+ onComplete: handleComplete,
156
+ onCancel: handleCancel,
157
+ });
158
+ }
159
+
160
+ // Render the test app
161
+ const { unmount } = render(React.createElement(TestApp));
162
+
163
+ // Handle Ctrl+C
164
+ process.on('SIGINT', () => {
165
+ unmount();
166
+ process.exit(0);
167
+ });
package/jest.config.js ADDED
@@ -0,0 +1,26 @@
1
+ /** @type {import('ts-jest').JestConfigWithTsJest} */
2
+ export default {
3
+ preset: 'ts-jest/presets/default-esm',
4
+ testEnvironment: 'node',
5
+ extensionsToTreatAsEsm: ['.ts'],
6
+ moduleNameMapper: {
7
+ '^(\\.{1,2}/.*)\\.js$': '$1',
8
+ },
9
+ transform: {
10
+ '^.+\\.tsx?$': [
11
+ 'ts-jest',
12
+ {
13
+ useESM: true,
14
+ isolatedModules: true,
15
+ },
16
+ ],
17
+ },
18
+ testMatch: ['**/*.test.ts'],
19
+ collectCoverageFrom: [
20
+ 'src/**/*.ts',
21
+ '!src/**/*.d.ts',
22
+ '!src/**/*.test.ts',
23
+ ],
24
+ coverageDirectory: 'coverage',
25
+ moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
26
+ };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "gencode-ai",
3
- "version": "0.1.1",
4
- "description": "GenCode - An open-source, provider-agnostic AI coding assistant",
3
+ "version": "0.1.3",
4
+ "description": "An open-source AI assistant for your terminal",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
@@ -35,10 +35,12 @@
35
35
  "fast-glob": "^3.3.3",
36
36
  "glob": "^13.0.0",
37
37
  "google-auth-library": "^10.5.0",
38
+ "gray-matter": "^4.0.3",
38
39
  "ink": "^6.6.0",
39
40
  "ink-spinner": "^5.0.0",
40
41
  "ink-text-input": "^6.0.0",
41
42
  "marked": "^17.0.1",
43
+ "minimatch": "^10.1.1",
42
44
  "openai": "^6.16.0",
43
45
  "ora": "^9.0.0",
44
46
  "react": "^19.2.3",
@@ -47,8 +49,12 @@
47
49
  "zod": "^4.3.5"
48
50
  },
49
51
  "devDependencies": {
52
+ "@types/jest": "^30.0.0",
53
+ "@types/minimatch": "^5.1.2",
50
54
  "@types/node": "^25.0.8",
51
55
  "@types/react": "^19.2.8",
56
+ "jest": "^30.2.0",
57
+ "ts-jest": "^29.4.6",
52
58
  "tsx": "^4.21.0",
53
59
  "typescript": "^5.9.3"
54
60
  }
@@ -5,29 +5,33 @@
5
5
  import type { LLMProvider, Message, ToolResultContent } from '../providers/types.js';
6
6
  import { createProvider, inferProvider } from '../providers/index.js';
7
7
  import { ToolRegistry, createDefaultRegistry } from '../tools/index.js';
8
- import { PermissionManager } from '../permissions/index.js';
8
+ import {
9
+ PermissionManager,
10
+ type ApprovalAction,
11
+ type ApprovalSuggestion,
12
+ type PromptPermission,
13
+ type PermissionSettings,
14
+ } from '../permissions/index.js';
9
15
  import { SessionManager } from '../session/index.js';
16
+ import { MemoryManager, type LoadedMemory } from '../memory/index.js';
10
17
  import type { AgentConfig, AgentEvent } from './types.js';
18
+ import { buildSystemPromptForModel, debugPromptLoading } from '../prompts/index.js';
19
+ import type { Question, QuestionAnswer } from '../tools/types.js';
11
20
 
12
- const DEFAULT_SYSTEM_PROMPT = `You are a helpful AI assistant with access to tools for reading, writing, and executing code.
13
-
14
- When using tools:
15
- - Use Read to view file contents before editing
16
- - Use Glob/Grep to find files
17
- - Use Edit for precise changes (old_string must be unique)
18
- - Use Write for new files or full rewrites
19
- - Use Bash for commands, git operations, etc.
20
-
21
- Be concise and focus on completing the user's task.`;
21
+ // Type for askUser callback
22
+ export type AskUserCallback = (questions: Question[]) => Promise<QuestionAnswer[]>;
22
23
 
23
24
  export class Agent {
24
25
  private provider: LLMProvider;
25
26
  private registry: ToolRegistry;
26
27
  private permissions: PermissionManager;
27
28
  private sessionManager: SessionManager;
29
+ private memoryManager: MemoryManager;
28
30
  private config: AgentConfig;
29
31
  private messages: Message[] = [];
30
32
  private sessionId: string | null = null;
33
+ private loadedMemory: LoadedMemory | null = null;
34
+ private askUserCallback: AskUserCallback | null = null;
31
35
 
32
36
  constructor(config: AgentConfig) {
33
37
  this.config = {
@@ -38,17 +42,101 @@ export class Agent {
38
42
 
39
43
  this.provider = createProvider({ provider: config.provider });
40
44
  this.registry = createDefaultRegistry();
41
- this.permissions = new PermissionManager(config.permissions);
45
+ this.permissions = new PermissionManager({
46
+ config: config.permissions,
47
+ projectPath: config.cwd,
48
+ });
42
49
  this.sessionManager = new SessionManager();
50
+ this.memoryManager = new MemoryManager();
51
+ }
52
+
53
+ /**
54
+ * Initialize permission system (load persisted rules)
55
+ */
56
+ async initializePermissions(settings?: PermissionSettings): Promise<void> {
57
+ await this.permissions.initialize(settings);
43
58
  }
44
59
 
45
60
  /**
46
- * Set permission confirmation callback
61
+ * Set simple permission confirmation callback (backward compatible)
47
62
  */
48
63
  setConfirmCallback(callback: (tool: string, input: unknown) => Promise<boolean>): void {
64
+ this.permissions.setSimpleConfirmCallback(callback);
65
+ }
66
+
67
+ /**
68
+ * Set enhanced permission confirmation callback with approval options
69
+ */
70
+ setEnhancedConfirmCallback(
71
+ callback: (
72
+ tool: string,
73
+ input: unknown,
74
+ suggestions: ApprovalSuggestion[]
75
+ ) => Promise<ApprovalAction>
76
+ ): void {
49
77
  this.permissions.setConfirmCallback(callback);
50
78
  }
51
79
 
80
+ /**
81
+ * Add prompt-based permissions (Claude Code ExitPlanMode style)
82
+ */
83
+ addAllowedPrompts(prompts: PromptPermission[]): void {
84
+ this.permissions.addAllowedPrompts(prompts);
85
+ }
86
+
87
+ /**
88
+ * Clear prompt-based permissions
89
+ */
90
+ clearAllowedPrompts(): void {
91
+ this.permissions.clearAllowedPrompts();
92
+ }
93
+
94
+ /**
95
+ * Set callback to save permission rules to settings
96
+ * This enables saving rules to settings.local.json instead of permissions.json
97
+ */
98
+ setSaveRuleCallback(callback: (tool: string, pattern?: string) => Promise<void>): void {
99
+ this.permissions.setSaveRuleCallback(callback);
100
+ }
101
+
102
+ /**
103
+ * Get permission manager for direct access
104
+ */
105
+ getPermissionManager(): PermissionManager {
106
+ return this.permissions;
107
+ }
108
+
109
+ /**
110
+ * Set callback for AskUserQuestion tool
111
+ * This allows the CLI to handle user questioning
112
+ */
113
+ setAskUserCallback(callback: AskUserCallback): void {
114
+ this.askUserCallback = callback;
115
+ }
116
+
117
+ /**
118
+ * Get memory manager for direct access
119
+ */
120
+ getMemoryManager(): MemoryManager {
121
+ return this.memoryManager;
122
+ }
123
+
124
+ /**
125
+ * Get loaded memory (null if not loaded yet)
126
+ */
127
+ getLoadedMemory(): LoadedMemory | null {
128
+ return this.loadedMemory;
129
+ }
130
+
131
+ /**
132
+ * Load memory for the current working directory
133
+ */
134
+ async loadMemory(): Promise<LoadedMemory> {
135
+ const cwd = this.config.cwd ?? process.cwd();
136
+ this.loadedMemory = await this.memoryManager.load({ cwd });
137
+ return this.loadedMemory;
138
+ }
139
+
52
140
  /**
53
141
  * Get current session ID
54
142
  */
@@ -186,6 +274,11 @@ export class Agent {
186
274
  await this.startSession();
187
275
  }
188
276
 
277
+ // Load memory if not already loaded
278
+ if (!this.loadedMemory) {
279
+ await this.loadMemory();
280
+ }
281
+
189
282
  // Add user message
190
283
  const userMessage: Message = { role: 'user', content: prompt };
191
284
  this.messages.push(userMessage);
@@ -203,11 +296,26 @@ export class Agent {
203
296
  // Call LLM
204
297
  let response;
205
298
  try {
299
+ // Debug prompt loading (enabled with GENCODE_DEBUG_PROMPTS=1)
300
+ debugPromptLoading(this.config.model, this.config.provider);
301
+
302
+ // Build system prompt based on model → provider → prompt flow
303
+ // Looks up provider from ~/.gencode/providers.json, falls back to config.provider
304
+ const systemPrompt =
305
+ this.config.systemPrompt ??
306
+ buildSystemPromptForModel(
307
+ this.config.model,
308
+ this.config.cwd ?? process.cwd(),
309
+ true, // Assume git repo for now
310
+ this.loadedMemory?.context,
311
+ this.config.provider // Fallback provider if model lookup fails
312
+ );
313
+
206
314
  response = await this.provider.complete({
207
315
  model: this.config.model,
208
316
  messages: this.messages,
209
317
  tools: toolDefs,
210
- systemPrompt: this.config.systemPrompt ?? DEFAULT_SYSTEM_PROMPT,
318
+ systemPrompt,
211
319
  maxTokens: 4096,
212
320
  });
213
321
  } catch (error) {
@@ -241,12 +349,18 @@ export class Agent {
241
349
  const toolResults: ToolResultContent[] = [];
242
350
  const cwd = this.config.cwd ?? process.cwd();
243
351
 
352
+ // Build tool context with askUser callback
353
+ const toolContext = {
354
+ cwd,
355
+ askUser: this.askUserCallback ?? undefined,
356
+ };
357
+
244
358
  for (const call of toolCalls) {
245
359
  yield { type: 'tool_start', id: call.id, name: call.name, input: call.input };
246
360
 
247
- const allowed = await this.permissions.checkPermission(call.name, call.input);
361
+ const allowed = await this.permissions.requestPermission(call.name, call.input);
248
362
  const result = allowed
249
- ? await this.registry.execute(call.name, call.input, { cwd })
363
+ ? await this.registry.execute(call.name, call.input, toolContext)
250
364
  : { success: false, output: '', error: 'Permission denied by user' };
251
365
 
252
366
  yield { type: 'tool_result', id: call.id, name: call.name, result };
@@ -4,3 +4,4 @@
4
4
 
5
5
  export * from './types.js';
6
6
  export { Agent } from './agent.js';
7
+ export type { AskUserCallback } from './agent.js';
@@ -61,10 +61,22 @@ export interface AgentEventDone {
61
61
  text: string;
62
62
  }
63
63
 
64
+ export interface AgentEventAskUser {
65
+ type: 'ask_user';
66
+ id: string;
67
+ questions: Array<{
68
+ question: string;
69
+ header: string;
70
+ options: Array<{ label: string; description: string }>;
71
+ multiSelect: boolean;
72
+ }>;
73
+ }
74
+
64
75
  export type AgentEvent =
65
76
  | AgentEventText
66
77
  | AgentEventToolStart
67
78
  | AgentEventToolResult
68
79
  | AgentEventThinking
69
80
  | AgentEventError
70
- | AgentEventDone;
81
+ | AgentEventDone
82
+ | AgentEventAskUser;