@aicgen/aicgen 1.0.0-beta.1 → 1.0.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 (160) hide show
  1. package/{.claude/guidelines → .agent/rules}/api-design.md +5 -1
  2. package/{.claude/guidelines → .agent/rules}/architecture.md +5 -1
  3. package/{.claude/guidelines → .agent/rules}/best-practices.md +5 -1
  4. package/{.claude/guidelines → .agent/rules}/code-style.md +5 -1
  5. package/{.claude/guidelines → .agent/rules}/design-patterns.md +5 -1
  6. package/{.claude/guidelines → .agent/rules}/devops.md +5 -1
  7. package/{.claude/guidelines → .agent/rules}/error-handling.md +5 -1
  8. package/.agent/rules/instructions.md +28 -0
  9. package/{.claude/guidelines → .agent/rules}/language.md +5 -1
  10. package/{.claude/guidelines → .agent/rules}/performance.md +5 -1
  11. package/{.claude/guidelines → .agent/rules}/security.md +5 -1
  12. package/{.claude/guidelines → .agent/rules}/testing.md +5 -1
  13. package/.agent/workflows/add-documentation.md +10 -0
  14. package/.agent/workflows/generate-integration-tests.md +10 -0
  15. package/.agent/workflows/generate-unit-tests.md +11 -0
  16. package/.agent/workflows/performance-audit.md +11 -0
  17. package/.agent/workflows/refactor-extract-module.md +12 -0
  18. package/.agent/workflows/security-audit.md +12 -0
  19. package/.gemini/instructions.md +4843 -0
  20. package/.vs/ProjectSettings.json +2 -2
  21. package/.vs/VSWorkspaceState.json +15 -15
  22. package/.vs/aicgen.slnx/v18/DocumentLayout.json +53 -53
  23. package/AGENTS.md +9 -11
  24. package/assets/icon.svg +33 -33
  25. package/bun.lock +734 -26
  26. package/{CLAUDE.md → claude.md} +2 -2
  27. package/config.example.yml +129 -0
  28. package/config.yml +38 -0
  29. package/data/architecture/microservices/api-gateway.md +56 -56
  30. package/data/devops/observability.md +73 -73
  31. package/data/guideline-mappings.yml +128 -0
  32. package/data/language/dart/async.md +289 -0
  33. package/data/language/dart/basics.md +280 -0
  34. package/data/language/dart/error-handling.md +355 -0
  35. package/data/language/dart/index.md +10 -0
  36. package/data/language/dart/testing.md +352 -0
  37. package/data/language/swift/basics.md +477 -0
  38. package/data/language/swift/concurrency.md +654 -0
  39. package/data/language/swift/error-handling.md +679 -0
  40. package/data/language/swift/swiftui-mvvm.md +795 -0
  41. package/data/language/swift/testing.md +708 -0
  42. package/data/version.json +10 -8
  43. package/dist/index.js +50153 -28959
  44. package/jest.config.js +46 -0
  45. package/package.json +14 -3
  46. package/.claude/agents/architecture-reviewer.md +0 -88
  47. package/.claude/agents/guideline-checker.md +0 -73
  48. package/.claude/agents/security-auditor.md +0 -108
  49. package/.claude/settings.json +0 -98
  50. package/.claude/settings.local.json +0 -8
  51. package/.eslintrc.json +0 -28
  52. package/.github/workflows/release.yml +0 -180
  53. package/.github/workflows/test.yml +0 -81
  54. package/CONTRIBUTING.md +0 -821
  55. package/dist/commands/init.d.ts +0 -8
  56. package/dist/commands/init.d.ts.map +0 -1
  57. package/dist/commands/init.js +0 -46
  58. package/dist/commands/init.js.map +0 -1
  59. package/dist/config/profiles.d.ts +0 -4
  60. package/dist/config/profiles.d.ts.map +0 -1
  61. package/dist/config/profiles.js +0 -30
  62. package/dist/config/profiles.js.map +0 -1
  63. package/dist/config/settings.d.ts +0 -7
  64. package/dist/config/settings.d.ts.map +0 -1
  65. package/dist/config/settings.js +0 -7
  66. package/dist/config/settings.js.map +0 -1
  67. package/dist/index.d.ts +0 -3
  68. package/dist/index.d.ts.map +0 -1
  69. package/dist/index.js.map +0 -1
  70. package/dist/models/guideline.d.ts +0 -15
  71. package/dist/models/guideline.d.ts.map +0 -1
  72. package/dist/models/guideline.js +0 -2
  73. package/dist/models/guideline.js.map +0 -1
  74. package/dist/models/preference.d.ts +0 -9
  75. package/dist/models/preference.d.ts.map +0 -1
  76. package/dist/models/preference.js +0 -2
  77. package/dist/models/preference.js.map +0 -1
  78. package/dist/models/profile.d.ts +0 -9
  79. package/dist/models/profile.d.ts.map +0 -1
  80. package/dist/models/profile.js +0 -2
  81. package/dist/models/profile.js.map +0 -1
  82. package/dist/models/project.d.ts +0 -13
  83. package/dist/models/project.d.ts.map +0 -1
  84. package/dist/models/project.js +0 -2
  85. package/dist/models/project.js.map +0 -1
  86. package/dist/services/ai/anthropic.d.ts +0 -7
  87. package/dist/services/ai/anthropic.d.ts.map +0 -1
  88. package/dist/services/ai/anthropic.js +0 -39
  89. package/dist/services/ai/anthropic.js.map +0 -1
  90. package/dist/services/generator.d.ts +0 -2
  91. package/dist/services/generator.d.ts.map +0 -1
  92. package/dist/services/generator.js +0 -4
  93. package/dist/services/generator.js.map +0 -1
  94. package/dist/services/learner.d.ts +0 -2
  95. package/dist/services/learner.d.ts.map +0 -1
  96. package/dist/services/learner.js +0 -4
  97. package/dist/services/learner.js.map +0 -1
  98. package/dist/services/scanner.d.ts +0 -3
  99. package/dist/services/scanner.d.ts.map +0 -1
  100. package/dist/services/scanner.js +0 -54
  101. package/dist/services/scanner.js.map +0 -1
  102. package/dist/utils/errors.d.ts +0 -15
  103. package/dist/utils/errors.d.ts.map +0 -1
  104. package/dist/utils/errors.js +0 -27
  105. package/dist/utils/errors.js.map +0 -1
  106. package/dist/utils/file.d.ts +0 -7
  107. package/dist/utils/file.d.ts.map +0 -1
  108. package/dist/utils/file.js +0 -32
  109. package/dist/utils/file.js.map +0 -1
  110. package/dist/utils/logger.d.ts +0 -6
  111. package/dist/utils/logger.d.ts.map +0 -1
  112. package/dist/utils/logger.js +0 -17
  113. package/dist/utils/logger.js.map +0 -1
  114. package/dist/utils/path.d.ts +0 -6
  115. package/dist/utils/path.d.ts.map +0 -1
  116. package/dist/utils/path.js +0 -14
  117. package/dist/utils/path.js.map +0 -1
  118. package/docs/planning/memory-lane.md +0 -83
  119. package/packaging/linux/aicgen.spec +0 -23
  120. package/packaging/linux/control +0 -9
  121. package/packaging/macos/scripts/postinstall +0 -12
  122. package/packaging/windows/setup.nsi +0 -92
  123. package/scripts/add-categories.ts +0 -87
  124. package/scripts/build-binary.ts +0 -46
  125. package/scripts/embed-data.ts +0 -105
  126. package/scripts/generate-version.ts +0 -150
  127. package/scripts/test-decompress.ts +0 -27
  128. package/scripts/test-extract.ts +0 -31
  129. package/src/__tests__/services/assistant-file-writer.test.ts +0 -400
  130. package/src/__tests__/services/guideline-loader.test.ts +0 -281
  131. package/src/__tests__/services/tarball-extraction.test.ts +0 -125
  132. package/src/commands/add-guideline.ts +0 -296
  133. package/src/commands/clear.ts +0 -61
  134. package/src/commands/guideline-selector.ts +0 -123
  135. package/src/commands/init.ts +0 -645
  136. package/src/commands/quick-add.ts +0 -586
  137. package/src/commands/remove-guideline.ts +0 -152
  138. package/src/commands/stats.ts +0 -49
  139. package/src/commands/update.ts +0 -240
  140. package/src/config.ts +0 -82
  141. package/src/embedded-data.ts +0 -1492
  142. package/src/index.ts +0 -67
  143. package/src/models/profile.ts +0 -24
  144. package/src/models/project.ts +0 -43
  145. package/src/services/assistant-file-writer.ts +0 -612
  146. package/src/services/config-generator.ts +0 -150
  147. package/src/services/config-manager.ts +0 -70
  148. package/src/services/data-source.ts +0 -248
  149. package/src/services/first-run-init.ts +0 -148
  150. package/src/services/guideline-loader.ts +0 -311
  151. package/src/services/hook-generator.ts +0 -178
  152. package/src/services/subagent-generator.ts +0 -310
  153. package/src/utils/banner.ts +0 -66
  154. package/src/utils/errors.ts +0 -27
  155. package/src/utils/file.ts +0 -67
  156. package/src/utils/formatting.ts +0 -172
  157. package/src/utils/logger.ts +0 -89
  158. package/src/utils/path.ts +0 -17
  159. package/src/utils/wizard-state.ts +0 -132
  160. package/tsconfig.json +0 -25
@@ -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
- });