@aicgen/aicgen 1.0.0-beta.1 → 1.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. package/.vs/ProjectSettings.json +2 -2
  2. package/.vs/VSWorkspaceState.json +15 -15
  3. package/.vs/aicgen.slnx/v18/DocumentLayout.json +53 -53
  4. package/assets/icon.svg +33 -33
  5. package/bun.lock +0 -43
  6. package/data/architecture/microservices/api-gateway.md +56 -56
  7. package/data/devops/observability.md +73 -73
  8. package/dist/index.js +9299 -9299
  9. package/package.json +2 -2
  10. package/.claude/agents/architecture-reviewer.md +0 -88
  11. package/.claude/agents/guideline-checker.md +0 -73
  12. package/.claude/agents/security-auditor.md +0 -108
  13. package/.claude/guidelines/api-design.md +0 -645
  14. package/.claude/guidelines/architecture.md +0 -2503
  15. package/.claude/guidelines/best-practices.md +0 -618
  16. package/.claude/guidelines/code-style.md +0 -304
  17. package/.claude/guidelines/design-patterns.md +0 -573
  18. package/.claude/guidelines/devops.md +0 -226
  19. package/.claude/guidelines/error-handling.md +0 -413
  20. package/.claude/guidelines/language.md +0 -782
  21. package/.claude/guidelines/performance.md +0 -706
  22. package/.claude/guidelines/security.md +0 -583
  23. package/.claude/guidelines/testing.md +0 -568
  24. package/.claude/settings.json +0 -98
  25. package/.claude/settings.local.json +0 -8
  26. package/.eslintrc.json +0 -28
  27. package/.github/workflows/release.yml +0 -180
  28. package/.github/workflows/test.yml +0 -81
  29. package/CONTRIBUTING.md +0 -821
  30. package/dist/commands/init.d.ts +0 -8
  31. package/dist/commands/init.d.ts.map +0 -1
  32. package/dist/commands/init.js +0 -46
  33. package/dist/commands/init.js.map +0 -1
  34. package/dist/config/profiles.d.ts +0 -4
  35. package/dist/config/profiles.d.ts.map +0 -1
  36. package/dist/config/profiles.js +0 -30
  37. package/dist/config/profiles.js.map +0 -1
  38. package/dist/config/settings.d.ts +0 -7
  39. package/dist/config/settings.d.ts.map +0 -1
  40. package/dist/config/settings.js +0 -7
  41. package/dist/config/settings.js.map +0 -1
  42. package/dist/index.d.ts +0 -3
  43. package/dist/index.d.ts.map +0 -1
  44. package/dist/index.js.map +0 -1
  45. package/dist/models/guideline.d.ts +0 -15
  46. package/dist/models/guideline.d.ts.map +0 -1
  47. package/dist/models/guideline.js +0 -2
  48. package/dist/models/guideline.js.map +0 -1
  49. package/dist/models/preference.d.ts +0 -9
  50. package/dist/models/preference.d.ts.map +0 -1
  51. package/dist/models/preference.js +0 -2
  52. package/dist/models/preference.js.map +0 -1
  53. package/dist/models/profile.d.ts +0 -9
  54. package/dist/models/profile.d.ts.map +0 -1
  55. package/dist/models/profile.js +0 -2
  56. package/dist/models/profile.js.map +0 -1
  57. package/dist/models/project.d.ts +0 -13
  58. package/dist/models/project.d.ts.map +0 -1
  59. package/dist/models/project.js +0 -2
  60. package/dist/models/project.js.map +0 -1
  61. package/dist/services/ai/anthropic.d.ts +0 -7
  62. package/dist/services/ai/anthropic.d.ts.map +0 -1
  63. package/dist/services/ai/anthropic.js +0 -39
  64. package/dist/services/ai/anthropic.js.map +0 -1
  65. package/dist/services/generator.d.ts +0 -2
  66. package/dist/services/generator.d.ts.map +0 -1
  67. package/dist/services/generator.js +0 -4
  68. package/dist/services/generator.js.map +0 -1
  69. package/dist/services/learner.d.ts +0 -2
  70. package/dist/services/learner.d.ts.map +0 -1
  71. package/dist/services/learner.js +0 -4
  72. package/dist/services/learner.js.map +0 -1
  73. package/dist/services/scanner.d.ts +0 -3
  74. package/dist/services/scanner.d.ts.map +0 -1
  75. package/dist/services/scanner.js +0 -54
  76. package/dist/services/scanner.js.map +0 -1
  77. package/dist/utils/errors.d.ts +0 -15
  78. package/dist/utils/errors.d.ts.map +0 -1
  79. package/dist/utils/errors.js +0 -27
  80. package/dist/utils/errors.js.map +0 -1
  81. package/dist/utils/file.d.ts +0 -7
  82. package/dist/utils/file.d.ts.map +0 -1
  83. package/dist/utils/file.js +0 -32
  84. package/dist/utils/file.js.map +0 -1
  85. package/dist/utils/logger.d.ts +0 -6
  86. package/dist/utils/logger.d.ts.map +0 -1
  87. package/dist/utils/logger.js +0 -17
  88. package/dist/utils/logger.js.map +0 -1
  89. package/dist/utils/path.d.ts +0 -6
  90. package/dist/utils/path.d.ts.map +0 -1
  91. package/dist/utils/path.js +0 -14
  92. package/dist/utils/path.js.map +0 -1
  93. package/docs/planning/memory-lane.md +0 -83
  94. package/packaging/linux/aicgen.spec +0 -23
  95. package/packaging/linux/control +0 -9
  96. package/packaging/macos/scripts/postinstall +0 -12
  97. package/packaging/windows/setup.nsi +0 -92
  98. package/scripts/add-categories.ts +0 -87
  99. package/scripts/build-binary.ts +0 -46
  100. package/scripts/embed-data.ts +0 -105
  101. package/scripts/generate-version.ts +0 -150
  102. package/scripts/test-decompress.ts +0 -27
  103. package/scripts/test-extract.ts +0 -31
  104. package/src/__tests__/services/assistant-file-writer.test.ts +0 -400
  105. package/src/__tests__/services/guideline-loader.test.ts +0 -281
  106. package/src/__tests__/services/tarball-extraction.test.ts +0 -125
  107. package/src/commands/add-guideline.ts +0 -296
  108. package/src/commands/clear.ts +0 -61
  109. package/src/commands/guideline-selector.ts +0 -123
  110. package/src/commands/init.ts +0 -645
  111. package/src/commands/quick-add.ts +0 -586
  112. package/src/commands/remove-guideline.ts +0 -152
  113. package/src/commands/stats.ts +0 -49
  114. package/src/commands/update.ts +0 -240
  115. package/src/config.ts +0 -82
  116. package/src/embedded-data.ts +0 -1492
  117. package/src/index.ts +0 -67
  118. package/src/models/profile.ts +0 -24
  119. package/src/models/project.ts +0 -43
  120. package/src/services/assistant-file-writer.ts +0 -612
  121. package/src/services/config-generator.ts +0 -150
  122. package/src/services/config-manager.ts +0 -70
  123. package/src/services/data-source.ts +0 -248
  124. package/src/services/first-run-init.ts +0 -148
  125. package/src/services/guideline-loader.ts +0 -311
  126. package/src/services/hook-generator.ts +0 -178
  127. package/src/services/subagent-generator.ts +0 -310
  128. package/src/utils/banner.ts +0 -66
  129. package/src/utils/errors.ts +0 -27
  130. package/src/utils/file.ts +0 -67
  131. package/src/utils/formatting.ts +0 -172
  132. package/src/utils/logger.ts +0 -89
  133. package/src/utils/path.ts +0 -17
  134. package/src/utils/wizard-state.ts +0 -132
  135. package/tsconfig.json +0 -25
  136. /package/{CLAUDE.md → claude.md} +0 -0
