gencode-ai 0.1.3 → 0.3.0

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 (260) hide show
  1. package/README.md +2 -1
  2. package/dist/agent/agent.d.ts +44 -2
  3. package/dist/agent/agent.d.ts.map +1 -1
  4. package/dist/agent/agent.js +130 -11
  5. package/dist/agent/agent.js.map +1 -1
  6. package/dist/agent/types.d.ts +11 -1
  7. package/dist/agent/types.d.ts.map +1 -1
  8. package/dist/checkpointing/checkpoint-manager.d.ts +87 -0
  9. package/dist/checkpointing/checkpoint-manager.d.ts.map +1 -0
  10. package/dist/checkpointing/checkpoint-manager.js +281 -0
  11. package/dist/checkpointing/checkpoint-manager.js.map +1 -0
  12. package/dist/checkpointing/index.d.ts +29 -0
  13. package/dist/checkpointing/index.d.ts.map +1 -0
  14. package/dist/checkpointing/index.js +29 -0
  15. package/dist/checkpointing/index.js.map +1 -0
  16. package/dist/checkpointing/types.d.ts +98 -0
  17. package/dist/checkpointing/types.d.ts.map +1 -0
  18. package/dist/checkpointing/types.js +7 -0
  19. package/dist/checkpointing/types.js.map +1 -0
  20. package/dist/cli/components/App.d.ts.map +1 -1
  21. package/dist/cli/components/App.js +171 -14
  22. package/dist/cli/components/App.js.map +1 -1
  23. package/dist/cli/components/CommandSuggestions.d.ts.map +1 -1
  24. package/dist/cli/components/CommandSuggestions.js +5 -0
  25. package/dist/cli/components/CommandSuggestions.js.map +1 -1
  26. package/dist/cli/components/Messages.d.ts +7 -1
  27. package/dist/cli/components/Messages.d.ts.map +1 -1
  28. package/dist/cli/components/Messages.js +12 -3
  29. package/dist/cli/components/Messages.js.map +1 -1
  30. package/dist/cli/components/ModeIndicator.d.ts +42 -0
  31. package/dist/cli/components/ModeIndicator.d.ts.map +1 -0
  32. package/dist/cli/components/ModeIndicator.js +52 -0
  33. package/dist/cli/components/ModeIndicator.js.map +1 -0
  34. package/dist/cli/components/ModelSelector.d.ts +4 -3
  35. package/dist/cli/components/ModelSelector.d.ts.map +1 -1
  36. package/dist/cli/components/ModelSelector.js +54 -37
  37. package/dist/cli/components/ModelSelector.js.map +1 -1
  38. package/dist/cli/components/PlanApproval.d.ts +36 -0
  39. package/dist/cli/components/PlanApproval.d.ts.map +1 -0
  40. package/dist/cli/components/PlanApproval.js +154 -0
  41. package/dist/cli/components/PlanApproval.js.map +1 -0
  42. package/dist/cli/components/ProviderManager.d.ts +2 -2
  43. package/dist/cli/components/ProviderManager.d.ts.map +1 -1
  44. package/dist/cli/components/ProviderManager.js +137 -156
  45. package/dist/cli/components/ProviderManager.js.map +1 -1
  46. package/dist/cli/components/theme.d.ts +2 -0
  47. package/dist/cli/components/theme.d.ts.map +1 -1
  48. package/dist/cli/components/theme.js +3 -0
  49. package/dist/cli/components/theme.js.map +1 -1
  50. package/dist/cli/index.js +30 -13
  51. package/dist/cli/index.js.map +1 -1
  52. package/dist/config/index.d.ts +2 -2
  53. package/dist/config/index.d.ts.map +1 -1
  54. package/dist/config/index.js +1 -1
  55. package/dist/config/index.js.map +1 -1
  56. package/dist/config/levels.d.ts +5 -5
  57. package/dist/config/levels.d.ts.map +1 -1
  58. package/dist/config/levels.js +20 -20
  59. package/dist/config/levels.js.map +1 -1
  60. package/dist/config/merger.js +1 -1
  61. package/dist/config/merger.js.map +1 -1
  62. package/dist/config/providers-config.d.ts +8 -5
  63. package/dist/config/providers-config.d.ts.map +1 -1
  64. package/dist/config/providers-config.js +19 -22
  65. package/dist/config/providers-config.js.map +1 -1
  66. package/dist/config/test-utils.d.ts +2 -2
  67. package/dist/config/test-utils.d.ts.map +1 -1
  68. package/dist/config/test-utils.js +4 -4
  69. package/dist/config/test-utils.js.map +1 -1
  70. package/dist/config/types.d.ts +23 -17
  71. package/dist/config/types.d.ts.map +1 -1
  72. package/dist/config/types.js +14 -14
  73. package/dist/config/types.js.map +1 -1
  74. package/dist/index.d.ts +1 -0
  75. package/dist/index.d.ts.map +1 -1
  76. package/dist/index.js +2 -0
  77. package/dist/index.js.map +1 -1
  78. package/dist/memory/memory-manager.d.ts +25 -12
  79. package/dist/memory/memory-manager.d.ts.map +1 -1
  80. package/dist/memory/memory-manager.js +241 -112
  81. package/dist/memory/memory-manager.js.map +1 -1
  82. package/dist/memory/test-utils.d.ts +1 -1
  83. package/dist/memory/test-utils.d.ts.map +1 -1
  84. package/dist/memory/test-utils.js +3 -3
  85. package/dist/memory/test-utils.js.map +1 -1
  86. package/dist/memory/types.d.ts +20 -10
  87. package/dist/memory/types.d.ts.map +1 -1
  88. package/dist/memory/types.js +13 -13
  89. package/dist/memory/types.js.map +1 -1
  90. package/dist/migration/migrate.d.ts +24 -0
  91. package/dist/migration/migrate.d.ts.map +1 -0
  92. package/dist/migration/migrate.js +164 -0
  93. package/dist/migration/migrate.js.map +1 -0
  94. package/dist/permissions/persistence.d.ts +2 -2
  95. package/dist/permissions/persistence.js +4 -4
  96. package/dist/permissions/persistence.js.map +1 -1
  97. package/dist/planning/index.d.ts +13 -0
  98. package/dist/planning/index.d.ts.map +1 -0
  99. package/dist/planning/index.js +15 -0
  100. package/dist/planning/index.js.map +1 -0
  101. package/dist/planning/plan-file.d.ts +59 -0
  102. package/dist/planning/plan-file.d.ts.map +1 -0
  103. package/dist/planning/plan-file.js +278 -0
  104. package/dist/planning/plan-file.js.map +1 -0
  105. package/dist/planning/state.d.ts +127 -0
  106. package/dist/planning/state.d.ts.map +1 -0
  107. package/dist/planning/state.js +261 -0
  108. package/dist/planning/state.js.map +1 -0
  109. package/dist/planning/tools/enter-plan-mode.d.ts +25 -0
  110. package/dist/planning/tools/enter-plan-mode.d.ts.map +1 -0
  111. package/dist/planning/tools/enter-plan-mode.js +98 -0
  112. package/dist/planning/tools/enter-plan-mode.js.map +1 -0
  113. package/dist/planning/tools/exit-plan-mode.d.ts +24 -0
  114. package/dist/planning/tools/exit-plan-mode.d.ts.map +1 -0
  115. package/dist/planning/tools/exit-plan-mode.js +149 -0
  116. package/dist/planning/tools/exit-plan-mode.js.map +1 -0
  117. package/dist/planning/types.d.ts +100 -0
  118. package/dist/planning/types.d.ts.map +1 -0
  119. package/dist/planning/types.js +28 -0
  120. package/dist/planning/types.js.map +1 -0
  121. package/dist/pricing/calculator.d.ts +21 -0
  122. package/dist/pricing/calculator.d.ts.map +1 -0
  123. package/dist/pricing/calculator.js +59 -0
  124. package/dist/pricing/calculator.js.map +1 -0
  125. package/dist/pricing/index.d.ts +7 -0
  126. package/dist/pricing/index.d.ts.map +1 -0
  127. package/dist/pricing/index.js +7 -0
  128. package/dist/pricing/index.js.map +1 -0
  129. package/dist/pricing/models.d.ts +20 -0
  130. package/dist/pricing/models.d.ts.map +1 -0
  131. package/dist/pricing/models.js +322 -0
  132. package/dist/pricing/models.js.map +1 -0
  133. package/dist/pricing/types.d.ts +30 -0
  134. package/dist/pricing/types.d.ts.map +1 -0
  135. package/dist/pricing/types.js +5 -0
  136. package/dist/pricing/types.js.map +1 -0
  137. package/dist/prompts/index.d.ts +5 -4
  138. package/dist/prompts/index.d.ts.map +1 -1
  139. package/dist/prompts/index.js +11 -8
  140. package/dist/prompts/index.js.map +1 -1
  141. package/dist/providers/anthropic.d.ts +2 -1
  142. package/dist/providers/anthropic.d.ts.map +1 -1
  143. package/dist/providers/anthropic.js +24 -10
  144. package/dist/providers/anthropic.js.map +1 -1
  145. package/dist/providers/gemini.d.ts +2 -1
  146. package/dist/providers/gemini.d.ts.map +1 -1
  147. package/dist/providers/gemini.js +28 -14
  148. package/dist/providers/gemini.js.map +1 -1
  149. package/dist/providers/index.d.ts +20 -10
  150. package/dist/providers/index.d.ts.map +1 -1
  151. package/dist/providers/index.js +48 -24
  152. package/dist/providers/index.js.map +1 -1
  153. package/dist/providers/openai.d.ts +2 -1
  154. package/dist/providers/openai.d.ts.map +1 -1
  155. package/dist/providers/openai.js +19 -8
  156. package/dist/providers/openai.js.map +1 -1
  157. package/dist/providers/registry.d.ts +48 -34
  158. package/dist/providers/registry.d.ts.map +1 -1
  159. package/dist/providers/registry.js +72 -88
  160. package/dist/providers/registry.js.map +1 -1
  161. package/dist/providers/store.d.ts +43 -17
  162. package/dist/providers/store.d.ts.map +1 -1
  163. package/dist/providers/store.js +112 -19
  164. package/dist/providers/store.js.map +1 -1
  165. package/dist/providers/types.d.ts +25 -0
  166. package/dist/providers/types.d.ts.map +1 -1
  167. package/dist/providers/vertex-ai.d.ts +15 -7
  168. package/dist/providers/vertex-ai.d.ts.map +1 -1
  169. package/dist/providers/vertex-ai.js +63 -23
  170. package/dist/providers/vertex-ai.js.map +1 -1
  171. package/dist/session/manager.d.ts +4 -0
  172. package/dist/session/manager.d.ts.map +1 -1
  173. package/dist/session/manager.js +8 -0
  174. package/dist/session/manager.js.map +1 -1
  175. package/dist/session/types.js +1 -1
  176. package/dist/session/types.js.map +1 -1
  177. package/dist/tools/index.d.ts +7 -1
  178. package/dist/tools/index.d.ts.map +1 -1
  179. package/dist/tools/index.js +7 -0
  180. package/dist/tools/index.js.map +1 -1
  181. package/dist/tools/registry.d.ts +13 -0
  182. package/dist/tools/registry.d.ts.map +1 -1
  183. package/dist/tools/registry.js +79 -2
  184. package/dist/tools/registry.js.map +1 -1
  185. package/docs/config-system-comparison.md +50 -50
  186. package/docs/cost-tracking-comparison.md +904 -0
  187. package/docs/memory-system.md +124 -31
  188. package/docs/operating-modes.md +96 -0
  189. package/docs/permissions.md +2 -2
  190. package/docs/proposals/0006-memory-system.md +4 -4
  191. package/docs/proposals/0008-checkpointing.md +109 -2
  192. package/docs/proposals/0011-custom-commands.md +2 -1
  193. package/docs/proposals/0021-skills-system.md +2 -1
  194. package/docs/proposals/0023-permission-enhancements.md +2 -2
  195. package/docs/proposals/0025-cost-tracking.md +60 -2
  196. package/docs/proposals/0033-enterprise-deployment.md +1 -1
  197. package/docs/proposals/0041-configuration-system.md +17 -19
  198. package/docs/proposals/0042-prompt-optimization.md +17 -9
  199. package/docs/proposals/README.md +6 -6
  200. package/docs/providers.md +94 -9
  201. package/examples/test-checkpointing.ts +121 -0
  202. package/examples/test-cost-tracking.ts +77 -0
  203. package/examples/test-interrupt-cleanup.ts +94 -0
  204. package/package.json +3 -2
  205. package/scripts/migrate.ts +449 -0
  206. package/src/agent/agent.ts +161 -12
  207. package/src/agent/types.ts +11 -1
  208. package/src/checkpointing/checkpoint-manager.ts +327 -0
  209. package/src/checkpointing/index.ts +45 -0
  210. package/src/checkpointing/types.ts +104 -0
  211. package/src/cli/components/App.tsx +221 -13
  212. package/src/cli/components/CommandSuggestions.tsx +5 -0
  213. package/src/cli/components/Messages.tsx +24 -5
  214. package/src/cli/components/ModeIndicator.tsx +174 -0
  215. package/src/cli/components/ModelSelector.tsx +62 -43
  216. package/src/cli/components/PlanApproval.tsx +327 -0
  217. package/src/cli/components/ProviderManager.tsx +278 -323
  218. package/src/cli/components/theme.ts +3 -0
  219. package/src/cli/index.tsx +36 -17
  220. package/src/config/index.ts +5 -3
  221. package/src/config/levels.test.ts +22 -22
  222. package/src/config/levels.ts +22 -22
  223. package/src/config/loader.test.ts +14 -14
  224. package/src/config/manager.test.ts +19 -19
  225. package/src/config/merger.test.ts +23 -23
  226. package/src/config/merger.ts +1 -1
  227. package/src/config/providers-config.ts +23 -21
  228. package/src/config/test-utils.ts +6 -6
  229. package/src/config/types.ts +30 -20
  230. package/src/index.ts +15 -0
  231. package/src/memory/memory-manager.test.ts +242 -24
  232. package/src/memory/memory-manager.ts +270 -141
  233. package/src/memory/test-utils.ts +4 -4
  234. package/src/memory/types.ts +28 -17
  235. package/src/permissions/persistence.ts +4 -4
  236. package/src/planning/index.ts +53 -0
  237. package/src/planning/plan-file.ts +326 -0
  238. package/src/planning/state.ts +305 -0
  239. package/src/planning/tools/enter-plan-mode.ts +111 -0
  240. package/src/planning/tools/exit-plan-mode.ts +170 -0
  241. package/src/planning/types.ts +150 -0
  242. package/src/pricing/calculator.ts +71 -0
  243. package/src/pricing/index.ts +7 -0
  244. package/src/pricing/models.ts +334 -0
  245. package/src/pricing/types.ts +32 -0
  246. package/src/prompts/index.ts +13 -9
  247. package/src/providers/anthropic.ts +30 -10
  248. package/src/providers/gemini.ts +34 -14
  249. package/src/providers/index.ts +76 -33
  250. package/src/providers/openai.ts +26 -8
  251. package/src/providers/registry.ts +116 -111
  252. package/src/providers/store.ts +130 -28
  253. package/src/providers/types.ts +36 -1
  254. package/src/providers/vertex-ai.ts +70 -23
  255. package/src/session/manager.ts +9 -0
  256. package/src/session/types.ts +1 -1
  257. package/src/tools/index.ts +8 -0
  258. package/src/tools/registry.ts +95 -2
  259. package/.gencode/settings.local.json +0 -7
  260. package/CLAUDE.md +0 -86
