@iservu-inc/adf-cli 0.4.35 → 0.4.36

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/CHANGELOG.md CHANGED
@@ -5,6 +5,67 @@ All notable changes to `@iservu-inc/adf-cli` will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.4.36] - 2025-10-04
9
+
10
+ ### ✨ Multi-IDE Improvements + Config Command Enhancement
11
+
12
+ **1. Added IDE Deployment to `adf config`**
13
+ - New category: "IDE Deployment"
14
+ - Deploy to multiple IDEs without re-running `adf init`
15
+ - Shows which IDEs are already deployed
16
+ - Pre-selects already deployed IDEs in checkbox
17
+ - Allows quick re-deployment or deployment to new IDEs
18
+
19
+ **New Config Menu:**
20
+ ```
21
+ ⚙️ ADF Configuration
22
+
23
+ ? Select configuration category:
24
+ > AI Provider Setup - ✓ Configured (Openai)
25
+ IDE Deployment - ✓ Deployed (Windsurf, Cursor)
26
+ Learning System - ✓ Active (5 sessions, 12 patterns)
27
+ ```
28
+
29
+ **Usage:**
30
+ ```bash
31
+ adf config
32
+ # Select "IDE Deployment"
33
+ # Choose IDEs to deploy to
34
+ # Done!
35
+ ```
36
+
37
+ **2. Improved Cursor Generator**
38
+ - Added `loadSessionAnswers()` - reads actual session data
39
+ - Added `extractTechStackFromAnswers()` - detects tech in answers
40
+ - Added `extractWhatBuildingFromAnswers()` - finds project goals
41
+ - Falls back to session answers when PRP sections empty
42
+ - Better content instead of "See PRP for details"
43
+
44
+ **3. Improved VSCode/Copilot Generator**
45
+ - Same answer extraction improvements as Cursor
46
+ - Better Copilot instructions with real content
47
+ - Falls back to session answers
48
+ - Improved tech stack detection
49
+
50
+ **Code Changes:**
51
+ - config.js:18-27 - Added IDE_DEPLOYMENT category
52
+ - config.js:221-331 - IDE deployment configuration logic
53
+ - cursor-generator.js:41-51 - Made generateRules async
54
+ - cursor-generator.js:53-129 - Enhanced generateRulesPRP with answer extraction
55
+ - cursor-generator.js:373-424 - Added helper methods
56
+ - vscode-generator.js:40-50 - Made generateCopilotInstructions async
57
+ - vscode-generator.js:52-124 - Enhanced generateCopilotPRP with answer extraction
58
+ - vscode-generator.js:402-451 - Added helper methods
59
+
60
+ **Impact:**
61
+ - ✅ `adf config` now lets you deploy to IDEs
62
+ - ✅ Cursor files now have real content
63
+ - ✅ VSCode Copilot instructions have real content
64
+ - ✅ All generators use session answers as fallback
65
+ - ✅ No more "See PRP for details" placeholders
66
+
67
+ ---
68
+
8
69
  ## [0.4.35] - 2025-10-04
9
70
 
10
71
  ### 🔧 MAJOR FIX: Windsurf Configuration - Activation Modes & Content Generation
@@ -15,14 +15,16 @@ const CONFIG_CATEGORIES = {
15
15
  description: 'Configure AI provider (Anthropic, OpenAI, Google Gemini, OpenRouter)',
16
16
  value: 'ai-provider'
17
17
  },
18
+ IDE_DEPLOYMENT: {
19
+ name: 'IDE Deployment',
20
+ description: 'Deploy requirements to IDEs (Windsurf, Cursor, VSCode, etc.)',
21
+ value: 'ide-deployment'
22
+ },
18
23
  LEARNING_SYSTEM: {
19
24
  name: 'Learning System',
20
25
  description: 'Manage interview learning data and preferences',
21
26
  value: 'learning'
22
27
  }
23
- // Future config categories can be added here:
24
- // PROJECT_SETTINGS: { name: 'Project Settings', description: '...', value: 'project' },
25
- // DEPLOYMENT: { name: 'Deployment Preferences', description: '...', value: 'deployment' },
26
28
  };
27
29
 
