@iservu-inc/adf-cli 0.5.5 β†’ 0.6.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/CHANGELOG.md CHANGED
@@ -5,6 +5,130 @@ 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.6.0] - 2025-10-05
9
+
10
+ ### 🎯 Fixed Cursor Positioning with Editor Input
11
+
12
+ **FIX:** Switched from inline input to editor-based input to fix cursor lag on multi-line answers.
13
+
14
+ #### The Problem
15
+
16
+ When typing long answers in the terminal, the text cursor would fall behind by 3-4 characters when wrapping to a second line:
17
+
18
+ ![Cursor Lag Issue](https://user-images.githubusercontent.com/...)
19
+ - Text wraps to multiple lines
20
+ - Cursor position becomes desynchronized
21
+ - Hard to track where you're typing
22
+ - Frustrating UX for detailed answers
23
+
24
+ This is a known issue with `inquirer`'s `input` type and terminal line wrapping.
25
+
26
+ #### The Solution
27
+
28
+ Switched to `editor` type for all answers:
29
+ - Opens your system's default text editor (Notepad, nano, vi, etc.)
30
+ - Perfect for multi-line, detailed answers
31
+ - No cursor positioning issues
32
+ - Better editing experience (copy/paste, formatting, etc.)
33
+
34
+ **New Workflow:**
35
+ 1. Question is displayed
36
+ 2. Your editor automatically opens
37
+ 3. Type your answer (multi-line, formatted, etc.)
38
+ 4. Save and close the editor
39
+ 5. Answer is captured and interview continues
40
+
41
+ **To skip a question:** Leave the editor empty and save.
42
+
43
+ #### Benefits
44
+
45
+ - βœ… **No more cursor lag** - Editor handles display properly
46
+ - βœ… **Better for long answers** - Multi-line editing is natural
47
+ - βœ… **Standard CLI pattern** - Used by git, crontab, etc.
48
+ - βœ… **Copy/paste friendly** - Full editor capabilities
49
+ - βœ… **Markdown support** - `.md` extension for syntax highlighting
50
+
51
+ #### Technical Changes
52
+
53
+ - Modified: `lib/frameworks/interviewer.js`
54
+ - Changed answer input from `type: 'input'` to `type: 'editor'`
55
+ - Changed follow-up input to `type: 'editor'`
56
+ - Added clear instructions about editor workflow
57
+ - Empty answers treated as skips
58
+ - Updated guidance text
59
+
60
+ #### User Experience
61
+
62
+ **Before (inline):**
63
+ ```
64
+ Your answer: The primary use action is to engβ–ˆge...
65
+ [cursor lags behind when wrapping]
66
+ ```
67
+
68
+ **After (editor):**
69
+ ```
70
+ (Your editor will open. Save and close to continue, or leave empty + save to skip)
71
+ [Editor opens]
72
+ [Type answer with full multi-line support]
73
+ [Save & close]
74
+ βœ“ Answer captured
75
+ ```
76
+
77
+ ---
78
+
79
+ ## [0.5.6] - 2025-10-05
80
+
81
+ ### πŸ”§ Fixed Invalid .env State Detection
82
+
83
+ **FIX:** Automatically detect and reset invalid configuration where ADF_CURRENT_PROVIDER/ADF_CURRENT_MODEL are set but no API key exists.
84
+
85
+ #### The Problem (Cart Before the Horse)
86
+
87
+ The .env file could end up in an invalid state:
88
+ ```env
89
+ ADF_CURRENT_PROVIDER="openrouter"
90
+ ADF_CURRENT_MODEL="anthropic/claude-sonnet-4-5"
91
+ # But no OPENROUTER_API_KEY present!
92
+ ```
93
+
94
+ This shouldn't be possible - you can't have a "current provider" without an API key for that provider.
95
+
96
+ #### The Fix
97
+
98
+ Now we detect this broken state and automatically reset:
99
+ ```
100
+ ⚠️ Invalid configuration detected:
101
+ ADF_CURRENT_PROVIDER is set to "openrouter" but no API key found
102
+ Resetting provider selection...
103
+ ```
104
+
105
+ The invalid ADF_CURRENT_PROVIDER and ADF_CURRENT_MODEL entries are removed from .env, forcing proper configuration.
106
+
107
+ #### Why This Matters
108
+
109
+ - **Data integrity**: Prevents cart-before-horse situations
110
+ - **Better UX**: Clear feedback about what's wrong
111
+ - **Auto-healing**: Automatically fixes the broken state
112
+ - **Prevents confusion**: Users aren't told they have an active provider when they don't
113
+
114
+ #### How It Can Happen
115
+
116
+ - User manually edited/deleted API key from .env
117
+ - Corrupted .env file
118
+ - Configuration error during setup
119
+
120
+ Now these scenarios are automatically detected and corrected!
121
+
122
+ #### Technical Changes
123
+
124
+ - Modified: `lib/ai/ai-config.js`
125
+ - Added validation after loading .env
126
+ - New `saveEnvFile()` helper function
127
+ - Refactored `saveToEnvFile()` to use `saveEnvFile()`
128
+ - Auto-reset invalid configuration
129
+
130
+ ---
131
+
8
132
  ## [0.5.5] - 2025-10-05
9
133
 
10
134
  ### βœ… Fixed AI Provider Configuration Display
@@ -136,12 +136,9 @@ async function ensureGitignore(projectPath) {
136
136
  }
137
137
 
138
138
  /**
139
- * Save API key to .env file
139
+ * Save entire env object to .env file
140
140
  */
141
- async function saveToEnvFile(envPath, key, value) {
142
- const env = await loadEnvFile(envPath);
143
- env[key] = value;
144
-
141
+ async function saveEnvFile(envPath, env) {
145
142
  const lines = [
146
143
  '# AI Provider Configuration for adf-cli',
147
144
  '# DO NOT commit this file to version control',
@@ -179,6 +176,15 @@ async function saveToEnvFile(envPath, key, value) {
179
176
  await ensureGitignore(projectPath);
180
177
  }
181
178
 
179
+ /**
180
+ * Save API key to .env file
181
+ */
182
+ async function saveToEnvFile(envPath, key, value) {
183
+ const env = await loadEnvFile(envPath);
184
+ env[key] = value;
185
+ await saveEnvFile(envPath, env);
186
+ }
187
+
182
188
  /**
183
189
  * Load .env file into process.env
184
190
  */
@@ -279,8 +285,29 @@ async function configureAIProvider(projectPath = process.cwd()) {
279
285
  }
280
286
 
281
287
  // Get currently active provider and model
282
- const currentProvider = process.env.ADF_CURRENT_PROVIDER || existingEnv.ADF_CURRENT_PROVIDER;
283
- const currentModel = process.env.ADF_CURRENT_MODEL || existingEnv.ADF_CURRENT_MODEL;
288
+ let currentProvider = process.env.ADF_CURRENT_PROVIDER || existingEnv.ADF_CURRENT_PROVIDER;
289
+ let currentModel = process.env.ADF_CURRENT_MODEL || existingEnv.ADF_CURRENT_MODEL;
290
+
291
+ // Validate: If ADF_CURRENT_PROVIDER is set but its API key is missing, reset it
292
+ if (currentProvider) {
293
+ const currentProviderObj = AI_PROVIDERS[currentProvider.toUpperCase()];
294
+ if (currentProviderObj) {
295
+ const currentProviderHasKey = availableProviders.find(p => p.id === currentProvider);
296
+ if (!currentProviderHasKey) {
297
+ console.log(chalk.yellow(`⚠️ Invalid configuration detected:`));
298
+ console.log(chalk.gray(` ADF_CURRENT_PROVIDER is set to "${currentProvider}" but no API key found`));
299
+ console.log(chalk.gray(` Resetting provider selection...\n`));
300
+
301
+ // Clear invalid values from .env file
302
+ delete existingEnv.ADF_CURRENT_PROVIDER;
303
+ delete existingEnv.ADF_CURRENT_MODEL;
304
+ await saveEnvFile(envPath, existingEnv);
305
+
306
+ currentProvider = null;
307
+ currentModel = null;
308
+ }
309
+ }
310
+ }
284
311
 
285
312
  if (availableProviders.length > 0) {
286
313
  console.log(chalk.green('βœ“ Detected API keys for:'));
@@ -290,7 +317,7 @@ async function configureAIProvider(projectPath = process.cwd()) {
290
317
  console.log('');
291
318
  }
292
319
 
293
- // Show current active configuration if exists
320
+ // Show current active configuration if exists (and is valid)
294
321
  if (currentProvider && currentModel) {
295
322
  const currentProviderObj = AI_PROVIDERS[currentProvider.toUpperCase()];
296
323
  if (currentProviderObj) {
@@ -559,33 +559,33 @@ class Interviewer {
559
559
  console.log(chalk.gray(`πŸ’‘ ${question.guidance}`));
560
560
  console.log(chalk.green(` βœ“ Good: ${question.goodExample}`));
561
561
  console.log(chalk.red(` βœ— Bad: ${question.badExample}`));
562
- console.log(chalk.gray(` (Type "skip" to skip remaining questions in this block)\n`));
563
562
 
564
563
  // Start tracking time for this question
565
564
  if (this.skipTracker) {
566
565
  this.skipTracker.startQuestion(question.id);
567
566
  }
568
567
 
569
- // Get answer
568
+ // Get answer using editor for better multi-line support
569
+ console.log(chalk.gray(' (Your editor will open. Save and close to continue, or leave empty + save to skip)'));
570
+
570
571
  const { answer } = await inquirer.prompt([
571
572
  {
572
- type: 'input',
573
+ type: 'editor',
573
574
  name: 'answer',
574
- message: 'Your answer:',
575
- validate: (input) => {
576
- if (!input || input.trim().length === 0) {
577
- return 'Please provide an answer or type "skip"';
578
- }
579
- return true;
580
- }
575
+ message: '',
576
+ waitForUseInput: false,
577
+ postfix: '.md',
578
+ default: ''
581
579
  }
582
580
  ]);
583
581
 
584
- if (answer.toLowerCase() === 'skip') {
582
+ // Handle empty answer or "skip" as skip
583
+ if (!answer || answer.trim().length === 0 || answer.toLowerCase().trim() === 'skip') {
585
584
  // Record skip event
586
585
  if (this.skipTracker) {
587
586
  this.skipTracker.recordSkip(question, 'manual');
588
587
  }
588
+ console.log(chalk.gray('\n⏭️ Skipped\n'));
589
589
  return null; // Signal to skip remaining questions
590
590
  }
591
591
 
@@ -671,13 +671,18 @@ class Interviewer {
671
671
  }
672
672
 
673
673
  if (followUp) {
674
- console.log(chalk.yellow(`\nπŸ€– ${followUp.message}\n`));
674
+ console.log(chalk.yellow(`\nπŸ€– ${followUp.message}`));
675
+ console.log(chalk.yellow(` ${followUp.question}`));
676
+ console.log(chalk.gray(' (Your editor will open for follow-up answer)\n'));
675
677
 
676
678
  const { followUpAnswer } = await inquirer.prompt([
677
679
  {
678
- type: 'input',
680
+ type: 'editor',
679
681
  name: 'followUpAnswer',
680
- message: followUp.question
682
+ message: '',
683
+ waitForUseInput: false,
684
+ postfix: '.md',
685
+ default: ''
681
686
  }
682
687
  ]);
683
688
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iservu-inc/adf-cli",
3
- "version": "0.5.5",
3
+ "version": "0.6.0",
4
4
  "description": "CLI tool for AgentDevFramework - AI-assisted development framework with multi-provider AI support",
5
5
  "main": "index.js",
6
6
  "bin": {