gencode-ai 0.2.0 → 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 (150) hide show
  1. package/dist/agent/agent.d.ts +9 -2
  2. package/dist/agent/agent.d.ts.map +1 -1
  3. package/dist/agent/agent.js +37 -8
  4. package/dist/agent/agent.js.map +1 -1
  5. package/dist/agent/types.d.ts +5 -1
  6. package/dist/agent/types.d.ts.map +1 -1
  7. package/dist/cli/components/App.d.ts.map +1 -1
  8. package/dist/cli/components/App.js +15 -9
  9. package/dist/cli/components/App.js.map +1 -1
  10. package/dist/cli/components/Messages.js +1 -1
  11. package/dist/cli/components/Messages.js.map +1 -1
  12. package/dist/cli/components/ModelSelector.d.ts +4 -3
  13. package/dist/cli/components/ModelSelector.d.ts.map +1 -1
  14. package/dist/cli/components/ModelSelector.js +54 -37
  15. package/dist/cli/components/ModelSelector.js.map +1 -1
  16. package/dist/cli/components/ProviderManager.d.ts +2 -2
  17. package/dist/cli/components/ProviderManager.d.ts.map +1 -1
  18. package/dist/cli/components/ProviderManager.js +137 -156
  19. package/dist/cli/components/ProviderManager.js.map +1 -1
  20. package/dist/cli/index.js +30 -13
  21. package/dist/cli/index.js.map +1 -1
  22. package/dist/config/index.d.ts +2 -2
  23. package/dist/config/index.d.ts.map +1 -1
  24. package/dist/config/index.js +1 -1
  25. package/dist/config/index.js.map +1 -1
  26. package/dist/config/levels.d.ts +5 -5
  27. package/dist/config/levels.d.ts.map +1 -1
  28. package/dist/config/levels.js +20 -20
  29. package/dist/config/levels.js.map +1 -1
  30. package/dist/config/merger.js +1 -1
  31. package/dist/config/merger.js.map +1 -1
  32. package/dist/config/providers-config.d.ts +8 -5
  33. package/dist/config/providers-config.d.ts.map +1 -1
  34. package/dist/config/providers-config.js +19 -22
  35. package/dist/config/providers-config.js.map +1 -1
  36. package/dist/config/test-utils.d.ts +2 -2
  37. package/dist/config/test-utils.d.ts.map +1 -1
  38. package/dist/config/test-utils.js +4 -4
  39. package/dist/config/test-utils.js.map +1 -1
  40. package/dist/config/types.d.ts +23 -17
  41. package/dist/config/types.d.ts.map +1 -1
  42. package/dist/config/types.js +14 -14
  43. package/dist/config/types.js.map +1 -1
  44. package/dist/memory/memory-manager.d.ts +25 -12
  45. package/dist/memory/memory-manager.d.ts.map +1 -1
  46. package/dist/memory/memory-manager.js +241 -112
  47. package/dist/memory/memory-manager.js.map +1 -1
  48. package/dist/memory/test-utils.d.ts +1 -1
  49. package/dist/memory/test-utils.d.ts.map +1 -1
  50. package/dist/memory/test-utils.js +3 -3
  51. package/dist/memory/test-utils.js.map +1 -1
  52. package/dist/memory/types.d.ts +20 -10
  53. package/dist/memory/types.d.ts.map +1 -1
  54. package/dist/memory/types.js +13 -13
  55. package/dist/memory/types.js.map +1 -1
  56. package/dist/migration/migrate.d.ts +24 -0
  57. package/dist/migration/migrate.d.ts.map +1 -0
  58. package/dist/migration/migrate.js +164 -0
  59. package/dist/migration/migrate.js.map +1 -0
  60. package/dist/permissions/persistence.d.ts +2 -2
  61. package/dist/permissions/persistence.js +4 -4
  62. package/dist/permissions/persistence.js.map +1 -1
  63. package/dist/planning/plan-file.d.ts +1 -1
  64. package/dist/planning/plan-file.js +2 -2
  65. package/dist/planning/plan-file.js.map +1 -1
  66. package/dist/prompts/index.d.ts +5 -4
  67. package/dist/prompts/index.d.ts.map +1 -1
  68. package/dist/prompts/index.js +11 -8
  69. package/dist/prompts/index.js.map +1 -1
  70. package/dist/providers/anthropic.d.ts +2 -1
  71. package/dist/providers/anthropic.d.ts.map +1 -1
  72. package/dist/providers/anthropic.js +7 -0
  73. package/dist/providers/anthropic.js.map +1 -1
  74. package/dist/providers/gemini.d.ts +2 -1
  75. package/dist/providers/gemini.d.ts.map +1 -1
  76. package/dist/providers/gemini.js +7 -0
  77. package/dist/providers/gemini.js.map +1 -1
  78. package/dist/providers/index.d.ts +20 -10
  79. package/dist/providers/index.d.ts.map +1 -1
  80. package/dist/providers/index.js +48 -24
  81. package/dist/providers/index.js.map +1 -1
  82. package/dist/providers/openai.d.ts +2 -1
  83. package/dist/providers/openai.d.ts.map +1 -1
  84. package/dist/providers/openai.js +7 -0
  85. package/dist/providers/openai.js.map +1 -1
  86. package/dist/providers/registry.d.ts +48 -34
  87. package/dist/providers/registry.d.ts.map +1 -1
  88. package/dist/providers/registry.js +72 -88
  89. package/dist/providers/registry.js.map +1 -1
  90. package/dist/providers/store.d.ts +43 -17
  91. package/dist/providers/store.d.ts.map +1 -1
  92. package/dist/providers/store.js +112 -19
  93. package/dist/providers/store.js.map +1 -1
  94. package/dist/providers/types.d.ts +23 -0
  95. package/dist/providers/types.d.ts.map +1 -1
  96. package/dist/providers/vertex-ai.d.ts +15 -7
  97. package/dist/providers/vertex-ai.d.ts.map +1 -1
  98. package/dist/providers/vertex-ai.js +46 -13
  99. package/dist/providers/vertex-ai.js.map +1 -1
  100. package/dist/session/types.js +1 -1
  101. package/dist/session/types.js.map +1 -1
  102. package/docs/config-system-comparison.md +50 -50
  103. package/docs/cost-tracking-comparison.md +2 -2
  104. package/docs/memory-system.md +124 -31
  105. package/docs/permissions.md +2 -2
  106. package/docs/proposals/0006-memory-system.md +4 -4
  107. package/docs/proposals/0008-checkpointing.md +109 -2
  108. package/docs/proposals/0011-custom-commands.md +2 -1
  109. package/docs/proposals/0021-skills-system.md +2 -1
  110. package/docs/proposals/0023-permission-enhancements.md +2 -2
  111. package/docs/proposals/0033-enterprise-deployment.md +1 -1
  112. package/docs/proposals/0041-configuration-system.md +17 -19
  113. package/docs/proposals/0042-prompt-optimization.md +17 -9
  114. package/docs/proposals/README.md +5 -5
  115. package/docs/providers.md +94 -9
  116. package/package.json +3 -2
  117. package/scripts/migrate.ts +449 -0
  118. package/src/agent/agent.ts +51 -9
  119. package/src/agent/types.ts +5 -1
  120. package/src/cli/components/App.tsx +17 -8
  121. package/src/cli/components/Messages.tsx +1 -1
  122. package/src/cli/components/ModelSelector.tsx +62 -43
  123. package/src/cli/components/ProviderManager.tsx +278 -323
  124. package/src/cli/index.tsx +36 -17
  125. package/src/config/index.ts +5 -3
  126. package/src/config/levels.test.ts +22 -22
  127. package/src/config/levels.ts +22 -22
  128. package/src/config/loader.test.ts +14 -14
  129. package/src/config/manager.test.ts +19 -19
  130. package/src/config/merger.test.ts +23 -23
  131. package/src/config/merger.ts +1 -1
  132. package/src/config/providers-config.ts +23 -21
  133. package/src/config/test-utils.ts +6 -6
  134. package/src/config/types.ts +30 -20
  135. package/src/memory/memory-manager.test.ts +242 -24
  136. package/src/memory/memory-manager.ts +270 -141
  137. package/src/memory/test-utils.ts +4 -4
  138. package/src/memory/types.ts +28 -17
  139. package/src/permissions/persistence.ts +4 -4
  140. package/src/planning/plan-file.ts +2 -2
  141. package/src/prompts/index.ts +13 -9
  142. package/src/providers/anthropic.ts +9 -0
  143. package/src/providers/gemini.ts +9 -0
  144. package/src/providers/index.ts +76 -33
  145. package/src/providers/openai.ts +9 -0
  146. package/src/providers/registry.ts +116 -111
  147. package/src/providers/store.ts +130 -28
  148. package/src/providers/types.ts +33 -1
  149. package/src/providers/vertex-ai.ts +49 -13
  150. package/src/session/types.ts +1 -1
