@iservu-inc/adf-cli 0.2.0 → 0.3.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.
@@ -0,0 +1,245 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+ const AgentsMdGenerator = require('../lib/generators/agents-md-generator');
4
+
5
+ const TEST_PROJECT_PATH = path.join(__dirname, 'test-project-generator');
6
+ const TEST_SESSION_PATH = path.join(TEST_PROJECT_PATH, '.adf', 'sessions', 'test-session');
7
+
8
+ describe('AgentsMdGenerator', () => {
9
+ beforeEach(async () => {
10
+ // Clean up test directories
11
+ await fs.remove(TEST_PROJECT_PATH);
12
+ await fs.ensureDir(TEST_PROJECT_PATH);
13
+ await fs.ensureDir(TEST_SESSION_PATH);
14
+ await fs.ensureDir(path.join(TEST_SESSION_PATH, 'outputs'));
15
+ });
16
+
17
+ afterEach(async () => {
18
+ // Clean up after tests
19
+ await fs.remove(TEST_PROJECT_PATH);
20
+ });
21
+
22
+ describe('PRP Framework', () => {
23
+ it('should generate AGENTS.md from PRP output', async () => {
24
+ // Create mock PRP output
25
+ const prpContent = `# Product Requirement Prompt (PRP)
26
+
27
+ ## 1. Goal Definition
28
+ Build a React dashboard that displays real-time analytics from PostgreSQL database.
29
+
30
+ ## 2. Business Justification
31
+ This will help users make data-driven decisions and improve productivity.
32
+
33
+ ## 3. Contextual Intelligence
34
+ ### Technology Stack
35
+ - Frontend: React 18, TypeScript
36
+ - Backend: Node.js, Express
37
+ - Database: PostgreSQL
38
+
39
+ ## 4. Implementation Blueprint
40
+ ### File Structure
41
+ - src/components/Dashboard/
42
+ - src/api/analytics/
43
+
44
+ ### Core Logic
45
+ 1. Fetch data from analytics API
46
+ 2. Process and aggregate
47
+ 3. Render charts
48
+
49
+ ## 5. Validation
50
+ ### Success Criteria
51
+ - Dashboard loads in <2s
52
+ - All charts render correctly
53
+ `;
54
+
55
+ await fs.writeFile(
56
+ path.join(TEST_SESSION_PATH, 'outputs', 'prp.md'),
57
+ prpContent,
58
+ 'utf-8'
59
+ );
60
+
61
+ // Create metadata
62
+ await fs.writeJson(path.join(TEST_SESSION_PATH, '_metadata.json'), {
63
+ framework: 'rapid',
64
+ projectName: 'Test Analytics Dashboard'
65
+ });
66
+
67
+ // Generate AGENTS.md
68
+ const generator = new AgentsMdGenerator(TEST_SESSION_PATH, TEST_PROJECT_PATH, 'rapid');
69
+ const generatedPath = await generator.generate();
70
+
71
+ // Verify file was created
72
+ expect(await fs.pathExists(generatedPath)).toBe(true);
73
+
74
+ // Verify content
75
+ const content = await fs.readFile(generatedPath, 'utf-8');
76
+
77
+ expect(content).toContain('# Test Analytics Dashboard');
78
+ expect(content).toContain('## Overview');
79
+ expect(content).toContain('React dashboard');
80
+ expect(content).toContain('## Tech Stack');
81
+ expect(content).toContain('## Build Commands');
82
+ expect(content).toContain('npm install');
83
+ expect(content).toContain('## AI Agent Instructions');
84
+ expect(content).toContain('.adf/sessions/test-session/outputs/prp.md');
85
+ expect(content).toContain('Generated by');
86
+ expect(content).toContain('ADF CLI');
87
+ });
88
+ });
89
+
90
+ describe('Balanced Framework', () => {
91
+ it('should generate AGENTS.md from Balanced outputs', async () => {
92
+ // Create mock outputs
93
+ const constitutionContent = `# Constitution
94
+
95
+ ## Core Principles
96
+ 1. User privacy is paramount
97
+ 2. Performance over features
98
+
99
+ ## Constraints
100
+ - No third-party analytics
101
+ - WCAG 2.1 AA compliance
102
+ `;
103
+
104
+ const specificationContent = `# Specification
105
+
106
+ ## Overview
107
+ A comprehensive user management system.
108
+
109
+ ## Architecture
110
+ Microservices architecture with API gateway.
111
+ `;
112
+
113
+ const planContent = `# Technical Plan
114
+
115
+ ## Technology Stack
116
+ - React 18
117
+ - Node.js 20
118
+ - PostgreSQL 15
119
+ `;
120
+
121
+ await fs.writeFile(
122
+ path.join(TEST_SESSION_PATH, 'outputs', 'constitution.md'),
123
+ constitutionContent,
124
+ 'utf-8'
125
+ );
126
+
127
+ await fs.writeFile(
128
+ path.join(TEST_SESSION_PATH, 'outputs', 'specification.md'),
129
+ specificationContent,
130
+ 'utf-8'
131
+ );
132
+
133
+ await fs.writeFile(
134
+ path.join(TEST_SESSION_PATH, 'outputs', 'plan.md'),
135
+ planContent,
136
+ 'utf-8'
137
+ );
138
+
139
+ // Generate AGENTS.md
140
+ const generator = new AgentsMdGenerator(TEST_SESSION_PATH, TEST_PROJECT_PATH, 'balanced');
141
+ const generatedPath = await generator.generate();
142
+
143
+ // Verify content
144
+ const content = await fs.readFile(generatedPath, 'utf-8');
145
+
146
+ expect(content).toContain('## Constitution');
147
+ expect(content).toContain('User privacy is paramount');
148
+ expect(content).toContain('## Tech Stack');
149
+ expect(content).toContain('React 18');
150
+ expect(content).toContain('constitution.md');
151
+ expect(content).toContain('specification.md');
152
+ expect(content).toContain('plan.md');
153
+ });
154
+ });
155
+
156
+ describe('BMAD Framework', () => {
157
+ it('should generate AGENTS.md from BMAD outputs', async () => {
158
+ // Create mock outputs
159
+ const prdContent = `# Product Requirements Document
160
+
161
+ ## Executive Summary
162
+ A complete e-commerce platform for small businesses.
163
+
164
+ ## Goals and Objectives
165
+ - Enable online sales
166
+ - Provide analytics
167
+
168
+ ## Technical Requirements
169
+ - RESTful API
170
+ - Payment gateway integration
171
+ `;
172
+
173
+ const architectureContent = `# System Architecture
174
+
175
+ ## System Overview
176
+ Modular monolith architecture with separate domains.
177
+ `;
178
+
179
+ await fs.writeFile(
180
+ path.join(TEST_SESSION_PATH, 'outputs', 'prd.md'),
181
+ prdContent,
182
+ 'utf-8'
183
+ );
184
+
185
+ await fs.writeFile(
186
+ path.join(TEST_SESSION_PATH, 'outputs', 'architecture.md'),
187
+ architectureContent,
188
+ 'utf-8'
189
+ );
190
+
191
+ // Generate AGENTS.md
192
+ const generator = new AgentsMdGenerator(TEST_SESSION_PATH, TEST_PROJECT_PATH, 'comprehensive');
193
+ const generatedPath = await generator.generate();
194
+
195
+ // Verify content
196
+ const content = await fs.readFile(generatedPath, 'utf-8');
197
+
198
+ expect(content).toContain('## Product Overview');
199
+ expect(content).toContain('e-commerce platform');
200
+ expect(content).toContain('## Goals and Objectives');
201
+ expect(content).toContain('Enable online sales');
202
+ expect(content).toContain('## Security Notes');
203
+ expect(content).toContain('prd.md');
204
+ expect(content).toContain('architecture.md');
205
+ });
206
+ });
207
+
208
+ describe('Template Variables', () => {
209
+ it('should replace session ID in paths', async () => {
210
+ const prpContent = '# PRP\n\n## 1. Goal Definition\nTest project';
211
+
212
+ await fs.writeFile(
213
+ path.join(TEST_SESSION_PATH, 'outputs', 'prp.md'),
214
+ prpContent,
215
+ 'utf-8'
216
+ );
217
+
218
+ const generator = new AgentsMdGenerator(TEST_SESSION_PATH, TEST_PROJECT_PATH, 'rapid');
219
+ const generatedPath = await generator.generate();
220
+
221
+ const content = await fs.readFile(generatedPath, 'utf-8');
222
+
223
+ // Should contain the actual session ID, not a template variable
224
+ expect(content).toContain('test-session');
225
+ expect(content).not.toContain('{SESSION_ID}');
226
+ });
227
+
228
+ it('should include ADF CLI version', async () => {
229
+ const prpContent = '# PRP\n\n## 1. Goal Definition\nTest';
230
+
231
+ await fs.writeFile(
232
+ path.join(TEST_SESSION_PATH, 'outputs', 'prp.md'),
233
+ prpContent,
234
+ 'utf-8'
235
+ );
236
+
237
+ const generator = new AgentsMdGenerator(TEST_SESSION_PATH, TEST_PROJECT_PATH, 'rapid');
238
+ const generatedPath = await generator.generate();
239
+
240
+ const content = await fs.readFile(generatedPath, 'utf-8');
241
+
242
+ expect(content).toMatch(/Generated by.*ADF CLI.*v\d+\.\d+\.\d+/);
243
+ });
244
+ });
245
+ });
@@ -0,0 +1,326 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+ const CursorGenerator = require('../lib/generators/cursor-generator');
4
+
5
+ const TEST_PROJECT_PATH = path.join(__dirname, 'test-project-cursor');
6
+ const TEST_SESSION_PATH = path.join(TEST_PROJECT_PATH, '.adf', 'sessions', 'test-session');
7
+
8
+ describe('CursorGenerator', () => {
9
+ beforeEach(async () => {
10
+ // Clean up test directories
11
+ await fs.remove(TEST_PROJECT_PATH);
12
+ await fs.ensureDir(TEST_PROJECT_PATH);
13
+ await fs.ensureDir(TEST_SESSION_PATH);
14
+ await fs.ensureDir(path.join(TEST_SESSION_PATH, 'outputs'));
15
+ });
16
+
17
+ afterEach(async () => {
18
+ // Clean up after tests
19
+ await fs.remove(TEST_PROJECT_PATH);
20
+ });
21
+
22
+ describe('PRP Framework', () => {
23
+ it('should generate Cursor configurations from PRP output', async () => {
24
+ // Create mock PRP output
25
+ const prpContent = `# Product Requirement Prompt (PRP)
26
+
27
+ ## 1. Goal Definition
28
+ Build a React dashboard that displays real-time analytics from PostgreSQL database.
29
+
30
+ ## 2. Business Justification
31
+ This will help users make data-driven decisions and improve productivity.
32
+
33
+ ## 3. Contextual Intelligence
34
+ ### Technology Stack
35
+ - Frontend: React 18, TypeScript
36
+ - Backend: Node.js, Express
37
+ - Database: PostgreSQL
38
+
39
+ ## 4. Implementation Blueprint
40
+ ### File Structure
41
+ - src/components/Dashboard/
42
+ - src/api/analytics/
43
+
44
+ ### Core Logic
45
+ 1. Fetch data from analytics API
46
+ 2. Process and aggregate
47
+ 3. Render charts
48
+
49
+ ## 5. Validation
50
+ ### Success Criteria
51
+ - Dashboard loads in <2s
52
+ - All charts render correctly
53
+ `;
54
+
55
+ await fs.writeFile(
56
+ path.join(TEST_SESSION_PATH, 'outputs', 'prp.md'),
57
+ prpContent,
58
+ 'utf-8'
59
+ );
60
+
61
+ // Create metadata
62
+ await fs.writeJson(path.join(TEST_SESSION_PATH, '_metadata.json'), {
63
+ framework: 'rapid',
64
+ projectName: 'Test Analytics Dashboard'
65
+ });
66
+
67
+ // Generate Cursor configs
68
+ const generator = new CursorGenerator(TEST_SESSION_PATH, TEST_PROJECT_PATH, 'rapid');
69
+ const generated = await generator.generate();
70
+
71
+ // Verify .cursor/rules was created
72
+ const rulesPath = path.join(TEST_PROJECT_PATH, '.cursor', 'rules');
73
+ expect(await fs.pathExists(rulesPath)).toBe(true);
74
+
75
+ const rulesContent = await fs.readFile(rulesPath, 'utf-8');
76
+ expect(rulesContent).toContain('Test Analytics Dashboard');
77
+ expect(rulesContent).toContain('Cursor Rules');
78
+ expect(rulesContent).toContain('Project Goal');
79
+ expect(rulesContent).toContain('React dashboard');
80
+ expect(rulesContent).toContain('Tech Stack');
81
+ expect(rulesContent).toContain('Before Implementing Features');
82
+ expect(rulesContent).toContain('.adf/sessions/test-session/outputs/prp.md');
83
+ expect(rulesContent).toContain('Code Standards');
84
+ expect(rulesContent).toContain('What to Avoid');
85
+
86
+ // Verify .cursorrules deprecation notice was created
87
+ const legacyPath = path.join(TEST_PROJECT_PATH, '.cursorrules');
88
+ expect(await fs.pathExists(legacyPath)).toBe(true);
89
+
90
+ const legacyContent = await fs.readFile(legacyPath, 'utf-8');
91
+ expect(legacyContent).toContain('DEPRECATED');
92
+ expect(legacyContent).toContain('.cursor/rules');
93
+ expect(legacyContent).toContain('Migration');
94
+
95
+ // Verify generated structure
96
+ expect(generated.rules).toHaveLength(1);
97
+ expect(generated.legacy).toHaveLength(1);
98
+ });
99
+ });
100
+
101
+ describe('Balanced Framework', () => {
102
+ it('should generate Cursor configurations from Balanced outputs', async () => {
103
+ // Create mock outputs
104
+ const constitutionContent = `# Constitution
105
+
106
+ ## Core Principles
107
+ 1. User privacy is paramount
108
+ 2. Performance over features
109
+
110
+ ## Constraints
111
+ - No third-party analytics
112
+ - WCAG 2.1 AA compliance
113
+ `;
114
+
115
+ const specificationContent = `# Specification
116
+
117
+ ## Overview
118
+ A comprehensive user management system.
119
+
120
+ ## Architecture
121
+ Microservices architecture with API gateway.
122
+ `;
123
+
124
+ const planContent = `# Technical Plan
125
+
126
+ ## Technology Stack
127
+ - React 18
128
+ - Node.js 20
129
+ - PostgreSQL 15
130
+
131
+ ## Code Style
132
+ - Use TypeScript strict mode
133
+ - Follow Airbnb style guide
134
+
135
+ ## Coding Standards
136
+ - Write tests first
137
+ - Document public APIs
138
+ `;
139
+
140
+ await fs.writeFile(
141
+ path.join(TEST_SESSION_PATH, 'outputs', 'constitution.md'),
142
+ constitutionContent,
143
+ 'utf-8'
144
+ );
145
+
146
+ await fs.writeFile(
147
+ path.join(TEST_SESSION_PATH, 'outputs', 'specification.md'),
148
+ specificationContent,
149
+ 'utf-8'
150
+ );
151
+
152
+ await fs.writeFile(
153
+ path.join(TEST_SESSION_PATH, 'outputs', 'plan.md'),
154
+ planContent,
155
+ 'utf-8'
156
+ );
157
+
158
+ await fs.writeJson(path.join(TEST_SESSION_PATH, '_metadata.json'), {
159
+ framework: 'balanced',
160
+ projectName: 'User Management System'
161
+ });
162
+
163
+ // Generate Cursor configs
164
+ const generator = new CursorGenerator(TEST_SESSION_PATH, TEST_PROJECT_PATH, 'balanced');
165
+ await generator.generate();
166
+
167
+ // Verify .cursor/rules
168
+ const rulesPath = path.join(TEST_PROJECT_PATH, '.cursor', 'rules');
169
+ const rulesContent = await fs.readFile(rulesPath, 'utf-8');
170
+
171
+ expect(rulesContent).toContain('User Management System');
172
+ expect(rulesContent).toContain('Core Principles');
173
+ expect(rulesContent).toContain('User privacy is paramount');
174
+ expect(rulesContent).toContain('Constraints (Non-Negotiable)');
175
+ expect(rulesContent).toContain('WCAG 2.1 AA compliance');
176
+ expect(rulesContent).toContain('Microservices architecture');
177
+ expect(rulesContent).toContain('constitution.md');
178
+ expect(rulesContent).toContain('specification.md');
179
+ expect(rulesContent).toContain('plan.md');
180
+ expect(rulesContent).toContain('What You MUST NOT Do');
181
+ });
182
+ });
183
+
184
+ describe('BMAD Framework', () => {
185
+ it('should generate Cursor configurations from BMAD outputs', async () => {
186
+ // Create mock outputs
187
+ const prdContent = `# Product Requirements Document
188
+
189
+ ## Executive Summary
190
+ A complete e-commerce platform for small businesses.
191
+
192
+ ## Goals and Objectives
193
+ - Enable online sales
194
+ - Provide analytics
195
+
196
+ ## Technical Requirements
197
+ - RESTful API
198
+ - Payment gateway integration
199
+ - Secure checkout flow
200
+ `;
201
+
202
+ const architectureContent = `# System Architecture
203
+
204
+ ## System Overview
205
+ Modular monolith architecture with separate domains.
206
+
207
+ ## Architecture Overview
208
+ Clean architecture with domain-driven design.
209
+
210
+ ## Components
211
+ - Order Management
212
+ - Inventory System
213
+ - Payment Processing
214
+ `;
215
+
216
+ await fs.writeFile(
217
+ path.join(TEST_SESSION_PATH, 'outputs', 'prd.md'),
218
+ prdContent,
219
+ 'utf-8'
220
+ );
221
+
222
+ await fs.writeFile(
223
+ path.join(TEST_SESSION_PATH, 'outputs', 'architecture.md'),
224
+ architectureContent,
225
+ 'utf-8'
226
+ );
227
+
228
+ await fs.writeJson(path.join(TEST_SESSION_PATH, '_metadata.json'), {
229
+ framework: 'comprehensive',
230
+ projectName: 'E-commerce Platform'
231
+ });
232
+
233
+ // Generate Cursor configs
234
+ const generator = new CursorGenerator(TEST_SESSION_PATH, TEST_PROJECT_PATH, 'comprehensive');
235
+ await generator.generate();
236
+
237
+ // Verify .cursor/rules
238
+ const rulesPath = path.join(TEST_PROJECT_PATH, '.cursor', 'rules');
239
+ const rulesContent = await fs.readFile(rulesPath, 'utf-8');
240
+
241
+ expect(rulesContent).toContain('E-commerce Platform');
242
+ expect(rulesContent).toContain('Product Overview');
243
+ expect(rulesContent).toContain('e-commerce platform');
244
+ expect(rulesContent).toContain('Goals and Objectives');
245
+ expect(rulesContent).toContain('Enable online sales');
246
+ expect(rulesContent).toContain('System Architecture');
247
+ expect(rulesContent).toContain('Code Quality Standards');
248
+ expect(rulesContent).toContain('Security');
249
+ expect(rulesContent).toContain('Performance');
250
+ expect(rulesContent).toContain('prd.md');
251
+ expect(rulesContent).toContain('architecture.md');
252
+ expect(rulesContent).toContain('stories.md');
253
+ });
254
+ });
255
+
256
+ describe('Modern vs Legacy', () => {
257
+ it('should create modern .cursor/rules as primary config', async () => {
258
+ const prpContent = '# PRP\n\n## 1. Goal Definition\nTest project';
259
+
260
+ await fs.writeFile(
261
+ path.join(TEST_SESSION_PATH, 'outputs', 'prp.md'),
262
+ prpContent,
263
+ 'utf-8'
264
+ );
265
+
266
+ const generator = new CursorGenerator(TEST_SESSION_PATH, TEST_PROJECT_PATH, 'rapid');
267
+ const generated = await generator.generate();
268
+
269
+ // Modern config should exist
270
+ const modernPath = path.join(TEST_PROJECT_PATH, '.cursor', 'rules');
271
+ expect(await fs.pathExists(modernPath)).toBe(true);
272
+
273
+ // Legacy should be deprecation notice
274
+ const legacyPath = path.join(TEST_PROJECT_PATH, '.cursorrules');
275
+ expect(await fs.pathExists(legacyPath)).toBe(true);
276
+
277
+ const legacyContent = await fs.readFile(legacyPath, 'utf-8');
278
+ expect(legacyContent).toContain('DEPRECATED');
279
+ });
280
+ });
281
+
282
+ describe('Template Variables', () => {
283
+ it('should replace session ID in paths', async () => {
284
+ const prpContent = '# PRP\n\n## 1. Goal Definition\nTest project';
285
+
286
+ await fs.writeFile(
287
+ path.join(TEST_SESSION_PATH, 'outputs', 'prp.md'),
288
+ prpContent,
289
+ 'utf-8'
290
+ );
291
+
292
+ const generator = new CursorGenerator(TEST_SESSION_PATH, TEST_PROJECT_PATH, 'rapid');
293
+ await generator.generate();
294
+
295
+ const rulesContent = await fs.readFile(
296
+ path.join(TEST_PROJECT_PATH, '.cursor', 'rules'),
297
+ 'utf-8'
298
+ );
299
+
300
+ // Should contain the actual session ID, not a template variable
301
+ expect(rulesContent).toContain('test-session');
302
+ expect(rulesContent).not.toContain('{SESSION_ID}');
303
+ });
304
+
305
+ it('should include ADF CLI version', async () => {
306
+ const prpContent = '# PRP\n\n## 1. Goal Definition\nTest';
307
+
308
+ await fs.writeFile(
309
+ path.join(TEST_SESSION_PATH, 'outputs', 'prp.md'),
310
+ prpContent,
311
+ 'utf-8'
312
+ );
313
+
314
+ const generator = new CursorGenerator(TEST_SESSION_PATH, TEST_PROJECT_PATH, 'rapid');
315
+ await generator.generate();
316
+
317
+ const rulesContent = await fs.readFile(
318
+ path.join(TEST_PROJECT_PATH, '.cursor', 'rules'),
319
+ 'utf-8'
320
+ );
321
+
322
+ expect(rulesContent).toContain('Generated by');
323
+ expect(rulesContent).toContain('ADF CLI');
324
+ });
325
+ });
326
+ });