@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
|
+

|
|
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
|
package/lib/ai/ai-config.js
CHANGED
|
@@ -136,12 +136,9 @@ async function ensureGitignore(projectPath) {
|
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
/**
|
|
139
|
-
* Save
|
|
139
|
+
* Save entire env object to .env file
|
|
140
140
|
*/
|
|
141
|
-
async function
|
|
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
|
-
|
|
283
|
-
|
|
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: '
|
|
573
|
+
type: 'editor',
|
|
573
574
|
name: 'answer',
|
|
574
|
-
message: '
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
}
|
|
579
|
-
return true;
|
|
580
|
-
}
|
|
575
|
+
message: '',
|
|
576
|
+
waitForUseInput: false,
|
|
577
|
+
postfix: '.md',
|
|
578
|
+
default: ''
|
|
581
579
|
}
|
|
582
580
|
]);
|
|
583
581
|
|
|
584
|
-
|
|
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}
|
|
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: '
|
|
680
|
+
type: 'editor',
|
|
679
681
|
name: 'followUpAnswer',
|
|
680
|
-
message:
|
|
682
|
+
message: '',
|
|
683
|
+
waitForUseInput: false,
|
|
684
|
+
postfix: '.md',
|
|
685
|
+
default: ''
|
|
681
686
|
}
|
|
682
687
|
]);
|
|
683
688
|
|
package/package.json
CHANGED
|
Binary file
|