@@ -2,18 +2,18 @@
2
2
  * Memory Manager - Core memory system implementation
3
3
  *
4
4
  * Implements Claude Code compatible memory loading with merge semantics:
5
- * At each level, both .gencode and .claude directories are loaded.
6
- * Content from .gencode appears later in the context (higher priority for LLM).
5
+ * At each level, both .gen and .claude directories are loaded.
6
+ * Content from .gen appears later in the context (higher priority for LLM).
7
7
  *
8
8
  * Loading order within each level:
9
9
  * 1. .claude files first (lower priority - LLM sees earlier)
10
- * 2. .gencode files second (higher priority - LLM sees later)
10
+ * 2. .gen files second (higher priority - LLM sees later)
11
11
  *
12
12
  * Level loading order:
13
13
  * 1. Enterprise (system-wide managed, enforced)
14
- * 2. User (~/.gencode/ + ~/.claude/)
14
+ * 2. User (~/.gen/ + ~/.claude/)
15
15
  * 3. User Rules
16
- * 4. Extra (GENCODE_CONFIG_DIRS)
16
+ * 4. Extra (GEN_CONFIG)
17
17
  * 5. Project (recursive upward search)
18
18
  * 6. Project Rules
19
19
  * 7. Local (*.local.md files)
@@ -34,9 +34,18 @@ import type {
34
34
  MemoryLevel,
35
35
  MemoryNamespace,
36
36
  MemorySource,
37
+ MemoryMergeStrategy,
37
38
  } from './types.js';
