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.
- package/README.md +2 -1
- package/dist/agent/agent.d.ts +44 -2
- package/dist/agent/agent.d.ts.map +1 -1
- package/dist/agent/agent.js +130 -11
- package/dist/agent/agent.js.map +1 -1
- package/dist/agent/types.d.ts +11 -1
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/checkpointing/checkpoint-manager.d.ts +87 -0
- package/dist/checkpointing/checkpoint-manager.d.ts.map +1 -0
- package/dist/checkpointing/checkpoint-manager.js +281 -0
- package/dist/checkpointing/checkpoint-manager.js.map +1 -0
- package/dist/checkpointing/index.d.ts +29 -0
- package/dist/checkpointing/index.d.ts.map +1 -0
- package/dist/checkpointing/index.js +29 -0
- package/dist/checkpointing/index.js.map +1 -0
- package/dist/checkpointing/types.d.ts +98 -0
- package/dist/checkpointing/types.d.ts.map +1 -0
- package/dist/checkpointing/types.js +7 -0
- package/dist/checkpointing/types.js.map +1 -0
- package/dist/cli/components/App.d.ts.map +1 -1
- package/dist/cli/components/App.js +171 -14
- package/dist/cli/components/App.js.map +1 -1
- package/dist/cli/components/CommandSuggestions.d.ts.map +1 -1
- package/dist/cli/components/CommandSuggestions.js +5 -0
- package/dist/cli/components/CommandSuggestions.js.map +1 -1
- package/dist/cli/components/Messages.d.ts +7 -1
- package/dist/cli/components/Messages.d.ts.map +1 -1
- package/dist/cli/components/Messages.js +12 -3
- package/dist/cli/components/Messages.js.map +1 -1
- package/dist/cli/components/ModeIndicator.d.ts +42 -0
- package/dist/cli/components/ModeIndicator.d.ts.map +1 -0
- package/dist/cli/components/ModeIndicator.js +52 -0
- package/dist/cli/components/ModeIndicator.js.map +1 -0
- package/dist/cli/components/ModelSelector.d.ts +4 -3
- package/dist/cli/components/ModelSelector.d.ts.map +1 -1
- package/dist/cli/components/ModelSelector.js +54 -37
- package/dist/cli/components/ModelSelector.js.map +1 -1
- package/dist/cli/components/PlanApproval.d.ts +36 -0
- package/dist/cli/components/PlanApproval.d.ts.map +1 -0
- package/dist/cli/components/PlanApproval.js +154 -0
- package/dist/cli/components/PlanApproval.js.map +1 -0
- package/dist/cli/components/ProviderManager.d.ts +2 -2
- package/dist/cli/components/ProviderManager.d.ts.map +1 -1
- package/dist/cli/components/ProviderManager.js +137 -156
- package/dist/cli/components/ProviderManager.js.map +1 -1
- package/dist/cli/components/theme.d.ts +2 -0
- package/dist/cli/components/theme.d.ts.map +1 -1
- package/dist/cli/components/theme.js +3 -0
- package/dist/cli/components/theme.js.map +1 -1
- package/dist/cli/index.js +30 -13
- package/dist/cli/index.js.map +1 -1
- package/dist/config/index.d.ts +2 -2
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +1 -1
- package/dist/config/index.js.map +1 -1
- package/dist/config/levels.d.ts +5 -5
- package/dist/config/levels.d.ts.map +1 -1
- package/dist/config/levels.js +20 -20
- package/dist/config/levels.js.map +1 -1
- package/dist/config/merger.js +1 -1
- package/dist/config/merger.js.map +1 -1
- package/dist/config/providers-config.d.ts +8 -5
- package/dist/config/providers-config.d.ts.map +1 -1
- package/dist/config/providers-config.js +19 -22
- package/dist/config/providers-config.js.map +1 -1
- package/dist/config/test-utils.d.ts +2 -2
- package/dist/config/test-utils.d.ts.map +1 -1
- package/dist/config/test-utils.js +4 -4
- package/dist/config/test-utils.js.map +1 -1
- package/dist/config/types.d.ts +23 -17
- package/dist/config/types.d.ts.map +1 -1
- package/dist/config/types.js +14 -14
- package/dist/config/types.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/memory/memory-manager.d.ts +25 -12
- package/dist/memory/memory-manager.d.ts.map +1 -1
- package/dist/memory/memory-manager.js +241 -112
- package/dist/memory/memory-manager.js.map +1 -1
- package/dist/memory/test-utils.d.ts +1 -1
- package/dist/memory/test-utils.d.ts.map +1 -1
- package/dist/memory/test-utils.js +3 -3
- package/dist/memory/test-utils.js.map +1 -1
- package/dist/memory/types.d.ts +20 -10
- package/dist/memory/types.d.ts.map +1 -1
- package/dist/memory/types.js +13 -13
- package/dist/memory/types.js.map +1 -1
- package/dist/migration/migrate.d.ts +24 -0
- package/dist/migration/migrate.d.ts.map +1 -0
- package/dist/migration/migrate.js +164 -0
- package/dist/migration/migrate.js.map +1 -0
- package/dist/permissions/persistence.d.ts +2 -2
- package/dist/permissions/persistence.js +4 -4
- package/dist/permissions/persistence.js.map +1 -1
- package/dist/planning/index.d.ts +13 -0
- package/dist/planning/index.d.ts.map +1 -0
- package/dist/planning/index.js +15 -0
- package/dist/planning/index.js.map +1 -0
- package/dist/planning/plan-file.d.ts +59 -0
- package/dist/planning/plan-file.d.ts.map +1 -0
- package/dist/planning/plan-file.js +278 -0
- package/dist/planning/plan-file.js.map +1 -0
- package/dist/planning/state.d.ts +127 -0
- package/dist/planning/state.d.ts.map +1 -0
- package/dist/planning/state.js +261 -0
- package/dist/planning/state.js.map +1 -0
- package/dist/planning/tools/enter-plan-mode.d.ts +25 -0
- package/dist/planning/tools/enter-plan-mode.d.ts.map +1 -0
- package/dist/planning/tools/enter-plan-mode.js +98 -0
- package/dist/planning/tools/enter-plan-mode.js.map +1 -0
- package/dist/planning/tools/exit-plan-mode.d.ts +24 -0
- package/dist/planning/tools/exit-plan-mode.d.ts.map +1 -0
- package/dist/planning/tools/exit-plan-mode.js +149 -0
- package/dist/planning/tools/exit-plan-mode.js.map +1 -0
- package/dist/planning/types.d.ts +100 -0
- package/dist/planning/types.d.ts.map +1 -0
- package/dist/planning/types.js +28 -0
- package/dist/planning/types.js.map +1 -0
- package/dist/pricing/calculator.d.ts +21 -0
- package/dist/pricing/calculator.d.ts.map +1 -0
- package/dist/pricing/calculator.js +59 -0
- package/dist/pricing/calculator.js.map +1 -0
- package/dist/pricing/index.d.ts +7 -0
- package/dist/pricing/index.d.ts.map +1 -0
- package/dist/pricing/index.js +7 -0
- package/dist/pricing/index.js.map +1 -0
- package/dist/pricing/models.d.ts +20 -0
- package/dist/pricing/models.d.ts.map +1 -0
- package/dist/pricing/models.js +322 -0
- package/dist/pricing/models.js.map +1 -0
- package/dist/pricing/types.d.ts +30 -0
- package/dist/pricing/types.d.ts.map +1 -0
- package/dist/pricing/types.js +5 -0
- package/dist/pricing/types.js.map +1 -0
- package/dist/prompts/index.d.ts +5 -4
- package/dist/prompts/index.d.ts.map +1 -1
- package/dist/prompts/index.js +11 -8
- package/dist/prompts/index.js.map +1 -1
- package/dist/providers/anthropic.d.ts +2 -1
- package/dist/providers/anthropic.d.ts.map +1 -1
- package/dist/providers/anthropic.js +24 -10
- package/dist/providers/anthropic.js.map +1 -1
- package/dist/providers/gemini.d.ts +2 -1
- package/dist/providers/gemini.d.ts.map +1 -1
- package/dist/providers/gemini.js +28 -14
- package/dist/providers/gemini.js.map +1 -1
- package/dist/providers/index.d.ts +20 -10
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js +48 -24
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/openai.d.ts +2 -1
- package/dist/providers/openai.d.ts.map +1 -1
- package/dist/providers/openai.js +19 -8
- package/dist/providers/openai.js.map +1 -1
- package/dist/providers/registry.d.ts +48 -34
- package/dist/providers/registry.d.ts.map +1 -1
- package/dist/providers/registry.js +72 -88
- package/dist/providers/registry.js.map +1 -1
- package/dist/providers/store.d.ts +43 -17
- package/dist/providers/store.d.ts.map +1 -1
- package/dist/providers/store.js +112 -19
- package/dist/providers/store.js.map +1 -1
- package/dist/providers/types.d.ts +25 -0
- package/dist/providers/types.d.ts.map +1 -1
- package/dist/providers/vertex-ai.d.ts +15 -7
- package/dist/providers/vertex-ai.d.ts.map +1 -1
- package/dist/providers/vertex-ai.js +63 -23
- package/dist/providers/vertex-ai.js.map +1 -1
- package/dist/session/manager.d.ts +4 -0
- package/dist/session/manager.d.ts.map +1 -1
- package/dist/session/manager.js +8 -0
- package/dist/session/manager.js.map +1 -1
- package/dist/session/types.js +1 -1
- package/dist/session/types.js.map +1 -1
- package/dist/tools/index.d.ts +7 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +7 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/registry.d.ts +13 -0
- package/dist/tools/registry.d.ts.map +1 -1
- package/dist/tools/registry.js +79 -2
- package/dist/tools/registry.js.map +1 -1
- package/docs/config-system-comparison.md +50 -50
- package/docs/cost-tracking-comparison.md +904 -0
- package/docs/memory-system.md +124 -31
- package/docs/operating-modes.md +96 -0
- package/docs/permissions.md +2 -2
- package/docs/proposals/0006-memory-system.md +4 -4
- package/docs/proposals/0008-checkpointing.md +109 -2
- package/docs/proposals/0011-custom-commands.md +2 -1
- package/docs/proposals/0021-skills-system.md +2 -1
- package/docs/proposals/0023-permission-enhancements.md +2 -2
- package/docs/proposals/0025-cost-tracking.md +60 -2
- package/docs/proposals/0033-enterprise-deployment.md +1 -1
- package/docs/proposals/0041-configuration-system.md +17 -19
- package/docs/proposals/0042-prompt-optimization.md +17 -9
- package/docs/proposals/README.md +6 -6
- package/docs/providers.md +94 -9
- package/examples/test-checkpointing.ts +121 -0
- package/examples/test-cost-tracking.ts +77 -0
- package/examples/test-interrupt-cleanup.ts +94 -0
- package/package.json +3 -2
- package/scripts/migrate.ts +449 -0
- package/src/agent/agent.ts +161 -12
- package/src/agent/types.ts +11 -1
- package/src/checkpointing/checkpoint-manager.ts +327 -0
- package/src/checkpointing/index.ts +45 -0
- package/src/checkpointing/types.ts +104 -0
- package/src/cli/components/App.tsx +221 -13
- package/src/cli/components/CommandSuggestions.tsx +5 -0
- package/src/cli/components/Messages.tsx +24 -5
- package/src/cli/components/ModeIndicator.tsx +174 -0
- package/src/cli/components/ModelSelector.tsx +62 -43
- package/src/cli/components/PlanApproval.tsx +327 -0
- package/src/cli/components/ProviderManager.tsx +278 -323
- package/src/cli/components/theme.ts +3 -0
- package/src/cli/index.tsx +36 -17
- package/src/config/index.ts +5 -3
- package/src/config/levels.test.ts +22 -22
- package/src/config/levels.ts +22 -22
- package/src/config/loader.test.ts +14 -14
- package/src/config/manager.test.ts +19 -19
- package/src/config/merger.test.ts +23 -23
- package/src/config/merger.ts +1 -1
- package/src/config/providers-config.ts +23 -21
- package/src/config/test-utils.ts +6 -6
- package/src/config/types.ts +30 -20
- package/src/index.ts +15 -0
- package/src/memory/memory-manager.test.ts +242 -24
- package/src/memory/memory-manager.ts +270 -141
- package/src/memory/test-utils.ts +4 -4
- package/src/memory/types.ts +28 -17
- package/src/permissions/persistence.ts +4 -4
- package/src/planning/index.ts +53 -0
- package/src/planning/plan-file.ts +326 -0
- package/src/planning/state.ts +305 -0
- package/src/planning/tools/enter-plan-mode.ts +111 -0
- package/src/planning/tools/exit-plan-mode.ts +170 -0
- package/src/planning/types.ts +150 -0
- package/src/pricing/calculator.ts +71 -0
- package/src/pricing/index.ts +7 -0
- package/src/pricing/models.ts +334 -0
- package/src/pricing/types.ts +32 -0
- package/src/prompts/index.ts +13 -9
- package/src/providers/anthropic.ts +30 -10
- package/src/providers/gemini.ts +34 -14
- package/src/providers/index.ts +76 -33
- package/src/providers/openai.ts +26 -8
- package/src/providers/registry.ts +116 -111
- package/src/providers/store.ts +130 -28
- package/src/providers/types.ts +36 -1
- package/src/providers/vertex-ai.ts +70 -23
- package/src/session/manager.ts +9 -0
- package/src/session/types.ts +1 -1
- package/src/tools/index.ts +8 -0
- package/src/tools/registry.ts +95 -2
- package/.gencode/settings.local.json +0 -7
- 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 .
|
|
6
|
-
* Content from .
|
|
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. .
|
|
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 (~/.
|
|
14
|
+
* 2. User (~/.gen/ + ~/.claude/)
|
|
15
15
|
* 3. User Rules
|
|
16
|
-
* 4. Extra (
|
|
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,
|
|
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
|
|
69
|
-
for (const file of
|
|
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
|
|
82
|
-
const
|
|
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
|
|
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
|
|
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
|
|
131
|
-
const
|
|
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
|
|
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
|
|
162
|
-
const
|
|
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 === '
|
|
272
|
+
const namespaceLabel = namespace === 'gen' ? 'gen' : namespace === 'claude' ? 'claude' : 'extra';
|
|
253
273
|
return `${levelLabels[level]} - ${namespaceLabel}`;
|
|
254
274
|
}
|
|
255
275
|
|
|
256
276
|
/**
|
|
257
|
-
*
|
|
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
|
|
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
|
|
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
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
'
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
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
|
-
|
|
275
|
-
|
|
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
|
-
|
|
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
|
|
361
|
+
* Load enterprise-level memory files
|
|
290
362
|
*/
|
|
291
|
-
private async
|
|
292
|
-
const
|
|
293
|
-
const
|
|
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
|
-
|
|
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
|
-
//
|
|
304
|
-
const
|
|
305
|
-
|
|
306
|
-
|
|
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
|
|
375
|
+
return result;
|
|
312
376
|
}
|
|
313
377
|
|
|
314
378
|
/**
|
|
315
|
-
* Load user-level
|
|
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
|
|
328
|
-
const
|
|
329
|
-
rules.push(...
|
|
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<
|
|
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
|
-
|
|
343
|
-
const
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
);
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
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
|
|
430
|
+
* Parse GEN_CONFIG environment variable
|
|
364
431
|
*/
|
|
365
432
|
private parseExtraConfigDirs(): string[] {
|
|
366
|
-
const value = process.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
|
|
444
|
+
* Load project-level memory files (both claude and gen)
|
|
378
445
|
*/
|
|
379
|
-
private async loadProjectMemory(
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
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
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
break;
|
|
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
|
-
//
|
|
397
|
-
const
|
|
398
|
-
path.join(projectRoot, this.config.
|
|
399
|
-
path.join(projectRoot, this.config.
|
|
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
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
break;
|
|
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
|
|
483
|
+
return await this.applyMergeStrategy(claudePath, genPath, 'project', strategy);
|
|
411
484
|
}
|
|
412
485
|
|
|
413
486
|
/**
|
|
414
|
-
* Load project-level rules (both claude and
|
|
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
|
|
426
|
-
const
|
|
427
|
-
rules.push(...
|
|
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
|
|
506
|
+
* Load local memory files (both claude and gen)
|
|
434
507
|
*/
|
|
435
|
-
private async loadLocalMemory(
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
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
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
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
|
-
//
|
|
453
|
-
const
|
|
454
|
-
path.join(projectRoot, this.config.
|
|
455
|
-
path.join(projectRoot, this.config.
|
|
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
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
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
|
|
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.
|
|
649
|
+
const dir = path.join(home, this.config.genDir);
|
|
572
650
|
await fs.mkdir(dir, { recursive: true });
|
|
573
|
-
filePath = path.join(dir, this.config.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
652
|
-
path.join(projectRoot, this.config.
|
|
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.
|
|
676
|
-
path.join(projectRoot, this.config.
|
|
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
|
}
|
package/src/memory/test-utils.ts
CHANGED
|
@@ -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.
|
|
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' | '
|
|
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 ? '
|
|
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' : '.
|
|
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 {
|