@@ -0,0 +1,449 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * Migration Script: .gencode → .gen
4
+ *
5
+ * Migrates GenCode configuration from old naming to new:
6
+ * - ~/.gencode/ → ~/.gen/
7
+ * - ./.gencode/ → ./.gen/
8
+ * - AGENT.md → GEN.md
9
+ * - AGENT.local.md → GEN.local.md
10
+ * - providers.json: Old format → New format (provider:authMethod keys)
11
+ *
12
+ * Usage:
13
+ * npm run migrate # Run migration
14
+ * tsx scripts/migrate.ts # Direct execution
15
+ */
16
+
17
+ import * as fs from 'fs/promises';
18
+ import * as path from 'path';
19
+ import * as os from 'os';
20
+ import * as readline from 'readline';
21
+
22
+ interface MigrationResult {
23
+ success: boolean;
24
+ migratedPaths: string[];
25
+ errors: string[];
26
+ warnings: string[];
27
+ }
28
+
29
+ /**
30
+ * Check if a path exists
31
+ */
32
+ async function pathExists(p: string): Promise<boolean> {
33
+ try {
34
+ await fs.access(p);
35
+ return true;
36
+ } catch {
37
+ return false;
38
+ }
39
+ }
40
+
41
+ /**
42
+ * Rename files within a directory (AGENT.md → GEN.md, AGENT.local.md → GEN.local.md)
43
+ */
44
+ async function renameFilesInDir(dir: string): Promise<string[]> {
45
+ const renamed: string[] = [];
46
+
47
+ // Rename AGENT.md → GEN.md
48
+ const agentPath = path.join(dir, 'AGENT.md');
49
+ const genPath = path.join(dir, 'GEN.md');
50
+
51
+ if (await pathExists(agentPath)) {
52
+ if (await pathExists(genPath)) {
53
+ console.log(` ⚠️ Skipping ${agentPath} (${genPath} already exists)`);
54
+ } else {
55
+ try {
56
+ await fs.rename(agentPath, genPath);
57
+ renamed.push(`${agentPath} → ${genPath}`);
58
+ } catch (error) {
59
+ throw new Error(`Failed to rename ${agentPath}: ${error instanceof Error ? error.message : String(error)}`);
60
+ }
61
+ }
62
+ }
63
+
64
+ // Rename AGENT.local.md → GEN.local.md
65
+ const agentLocalPath = path.join(dir, 'AGENT.local.md');
66
+ const genLocalPath = path.join(dir, 'GEN.local.md');
67
+
68
+ if (await pathExists(agentLocalPath)) {
69
+ if (await pathExists(genLocalPath)) {
70
+ console.log(` ⚠️ Skipping ${agentLocalPath} (${genLocalPath} already exists)`);
71
+ } else {
72
+ try {
73
+ await fs.rename(agentLocalPath, genLocalPath);
74
+ renamed.push(`${agentLocalPath} → ${genLocalPath}`);
75
+ } catch (error) {
76
+ throw new Error(`Failed to rename ${agentLocalPath}: ${error instanceof Error ? error.message : String(error)}`);
77
+ }
78
+ }
79
+ }
80
+
81
+ return renamed;
82
+ }
83
+
84
+ /**
85
+ * Migrate providers.json from old format to new format
86
+ * Old format: models[provider] = { provider, authMethod, cachedAt, list }
87
+ * New format: models["provider:authMethod"] = { cachedAt, list }
88
+ */
89
+ async function migrateProvidersJson(dryRun = false): Promise<MigrationResult> {
90
+ const result: MigrationResult = {
91
+ success: true,
92
+ migratedPaths: [],
93
+ errors: [],
94
+ warnings: [],
95
+ };
96
+
97
+ const providersPath = path.join(os.homedir(), '.gen', 'providers.json');
98
+
99
+ // Check if providers.json exists
100
+ if (!(await pathExists(providersPath))) {
101
+ return result; // Nothing to migrate
102
+ }
103
+
104
+ try {
105
+ // Read current config
106
+ const content = await fs.readFile(providersPath, 'utf-8');
107
+ const config = JSON.parse(content);
108
+
109
+ // Check if migration is needed
110
+ let needsMigration = false;
111
+ const newModels: Record<string, any> = {};
112
+
113
+ if (config.models) {
114
+ for (const [key, value] of Object.entries(config.models)) {
115
+ // Detect old format: key doesn't contain ':' AND value has provider/authMethod fields
116
+ if (
117
+ !key.includes(':') &&
118
+ typeof value === 'object' &&
119
+ value !== null &&
120
+ 'provider' in value &&
121
+ 'authMethod' in value
122
+ ) {
123
+ needsMigration = true;
124
+ const oldCache = value as any;
125
+ const newKey = `${oldCache.provider}:${oldCache.authMethod}`;
126
+ newModels[newKey] = {
127
+ cachedAt: oldCache.cachedAt,
128
+ list: oldCache.list,
129
+ };
130
+ } else {
131
+ // Already new format
132
+ newModels[key] = value;
133
+ }
134
+ }
135
+ }
136
+
137
+ if (!needsMigration) {
138
+ return result; // Already in new format
139
+ }
140
+
141
+ if (dryRun) {
142
+ result.migratedPaths.push(`[DRY RUN] providers.json: Old format → New format (provider:authMethod keys)`);
143
+ const oldKeys = Object.keys(config.models || {}).filter(k => !k.includes(':'));
144
+ const newKeys = Object.keys(newModels).filter(k => k.includes(':'));
145
+ result.migratedPaths.push(` Old keys: ${oldKeys.join(', ') || 'none'}`);
146
+ result.migratedPaths.push(` New keys: ${newKeys.join(', ') || 'none'}`);
147
+ } else {
148
+ // Backup old config
149
+ const backupPath = `${providersPath}.backup`;
150
+ await fs.copyFile(providersPath, backupPath);
151
+
152
+ // Update config with new format
153
+ config.models = newModels;
154
+
155
+ // Also update connections to ensure authMethod is set
156
+ if (config.connections) {
157
+ for (const [provider, connection] of Object.entries(config.connections)) {
158
+ if (typeof connection === 'object' && connection !== null && !('authMethod' in connection)) {
159
+ // Try to infer authMethod from connection method name
160
+ const method = (connection as any).method;
161
+ if (method?.includes('Vertex')) {
162
+ (connection as any).authMethod = 'vertex';
163
+ } else if (method?.includes('Bedrock')) {
164
+ (connection as any).authMethod = 'bedrock';
165
+ } else if (method?.includes('Azure')) {
166
+ (connection as any).authMethod = 'azure';
167
+ } else {
168
+ (connection as any).authMethod = 'api_key';
169
+ }
170
+ }
171
+ }
172
+ }
173
+
174
+ // Write new config
175
+ await fs.writeFile(providersPath, JSON.stringify(config, null, 2));
176
+
177
+ result.migratedPaths.push(`providers.json: Migrated to new format`);
178
+ result.migratedPaths.push(` Backup saved: ${backupPath}`);
179
+ }
180
+ } catch (error) {
181
+ result.errors.push(`Failed to migrate providers.json: ${error instanceof Error ? error.message : String(error)}`);
182
+ result.success = false;
183
+ }
184
+
185
+ return result;
186
+ }
187
+
188
+ /**
189
+ * Migrate .gencode to .gen
190
+ */
191
+ async function migrateToGen(dryRun = false): Promise<MigrationResult> {
192
+ const result: MigrationResult = {
193
+ success: true,
194
+ migratedPaths: [],
195
+ errors: [],
196
+ warnings: [],
197
+ };
198
+
199
+ // 1. Migrate user directory (~/.gencode → ~/.gen)
200
+ const homeGencodePath = path.join(os.homedir(), '.gencode');
201
+ const homeGenPath = path.join(os.homedir(), '.gen');
202
+
203
+ if (await pathExists(homeGencodePath)) {
204
+ if (await pathExists(homeGenPath)) {
205
+ result.errors.push(`~/.gen already exists! Please manually merge ~/.gencode into it.`);
206
+ result.success = false;
207
+ } else {
208
+ if (!dryRun) {
209
+ try {
210
+ await fs.rename(homeGencodePath, homeGenPath);
211
+ const renamedFiles = await renameFilesInDir(homeGenPath);
212
+ result.migratedPaths.push(`${homeGencodePath} → ${homeGenPath}`);
213
+ result.migratedPaths.push(...renamedFiles);
214
+ } catch (error) {
215
+ result.errors.push(`Failed to migrate ${homeGencodePath}: ${error instanceof Error ? error.message : String(error)}`);
216
+ result.success = false;
217
+ }
218
+ } else {
219
+ result.migratedPaths.push(`[DRY RUN] ${homeGencodePath} → ${homeGenPath}`);
220
+ result.migratedPaths.push(`[DRY RUN] Will rename AGENT.md → GEN.md in ${homeGenPath}`);
221
+ result.migratedPaths.push(`[DRY RUN] Will rename AGENT.local.md → GEN.local.md in ${homeGenPath}`);
222
+ }
223
+ }
224
+ }
225
+
226
+ // 2. Migrate project directory (./.gencode → ./.gen)
227
+ const cwd = process.cwd();
228
+ const projectGencodePath = path.join(cwd, '.gencode');
229
+ const projectGenPath = path.join(cwd, '.gen');
230
+
231
+ if (await pathExists(projectGencodePath)) {
232
+ if (await pathExists(projectGenPath)) {
233
+ result.errors.push(`./.gen already exists! Please manually merge ./.gencode into it.`);
234
+ result.success = false;
235
+ } else {
236
+ if (!dryRun) {
237
+ try {
238
+ await fs.rename(projectGencodePath, projectGenPath);
239
+ const renamedFiles = await renameFilesInDir(projectGenPath);
240
+ result.migratedPaths.push(`${projectGencodePath} → ${projectGenPath}`);
241
+ result.migratedPaths.push(...renamedFiles);
242
+ } catch (error) {
243
+ result.errors.push(`Failed to migrate ${projectGencodePath}: ${error instanceof Error ? error.message : String(error)}`);
244
+ result.success = false;
245
+ }
246
+ } else {
247
+ result.migratedPaths.push(`[DRY RUN] ${projectGencodePath} → ${projectGenPath}`);
248
+ result.migratedPaths.push(`[DRY RUN] Will rename AGENT.md → GEN.md in ${projectGenPath}`);
249
+ result.migratedPaths.push(`[DRY RUN] Will rename AGENT.local.md → GEN.local.md in ${projectGenPath}`);
250
+ }
251
+ }
252
+ }
253
+
254
+ // 3. Migrate root-level files (./AGENT.md → ./GEN.md)
255
+ const rootAgentPath = path.join(cwd, 'AGENT.md');
256
+ const rootGenPath = path.join(cwd, 'GEN.md');
257
+
258
+ if (await pathExists(rootAgentPath)) {
259
+ if (await pathExists(rootGenPath)) {
260
+ result.warnings.push(`./GEN.md already exists! Skipping ./AGENT.md migration.`);
261
+ } else {
262
+ if (!dryRun) {
263
+ try {
264
+ await fs.rename(rootAgentPath, rootGenPath);
265
+ result.migratedPaths.push(`${rootAgentPath} → ${rootGenPath}`);
266
+ } catch (error) {
267
+ result.errors.push(`Failed to migrate ${rootAgentPath}: ${error instanceof Error ? error.message : String(error)}`);
268
+ result.success = false;
269
+ }
270
+ } else {
271
+ result.migratedPaths.push(`[DRY RUN] ${rootAgentPath} → ${rootGenPath}`);
272
+ }
273
+ }
274
+ }
275
+
276
+ // 4. Migrate root-level local files (./AGENT.local.md → ./GEN.local.md)
277
+ const rootAgentLocalPath = path.join(cwd, 'AGENT.local.md');
278
+ const rootGenLocalPath = path.join(cwd, 'GEN.local.md');
279
+
280
+ if (await pathExists(rootAgentLocalPath)) {
281
+ if (await pathExists(rootGenLocalPath)) {
282
+ result.warnings.push(`./GEN.local.md already exists! Skipping ./AGENT.local.md migration.`);
283
+ } else {
284
+ if (!dryRun) {
285
+ try {
286
+ await fs.rename(rootAgentLocalPath, rootGenLocalPath);
287
+ result.migratedPaths.push(`${rootAgentLocalPath} → ${rootGenLocalPath}`);
288
+ } catch (error) {
289
+ result.errors.push(`Failed to migrate ${rootAgentLocalPath}: ${error instanceof Error ? error.message : String(error)}`);
290
+ result.success = false;
291
+ }
292
+ } else {
293
+ result.migratedPaths.push(`[DRY RUN] ${rootAgentLocalPath} → ${rootGenLocalPath}`);
294
+ }
295
+ }
296
+ }
297
+
298
+ // If no migrations needed
299
+ if (result.migratedPaths.length === 0 && result.errors.length === 0) {
300
+ result.warnings.push('No .gencode directories or AGENT.md files found. Already using .gen?');
301
+ }
302
+
303
+ return result;
304
+ }
305
+
306
+ /**
307
+ * Check if migration is needed
308
+ */
309
+ async function needsMigration(): Promise<boolean> {
310
+ const homeGencodePath = path.join(os.homedir(), '.gencode');
311
+ const projectGencodePath = path.join(process.cwd(), '.gencode');
312
+ const rootAgentPath = path.join(process.cwd(), 'AGENT.md');
313
+ const rootAgentLocalPath = path.join(process.cwd(), 'AGENT.local.md');
314
+
315
+ return (
316
+ (await pathExists(homeGencodePath)) ||
317
+ (await pathExists(projectGencodePath)) ||
318
+ (await pathExists(rootAgentPath)) ||
319
+ (await pathExists(rootAgentLocalPath))
320
+ );
321
+ }
322
+
323
+ /**
324
+ * Prompt user for confirmation
325
+ */
326
+ async function confirm(message: string): Promise<boolean> {
327
+ const rl = readline.createInterface({
328
+ input: process.stdin,
329
+ output: process.stdout,
330
+ });
331
+
332
+ return new Promise((resolve) => {
333
+ rl.question(`${message} (y/N): `, (answer) => {
334
+ rl.close();
335
+ resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');
336
+ });
337
+ });
338
+ }
339
+
340
+ /**
341
+ * Main migration flow
342
+ */
343
+ async function main() {
344
+ console.log('🔄 GenCode Migration: .gencode → .gen\n');
345
+
346
+ // Check if migration is needed
347
+ const needs = await needsMigration();
348
+ if (!needs) {
349
+ console.log('✅ No .gencode directories or AGENT.md files found.');
350
+ console.log(' Already using .gen? Nothing to migrate.\n');
351
+ }
352
+
353
+ // Always check providers.json migration (even if .gencode migration not needed)
354
+ console.log('📋 Scanning for files to migrate...\n');
355
+
356
+ // Perform dry run for providers.json
357
+ const providersResult = await migrateProvidersJson(true);
358
+
359
+ // Perform dry run for .gencode
360
+ const dryRunResult = await migrateToGen(true);
361
+
362
+ // Merge results
363
+ const allMigrations = [...providersResult.migratedPaths, ...dryRunResult.migratedPaths];
364
+ const allErrors = [...providersResult.errors, ...dryRunResult.errors];
365
+ const allWarnings = [...providersResult.warnings, ...dryRunResult.warnings];
366
+
367
+ if (allMigrations.length === 0 && allErrors.length === 0) {
368
+ console.log('✅ All configurations are up to date. Nothing to migrate.\n');
369
+ return;
370
+ }
371
+
372
+ if (allMigrations.length > 0) {
373
+ console.log('📦 Migration Plan:\n');
374
+ for (const path of allMigrations) {
375
+ console.log(` ✓ ${path}`);
376
+ }
377
+ console.log('');
378
+ }
379
+
380
+ if (allErrors.length > 0) {
381
+ console.log('❌ Errors:\n');
382
+ for (const error of allErrors) {
383
+ console.log(` ✗ ${error}`);
384
+ }
385
+ console.log('\n⚠️ Migration aborted. Please resolve conflicts manually.\n');
386
+ process.exit(1);
387
+ }
388
+
389
+ if (allWarnings.length > 0) {
390
+ console.log('⚠️ Warnings:\n');
391
+ for (const warning of allWarnings) {
392
+ console.log(` • ${warning}`);
393
+ }
394
+ console.log('');
395
+ }
396
+
397
+ // Ask for confirmation
398
+ const confirmed = await confirm('Proceed with migration?');
399
+ if (!confirmed) {
400
+ console.log('\n❌ Migration cancelled.\n');
401
+ return;
402
+ }
403
+
404
+ // Execute migration
405
+ console.log('\n🚀 Executing migration...\n');
406
+
407
+ // Migrate providers.json first
408
+ const providersExecResult = await migrateProvidersJson(false);
409
+
410
+ // Then migrate .gencode
411
+ const result = await migrateToGen(false);
412
+
413
+ const allSuccess = providersExecResult.success && result.success;
414
+ const allMigratedPaths = [...providersExecResult.migratedPaths, ...result.migratedPaths];
415
+ const allExecErrors = [...providersExecResult.errors, ...result.errors];
416
+
417
+ if (allSuccess) {
418
+ console.log('✅ Migration completed successfully!\n');
419
+ if (allMigratedPaths.length > 0) {
420
+ console.log('Migrated paths:\n');
421
+ for (const path of allMigratedPaths) {
422
+ console.log(` ✓ ${path}`);
423
+ }
424
+ console.log('');
425
+ }
426
+ console.log('📝 Next steps:\n');
427
+ console.log(' 1. Update environment variables: GENCODE_* → GEN_*');
428
+ console.log(' - GENCODE_PROVIDER → GEN_PROVIDER');
429
+ console.log(' - GENCODE_MODEL → GEN_MODEL');
430
+ console.log(' - GENCODE_CONFIG_DIRS → GEN_CONFIG\n');
431
+ console.log(' 2. Update any scripts or CI/CD configs\n');
432
+ console.log(' 3. Restart GenCode to load from .gen directories\n');
433
+ } else {
434
+ console.log('❌ Migration failed!\n');
435
+ if (allExecErrors.length > 0) {
436
+ console.log('Errors:\n');
437
+ for (const error of allExecErrors) {
438
+ console.log(` ✗ ${error}`);
439
+ }
440
+ console.log('');
441
+ }
442
+ process.exit(1);
443
+ }
444
+ }
445
+
446
+ main().catch((error) => {
447
+ console.error('❌ Unexpected error:', error);
448
+ process.exit(1);
449
+ });
@@ -2,8 +2,8 @@
2
2
  * Agent - Core agent implementation with tool loop and session support