@@ -1,586 +0,0 @@
1
- import { select, checkbox, confirm } from '@inquirer/prompts';
2
- import chalk from 'chalk';
3
- import { existsSync } from 'fs';
4
- import { readFile, writeFile, appendFile, mkdir } from 'fs/promises';
5
- import { join } from 'path';
6
- import ora from 'ora';
7
- import { AIAssistant, Language, ProjectType } from '../models/project.js';
8
- import { GuidelineLoader } from '../services/guideline-loader.js';
9
- import { showBanner } from '../utils/banner.js';
10
- import { AssistantFileWriter } from '../services/assistant-file-writer.js';
11
- import { ProfileSelection, ArchitectureType, InstructionLevel } from '../models/profile.js';
12
- import { ConfigGenerator } from '../services/config-generator.js';
13
-
14
- interface CheckboxChoice {
15
- name: string;
16
- value: string;
17
- checked?: boolean;
18
- disabled?: boolean | string;
19
- }
20
-
21
-
22
- export async function quickAddCommand() {
23
- showBanner();
24
- console.log(chalk.cyan('🚀 Quick Add Guidelines\n'));
25
-
26
- const projectPath = process.cwd();
27
- const spinner = ora('Detecting project configuration...').start();
28
-
29
- // Detect which assistant is being used
30
- const assistant = await detectAssistant(projectPath);
31
-
32
- if (!assistant) {
33
- spinner.fail('No AI configuration found');
34
- console.log(chalk.yellow('\n⚠️ No existing AI configuration detected.'));
35
- console.log(chalk.gray(' Run `aicgen init` first to create a configuration.\n'));
36
- return;
37
- }
38
-
39
- spinner.succeed(`Detected: ${assistant}`);
40
-
41
- // Load existing configuration
42
- const existingConfig = await loadExistingConfig(projectPath, assistant);
43
-
44
- console.log(chalk.cyan('\n📋 Current Configuration:'));
45
- console.log(` Assistant: ${existingConfig.assistant}`);
46
- console.log(` Language: ${existingConfig.language}`);
47
- console.log(` Level: ${existingConfig.level}`);
48
- console.log(` Architecture: ${existingConfig.architecture || 'Not specified'}`);
49
-
50
- // Load guideline library
51
- const loader = await GuidelineLoader.create();
52
-
53
- let continueLoop = true;
54
- while (continueLoop) {
55
- // Organize by category
56
- const categoryTree = loader.getCategoryTree(
57
- existingConfig.language,
58
- existingConfig.level,
59
- existingConfig.architecture || 'modular-monolith',
60
- existingConfig.datasource || 'sql'
61
- );
62
-
63
- // Build choices
64
- const choices: CheckboxChoice[] = [];
65
- const guidelineMap = new Map<string, string>();
66
-
67
- for (const category of categoryTree) {
68
- choices.push({
69
- name: chalk.bold.cyan(`${category.name} (${category.count})`),
70
- value: `__CATEGORY_${category.name}__`,
71
- disabled: true
72
- });
73
-
74
- for (const guideline of category.guidelines) {
75
- choices.push({
76
- name: ` ${guideline.name}`,
77
- value: guideline.id,
78
- checked: false
79
- });
80
- guidelineMap.set(guideline.id, guideline.name);
81
- }
82
- }
83
-
84
- // Let user select guidelines
85
- const selectedIds = await checkbox({
86
- message: 'Select guidelines to add (Space to toggle, Enter to confirm, or press Enter with no selection to cancel):',
87
- choices,
88
- pageSize: 25,
89
- loop: false
90
- }) as string[];
91
-
92
- if (selectedIds.length === 0) {
93
- const action = await select({
94
- message: 'No guidelines selected. What would you like to do?',
95
- choices: [
96
- { value: 'retry', name: 'Try again', description: 'Go back to guideline selection' },
97
- { value: 'cancel', name: 'Cancel', description: 'Exit without changes' }
98
- ]
99
- });
100
-
101
- if (action === 'cancel') {
102
- console.log(chalk.gray('\nCancelled.'));
103
- return;
104
- }
105
-
106
- console.clear();
107
- showBanner();
108
- console.log(chalk.cyan('🚀 Quick Add Guidelines\n'));
109
- console.log(chalk.cyan('📋 Current Configuration:'));
110
- console.log(` Assistant: ${existingConfig.assistant}`);
111
- console.log(` Language: ${existingConfig.language}`);
112
- console.log(` Level: ${existingConfig.level}`);
113
- console.log(` Architecture: ${existingConfig.architecture || 'Not specified'}\n`);
114
- continue;
115
- }
116
-
117
- // Filter out category separators
118
- const validIds = selectedIds.filter(id => !id.startsWith('__CATEGORY_'));
119
-
120
- console.log(chalk.cyan(`\n✓ Selected ${validIds.length} guideline(s)`));
121
-
122
- // Show what will be added
123
- console.log(chalk.cyan('\n📚 Adding:'));
124
- validIds.slice(0, 10).forEach(id => {
125
- console.log(` • ${guidelineMap.get(id) || id}`);
126
- });
127
- if (validIds.length > 10) {
128
- console.log(chalk.gray(` ... and ${validIds.length - 10} more`));
129
- }
130
-
131
- // Inner loop for "how to add" and confirmation
132
- let addModeLoop = true;
133
- while (addModeLoop) {
134
- // Ask how to add
135
- const addChoices = [
136
- { value: 'append', name: 'Append to existing config', description: 'Add to current configuration' },
137
- { value: 'replace', name: 'Replace entire config', description: 'Regenerate with selected + existing guidelines' },
138
- { value: 'back', name: '← Back to selection', description: 'Change selected guidelines' },
139
- { value: 'cancel', name: 'Cancel', description: 'Exit without changes' }
140
- ];
141
-
142
- const addMode = await select({
143
- message: 'How would you like to add these guidelines?',
144
- choices: addChoices
145
- });
146
-
147
- if (addMode === 'back') {
148
- console.clear();
149
- showBanner();
150
- console.log(chalk.cyan('🚀 Quick Add Guidelines\n'));
151
- console.log(chalk.cyan('📋 Current Configuration:'));
152
- console.log(` Assistant: ${existingConfig.assistant}`);
153
- console.log(` Language: ${existingConfig.language}`);
154
- console.log(` Level: ${existingConfig.level}`);
155
- console.log(` Architecture: ${existingConfig.architecture || 'Not specified'}\n`);
156
- addModeLoop = false; // Exit inner loop, continue outer loop
157
- continue;
158
- }
159
-
160
- if (addMode === 'cancel') {
161
- console.log(chalk.gray('\nCancelled.'));
162
- return;
163
- }
164
-
165
- // Warn before destructive replace
166
- if (addMode === 'replace') {
167
- console.log(chalk.yellow('\n⚠️ Warning: Replace mode will regenerate your entire configuration.'));
168
- console.log(chalk.gray(' This will overwrite any manual edits to settings, hooks, or guidelines.'));
169
-
170
- const confirmReplace = await confirm({
171
- message: 'Are you sure you want to replace the entire configuration?',
172
- default: false
173
- });
174
-
175
- if (!confirmReplace) {
176
- console.log(chalk.gray('\nGoing back to mode selection...\n'));
177
- continue; // Stay in inner loop - go back to "how to add" question
178
- }
179
- }
180
-
181
- // Execute the operation
182
- spinner.start('Adding guidelines...');
183
-
184
- try {
185
- if (addMode === 'append') {
186
- await appendGuidelines(projectPath, assistant, validIds, loader);
187
- } else {
188
- await regenerateConfig(projectPath, existingConfig, validIds, loader);
189
- }
190
-
191
- spinner.succeed('Guidelines added successfully!');
192
- console.log(chalk.green(`\n✅ Added ${validIds.length} guideline(s) to ${assistant} configuration`));
193
- continueLoop = false;
194
- addModeLoop = false;
195
- } catch (error) {
196
- spinner.fail('Failed to add guidelines');
197
- console.error(chalk.red(`\n❌ Error: ${error}`));
198
- continueLoop = false;
199
- addModeLoop = false;
200
- }
201
- }
202
- }
203
- }
204
-
205
- async function detectAssistant(projectPath: string): Promise<AIAssistant | null> {
206
- const configs = [
207
- { path: 'CLAUDE.md', assistant: 'claude-code' as AIAssistant },
208
- { path: '.claude', assistant: 'claude-code' as AIAssistant },
209
- { path: '.github/copilot-instructions.md', assistant: 'copilot' as AIAssistant },
210
- { path: '.gemini', assistant: 'gemini' as AIAssistant },
211
- { path: '.agent', assistant: 'antigravity' as AIAssistant },
212
- { path: '.codex', assistant: 'codex' as AIAssistant }
213
- ];
214
-
215
- for (const config of configs) {
216
- if (existsSync(join(projectPath, config.path))) {
217
- return config.assistant;
218
- }
219
- }
220
-
221
- return null;
222
- }
223
-
224
- async function loadExistingConfig(projectPath: string, assistant: AIAssistant): Promise<ProfileSelection> {
225
- // Default fallback - get project name from path
226
- const pathParts = projectPath.split(/[/\\]/);
227
- const defaultName = pathParts[pathParts.length - 1] || 'project';
228
-
229
- const config: ProfileSelection = {
230
- assistant,
231
- language: 'typescript',
232
- level: 'standard',
233
- architecture: 'modular-monolith',
234
- projectType: 'web',
235
- projectName: defaultName,
236
- datasource: 'sql'
237
- };
238
-
239
- // 1. Detect language and name from project files using ConfigGenerator logic
240
- try {
241
- const generator = await ConfigGenerator.create();
242
- const detected = await generator.detectProject(projectPath);
243
- if (detected.language !== 'unknown') {
244
- config.language = detected.language;
245
- }
246
- config.projectName = detected.name;
247
- } catch {
248
- // Ignore errors here
249
- }
250
-
251
- // 2. Parsed from instruction files if possible
252
- try {
253
- let content = '';
254
- let filePath = '';
255
-
256
- switch (assistant) {
257
- case 'claude-code': {
258
- // Check root first, then .claude/ for backward compatibility
259
- const rootPath = join(projectPath, 'CLAUDE.md');
260
- const legacyPath = join(projectPath, '.claude', 'CLAUDE.md');
261
- filePath = existsSync(rootPath) ? rootPath : legacyPath;
262
- break;
263
- }
264
- case 'copilot':
265
- filePath = join(projectPath, '.github', 'copilot-instructions.md');
266
- break;
267
- case 'gemini':
268
- filePath = join(projectPath, '.gemini', 'instructions.md');
269
- break;
270
- case 'antigravity':
271
- filePath = join(projectPath, '.agent', 'rules', 'instructions.md');
272
- break;
273
- case 'codex':
274
- filePath = join(projectPath, '.codex', 'instructions.md');
275
- break;
276
- }
277
-
278
- if (filePath && existsSync(filePath)) {
279
- content = await readFile(filePath, 'utf-8');
280
-
281
- // Extract Language
282
- const langMatch = content.match(/Language:\*\*\s*([\w-#]+)/i) || content.match(/Language:\s*([\w-#]+)/i);
283
- if (langMatch && langMatch[1]) {
284
- config.language = langMatch[1].toLowerCase().trim() as Language;
285
- }
286
-
287
- // Extract Architecture
288
- const archMatch = content.match(/Architecture:\*\*\s*([\w-]+)/i) || content.match(/Architecture:\s*([\w-]+)/i);
289
- if (archMatch && archMatch[1]) {
290
- config.architecture = archMatch[1].toLowerCase().trim() as ArchitectureType;
291
- }
292
-
293
- // Extract Type
294
- const typeMatch = content.match(/Type:\*\*\s*([\w-]+)/i) || content.match(/Type:\s*([\w-]+)/i);
295
- if (typeMatch && typeMatch[1]) {
296
- const typeStr = typeMatch[1].toLowerCase().trim();
297
- // Simple mapping verification
298
- if (['web', 'api', 'cli', 'library', 'desktop', 'mobile', 'other'].includes(typeStr)) {
299
- config.projectType = typeStr as ProjectType;
300
- }
301
- }
302
-
303
- // Extract Level
304
- const levelMatch = content.match(/Level:\*\*\s*([\w-]+)/i) || content.match(/Level:\s*([\w-]+)/i);
305
- if (levelMatch && levelMatch[1]) {
306
- config.level = levelMatch[1].toLowerCase().trim() as InstructionLevel;
307
- }
308
- }
309
- } catch (err) {
310
- console.log(chalk.yellow(`\n⚠️ Could not parse existing config, using defaults: ${err}`));
311
- }
312
-
313
- return config;
314
- }
315
-
316
- async function appendGuidelines(
317
- projectPath: string,
318
- assistant: AIAssistant,
319
- guidelineIds: string[],
320
- loader: GuidelineLoader
321
- ): Promise<void> {
322
- const guidelines = guidelineIds.map(id => loader.loadGuideline(id)).filter(Boolean);
323
-
324
- switch (assistant) {
325
- case 'claude-code':
326
- await appendToClaudeCode(projectPath, guidelines);
327
- break;
328
- case 'copilot':
329
- await appendToCopilot(projectPath, guidelines);
330
- break;
331
- case 'gemini':
332
- await appendToGemini(projectPath, guidelines);
333
- break;
334
- case 'antigravity':
335
- await appendToAntigravity(projectPath, guidelines);
336
- break;
337
- case 'codex':
338
- await appendToCodex(projectPath, guidelines);
339
- break;
340
- }
341
- }
342
-
343
- async function appendToClaudeCode(projectPath: string, guidelines: string[]): Promise<void> {
344
- // Check root first, then .claude/ for backward compatibility
345
- const rootPath = join(projectPath, 'CLAUDE.md');
346
- const legacyPath = join(projectPath, '.claude', 'CLAUDE.md');
347
- const instructionsPath = existsSync(rootPath) ? rootPath : legacyPath;
348
-
349
- if (!existsSync(instructionsPath)) {
350
- throw new Error('CLAUDE.md not found');
351
- }
352
-
353
- // Create guidelines directory
354
- const guidelinesDir = join(projectPath, '.claude', 'guidelines');
355
- await mkdir(guidelinesDir, { recursive: true });
356
-
357
- // Create or append to additional.md file
358
- const additionalFile = join(guidelinesDir, 'additional.md');
359
- const additionalContent = `# Additional Guidelines\n\n${guidelines.join('\n\n---\n\n')}`;
360
-
361
- if (existsSync(additionalFile)) {
362
- // Append to existing file
363
- await appendFile(additionalFile, `\n\n---\n\n${guidelines.join('\n\n---\n\n')}`, 'utf-8');
364
- } else {
365
- // Create new file
366
- await writeFile(additionalFile, additionalContent, 'utf-8');
367
- }
368
-
369
- // Update CLAUDE.md with reference if not already present
370
- const content = await readFile(instructionsPath, 'utf-8');
371
-
372
- if (content.includes('@.claude/guidelines/additional.md')) {
373
- // Reference already exists, file is updated, we're done
374
- return;
375
- }
376
-
377
- // Add reference to guidelines section
378
- const guidelinesMatch = content.match(/(## Guidelines[\s\S]*?)(?=\n## |$)/);
379
- if (guidelinesMatch) {
380
- const guidelinesSection = guidelinesMatch[1];
381
- const newGuidelinesSection = guidelinesSection.trimEnd() + '\n- **Additional**: @.claude/guidelines/additional.md';
382
- const newContent = content.replace(guidelinesSection, newGuidelinesSection);
383
- await writeFile(instructionsPath, newContent, 'utf-8');
384
- } else {
385
- // Fallback: append to end of file
386
- const newContent = content.trimEnd() + '\n\n- **Additional**: @.claude/guidelines/additional.md\n';
387
- await writeFile(instructionsPath, newContent, 'utf-8');
388
- }
389
- }
390
-
391
- async function appendToCopilot(projectPath: string, guidelines: string[]): Promise<void> {
392
- const instructionsPath = join(projectPath, '.github', 'copilot-instructions.md');
393
-
394
- if (!existsSync(instructionsPath)) {
395
- throw new Error('copilot-instructions.md not found');
396
- }
397
-
398
- // Create instructions directory
399
- const instructionsDir = join(projectPath, '.github', 'instructions');
400
- await mkdir(instructionsDir, { recursive: true });
401
-
402
- // Create additional instructions file with frontmatter
403
- const additionalFile = join(instructionsDir, 'additional.instructions.md');
404
- const additionalContent = `---
405
- applyTo: "**/*"
406
- description: "Additional guidelines"
407
- ---
408
-
409
- # Additional Guidelines
410
-
411
- ${guidelines.join('\n\n---\n\n')}`;
412
-
413
- if (existsSync(additionalFile)) {
414
- // Append to existing file (skip frontmatter)
415
- await appendFile(additionalFile, `\n\n---\n\n${guidelines.join('\n\n---\n\n')}`, 'utf-8');
416
- } else {
417
- // Create new file
418
- await writeFile(additionalFile, additionalContent, 'utf-8');
419
- }
420
-
421
- // Update copilot-instructions.md with reference if not already present
422
- const content = await readFile(instructionsPath, 'utf-8');
423
-
424
- if (content.includes('@.github/instructions/additional.instructions.md')) {
425
- // Reference already exists
426
- return;
427
- }
428
-
429
- // Add reference to guidelines section
430
- const guidelinesMatch = content.match(/(## Guidelines[\s\S]*?)(?=\n## |$)/);
431
- if (guidelinesMatch) {
432
- const guidelinesSection = guidelinesMatch[1];
433
- const newGuidelinesSection = guidelinesSection.trimEnd() + '\n- Additional: @.github/instructions/additional.instructions.md';
434
- const newContent = content.replace(guidelinesSection, newGuidelinesSection);
435
- await writeFile(instructionsPath, newContent, 'utf-8');
436
- } else {
437
- // Fallback: append to end
438
- const newContent = content.trimEnd() + '\n\n- Additional: @.github/instructions/additional.instructions.md\n';
439
- await writeFile(instructionsPath, newContent, 'utf-8');
440
- }
441
- }
442
-
443
- async function appendToGemini(projectPath: string, guidelines: string[]): Promise<void> {
444
- const instructionsPath = join(projectPath, '.gemini', 'instructions.md');
445
-
446
- if (!existsSync(instructionsPath)) {
447
- throw new Error('instructions.md not found');
448
- }
449
-
450
- // Create guidelines directory
451
- const geminiDir = join(projectPath, '.gemini');
452
- await mkdir(geminiDir, { recursive: true });
453
-
454
- // Create additional guidelines file
455
- const additionalFile = join(geminiDir, 'additional-guidelines.md');
456
- const additionalContent = `# Additional Guidelines\n\n${guidelines.join('\n\n---\n\n')}`;
457
-
458
- if (existsSync(additionalFile)) {
459
- // Append to existing file
460
- await appendFile(additionalFile, `\n\n---\n\n${guidelines.join('\n\n---\n\n')}`, 'utf-8');
461
- } else {
462
- // Create new file
463
- await writeFile(additionalFile, additionalContent, 'utf-8');
464
- }
465
-
466
- // Update instructions.md with import reference if not already present
467
- const content = await readFile(instructionsPath, 'utf-8');
468
-
469
- if (content.includes('additional-guidelines.md')) {
470
- // Reference already exists
471
- return;
472
- }
473
-
474
- // Add reference before the closing section
475
- const newContent = content.trimEnd() + `\n\n## Additional Guidelines\n\nSee: additional-guidelines.md\n`;
476
- await writeFile(instructionsPath, newContent, 'utf-8');
477
- }
478
-
479
- async function appendToAntigravity(
480
- projectPath: string,
481
- guidelines: string[]
482
- ): Promise<void> {
483
- // Create rules directory
484
- const rulesDir = join(projectPath, '.agent', 'rules');
485
- await mkdir(rulesDir, { recursive: true });
486
-
487
- // Create additional rules file
488
- const additionalRulesPath = join(rulesDir, 'additional.md');
489
- const additionalContent = `# Additional Rules\n\n${guidelines.join('\n\n---\n\n')}\n\n---\n*Generated by aicgen*\n`;
490
-
491
- if (existsSync(additionalRulesPath)) {
492
- // Append to existing file
493
- await appendFile(additionalRulesPath, `\n\n---\n\n${guidelines.join('\n\n---\n\n')}`, 'utf-8');
494
- } else {
495
- // Create new file
496
- await writeFile(additionalRulesPath, additionalContent, 'utf-8');
497
- }
498
-
499
- // Update instructions.md with reference if not already present
500
- const instructionsPath = join(rulesDir, 'instructions.md');
501
- if (existsSync(instructionsPath)) {
502
- const content = await readFile(instructionsPath, 'utf-8');
503
-
504
- if (content.includes('@.agent/rules/additional.md')) {
505
- // Reference already exists
506
- return;
507
- }
508
-
509
- // Add reference to rule index section
510
- const ruleIndexMatch = content.match(/(## Rule Index[\s\S]*?)(?=\n## |$)/);
511
- if (ruleIndexMatch) {
512
- const ruleIndexSection = ruleIndexMatch[1];
513
- const newRuleIndexSection = ruleIndexSection.trimEnd() + '\n- **Additional**: @.agent/rules/additional.md';
514
- const newContent = content.replace(ruleIndexSection, newRuleIndexSection);
515
- await writeFile(instructionsPath, newContent, 'utf-8');
516
- } else {
517
- // Fallback: append to end
518
- const newContent = content.trimEnd() + '\n\n- **Additional**: @.agent/rules/additional.md\n';
519
- await writeFile(instructionsPath, newContent, 'utf-8');
520
- }
521
- }
522
- }
523
-
524
- async function appendToCodex(projectPath: string, guidelines: string[]): Promise<void> {
525
- const instructionsPath = join(projectPath, '.codex', 'instructions.md');
526
-
527
- if (!existsSync(instructionsPath)) {
528
- throw new Error('instructions.md not found');
529
- }
530
-
531
- // Create codex directory
532
- const codexDir = join(projectPath, '.codex');
533
- await mkdir(codexDir, { recursive: true });
534
-
535
- // Create additional guidelines file
536
- const additionalFile = join(codexDir, 'additional-guidelines.md');
537
- const additionalContent = `# Additional Guidelines\n\n${guidelines.join('\n\n---\n\n')}`;
538
-
539
- if (existsSync(additionalFile)) {
540
- // Append to existing file
541
- await appendFile(additionalFile, `\n\n---\n\n${guidelines.join('\n\n---\n\n')}`, 'utf-8');
542
- } else {
543
- // Create new file
544
- await writeFile(additionalFile, additionalContent, 'utf-8');
545
- }
546
-
547
- // Update instructions.md with import reference if not already present
548
- const content = await readFile(instructionsPath, 'utf-8');
549
-
550
- if (content.includes('additional-guidelines.md')) {
551
- // Reference already exists
552
- return;
553
- }
554
-
555
- // Add reference before the closing section
556
- const newContent = content.trimEnd() + `\n\n## Additional Guidelines\n\nSee: additional-guidelines.md\n`;
557
- await writeFile(instructionsPath, newContent, 'utf-8');
558
- }
559
-
560
- async function regenerateConfig(
561
- projectPath: string,
562
- existingConfig: ProfileSelection,
563
- additionalIds: string[],
564
- loader: GuidelineLoader
565
- ): Promise<void> {
566
- // Get existing guidelines + new ones
567
- const existingIds = loader.getGuidelinesForProfile(
568
- existingConfig.language,
569
- existingConfig.level,
570
- existingConfig.architecture,
571
- existingConfig.datasource
572
- );
573
-
574
- const allIds = [...new Set([...existingIds, ...additionalIds])];
575
-
576
- // Regenerate configuration with all guidelines
577
- const fileWriter = await AssistantFileWriter.create();
578
- const files = await fileWriter.generateFiles(
579
- existingConfig.assistant,
580
- allIds,
581
- existingConfig,
582
- projectPath
583
- );
584
-
585
- await fileWriter.writeFiles(files);
586
- }