38
39
  import { DEFAULT_MEMORY_CONFIG } from './types.js';
39
- import { getManagedPaths, GENCODE_CONFIG_DIRS_ENV } from '../config/types.js';
40
+ import { getManagedPaths, GEN_CONFIG_ENV } from '../config/types.js';
41
+
42
+ /**
43
+ * Result of loading files at a level with merge strategy
44
+ */
45
+ interface LevelLoadResult {
46
+ files: MemoryFile[];
47
+ skipped: string[];
48
+ }
40
49
 
41
50
  export class MemoryManager {
42
51
  private config: MemoryConfig;
@@ -53,11 +62,12 @@ export class MemoryManager {
53
62
  * Load all memory files for the given working directory
54
63
  */
55
64
  async load(options: MemoryLoadOptions): Promise<LoadedMemory> {
56
- const { cwd, currentFile } = options;
65
+ const { cwd, currentFile, strategy = 'fallback' } = options;
57
66
  const files: MemoryFile[] = [];
58
67
  const rules: MemoryRule[] = [];
59
68
  const errors: string[] = [];
60
69
  const sources: MemorySource[] = [];
70
+ const skippedFiles: string[] = [];
61
71
  let totalSize = 0;
62
72
 
63
73
  this.importResolver.reset();
@@ -65,8 +75,8 @@ export class MemoryManager {
65
75
  this.importResolver.setProjectRoot(projectRoot);
66
76
 
67
77
  // 1. Load enterprise memory (system-wide, enforced)
68
- const enterpriseFiles = await this.loadEnterpriseMemory();
69
- for (const file of enterpriseFiles) {
78
+ const enterpriseResult = await this.loadEnterpriseMemory(strategy);
79
+ for (const file of enterpriseResult.files) {
70
80
  files.push(file);
71
81
  totalSize += file.content.length;
72
82
  sources.push({
@@ -77,9 +87,11 @@ export class MemoryManager {
77
87
  size: file.content.length,
78
88
  });
79
89
  }
90
+ skippedFiles.push(...enterpriseResult.skipped);
80
91
 
81
- // 2. Load user-level memory (both claude and gencode)
82
- const userFiles = await this.loadUserMemory();
92
+ // 2. Load user-level memory (both claude and gen)
93
+ const userResult = await this.loadUserMemory(strategy);
94
+ const userFiles = userResult.files;
83
95
  for (const file of userFiles) {
84
96
  if (totalSize + file.content.length <= this.config.maxTotalSize) {
85
97
  files.push(file);
@@ -95,8 +107,9 @@ export class MemoryManager {
95
107
  errors.push(`Skipped ${file.path}: would exceed max total size`);
96
108
  }
97
109
  }
110
+ skippedFiles.push(...userResult.skipped);
98
111
 
99
- // 3. Load user-level rules (both claude and gencode)
112
+ // 3. Load user-level rules (both claude and gen)
100
113
  const userRules = await this.loadUserRules();
101
114
  for (const rule of userRules) {
102
115
  rules.push(rule);
@@ -110,7 +123,8 @@ export class MemoryManager {
110
123
  }
111
124
 
112
125
  // 4. Load extra config dirs memory
113
- const extraFiles = await this.loadExtraMemory();
126
+ const extraResult = await this.loadExtraMemory(strategy);
127
+ const extraFiles = extraResult.files;
114
128
  for (const file of extraFiles) {
115
129
  if (totalSize + file.content.length <= this.config.maxTotalSize) {
116
130
  files.push(file);
@@ -126,9 +140,11 @@ export class MemoryManager {
126
140
  errors.push(`Skipped ${file.path}: would exceed max total size`);
127
141
  }
128
142
  }
143
+ skippedFiles.push(...extraResult.skipped);
129
144
 
130
- // 5. Load project-level memory (both claude and gencode, recursive upward)
131
- const projectFiles = await this.loadProjectMemory(cwd, projectRoot);
145
+ // 5. Load project-level memory (both claude and gen, recursive upward)
146
+ const projectResult = await this.loadProjectMemory(cwd, projectRoot, strategy);
147
+ const projectFiles = projectResult.files;
132
148
  for (const file of projectFiles) {
133
149
  if (totalSize + file.content.length <= this.config.maxTotalSize) {
134
150
  files.push(file);
@@ -144,8 +160,9 @@ export class MemoryManager {
144
160
  errors.push(`Skipped ${file.path}: would exceed max total size`);
145
161
  }
146
162
  }
163
+ skippedFiles.push(...projectResult.skipped);
147
164
 
148
- // 6. Load project-level rules (both claude and gencode)
165
+ // 6. Load project-level rules (both claude and gen)
149
166
  const projectRules = await this.loadProjectRules(projectRoot);
150
167
  for (const rule of projectRules) {
151
168
  rules.push(rule);
@@ -158,8 +175,9 @@ export class MemoryManager {
158
175
  });
159
176
  }
160
177
 
161
- // 7. Load local memory (both claude and gencode)
162
- const localFiles = await this.loadLocalMemory(projectRoot);
178
+ // 7. Load local memory (both claude and gen)
179
+ const localResult = await this.loadLocalMemory(projectRoot, strategy);
180
+ const localFiles = localResult.files;
163
181
  for (const file of localFiles) {
164
182
  if (totalSize + file.content.length <= this.config.maxTotalSize) {
165
183
  files.push(file);
@@ -175,6 +193,7 @@ export class MemoryManager {
175
193
  errors.push(`Skipped ${file.path}: would exceed max total size`);
176
194
  }
177
195
  }
196
+ skippedFiles.push(...localResult.skipped);
178
197
 
179
198
  // Activate rules based on current file
180
199
  const activatedRules = activateRules(rules, currentFile);
@@ -189,6 +208,7 @@ export class MemoryManager {
189
208
  context,
190
209
  errors,
191
210
  sources,
211
+ skippedFiles,
192
212
  };
193
213
 
194
214
  return this.loadedMemory;
@@ -249,70 +269,125 @@ export class MemoryManager {
249
269
  'project-rules': 'project rules',
250
270
  local: 'local personal notes',
251
271
  };
252
- const namespaceLabel = namespace === 'gencode' ? 'gencode' : namespace === 'claude' ? 'claude' : 'extra';
272
+ const namespaceLabel = namespace === 'gen' ? 'gen' : namespace === 'claude' ? 'claude' : 'extra';
253
273
  return `${levelLabels[level]} - ${namespaceLabel}`;
254
274
  }
255
275
 
256
276
  /**
257
- * Load enterprise-level memory files
277
+ * Apply merge strategy to decide which files to load
278
+ * Returns the files to load and the files to skip
258
279
  */
259
- private async loadEnterpriseMemory(): Promise<MemoryFile[]> {
280
+ private async applyMergeStrategy(
281
+ claudeFilePath: string,
282
+ genFilePath: string,
283
+ level: MemoryLevel,
284
+ strategy: MemoryMergeStrategy
285
+ ): Promise<LevelLoadResult> {
260
286
  const files: MemoryFile[] = [];
261
- const managedPaths = getManagedPaths();
287
+ const skipped: string[] = [];
288
+
289
+ switch (strategy) {
290
+ case 'fallback': {
291
+ // Try gen first, fallback to claude
292
+ const genFile = await this.loadFile(genFilePath, level, 'gen');
293
+ if (genFile) {
294
+ files.push(genFile);
295
+ // Only skip claude file if it exists
296
+ const claudeExists = await this.fileExists(claudeFilePath);
297
+ if (claudeExists) {
298
+ skipped.push(claudeFilePath);
299
+ }
300
+ } else {
301
+ const claudeFile = await this.loadFile(claudeFilePath, level, 'claude');
302
+ if (claudeFile) {
303
+ files.push(claudeFile);
304
+ }
305
+ }
306
+ break;
307
+ }
308
+ case 'both': {
309
+ // Load both (claude first for lower priority)
310
+ const claudeFile = await this.loadFile(claudeFilePath, level, 'claude');
311
+ if (claudeFile) files.push(claudeFile);
262
312
 
263
- // Load Claude first (lower priority)
264
- const claudeFile = await this.loadFile(
265
- path.join(managedPaths.claude, this.config.claudeFilename),
266
- 'enterprise',
267
- 'claude'
268
- );
269
- if (claudeFile) {
270
- claudeFile.enforced = true;
271
- files.push(claudeFile);
313
+ const genFile = await this.loadFile(genFilePath, level, 'gen');
314
+ if (genFile) files.push(genFile);
315
+ break;
316
+ }
317
+ case 'gen-only': {
318
+ // Only load gen
319
+ const genFile = await this.loadFile(genFilePath, level, 'gen');
320
+ if (genFile) {
321
+ files.push(genFile);
322
+ }
323
+ // Only mark as skipped if claude file exists
324
+ const claudeExists = await this.fileExists(claudeFilePath);
325
+ if (claudeExists) {
326
+ skipped.push(claudeFilePath);
327
+ }
328
+ break;
329
+ }
330
+ case 'claude-only': {
331
+ // Only load claude
332
+ const claudeFile = await this.loadFile(claudeFilePath, level, 'claude');
333
+ if (claudeFile) {
334
+ files.push(claudeFile);
335
+ }
336
+ // Only mark as skipped if gen file exists
337
+ const genExists = await this.fileExists(genFilePath);
338
+ if (genExists) {
339
+ skipped.push(genFilePath);
340
+ }
341
+ break;
342
+ }
272
343
  }
273
344
 
274
- // Load GenCode second (higher priority)
275
- const gencodeFile = await this.loadFile(
276
- path.join(managedPaths.gencode, this.config.gencodeFilename),
277
- 'enterprise',
278
- 'gencode'
279
- );
280
- if (gencodeFile) {
281
- gencodeFile.enforced = true;
282
- files.push(gencodeFile);
283
- }
345
+ return { files, skipped };
346
+ }
284
347
 
285
- return files;
348
+ /**
349
+ * Check if a file exists
350
+ */
351
+ private async fileExists(filePath: string): Promise<boolean> {
352
+ try {
353
+ await fs.stat(filePath);
354
+ return true;
355
+ } catch {
356
+ return false;
357
+ }
286
358
  }
287
359
 
288
360
  /**
289
- * Load user-level memory files (both claude and gencode)
361
+ * Load enterprise-level memory files
290
362
  */
291
- private async loadUserMemory(): Promise<MemoryFile[]> {
292
- const home = os.homedir();
293
- const files: MemoryFile[] = [];
363
+ private async loadEnterpriseMemory(strategy: MemoryMergeStrategy): Promise<LevelLoadResult> {
364
+ const managedPaths = getManagedPaths();
365
+ const claudePath = path.join(managedPaths.claude, this.config.claudeFilename);
366
+ const genPath = path.join(managedPaths.gen, this.config.genFilename);
294
367
 
295
- // Load Claude first (lower priority)
296
- const claudeFile = await this.loadFile(
297
- path.join(home, this.config.claudeDir, this.config.claudeFilename),
298
- 'user',
299
- 'claude'
300
- );
301
- if (claudeFile) files.push(claudeFile);
368
+ const result = await this.applyMergeStrategy(claudePath, genPath, 'enterprise', strategy);
302
369
 
303
- // Load GenCode second (higher priority)
304
- const gencodeFile = await this.loadFile(
305
- path.join(home, this.config.gencodeDir, this.config.gencodeFilename),
306
- 'user',
307
- 'gencode'
308
- );
309
- if (gencodeFile) files.push(gencodeFile);
370
+ // Mark all enterprise files as enforced
371
+ for (const file of result.files) {
372
+ file.enforced = true;
373
+ }
310
374
 
311
- return files;
375
+ return result;
312
376
  }
313
377
 
314
378
  /**
315
- * Load user-level rules (both claude and gencode)
379
+ * Load user-level memory files (both claude and gen)
380
+ */
381
+ private async loadUserMemory(strategy: MemoryMergeStrategy): Promise<LevelLoadResult> {
382
+ const home = os.homedir();
383
+ const claudePath = path.join(home, this.config.claudeDir, this.config.claudeFilename);
384
+ const genPath = path.join(home, this.config.genDir, this.config.genFilename);
385
+
386
+ return await this.applyMergeStrategy(claudePath, genPath, 'user', strategy);
387
+ }
388
+
389
+ /**
390
+ * Load user-level rules (both claude and gen)
316
391
  */
317
392
  private async loadUserRules(): Promise<MemoryRule[]> {
318
393
  const home = os.homedir();
@@ -324,9 +399,9 @@ export class MemoryManager {
324
399
  rules.push(...claudeRules);
325
400
 
326
401
  // Load GenCode rules second (higher priority)
327
- const gencodeRulesDir = path.join(home, this.config.gencodeDir, this.config.rulesDir);
328
- const gencodeRules = await this.loadRulesFromDir(gencodeRulesDir, 'user-rules', 'gencode');
329
- rules.push(...gencodeRules);
402
+ const genRulesDir = path.join(home, this.config.genDir, this.config.rulesDir);
403
+ const genRules = await this.loadRulesFromDir(genRulesDir, 'user-rules', 'gen');
404
+ rules.push(...genRules);
330
405
 
331
406
  return rules;
332
407
  }
@@ -334,36 +409,28 @@ export class MemoryManager {
334
409
  /**
335
410
  * Load extra config dirs memory
336
411
  */
337
- private async loadExtraMemory(): Promise<MemoryFile[]> {
412
+ private async loadExtraMemory(strategy: MemoryMergeStrategy): Promise<LevelLoadResult> {
338
413
  const extraDirs = this.parseExtraConfigDirs();
339
414
  const files: MemoryFile[] = [];
415
+ const skipped: string[] = [];
340
416
 
341
417
  for (const dir of extraDirs) {
342
- // Try CLAUDE.md
343
- const claudeFile = await this.loadFile(
344
- path.join(dir, this.config.claudeFilename),
345
- 'extra',
346
- 'extra'
347
- );
348
- if (claudeFile) files.push(claudeFile);
349
-
350
- // Try AGENT.md
351
- const gencodeFile = await this.loadFile(
352
- path.join(dir, this.config.gencodeFilename),
353
- 'extra',
354
- 'extra'
355
- );
356
- if (gencodeFile) files.push(gencodeFile);
357
- }
358
-
359
- return files;
418
+ const claudePath = path.join(dir, this.config.claudeFilename);
419
+ const genPath = path.join(dir, this.config.genFilename);
420
+ const result = await this.applyMergeStrategy(claudePath, genPath, 'extra', strategy);
421
+
422
+ files.push(...result.files);
423
+ skipped.push(...result.skipped);
424
+ }
425
+
426
+ return { files, skipped };
360
427
  }
361
428
 
362
429
  /**
363
- * Parse GENCODE_CONFIG_DIRS environment variable
430
+ * Parse GEN_CONFIG environment variable
364
431
  */
365
432
  private parseExtraConfigDirs(): string[] {
366
- const value = process.env[GENCODE_CONFIG_DIRS_ENV];
433
+ const value = process.env[GEN_CONFIG_ENV];
367
434
  if (!value) return [];
368
435
 
369
436
  return value
@@ -374,44 +441,50 @@ export class MemoryManager {
374
441
  }
375
442
 
376
443
  /**
377
- * Load project-level memory files (both claude and gencode)
444
+ * Load project-level memory files (both claude and gen)
378
445
  */
379
- private async loadProjectMemory(cwd: string, projectRoot: string): Promise<MemoryFile[]> {
380
- const files: MemoryFile[] = [];
381
-
382
- // Load from project root - Claude files first
446
+ private async loadProjectMemory(
447
+ cwd: string,
448
+ projectRoot: string,
449
+ strategy: MemoryMergeStrategy
450
+ ): Promise<LevelLoadResult> {
451
+ // Find first existing claude file
383
452
  const claudeCandidates = [
384
453
  path.join(projectRoot, this.config.claudeFilename),
385
454
  path.join(projectRoot, this.config.claudeDir, this.config.claudeFilename),
386
455
  ];
387
-
388
- for (const filePath of claudeCandidates) {
389
- const file = await this.loadFile(filePath, 'project', 'claude');
390
- if (file) {
391
- files.push(file);
392
- break; // Only load one claude file
456
+ let claudePath = claudeCandidates[0]; // Default for skipped tracking
457
+ for (const candidate of claudeCandidates) {
458
+ try {
459
+ await fs.stat(candidate);
460
+ claudePath = candidate;
461
+ break;
462
+ } catch {
463
+ continue;
393
464
  }
394
465
  }
395
466
 
396
- // Load from project root - GenCode files second
397
- const gencodeCandidates = [
398
- path.join(projectRoot, this.config.gencodeFilename),
399
- path.join(projectRoot, this.config.gencodeDir, this.config.gencodeFilename),
467
+ // Find first existing gen file
468
+ const genCandidates = [
469
+ path.join(projectRoot, this.config.genFilename),
470
+ path.join(projectRoot, this.config.genDir, this.config.genFilename),
400
471
  ];
401
-
402
- for (const filePath of gencodeCandidates) {
403
- const file = await this.loadFile(filePath, 'project', 'gencode');
404
- if (file) {
405
- files.push(file);
406
- break; // Only load one gencode file
472
+ let genPath = genCandidates[0]; // Default for skipped tracking
473
+ for (const candidate of genCandidates) {
474
+ try {
475
+ await fs.stat(candidate);
476
+ genPath = candidate;
477
+ break;
478
+ } catch {
479
+ continue;
407
480
  }
408
481
  }
409
482
 
410
- return files;
483
+ return await this.applyMergeStrategy(claudePath, genPath, 'project', strategy);
411
484
  }
412
485
 
413
486
  /**
414
- * Load project-level rules (both claude and gencode)
487
+ * Load project-level rules (both claude and gen)
415
488
  */
416
489
  private async loadProjectRules(projectRoot: string): Promise<MemoryRule[]> {
417
490
  const rules: MemoryRule[] = [];
@@ -422,48 +495,53 @@ export class MemoryManager {
422
495
  rules.push(...claudeRules);
423
496
 
424
497
  // Load GenCode rules second (higher priority)
425
- const gencodeRulesDir = path.join(projectRoot, this.config.gencodeDir, this.config.rulesDir);
426
- const gencodeRules = await this.loadRulesFromDir(gencodeRulesDir, 'project-rules', 'gencode');
427
- rules.push(...gencodeRules);
498
+ const genRulesDir = path.join(projectRoot, this.config.genDir, this.config.rulesDir);
499
+ const genRules = await this.loadRulesFromDir(genRulesDir, 'project-rules', 'gen');
500
+ rules.push(...genRules);
428
501
 
429
502
  return rules;
430
503
  }
431
504
 
432
505
  /**
433
- * Load local memory files (both claude and gencode)
506
+ * Load local memory files (both claude and gen)
434
507
  */
435
- private async loadLocalMemory(projectRoot: string): Promise<MemoryFile[]> {
436
- const files: MemoryFile[] = [];
437
-
438
- // Load Claude local files first
508
+ private async loadLocalMemory(
509
+ projectRoot: string,
510
+ strategy: MemoryMergeStrategy
511
+ ): Promise<LevelLoadResult> {
512
+ // Find first existing claude local file
439
513
  const claudeCandidates = [
440
514
  path.join(projectRoot, this.config.claudeLocalFilename),
441
515
  path.join(projectRoot, this.config.claudeDir, this.config.claudeLocalFilename),
442
516
  ];
443
-
444
- for (const filePath of claudeCandidates) {
445
- const file = await this.loadFile(filePath, 'local', 'claude');
446
- if (file) {
447
- files.push(file);
517
+ let claudePath = claudeCandidates[0];
518
+ for (const candidate of claudeCandidates) {
519
+ try {
520
+ await fs.stat(candidate);
521
+ claudePath = candidate;
448
522
  break;
523
+ } catch {
524
+ continue;
449
525
  }
450
526
  }
451
527
 
452
- // Load GenCode local files second
453
- const gencodeCandidates = [
454
- path.join(projectRoot, this.config.gencodeLocalFilename),
455
- path.join(projectRoot, this.config.gencodeDir, this.config.gencodeLocalFilename),
528
+ // Find first existing gen local file
529
+ const genCandidates = [
530
+ path.join(projectRoot, this.config.genLocalFilename),
531
+ path.join(projectRoot, this.config.genDir, this.config.genLocalFilename),
456
532
  ];
457
-
458
- for (const filePath of gencodeCandidates) {
459
- const file = await this.loadFile(filePath, 'local', 'gencode');
460
- if (file) {
461
- files.push(file);
533
+ let genPath = genCandidates[0];
534
+ for (const candidate of genCandidates) {
535
+ try {
536
+ await fs.stat(candidate);
537
+ genPath = candidate;
462
538
  break;
539
+ } catch {
540
+ continue;
463
541
  }
464
542
  }
465
543
 
466
- return files;
544
+ return await this.applyMergeStrategy(claudePath, genPath, 'local', strategy);
467
545
  }
468
546
 
469
547
  /**
@@ -568,12 +646,12 @@ export class MemoryManager {
568
646
  const home = os.homedir();
569
647
 
570
648
  if (level === 'user') {
571
- const dir = path.join(home, this.config.gencodeDir);
649
+ const dir = path.join(home, this.config.genDir);
572
650
  await fs.mkdir(dir, { recursive: true });
573
- filePath = path.join(dir, this.config.gencodeFilename);
651
+ filePath = path.join(dir, this.config.genFilename);
574
652
  } else {
575
653
  const projectRoot = await this.findProjectRoot(cwd);
576
- filePath = path.join(projectRoot, this.config.gencodeFilename);
654
+ filePath = path.join(projectRoot, this.config.genFilename);
577
655
  }
578
656
 
579
657
  // Read existing content
@@ -582,7 +660,7 @@ export class MemoryManager {
582
660
  existing = await fs.readFile(filePath, 'utf-8');
583
661
  } catch {
584
662
  // File doesn't exist, create with header
585
- existing = `# ${this.config.gencodeFilename.replace('.md', '')}\n\nThis file provides guidance when working with code in this repository.\n\n`;
663
+ existing = `# ${this.config.genFilename.replace('.md', '')}\n\nThis file provides guidance when working with code in this repository.\n\n`;
586
664
  }
587
665
 
588
666
  // Append new content
@@ -639,7 +717,7 @@ export class MemoryManager {
639
717
  * Get the path where /init would create a file
640
718
  */
641
719
  getInitFilePath(cwd: string): string {
642
- return path.join(cwd, this.config.gencodeFilename);
720
+ return path.join(cwd, this.config.genFilename);
643
721
  }
644
722
 
645
723
  /**
@@ -648,8 +726,8 @@ export class MemoryManager {
648
726
  async hasProjectMemory(cwd: string): Promise<boolean> {
649
727
  const projectRoot = await this.findProjectRoot(cwd);
650
728
  const candidates = [
651
- path.join(projectRoot, this.config.gencodeFilename),
652
- path.join(projectRoot, this.config.gencodeDir, this.config.gencodeFilename),
729
+ path.join(projectRoot, this.config.genFilename),
730
+ path.join(projectRoot, this.config.genDir, this.config.genFilename),
653
731
  path.join(projectRoot, this.config.claudeFilename),
654
732
  path.join(projectRoot, this.config.claudeDir, this.config.claudeFilename),
655
733
  ];
@@ -672,8 +750,8 @@ export class MemoryManager {
672
750
  async getExistingProjectMemoryPath(cwd: string): Promise<string | null> {
673
751
  const projectRoot = await this.findProjectRoot(cwd);
674
752
  const candidates = [
675
- path.join(projectRoot, this.config.gencodeFilename),
676
- path.join(projectRoot, this.config.gencodeDir, this.config.gencodeFilename),
753
+ path.join(projectRoot, this.config.genFilename),
754
+ path.join(projectRoot, this.config.genDir, this.config.genFilename),
677
755
  path.join(projectRoot, this.config.claudeFilename),
678
756
  path.join(projectRoot, this.config.claudeDir, this.config.claudeFilename),
679
757
  ];
@@ -713,4 +791,55 @@ export class MemoryManager {
713
791
 
714
792
  return lines.join('\n');
715
793
  }
794
+
795
+ /**
796
+ * Get verbose loading summary with strategy info
797
+ */
798
+ getVerboseSummary(strategy: MemoryMergeStrategy): string {
799
+ if (!this.loadedMemory) return 'Memory not loaded';
800
+
801
+ const lines: string[] = [];
802
+ const kbLoaded = (this.loadedMemory.totalSize / 1024).toFixed(1);
803
+
804
+ lines.push(`[Memory] Strategy: ${strategy}`);
805
+
806
+ // Group sources by level
807
+ const byLevel = new Map<string, typeof this.loadedMemory.sources>();
808
+ for (const source of this.loadedMemory.sources) {
809
+ const key = source.level;
810
+ if (!byLevel.has(key)) {
811
+ byLevel.set(key, []);
812
+ }
813
+ byLevel.get(key)!.push(source);
814
+ }
815
+
816
+ // Show what was loaded per level
817
+ for (const [level, sources] of byLevel) {
818
+ for (const source of sources) {
819
+ const sizeKb = (source.size / 1024).toFixed(1);
820
+ const marker = source.level === 'enterprise' ? ' [enforced]' : '';
821
+ lines.push(`[Memory] ${level}: ${source.path} (${sizeKb} KB)${marker}`);
822
+ }
823
+ }
824
+
825
+ // Show what was skipped
826
+ if (this.loadedMemory.skippedFiles.length > 0) {
827
+ for (const skipped of this.loadedMemory.skippedFiles) {
828
+ lines.push(`[Memory] Skipped: ${skipped}`);
829
+ }
830
+ }
831
+
832
+ lines.push(
833
+ `[Memory] Total: ${kbLoaded} KB (${this.loadedMemory.files.length} files loaded, ${this.loadedMemory.skippedFiles.length} skipped)`
834
+ );
835
+
836
+ if (this.loadedMemory.errors.length > 0) {
837
+ lines.push('[Memory] Errors:');
838
+ for (const error of this.loadedMemory.errors) {
839
+ lines.push(` - ${error}`);
840
+ }
841
+ }
842
+
843
+ return lines.join('\n');
844
+ }
716
845
  }
@@ -27,7 +27,7 @@ export async function createTestProject(prefix = 'gencode-test-'): Promise<TestP
27
27
  projectDir,
28
28
  cleanup: async () => {
29
29
  await fs.rm(tempDir, { recursive: true, force: true });
30
- delete process.env.GENCODE_CONFIG_DIRS;
30
+ delete process.env.GEN_CONFIG;
31
31
  },
32
32
  };
33
33
  }
@@ -37,18 +37,18 @@ export async function createTestProject(prefix = 'gencode-test-'): Promise<TestP
37
37
  */
38
38
  export async function writeMemory(
39
39
  projectDir: string,
40
- namespace: 'claude' | 'gencode',
40
+ namespace: 'claude' | 'gen',
41
41
  content: string,
42
42
  options: { local?: boolean; inDir?: boolean } = {}
43
43
  ): Promise<string> {
44
44
  const { local = false, inDir = true } = options;
45
45
  const filename = namespace === 'claude'
46
46
  ? (local ? 'CLAUDE.local.md' : 'CLAUDE.md')
47
- : (local ? 'AGENT.local.md' : 'AGENT.md');
47
+ : (local ? 'GEN.local.md' : 'GEN.md');
48
48
 
49
49
  let filePath: string;
50
50
  if (inDir) {
51
- const dir = path.join(projectDir, namespace === 'claude' ? '.claude' : '.gencode');
51
+ const dir = path.join(projectDir, namespace === 'claude' ? '.claude' : '.gen');
52
52
  await fs.mkdir(dir, { recursive: true });
53
53
  filePath = path.join(dir, filename);
54
54
  } else {