@sylphx/flow 1.8.2 → 2.0.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 +59 -0
- package/UPGRADE.md +140 -0
- package/package.json +2 -1
- package/src/commands/flow/execute-v2.ts +278 -0
- package/src/commands/flow/execute.ts +1 -18
- package/src/commands/flow/types.ts +3 -2
- package/src/commands/flow-command.ts +32 -69
- package/src/commands/flow-orchestrator.ts +18 -55
- package/src/commands/run-command.ts +12 -6
- package/src/commands/settings-command.ts +529 -0
- package/src/core/attach-manager.ts +482 -0
- package/src/core/backup-manager.ts +308 -0
- package/src/core/cleanup-handler.ts +166 -0
- package/src/core/flow-executor.ts +323 -0
- package/src/core/git-stash-manager.ts +133 -0
- package/src/core/project-manager.ts +274 -0
- package/src/core/secrets-manager.ts +229 -0
- package/src/core/session-manager.ts +268 -0
- package/src/core/template-loader.ts +189 -0
- package/src/core/upgrade-manager.ts +79 -47
- package/src/index.ts +13 -27
- package/src/services/first-run-setup.ts +220 -0
- package/src/services/global-config.ts +337 -0
- package/src/utils/__tests__/package-manager-detector.test.ts +163 -0
- package/src/utils/agent-enhancer.ts +40 -22
- package/src/utils/errors.ts +9 -0
- package/src/utils/package-manager-detector.ts +139 -0
|
@@ -0,0 +1,529 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Settings Command
|
|
3
|
+
* Interactive configuration for Sylphx Flow
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { Command } from 'commander';
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
import inquirer from 'inquirer';
|
|
9
|
+
import { GlobalConfigService } from '../services/global-config.js';
|
|
10
|
+
import { UserCancelledError } from '../utils/errors.js';
|
|
11
|
+
|
|
12
|
+
export const settingsCommand = new Command('settings')
|
|
13
|
+
.description('Configure Sylphx Flow settings')
|
|
14
|
+
.option('--section <section>', 'Directly open a section (mcp, provider, target, general)')
|
|
15
|
+
.action(async (options) => {
|
|
16
|
+
try {
|
|
17
|
+
const configService = new GlobalConfigService();
|
|
18
|
+
await configService.initialize();
|
|
19
|
+
|
|
20
|
+
console.log(chalk.cyan.bold('\n╭─ Sylphx Flow Settings ─────────────────────────╮'));
|
|
21
|
+
console.log(chalk.cyan.bold('│ │'));
|
|
22
|
+
console.log(chalk.cyan.bold('│ Configure your Flow environment │'));
|
|
23
|
+
console.log(chalk.cyan.bold('│ │'));
|
|
24
|
+
console.log(chalk.cyan.bold('╰─────────────────────────────────────────────────╯\n'));
|
|
25
|
+
|
|
26
|
+
if (options.section) {
|
|
27
|
+
await openSection(options.section, configService);
|
|
28
|
+
} else {
|
|
29
|
+
await showMainMenu(configService);
|
|
30
|
+
}
|
|
31
|
+
} catch (error: any) {
|
|
32
|
+
// Handle user cancellation (Ctrl+C)
|
|
33
|
+
if (error.name === 'ExitPromptError' || error.message?.includes('force closed')) {
|
|
34
|
+
throw new UserCancelledError('Settings cancelled by user');
|
|
35
|
+
}
|
|
36
|
+
throw error;
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Show main settings menu
|
|
42
|
+
*/
|
|
43
|
+
async function showMainMenu(configService: GlobalConfigService): Promise<void> {
|
|
44
|
+
while (true) {
|
|
45
|
+
const { choice } = await inquirer.prompt([
|
|
46
|
+
{
|
|
47
|
+
type: 'list',
|
|
48
|
+
name: 'choice',
|
|
49
|
+
message: 'What would you like to configure?',
|
|
50
|
+
choices: [
|
|
51
|
+
{ name: '🤖 Agents & Default Agent', value: 'agents' },
|
|
52
|
+
{ name: '📋 Rules', value: 'rules' },
|
|
53
|
+
{ name: '🎨 Output Styles', value: 'outputStyles' },
|
|
54
|
+
new inquirer.Separator(),
|
|
55
|
+
{ name: '📡 MCP Servers', value: 'mcp' },
|
|
56
|
+
{ name: '🔑 Provider & API Keys (Claude Code)', value: 'provider' },
|
|
57
|
+
{ name: '🎯 Target Platform', value: 'target' },
|
|
58
|
+
{ name: '⚙️ General Settings', value: 'general' },
|
|
59
|
+
new inquirer.Separator(),
|
|
60
|
+
{ name: '← Back / Exit', value: 'exit' },
|
|
61
|
+
],
|
|
62
|
+
},
|
|
63
|
+
]);
|
|
64
|
+
|
|
65
|
+
if (choice === 'exit') {
|
|
66
|
+
console.log(chalk.green('\n✓ Settings saved\n'));
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
await openSection(choice, configService);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Open specific settings section
|
|
76
|
+
*/
|
|
77
|
+
async function openSection(section: string, configService: GlobalConfigService): Promise<void> {
|
|
78
|
+
switch (section) {
|
|
79
|
+
case 'agents':
|
|
80
|
+
await configureAgents(configService);
|
|
81
|
+
break;
|
|
82
|
+
case 'rules':
|
|
83
|
+
await configureRules(configService);
|
|
84
|
+
break;
|
|
85
|
+
case 'outputStyles':
|
|
86
|
+
await configureOutputStyles(configService);
|
|
87
|
+
break;
|
|
88
|
+
case 'mcp':
|
|
89
|
+
await configureMCP(configService);
|
|
90
|
+
break;
|
|
91
|
+
case 'provider':
|
|
92
|
+
await configureProvider(configService);
|
|
93
|
+
break;
|
|
94
|
+
case 'target':
|
|
95
|
+
await configureTarget(configService);
|
|
96
|
+
break;
|
|
97
|
+
case 'general':
|
|
98
|
+
await configureGeneral(configService);
|
|
99
|
+
break;
|
|
100
|
+
default:
|
|
101
|
+
console.log(chalk.red(`Unknown section: ${section}`));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Configure Agents
|
|
107
|
+
*/
|
|
108
|
+
async function configureAgents(configService: GlobalConfigService): Promise<void> {
|
|
109
|
+
console.log(chalk.cyan.bold('\n━━━ 🤖 Agent Configuration\n'));
|
|
110
|
+
|
|
111
|
+
const flowConfig = await configService.loadFlowConfig();
|
|
112
|
+
const settings = await configService.loadSettings();
|
|
113
|
+
const currentAgents = flowConfig.agents || {};
|
|
114
|
+
|
|
115
|
+
// Available agents
|
|
116
|
+
const availableAgents = {
|
|
117
|
+
coder: 'Coder - Write and modify code',
|
|
118
|
+
writer: 'Writer - Documentation and explanation',
|
|
119
|
+
reviewer: 'Reviewer - Code review and critique',
|
|
120
|
+
orchestrator: 'Orchestrator - Task coordination',
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
// Get current enabled agents
|
|
124
|
+
const currentEnabled = Object.keys(currentAgents).filter(
|
|
125
|
+
(key) => currentAgents[key].enabled
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
const { selectedAgents } = await inquirer.prompt([
|
|
129
|
+
{
|
|
130
|
+
type: 'checkbox',
|
|
131
|
+
name: 'selectedAgents',
|
|
132
|
+
message: 'Select agents to enable:',
|
|
133
|
+
choices: Object.entries(availableAgents).map(([key, name]) => ({
|
|
134
|
+
name,
|
|
135
|
+
value: key,
|
|
136
|
+
checked: currentEnabled.includes(key),
|
|
137
|
+
})),
|
|
138
|
+
},
|
|
139
|
+
]);
|
|
140
|
+
|
|
141
|
+
// Update agents
|
|
142
|
+
for (const key of Object.keys(availableAgents)) {
|
|
143
|
+
if (selectedAgents.includes(key)) {
|
|
144
|
+
currentAgents[key] = { enabled: true };
|
|
145
|
+
} else {
|
|
146
|
+
currentAgents[key] = { enabled: false };
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Select default agent
|
|
151
|
+
const { defaultAgent } = await inquirer.prompt([
|
|
152
|
+
{
|
|
153
|
+
type: 'list',
|
|
154
|
+
name: 'defaultAgent',
|
|
155
|
+
message: 'Select default agent:',
|
|
156
|
+
choices: selectedAgents.map((key: string) => ({
|
|
157
|
+
name: availableAgents[key as keyof typeof availableAgents],
|
|
158
|
+
value: key,
|
|
159
|
+
})),
|
|
160
|
+
default: settings.defaultAgent || 'coder',
|
|
161
|
+
},
|
|
162
|
+
]);
|
|
163
|
+
|
|
164
|
+
flowConfig.agents = currentAgents;
|
|
165
|
+
await configService.saveFlowConfig(flowConfig);
|
|
166
|
+
|
|
167
|
+
settings.defaultAgent = defaultAgent;
|
|
168
|
+
await configService.saveSettings(settings);
|
|
169
|
+
|
|
170
|
+
console.log(chalk.green(`\n✓ Agent configuration saved`));
|
|
171
|
+
console.log(chalk.dim(` Enabled agents: ${selectedAgents.length}`));
|
|
172
|
+
console.log(chalk.dim(` Default agent: ${defaultAgent}`));
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Configure Rules
|
|
177
|
+
*/
|
|
178
|
+
async function configureRules(configService: GlobalConfigService): Promise<void> {
|
|
179
|
+
console.log(chalk.cyan.bold('\n━━━ 📋 Rules Configuration\n'));
|
|
180
|
+
|
|
181
|
+
const flowConfig = await configService.loadFlowConfig();
|
|
182
|
+
const currentRules = flowConfig.rules || {};
|
|
183
|
+
|
|
184
|
+
// Available rules
|
|
185
|
+
const availableRules = {
|
|
186
|
+
core: 'Core - Identity, personality, execution',
|
|
187
|
+
'code-standards': 'Code Standards - Quality, patterns, anti-patterns',
|
|
188
|
+
workspace: 'Workspace - Documentation management',
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
// Get current enabled rules
|
|
192
|
+
const currentEnabled = Object.keys(currentRules).filter(
|
|
193
|
+
(key) => currentRules[key].enabled
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
const { selectedRules } = await inquirer.prompt([
|
|
197
|
+
{
|
|
198
|
+
type: 'checkbox',
|
|
199
|
+
name: 'selectedRules',
|
|
200
|
+
message: 'Select rules to enable:',
|
|
201
|
+
choices: Object.entries(availableRules).map(([key, name]) => ({
|
|
202
|
+
name,
|
|
203
|
+
value: key,
|
|
204
|
+
checked: currentEnabled.includes(key),
|
|
205
|
+
})),
|
|
206
|
+
},
|
|
207
|
+
]);
|
|
208
|
+
|
|
209
|
+
// Update rules
|
|
210
|
+
for (const key of Object.keys(availableRules)) {
|
|
211
|
+
if (selectedRules.includes(key)) {
|
|
212
|
+
currentRules[key] = { enabled: true };
|
|
213
|
+
} else {
|
|
214
|
+
currentRules[key] = { enabled: false };
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
flowConfig.rules = currentRules;
|
|
219
|
+
await configService.saveFlowConfig(flowConfig);
|
|
220
|
+
|
|
221
|
+
console.log(chalk.green(`\n✓ Rules configuration saved`));
|
|
222
|
+
console.log(chalk.dim(` Enabled rules: ${selectedRules.length}`));
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Configure Output Styles
|
|
227
|
+
*/
|
|
228
|
+
async function configureOutputStyles(configService: GlobalConfigService): Promise<void> {
|
|
229
|
+
console.log(chalk.cyan.bold('\n━━━ 🎨 Output Styles Configuration\n'));
|
|
230
|
+
|
|
231
|
+
const flowConfig = await configService.loadFlowConfig();
|
|
232
|
+
const currentStyles = flowConfig.outputStyles || {};
|
|
233
|
+
|
|
234
|
+
// Available output styles
|
|
235
|
+
const availableStyles = {
|
|
236
|
+
silent: 'Silent - Execution without narration',
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
// Get current enabled styles
|
|
240
|
+
const currentEnabled = Object.keys(currentStyles).filter(
|
|
241
|
+
(key) => currentStyles[key].enabled
|
|
242
|
+
);
|
|
243
|
+
|
|
244
|
+
const { selectedStyles } = await inquirer.prompt([
|
|
245
|
+
{
|
|
246
|
+
type: 'checkbox',
|
|
247
|
+
name: 'selectedStyles',
|
|
248
|
+
message: 'Select output styles to enable:',
|
|
249
|
+
choices: Object.entries(availableStyles).map(([key, name]) => ({
|
|
250
|
+
name,
|
|
251
|
+
value: key,
|
|
252
|
+
checked: currentEnabled.includes(key),
|
|
253
|
+
})),
|
|
254
|
+
},
|
|
255
|
+
]);
|
|
256
|
+
|
|
257
|
+
// Update styles
|
|
258
|
+
for (const key of Object.keys(availableStyles)) {
|
|
259
|
+
if (selectedStyles.includes(key)) {
|
|
260
|
+
currentStyles[key] = { enabled: true };
|
|
261
|
+
} else {
|
|
262
|
+
currentStyles[key] = { enabled: false };
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
flowConfig.outputStyles = currentStyles;
|
|
267
|
+
await configService.saveFlowConfig(flowConfig);
|
|
268
|
+
|
|
269
|
+
console.log(chalk.green(`\n✓ Output styles configuration saved`));
|
|
270
|
+
console.log(chalk.dim(` Enabled styles: ${selectedStyles.length}`));
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Configure MCP servers
|
|
275
|
+
*/
|
|
276
|
+
async function configureMCP(configService: GlobalConfigService): Promise<void> {
|
|
277
|
+
console.log(chalk.cyan.bold('\n━━━ 📡 MCP Server Configuration\n'));
|
|
278
|
+
|
|
279
|
+
const mcpConfig = await configService.loadMCPConfig();
|
|
280
|
+
const currentServers = mcpConfig.servers || {};
|
|
281
|
+
|
|
282
|
+
// Available MCP servers (from MCP_SERVER_REGISTRY)
|
|
283
|
+
const availableServers = {
|
|
284
|
+
'grep': { name: 'GitHub Code Search (grep.app)', requiresEnv: [] },
|
|
285
|
+
'context7': { name: 'Context7 Docs', requiresEnv: [] },
|
|
286
|
+
'playwright': { name: 'Playwright Browser Control', requiresEnv: [] },
|
|
287
|
+
'github': { name: 'GitHub', requiresEnv: ['GITHUB_TOKEN'] },
|
|
288
|
+
'notion': { name: 'Notion', requiresEnv: ['NOTION_API_KEY'] },
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
// Get current enabled servers
|
|
292
|
+
const currentEnabled = Object.keys(currentServers).filter(
|
|
293
|
+
(key) => currentServers[key].enabled
|
|
294
|
+
);
|
|
295
|
+
|
|
296
|
+
const { selectedServers } = await inquirer.prompt([
|
|
297
|
+
{
|
|
298
|
+
type: 'checkbox',
|
|
299
|
+
name: 'selectedServers',
|
|
300
|
+
message: 'Select MCP servers to enable:',
|
|
301
|
+
choices: Object.entries(availableServers).map(([key, info]) => {
|
|
302
|
+
const requiresText = info.requiresEnv.length > 0
|
|
303
|
+
? chalk.dim(` (requires ${info.requiresEnv.join(', ')})`)
|
|
304
|
+
: '';
|
|
305
|
+
return {
|
|
306
|
+
name: `${info.name}${requiresText}`,
|
|
307
|
+
value: key,
|
|
308
|
+
checked: currentEnabled.includes(key),
|
|
309
|
+
};
|
|
310
|
+
}),
|
|
311
|
+
},
|
|
312
|
+
]);
|
|
313
|
+
|
|
314
|
+
// Update servers
|
|
315
|
+
for (const key of Object.keys(availableServers)) {
|
|
316
|
+
if (selectedServers.includes(key)) {
|
|
317
|
+
if (!currentServers[key]) {
|
|
318
|
+
currentServers[key] = { enabled: true, env: {} };
|
|
319
|
+
} else {
|
|
320
|
+
currentServers[key].enabled = true;
|
|
321
|
+
}
|
|
322
|
+
} else if (currentServers[key]) {
|
|
323
|
+
currentServers[key].enabled = false;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// Ask for API keys for newly enabled servers
|
|
328
|
+
for (const serverKey of selectedServers) {
|
|
329
|
+
const serverInfo = availableServers[serverKey as keyof typeof availableServers];
|
|
330
|
+
if (serverInfo.requiresEnv.length > 0) {
|
|
331
|
+
const server = currentServers[serverKey];
|
|
332
|
+
|
|
333
|
+
for (const envKey of serverInfo.requiresEnv) {
|
|
334
|
+
const hasKey = server.env && server.env[envKey];
|
|
335
|
+
|
|
336
|
+
const { shouldConfigure } = await inquirer.prompt([
|
|
337
|
+
{
|
|
338
|
+
type: 'confirm',
|
|
339
|
+
name: 'shouldConfigure',
|
|
340
|
+
message: hasKey
|
|
341
|
+
? `Update ${envKey} for ${serverInfo.name}?`
|
|
342
|
+
: `Configure ${envKey} for ${serverInfo.name}?`,
|
|
343
|
+
default: !hasKey,
|
|
344
|
+
},
|
|
345
|
+
]);
|
|
346
|
+
|
|
347
|
+
if (shouldConfigure) {
|
|
348
|
+
const { apiKey } = await inquirer.prompt([
|
|
349
|
+
{
|
|
350
|
+
type: 'password',
|
|
351
|
+
name: 'apiKey',
|
|
352
|
+
message: `Enter ${envKey}:`,
|
|
353
|
+
mask: '*',
|
|
354
|
+
},
|
|
355
|
+
]);
|
|
356
|
+
|
|
357
|
+
if (!server.env) {
|
|
358
|
+
server.env = {};
|
|
359
|
+
}
|
|
360
|
+
server.env[envKey] = apiKey;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
mcpConfig.servers = currentServers;
|
|
367
|
+
await configService.saveMCPConfig(mcpConfig);
|
|
368
|
+
|
|
369
|
+
console.log(chalk.green(`\n✓ MCP configuration saved`));
|
|
370
|
+
console.log(chalk.dim(` Enabled servers: ${selectedServers.length}`));
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Configure provider settings (Claude Code)
|
|
375
|
+
*/
|
|
376
|
+
async function configureProvider(configService: GlobalConfigService): Promise<void> {
|
|
377
|
+
console.log(chalk.cyan.bold('\n━━━ 🔑 Provider Configuration (Claude Code)\n'));
|
|
378
|
+
|
|
379
|
+
const providerConfig = await configService.loadProviderConfig();
|
|
380
|
+
|
|
381
|
+
const { defaultProvider } = await inquirer.prompt([
|
|
382
|
+
{
|
|
383
|
+
type: 'list',
|
|
384
|
+
name: 'defaultProvider',
|
|
385
|
+
message: 'Select default provider:',
|
|
386
|
+
choices: [
|
|
387
|
+
{ name: 'Default (Claude Code built-in)', value: 'default' },
|
|
388
|
+
{ name: 'Kimi', value: 'kimi' },
|
|
389
|
+
{ name: 'Z.ai', value: 'zai' },
|
|
390
|
+
new inquirer.Separator(),
|
|
391
|
+
{ name: 'Ask me every time', value: 'ask-every-time' },
|
|
392
|
+
],
|
|
393
|
+
default: providerConfig.claudeCode.defaultProvider,
|
|
394
|
+
},
|
|
395
|
+
]);
|
|
396
|
+
|
|
397
|
+
providerConfig.claudeCode.defaultProvider = defaultProvider;
|
|
398
|
+
|
|
399
|
+
// Configure API keys if provider selected
|
|
400
|
+
if (defaultProvider === 'kimi' || defaultProvider === 'zai') {
|
|
401
|
+
const currentKey = providerConfig.claudeCode.providers[defaultProvider]?.apiKey;
|
|
402
|
+
|
|
403
|
+
const { shouldConfigure } = await inquirer.prompt([
|
|
404
|
+
{
|
|
405
|
+
type: 'confirm',
|
|
406
|
+
name: 'shouldConfigure',
|
|
407
|
+
message: currentKey ? `Update ${defaultProvider} API key?` : `Configure ${defaultProvider} API key?`,
|
|
408
|
+
default: !currentKey,
|
|
409
|
+
},
|
|
410
|
+
]);
|
|
411
|
+
|
|
412
|
+
if (shouldConfigure) {
|
|
413
|
+
const { apiKey } = await inquirer.prompt([
|
|
414
|
+
{
|
|
415
|
+
type: 'password',
|
|
416
|
+
name: 'apiKey',
|
|
417
|
+
message: 'Enter API key:',
|
|
418
|
+
mask: '*',
|
|
419
|
+
},
|
|
420
|
+
]);
|
|
421
|
+
|
|
422
|
+
if (!providerConfig.claudeCode.providers[defaultProvider]) {
|
|
423
|
+
providerConfig.claudeCode.providers[defaultProvider] = { enabled: true };
|
|
424
|
+
}
|
|
425
|
+
providerConfig.claudeCode.providers[defaultProvider]!.apiKey = apiKey;
|
|
426
|
+
providerConfig.claudeCode.providers[defaultProvider]!.enabled = true;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
await configService.saveProviderConfig(providerConfig);
|
|
431
|
+
|
|
432
|
+
console.log(chalk.green('\n✓ Provider configuration saved'));
|
|
433
|
+
console.log(chalk.dim(` Default provider: ${defaultProvider}`));
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Configure target platform
|
|
438
|
+
*/
|
|
439
|
+
async function configureTarget(configService: GlobalConfigService): Promise<void> {
|
|
440
|
+
console.log(chalk.cyan.bold('\n━━━ 🎯 Target Platform\n'));
|
|
441
|
+
|
|
442
|
+
const settings = await configService.loadSettings();
|
|
443
|
+
|
|
444
|
+
const { defaultTarget } = await inquirer.prompt([
|
|
445
|
+
{
|
|
446
|
+
type: 'list',
|
|
447
|
+
name: 'defaultTarget',
|
|
448
|
+
message: 'Select default target platform:',
|
|
449
|
+
choices: [
|
|
450
|
+
{ name: 'Claude Code', value: 'claude-code' },
|
|
451
|
+
{ name: 'OpenCode', value: 'opencode' },
|
|
452
|
+
],
|
|
453
|
+
default: settings.defaultTarget || 'claude-code',
|
|
454
|
+
},
|
|
455
|
+
]);
|
|
456
|
+
|
|
457
|
+
settings.defaultTarget = defaultTarget;
|
|
458
|
+
await configService.saveSettings(settings);
|
|
459
|
+
|
|
460
|
+
console.log(chalk.green('\n✓ Target platform saved'));
|
|
461
|
+
console.log(chalk.dim(` Default: ${defaultTarget}`));
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* Configure general settings
|
|
466
|
+
*/
|
|
467
|
+
async function configureGeneral(configService: GlobalConfigService): Promise<void> {
|
|
468
|
+
console.log(chalk.cyan.bold('\n━━━ ⚙️ General Settings\n'));
|
|
469
|
+
|
|
470
|
+
const settings = await configService.loadSettings();
|
|
471
|
+
|
|
472
|
+
console.log(chalk.dim('Flow Home Directory:'), configService.getFlowHomeDir());
|
|
473
|
+
console.log(chalk.dim('Version:'), settings.version);
|
|
474
|
+
console.log(chalk.dim('Last Updated:'), new Date(settings.lastUpdated).toLocaleString());
|
|
475
|
+
|
|
476
|
+
const { action } = await inquirer.prompt([
|
|
477
|
+
{
|
|
478
|
+
type: 'list',
|
|
479
|
+
name: 'action',
|
|
480
|
+
message: 'What would you like to do?',
|
|
481
|
+
choices: [
|
|
482
|
+
{ name: 'Reset to defaults', value: 'reset' },
|
|
483
|
+
{ name: 'Show current configuration', value: 'show' },
|
|
484
|
+
new inquirer.Separator(),
|
|
485
|
+
{ name: '← Back', value: 'back' },
|
|
486
|
+
],
|
|
487
|
+
},
|
|
488
|
+
]);
|
|
489
|
+
|
|
490
|
+
if (action === 'reset') {
|
|
491
|
+
const { confirm } = await inquirer.prompt([
|
|
492
|
+
{
|
|
493
|
+
type: 'confirm',
|
|
494
|
+
name: 'confirm',
|
|
495
|
+
message: 'Are you sure you want to reset all settings to defaults?',
|
|
496
|
+
default: false,
|
|
497
|
+
},
|
|
498
|
+
]);
|
|
499
|
+
|
|
500
|
+
if (confirm) {
|
|
501
|
+
await configService.saveSettings({
|
|
502
|
+
version: '1.0.0',
|
|
503
|
+
firstRun: false,
|
|
504
|
+
lastUpdated: new Date().toISOString(),
|
|
505
|
+
});
|
|
506
|
+
await configService.saveProviderConfig({
|
|
507
|
+
claudeCode: {
|
|
508
|
+
defaultProvider: 'ask-every-time',
|
|
509
|
+
providers: {
|
|
510
|
+
kimi: { enabled: false },
|
|
511
|
+
zai: { enabled: false },
|
|
512
|
+
},
|
|
513
|
+
},
|
|
514
|
+
});
|
|
515
|
+
await configService.saveMCPConfig({
|
|
516
|
+
version: '1.0.0',
|
|
517
|
+
servers: {},
|
|
518
|
+
});
|
|
519
|
+
|
|
520
|
+
console.log(chalk.green('\n✓ Settings reset to defaults'));
|
|
521
|
+
}
|
|
522
|
+
} else if (action === 'show') {
|
|
523
|
+
const providerConfig = await configService.loadProviderConfig();
|
|
524
|
+
const mcpConfig = await configService.loadMCPConfig();
|
|
525
|
+
|
|
526
|
+
console.log(chalk.cyan('\nCurrent Configuration:'));
|
|
527
|
+
console.log(JSON.stringify({ settings, providerConfig, mcpConfig }, null, 2));
|
|
528
|
+
}
|
|
529
|
+
}
|