28
30
  /**
@@ -118,6 +120,7 @@ async function config() {
118
120
 
119
121
  // Check configuration status for all categories
120
122
  const aiStatus = await isAIConfigured(cwd);
123
+ const deploymentStatus = await getDeploymentStatus(cwd);
121
124
  const learningStatus = await getLearningStatus(cwd);
122
125
 
123
126
  // Build choices with status indicators
@@ -127,6 +130,11 @@ async function config() {
127
130
  value: CONFIG_CATEGORIES.AI_PROVIDER.value,
128
131
  short: CONFIG_CATEGORIES.AI_PROVIDER.name
129
132
  },
133
+ {
134
+ name: `${CONFIG_CATEGORIES.IDE_DEPLOYMENT.name} - ${displayDeploymentStatus(deploymentStatus)}`,
135
+ value: CONFIG_CATEGORIES.IDE_DEPLOYMENT.value,
136
+ short: CONFIG_CATEGORIES.IDE_DEPLOYMENT.name
137
+ },
130
138
  {
131
139
  name: `${CONFIG_CATEGORIES.LEARNING_SYSTEM.name} - ${displayLearningStatus(learningStatus)}`,
132
140
  value: CONFIG_CATEGORIES.LEARNING_SYSTEM.value,
@@ -160,11 +168,14 @@ async function config() {
160
168
  await configureAIProviderCategory(cwd, aiStatus);
161
169
  break;
162
170
 
171
+ case 'ide-deployment':
172
+ await configureIDEDeploymentCategory(cwd, deploymentStatus);
173
+ break;
174
+
163
175
  case 'learning':
164
176
  await configureLearningCategory(cwd, learningStatus);
165
177
  break;
166
178
 
167
- // Future categories will be handled here
168
179
  default:
169
180
  console.log(chalk.red('\n❌ Configuration category not implemented yet.\n'));
170
181
  }
@@ -207,6 +218,118 @@ async function configureAIProviderCategory(cwd, aiStatus) {
207
218
  }
208
219
  }
209
220
 
221
+ /**
222
+ * Check deployment status
223
+ */
224
+ async function getDeploymentStatus(projectPath = process.cwd()) {
225
+ const adfDir = path.join(projectPath, '.adf');
226
+
227
+ if (!await fs.pathExists(adfDir)) {
228
+ return { hasSession: false, tools: [] };
229
+ }
230
+
231
+ // Check for latest session
232
+ const sessionsDir = path.join(adfDir, 'sessions');
233
+ if (!await fs.pathExists(sessionsDir)) {
234
+ return { hasSession: false, tools: [] };
235
+ }
236
+
237
+ const sessions = await fs.readdir(sessionsDir);
238
+ if (sessions.length === 0) {
239
+ return { hasSession: false, tools: [] };
240
+ }
241
+
242
+ // Check which IDE tools have been deployed
243
+ const deployedTools = [];
244
+ const ideMarkers = [
245
+ { name: 'Windsurf', path: '.windsurf/rules' },
246
+ { name: 'Cursor', path: '.cursor/rules' },
247
+ { name: 'VSCode', path: '.github/copilot-instructions.md' },
248
+ { name: 'Claude Code', path: '.claude/commands' }
249
+ ];
250
+
251
+ for (const marker of ideMarkers) {
252
+ if (await fs.pathExists(path.join(projectPath, marker.path))) {
253
+ deployedTools.push(marker.name);
254
+ }
255
+ }
256
+
257
+ return {
258
+ hasSession: true,
259
+ sessionCount: sessions.length,
260
+ tools: deployedTools
261
+ };
262
+ }
263
+
264
+ /**
265
+ * Display deployment status
266
+ */
267
+ function displayDeploymentStatus(status) {
268
+ if (status.hasSession && status.tools.length > 0) {
269
+ return `${chalk.green('✓ Deployed')} ${chalk.gray(`(${status.tools.join(', ')})`)}`;
270
+ } else if (status.hasSession) {
271
+ return chalk.yellow('○ Session exists, not deployed');
272
+ } else {
273
+ return chalk.gray('○ No sessions yet');
274
+ }
275
+ }
276
+
277
+ /**
278
+ * Configure IDE Deployment category
279
+ */
280
+ async function configureIDEDeploymentCategory(cwd, deploymentStatus) {
281
+ const { deployToTool } = require('./deploy');
282
+
283
+ console.log(chalk.gray('\n' + '─'.repeat(60) + '\n'));
284
+
285
+ if (!deploymentStatus.hasSession) {
286
+ console.log(chalk.yellow('⚠️ No ADF sessions found.\n'));
287
+ console.log(chalk.gray('You need to run `adf init` first to create requirements.'));
288
+ console.log(chalk.gray('Then you can deploy them to your IDE.\n'));
289
+ return;
290
+ }
291
+
292
+ console.log(chalk.cyan(`Found ${deploymentStatus.sessionCount} session(s)\n`));
293
+
294
+ if (deploymentStatus.tools.length > 0) {
295
+ console.log(chalk.green('✓ Already deployed to:'));
296
+ deploymentStatus.tools.forEach(tool => {
297
+ console.log(chalk.gray(` • ${tool}`));
298
+ });
299
+ console.log('');
300
+ }
301
+
302
+ // Ask which tools to deploy to
303
+ const { tools } = await inquirer.prompt([
304
+ {
305
+ type: 'checkbox',
306
+ name: 'tools',
307
+ message: 'Select IDEs to deploy to (space to select, enter to confirm):',
308
+ choices: [
309
+ { name: 'Windsurf', value: 'windsurf', checked: deploymentStatus.tools.includes('Windsurf') },
310
+ { name: 'Cursor', value: 'cursor', checked: deploymentStatus.tools.includes('Cursor') },
311
+ { name: 'VSCode/Copilot', value: 'vscode', checked: deploymentStatus.tools.includes('VSCode') },
312
+ { name: 'Claude Code', value: 'claude-code', checked: deploymentStatus.tools.includes('Claude Code') },
313
+ { name: 'Gemini CLI', value: 'gemini-cli' }
314
+ ],
315
+ validate: (answer) => {
316
+ if (answer.length === 0) {
317
+ return 'You must choose at least one IDE.';
318
+ }
319
+ return true;
320
+ }
321
+ }
322
+ ]);
323
+
324
+ // Deploy to each selected tool
325
+ for (const tool of tools) {
326
+ console.log('');
327
+ await deployToTool(tool, { silent: false });
328
+ }
329
+
330
+ console.log(chalk.green.bold('\n✅ Deployment complete!\n'));
331
+ }
332
+
210
333
  /**
211
334
  * Configure Learning System category
212
335
  */
