@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.
- package/{.claude/guidelines → .agent/rules}/api-design.md +5 -1
- package/{.claude/guidelines → .agent/rules}/architecture.md +5 -1
- package/{.claude/guidelines → .agent/rules}/best-practices.md +5 -1
- package/{.claude/guidelines → .agent/rules}/code-style.md +5 -1
- package/{.claude/guidelines → .agent/rules}/design-patterns.md +5 -1
- package/{.claude/guidelines → .agent/rules}/devops.md +5 -1
- package/{.claude/guidelines → .agent/rules}/error-handling.md +5 -1
- package/.agent/rules/instructions.md +28 -0
- package/{.claude/guidelines → .agent/rules}/language.md +5 -1
- package/{.claude/guidelines → .agent/rules}/performance.md +5 -1
- package/{.claude/guidelines → .agent/rules}/security.md +5 -1
- package/{.claude/guidelines → .agent/rules}/testing.md +5 -1
- package/.agent/workflows/add-documentation.md +10 -0
- package/.agent/workflows/generate-integration-tests.md +10 -0
- package/.agent/workflows/generate-unit-tests.md +11 -0
- package/.agent/workflows/performance-audit.md +11 -0
- package/.agent/workflows/refactor-extract-module.md +12 -0
- package/.agent/workflows/security-audit.md +12 -0
- package/.gemini/instructions.md +4843 -0
- package/.vs/ProjectSettings.json +2 -2
- package/.vs/VSWorkspaceState.json +15 -15
- package/.vs/aicgen.slnx/v18/DocumentLayout.json +53 -53
- package/AGENTS.md +9 -11
- package/assets/icon.svg +33 -33
- package/bun.lock +734 -26
- package/{CLAUDE.md → claude.md} +2 -2
- package/config.example.yml +129 -0
- package/config.yml +38 -0
- package/data/architecture/microservices/api-gateway.md +56 -56
- package/data/devops/observability.md +73 -73
- package/data/guideline-mappings.yml +128 -0
- package/data/language/dart/async.md +289 -0
- package/data/language/dart/basics.md +280 -0
- package/data/language/dart/error-handling.md +355 -0
- package/data/language/dart/index.md +10 -0
- package/data/language/dart/testing.md +352 -0
- package/data/language/swift/basics.md +477 -0
- package/data/language/swift/concurrency.md +654 -0
- package/data/language/swift/error-handling.md +679 -0
- package/data/language/swift/swiftui-mvvm.md +795 -0
- package/data/language/swift/testing.md +708 -0
- package/data/version.json +10 -8
- package/dist/index.js +50153 -28959
- package/jest.config.js +46 -0
- package/package.json +14 -3
- package/.claude/agents/architecture-reviewer.md +0 -88
- package/.claude/agents/guideline-checker.md +0 -73
- package/.claude/agents/security-auditor.md +0 -108
- package/.claude/settings.json +0 -98
- package/.claude/settings.local.json +0 -8
- package/.eslintrc.json +0 -28
- package/.github/workflows/release.yml +0 -180
- package/.github/workflows/test.yml +0 -81
- package/CONTRIBUTING.md +0 -821
- package/dist/commands/init.d.ts +0 -8
- package/dist/commands/init.d.ts.map +0 -1
- package/dist/commands/init.js +0 -46
- package/dist/commands/init.js.map +0 -1
- package/dist/config/profiles.d.ts +0 -4
- package/dist/config/profiles.d.ts.map +0 -1
- package/dist/config/profiles.js +0 -30
- package/dist/config/profiles.js.map +0 -1
- package/dist/config/settings.d.ts +0 -7
- package/dist/config/settings.d.ts.map +0 -1
- package/dist/config/settings.js +0 -7
- package/dist/config/settings.js.map +0 -1
- package/dist/index.d.ts +0 -3
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/models/guideline.d.ts +0 -15
- package/dist/models/guideline.d.ts.map +0 -1
- package/dist/models/guideline.js +0 -2
- package/dist/models/guideline.js.map +0 -1
- package/dist/models/preference.d.ts +0 -9
- package/dist/models/preference.d.ts.map +0 -1
- package/dist/models/preference.js +0 -2
- package/dist/models/preference.js.map +0 -1
- package/dist/models/profile.d.ts +0 -9
- package/dist/models/profile.d.ts.map +0 -1
- package/dist/models/profile.js +0 -2
- package/dist/models/profile.js.map +0 -1
- package/dist/models/project.d.ts +0 -13
- package/dist/models/project.d.ts.map +0 -1
- package/dist/models/project.js +0 -2
- package/dist/models/project.js.map +0 -1
- package/dist/services/ai/anthropic.d.ts +0 -7
- package/dist/services/ai/anthropic.d.ts.map +0 -1
- package/dist/services/ai/anthropic.js +0 -39
- package/dist/services/ai/anthropic.js.map +0 -1
- package/dist/services/generator.d.ts +0 -2
- package/dist/services/generator.d.ts.map +0 -1
- package/dist/services/generator.js +0 -4
- package/dist/services/generator.js.map +0 -1
- package/dist/services/learner.d.ts +0 -2
- package/dist/services/learner.d.ts.map +0 -1
- package/dist/services/learner.js +0 -4
- package/dist/services/learner.js.map +0 -1
- package/dist/services/scanner.d.ts +0 -3
- package/dist/services/scanner.d.ts.map +0 -1
- package/dist/services/scanner.js +0 -54
- package/dist/services/scanner.js.map +0 -1
- package/dist/utils/errors.d.ts +0 -15
- package/dist/utils/errors.d.ts.map +0 -1
- package/dist/utils/errors.js +0 -27
- package/dist/utils/errors.js.map +0 -1
- package/dist/utils/file.d.ts +0 -7
- package/dist/utils/file.d.ts.map +0 -1
- package/dist/utils/file.js +0 -32
- package/dist/utils/file.js.map +0 -1
- package/dist/utils/logger.d.ts +0 -6
- package/dist/utils/logger.d.ts.map +0 -1
- package/dist/utils/logger.js +0 -17
- package/dist/utils/logger.js.map +0 -1
- package/dist/utils/path.d.ts +0 -6
- package/dist/utils/path.d.ts.map +0 -1
- package/dist/utils/path.js +0 -14
- package/dist/utils/path.js.map +0 -1
- package/docs/planning/memory-lane.md +0 -83
- package/packaging/linux/aicgen.spec +0 -23
- package/packaging/linux/control +0 -9
- package/packaging/macos/scripts/postinstall +0 -12
- package/packaging/windows/setup.nsi +0 -92
- package/scripts/add-categories.ts +0 -87
- package/scripts/build-binary.ts +0 -46
- package/scripts/embed-data.ts +0 -105
- package/scripts/generate-version.ts +0 -150
- package/scripts/test-decompress.ts +0 -27
- package/scripts/test-extract.ts +0 -31
- package/src/__tests__/services/assistant-file-writer.test.ts +0 -400
- package/src/__tests__/services/guideline-loader.test.ts +0 -281
- package/src/__tests__/services/tarball-extraction.test.ts +0 -125
- package/src/commands/add-guideline.ts +0 -296
- package/src/commands/clear.ts +0 -61
- package/src/commands/guideline-selector.ts +0 -123
- package/src/commands/init.ts +0 -645
- package/src/commands/quick-add.ts +0 -586
- package/src/commands/remove-guideline.ts +0 -152
- package/src/commands/stats.ts +0 -49
- package/src/commands/update.ts +0 -240
- package/src/config.ts +0 -82
- package/src/embedded-data.ts +0 -1492
- package/src/index.ts +0 -67
- package/src/models/profile.ts +0 -24
- package/src/models/project.ts +0 -43
- package/src/services/assistant-file-writer.ts +0 -612
- package/src/services/config-generator.ts +0 -150
- package/src/services/config-manager.ts +0 -70
- package/src/services/data-source.ts +0 -248
- package/src/services/first-run-init.ts +0 -148
- package/src/services/guideline-loader.ts +0 -311
- package/src/services/hook-generator.ts +0 -178
- package/src/services/subagent-generator.ts +0 -310
- package/src/utils/banner.ts +0 -66
- package/src/utils/errors.ts +0 -27
- package/src/utils/file.ts +0 -67
- package/src/utils/formatting.ts +0 -172
- package/src/utils/logger.ts +0 -89
- package/src/utils/path.ts +0 -17
- package/src/utils/wizard-state.ts +0 -132
- 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
|
-
});
|