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,29 +1,257 @@
1
1
  /**
2
2
  * Permission System Types
3
+ * Enhanced permission management with pattern matching, prompt-based approvals,
4
+ * persistence, and audit logging - Claude Code compatible design.
3
5
  */
4
6
 
7
+ // ============================================================================
8
+ // Core Types
9
+ // ============================================================================
10
+
5
11
  export type PermissionMode = 'auto' | 'confirm' | 'deny';
12
+ export type PermissionScope = 'session' | 'project' | 'global';
13
+ export type ApprovalAction = 'allow_once' | 'allow_session' | 'allow_always' | 'deny';
14
+
15
+ // ============================================================================
16
+ // Permission Rules
17
+ // ============================================================================
6
18
 
19
+ /**
20
+ * Permission rule for matching tool operations
21
+ * Claude Code style: "Bash(git add:*)"
22
+ */
7
23
  export interface PermissionRule {
24
+ /** Tool name or regex pattern */
8
25
  tool: string | RegExp;
26
+ /** Permission mode for matched operations */
9
27
  mode: PermissionMode;
28
+ /** Optional input pattern for matching (glob-style, e.g., "git add:*") */
29
+ pattern?: string | RegExp;
30
+ /** Semantic description for prompt-based matching */
31
+ prompt?: string;
32
+ /** Rule scope - where this rule applies */
33
+ scope?: PermissionScope;
34
+ /** Expiration timestamp for time-limited rules */
35
+ expiresAt?: Date;
36
+ /** Human-readable description of the rule */
37
+ description?: string;
38
+ }
39
+
40
+ /**
41
+ * Prompt-based permission (Claude Code ExitPlanMode style)
42
+ * { tool: "Bash", prompt: "run tests" }
43
+ */
44
+ export interface PromptPermission {
45
+ /** Tool this permission applies to */
46
+ tool: string;
47
+ /** Semantic description of allowed action */
48
+ prompt: string;
10
49
  }
11
50
 
51
+ // ============================================================================
52
+ // Permission Config
53
+ // ============================================================================
54
+
55
+ /**
56
+ * Complete permission configuration
57
+ */
12
58
  export interface PermissionConfig {
59
+ /** Default mode for unmatched tools */
13
60
  defaultMode: PermissionMode;
61
+ /** Built-in and user-defined rules */
14
62
  rules: PermissionRule[];
63
+ /** Prompt-based permissions (from plan approval) */
64
+ allowedPrompts: PromptPermission[];
65
+ }
66
+
67
+ /**
68
+ * Serializable permission settings (for settings.json)
69
+ * Claude Code format: { allow: ["Bash(git add:*)"], ask: ["Bash(npm run:*)"], deny: ["Bash(rm -rf:*)"] }
70
+ */
71
+ export interface PermissionSettings {
72
+ /** Allow patterns - auto-approve matching operations */
73
+ allow?: string[];
74
+ /** Ask patterns - require confirmation for matching operations */
75
+ ask?: string[];
76
+ /** Deny patterns - block matching operations */
77
+ deny?: string[];
78
+ }
79
+
80
+ // ============================================================================
81
+ // Permission Context
82
+ // ============================================================================
83
+
84
+ /**
85
+ * Context for permission check
86
+ */
87
+ export interface PermissionContext {
88
+ /** Tool being executed */
89
+ tool: string;
90
+ /** Tool input/parameters */
91
+ input: unknown;
92
+ /** Current session ID */
93
+ sessionId?: string;
94
+ /** Project path */
95
+ projectPath?: string;
96
+ }
97
+
98
+ // ============================================================================
99
+ // Permission Decision
100
+ // ============================================================================
101
+
102
+ /**
103
+ * Result of a permission check
104
+ */
105
+ export interface PermissionDecision {
106
+ /** Whether operation is allowed */
107
+ allowed: boolean;
108
+ /** Reason for the decision */
109
+ reason: string;
110
+ /** Rule that matched (if any) */
111
+ matchedRule?: PermissionRule | PromptPermission;
112
+ /** Whether user confirmation is required */
113
+ requiresConfirmation: boolean;
114
+ /** Suggested approval options */
115
+ suggestions?: ApprovalSuggestion[];
116
+ }
117
+
118
+ /**
119
+ * Approval option presented to user
120
+ */
121
+ export interface ApprovalSuggestion {
122
+ /** Action identifier */
123
+ action: ApprovalAction;
124
+ /** User-facing label */
125
+ label: string;
126
+ /** Description of what this option does */
127
+ description?: string;
128
+ /** Keyboard shortcut (e.g., "1", "y") */
129
+ shortcut?: string;
15
130
  }
