@iservu-inc/adf-cli 0.4.31 → 0.4.33
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 +85 -0
- package/lib/ai/ai-config.js +42 -7
- package/lib/commands/init.js +65 -13
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,91 @@ 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.33] - 2025-10-04
|
|
9
|
+
|
|
10
|
+
### ✨ Feature: Show Active Provider and Model
|
|
11
|
+
|
|
12
|
+
**Added: Active Configuration Display**
|
|
13
|
+
- **Problem:** All configured providers showed ✓ checkmark, impossible to know which is currently active
|
|
14
|
+
- **Solution:** Track and display currently active provider and model
|
|
15
|
+
|
|
16
|
+
**New Display:**
|
|
17
|
+
```
|
|
18
|
+
★ Currently Active: OpenAI GPT - o3
|
|
19
|
+
|
|
20
|
+
? Select AI provider:
|
|
21
|
+
> Anthropic Claude
|
|
22
|
+
OpenAI GPT ✓ Configured ★ Active
|
|
23
|
+
Google Gemini ✓ Configured
|
|
24
|
+
OpenRouter (Multi-Model) ✓ Configured
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
**Implementation:**
|
|
28
|
+
- New env variables: `ADF_CURRENT_PROVIDER`, `ADF_CURRENT_MODEL`
|
|
29
|
+
- Saved automatically after successful AI configuration
|
|
30
|
+
- Displayed at top of configuration screen
|
|
31
|
+
- ★ Active indicator in provider list
|
|
32
|
+
- Organized .env file with sections
|
|
33
|
+
|
|
34
|
+
**Code Changes:**
|
|
35
|
+
- ai-config.js:262-280 - Load and display current config
|
|
36
|
+
- ai-config.js:285-303 - Add ★ Active indicator to choices
|
|
37
|
+
- ai-config.js:476-478 - Save current selection
|
|
38
|
+
- ai-config.js:141-180 - Enhanced .env file formatting
|
|
39
|
+
|
|
40
|
+
**Enhanced .env File:**
|
|
41
|
+
```env
|
|
42
|
+
# AI Provider Configuration for adf-cli
|
|
43
|
+
# DO NOT commit this file to version control
|
|
44
|
+
|
|
45
|
+
# Currently Active Provider and Model
|
|
46
|
+
# (Set automatically when you configure AI provider)
|
|
47
|
+
ADF_CURRENT_PROVIDER="openai"
|
|
48
|
+
ADF_CURRENT_MODEL="o3"
|
|
49
|
+
|
|
50
|
+
# API Keys for Each Provider
|
|
51
|
+
OPENAI_API_KEY="sk-..."
|
|
52
|
+
GOOGLE_API_KEY="..."
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## [0.4.32] - 2025-10-04
|
|
58
|
+
|
|
59
|
+
### ✨ Improved: Smarter .adf Directory Detection
|
|
60
|
+
|
|
61
|
+
**Enhanced: Content-Based Initialization Check**
|
|
62
|
+
- **Problem:** `adf init` prompted to overwrite even when `.adf` only contained `.env` file
|
|
63
|
+
- **Solution:** Now checks for meaningful content before prompting
|
|
64
|
+
|
|
65
|
+
**New Behavior:**
|
|
66
|
+
- `.adf` with only `.env` file → Continues silently ✓
|
|
67
|
+
- `.adf` with session files → Prompts to overwrite ⚠️
|
|
68
|
+
- Empty `.adf` → Creates structure ✓
|
|
69
|
+
|
|
70
|
+
**Implementation:**
|
|
71
|
+
- New `hasMeaningfulContent()` function (init.js:167-204)
|
|
72
|
+
- Checks for sessions/, outputs/, progress files
|
|
73
|
+
- Ignores `.env`, `.gitignore`, hidden files
|
|
74
|
+
- Only prompts when actual work would be lost
|
|
75
|
+
|
|
76
|
+
**User Experience:**
|
|
77
|
+
```
|
|
78
|
+
# Before v0.4.32 (annoying)
|
|
79
|
+
.adf directory already exists. Overwrite? (y/N)
|
|
80
|
+
|
|
81
|
+
# After v0.4.32 (smart)
|
|
82
|
+
✓ Using existing .adf directory
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**Confirmed: .gitignore Protection Working**
|
|
86
|
+
- v0.4.30 added automatic root `.gitignore` creation
|
|
87
|
+
- Entry: `.adf/.env` (protects API keys)
|
|
88
|
+
- Created at project root, not in `.adf/`
|
|
89
|
+
- Non-destructive: only adds if missing
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
8
93
|
## [0.4.31] - 2025-10-04
|
|
9
94
|
|
|
10
95
|
### 🐛 Fix: OpenAI o-series Model Support (o3, o3-mini, o3-pro)
|
package/lib/ai/ai-config.js
CHANGED
|
@@ -143,13 +143,32 @@ async function saveToEnvFile(envPath, key, value) {
|
|
|
143
143
|
env[key] = value;
|
|
144
144
|
|
|
145
145
|
const lines = [
|
|
146
|
-
'# AI Provider
|
|
146
|
+
'# AI Provider Configuration for adf-cli',
|
|
147
147
|
'# DO NOT commit this file to version control',
|
|
148
|
-
''
|
|
148
|
+
'',
|
|
149
|
+
'# Currently Active Provider and Model',
|
|
150
|
+
'# (Set automatically when you configure AI provider)'
|
|
149
151
|
];
|
|
150
152
|
|
|
153
|
+
// Add current provider/model first
|
|
154
|
+
const currentKeys = ['ADF_CURRENT_PROVIDER', 'ADF_CURRENT_MODEL'];
|
|
155
|
+
currentKeys.forEach(k => {
|
|
156
|
+
if (env[k]) {
|
|
157
|
+
lines.push(`${k}="${env[k]}"`);
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
// Add separator if we have current config
|
|
162
|
+
if (env['ADF_CURRENT_PROVIDER'] || env['ADF_CURRENT_MODEL']) {
|
|
163
|
+
lines.push('');
|
|
164
|
+
lines.push('# API Keys for Each Provider');
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Add all other keys (API keys)
|
|
151
168
|
for (const [k, v] of Object.entries(env)) {
|
|
152
|
-
|
|
169
|
+
if (!currentKeys.includes(k)) {
|
|
170
|
+
lines.push(`${k}="${v}"`);
|
|
171
|
+
}
|
|
153
172
|
}
|
|
154
173
|
|
|
155
174
|
await fs.ensureDir(path.dirname(envPath));
|
|
@@ -259,6 +278,10 @@ async function configureAIProvider(projectPath = process.cwd()) {
|
|
|
259
278
|
}
|
|
260
279
|
}
|
|
261
280
|
|
|
281
|
+
// 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;
|
|
284
|
+
|
|
262
285
|
if (availableProviders.length > 0) {
|
|
263
286
|
console.log(chalk.green('✓ Detected API keys for:'));
|
|
264
287
|
availableProviders.forEach(p => {
|
|
@@ -267,25 +290,33 @@ async function configureAIProvider(projectPath = process.cwd()) {
|
|
|
267
290
|
console.log('');
|
|
268
291
|
}
|
|
269
292
|
|
|
293
|
+
// Show current active configuration if exists
|
|
294
|
+
if (currentProvider && currentModel) {
|
|
295
|
+
const currentProviderObj = AI_PROVIDERS[currentProvider.toUpperCase()];
|
|
296
|
+
if (currentProviderObj) {
|
|
297
|
+
console.log(chalk.cyan(`★ Currently Active: ${currentProviderObj.name} - ${currentModel}\n`));
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
270
301
|
// Provider selection
|
|
271
302
|
const providerChoices = [
|
|
272
303
|
{
|
|
273
|
-
name: `${AI_PROVIDERS.ANTHROPIC.name} ${availableProviders.find(p => p.id === 'anthropic') ? chalk.green('✓ Configured') : ''}`,
|
|
304
|
+
name: `${AI_PROVIDERS.ANTHROPIC.name} ${availableProviders.find(p => p.id === 'anthropic') ? chalk.green('✓ Configured') : ''} ${currentProvider === 'anthropic' ? chalk.cyan('★ Active') : ''}`,
|
|
274
305
|
value: 'anthropic',
|
|
275
306
|
short: 'Anthropic'
|
|
276
307
|
},
|
|
277
308
|
{
|
|
278
|
-
name: `${AI_PROVIDERS.OPENAI.name} ${availableProviders.find(p => p.id === 'openai') ? chalk.green('✓ Configured') : ''}`,
|
|
309
|
+
name: `${AI_PROVIDERS.OPENAI.name} ${availableProviders.find(p => p.id === 'openai') ? chalk.green('✓ Configured') : ''} ${currentProvider === 'openai' ? chalk.cyan('★ Active') : ''}`,
|
|
279
310
|
value: 'openai',
|
|
280
311
|
short: 'OpenAI'
|
|
281
312
|
},
|
|
282
313
|
{
|
|
283
|
-
name: `${AI_PROVIDERS.GOOGLE.name} ${availableProviders.find(p => p.id === 'google') ? chalk.green('✓ Configured') : ''}`,
|
|
314
|
+
name: `${AI_PROVIDERS.GOOGLE.name} ${availableProviders.find(p => p.id === 'google') ? chalk.green('✓ Configured') : ''} ${currentProvider === 'google' ? chalk.cyan('★ Active') : ''}`,
|
|
284
315
|
value: 'google',
|
|
285
316
|
short: 'Google'
|
|
286
317
|
},
|
|
287
318
|
{
|
|
288
|
-
name: `${AI_PROVIDERS.OPENROUTER.name} ${availableProviders.find(p => p.id === 'openrouter') ? chalk.green('✓ Configured') : ''}`,
|
|
319
|
+
name: `${AI_PROVIDERS.OPENROUTER.name} ${availableProviders.find(p => p.id === 'openrouter') ? chalk.green('✓ Configured') : ''} ${currentProvider === 'openrouter' ? chalk.cyan('★ Active') : ''}`,
|
|
289
320
|
value: 'openrouter',
|
|
290
321
|
short: 'OpenRouter'
|
|
291
322
|
}
|
|
@@ -461,6 +492,10 @@ async function configureAIProvider(projectPath = process.cwd()) {
|
|
|
461
492
|
|
|
462
493
|
console.log(chalk.gray('\n' + '━'.repeat(60)) + '\n');
|
|
463
494
|
|
|
495
|
+
// Save current provider and model selection to .env for future reference
|
|
496
|
+
await saveToEnvFile(envPath, 'ADF_CURRENT_PROVIDER', selectedProvider.id);
|
|
497
|
+
await saveToEnvFile(envPath, 'ADF_CURRENT_MODEL', config.model);
|
|
498
|
+
|
|
464
499
|
return config;
|
|
465
500
|
}
|
|
466
501
|
|
package/lib/commands/init.js
CHANGED
|
@@ -61,23 +61,31 @@ async function init(options) {
|
|
|
61
61
|
return;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
// Check if already initialized
|
|
64
|
+
// Check if already initialized with actual content
|
|
65
65
|
if (await fs.pathExists(adfDir)) {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
66
|
+
// Check for meaningful content (not just .env file)
|
|
67
|
+
const hasContent = await hasMeaningfulContent(adfDir);
|
|
68
|
+
|
|
69
|
+
if (hasContent) {
|
|
70
|
+
const { overwrite } = await inquirer.prompt([
|
|
71
|
+
{
|
|
72
|
+
type: 'confirm',
|
|
73
|
+
name: 'overwrite',
|
|
74
|
+
message: chalk.yellow('.adf directory already exists with sessions. Overwrite?'),
|
|
75
|
+
default: false
|
|
76
|
+
}
|
|
77
|
+
]);
|
|
78
|
+
|
|
79
|
+
if (!overwrite) {
|
|
80
|
+
console.log(chalk.yellow('\n✋ Initialization cancelled.\n'));
|
|
81
|
+
return;
|
|
72
82
|
}
|
|
73
|
-
]);
|
|
74
83
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
84
|
+
await fs.remove(adfDir);
|
|
85
|
+
} else {
|
|
86
|
+
// Only .env file exists - safe to continue without prompting
|
|
87
|
+
console.log(chalk.gray('✓ Using existing .adf directory\n'));
|
|
78
88
|
}
|
|
79
|
-
|
|
80
|
-
await fs.remove(adfDir);
|
|
81
89
|
}
|
|
82
90
|
|
|
83
91
|
// Detect project type
|
|
@@ -151,4 +159,48 @@ async function init(options) {
|
|
|
151
159
|
console.log(chalk.green.bold('\n✅ All done! Happy coding! 🚀\n'));
|
|
152
160
|
}
|
|
153
161
|
|
|
162
|
+
/**
|
|
163
|
+
* Check if .adf directory has meaningful content
|
|
164
|
+
* Returns true if there are session files, progress files, or outputs
|
|
165
|
+
* Returns false if only .env or empty
|
|
166
|
+
*/
|
|
167
|
+
async function hasMeaningfulContent(adfDir) {
|
|
168
|
+
try {
|
|
169
|
+
const contents = await fs.readdir(adfDir);
|
|
170
|
+
|
|
171
|
+
// Filter out .env and other config files that don't represent sessions
|
|
172
|
+
const meaningfulFiles = contents.filter(item => {
|
|
173
|
+
return item !== '.env' &&
|
|
174
|
+
item !== '.gitignore' &&
|
|
175
|
+
!item.startsWith('.');
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
if (meaningfulFiles.length === 0) {
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Check for session directories or files
|
|
183
|
+
for (const item of meaningfulFiles) {
|
|
184
|
+
const itemPath = path.join(adfDir, item);
|
|
185
|
+
const stats = await fs.stat(itemPath);
|
|
186
|
+
|
|
187
|
+
if (stats.isDirectory()) {
|
|
188
|
+
// Check if directory has files (sessions/, outputs/, etc.)
|
|
189
|
+
const dirContents = await fs.readdir(itemPath);
|
|
190
|
+
if (dirContents.length > 0) {
|
|
191
|
+
return true;
|
|
192
|
+
}
|
|
193
|
+
} else if (stats.isFile()) {
|
|
194
|
+
// Any non-config file indicates content
|
|
195
|
+
return true;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return false;
|
|
200
|
+
} catch (error) {
|
|
201
|
+
// If error reading, assume no content
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
154
206
|
module.exports = init;
|