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
@@ -0,0 +1,182 @@
1
+ /**
2
+ * Rules Parser Tests
3
+ */
4
+
5
+ import { parseRuleFrontmatter, matchesPatterns } from './rules-parser.js';
6
+
7
+ describe('Rules Parser', () => {
8
+ describe('parseRuleFrontmatter', () => {
9
+ it('should parse simple YAML frontmatter with paths', () => {
10
+ const content = `---
11
+ paths:
12
+ - "src/**/*.ts"
13
+ - "lib/**/*.ts"
14
+ ---
15
+
16
+ # Rule Content
17
+
18
+ This is the rule body.`;
19
+
20
+ const result = parseRuleFrontmatter(content);
21
+
22
+ expect(result.paths).toEqual(['src/**/*.ts', 'lib/**/*.ts']);
23
+ expect(result.content).toBe('# Rule Content\n\nThis is the rule body.');
24
+ });
25
+
26
+ it('should return empty paths for content without frontmatter', () => {
27
+ const content = `# Rule Without Frontmatter
28
+
29
+ Just regular markdown content.`;
30
+
31
+ const result = parseRuleFrontmatter(content);
32
+
33
+ expect(result.paths).toEqual([]);
34
+ expect(result.content).toBe('# Rule Without Frontmatter\n\nJust regular markdown content.');
35
+ });
36
+
37
+ it('should return empty paths when frontmatter has no paths field', () => {
38
+ const content = `---
39
+ title: Some Rule
40
+ description: A rule without path scoping
41
+ ---
42
+
43
+ # Rule Content`;
44
+
45
+ const result = parseRuleFrontmatter(content);
46
+
47
+ expect(result.paths).toEqual([]);
48
+ expect(result.content).toBe('# Rule Content');
49
+ });
50
+
51
+ it('should handle single path as array', () => {
52
+ const content = `---
53
+ paths:
54
+ - "src/api/**/*.ts"
55
+ ---
56
+
57
+ # API Rules`;
58
+
59
+ const result = parseRuleFrontmatter(content);
60
+
61
+ expect(result.paths).toEqual(['src/api/**/*.ts']);
62
+ });
63
+
64
+ it('should filter non-string paths', () => {
65
+ const content = `---
66
+ paths:
67
+ - "valid/path/*.ts"
68
+ - 123
69
+ - true
70
+ - "another/valid/*.js"
71
+ ---
72
+
73
+ # Mixed Paths`;
74
+
75
+ const result = parseRuleFrontmatter(content);
76
+
77
+ expect(result.paths).toEqual(['valid/path/*.ts', 'another/valid/*.js']);
78
+ });
79
+
80
+ it('should handle empty frontmatter', () => {
81
+ const content = `---
82
+ ---
83
+
84
+ # Empty Frontmatter`;
85
+
86
+ const result = parseRuleFrontmatter(content);
87
+
88
+ expect(result.paths).toEqual([]);
89
+ expect(result.content).toBe('# Empty Frontmatter');
90
+ });
91
+
92
+ it('should trim content whitespace', () => {
93
+ const content = `---
94
+ paths: []
95
+ ---
96
+
97
+
98
+ # Content with extra whitespace
99
+
100
+
101
+ `;
102
+
103
+ const result = parseRuleFrontmatter(content);
104
+
105
+ expect(result.content).toBe('# Content with extra whitespace');
106
+ });
107
+ });
108
+
109
+ describe('matchesPatterns', () => {
110
+ it('should return true when patterns is empty (always active)', () => {
111
+ expect(matchesPatterns('any/file.ts', [])).toBe(true);
112
+ });
113
+
114
+ it('should match glob patterns', () => {
115
+ const patterns = ['src/**/*.ts'];
116
+
117
+ expect(matchesPatterns('src/components/Button.ts', patterns)).toBe(true);
118
+ expect(matchesPatterns('src/deep/nested/file.ts', patterns)).toBe(true);
119
+ expect(matchesPatterns('lib/file.ts', patterns)).toBe(false);
120
+ });
121
+
122
+ it('should match multiple patterns (OR logic)', () => {
123
+ const patterns = ['src/**/*.ts', 'lib/**/*.ts'];
124
+
125
+ expect(matchesPatterns('src/file.ts', patterns)).toBe(true);
126
+ expect(matchesPatterns('lib/file.ts', patterns)).toBe(true);
127
+ expect(matchesPatterns('test/file.ts', patterns)).toBe(false);
128
+ });
129
+
130
+ it('should match file extensions', () => {
131
+ const patterns = ['**/*.test.ts', '**/*.spec.ts'];
132
+
133
+ expect(matchesPatterns('src/Button.test.ts', patterns)).toBe(true);
134
+ expect(matchesPatterns('lib/utils.spec.ts', patterns)).toBe(true);
135
+ expect(matchesPatterns('src/Button.ts', patterns)).toBe(false);
136
+ });
137
+
138
+ it('should handle matchBase for simple patterns', () => {
139
+ const patterns = ['*.ts'];
140
+
141
+ // With matchBase: true, *.ts should match file.ts anywhere
142
+ expect(matchesPatterns('file.ts', patterns)).toBe(true);
143
+ });
144
+
145
+ it('should match specific directories', () => {
146
+ const patterns = ['src/api/**', 'src/routes/**'];
147
+
148
+ expect(matchesPatterns('src/api/users.ts', patterns)).toBe(true);
149
+ expect(matchesPatterns('src/routes/index.ts', patterns)).toBe(true);
150
+ expect(matchesPatterns('src/components/Button.ts', patterns)).toBe(false);
151
+ });
152
+
153
+ it('should handle dot files when dot option is true', () => {
154
+ const patterns = ['**/*.md'];
155
+
156
+ // Should match hidden directories
157
+ expect(matchesPatterns('.github/README.md', patterns)).toBe(true);
158
+ });
159
+
160
+ it('should handle negation in paths', () => {
161
+ // This tests behavior - minimatch handles negation differently
162
+ const patterns = ['src/**/*.ts'];
163
+
164
+ expect(matchesPatterns('src/index.ts', patterns)).toBe(true);
165
+ expect(matchesPatterns('src/index.js', patterns)).toBe(false);
166
+ });
167
+
168
+ it('should handle complex patterns', () => {
169
+ const patterns = ['src/{api,routes}/**/*.ts'];
170
+
171
+ expect(matchesPatterns('src/api/users.ts', patterns)).toBe(true);
172
+ expect(matchesPatterns('src/routes/auth.ts', patterns)).toBe(true);
173
+ expect(matchesPatterns('src/utils/helpers.ts', patterns)).toBe(false);
174
+ });
175
+
176
+ it('should match relative paths', () => {
177
+ const patterns = ['./src/**/*.ts'];
178
+
179
+ expect(matchesPatterns('./src/file.ts', patterns)).toBe(true);
180
+ });
181
+ });
182
+ });
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Rules Parser - Parse frontmatter from rules files
3
+ *
4
+ * Uses gray-matter for YAML frontmatter parsing.
5
+ * Supports 'paths:' frontmatter for glob-based rule scoping.
6
+ *
7
+ * Example rule file:
8
+ * ---
9
+ * paths:
10
+ * - "src/api/**\/*.ts"
11
+ * - "src/routes/**\/*.ts"
12
+ * ---
13
+ *
14
+ * # API Development Rules
15
+ * - Use async/await consistently
16
+ */
17
+
18
+ import matter from 'gray-matter';
19
+ import { minimatch } from 'minimatch';
20
+ import type { MemoryRule } from './types.js';
21
+
22
+ export interface ParsedRule {
23
+ paths: string[];
24
+ content: string;
25
+ }
26
+
27
+ /**
28
+ * Parse frontmatter from a rule file
29
+ */
30
+ export function parseRuleFrontmatter(fileContent: string): ParsedRule {
31
+ try {
32
+ const { data, content } = matter(fileContent);
33
+
34
+ // Extract paths from frontmatter
35
+ let paths: string[] = [];
36
+ if (data.paths) {
37
+ if (Array.isArray(data.paths)) {
38
+ paths = data.paths.filter((p: unknown) => typeof p === 'string');
39
+ } else if (typeof data.paths === 'string') {
40
+ paths = [data.paths];
41
+ }
42
+ }
43
+
44
+ return { paths, content: content.trim() };
45
+ } catch {
46
+ // If frontmatter parsing fails, return full content with no paths
47
+ return { paths: [], content: fileContent };
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Check if a file path matches any of the glob patterns
53
+ */
54
+ export function matchesPatterns(filePath: string, patterns: string[]): boolean {
55
+ if (patterns.length === 0) {
56
+ return true; // No patterns = always active
57
+ }
58
+
59
+ return patterns.some((pattern) =>
60
+ minimatch(filePath, pattern, {
61
+ matchBase: true,
62
+ dot: true,
63
+ })
64
+ );
65
+ }
66
+
67
+ /**
68
+ * Activate rules based on current file context
69
+ */
70
+ export function activateRules(rules: MemoryRule[], currentFile?: string): MemoryRule[] {
71
+ return rules.map((rule) => ({
72
+ ...rule,
73
+ isActive: currentFile ? matchesPatterns(currentFile, rule.patterns) : rule.patterns.length === 0,
74
+ }));
75
+ }
76
+
77
+ /**
78
+ * Get only active rules
79
+ */
80
+ export function getActiveRules(rules: MemoryRule[]): MemoryRule[] {
81
+ return rules.filter((rule) => rule.isActive);
82
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Shared test utilities for memory tests
3
+ */
4
+
5
+ import * as fs from 'fs/promises';
6
+ import * as path from 'path';
7
+ import * as os from 'os';
8
+
9
+ export interface TestProject {
10
+ tempDir: string;
11
+ projectDir: string;
12
+ cleanup: () => Promise<void>;
13
+ }
14
+
15
+ /**
16
+ * Create a test project with temp directory and git marker
17
+ */
18
+ export async function createTestProject(prefix = 'gencode-test-'): Promise<TestProject> {
19
+ const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), prefix));
20
+ const projectDir = path.join(tempDir, 'project');
21
+
22
+ await fs.mkdir(projectDir, { recursive: true });
23
+ await fs.mkdir(path.join(projectDir, '.git'));
24
+
25
+ return {
26
+ tempDir,
27
+ projectDir,
28
+ cleanup: async () => {
29
+ await fs.rm(tempDir, { recursive: true, force: true });
30
+ delete process.env.GENCODE_CONFIG_DIRS;
31
+ },
32
+ };
33
+ }
34
+
35
+ /**
36
+ * Write memory file to a directory
37
+ */
38
+ export async function writeMemory(
39
+ projectDir: string,
40
+ namespace: 'claude' | 'gencode',
41
+ content: string,
42
+ options: { local?: boolean; inDir?: boolean } = {}
43
+ ): Promise<string> {
44
+ const { local = false, inDir = true } = options;
45
+ const filename = namespace === 'claude'
46
+ ? (local ? 'CLAUDE.local.md' : 'CLAUDE.md')
47
+ : (local ? 'AGENT.local.md' : 'AGENT.md');
48
+
49
+ let filePath: string;
50
+ if (inDir) {
51
+ const dir = path.join(projectDir, namespace === 'claude' ? '.claude' : '.gencode');
52
+ await fs.mkdir(dir, { recursive: true });
53
+ filePath = path.join(dir, filename);
54
+ } else {
55
+ filePath = path.join(projectDir, filename);
56
+ }
57
+
58
+ await fs.writeFile(filePath, content);
59
+ return filePath;
60
+ }
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Memory System Types
3
+ *
4
+ * Hierarchical memory loading compatible with Claude Code:
5
+ * At each level, both .gencode and .claude are loaded and merged (gencode has higher priority).
6
+ *
7
+ * Levels:
8
+ * - Enterprise: System-wide managed memory (enforced)
9
+ * - User: ~/.gencode/ + ~/.claude/ (both loaded, gencode content appears later)
10
+ * - User Rules: ~/.gencode/rules/ + ~/.claude/rules/
11
+ * - Extra: GENCODE_CONFIG_DIRS directories
12
+ * - Project: ./AGENT.md, .gencode/, ./CLAUDE.md, .claude/ (recursive upward search)
13
+ * - Project Rules: .gencode/rules/ + .claude/rules/
14
+ * - Local: *.local.md files (gitignored)
15
+ */
16
+
17
+ export type MemoryLevel =
18
+ | 'enterprise'
19
+ | 'user'
20
+ | 'user-rules'
21
+ | 'extra'
22
+ | 'project'
23
+ | 'project-rules'
24
+ | 'local';
25
+
26
+ export type MemoryNamespace = 'gencode' | 'claude' | 'extra';
27
+
28
+ export interface MemoryFile {
29
+ path: string;
30
+ content: string;
31
+ level: MemoryLevel;
32
+ namespace: MemoryNamespace;
33
+ loadedAt: Date;
34
+ resolvedImports: string[];
35
+ enforced?: boolean; // For enterprise level
36
+ }
37
+
38
+ export interface MemoryRule {
39
+ path: string;
40
+ content: string;
41
+ patterns: string[]; // Glob patterns from 'paths:' frontmatter
42
+ isActive: boolean; // Whether current file context matches
43
+ level: 'user-rules' | 'project-rules';
44
+ namespace: MemoryNamespace;
45
+ }
46
+
47
+ export interface MemoryConfig {
48
+ // GenCode file names (higher priority)
49
+ gencodeFilename: string;
50
+ gencodeLocalFilename: string;
51
+ gencodeDir: string;
52
+
53
+ // Claude file names (lower priority, loaded first)
54
+ claudeFilename: string;
55
+ claudeLocalFilename: string;
56
+ claudeDir: string;
57
+
58
+ // Common settings
59
+ rulesDir: string;
60
+ maxFileSize: number;
61
+ maxTotalSize: number;
62
+ maxImportDepth: number;
63
+ }
64
+
65
+ export const DEFAULT_MEMORY_CONFIG: MemoryConfig = {
66
+ // GenCode
67
+ gencodeFilename: 'AGENT.md',
68
+ gencodeLocalFilename: 'AGENT.local.md',
69
+ gencodeDir: '.gencode',
70
+
71
+ // Claude
72
+ claudeFilename: 'CLAUDE.md',
73
+ claudeLocalFilename: 'CLAUDE.local.md',
74
+ claudeDir: '.claude',
75
+
76
+ // Common
77
+ rulesDir: 'rules',
78
+ maxFileSize: 100 * 1024, // 100KB
79
+ maxTotalSize: 500 * 1024, // 500KB
80
+ maxImportDepth: 5,
81
+ };
82
+
83
+ // Legacy compatibility
84
+ export const LEGACY_MEMORY_CONFIG = {
85
+ primaryFilename: 'AGENT.md',
86
+ fallbackFilename: 'CLAUDE.md',
87
+ localFilename: 'AGENT.local.md',
88
+ localFallbackFilename: 'CLAUDE.local.md',
89
+ primaryUserDir: '.gencode',
90
+ fallbackUserDir: '.claude',
91
+ primaryLocalDir: '.gencode',
92
+ fallbackLocalDir: '.claude',
93
+ rulesDir: 'rules',
94
+ maxFileSize: 100 * 1024,
95
+ maxTotalSize: 500 * 1024,
96
+ maxImportDepth: 5,
97
+ };
98
+
99
+ export interface LoadedMemory {
100
+ files: MemoryFile[];
101
+ rules: MemoryRule[];
102
+ totalSize: number;
103
+ context: string;
104
+ errors: string[];
105
+ sources: MemorySource[]; // For debugging
106
+ }
107
+
108
+ export interface MemorySource {
109
+ level: MemoryLevel;
110
+ namespace: MemoryNamespace;
111
+ path: string;
112
+ type: 'file' | 'rule';
113
+ size: number;
114
+ }
115
+
116
+ export interface MemoryLoadOptions {
117
+ cwd: string;
118
+ currentFile?: string; // For activating path-scoped rules
119
+ }