16
131
 
132
+ // ============================================================================
133
+ // Audit Types
134
+ // ============================================================================
135
+
136
+ export type AuditDecision = 'allowed' | 'denied' | 'confirmed' | 'rejected';
137
+
138
+ /**
139
+ * Audit log entry for permission decisions
140
+ */
141
+ export interface PermissionAuditEntry {
142
+ /** When the decision was made */
143
+ timestamp: Date;
144
+ /** Tool that was checked */
145
+ tool: string;
146
+ /** Summarized input (not full payload for privacy) */
147
+ inputSummary: string;
148
+ /** Final decision */
149
+ decision: AuditDecision;
150
+ /** Reason for decision */
151
+ reason: string;
152
+ /** Rule that matched (if any) */
153
+ matchedRule?: string;
154
+ /** Session ID */
155
+ sessionId?: string;
156
+ }
157
+
158
+ // ============================================================================
159
+ // Persistence Types
160
+ // ============================================================================
161
+
162
+ /**
163
+ * Persisted rule for permanent storage
164
+ */
165
+ export interface PersistedRule {
166
+ /** Unique rule ID */
167
+ id: string;
168
+ /** Tool pattern string */
169
+ tool: string;
170
+ /** Input pattern string */
171
+ pattern?: string;
172
+ /** Permission mode */
173
+ mode: PermissionMode;
174
+ /** Rule scope */
175
+ scope: PermissionScope;
176
+ /** When rule was created */
177
+ createdAt: string;
178
+ /** Description */
179
+ description?: string;
180
+ }
181
+
182
+ /**
183
+ * Persisted permissions file structure
184
+ */
185
+ export interface PersistedPermissions {
186
+ /** Version for migration */
187
+ version: number;
188
+ /** Global rules */
189
+ rules: PersistedRule[];
190
+ }
191
+
192
+ // ============================================================================
193
+ // Callback Types
194
+ // ============================================================================
195
+
196
+ /**
197
+ * Confirmation callback with approval options
198
+ */
199
+ export type ConfirmCallback = (
200
+ tool: string,
201
+ input: unknown,
202
+ suggestions: ApprovalSuggestion[]
203
+ ) => Promise<ApprovalAction>;
204
+
205
+ /**
206
+ * Simple yes/no confirmation callback (for backward compatibility)
207
+ */
208
+ export type SimpleConfirmCallback = (tool: string, input: unknown) => Promise<boolean>;
209
+
210
+ // ============================================================================
211
+ // Default Configuration
212
+ // ============================================================================
213
+
214
+ /**
215
+ * Default permission configuration (Claude Code style)
216
+ * - Read-only tools auto-approved
217
+ * - Write operations require confirmation
218
+ * - Users can configure additional rules in settings.json
219
+ */
17
220
  export const DEFAULT_PERMISSION_CONFIG: PermissionConfig = {
18
221
  defaultMode: 'confirm',
19
222
  rules: [
20
- // Read-only tools are auto-approved
21
- { tool: 'Read', mode: 'auto' },
22
- { tool: 'Glob', mode: 'auto' },
23
- { tool: 'Grep', mode: 'auto' },
24
- // Write operations require confirmation
25
- { tool: 'Write', mode: 'confirm' },
26
- { tool: 'Edit', mode: 'confirm' },
27
- { tool: 'Bash', mode: 'confirm' },
223
+ // Read-only tools - auto-approve (Claude Code behavior)
224
+ { tool: 'Read', mode: 'auto', description: 'File reading' },
225
+ { tool: 'Glob', mode: 'auto', description: 'Pattern matching' },
226
+ { tool: 'Grep', mode: 'auto', description: 'Content search' },
227
+ { tool: 'LSP', mode: 'auto', description: 'Language server' },
228
+ // Internal state management - auto-approve (no side effects)
229
+ { tool: 'TodoWrite', mode: 'auto', description: 'Task tracking' },
28
230
  ],
231
+ allowedPrompts: [],
29
232
  };
