@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 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)
@@ -143,13 +143,32 @@ async function saveToEnvFile(envPath, key, value) {
143
143
  env[key] = value;
144
144
 
145
145
  const lines = [
146
- '# AI Provider API Keys for adf-cli',
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
- lines.push(`${k}="${v}"`);
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
 
@@ -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
- const { overwrite } = await inquirer.prompt([
67
- {
68
- type: 'confirm',
69
- name: 'overwrite',
70
- message: chalk.yellow('.adf directory already exists. Overwrite?'),
71
- default: false
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
- if (!overwrite) {
76
- console.log(chalk.yellow('\n✋ Initialization cancelled.\n'));
77
- return;
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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iservu-inc/adf-cli",
3
- "version": "0.4.31",
3
+ "version": "0.4.33",
4
4
  "description": "CLI tool for AgentDevFramework - AI-assisted development framework with multi-provider AI support",
5
5
  "main": "index.js",
6
6
  "bin": {