clavix 3.2.2 → 3.3.1
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/dist/cli/commands/config.d.ts +4 -2
- package/dist/cli/commands/config.js +262 -91
- package/dist/cli/commands/init.js +62 -103
- package/dist/cli/commands/update.js +15 -43
- package/dist/core/adapters/base-adapter.d.ts +13 -0
- package/dist/core/adapters/base-adapter.js +37 -0
- package/dist/core/adapters/claude-code-adapter.d.ts +5 -0
- package/dist/core/adapters/claude-code-adapter.js +9 -0
- package/dist/index 2.js +13 -0
- package/dist/index.d 2.ts +4 -0
- package/dist/types/agent.d.ts +1 -0
- package/dist/utils/provider-selector.d.ts +8 -0
- package/dist/utils/provider-selector.js +60 -0
- package/package.json +1 -1
|
@@ -12,17 +12,19 @@ export default class Config extends Command {
|
|
|
12
12
|
};
|
|
13
13
|
run(): Promise<void>;
|
|
14
14
|
private showInteractiveMenu;
|
|
15
|
+
private manageProviders;
|
|
16
|
+
private addProviders;
|
|
17
|
+
private removeProviders;
|
|
18
|
+
private replaceProviders;
|
|
15
19
|
private getConfig;
|
|
16
20
|
private setConfig;
|
|
17
21
|
private editConfig;
|
|
18
22
|
private resetConfig;
|
|
19
|
-
private changeAgent;
|
|
20
23
|
private editPreferences;
|
|
21
24
|
private loadConfig;
|
|
22
25
|
private saveConfig;
|
|
23
26
|
private displayConfig;
|
|
24
27
|
private getNestedValue;
|
|
25
28
|
private setNestedValue;
|
|
26
|
-
private getDefaultConfig;
|
|
27
29
|
}
|
|
28
30
|
//# sourceMappingURL=config.d.ts.map
|
|
@@ -4,13 +4,14 @@ import fs from 'fs-extra';
|
|
|
4
4
|
import * as path from 'path';
|
|
5
5
|
import inquirer from 'inquirer';
|
|
6
6
|
import { AgentManager } from '../../core/agent-manager.js';
|
|
7
|
+
import { DEFAULT_CONFIG, isLegacyConfig, migrateConfig } from '../../types/config.js';
|
|
8
|
+
import { loadCommandTemplates } from '../../utils/template-loader.js';
|
|
7
9
|
export default class Config extends Command {
|
|
8
10
|
static description = 'Manage Clavix configuration';
|
|
9
11
|
static examples = [
|
|
10
12
|
'<%= config.bin %> <%= command.id %>',
|
|
11
|
-
'<%= config.bin %> <%= command.id %> get
|
|
12
|
-
'<%= config.bin %> <%= command.id %> set
|
|
13
|
-
'<%= config.bin %> <%= command.id %> edit',
|
|
13
|
+
'<%= config.bin %> <%= command.id %> get providers',
|
|
14
|
+
'<%= config.bin %> <%= command.id %> set preferences.verboseLogging true',
|
|
14
15
|
];
|
|
15
16
|
static args = {
|
|
16
17
|
action: Args.string({
|
|
@@ -71,39 +72,246 @@ export default class Config extends Command {
|
|
|
71
72
|
}
|
|
72
73
|
}
|
|
73
74
|
async showInteractiveMenu(configPath) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
75
|
+
let continueMenu = true;
|
|
76
|
+
while (continueMenu) {
|
|
77
|
+
const config = this.loadConfig(configPath);
|
|
78
|
+
this.log(chalk.bold.cyan('\n⚙️ Clavix Configuration\n'));
|
|
79
|
+
this.displayConfig(config);
|
|
80
|
+
const { action } = await inquirer.prompt([
|
|
81
|
+
{
|
|
82
|
+
type: 'list',
|
|
83
|
+
name: 'action',
|
|
84
|
+
message: 'What would you like to do?',
|
|
85
|
+
choices: [
|
|
86
|
+
{ name: 'View current configuration', value: 'view' },
|
|
87
|
+
{ name: 'Manage providers (add/remove)', value: 'providers' },
|
|
88
|
+
{ name: 'Edit preferences', value: 'edit-preferences' },
|
|
89
|
+
{ name: 'Reset to defaults', value: 'reset' },
|
|
90
|
+
{ name: 'Exit', value: 'exit' },
|
|
91
|
+
],
|
|
92
|
+
},
|
|
93
|
+
]);
|
|
94
|
+
switch (action) {
|
|
95
|
+
case 'view':
|
|
96
|
+
// Already displayed above
|
|
97
|
+
break;
|
|
98
|
+
case 'providers':
|
|
99
|
+
await this.manageProviders(config, configPath);
|
|
100
|
+
break;
|
|
101
|
+
case 'edit-preferences':
|
|
102
|
+
await this.editPreferences(configPath, config);
|
|
103
|
+
break;
|
|
104
|
+
case 'reset':
|
|
105
|
+
await this.resetConfig(configPath);
|
|
106
|
+
break;
|
|
107
|
+
case 'exit':
|
|
108
|
+
continueMenu = false;
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
async manageProviders(config, configPath) {
|
|
114
|
+
const agentManager = new AgentManager();
|
|
115
|
+
while (true) {
|
|
116
|
+
// Show current providers
|
|
117
|
+
this.log(chalk.cyan('\n📦 Current Providers:'));
|
|
118
|
+
if (config.providers.length === 0) {
|
|
119
|
+
this.log(chalk.gray(' (none configured)'));
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
for (const providerName of config.providers) {
|
|
123
|
+
const adapter = agentManager.getAdapter(providerName);
|
|
124
|
+
const displayName = adapter?.displayName || providerName;
|
|
125
|
+
this.log(chalk.gray(` • ${displayName}`));
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
// Submenu
|
|
129
|
+
const { action } = await inquirer.prompt([
|
|
130
|
+
{
|
|
131
|
+
type: 'list',
|
|
132
|
+
name: 'action',
|
|
133
|
+
message: 'What would you like to do?',
|
|
134
|
+
choices: [
|
|
135
|
+
{ name: 'Add provider', value: 'add' },
|
|
136
|
+
{ name: 'Remove provider', value: 'remove' },
|
|
137
|
+
{ name: 'Replace all providers', value: 'replace' },
|
|
138
|
+
{ name: 'Back to main menu', value: 'back' },
|
|
139
|
+
],
|
|
140
|
+
},
|
|
141
|
+
]);
|
|
142
|
+
if (action === 'back')
|
|
143
|
+
break;
|
|
144
|
+
switch (action) {
|
|
145
|
+
case 'add':
|
|
146
|
+
await this.addProviders(config, configPath);
|
|
147
|
+
break;
|
|
148
|
+
case 'remove':
|
|
149
|
+
await this.removeProviders(config, configPath);
|
|
150
|
+
break;
|
|
151
|
+
case 'replace':
|
|
152
|
+
await this.replaceProviders(config, configPath);
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
// Reload config after modifications
|
|
156
|
+
config = this.loadConfig(configPath);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
async addProviders(config, configPath) {
|
|
160
|
+
const agentManager = new AgentManager();
|
|
161
|
+
const allProviders = agentManager.getAdapters();
|
|
162
|
+
// Show only non-selected providers
|
|
163
|
+
const availableToAdd = allProviders.filter((a) => !config.providers.includes(a.name));
|
|
164
|
+
if (availableToAdd.length === 0) {
|
|
165
|
+
this.log(chalk.yellow('\n✓ All providers already added!'));
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
// Multi-select checkbox
|
|
169
|
+
const { newProviders } = await inquirer.prompt([
|
|
78
170
|
{
|
|
79
|
-
type: '
|
|
80
|
-
name: '
|
|
81
|
-
message: '
|
|
82
|
-
choices:
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
{ name: 'Reset to defaults', value: 'reset' },
|
|
87
|
-
{ name: 'Exit', value: 'exit' },
|
|
88
|
-
],
|
|
171
|
+
type: 'checkbox',
|
|
172
|
+
name: 'newProviders',
|
|
173
|
+
message: 'Select providers to add:',
|
|
174
|
+
choices: availableToAdd.map((adapter) => ({
|
|
175
|
+
name: `${adapter.displayName} (${adapter.directory})`,
|
|
176
|
+
value: adapter.name,
|
|
177
|
+
})),
|
|
89
178
|
},
|
|
90
179
|
]);
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
break;
|
|
95
|
-
case 'change-agent':
|
|
96
|
-
await this.changeAgent(configPath, config);
|
|
97
|
-
break;
|
|
98
|
-
case 'edit-preferences':
|
|
99
|
-
await this.editPreferences(configPath, config);
|
|
100
|
-
break;
|
|
101
|
-
case 'reset':
|
|
102
|
-
await this.resetConfig(configPath);
|
|
103
|
-
break;
|
|
104
|
-
case 'exit':
|
|
105
|
-
return;
|
|
180
|
+
if (newProviders.length === 0) {
|
|
181
|
+
this.log(chalk.gray('No providers selected'));
|
|
182
|
+
return;
|
|
106
183
|
}
|
|
184
|
+
// Add to config
|
|
185
|
+
config.providers.push(...newProviders);
|
|
186
|
+
this.saveConfig(configPath, config);
|
|
187
|
+
this.log(chalk.gray('\n🔧 Generating commands for new providers...'));
|
|
188
|
+
// Generate commands for new providers
|
|
189
|
+
for (const providerName of newProviders) {
|
|
190
|
+
const adapter = agentManager.getAdapter(providerName);
|
|
191
|
+
if (!adapter)
|
|
192
|
+
continue;
|
|
193
|
+
const templates = await loadCommandTemplates(adapter);
|
|
194
|
+
await adapter.generateCommands(templates);
|
|
195
|
+
this.log(chalk.green(` ✓ Generated ${templates.length} command(s) for ${adapter.displayName}`));
|
|
196
|
+
}
|
|
197
|
+
this.log(chalk.green('\n✅ Providers added successfully!'));
|
|
198
|
+
}
|
|
199
|
+
async removeProviders(config, configPath) {
|
|
200
|
+
if (config.providers.length === 0) {
|
|
201
|
+
this.log(chalk.yellow('\n⚠ No providers configured!'));
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
const agentManager = new AgentManager();
|
|
205
|
+
// Multi-select from current providers
|
|
206
|
+
const { providersToRemove } = await inquirer.prompt([
|
|
207
|
+
{
|
|
208
|
+
type: 'checkbox',
|
|
209
|
+
name: 'providersToRemove',
|
|
210
|
+
message: 'Select providers to remove:',
|
|
211
|
+
choices: config.providers.map((name) => {
|
|
212
|
+
const adapter = agentManager.getAdapter(name);
|
|
213
|
+
return {
|
|
214
|
+
name: `${adapter?.displayName || name} (${adapter?.directory || 'unknown'})`,
|
|
215
|
+
value: name,
|
|
216
|
+
};
|
|
217
|
+
}),
|
|
218
|
+
validate: (answer) => {
|
|
219
|
+
if (answer.length === config.providers.length) {
|
|
220
|
+
return 'You must keep at least one provider. Use "Reset to defaults" to reconfigure completely.';
|
|
221
|
+
}
|
|
222
|
+
return true;
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
]);
|
|
226
|
+
if (providersToRemove.length === 0) {
|
|
227
|
+
this.log(chalk.gray('No providers selected'));
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
// Confirm cleanup
|
|
231
|
+
const { cleanup } = await inquirer.prompt([
|
|
232
|
+
{
|
|
233
|
+
type: 'confirm',
|
|
234
|
+
name: 'cleanup',
|
|
235
|
+
message: 'Remove command files for these providers?',
|
|
236
|
+
default: true,
|
|
237
|
+
},
|
|
238
|
+
]);
|
|
239
|
+
// Remove from config
|
|
240
|
+
config.providers = config.providers.filter((p) => !providersToRemove.includes(p));
|
|
241
|
+
this.saveConfig(configPath, config);
|
|
242
|
+
// Clean up command files
|
|
243
|
+
if (cleanup) {
|
|
244
|
+
this.log(chalk.gray('\n🗑️ Cleaning up command files...'));
|
|
245
|
+
for (const providerName of providersToRemove) {
|
|
246
|
+
const adapter = agentManager.getAdapter(providerName);
|
|
247
|
+
if (adapter) {
|
|
248
|
+
const removed = await adapter.removeAllCommands();
|
|
249
|
+
this.log(chalk.gray(` ✓ Removed ${removed} command(s) from ${adapter.displayName}`));
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
this.log(chalk.green('\n✅ Providers removed successfully!'));
|
|
254
|
+
}
|
|
255
|
+
async replaceProviders(config, configPath) {
|
|
256
|
+
const agentManager = new AgentManager();
|
|
257
|
+
// Use shared provider selector
|
|
258
|
+
const { selectProviders } = await import('../../utils/provider-selector.js');
|
|
259
|
+
const newProviders = await selectProviders(agentManager, config.providers);
|
|
260
|
+
if (newProviders.length === 0) {
|
|
261
|
+
this.log(chalk.gray('No providers selected'));
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
// Find deselected providers
|
|
265
|
+
const deselected = config.providers.filter((p) => !newProviders.includes(p));
|
|
266
|
+
// Handle cleanup if providers were deselected
|
|
267
|
+
if (deselected.length > 0) {
|
|
268
|
+
this.log(chalk.yellow('\n⚠ Previously configured but not selected:'));
|
|
269
|
+
for (const providerName of deselected) {
|
|
270
|
+
const adapter = agentManager.getAdapter(providerName);
|
|
271
|
+
const displayName = adapter?.displayName || providerName;
|
|
272
|
+
const directory = adapter?.directory || 'unknown';
|
|
273
|
+
this.log(chalk.gray(` • ${displayName} (${directory})`));
|
|
274
|
+
}
|
|
275
|
+
const { cleanupAction } = await inquirer.prompt([
|
|
276
|
+
{
|
|
277
|
+
type: 'list',
|
|
278
|
+
name: 'cleanupAction',
|
|
279
|
+
message: 'What would you like to do with these providers?',
|
|
280
|
+
choices: [
|
|
281
|
+
{ name: 'Clean up (remove all command files)', value: 'cleanup' },
|
|
282
|
+
{ name: 'Skip (leave as-is)', value: 'skip' },
|
|
283
|
+
],
|
|
284
|
+
},
|
|
285
|
+
]);
|
|
286
|
+
if (cleanupAction === 'cleanup') {
|
|
287
|
+
this.log(chalk.gray('\n🗑️ Cleaning up deselected providers...'));
|
|
288
|
+
for (const providerName of deselected) {
|
|
289
|
+
const adapter = agentManager.getAdapter(providerName);
|
|
290
|
+
if (adapter) {
|
|
291
|
+
const removed = await adapter.removeAllCommands();
|
|
292
|
+
this.log(chalk.gray(` ✓ Removed ${removed} command(s) from ${adapter.displayName}`));
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
// Update config
|
|
298
|
+
config.providers = newProviders;
|
|
299
|
+
this.saveConfig(configPath, config);
|
|
300
|
+
// Prompt to run update
|
|
301
|
+
const { runUpdate } = await inquirer.prompt([
|
|
302
|
+
{
|
|
303
|
+
type: 'confirm',
|
|
304
|
+
name: 'runUpdate',
|
|
305
|
+
message: 'Run update to regenerate all commands?',
|
|
306
|
+
default: true,
|
|
307
|
+
},
|
|
308
|
+
]);
|
|
309
|
+
if (runUpdate) {
|
|
310
|
+
this.log(chalk.gray('\n🔧 Regenerating commands for all providers...\n'));
|
|
311
|
+
const Update = (await import('./update.js')).default;
|
|
312
|
+
await Update.run([]);
|
|
313
|
+
}
|
|
314
|
+
this.log(chalk.green('\n✅ Providers replaced successfully!'));
|
|
107
315
|
}
|
|
108
316
|
async getConfig(configPath, key) {
|
|
109
317
|
const config = this.loadConfig(configPath);
|
|
@@ -153,57 +361,33 @@ export default class Config extends Command {
|
|
|
153
361
|
return;
|
|
154
362
|
}
|
|
155
363
|
const config = this.loadConfig(configPath);
|
|
156
|
-
const defaultConfig =
|
|
364
|
+
const defaultConfig = {
|
|
365
|
+
...DEFAULT_CONFIG,
|
|
366
|
+
providers: config.providers, // Keep existing providers
|
|
367
|
+
};
|
|
157
368
|
this.saveConfig(configPath, defaultConfig);
|
|
158
|
-
this.log(chalk.green('✅ Configuration reset to defaults'));
|
|
159
|
-
}
|
|
160
|
-
async changeAgent(configPath, config) {
|
|
161
|
-
const agentManager = new AgentManager();
|
|
162
|
-
const availableAgents = await agentManager.detectAgents();
|
|
163
|
-
if (availableAgents.length === 0) {
|
|
164
|
-
this.error('No supported agents detected in this project');
|
|
165
|
-
}
|
|
166
|
-
const { newAgent } = await inquirer.prompt([
|
|
167
|
-
{
|
|
168
|
-
type: 'list',
|
|
169
|
-
name: 'newAgent',
|
|
170
|
-
message: 'Select agent:',
|
|
171
|
-
choices: availableAgents.map(agent => ({
|
|
172
|
-
name: agent.displayName,
|
|
173
|
-
value: agent.name,
|
|
174
|
-
})),
|
|
175
|
-
default: config.agent,
|
|
176
|
-
},
|
|
177
|
-
]);
|
|
178
|
-
if (newAgent === config.agent) {
|
|
179
|
-
this.log(chalk.gray('No changes made'));
|
|
180
|
-
return;
|
|
181
|
-
}
|
|
182
|
-
config.agent = newAgent;
|
|
183
|
-
this.saveConfig(configPath, config);
|
|
184
|
-
this.log(chalk.green(`✅ Agent changed to ${newAgent}`));
|
|
185
|
-
this.log(chalk.yellow('\n⚠️ Run ') + chalk.cyan('clavix update') + chalk.yellow(' to update slash commands'));
|
|
369
|
+
this.log(chalk.green('✅ Configuration reset to defaults (providers preserved)'));
|
|
186
370
|
}
|
|
187
371
|
async editPreferences(configPath, config) {
|
|
188
|
-
const preferences = config.preferences ||
|
|
372
|
+
const preferences = config.preferences || DEFAULT_CONFIG.preferences;
|
|
189
373
|
const answers = await inquirer.prompt([
|
|
190
374
|
{
|
|
191
375
|
type: 'confirm',
|
|
192
376
|
name: 'autoOpenOutputs',
|
|
193
377
|
message: 'Auto-open generated outputs?',
|
|
194
|
-
default: preferences.autoOpenOutputs
|
|
378
|
+
default: preferences.autoOpenOutputs,
|
|
195
379
|
},
|
|
196
380
|
{
|
|
197
381
|
type: 'confirm',
|
|
198
382
|
name: 'verboseLogging',
|
|
199
383
|
message: 'Enable verbose logging?',
|
|
200
|
-
default: preferences.verboseLogging
|
|
384
|
+
default: preferences.verboseLogging,
|
|
201
385
|
},
|
|
202
386
|
{
|
|
203
387
|
type: 'confirm',
|
|
204
388
|
name: 'preserveSessions',
|
|
205
389
|
message: 'Preserve completed sessions?',
|
|
206
|
-
default: preferences.preserveSessions
|
|
390
|
+
default: preferences.preserveSessions,
|
|
207
391
|
},
|
|
208
392
|
]);
|
|
209
393
|
config.preferences = answers;
|
|
@@ -212,7 +396,15 @@ export default class Config extends Command {
|
|
|
212
396
|
}
|
|
213
397
|
loadConfig(configPath) {
|
|
214
398
|
try {
|
|
215
|
-
|
|
399
|
+
const rawConfig = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
400
|
+
// Check if legacy config and migrate
|
|
401
|
+
if (isLegacyConfig(rawConfig)) {
|
|
402
|
+
this.warn(chalk.yellow('Detected legacy config format. Migrating to new format...'));
|
|
403
|
+
const migratedConfig = migrateConfig(rawConfig);
|
|
404
|
+
this.saveConfig(configPath, migratedConfig);
|
|
405
|
+
return migratedConfig;
|
|
406
|
+
}
|
|
407
|
+
return rawConfig;
|
|
216
408
|
}
|
|
217
409
|
catch (error) {
|
|
218
410
|
this.error(chalk.red(`Failed to load configuration: ${error.message}`));
|
|
@@ -228,17 +420,17 @@ export default class Config extends Command {
|
|
|
228
420
|
}
|
|
229
421
|
displayConfig(config) {
|
|
230
422
|
this.log(` ${chalk.gray('Version:')} ${config.version}`);
|
|
231
|
-
this.log(` ${chalk.gray('
|
|
423
|
+
this.log(` ${chalk.gray('Providers:')} ${config.providers.map(p => chalk.cyan(p)).join(', ') || chalk.gray('(none)')}`);
|
|
232
424
|
if (config.preferences) {
|
|
233
425
|
this.log(`\n ${chalk.bold('Preferences:')}`);
|
|
234
426
|
this.log(` ${chalk.gray('Auto-open outputs:')} ${config.preferences.autoOpenOutputs ? chalk.green('yes') : chalk.gray('no')}`);
|
|
235
427
|
this.log(` ${chalk.gray('Verbose logging:')} ${config.preferences.verboseLogging ? chalk.green('yes') : chalk.gray('no')}`);
|
|
236
|
-
this.log(` ${chalk.gray('Preserve sessions:')} ${config.preferences.preserveSessions
|
|
428
|
+
this.log(` ${chalk.gray('Preserve sessions:')} ${config.preferences.preserveSessions ? chalk.green('yes') : chalk.gray('no')}`);
|
|
237
429
|
}
|
|
238
430
|
if (config.outputs) {
|
|
239
431
|
this.log(`\n ${chalk.bold('Outputs:')}`);
|
|
240
|
-
this.log(` ${chalk.gray('Path:')} ${config.outputs.path
|
|
241
|
-
this.log(` ${chalk.gray('Format:')} ${config.outputs.format
|
|
432
|
+
this.log(` ${chalk.gray('Path:')} ${config.outputs.path}`);
|
|
433
|
+
this.log(` ${chalk.gray('Format:')} ${config.outputs.format}`);
|
|
242
434
|
}
|
|
243
435
|
this.log('');
|
|
244
436
|
}
|
|
@@ -260,26 +452,5 @@ export default class Config extends Command {
|
|
|
260
452
|
}, obj);
|
|
261
453
|
target[lastKey] = value;
|
|
262
454
|
}
|
|
263
|
-
getDefaultConfig(agent) {
|
|
264
|
-
return {
|
|
265
|
-
version: '1.0.0',
|
|
266
|
-
agent,
|
|
267
|
-
templates: {
|
|
268
|
-
prdQuestions: 'default',
|
|
269
|
-
fullPrd: 'default',
|
|
270
|
-
quickPrd: 'default',
|
|
271
|
-
},
|
|
272
|
-
outputs: {
|
|
273
|
-
path: '.clavix/outputs',
|
|
274
|
-
format: 'markdown',
|
|
275
|
-
},
|
|
276
|
-
preferences: {
|
|
277
|
-
autoOpenOutputs: false,
|
|
278
|
-
verboseLogging: false,
|
|
279
|
-
preserveSessions: true,
|
|
280
|
-
},
|
|
281
|
-
experimental: {},
|
|
282
|
-
};
|
|
283
|
-
}
|
|
284
455
|
}
|
|
285
456
|
//# sourceMappingURL=config.js.map
|
|
@@ -38,115 +38,67 @@ export default class Init extends Command {
|
|
|
38
38
|
return;
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
|
-
//
|
|
41
|
+
// Load existing config if re-initializing
|
|
42
42
|
const agentManager = new AgentManager();
|
|
43
|
+
let existingProviders = [];
|
|
44
|
+
if (await FileSystem.exists('.clavix/config.json')) {
|
|
45
|
+
try {
|
|
46
|
+
const configContent = await FileSystem.readFile('.clavix/config.json');
|
|
47
|
+
const config = JSON5.parse(configContent);
|
|
48
|
+
existingProviders = config.providers || [];
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
// Ignore parse errors, will use empty array
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// Select providers using shared utility
|
|
43
55
|
console.log(chalk.gray('Select AI development tools to support:\n'));
|
|
44
56
|
console.log(chalk.gray('(Space to select, Enter to confirm)\n'));
|
|
45
|
-
const {
|
|
46
|
-
|
|
47
|
-
type: 'checkbox',
|
|
48
|
-
name: 'selectedProviders',
|
|
49
|
-
message: 'Which AI tools are you using?',
|
|
50
|
-
choices: [
|
|
51
|
-
// CLI Tools
|
|
52
|
-
{
|
|
53
|
-
name: 'Amp (.agents/commands/)',
|
|
54
|
-
value: 'amp',
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
name: 'Augment CLI (.augment/commands/clavix/)',
|
|
58
|
-
value: 'augment',
|
|
59
|
-
},
|
|
60
|
-
{
|
|
61
|
-
name: 'Codex CLI (~/.codex/prompts)',
|
|
62
|
-
value: 'codex',
|
|
63
|
-
},
|
|
64
|
-
{
|
|
65
|
-
name: 'CodeBuddy (.codebuddy/commands/)',
|
|
66
|
-
value: 'codebuddy',
|
|
67
|
-
},
|
|
68
|
-
{
|
|
69
|
-
name: 'Crush CLI (.crush/commands/clavix/)',
|
|
70
|
-
value: 'crush',
|
|
71
|
-
},
|
|
72
|
-
{
|
|
73
|
-
name: 'Claude Code (.claude/commands/clavix/)',
|
|
74
|
-
value: 'claude-code',
|
|
75
|
-
},
|
|
76
|
-
{
|
|
77
|
-
name: 'Droid CLI (.factory/commands/)',
|
|
78
|
-
value: 'droid',
|
|
79
|
-
},
|
|
80
|
-
{
|
|
81
|
-
name: 'Gemini CLI (.gemini/commands/clavix/)',
|
|
82
|
-
value: 'gemini',
|
|
83
|
-
},
|
|
84
|
-
{
|
|
85
|
-
name: 'LLXPRT (.llxprt/commands/clavix/)',
|
|
86
|
-
value: 'llxprt',
|
|
87
|
-
},
|
|
88
|
-
{
|
|
89
|
-
name: 'OpenCode (.opencode/command/)',
|
|
90
|
-
value: 'opencode',
|
|
91
|
-
},
|
|
92
|
-
{
|
|
93
|
-
name: 'Qwen Code (.qwen/commands/clavix/)',
|
|
94
|
-
value: 'qwen',
|
|
95
|
-
},
|
|
96
|
-
new inquirer.Separator(),
|
|
97
|
-
// IDE & IDE Extensions
|
|
98
|
-
{
|
|
99
|
-
name: 'Cursor (.cursor/commands/)',
|
|
100
|
-
value: 'cursor',
|
|
101
|
-
},
|
|
102
|
-
{
|
|
103
|
-
name: 'Windsurf (.windsurf/workflows/)',
|
|
104
|
-
value: 'windsurf',
|
|
105
|
-
},
|
|
106
|
-
{
|
|
107
|
-
name: 'Kilocode (.kilocode/workflows/)',
|
|
108
|
-
value: 'kilocode',
|
|
109
|
-
},
|
|
110
|
-
{
|
|
111
|
-
name: 'Roocode (.roo/commands/)',
|
|
112
|
-
value: 'roocode',
|
|
113
|
-
},
|
|
114
|
-
{
|
|
115
|
-
name: 'Cline (.clinerules/workflows/)',
|
|
116
|
-
value: 'cline',
|
|
117
|
-
},
|
|
118
|
-
new inquirer.Separator(),
|
|
119
|
-
// Universal Adapters
|
|
120
|
-
{
|
|
121
|
-
name: 'Agents (AGENTS.md - Universal - for tools without slash commands)',
|
|
122
|
-
value: 'agents-md',
|
|
123
|
-
},
|
|
124
|
-
{
|
|
125
|
-
name: 'GitHub Copilot (.github/copilot-instructions.md)',
|
|
126
|
-
value: 'copilot-instructions',
|
|
127
|
-
},
|
|
128
|
-
{
|
|
129
|
-
name: 'Warp (WARP.md - optimized for Warp)',
|
|
130
|
-
value: 'warp-md',
|
|
131
|
-
},
|
|
132
|
-
{
|
|
133
|
-
name: 'Octofriend (OCTO.md - optimized for Octofriend)',
|
|
134
|
-
value: 'octo-md',
|
|
135
|
-
},
|
|
136
|
-
new inquirer.Separator(),
|
|
137
|
-
],
|
|
138
|
-
validate: (answer) => {
|
|
139
|
-
if (answer.length === 0) {
|
|
140
|
-
return 'You must select at least one provider.';
|
|
141
|
-
}
|
|
142
|
-
return true;
|
|
143
|
-
},
|
|
144
|
-
},
|
|
145
|
-
]);
|
|
57
|
+
const { selectProviders } = await import('../../utils/provider-selector.js');
|
|
58
|
+
const selectedProviders = await selectProviders(agentManager, existingProviders);
|
|
146
59
|
if (!selectedProviders || selectedProviders.length === 0) {
|
|
147
60
|
console.log(chalk.red('\n✗ No providers selected\n'));
|
|
148
61
|
return;
|
|
149
62
|
}
|
|
63
|
+
// Handle deselected providers (cleanup prompt)
|
|
64
|
+
const deselectedProviders = existingProviders.filter((p) => !selectedProviders.includes(p));
|
|
65
|
+
if (deselectedProviders.length > 0) {
|
|
66
|
+
console.log(chalk.yellow('\n⚠ Previously configured but not selected:'));
|
|
67
|
+
for (const providerName of deselectedProviders) {
|
|
68
|
+
const adapter = agentManager.getAdapter(providerName);
|
|
69
|
+
const displayName = adapter?.displayName || providerName;
|
|
70
|
+
const directory = adapter?.directory || 'unknown';
|
|
71
|
+
console.log(chalk.gray(` • ${displayName} (${directory})`));
|
|
72
|
+
}
|
|
73
|
+
const { cleanupAction } = await inquirer.prompt([
|
|
74
|
+
{
|
|
75
|
+
type: 'list',
|
|
76
|
+
name: 'cleanupAction',
|
|
77
|
+
message: 'What would you like to do with these providers?',
|
|
78
|
+
choices: [
|
|
79
|
+
{ name: 'Clean up (remove all command files)', value: 'cleanup' },
|
|
80
|
+
{ name: 'Keep (also update their commands)', value: 'update' },
|
|
81
|
+
{ name: 'Skip (leave as-is)', value: 'skip' },
|
|
82
|
+
],
|
|
83
|
+
},
|
|
84
|
+
]);
|
|
85
|
+
if (cleanupAction === 'cleanup') {
|
|
86
|
+
console.log(chalk.gray('\n🗑️ Cleaning up deselected providers...'));
|
|
87
|
+
for (const providerName of deselectedProviders) {
|
|
88
|
+
const adapter = agentManager.getAdapter(providerName);
|
|
89
|
+
if (adapter) {
|
|
90
|
+
const removed = await adapter.removeAllCommands();
|
|
91
|
+
console.log(chalk.gray(` ✓ Removed ${removed} command(s) from ${adapter.displayName}`));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
else if (cleanupAction === 'update') {
|
|
96
|
+
// Add them back to selection
|
|
97
|
+
selectedProviders.push(...deselectedProviders);
|
|
98
|
+
console.log(chalk.gray('\n✓ Keeping all providers\n'));
|
|
99
|
+
}
|
|
100
|
+
// If 'skip': do nothing
|
|
101
|
+
}
|
|
150
102
|
// Create .clavix directory structure
|
|
151
103
|
console.log(chalk.cyan('\n📁 Creating directory structure...'));
|
|
152
104
|
await this.createDirectoryStructure();
|
|
@@ -235,6 +187,11 @@ export default class Init extends Command {
|
|
|
235
187
|
}
|
|
236
188
|
}
|
|
237
189
|
}
|
|
190
|
+
// Remove all existing commands before regenerating (ensures clean state)
|
|
191
|
+
const removed = await adapter.removeAllCommands();
|
|
192
|
+
if (removed > 0) {
|
|
193
|
+
console.log(chalk.gray(` Removed ${removed} existing command(s)`));
|
|
194
|
+
}
|
|
238
195
|
// Generate slash commands
|
|
239
196
|
const generatedTemplates = await this.generateSlashCommands(adapter);
|
|
240
197
|
await this.handleLegacyCommands(adapter, generatedTemplates);
|
|
@@ -295,7 +252,7 @@ export default class Init extends Command {
|
|
|
295
252
|
providers,
|
|
296
253
|
};
|
|
297
254
|
const configPath = '.clavix/config.json';
|
|
298
|
-
const configContent =
|
|
255
|
+
const configContent = JSON.stringify(config, null, 2);
|
|
299
256
|
await FileSystem.writeFileAtomic(configPath, configContent);
|
|
300
257
|
}
|
|
301
258
|
async generateInstructions() {
|
|
@@ -357,6 +314,8 @@ Welcome to Clavix! This directory contains your local Clavix configuration and d
|
|
|
357
314
|
|
|
358
315
|
If using Claude Code, Cursor, or Windsurf, the following slash commands are available:
|
|
359
316
|
|
|
317
|
+
**Note:** Running \`clavix init\` or \`clavix update\` will regenerate all slash commands from templates. Any manual edits to generated commands will be lost. If you need custom commands, create new command files instead of modifying generated ones.
|
|
318
|
+
|
|
360
319
|
### Prompt Improvement
|
|
361
320
|
- \`/clavix:fast [prompt]\` - Quick prompt improvements
|
|
362
321
|
- \`/clavix:deep [prompt]\` - Comprehensive prompt analysis
|
|
@@ -146,53 +146,25 @@ export default class Update extends Command {
|
|
|
146
146
|
}
|
|
147
147
|
async updateCommands(adapter, force) {
|
|
148
148
|
this.log(chalk.cyan(`\n🔧 Updating slash commands for ${adapter.displayName}...`));
|
|
149
|
-
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
const templatesDir = path.join(__dirname, '..', '..', 'templates', 'slash-commands', adapter.name);
|
|
154
|
-
if (!fs.existsSync(templatesDir)) {
|
|
155
|
-
this.log(chalk.yellow(` ⚠ Templates directory not found: ${templatesDir}`));
|
|
156
|
-
return 0;
|
|
149
|
+
// Remove all existing commands first (force regeneration)
|
|
150
|
+
const removed = await adapter.removeAllCommands();
|
|
151
|
+
if (removed > 0) {
|
|
152
|
+
this.log(chalk.gray(` Removed ${removed} existing command(s)`));
|
|
157
153
|
}
|
|
158
|
-
//
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
if (templateFiles.length === 0) {
|
|
154
|
+
// Load templates using the canonical template loader
|
|
155
|
+
const { loadCommandTemplates } = await import('../../utils/template-loader.js');
|
|
156
|
+
const templates = await loadCommandTemplates(adapter);
|
|
157
|
+
if (templates.length === 0) {
|
|
163
158
|
this.log(chalk.yellow(' ⚠ No command templates found'));
|
|
164
159
|
return 0;
|
|
165
160
|
}
|
|
166
|
-
//
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
const filename = adapter.getTargetFilename(command);
|
|
174
|
-
const commandFile = path.join(commandsPath, filename);
|
|
175
|
-
const templatePath = path.join(templatesDir, `${command}${extension}`);
|
|
176
|
-
const newContent = fs.readFileSync(templatePath, 'utf-8');
|
|
177
|
-
if (fs.existsSync(commandFile)) {
|
|
178
|
-
const currentContent = fs.readFileSync(commandFile, 'utf-8');
|
|
179
|
-
if (force || currentContent !== newContent) {
|
|
180
|
-
fs.writeFileSync(commandFile, newContent);
|
|
181
|
-
this.log(chalk.gray(` ✓ Updated ${filename}`));
|
|
182
|
-
updated++;
|
|
183
|
-
}
|
|
184
|
-
else {
|
|
185
|
-
this.log(chalk.gray(` • ${filename} already up to date`));
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
else {
|
|
189
|
-
fs.writeFileSync(commandFile, newContent);
|
|
190
|
-
this.log(chalk.gray(` ✓ Created ${filename}`));
|
|
191
|
-
updated++;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
updated += await this.handleLegacyCommands(adapter, templateFiles, force);
|
|
195
|
-
return updated;
|
|
161
|
+
// Generate fresh commands from templates
|
|
162
|
+
await adapter.generateCommands(templates);
|
|
163
|
+
this.log(chalk.gray(` ✓ Generated ${templates.length} command(s)`));
|
|
164
|
+
// Handle legacy commands (cleanup old naming patterns)
|
|
165
|
+
const commandNames = templates.map(t => t.name);
|
|
166
|
+
const legacyRemoved = await this.handleLegacyCommands(adapter, commandNames, force);
|
|
167
|
+
return removed + templates.length + legacyRemoved;
|
|
196
168
|
}
|
|
197
169
|
async handleLegacyCommands(adapter, commandNames, force) {
|
|
198
170
|
if (commandNames.length === 0) {
|
|
@@ -21,6 +21,19 @@ export declare abstract class BaseAdapter implements AgentAdapter {
|
|
|
21
21
|
* Checks if directory can be created and is writable
|
|
22
22
|
*/
|
|
23
23
|
validate(): Promise<ValidationResult>;
|
|
24
|
+
/**
|
|
25
|
+
* Remove all existing Clavix-generated commands for this adapter
|
|
26
|
+
* Called before regenerating to ensure clean state
|
|
27
|
+
* @returns Number of files removed
|
|
28
|
+
*/
|
|
29
|
+
removeAllCommands(): Promise<number>;
|
|
30
|
+
/**
|
|
31
|
+
* Determine if a file is a Clavix-generated command
|
|
32
|
+
* Override in adapters for provider-specific patterns
|
|
33
|
+
* @param filename The filename to check
|
|
34
|
+
* @returns true if this is a Clavix-generated command file
|
|
35
|
+
*/
|
|
36
|
+
protected isClavixGeneratedCommand(filename: string): boolean;
|
|
24
37
|
/**
|
|
25
38
|
* Generate commands - default implementation
|
|
26
39
|
* Creates command files in the provider's directory
|
|
@@ -59,6 +59,43 @@ export class BaseAdapter {
|
|
|
59
59
|
warnings: warnings.length > 0 ? warnings : undefined,
|
|
60
60
|
};
|
|
61
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Remove all existing Clavix-generated commands for this adapter
|
|
64
|
+
* Called before regenerating to ensure clean state
|
|
65
|
+
* @returns Number of files removed
|
|
66
|
+
*/
|
|
67
|
+
async removeAllCommands() {
|
|
68
|
+
const commandPath = this.getCommandPath();
|
|
69
|
+
// If directory doesn't exist, nothing to remove
|
|
70
|
+
if (!(await FileSystem.exists(commandPath))) {
|
|
71
|
+
return 0;
|
|
72
|
+
}
|
|
73
|
+
const files = await FileSystem.listFiles(commandPath);
|
|
74
|
+
const clavixCommands = files.filter((f) => this.isClavixGeneratedCommand(f));
|
|
75
|
+
let removed = 0;
|
|
76
|
+
for (const file of clavixCommands) {
|
|
77
|
+
const filePath = path.join(commandPath, file);
|
|
78
|
+
try {
|
|
79
|
+
await FileSystem.remove(filePath);
|
|
80
|
+
removed++;
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
// Log warning but continue with other files
|
|
84
|
+
console.warn(`Failed to remove ${filePath}: ${error}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return removed;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Determine if a file is a Clavix-generated command
|
|
91
|
+
* Override in adapters for provider-specific patterns
|
|
92
|
+
* @param filename The filename to check
|
|
93
|
+
* @returns true if this is a Clavix-generated command file
|
|
94
|
+
*/
|
|
95
|
+
isClavixGeneratedCommand(filename) {
|
|
96
|
+
// Default: match files with our extension
|
|
97
|
+
return filename.endsWith(this.fileExtension);
|
|
98
|
+
}
|
|
62
99
|
/**
|
|
63
100
|
* Generate commands - default implementation
|
|
64
101
|
* Creates command files in the provider's directory
|
|
@@ -20,6 +20,11 @@ export declare class ClaudeCodeAdapter extends BaseAdapter {
|
|
|
20
20
|
* Get command path for Claude Code
|
|
21
21
|
*/
|
|
22
22
|
getCommandPath(): string;
|
|
23
|
+
/**
|
|
24
|
+
* Determine if a file is a Clavix-generated command
|
|
25
|
+
* For Claude Code: Any .md file in .claude/commands/clavix/ is ours
|
|
26
|
+
*/
|
|
27
|
+
protected isClavixGeneratedCommand(filename: string): boolean;
|
|
23
28
|
/**
|
|
24
29
|
* Inject documentation blocks into CLAUDE.md
|
|
25
30
|
*/
|
|
@@ -27,6 +27,15 @@ export class ClaudeCodeAdapter extends BaseAdapter {
|
|
|
27
27
|
getCommandPath() {
|
|
28
28
|
return this.directory;
|
|
29
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* Determine if a file is a Clavix-generated command
|
|
32
|
+
* For Claude Code: Any .md file in .claude/commands/clavix/ is ours
|
|
33
|
+
*/
|
|
34
|
+
isClavixGeneratedCommand(filename) {
|
|
35
|
+
// Only remove .md files (our slash commands)
|
|
36
|
+
// This is safe because we control the entire .claude/commands/clavix/ directory
|
|
37
|
+
return filename.endsWith('.md');
|
|
38
|
+
}
|
|
30
39
|
// generateCommands is inherited from BaseAdapter
|
|
31
40
|
/**
|
|
32
41
|
* Inject documentation blocks into CLAUDE.md
|
package/dist/index 2.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { run, handle, settings } from '@oclif/core';
|
|
3
|
+
// Disable debug mode (stack traces) unless explicitly requested via DEBUG env var
|
|
4
|
+
if (!process.env.DEBUG) {
|
|
5
|
+
settings.debug = false;
|
|
6
|
+
}
|
|
7
|
+
// Run if called directly
|
|
8
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
9
|
+
run().catch(handle);
|
|
10
|
+
}
|
|
11
|
+
// Export for testing
|
|
12
|
+
export { run };
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
package/dist/types/agent.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export interface AgentAdapter {
|
|
|
9
9
|
features?: ProviderFeatures;
|
|
10
10
|
detectProject(): Promise<boolean>;
|
|
11
11
|
generateCommands(templates: CommandTemplate[]): Promise<void>;
|
|
12
|
+
removeAllCommands(): Promise<number>;
|
|
12
13
|
injectDocumentation(blocks: ManagedBlock[]): Promise<void>;
|
|
13
14
|
getCommandPath(): string;
|
|
14
15
|
getTargetFilename(name: string): string;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { AgentManager } from '../core/agent-manager.js';
|
|
2
|
+
/**
|
|
3
|
+
* Interactive provider selection utility
|
|
4
|
+
* Displays multi-select checkbox for all available providers
|
|
5
|
+
* Used by both init and config commands
|
|
6
|
+
*/
|
|
7
|
+
export declare function selectProviders(agentManager: AgentManager, preSelected?: string[]): Promise<string[]>;
|
|
8
|
+
//# sourceMappingURL=provider-selector.d.ts.map
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import inquirer from 'inquirer';
|
|
2
|
+
/**
|
|
3
|
+
* Interactive provider selection utility
|
|
4
|
+
* Displays multi-select checkbox for all available providers
|
|
5
|
+
* Used by both init and config commands
|
|
6
|
+
*/
|
|
7
|
+
export async function selectProviders(agentManager, preSelected = []) {
|
|
8
|
+
const { selectedProviders } = await inquirer.prompt([
|
|
9
|
+
{
|
|
10
|
+
type: 'checkbox',
|
|
11
|
+
name: 'selectedProviders',
|
|
12
|
+
message: 'Which AI tools are you using?',
|
|
13
|
+
choices: [
|
|
14
|
+
new inquirer.Separator('=== CLI Tools ==='),
|
|
15
|
+
{ name: 'Amp (.agents/commands/)', value: 'amp' },
|
|
16
|
+
{ name: 'Augment CLI (.augment/commands/clavix/)', value: 'augment' },
|
|
17
|
+
{ name: 'Codex CLI (~/.codex/prompts)', value: 'codex' },
|
|
18
|
+
{ name: 'Droid (.droid/clavix/)', value: 'droid' },
|
|
19
|
+
{ name: 'Gemini CLI (.gemini/commands/clavix/)', value: 'gemini' },
|
|
20
|
+
{ name: 'Kilocode (.kilo/clavix/)', value: 'kilocode' },
|
|
21
|
+
{ name: 'LLXPRT CLI (.llxprt/clavix/)', value: 'llxprt' },
|
|
22
|
+
{ name: 'OpenCode (.opencode/clavix/)', value: 'opencode' },
|
|
23
|
+
{ name: 'Qwen (通义灵码) (~/.qwen/commands/clavix/)', value: 'qwen' },
|
|
24
|
+
{ name: 'RooCode (.roo/clavix/)', value: 'roocode' },
|
|
25
|
+
new inquirer.Separator(),
|
|
26
|
+
new inquirer.Separator('=== IDE & IDE Extensions ==='),
|
|
27
|
+
{ name: 'Claude Code (.claude/commands/clavix/)', value: 'claude-code' },
|
|
28
|
+
{ name: 'Cline (.cline/workflows/)', value: 'cline' },
|
|
29
|
+
{ name: 'CodeBuddy (.codebuddy/prompts/)', value: 'codebuddy' },
|
|
30
|
+
{ name: 'Copilot Instructions (.github/copilot-instructions.md)', value: 'copilot-instructions' },
|
|
31
|
+
{ name: 'Crush (crush://prompts)', value: 'crush' },
|
|
32
|
+
{ name: 'Cursor (.cursor/commands/)', value: 'cursor' },
|
|
33
|
+
{ name: 'Windsurf (.windsurf/rules/)', value: 'windsurf' },
|
|
34
|
+
new inquirer.Separator(),
|
|
35
|
+
new inquirer.Separator('=== Universal Adapters ==='),
|
|
36
|
+
{ name: 'Agents (AGENTS.md - Universal)', value: 'agents-md' },
|
|
37
|
+
{ name: 'Octo (OCTO.md - Universal)', value: 'octo-md' },
|
|
38
|
+
{ name: 'Custom (custom/ directory)', value: 'custom' },
|
|
39
|
+
].map((choice) => {
|
|
40
|
+
// Keep separators as-is
|
|
41
|
+
if (choice instanceof inquirer.Separator) {
|
|
42
|
+
return choice;
|
|
43
|
+
}
|
|
44
|
+
// Add 'checked' property based on preSelected
|
|
45
|
+
return {
|
|
46
|
+
...choice,
|
|
47
|
+
checked: preSelected.includes(choice.value),
|
|
48
|
+
};
|
|
49
|
+
}),
|
|
50
|
+
validate: (answer) => {
|
|
51
|
+
if (answer.length === 0) {
|
|
52
|
+
return 'You must select at least one provider.';
|
|
53
|
+
}
|
|
54
|
+
return true;
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
]);
|
|
58
|
+
return selectedProviders;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=provider-selector.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clavix",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.1",
|
|
4
4
|
"description": "Clavix Intelligence™ for AI coding. Automatically optimizes prompts with intent detection, quality assessment, and adaptive patterns—no framework to learn. Works with Claude Code, Cursor, Windsurf, and 19+ other AI coding tools.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|