233
+
234
+ /**
235
+ * Default approval suggestions (Claude Code style)
236
+ * The second option dynamically shows the path context
237
+ */
238
+ export const DEFAULT_SUGGESTIONS: ApprovalSuggestion[] = [
239
+ {
240
+ action: 'allow_once',
241
+ label: 'Yes',
242
+ description: 'Allow this operation',
243
+ shortcut: '1',
244
+ },
245
+ {
246
+ action: 'allow_always',
247
+ label: "Yes, and don't ask again",
248
+ description: 'Add to project allowlist',
249
+ shortcut: '2',
250
+ },
251
+ {
252
+ action: 'deny',
253
+ label: 'No',
254
+ description: 'Block this operation',
255
+ shortcut: '3',
256
+ },
257
+ ];
@@ -0,0 +1,279 @@
1
+ /**
2
+ * Prompt System Tests
3
+ *
4
+ * Tests to ensure prompts are correctly loaded and contain key guidance.
5
+ */
6
+
7
+ import { describe, it, expect } from '@jest/globals';
8
+ import {
9
+ loadPrompt,
10
+ loadSystemPrompt,
11
+ buildSystemPrompt,
12
+ buildSystemPromptWithMemory,
13
+ buildSystemPromptForModel,
14
+ mapProviderToPromptType,
15
+ getPromptTypeForModel,
16
+ formatEnvironmentInfo,
17
+ getEnvironmentInfo,
18
+ type ProviderType,
19
+ } from './index.js';
20
+
21
+ describe('Prompt Loader', () => {
22
+ describe('loadPrompt', () => {
23
+ it('should load base.txt from system category', () => {
24
+ const content = loadPrompt('system', 'base');
25
+ expect(content).toContain('GenCode');
26
+ expect(content.length).toBeGreaterThan(100);
27
+ });
28
+
29
+ it('should load provider-specific prompts', () => {
30
+ const providers: ProviderType[] = ['anthropic', 'openai', 'gemini', 'generic'];
31
+ for (const provider of providers) {
32
+ const content = loadPrompt('system', provider);
33
+ expect(content.length).toBeGreaterThan(0);
34
+ }
35
+ });
36
+
37
+ it('should load tool descriptions', () => {
38
+ const tools = ['read', 'write', 'edit', 'bash', 'glob', 'grep'];
39
+ for (const tool of tools) {
40
+ const content = loadPrompt('tools', tool);
41
+ expect(content.length).toBeGreaterThan(0);
42
+ }
43
+ });
44
+ });
45
+
46
+ describe('loadSystemPrompt', () => {
47
+ it('should concatenate base + provider prompts', () => {
48
+ const prompt = loadSystemPrompt('anthropic');
49
+
50
+ // Should contain base content
51
+ expect(prompt).toContain('GenCode');
52
+ expect(prompt).toContain('# Tone and Style');
53
+
54
+ // Should contain anthropic-specific content
55
+ expect(prompt).toContain('Claude');
56
+ });
57
+
58
+ it('should work for all provider types', () => {
59
+ const providers: ProviderType[] = ['anthropic', 'openai', 'gemini', 'generic'];
60
+ for (const provider of providers) {
61
+ const prompt = loadSystemPrompt(provider);
62
+ expect(prompt).toContain('GenCode');
63
+ expect(prompt.length).toBeGreaterThan(500);
64
+ }
65
+ });
66
+ });
67
+
68
+ describe('buildSystemPrompt', () => {
69
+ it('should inject environment info', () => {
70
+ const prompt = buildSystemPrompt('generic', '/tmp/test', true);
71
+
72
+ expect(prompt).toContain('<env>');
73
+ expect(prompt).toContain('Working directory: /tmp/test');
74
+ expect(prompt).toContain('Is directory a git repo: Yes');
75
+ expect(prompt).toContain('Platform:');
76
+ expect(prompt).toContain("Today's date:");
77
+ expect(prompt).toContain('</env>');
78
+ });
79
+
80
+ it('should replace {{ENVIRONMENT}} placeholder', () => {
81
+ const prompt = buildSystemPrompt('generic', '/test');
82
+ expect(prompt).not.toContain('{{ENVIRONMENT}}');
83
+ });
84
+ });
85
+
86
+ describe('buildSystemPromptWithMemory', () => {
87
+ it('should append memory context when provided', () => {
88
+ const memoryContext = '# Project Rules\n- Use TypeScript';
89
+ const prompt = buildSystemPromptWithMemory('generic', '/test', false, memoryContext);
90
+
91
+ expect(prompt).toContain('<claudeMd>');
92
+ expect(prompt).toContain('# Project Rules');
93
+ expect(prompt).toContain('Use TypeScript');
94
+ expect(prompt).toContain('</claudeMd>');
95
+ });
96
+
97
+ it('should not add memory section when context is empty', () => {
98
+ const prompt = buildSystemPromptWithMemory('generic', '/test', false);
99
+ expect(prompt).not.toContain('<claudeMd>');
100
+ });
101
+ });
102
+
103
+ describe('mapProviderToPromptType', () => {
104
+ it('should map known providers correctly', () => {
105
+ expect(mapProviderToPromptType('anthropic')).toBe('anthropic');
106
+ expect(mapProviderToPromptType('openai')).toBe('openai');
107
+ expect(mapProviderToPromptType('gemini')).toBe('gemini');
108
+ });
109
+
110
+ it('should return generic for unknown providers', () => {
111
+ expect(mapProviderToPromptType('unknown')).toBe('generic');
112
+ expect(mapProviderToPromptType('ollama')).toBe('generic');
113
+ });
114
+ });
115
+
116
+ describe('getPromptTypeForModel', () => {
117
+ it('should use fallback provider when model lookup fails', () => {
118
+ // Unknown model with fallback
119
+ expect(getPromptTypeForModel('unknown-model', 'anthropic')).toBe('anthropic');
120
+ expect(getPromptTypeForModel('unknown-model', 'openai')).toBe('openai');
121
+ });
122
+
123
+ it('should return generic when no fallback provided', () => {
124
+ expect(getPromptTypeForModel('unknown-model')).toBe('generic');
125
+ });
126
+ });
127
+
128
+ describe('buildSystemPromptForModel', () => {
129
+ it('should build prompt using fallback provider', () => {
130
+ const prompt = buildSystemPromptForModel(
131
+ 'unknown-model',
132
+ '/test',
133
+ false,
134
+ undefined,
135
+ 'anthropic'
136
+ );
137
+
138
+ expect(prompt).toContain('GenCode');
139
+ expect(prompt).toContain('Claude');
140
+ });
141
+ });
142
+
143
+ describe('Environment Info', () => {
144
+ it('should generate correct environment info', () => {
145
+ const env = getEnvironmentInfo('/my/project', true);
146
+
147
+ expect(env.cwd).toBe('/my/project');
148
+ expect(env.isGitRepo).toBe(true);
149
+ expect(env.platform).toBe(process.platform);
150
+ expect(env.date).toMatch(/^\d{4}-\d{2}-\d{2}$/);
151
+ });
152
+
153
+ it('should format environment info correctly', () => {
154
+ const env = getEnvironmentInfo('/test', false);
155
+ const formatted = formatEnvironmentInfo(env);
156
+
157
+ expect(formatted).toContain('<env>');
158
+ expect(formatted).toContain('Working directory: /test');
159
+ expect(formatted).toContain('Is directory a git repo: No');
160
+ expect(formatted).toContain('</env>');
161
+ });
162
+ });
163
+ });
164
+
165
+ describe('Prompt Content Validation', () => {
166
+ describe('base.txt - Claude Code key guidance', () => {
167
+ let basePrompt: string;
168
+
169
+ beforeAll(() => {
170
+ basePrompt = loadPrompt('system', 'base');
171
+ });
172
+
173
+ it('should contain token minimization guidance', () => {
174
+ expect(basePrompt).toMatch(/minimize output tokens/i);
175
+ });
176
+
177
+ it('should contain CommonMark rendering info', () => {
178
+ expect(basePrompt).toMatch(/CommonMark/i);
179
+ });
180
+
181
+ it('should contain forbidden preamble/postamble phrases', () => {
182
+ expect(basePrompt).toContain('The answer is');
183
+ expect(basePrompt).toContain('Here is the content');
184
+ });
185
+
186
+ it('should contain conciseness guidance', () => {
187
+ expect(basePrompt).toMatch(/concise|fewer than 4 lines/i);
188
+ });
189
+
190
+ it('should contain non-preachy refusal guidance', () => {
191
+ expect(basePrompt).toMatch(/preachy|annoying/i);
192
+ });
193
+
194
+ it('should contain examples', () => {
195
+ expect(basePrompt).toContain('<example>');
196
+ expect(basePrompt).toContain('</example>');
197
+ // Verify at least one simple example
198
+ expect(basePrompt).toMatch(/2 \+ 2[\s\S]*?4/);
199
+ });
200
+
201
+ it('should contain task management section', () => {
202
+ expect(basePrompt).toContain('TodoWrite');
203
+ });
204
+
205
+ it('should contain tool usage policy', () => {
206
+ expect(basePrompt).toContain('Tool Usage');
207
+ });
208
+
209
+ it('should contain environment placeholder', () => {
210
+ expect(basePrompt).toContain('{{ENVIRONMENT}}');
211
+ });
212
+ });
213
+
214
+ describe('generic.txt - standalone comprehensive prompt', () => {
215
+ let genericPrompt: string;
216
+
217
+ beforeAll(() => {
218
+ genericPrompt = loadPrompt('system', 'generic');
219
+ });
220
+
221
+ it('should contain token minimization guidance', () => {
222
+ expect(genericPrompt).toMatch(/minimize output tokens/i);
223
+ });
224
+
225
+ it('should contain tool selection guidelines table', () => {
226
+ expect(genericPrompt).toContain('| Task | Tool |');
227
+ });
228
+
229
+ it('should contain software engineering workflow', () => {
230
+ expect(genericPrompt).toContain('Software Engineering Workflow');
231
+ });
232
+
233
+ it('should contain security guidance', () => {
234
+ expect(genericPrompt).toMatch(/security|secrets/i);
235
+ });
236
+
237
+ it('should contain examples', () => {
238
+ expect(genericPrompt).toContain('<example>');
239
+ const exampleCount = (genericPrompt.match(/<example>/g) || []).length;
240
+ expect(exampleCount).toBeGreaterThanOrEqual(3);
241
+ });
242
+ });
243
+
244
+ describe('Provider-specific prompts', () => {
245
+ it('anthropic.txt should reference Claude capabilities', () => {
246
+ const prompt = loadPrompt('system', 'anthropic');
247
+ expect(prompt).toMatch(/claude|thinking|anthropic/i);
248
+ });
249
+
250
+ it('openai.txt should reference GPT capabilities', () => {
251
+ const prompt = loadPrompt('system', 'openai');
252
+ expect(prompt).toMatch(/gpt|openai|structured/i);
253
+ });
254
+
255
+ it('gemini.txt should reference Gemini capabilities', () => {
256
+ const prompt = loadPrompt('system', 'gemini');
257
+ expect(prompt).toMatch(/gemini|google|multimodal/i);
258
+ });
259
+ });
260
+ });
261
+
262
+ describe('Tool Description Validation', () => {
263
+ const requiredTools = ['read', 'write', 'edit', 'bash', 'glob', 'grep', 'todowrite'];
264
+
265
+ it.each(requiredTools)('should have description for %s tool', (tool) => {
266
+ const description = loadPrompt('tools', tool);
267
+ expect(description.length).toBeGreaterThan(50);
268
+ });
269
+
270
+ it('bash.txt should contain git safety guidance', () => {
271
+ const bash = loadPrompt('tools', 'bash');
272
+ expect(bash).toMatch(/git|commit/i);
273
+ });
274
+
275
+ it('todowrite.txt should contain task state guidance', () => {
276
+ const todo = loadPrompt('tools', 'todowrite');
277
+ expect(todo).toMatch(/pending|in_progress|completed/i);
278
+ });
279
+ });