@@ -42,7 +42,7 @@ class CursorGenerator extends ToolConfigGenerator {
42
42
  await this.ensureDir('.cursor');
43
43
 
44
44
  const content = this.framework === 'rapid' ?
45
- this.generateRulesPRP() :
45
+ await this.generateRulesPRP() :
46
46
  this.framework === 'balanced' ?
47
47
  this.generateRulesBalanced() :
48
48
  this.generateRulesBMAD();
@@ -50,9 +50,27 @@ class CursorGenerator extends ToolConfigGenerator {
50
50
  return await this.writeToProject('.cursor/rules', content);
51
51
  }
52
52
 
53
- generateRulesPRP() {
53
+ async generateRulesPRP() {
54
54
  const projectName = this.getProjectName();
55
55
  const sections = this.outputs.sections || {};
56
+ const answers = await this.loadSessionAnswers();
57
+
58
+ // Extract content with fallback to answers
59
+ let goal = sections['1._goal_definition'] || sections['goal_definition'];
60
+ let techStack = this.extractTechStack(sections);
61
+ let blueprint = sections['4._implementation_blueprint'] || sections['implementation_blueprint'];
62
+ let validation = sections['5._validation'] || sections['validation'];
63
+
64
+ // Fallback to extracted answers if sections are empty
65
+ if (!goal || goal.length < 20) {
66
+ const whatBuilding = this.extractWhatBuildingFromAnswers(answers);
67
+ if (whatBuilding) goal = whatBuilding;
68
+ }
69
+
70
+ if (!techStack || techStack.includes('See framework')) {
71
+ const techFromAnswers = this.extractTechStackFromAnswers(answers);
72
+ if (techFromAnswers) techStack = techFromAnswers;
73
+ }
56
74
 
57
75
  return `# ${projectName} - Cursor Rules
58
76
 
@@ -60,19 +78,19 @@ You are a senior developer working on ${projectName}.
60
78
 
61
79
  ## Project Goal
62
80
 
63
- ${sections['1._goal_definition'] || sections['goal_definition'] || 'See PRP for details'}
81
+ ${goal || 'See PRP for complete details'}
64
82
 
65
83
  ## Tech Stack
66
84
 
67
- ${this.extractTechStack(sections)}
85
+ ${techStack || 'See PRP for tech stack details'}
68
86
 
69
87
  ## Implementation Blueprint
70
88
 
71
- ${sections['4._implementation_blueprint'] || sections['implementation_blueprint'] || 'See PRP for details'}
89
+ ${blueprint || 'See PRP for implementation details'}
72
90
 
73
91
  ## Success Criteria
74
92
 
75
- ${sections['5._validation'] || sections['validation'] || 'See PRP for validation criteria'}
93
+ ${validation || 'See PRP for validation criteria'}
76
94
 
77
95
  ## Before Implementing Features
78
96
 
@@ -369,6 +387,59 @@ You can delete this .cursorrules file.
369
387
  return '0.3.0';
370
388
  }
371
389
  }
390
+
391
+ /**
392
+ * Load session answers from _progress.json
393
+ */
394
+ async loadSessionAnswers() {
395
+ const fs = require('fs-extra');
396
+ const path = require('path');
397
+ const progressPath = path.join(this.sessionPath, '_progress.json');
398
+
399
+ try {
400
+ if (await fs.pathExists(progressPath)) {
401
+ const progress = await fs.readJson(progressPath);
402
+ return progress.answers || {};
403
+ }
404
+ } catch (error) {
405
+ // Fall back to empty if can't load
406
+ }
407
+
408
+ return {};
409
+ }
410
+
411
+ /**
412
+ * Extract tech stack from any answer
413
+ */
414
+ extractTechStackFromAnswers(answers) {
415
+ for (const [questionId, answer] of Object.entries(answers)) {
416
+ if (typeof answer === 'string') {
417
+ const lower = answer.toLowerCase();
418
+ if (lower.includes('react') || lower.includes('vue') || lower.includes('angular') ||
419
+ lower.includes('node') || lower.includes('python') || lower.includes('next') ||
420
+ lower.includes('postgres') || lower.includes('mongo') || lower.includes('mysql')) {
421
+ return answer;
422
+ }
423
+ }
424
+ }
425
+ return null;
426
+ }
427
+
428
+ /**
429
+ * Extract "what are you building" from any answer
430
+ */
431
+ extractWhatBuildingFromAnswers(answers) {
432
+ for (const [questionId, answer] of Object.entries(answers)) {
433
+ if (questionId.toLowerCase().includes('goal') ||
434
+ questionId.toLowerCase().includes('building') ||
435
+ questionId.toLowerCase().includes('project')) {
436
+ if (typeof answer === 'string' && answer.length > 20) {
437
+ return answer;
438
+ }
439
+ }
440
+ }
441
+ return null;
442
+ }
372
443
  }
373
444
 
374
445
  module.exports = CursorGenerator;
@@ -41,7 +41,7 @@ class VSCodeGenerator extends ToolConfigGenerator {
41
41
  await this.ensureDir('.github');
42
42
 
43
43
  const content = this.framework === 'rapid' ?
44
- this.generateCopilotPRP() :
44
+ await this.generateCopilotPRP() :
45
45
  this.framework === 'balanced' ?
46
46
  this.generateCopilotBalanced() :
47
47
  this.generateCopilotBMAD();
@@ -49,23 +49,41 @@ class VSCodeGenerator extends ToolConfigGenerator {
49
49
  return await this.writeToProject('.github/copilot-instructions.md', content);
50
50
  }
51
51
 
52
- generateCopilotPRP() {
52
+ async generateCopilotPRP() {
53
53
  const projectName = this.getProjectName();
54
54
  const sections = this.outputs.sections || {};
55
+ const answers = await this.loadSessionAnswers();
56
+
57
+ // Extract content with fallback to answers
58
+ let goal = sections['1._goal_definition'] || sections['goal_definition'];
59
+ let techStack = this.extractTechStack(sections);
60
+ let blueprint = sections['4._implementation_blueprint'] || sections['implementation_blueprint'];
61
+ let validation = sections['5._validation'] || sections['validation'];
62
+
63
+ // Fallback to extracted answers if sections are empty
64
+ if (!goal || goal.length < 20) {
65
+ const whatBuilding = this.extractWhatBuildingFromAnswers(answers);
66
+ if (whatBuilding) goal = whatBuilding;
67
+ }
68
+
69
+ if (!techStack || techStack.includes('See framework')) {
70
+ const techFromAnswers = this.extractTechStackFromAnswers(answers);
71
+ if (techFromAnswers) techStack = techFromAnswers;
72
+ }
55
73
 
56
74
  return `# Copilot Instructions for ${projectName}
57
75
 
58
76
  ## Project Overview
59
77
 
60
- ${sections['1._goal_definition'] || sections['goal_definition'] || 'Software development project'}
78
+ ${goal || 'Software development project'}
61
79
 
62
80
  ## Tech Stack
63
81
 
64
- ${this.extractTechStack(sections)}
82
+ ${techStack || 'See PRP for tech stack'}
65
83
 
66
84
  ## Implementation Blueprint
67
85
 
68
- ${sections['4._implementation_blueprint'] || sections['implementation_blueprint'] || 'See PRP for details'}
86
+ ${blueprint || 'See PRP for implementation details'}
69
87
 
70
88
  ## Code Style
71
89
 
@@ -91,7 +109,7 @@ ${sections['4._implementation_blueprint'] || sections['implementation_blueprint'
91
109
 
92
110
  ## Success Criteria
93
111
 
94
- ${sections['5._validation'] || sections['validation'] || 'See PRP'}
112
+ ${validation || 'See PRP for validation criteria'}
95
113
 
96
114
  Ensure all code meets these criteria before considering it complete.
97
115
 
@@ -398,6 +416,57 @@ ${this.extractSection(prd, 'Performance') || '- Optimize critical paths\n- Monit
398
416
  return '0.3.0';
399
417
  }
400
418
  }
419
+
420
+ /**
421
+ * Load session answers from _progress.json
422
+ */
423
+ async loadSessionAnswers() {
424
+ const progressPath = path.join(this.sessionPath, '_progress.json');
425
+
426
+ try {
427
+ if (await fs.pathExists(progressPath)) {
428
+ const progress = await fs.readJson(progressPath);
429
+ return progress.answers || {};
430
+ }
431
+ } catch (error) {
432
+ // Fall back to empty if can't load
433
+ }
434
+
435
+ return {};
436
+ }
437
+
438
+ /**
439
+ * Extract tech stack from any answer
440
+ */
441
+ extractTechStackFromAnswers(answers) {
442
+ for (const [questionId, answer] of Object.entries(answers)) {
443
+ if (typeof answer === 'string') {
444
+ const lower = answer.toLowerCase();
445
+ if (lower.includes('react') || lower.includes('vue') || lower.includes('angular') ||
446
+ lower.includes('node') || lower.includes('python') || lower.includes('next') ||
447
+ lower.includes('postgres') || lower.includes('mongo') || lower.includes('mysql')) {
448
+ return answer;
449
+ }
450
+ }
451
+ }
452
+ return null;
453
+ }
454
+
455
+ /**
456
+ * Extract "what are you building" from any answer
457
+ */
458
+ extractWhatBuildingFromAnswers(answers) {
459
+ for (const [questionId, answer] of Object.entries(answers)) {
460
+ if (questionId.toLowerCase().includes('goal') ||
461
+ questionId.toLowerCase().includes('building') ||
462
+ questionId.toLowerCase().includes('project')) {
463
+ if (typeof answer === 'string' && answer.length > 20) {
464
+ return answer;
465
+ }
466
+ }
467
+ }
468
+ return null;
469
+ }
401
470
  }
402
471
 
403
472
  module.exports = VSCodeGenerator;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iservu-inc/adf-cli",
3
- "version": "0.4.35",
3
+ "version": "0.4.36",
4
4
  "description": "CLI tool for AgentDevFramework - AI-assisted development framework with multi-provider AI support",
5
5
  "main": "index.js",
6
6
  "bin": {