@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,400 +0,0 @@
1
- import { describe, test, expect, beforeAll } from 'bun:test';
2
- import { AssistantFileWriter } from '../../services/assistant-file-writer.js';
3
- import { GuidelineLoader } from '../../services/guideline-loader.js';
4
- import type { ProfileSelection } from '../../models/profile.js';
5
-
6
- describe('AssistantFileWriter', () => {
7
- let writer: AssistantFileWriter;
8
- let loader: GuidelineLoader;
9
- const testSelection: ProfileSelection = {
10
- assistant: 'claude-code',
11
- language: 'typescript',
12
- level: 'standard',
13
- architecture: 'microservices',
14
- projectType: 'api',
15
- projectName: 'test-project',
16
- datasource: 'sql'
17
- };
18
-
19
- beforeAll(async () => {
20
- writer = await AssistantFileWriter.create();
21
- loader = await GuidelineLoader.create();
22
- });
23
-
24
- describe('Claude Code Files', () => {
25
- test('should generate files for Claude Code', async () => {
26
- const guidelineIds = loader.getGuidelinesForProfile(
27
- testSelection.language,
28
- testSelection.level,
29
- testSelection.architecture,
30
- testSelection.datasource
31
- );
32
-
33
- const files = await writer.generateFiles(
34
- 'claude-code',
35
- guidelineIds,
36
- testSelection,
37
- '/test/path'
38
- );
39
-
40
- expect(files.length).toBeGreaterThan(0);
41
- expect(files.some(f => f.path.endsWith('CLAUDE.md'))).toBe(true);
42
- expect(files.some(f => f.path.includes('.claude') && f.path.includes('guidelines'))).toBe(true);
43
- expect(files.some(f => f.path.endsWith('settings.json'))).toBe(true);
44
- });
45
-
46
- test('should create separate guideline files by category', async () => {
47
- const guidelineIds = loader.getGuidelinesForProfile(
48
- testSelection.language,
49
- testSelection.level,
50
- testSelection.architecture,
51
- testSelection.datasource
52
- );
53
-
54
- const files = await writer.generateFiles(
55
- 'claude-code',
56
- guidelineIds,
57
- testSelection,
58
- '/test/path'
59
- );
60
-
61
- const guidelineFiles = files.filter(f => f.type === 'guideline');
62
- expect(guidelineFiles.length).toBeGreaterThan(0);
63
-
64
- // Should have files like language.md, architecture.md, etc.
65
- expect(guidelineFiles.some(f => f.path.includes('language.md'))).toBe(true);
66
- });
67
-
68
- test('should create CLAUDE.md with references not content', async () => {
69
- const guidelineIds = loader.getGuidelinesForProfile(
70
- testSelection.language,
71
- testSelection.level,
72
- testSelection.architecture,
73
- testSelection.datasource
74
- );
75
-
76
- const files = await writer.generateFiles(
77
- 'claude-code',
78
- guidelineIds,
79
- testSelection,
80
- '/test/path'
81
- );
82
-
83
- const claudeFile = files.find(f => f.path.includes('CLAUDE.md'));
84
- expect(claudeFile).toBeDefined();
85
- expect(claudeFile!.content).toContain('@.claude/guidelines/');
86
- expect(claudeFile!.content).toContain('## Guidelines');
87
- });
88
-
89
- test('should concatenate guidelines within each category file', async () => {
90
- const guidelineIds = loader.getGuidelinesForProfile(
91
- testSelection.language,
92
- 'full', // Use full to get more guidelines
93
- testSelection.architecture,
94
- testSelection.datasource
95
- );
96
-
97
- const files = await writer.generateFiles(
98
- 'claude-code',
99
- guidelineIds,
100
- { ...testSelection, level: 'full' },
101
- '/test/path'
102
- );
103
-
104
- const languageFile = files.find(f => f.path.includes('language.md'));
105
- expect(languageFile).toBeDefined();
106
- expect(languageFile!.content).toContain('---'); // Separator between guidelines
107
- });
108
- });
109
-
110
- describe('Copilot Files', () => {
111
- test('should generate files for GitHub Copilot', async () => {
112
- const guidelineIds = loader.getGuidelinesForProfile(
113
- testSelection.language,
114
- testSelection.level,
115
- testSelection.architecture,
116
- testSelection.datasource
117
- );
118
-
119
- const files = await writer.generateFiles(
120
- 'copilot',
121
- guidelineIds,
122
- { ...testSelection, assistant: 'copilot' },
123
- '/test/path'
124
- );
125
-
126
- expect(files.length).toBeGreaterThan(0);
127
- expect(files.some(f => f.path.includes('copilot-instructions.md'))).toBe(true);
128
- expect(files.some(f => f.path.includes('.github') && f.path.includes('instructions'))).toBe(true);
129
- });
130
-
131
- test('should create instruction files with frontmatter', async () => {
132
- const guidelineIds = loader.getGuidelinesForProfile(
133
- testSelection.language,
134
- testSelection.level,
135
- testSelection.architecture,
136
- testSelection.datasource
137
- );
138
-
139
- const files = await writer.generateFiles(
140
- 'copilot',
141
- guidelineIds,
142
- { ...testSelection, assistant: 'copilot' },
143
- '/test/path'
144
- );
145
-
146
- const instructionFile = files.find(f =>
147
- f.path.includes('.github') && f.path.includes('instructions') && f.path.endsWith('.instructions.md')
148
- );
149
- expect(instructionFile).toBeDefined();
150
- expect(instructionFile!.content).toContain('---\napplyTo:');
151
- expect(instructionFile!.content).toContain('description:');
152
- });
153
- });
154
-
155
- describe('Gemini Files', () => {
156
- test('should generate single instructions file for Gemini', async () => {
157
- const guidelineIds = loader.getGuidelinesForProfile(
158
- testSelection.language,
159
- testSelection.level,
160
- testSelection.architecture,
161
- testSelection.datasource
162
- );
163
-
164
- const files = await writer.generateFiles(
165
- 'gemini',
166
- guidelineIds,
167
- { ...testSelection, assistant: 'gemini' },
168
- '/test/path'
169
- );
170
-
171
- expect(files.length).toBe(2); // instructions.md + AGENTS.md
172
- expect(files.some(f => f.path.includes('.gemini') && f.path.includes('instructions.md'))).toBe(true);
173
- });
174
-
175
- test('should inline all guidelines in Gemini file', async () => {
176
- const guidelineIds = loader.getGuidelinesForProfile(
177
- testSelection.language,
178
- testSelection.level,
179
- testSelection.architecture,
180
- testSelection.datasource
181
- );
182
-
183
- const files = await writer.generateFiles(
184
- 'gemini',
185
- guidelineIds,
186
- { ...testSelection, assistant: 'gemini' },
187
- '/test/path'
188
- );
189
-
190
- const geminiFile = files.find(f => f.path.includes('.gemini') && f.path.includes('instructions.md'));
191
- expect(geminiFile).toBeDefined();
192
- expect(geminiFile!.content).toContain('## Language');
193
- expect(geminiFile!.content).toContain('---'); // Category separators
194
- });
195
- });
196
-
197
- describe('Antigravity Files', () => {
198
- test('should generate files for Antigravity', async () => {
199
- const guidelineIds = loader.getGuidelinesForProfile(
200
- testSelection.language,
201
- testSelection.level,
202
- testSelection.architecture,
203
- testSelection.datasource
204
- );
205
-
206
- const files = await writer.generateFiles(
207
- 'antigravity',
208
- guidelineIds,
209
- { ...testSelection, assistant: 'antigravity' },
210
- '/test/path'
211
- );
212
-
213
- expect(files.length).toBeGreaterThan(0);
214
- expect(files.some(f => f.path.includes('.agent') && f.path.includes('rules') && f.path.includes('instructions.md'))).toBe(true);
215
- expect(files.some(f => f.path.includes('.agent') && f.path.includes('rules') && !f.path.includes('instructions.md'))).toBe(true);
216
- expect(files.some(f => f.path.includes('.agent') && f.path.includes('workflows'))).toBe(true);
217
- });
218
-
219
- test('should create workflow files based on level', async () => {
220
- const guidelineIds = loader.getGuidelinesForProfile(
221
- testSelection.language,
222
- 'expert',
223
- testSelection.architecture,
224
- testSelection.datasource
225
- );
226
-
227
- const files = await writer.generateFiles(
228
- 'antigravity',
229
- guidelineIds,
230
- { ...testSelection, assistant: 'antigravity', level: 'expert' },
231
- '/test/path'
232
- );
233
-
234
- const workflowFiles = files.filter(f => f.path.includes('.agent') && f.path.includes('workflows'));
235
- expect(workflowFiles.length).toBeGreaterThan(2); // Expert should have more workflows
236
- });
237
-
238
- test('should create rule index with references', async () => {
239
- const guidelineIds = loader.getGuidelinesForProfile(
240
- testSelection.language,
241
- testSelection.level,
242
- testSelection.architecture,
243
- testSelection.datasource
244
- );
245
-
246
- const files = await writer.generateFiles(
247
- 'antigravity',
248
- guidelineIds,
249
- { ...testSelection, assistant: 'antigravity' },
250
- '/test/path'
251
- );
252
-
253
- const instructionsFile = files.find(f => f.path.includes('.agent') && f.path.includes('rules') && f.path.includes('instructions.md'));
254
- expect(instructionsFile).toBeDefined();
255
- expect(instructionsFile!.content).toContain('## Rule Index');
256
- expect(instructionsFile!.content).toContain('@.agent/rules/');
257
- });
258
- });
259
-
260
- describe('Codex Files', () => {
261
- test('should generate single instructions file for Codex', async () => {
262
- const guidelineIds = loader.getGuidelinesForProfile(
263
- testSelection.language,
264
- testSelection.level,
265
- testSelection.architecture,
266
- testSelection.datasource
267
- );
268
-
269
- const files = await writer.generateFiles(
270
- 'codex',
271
- guidelineIds,
272
- { ...testSelection, assistant: 'codex' },
273
- '/test/path'
274
- );
275
-
276
- expect(files.length).toBe(2); // instructions.md + AGENTS.md
277
- expect(files.some(f => f.path.includes('.codex') && f.path.includes('instructions.md'))).toBe(true);
278
- });
279
- });
280
-
281
- describe('Universal AGENTS.md', () => {
282
- test('should generate AGENTS.md for all assistants', async () => {
283
- const guidelineIds = loader.getGuidelinesForProfile(
284
- testSelection.language,
285
- testSelection.level,
286
- testSelection.architecture,
287
- testSelection.datasource
288
- );
289
-
290
- const assistants: Array<'claude-code' | 'copilot' | 'gemini' | 'antigravity' | 'codex'> = [
291
- 'claude-code',
292
- 'copilot',
293
- 'gemini',
294
- 'antigravity',
295
- 'codex'
296
- ];
297
-
298
- for (const assistant of assistants) {
299
- const files = await writer.generateFiles(
300
- assistant,
301
- guidelineIds,
302
- { ...testSelection, assistant },
303
- '/test/path'
304
- );
305
-
306
- const agentsFile = files.find(f => f.path.includes('AGENTS.md'));
307
- expect(agentsFile).toBeDefined();
308
- expect(agentsFile!.type).toBe('universal');
309
- expect(agentsFile!.content).toContain('## Project Overview');
310
- }
311
- });
312
- });
313
-
314
- describe('File Paths', () => {
315
- test('should prepend project path to all file paths', async () => {
316
- const guidelineIds = loader.getGuidelinesForProfile(
317
- testSelection.language,
318
- testSelection.level,
319
- testSelection.architecture,
320
- testSelection.datasource
321
- );
322
-
323
- const files = await writer.generateFiles(
324
- 'claude-code',
325
- guidelineIds,
326
- testSelection,
327
- '/custom/project/path'
328
- );
329
-
330
- files.forEach(file => {
331
- // On Windows, paths will be normalized to use backslashes
332
- expect(file.path.includes('custom') && file.path.includes('project')).toBe(true);
333
- });
334
- });
335
- });
336
-
337
- describe('Content Validation', () => {
338
- test('all generated files should have non-empty content', async () => {
339
- const guidelineIds = loader.getGuidelinesForProfile(
340
- testSelection.language,
341
- testSelection.level,
342
- testSelection.architecture,
343
- testSelection.datasource
344
- );
345
-
346
- const files = await writer.generateFiles(
347
- 'claude-code',
348
- guidelineIds,
349
- testSelection,
350
- '/test/path'
351
- );
352
-
353
- files.forEach(file => {
354
- expect(file.content.length).toBeGreaterThan(0);
355
- expect(file.path.length).toBeGreaterThan(0);
356
- });
357
- });
358
-
359
- test('should include project name in main files', async () => {
360
- const guidelineIds = loader.getGuidelinesForProfile(
361
- testSelection.language,
362
- testSelection.level,
363
- testSelection.architecture,
364
- testSelection.datasource
365
- );
366
-
367
- const files = await writer.generateFiles(
368
- 'claude-code',
369
- guidelineIds,
370
- testSelection,
371
- '/test/path'
372
- );
373
-
374
- const claudeFile = files.find(f => f.type === 'main');
375
- expect(claudeFile).toBeDefined();
376
- expect(claudeFile!.content).toContain(testSelection.projectName);
377
- });
378
-
379
- test('should include language and architecture in main files', async () => {
380
- const guidelineIds = loader.getGuidelinesForProfile(
381
- testSelection.language,
382
- testSelection.level,
383
- testSelection.architecture,
384
- testSelection.datasource
385
- );
386
-
387
- const files = await writer.generateFiles(
388
- 'claude-code',
389
- guidelineIds,
390
- testSelection,
391
- '/test/path'
392
- );
393
-
394
- const claudeFile = files.find(f => f.type === 'main');
395
- expect(claudeFile).toBeDefined();
396
- expect(claudeFile!.content).toContain(testSelection.language);
397
- expect(claudeFile!.content).toContain(testSelection.architecture);
398
- });
399
- });
400
- });
@@ -1,281 +0,0 @@
1
- import { describe, test, expect, beforeAll } from 'bun:test';
2
- import { GuidelineLoader } from '../../services/guideline-loader.js';
3
- import type { Language, InstructionLevel, ArchitectureType, DatasourceType } from '../../models/profile.js';
4
-
5
- describe('GuidelineLoader', () => {
6
- let loader: GuidelineLoader;
7
-
8
- beforeAll(async () => {
9
- loader = await GuidelineLoader.create();
10
- });
11
-
12
- describe('Initialization', () => {
13
- test('should load embedded guidelines', async () => {
14
- expect(loader).toBeDefined();
15
- const stats = loader.getStats();
16
- expect(stats.totalGuidelines).toBeGreaterThan(0);
17
- });
18
-
19
- test('should have correct guideline count', async () => {
20
- const stats = loader.getStats();
21
- expect(stats.totalGuidelines).toBe(82);
22
- });
23
-
24
- test('should have expected categories', async () => {
25
- const stats = loader.getStats();
26
- expect(stats.byCategory).toBeDefined();
27
- expect(stats.byCategory['Language']).toBeGreaterThan(0);
28
- expect(stats.byCategory['Architecture']).toBeGreaterThan(0);
29
- expect(stats.byCategory['Testing']).toBeGreaterThan(0);
30
- expect(stats.byCategory['Security']).toBeGreaterThan(0);
31
- });
32
- });
33
-
34
- describe('Full Level Filtering', () => {
35
- test('should include ALL guidelines for full level regardless of architecture', async () => {
36
- const typescript = loader.getGuidelinesForProfile('typescript', 'full', 'microservices', 'sql');
37
- const typescriptMonolith = loader.getGuidelinesForProfile('typescript', 'full', 'modular-monolith', 'sql');
38
-
39
- // Full level should return same count regardless of architecture
40
- expect(typescript.length).toBe(typescriptMonolith.length);
41
- expect(typescript.length).toBeGreaterThanOrEqual(65); // Should include all applicable guidelines
42
- });
43
-
44
- test('should include all architecture patterns in full level', async () => {
45
- const guidelines = loader.getGuidelinesForProfile('typescript', 'full', 'microservices', 'sql');
46
- const allGuidelines = loader.getAllGuidelines();
47
-
48
- // Check if architecture-specific guidelines from OTHER architectures are included
49
- const architectureGuidelines = allGuidelines.filter(g =>
50
- g.mapping.architectures && g.mapping.architectures.length > 0
51
- );
52
-
53
- // At least some architecture guidelines should be in the result
54
- const includedArchGuidelines = guidelines.filter(id => {
55
- const mapping = loader.getMapping(id);
56
- return mapping?.architectures && mapping.architectures.length > 0;
57
- });
58
-
59
- expect(includedArchGuidelines.length).toBeGreaterThan(0);
60
- });
61
-
62
- test('full level should include microservices guidelines even when selecting modular-monolith', async () => {
63
- const guidelines = loader.getGuidelinesForProfile('typescript', 'full', 'modular-monolith', 'sql');
64
-
65
- // Find a microservices-specific guideline
66
- const allGuidelines = loader.getAllGuidelines();
67
- const microservicesGuideline = allGuidelines.find(g =>
68
- g.mapping.architectures?.includes('microservices') &&
69
- !g.mapping.architectures?.includes('modular-monolith')
70
- );
71
-
72
- if (microservicesGuideline) {
73
- expect(guidelines).toContain(microservicesGuideline.id);
74
- }
75
- });
76
- });
77
-
78
- describe('Level-Based Filtering', () => {
79
- test('basic level should return fewer guidelines than standard', async () => {
80
- const basic = loader.getGuidelinesForProfile('typescript', 'basic', 'microservices', 'sql');
81
- const standard = loader.getGuidelinesForProfile('typescript', 'standard', 'microservices', 'sql');
82
-
83
- expect(basic.length).toBeLessThan(standard.length);
84
- });
85
-
86
- test('standard level should return fewer guidelines than expert', async () => {
87
- const standard = loader.getGuidelinesForProfile('typescript', 'standard', 'microservices', 'sql');
88
- const expert = loader.getGuidelinesForProfile('typescript', 'expert', 'microservices', 'sql');
89
-
90
- expect(standard.length).toBeLessThan(expert.length);
91
- });
92
-
93
- test('expert level should return fewer or equal guidelines than full', async () => {
94
- const expert = loader.getGuidelinesForProfile('typescript', 'expert', 'microservices', 'sql');
95
- const full = loader.getGuidelinesForProfile('typescript', 'full', 'microservices', 'sql');
96
-
97
- expect(expert.length).toBeLessThanOrEqual(full.length);
98
- });
99
- });
100
-
101
- describe('Architecture-Based Filtering', () => {
102
- test('should filter by architecture for non-full levels', async () => {
103
- const microservices = loader.getGuidelinesForProfile('typescript', 'expert', 'microservices', 'sql');
104
- const monolith = loader.getGuidelinesForProfile('typescript', 'expert', 'modular-monolith', 'sql');
105
-
106
- // At non-full levels, different architectures should give different results
107
- // (though some guidelines may be shared)
108
- expect(microservices).toBeDefined();
109
- expect(monolith).toBeDefined();
110
- });
111
-
112
- test('should NOT filter by architecture for full level', async () => {
113
- const microservices = loader.getGuidelinesForProfile('typescript', 'full', 'microservices', 'sql');
114
- const monolith = loader.getGuidelinesForProfile('typescript', 'full', 'modular-monolith', 'sql');
115
-
116
- // Full level should return same guidelines regardless of selected architecture
117
- expect(microservices.length).toBe(monolith.length);
118
- });
119
- });
120
-
121
- describe('Language-Based Filtering', () => {
122
- test('should filter by language', async () => {
123
- const typescript = loader.getGuidelinesForProfile('typescript', 'standard', 'microservices', 'sql');
124
- const python = loader.getGuidelinesForProfile('python', 'standard', 'microservices', 'sql');
125
-
126
- // Different languages should have some different guidelines
127
- expect(typescript).toBeDefined();
128
- expect(python).toBeDefined();
129
- expect(typescript.length).toBeGreaterThan(0);
130
- expect(python.length).toBeGreaterThan(0);
131
- });
132
-
133
- test('should include language-agnostic guidelines for all languages', async () => {
134
- const typescript = loader.getGuidelinesForProfile('typescript', 'standard', 'microservices', 'sql');
135
- const python = loader.getGuidelinesForProfile('python', 'standard', 'microservices', 'sql');
136
-
137
- // Find language-agnostic guidelines
138
- const allGuidelines = loader.getAllGuidelines();
139
- const agnosticGuideline = allGuidelines.find(g => !g.mapping.languages);
140
-
141
- if (agnosticGuideline) {
142
- // Language-agnostic guidelines should be in both
143
- expect(typescript).toContain(agnosticGuideline.id);
144
- expect(python).toContain(agnosticGuideline.id);
145
- }
146
- });
147
- });
148
-
149
- describe('Datasource Filtering', () => {
150
- test('should exclude database guidelines when datasource is none', async () => {
151
- const withDb = loader.getGuidelinesForProfile('typescript', 'standard', 'microservices', 'sql');
152
- const withoutDb = loader.getGuidelinesForProfile('typescript', 'standard', 'microservices', 'none');
153
-
154
- expect(withoutDb.length).toBeLessThan(withDb.length);
155
- });
156
-
157
- test('should include SQL guidelines when datasource is sql', async () => {
158
- const guidelines = loader.getGuidelinesForProfile('typescript', 'standard', 'microservices', 'sql');
159
- const categoryTree = loader.getGuidelinesByCategory('typescript', 'standard', 'microservices', 'sql');
160
-
161
- // Should have database category when SQL is selected
162
- expect(categoryTree['Database']).toBeDefined();
163
- });
164
-
165
- test('should exclude database category when datasource is none', async () => {
166
- const categoryTree = loader.getGuidelinesByCategory('typescript', 'standard', 'microservices', 'none');
167
-
168
- // Should NOT have database category when datasource is none
169
- expect(categoryTree['Database']).toBeUndefined();
170
- });
171
- });
172
-
173
- describe('Guideline Loading', () => {
174
- test('should load guideline content by ID', async () => {
175
- const guidelines = loader.getGuidelinesForProfile('typescript', 'basic', 'microservices', 'sql');
176
- expect(guidelines.length).toBeGreaterThan(0);
177
-
178
- const content = loader.loadGuideline(guidelines[0]);
179
- expect(content).toBeDefined();
180
- expect(typeof content).toBe('string');
181
- expect(content.length).toBeGreaterThan(0);
182
- });
183
-
184
- test('should throw error for invalid guideline ID', async () => {
185
- expect(() => loader.loadGuideline('invalid-guideline-id-12345')).toThrow();
186
- });
187
- });
188
-
189
- describe('Guideline Mapping', () => {
190
- test('should get mapping for guideline ID', async () => {
191
- const guidelines = loader.getGuidelinesForProfile('typescript', 'basic', 'microservices', 'sql');
192
- const mapping = loader.getMapping(guidelines[0]);
193
-
194
- expect(mapping).toBeDefined();
195
- expect(mapping?.path).toBeDefined();
196
- expect(mapping?.category).toBeDefined();
197
- });
198
-
199
- test('should return undefined for invalid guideline ID', async () => {
200
- const mapping = loader.getMapping('invalid-guideline-id-12345');
201
- expect(mapping).toBeUndefined();
202
- });
203
- });
204
-
205
- describe('Profile Assembly', () => {
206
- test('should assemble complete profile', async () => {
207
- const profile = loader.assembleProfile('typescript', 'basic', 'microservices', 'sql');
208
-
209
- expect(profile).toBeDefined();
210
- expect(typeof profile).toBe('string');
211
- expect(profile.length).toBeGreaterThan(0);
212
- expect(profile).toContain('---'); // Should have separator between guidelines
213
- });
214
-
215
- test('should throw error when no guidelines found', async () => {
216
- // This would only throw if we had a scenario with truly no matching guidelines
217
- // Since basic level includes language-agnostic guidelines, most profiles will have some
218
- // The method throws when guidelineIds.length === 0
219
- const profile = loader.assembleProfile('typescript', 'basic', 'microservices', 'sql');
220
- expect(profile).toBeDefined();
221
- });
222
- });
223
-
224
- describe('Category Tree', () => {
225
- test('should generate category tree', async () => {
226
- const tree = loader.getCategoryTree('typescript', 'standard', 'microservices', 'sql');
227
-
228
- expect(tree).toBeDefined();
229
- expect(Array.isArray(tree)).toBe(true);
230
- expect(tree.length).toBeGreaterThan(0);
231
-
232
- const firstCategory = tree[0];
233
- expect(firstCategory.name).toBeDefined();
234
- expect(firstCategory.count).toBeGreaterThan(0);
235
- expect(Array.isArray(firstCategory.guidelines)).toBe(true);
236
- });
237
-
238
- test('should include guideline details in tree', async () => {
239
- const tree = loader.getCategoryTree('typescript', 'standard', 'microservices', 'sql');
240
- const firstGuideline = tree[0].guidelines[0];
241
-
242
- expect(firstGuideline.id).toBeDefined();
243
- expect(firstGuideline.name).toBeDefined();
244
- expect(firstGuideline.path).toBeDefined();
245
- });
246
- });
247
-
248
- describe('Metrics', () => {
249
- test('should calculate metrics for guidelines', async () => {
250
- const guidelines = loader.getGuidelinesForProfile('typescript', 'standard', 'microservices', 'sql');
251
- const metrics = loader.getMetrics(guidelines);
252
-
253
- expect(metrics.guidelineCount).toBe(guidelines.length);
254
- expect(metrics.hooksCount).toBeGreaterThanOrEqual(0);
255
- expect(metrics.subAgentsCount).toBeGreaterThanOrEqual(1);
256
- expect(metrics.estimatedSize).toBeDefined();
257
- expect(Array.isArray(metrics.categories)).toBe(true);
258
- });
259
- });
260
-
261
- describe('Statistics', () => {
262
- test('should provide comprehensive stats', async () => {
263
- const stats = loader.getStats();
264
-
265
- expect(stats.totalGuidelines).toBe(82);
266
- expect(Object.keys(stats.byLanguage).length).toBeGreaterThan(0);
267
- expect(Object.keys(stats.byLevel).length).toBeGreaterThan(0);
268
- expect(Object.keys(stats.byArchitecture).length).toBeGreaterThan(0);
269
- expect(Object.keys(stats.byCategory).length).toBe(12);
270
- });
271
-
272
- test('should have expected level counts', async () => {
273
- const stats = loader.getStats();
274
-
275
- expect(stats.byLevel['basic']).toBe(17);
276
- expect(stats.byLevel['standard']).toBe(68);
277
- expect(stats.byLevel['expert']).toBe(82);
278
- expect(stats.byLevel['full']).toBe(82);
279
- });
280
- });
281
- });