3
3
  */
4
4
 
5
- import type { LLMProvider, Message, ToolResultContent } from '../providers/types.js';
6
- import { createProvider, inferProvider } from '../providers/index.js';
5
+ import type { LLMProvider, Message, ToolResultContent, Provider, AuthMethod } from '../providers/types.js';
6
+ import { createProvider, inferProvider, inferAuthMethod } from '../providers/index.js';
7
7
  import { ToolRegistry, createDefaultRegistry } from '../tools/index.js';
8
8
  import {
9
9
  PermissionManager,
@@ -47,7 +47,10 @@ export class Agent {
47
47
  ...config,
48
48
  };
49
49
 
50
- this.provider = createProvider({ provider: config.provider });
50
+ this.provider = createProvider({
51
+ provider: config.provider,
52
+ authMethod: config.authMethod,
53
+ });
51
54
  this.registry = createDefaultRegistry();
52
55
  this.permissions = new PermissionManager({
53
56
  config: config.permissions,
@@ -141,7 +144,24 @@ export class Agent {
141
144
  */
142
145
  async loadMemory(): Promise<LoadedMemory> {
143
146
  const cwd = this.config.cwd ?? process.cwd();
144
- this.loadedMemory = await this.memoryManager.load({ cwd });
147
+
148
+ // Determine memory merge strategy (priority: env var > config > default)
149
+ const envStrategy = process.env.GEN_MEMORY_STRATEGY as
150
+ | 'fallback'
151
+ | 'both'
152
+ | 'gen-only'
153
+ | 'claude-only'
154
+ | undefined;
155
+ const strategy =
156
+ envStrategy ?? this.config.memoryMergeStrategy ?? 'fallback';
157
+
158
+ this.loadedMemory = await this.memoryManager.load({ cwd, strategy });
159
+
160
+ // Log verbose summary if verbose mode is enabled
161
+ if (this.config.verbose) {
162
+ console.log(this.memoryManager.getVerboseSummary(strategy));
163
+ }
164
+
145
165
  return this.loadedMemory;
146
166
  }
147
167
 
@@ -233,15 +253,30 @@ export class Agent {
233
253
 
234
254
  /**
235
255
  * Set the model to use (auto-switches provider if needed)
256
+ * @param model Model ID to use
257
+ * @param provider Optional: explicit provider (otherwise inferred from model name)
258
+ * @param authMethod Optional: explicit auth method (otherwise inferred or use current)
236
259
  */
237
- setModel(model: string): void {
260
+ setModel(model: string, provider?: string, authMethod?: string): void {
238
261
  this.config.model = model;
239
262
 
240
- // Auto-switch provider based on model name
241
- const newProvider = inferProvider(model);
242
- if (newProvider !== this.config.provider) {
263
+ // Determine new provider and authMethod
264
+ const newProvider = (provider as Provider | undefined) ?? inferProvider(model);
265
+ const newAuthMethod = (authMethod as AuthMethod | undefined) ??
266
+ inferAuthMethod(model) ??
267
+ this.config.authMethod;
268
+
269
+ // Recreate provider if either provider or authMethod changed
270
+ const providerChanged = newProvider !== this.config.provider;
271
+ const authMethodChanged = newAuthMethod !== this.config.authMethod;
272
+
273
+ if (providerChanged || authMethodChanged) {
243
274
  this.config.provider = newProvider;
244
- this.provider = createProvider({ provider: newProvider });
275
+ this.config.authMethod = newAuthMethod;
276
+ this.provider = createProvider({
277
+ provider: newProvider,
278
+ authMethod: newAuthMethod,
279
+ });
245
280
  }
246
281
  }
247
282
 
@@ -252,6 +287,13 @@ export class Agent {
252
287
  return this.config.model;
253
288
  }
254
289
 
290
+ /**
291
+ * Get current provider
292
+ */
293
+ getProvider(): Provider {
294
+ return this.config.provider;
295
+ }
296
+
255
297
  /**
256
298
  * List available models from the provider API
257
299
  */
@@ -4,15 +4,19 @@
4
4
 
5
5
  import type { PermissionConfig } from '../permissions/types.js';
6
6
  import type { CostEstimate } from '../pricing/types.js';
7
+ import type { Provider, AuthMethod } from '../providers/types.js';
7
8
 
8
9
  export interface AgentConfig {
9
- provider: 'openai' | 'anthropic' | 'gemini' | 'vertex-ai';
10
+ provider: Provider;
11
+ authMethod?: AuthMethod;
10
12
  model: string;
11
13
  systemPrompt?: string;
12
14
  tools?: string[];
13
15
  cwd?: string;
14
16
  maxTurns?: number;
15
17
  permissions?: Partial<PermissionConfig>;
18
+ memoryMergeStrategy?: 'fallback' | 'both' | 'gen-only' | 'claude-only';
19
+ verbose?: boolean;
16
20
  }
17
21
 
18
22
  // Agent Events
@@ -133,7 +133,7 @@ function HelpPanel() {
133
133
  ['/new', 'New session'],
134
134
  ['/save', 'Save session'],
135
135
  ['/clear', 'Clear chat'],
136
- ['/init', 'Generate AGENT.md'],
136
+ ['/init', 'Generate GEN.md'],
137
137
  ['/memory', 'Show memory files'],
138
138
  ['/changes', 'List file changes'],
139
139
  ['/rewind [n|all]', 'Undo file changes'],
@@ -266,6 +266,7 @@ export function App({ config, settingsManager, resumeLatest, permissionSettings
266
266
  const [showModelSelector, setShowModelSelector] = useState(false);
267
267
  const [showProviderManager, setShowProviderManager] = useState(false);
268
268
  const [currentModel, setCurrentModel] = useState(config.model);
269
+ const [currentProvider, setCurrentProvider] = useState(config.provider);
269
270
  const [cmdSuggestionIndex, setCmdSuggestionIndex] = useState(0);
270
271
  const [inputKey, setInputKey] = useState(0); // Force cursor to end after autocomplete
271
272
  const [pendingTool, setPendingTool] = useState<{ name: string; input: Record<string, unknown> } | null>(null);
@@ -380,9 +381,14 @@ export function App({ config, settingsManager, resumeLatest, permissionSettings
380
381
  };
381
382
 
382
383
  // Handle model selection
383
- const handleModelSelect = async (model: string, providerId?: ProviderName) => {
384
- agent.setModel(model);
384
+ const handleModelSelect = async (model: string, providerId?: ProviderName, authMethod?: string) => {
385
+ agent.setModel(model, providerId, authMethod);
385
386
  setCurrentModel(model);
387
+
388
+ // Update provider state to keep UI in sync
389
+ const newProvider = agent.getProvider();
390
+ setCurrentProvider(newProvider);
391
+
386
392
  setShowModelSelector(false);
387
393
 
388
394
  if (providerId) {
@@ -477,6 +483,7 @@ export function App({ config, settingsManager, resumeLatest, permissionSettings
477
483
  // Direct model switch: /model gpt-4o
478
484
  agent.setModel(arg);
479
485
  setCurrentModel(arg);
486
+ setCurrentProvider(agent.getProvider());
480
487
  addHistory({ type: 'info', content: `Model: ${arg}` });
481
488
  } else {
482
489
  // Show interactive model selector
@@ -540,13 +547,13 @@ export function App({ config, settingsManager, resumeLatest, permissionSettings
540
547
  }
541
548
 
542
549
  case 'init': {
543
- // Gather context files and generate AGENT.md
550
+ // Gather context files and generate GEN.md
544
551
  addHistory({ type: 'info', content: 'Analyzing codebase...' });
545
552
 
546
553
  const contextFiles = await gatherContextFiles(cwd);
547
554
  addHistory({ type: 'info', content: getContextSummary(contextFiles) });
548
555
 
549
- // Check if AGENT.md already exists
556
+ // Check if GEN.md already exists
550
557
  const memoryManager = agent.getMemoryManager();
551
558
  const existingPath = await memoryManager.getExistingProjectMemoryPath(cwd);
552
559
  let existingContent: string | undefined;
@@ -566,7 +573,7 @@ export function App({ config, settingsManager, resumeLatest, permissionSettings
566
573
 
567
574
  // Build init prompt and run through agent
568
575
  const initPrompt = buildInitPrompt(contextFiles, existingContent);
569
- addHistory({ type: 'info', content: 'Generating AGENT.md...' });
576
+ addHistory({ type: 'info', content: 'Generating GEN.md...' });
570
577
  addHistory({ type: 'user', content: '/init' });
571
578
  await runAgent(initPrompt);
572
579
  return true;
@@ -850,8 +857,8 @@ export function App({ config, settingsManager, resumeLatest, permissionSettings
850
857
  }
851
858
 
852
859
  // Handle # prefix for quick memory adds
853
- // ## note -> user memory (~/.gencode/AGENT.md)
854
- // # note -> project memory (./AGENT.md)
860
+ // ## note -> user memory (~/.gen/GEN.md)
861
+ // # note -> project memory (./GEN.md)
855
862
  if (trimmed.startsWith('#') && !trimmed.startsWith('#!/')) {
856
863
  const memoryManager = agent.getMemoryManager();
857
864
  let level: 'user' | 'project';
@@ -1082,6 +1089,7 @@ export function App({ config, settingsManager, resumeLatest, permissionSettings
1082
1089
  <Box marginTop={1}>
1083
1090
  <ModelSelector
1084
1091
  currentModel={currentModel}
1092
+ currentProvider={currentProvider}
1085
1093
  onSelect={handleModelSelect}
1086
1094
  onCancel={handleModelCancel}
1087
1095
  listModels={() => agent.listModels()}
@@ -1096,6 +1104,7 @@ export function App({ config, settingsManager, resumeLatest, permissionSettings
1096
1104
  onProviderChange={(providerId, model) => {
1097
1105
  agent.setModel(model);
1098
1106
  setCurrentModel(model);
1107
+ setCurrentProvider(agent.getProvider());
1099
1108
  addHistory({ type: 'info', content: `Switched to ${providerId}: ${model}` });
1100
1109
  }}
1101
1110
  />
@@ -288,7 +288,7 @@ export function InfoMessage({ text, type = 'info' }: InfoMessageProps) {
288
288
  const { color, icon } = config[type];
289
289
 
290
290
  return (
291
- <Box>
291
+ <Box marginTop={1}>
292
292
  <Text color={color}>{icon} </Text>
293
293
  <Text color={colors.textSecondary}>{text}</Text>
294
294
  </Box>