@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,125 +0,0 @@
1
- import { describe, test, expect } from 'bun:test';
2
- import { CONFIG } from '../../config.js';
3
-
4
- describe('Tarball Extraction Configuration', () => {
5
- describe('CONFIG-based Prefix', () => {
6
- test('should have correct GitHub owner configured', () => {
7
- expect(CONFIG.GITHUB_REPO_OWNER).toBe('aicgen');
8
- });
9
-
10
- test('should have correct GitHub repo configured', () => {
11
- expect(CONFIG.GITHUB_REPO_NAME).toBe('aicgen-data');
12
- });
13
-
14
- test('should construct correct expected prefix', () => {
15
- const expectedPrefix = `${CONFIG.GITHUB_REPO_OWNER}-${CONFIG.GITHUB_REPO_NAME}-`;
16
- expect(expectedPrefix).toBe('aicgen-aicgen-data-');
17
- });
18
-
19
- test('should not use hardcoded lpsandaruwan prefix', () => {
20
- const expectedPrefix = `${CONFIG.GITHUB_REPO_OWNER}-${CONFIG.GITHUB_REPO_NAME}-`;
21
- expect(expectedPrefix).not.toBe('lpsandaruwan-aicgen-docs-');
22
- });
23
- });
24
-
25
- describe('Directory Name Matching', () => {
26
- test('should match correct tarball directory format', () => {
27
- const expectedPrefix = `${CONFIG.GITHUB_REPO_OWNER}-${CONFIG.GITHUB_REPO_NAME}-`;
28
- const sampleDirectories = [
29
- 'aicgen-aicgen-data-abc123',
30
- 'aicgen-aicgen-data-def456',
31
- 'aicgen-aicgen-data-1234567890abcdef'
32
- ];
33
-
34
- sampleDirectories.forEach(dir => {
35
- expect(dir.startsWith(expectedPrefix)).toBe(true);
36
- });
37
- });
38
-
39
- test('should not match incorrect directory formats', () => {
40
- const expectedPrefix = `${CONFIG.GITHUB_REPO_OWNER}-${CONFIG.GITHUB_REPO_NAME}-`;
41
- const incorrectDirectories = [
42
- 'lpsandaruwan-aicgen-docs-abc123',
43
- 'other-repo-abc123',
44
- 'random-directory'
45
- ];
46
-
47
- incorrectDirectories.forEach(dir => {
48
- expect(dir.startsWith(expectedPrefix)).toBe(false);
49
- });
50
- });
51
-
52
- test('should find correct directory in mixed entries', () => {
53
- const expectedPrefix = `${CONFIG.GITHUB_REPO_OWNER}-${CONFIG.GITHUB_REPO_NAME}-`;
54
- const entries = [
55
- 'archive.tar.gz',
56
- 'aicgen-aicgen-data-abc123',
57
- 'other-file.md',
58
- '.temp'
59
- ];
60
-
61
- const rootDir = entries.find(entry => entry.startsWith(expectedPrefix));
62
- expect(rootDir).toBe('aicgen-aicgen-data-abc123');
63
- });
64
- });
65
-
66
- describe('GitHub API URLs', () => {
67
- test('should construct correct releases URL', () => {
68
- const repoUrl = `${CONFIG.GITHUB_API_BASE}/repos/${CONFIG.GITHUB_REPO_OWNER}/${CONFIG.GITHUB_REPO_NAME}`;
69
- expect(repoUrl).toBe('https://api.github.com/repos/aicgen/aicgen-data');
70
- });
71
-
72
- test('should construct correct releases latest URL', () => {
73
- const releasesUrl = `${CONFIG.GITHUB_API_BASE}/repos/${CONFIG.GITHUB_REPO_OWNER}/${CONFIG.GITHUB_REPO_NAME}/releases/latest`;
74
- expect(releasesUrl).toBe('https://api.github.com/repos/aicgen/aicgen-data/releases/latest');
75
- });
76
- });
77
-
78
- describe('Cache Directory Structure', () => {
79
- test('should have correct cache directory name', () => {
80
- expect(CONFIG.CACHE_DIR_NAME).toBe('.aicgen');
81
- });
82
-
83
- test('should have correct data directory name', () => {
84
- expect(CONFIG.DATA_DIR).toBe('data');
85
- });
86
-
87
- test('should have correct cache subdirectory', () => {
88
- expect(CONFIG.CACHE_DIR).toBe('cache/official');
89
- });
90
- });
91
-
92
- describe('Version Management', () => {
93
- test('should have valid version format', () => {
94
- const version = CONFIG.APP_VERSION;
95
- // Valid version: X.Y.Z-prerelease or X.Y-prerelease (e.g., "1.0.0-beta.1" or "1.0-beta")
96
- const versionPattern = /^\d+\.\d+(\.\d+)?(-[a-z0-9.]+)?$/i;
97
- expect(versionPattern.test(version)).toBe(true);
98
- });
99
-
100
- test('should not have invalid version patterns', () => {
101
- const version = CONFIG.APP_VERSION;
102
- // Should not match invalid patterns like "0.1.0b1" or "0.1b"
103
- expect(version).not.toMatch(/\d+\.\d+\.\d+b\d*/);
104
- expect(version).not.toMatch(/\d+b$/);
105
- });
106
- });
107
-
108
- describe('Environment Variable Override', () => {
109
- test('should allow GitHub owner override via env', () => {
110
- // This tests that the priority system exists (ENV > Config > Default)
111
- // Actual override would need to be tested in integration tests
112
- const hasEnvSupport = CONFIG.GITHUB_REPO_OWNER === (
113
- process.env.AICGEN_GITHUB_OWNER || 'aicgen'
114
- );
115
- expect(hasEnvSupport).toBe(true);
116
- });
117
-
118
- test('should allow GitHub repo override via env', () => {
119
- const hasEnvSupport = CONFIG.GITHUB_REPO_NAME === (
120
- process.env.AICGEN_GITHUB_REPO || 'aicgen-data'
121
- );
122
- expect(hasEnvSupport).toBe(true);
123
- });
124
- });
125
- });
@@ -1,296 +0,0 @@
1
- import { select, input, checkbox, confirm, editor } from '@inquirer/prompts';
2
- import chalk from 'chalk';
3
- import { homedir } from 'os';
4
- import { join, dirname } from 'path';
5
- import { mkdir, writeFile, readFile, access } from 'fs/promises';
6
- import YAML from 'yaml';
7
- import { GuidelineLoader, GuidelineMapping } from '../services/guideline-loader.js';
8
- import { showBanner } from '../utils/banner.js';
9
- import { createSummaryBox } from '../utils/formatting.js';
10
- import { Language } from '../models/project.js';
11
- import { InstructionLevel, ArchitectureType } from '../models/profile.js';
12
- import { CONFIG } from '../config.js';
13
-
14
-
15
- const LANGUAGES: { value: Language; name: string }[] = [
16
- { value: 'typescript', name: 'TypeScript' },
17
- { value: 'javascript', name: 'JavaScript' },
18
- { value: 'python', name: 'Python' },
19
- { value: 'go', name: 'Go' },
20
- { value: 'rust', name: 'Rust' },
21
- { value: 'java', name: 'Java' },
22
- { value: 'csharp', name: 'C#' },
23
- { value: 'ruby', name: 'Ruby' }
24
- ];
25
-
26
- const LEVELS: { value: InstructionLevel; name: string }[] = [
27
- { value: 'basic', name: 'Basic' },
28
- { value: 'standard', name: 'Standard' },
29
- { value: 'expert', name: 'Expert' },
30
- { value: 'full', name: 'Full' }
31
- ];
32
-
33
- const ARCHITECTURES: { value: ArchitectureType; name: string }[] = [
34
- { value: 'layered', name: 'Layered' },
35
- { value: 'modular-monolith', name: 'Modular Monolith' },
36
- { value: 'microservices', name: 'Microservices' },
37
- { value: 'event-driven', name: 'Event-Driven' },
38
- { value: 'hexagonal', name: 'Hexagonal' },
39
- { value: 'clean-architecture', name: 'Clean Architecture' },
40
- { value: 'ddd', name: 'Domain-Driven Design' },
41
- { value: 'serverless', name: 'Serverless' },
42
- { value: 'other', name: 'Other / None' }
43
- ];
44
-
45
- export async function addGuidelineCommand() {
46
- showBanner();
47
-
48
- console.log(chalk.cyan('\n📝 Add Custom Guideline\n'));
49
-
50
- try {
51
- // 1. Load existing guidelines to show categories
52
- const loader = await GuidelineLoader.create();
53
- const stats = loader.getStats();
54
- const existingCategories = Object.keys(stats.byCategory).sort();
55
-
56
- // 2. Select or create category
57
- const categoryChoice = await select({
58
- message: 'Select category:',
59
- choices: [
60
- { value: '__new__', name: chalk.green('+ Create new category') },
61
- { value: '__separator__', name: chalk.gray('─'.repeat(50)), disabled: true },
62
- ...existingCategories.map(c => ({ value: c, name: c })),
63
- { value: 'cancel', name: 'Cancel', description: 'Exit' }
64
- ]
65
- });
66
-
67
- if (categoryChoice === 'cancel') {
68
- console.log(chalk.gray('\nCancelled.'));
69
- return;
70
- }
71
-
72
- let category: string;
73
- if (categoryChoice === '__new__') {
74
- category = await input({
75
- message: 'Category name:',
76
- validate: (value) => {
77
- if (!value.trim()) return 'Category name is required';
78
- if (value.length > 50) return 'Category name too long (max 50 characters)';
79
- return true;
80
- }
81
- });
82
- } else {
83
- category = categoryChoice;
84
- }
85
-
86
- // 3. Guideline details
87
- const name = await input({
88
- message: 'Guideline name:',
89
- validate: (value) => {
90
- if (!value.trim()) return 'Name is required';
91
- if (value.length > 100) return 'Name too long (max 100 characters)';
92
- return true;
93
- }
94
- });
95
-
96
- const description = await input({
97
- message: 'Short description (optional):',
98
- default: ''
99
- });
100
-
101
- // 4. Applicability - Languages
102
- const languageChoice = await select({
103
- message: 'Applicable to languages:',
104
- choices: [
105
- { value: 'all', name: 'All languages' },
106
- { value: 'specific', name: 'Specific languages only' }
107
- ]
108
- });
109
-
110
- let languages: Language[] = [];
111
- if (languageChoice === 'specific') {
112
- languages = await checkbox({
113
- message: 'Select languages:',
114
- choices: LANGUAGES.map(l => ({ value: l.value, name: l.name }))
115
- }) as Language[];
116
-
117
- if (languages.length === 0) {
118
- console.log(chalk.yellow('\n⚠️ No languages selected, applying to all languages'));
119
- }
120
- }
121
-
122
- // 5. Applicability - Levels
123
- const levels = await checkbox({
124
- message: 'Applicable to instruction levels:',
125
- choices: LEVELS.map(l => ({ value: l.value, name: l.name, checked: true }))
126
- }) as InstructionLevel[];
127
-
128
- if (levels.length === 0) {
129
- console.log(chalk.yellow('\n⚠️ No levels selected, using all levels'));
130
- levels.push('basic', 'standard', 'expert', 'full');
131
- }
132
-
133
- // 6. Applicability - Architectures
134
- const architectureChoice = await select({
135
- message: 'Applicable to architectures:',
136
- choices: [
137
- { value: 'all', name: 'All architectures' },
138
- { value: 'specific', name: 'Specific architectures only' }
139
- ]
140
- });
141
-
142
- let architectures: ArchitectureType[] = [];
143
- if (architectureChoice === 'specific') {
144
- architectures = await checkbox({
145
- message: 'Select architectures:',
146
- choices: ARCHITECTURES.map(a => ({ value: a.value, name: a.name }))
147
- }) as ArchitectureType[];
148
-
149
- if (architectures.length === 0) {
150
- console.log(chalk.yellow('\n⚠️ No architectures selected, applying to all'));
151
- }
152
- }
153
-
154
- // 7. Tags
155
- const tagsInput = await input({
156
- message: 'Tags (comma-separated, optional):',
157
- default: ''
158
- });
159
-
160
- const tags = tagsInput
161
- ? tagsInput.split(',').map(t => t.trim()).filter(t => t.length > 0)
162
- : [];
163
-
164
- // 8. Content
165
- console.log(chalk.cyan('\n📄 Guideline Content\n'));
166
-
167
- const contentChoice = await select({
168
- message: 'How to provide content?',
169
- choices: [
170
- { value: 'editor', name: 'Open in default editor (recommended)', description: 'Uses $EDITOR or default system editor' },
171
- { value: 'file', name: 'Import from file', description: 'Copy content from existing markdown file' },
172
- { value: 'inline', name: 'Type inline', description: 'For short content only' }
173
- ]
174
- });
175
-
176
- let content: string;
177
- switch (contentChoice) {
178
- case 'file': {
179
- const filePath = await input({
180
- message: 'File path:',
181
- validate: async (value) => {
182
- try {
183
- await access(value);
184
- return true;
185
- } catch {
186
- return 'File not found';
187
- }
188
- }
189
- });
190
- content = await readFile(filePath, 'utf-8');
191
- break;
192
- }
193
-
194
- case 'editor':
195
- content = await editor({
196
- message: 'Write your guideline (will open in editor):',
197
- default: `# ${name}\n\n${description ? description + '\n\n' : ''}## Overview\n\nWrite your guideline content here...\n\n## Examples\n\n\`\`\`\n// Code examples\n\`\`\`\n\n## Best Practices\n\n- Point 1\n- Point 2\n`
198
- });
199
- break;
200
-
201
- case 'inline':
202
- content = await editor({
203
- message: 'Content (markdown):',
204
- default: `# ${name}\n\n`
205
- });
206
- break;
207
-
208
- default:
209
- content = '';
210
- }
211
-
212
- if (!content.trim()) {
213
- console.log(chalk.red('\n❌ Content cannot be empty'));
214
- return;
215
- }
216
-
217
- // 9. Generate ID and paths
218
- const id = generateGuidelineId(category, name);
219
- const categorySlug = category.toLowerCase().replace(/\s+/g, '-');
220
- const nameSlug = name.toLowerCase().replace(/[^a-z0-9]+/g, '-');
221
- const relativePath = `${categorySlug}/${nameSlug}.md`;
222
-
223
- // 10. Show preview
224
- console.log('\n' + createSummaryBox('📋 Guideline Preview', [
225
- { label: 'ID', value: id },
226
- { label: 'Category', value: category },
227
- { label: 'Name', value: name },
228
- { label: 'Path', value: relativePath },
229
- { label: 'Languages', value: languages.length > 0 ? languages.join(', ') : 'All' },
230
- { label: 'Levels', value: levels.join(', ') },
231
- { label: 'Architectures', value: architectures.length > 0 ? architectures.join(', ') : 'All' },
232
- { label: 'Tags', value: tags.length > 0 ? tags.join(', ') : 'None' },
233
- { label: 'Size', value: `${content.length} characters, ${content.split('\n').length} lines` }
234
- ]));
235
-
236
- const shouldAdd = await confirm({
237
- message: 'Add this guideline?',
238
- default: true
239
- });
240
-
241
- if (!shouldAdd) {
242
- console.log(chalk.gray('\nCancelled.'));
243
- return;
244
- }
245
-
246
- // 11. Write files
247
- const userDataPath = join(homedir(), CONFIG.CACHE_DIR_NAME, CONFIG.DATA_DIR);
248
- const guidelinePath = join(userDataPath, 'guidelines', relativePath);
249
- const mappingsPath = join(userDataPath, 'custom-mappings.yml');
250
-
251
- // Ensure directories exist
252
- await mkdir(dirname(guidelinePath), { recursive: true });
253
-
254
- // Write guideline content
255
- await writeFile(guidelinePath, content, 'utf-8');
256
-
257
- // Update mappings
258
- let mappings: Record<string, GuidelineMapping> = {};
259
- try {
260
- const mappingsContent = await readFile(mappingsPath, 'utf-8');
261
- mappings = YAML.parse(mappingsContent) as Record<string, GuidelineMapping>;
262
- } catch {
263
- // File doesn't exist yet, start with empty mappings
264
- }
265
-
266
- mappings[id] = {
267
- path: relativePath,
268
- category,
269
- ...(languages.length > 0 && { languages }),
270
- levels,
271
- ...(architectures.length > 0 && { architectures }),
272
- ...(tags.length > 0 && { tags })
273
- };
274
-
275
- await writeFile(mappingsPath, YAML.stringify(mappings), 'utf-8');
276
-
277
- console.log(chalk.green('\n✅ Guideline added successfully!'));
278
- console.log(chalk.gray(`\n Guideline: ${guidelinePath}`));
279
- console.log(chalk.gray(` Mapping: ${mappingsPath}`));
280
- console.log(chalk.cyan(`\n Run ${chalk.white('aicgen init')} to use your custom guideline`));
281
-
282
- } catch (error) {
283
- if ((error as Error).message.includes('User force closed')) {
284
- console.log(chalk.gray('\n\nCancelled.'));
285
- return;
286
- }
287
- console.error(chalk.red(`\n❌ ${(error as Error).message}`));
288
- process.exit(1);
289
- }
290
- }
291
-
292
- function generateGuidelineId(category: string, name: string): string {
293
- const categorySlug = category.toLowerCase().replace(/\s+/g, '-');
294
- const nameSlug = name.toLowerCase().replace(/[^a-z0-9]+/g, '-');
295
- return `custom-${categorySlug}-${nameSlug}`;
296
- }
@@ -1,61 +0,0 @@
1
- import { confirm } from '@inquirer/prompts';
2
- import chalk from 'chalk';
3
- import { rm } from 'fs/promises';
4
- import { join } from 'path';
5
- import { existsSync } from 'fs';
6
-
7
- export async function clearCommand(options: { force?: boolean } = {}) {
8
- const projectPath = process.cwd();
9
-
10
- // Define all possible config directories
11
- const configDirs = [
12
- { path: '.claude', name: 'Claude Code' },
13
- { path: '.github/copilot-instructions.md', name: 'GitHub Copilot', isFile: true },
14
- { path: '.gemini', name: 'Google Gemini' },
15
- { path: '.agent', name: 'Google Antigravity' },
16
- { path: '.codex', name: 'Codex' },
17
- { path: 'AGENTS.md', name: 'Universal AGENTS.md', isFile: true }
18
- ];
19
-
20
- // Find which configs exist
21
- const existingConfigs = configDirs.filter(dir =>
22
- existsSync(join(projectPath, dir.path))
23
- );
24
-
25
- if (existingConfigs.length === 0) {
26
- console.log(chalk.gray('\nNo AI configurations found in this project.'));
27
- return;
28
- }
29
-
30
- console.log(chalk.cyan('\n📂 Found AI Configurations:'));
31
- existingConfigs.forEach(config => {
32
- console.log(` • ${config.name} (${config.path})`);
33
- });
34
-
35
- if (!options.force) {
36
- const shouldDelete = await confirm({
37
- message: chalk.yellow('\n⚠️ Delete all AI configurations?'),
38
- default: false
39
- });
40
-
41
- if (!shouldDelete) {
42
- console.log(chalk.gray('\nCancelled.'));
43
- return;
44
- }
45
- }
46
-
47
- // Delete configs
48
- let deletedCount = 0;
49
- for (const config of existingConfigs) {
50
- try {
51
- const fullPath = join(projectPath, config.path);
52
- await rm(fullPath, { recursive: true, force: true });
53
- console.log(chalk.green(`✓ Removed ${config.name}`));
54
- deletedCount++;
55
- } catch (error) {
56
- console.log(chalk.red(`✗ Failed to remove ${config.name}: ${error}`));
57
- }
58
- }
59
-
60
- console.log(chalk.green(`\n✅ Cleared ${deletedCount} configuration(s)`));
61
- }
@@ -1,123 +0,0 @@
1
- import { checkbox } from '@inquirer/prompts';
2
- import chalk from 'chalk';
3
- import { Language } from '../models/project.js';
4
- import { InstructionLevel, ArchitectureType, DatasourceType } from '../models/profile.js';
5
- import { GuidelineLoader } from '../services/guideline-loader.js';
6
- import { showCheckboxInstructions } from '../utils/banner.js';
7
- import { BACK_VALUE } from '../utils/wizard-state.js';
8
-
9
- interface CheckboxChoice {
10
- name: string;
11
- value: string;
12
- checked?: boolean;
13
- disabled?: boolean | string;
14
- }
15
-
16
- export async function selectGuidelines(
17
- language: Language,
18
- level: InstructionLevel,
19
- architecture: ArchitectureType,
20
- canGoBack: boolean,
21
- datasource?: DatasourceType
22
- ): Promise<string[] | typeof BACK_VALUE> {
23
- const loader = await GuidelineLoader.create();
24
- const categoryTree = loader.getCategoryTree(language, level, architecture, datasource);
25
-
26
- console.log(chalk.cyan('\n📚 Select Guidelines'));
27
- showCheckboxInstructions();
28
-
29
- const allGuidelineIds: string[] = [];
30
- const categoryToGuidelines = new Map<string, string[]>();
31
- const choices: CheckboxChoice[] = [];
32
-
33
- // Add back option if applicable
34
- if (canGoBack) {
35
- choices.push({
36
- name: chalk.gray('← Back to previous step'),
37
- value: BACK_VALUE,
38
- checked: false
39
- });
40
- choices.push({
41
- name: chalk.gray('─'.repeat(50)),
42
- value: '__SEPARATOR__',
43
- disabled: true
44
- });
45
- }
46
-
47
- // Build choices with categories and guidelines
48
- for (const category of categoryTree) {
49
- const categoryKey = `category:${category.name}`;
50
- const guidelineIds: string[] = [];
51
-
52
- // Category header
53
- choices.push({
54
- name: chalk.bold.cyan(`${category.name} (${category.count} guidelines)`),
55
- value: categoryKey,
56
- checked: true
57
- });
58
-
59
- // Guidelines under category
60
- for (const guideline of category.guidelines) {
61
- allGuidelineIds.push(guideline.id);
62
- guidelineIds.push(guideline.id);
63
- choices.push({
64
- name: ` ${guideline.name}`,
65
- value: guideline.id,
66
- checked: true
67
- });
68
- }
69
-
70
- categoryToGuidelines.set(categoryKey, guidelineIds);
71
- }
72
-
73
- let selected = await checkbox({
74
- message: 'Select guidelines to include (Space to toggle, Enter to confirm):',
75
- choices,
76
- pageSize: 25,
77
- loop: false
78
- }) as string[];
79
-
80
- // Handle back selection
81
- if (selected.includes(BACK_VALUE)) {
82
- return BACK_VALUE;
83
- }
84
-
85
- // Filter out separator
86
- selected = selected.filter(s => s !== '__SEPARATOR__');
87
-
88
- // Smart category-child sync
89
- const categories = Array.from(categoryToGuidelines.keys());
90
- const selectedCategories = selected.filter(s => s.startsWith('category:'));
91
- const selectedGuidelines = selected.filter(s => !s.startsWith('category:'));
92
-
93
- const finalGuidelines = new Set<string>();
94
-
95
- for (const category of categories) {
96
- const guidelinesInCategory = categoryToGuidelines.get(category) || [];
97
- const isCategorySelected = selectedCategories.includes(category);
98
-
99
- if (isCategorySelected) {
100
- // Category is checked → include ALL guidelines in that category
101
- guidelinesInCategory.forEach(g => finalGuidelines.add(g));
102
- } else {
103
- // Category is NOT checked → include only individually selected guidelines
104
- guidelinesInCategory.forEach(g => {
105
- if (selectedGuidelines.includes(g)) {
106
- finalGuidelines.add(g);
107
- }
108
- });
109
- }
110
- }
111
-
112
- const result = Array.from(finalGuidelines);
113
-
114
- if (result.length === 0) {
115
- console.log(chalk.yellow('\n⚠️ No guidelines selected. Using all available guidelines.'));
116
- return allGuidelineIds;
117
- }
118
-
119
- // Show selection summary
120
- console.log(chalk.cyan(`\n✓ Selected ${result.length} of ${allGuidelineIds.length} guidelines`));
121
-
122
- return result;
123
- }