@sylphx/flow 3.16.0 → 3.17.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 +15 -0
- package/assets/agents/builder.md +3 -1
- package/package.json +80 -79
- package/src/commands/flow/execute-v2.ts +44 -58
- package/src/commands/settings/checkbox-config.ts +18 -18
- package/src/commands/settings-command.ts +122 -144
- package/src/core/installers/mcp-installer.ts +42 -34
- package/src/core/target-manager.ts +13 -19
- package/src/core/upgrade-manager.ts +22 -19
- package/src/services/mcp-service.ts +33 -29
- package/src/services/target-installer.ts +28 -57
- package/src/utils/config/mcp-config.ts +31 -56
- package/src/utils/display/logger.ts +95 -172
- package/src/utils/prompt-helpers.ts +16 -5
- package/src/utils/prompts/index.ts +232 -0
- package/src/utils/target-selection.ts +38 -46
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# @sylphx/flow
|
|
2
2
|
|
|
3
|
+
## 3.17.0 (2026-02-05)
|
|
4
|
+
|
|
5
|
+
### ♻️ Refactoring
|
|
6
|
+
|
|
7
|
+
- **flow:** migrate CLI prompts to Clack and logging to Pino ([08aceb7](https://github.com/SylphxAI/flow/commit/08aceb7d))
|
|
8
|
+
|
|
9
|
+
### 🐛 Bug Fixes
|
|
10
|
+
|
|
11
|
+
- **flow:** remove unsafe separator pattern from Clack prompts ([aaf17a7](https://github.com/SylphxAI/flow/commit/aaf17a7d))
|
|
12
|
+
|
|
13
|
+
### 📝 Documentation
|
|
14
|
+
|
|
15
|
+
- **builder:** add Zod v4 to tech stack ([2b37327](https://github.com/SylphxAI/flow/commit/2b373279))
|
|
16
|
+
- **builder:** restructure tech stack - Zod as standalone category ([90875ba](https://github.com/SylphxAI/flow/commit/90875baa))
|
|
17
|
+
|
|
3
18
|
## 3.16.0 (2026-02-05)
|
|
4
19
|
|
|
5
20
|
### ✨ Features
|
package/assets/agents/builder.md
CHANGED
|
@@ -46,13 +46,15 @@ State-of-the-art industrial standard. Every time. Would you stake your reputatio
|
|
|
46
46
|
|
|
47
47
|
**Framework & Runtime:** Next.js 16+, React, Bun
|
|
48
48
|
|
|
49
|
+
**Schema & Validation:** Zod v4
|
|
50
|
+
|
|
49
51
|
**Data & API:** Hono + @hono/zod-openapi + hc (type-safe client), React Query, Drizzle ORM
|
|
50
52
|
|
|
51
53
|
**Database & Infrastructure:** Neon PostgreSQL, Upstash Workflow, Vercel, Vercel Blob, Modal (serverless long-running)
|
|
52
54
|
|
|
53
55
|
**UI & Styling:** Base UI, Tailwind CSS v4 (CSS-first), Motion v12 (animation)
|
|
54
56
|
|
|
55
|
-
**Forms:** React Hook Form +
|
|
57
|
+
**Forms:** React Hook Form + @hookform/resolvers
|
|
56
58
|
|
|
57
59
|
**Tables & Lists:** TanStack Table, TanStack Virtual
|
|
58
60
|
|
package/package.json
CHANGED
|
@@ -1,81 +1,82 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
2
|
+
"name": "@sylphx/flow",
|
|
3
|
+
"version": "3.17.0",
|
|
4
|
+
"description": "One CLI to rule them all. Unified orchestration layer for AI coding assistants. Auto-detection, auto-installation, auto-upgrade.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"sylphx-flow": "./src/index.ts",
|
|
8
|
+
"flow": "./src/index.ts"
|
|
9
|
+
},
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"import": "./src/index.ts",
|
|
13
|
+
"types": "./src/index.ts"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"engines": {
|
|
17
|
+
"node": ">=18.0.0"
|
|
18
|
+
},
|
|
19
|
+
"scripts": {
|
|
20
|
+
"dev": "bun src/index.ts",
|
|
21
|
+
"start": "bun src/index.ts",
|
|
22
|
+
"test": "bun test",
|
|
23
|
+
"test:watch": "bun test --watch",
|
|
24
|
+
"type-check": "tsc --noEmit",
|
|
25
|
+
"prepublishOnly": "echo 'Using assets from packages/flow/assets'"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@clack/prompts": "^0.9.0",
|
|
29
|
+
"boxen": "^8.0.1",
|
|
30
|
+
"chalk": "^5.6.2",
|
|
31
|
+
"commander": "^14.0.2",
|
|
32
|
+
"debug": "^4.4.3",
|
|
33
|
+
"gradient-string": "^3.0.0",
|
|
34
|
+
"gray-matter": "^4.0.3",
|
|
35
|
+
"pino": "^9.0.0",
|
|
36
|
+
"pino-pretty": "^11.0.0",
|
|
37
|
+
"yaml": "^2.8.1",
|
|
38
|
+
"zod": "^4.1.12"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/node": "^24.9.2",
|
|
42
|
+
"typescript": "^5.9.3"
|
|
43
|
+
},
|
|
44
|
+
"publishConfig": {
|
|
45
|
+
"access": "public"
|
|
46
|
+
},
|
|
47
|
+
"files": [
|
|
48
|
+
"src",
|
|
49
|
+
"assets",
|
|
50
|
+
"README.md",
|
|
51
|
+
"CHANGELOG.md",
|
|
52
|
+
"LOOP_MODE.md",
|
|
53
|
+
"UPGRADE.md",
|
|
54
|
+
"package.json"
|
|
55
|
+
],
|
|
56
|
+
"keywords": [
|
|
57
|
+
"ai",
|
|
58
|
+
"automation",
|
|
59
|
+
"workflow",
|
|
60
|
+
"claude-code",
|
|
61
|
+
"opencode",
|
|
62
|
+
"cursor",
|
|
63
|
+
"cli",
|
|
64
|
+
"orchestration",
|
|
65
|
+
"unified",
|
|
66
|
+
"meta-layer",
|
|
67
|
+
"developer-tools",
|
|
68
|
+
"auto-install",
|
|
69
|
+
"auto-upgrade"
|
|
70
|
+
],
|
|
71
|
+
"repository": {
|
|
72
|
+
"type": "git",
|
|
73
|
+
"url": "https://github.com/sylphxltd/flow.git",
|
|
74
|
+
"directory": "packages/flow"
|
|
75
|
+
},
|
|
76
|
+
"bugs": {
|
|
77
|
+
"url": "https://github.com/sylphxltd/flow/issues"
|
|
78
|
+
},
|
|
79
|
+
"homepage": "https://github.com/sylphxltd/flow#readme",
|
|
80
|
+
"license": "MIT",
|
|
81
|
+
"author": "sylphxltd"
|
|
81
82
|
}
|
|
@@ -7,7 +7,6 @@ import fs from 'node:fs/promises';
|
|
|
7
7
|
import path from 'node:path';
|
|
8
8
|
import { fileURLToPath } from 'node:url';
|
|
9
9
|
import chalk from 'chalk';
|
|
10
|
-
import inquirer from 'inquirer';
|
|
11
10
|
import { FlowExecutor } from '../../core/flow-executor.js';
|
|
12
11
|
import { targetManager } from '../../core/target-manager.js';
|
|
13
12
|
import { AutoUpgrade } from '../../services/auto-upgrade.js';
|
|
@@ -18,6 +17,7 @@ import { extractAgentInstructions, loadAgentContent } from '../../utils/agent-en
|
|
|
18
17
|
import { showAttachSummary, showHeader } from '../../utils/display/banner.js';
|
|
19
18
|
import { CLIError } from '../../utils/error-handler.js';
|
|
20
19
|
import { UserCancelledError } from '../../utils/errors.js';
|
|
20
|
+
import { log, promptConfirm, promptSelect } from '../../utils/prompts/index.js';
|
|
21
21
|
import { ensureTargetInstalled, promptForTargetSelection } from '../../utils/target-selection.js';
|
|
22
22
|
import { resolvePrompt } from './prompt.js';
|
|
23
23
|
import type { FlowOptions } from './types.js';
|
|
@@ -62,66 +62,52 @@ function configureProviderEnv(provider: 'kimi' | 'zai', apiKey: string): void {
|
|
|
62
62
|
* Select and configure provider for Claude Code (silent unless prompting)
|
|
63
63
|
*/
|
|
64
64
|
async function selectProvider(configService: GlobalConfigService): Promise<void> {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
if (defaultProvider
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
configureProviderEnv(defaultProvider, provider.apiKey);
|
|
75
|
-
}
|
|
65
|
+
const providerConfig = await configService.loadProviderConfig();
|
|
66
|
+
const defaultProvider = providerConfig.claudeCode.defaultProvider;
|
|
67
|
+
|
|
68
|
+
// If not "ask-every-time", use the default provider silently
|
|
69
|
+
if (defaultProvider !== 'ask-every-time') {
|
|
70
|
+
if (defaultProvider === 'kimi' || defaultProvider === 'zai') {
|
|
71
|
+
const provider = providerConfig.claudeCode.providers[defaultProvider];
|
|
72
|
+
if (provider?.apiKey) {
|
|
73
|
+
configureProviderEnv(defaultProvider, provider.apiKey);
|
|
76
74
|
}
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Ask user which provider to use for this session
|
|
81
|
-
const { selectedProvider, rememberChoice } = await inquirer.prompt([
|
|
82
|
-
{
|
|
83
|
-
type: 'list',
|
|
84
|
-
name: 'selectedProvider',
|
|
85
|
-
message: 'Select provider:',
|
|
86
|
-
choices: [
|
|
87
|
-
{ name: 'Default (Claude Code built-in)', value: 'default' },
|
|
88
|
-
{ name: 'Kimi', value: 'kimi' },
|
|
89
|
-
{ name: 'Z.ai', value: 'zai' },
|
|
90
|
-
],
|
|
91
|
-
default: 'default',
|
|
92
|
-
},
|
|
93
|
-
{
|
|
94
|
-
type: 'confirm',
|
|
95
|
-
name: 'rememberChoice',
|
|
96
|
-
message: 'Remember this choice?',
|
|
97
|
-
default: true,
|
|
98
|
-
},
|
|
99
|
-
]);
|
|
100
|
-
|
|
101
|
-
// Save choice if user wants to remember
|
|
102
|
-
if (rememberChoice) {
|
|
103
|
-
providerConfig.claudeCode.defaultProvider = selectedProvider;
|
|
104
|
-
await configService.saveProviderConfig(providerConfig);
|
|
105
75
|
}
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
106
78
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
79
|
+
// Ask user which provider to use for this session
|
|
80
|
+
const selectedProvider = await promptSelect({
|
|
81
|
+
message: 'Select provider:',
|
|
82
|
+
options: [
|
|
83
|
+
{ label: 'Default (Claude Code built-in)', value: 'default' },
|
|
84
|
+
{ label: 'Kimi', value: 'kimi' },
|
|
85
|
+
{ label: 'Z.ai', value: 'zai' },
|
|
86
|
+
],
|
|
87
|
+
initialValue: 'default',
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const rememberChoice = await promptConfirm({
|
|
91
|
+
message: 'Remember this choice?',
|
|
92
|
+
initialValue: true,
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// Save choice if user wants to remember
|
|
96
|
+
if (rememberChoice) {
|
|
97
|
+
providerConfig.claudeCode.defaultProvider = selectedProvider;
|
|
98
|
+
await configService.saveProviderConfig(providerConfig);
|
|
99
|
+
}
|
|
110
100
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
}
|
|
101
|
+
// Configure environment variables based on selection
|
|
102
|
+
if (selectedProvider === 'kimi' || selectedProvider === 'zai') {
|
|
103
|
+
const provider = providerConfig.claudeCode.providers[selectedProvider];
|
|
115
104
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
// Handle user cancellation (Ctrl+C)
|
|
120
|
-
const err = error as Error & { name?: string };
|
|
121
|
-
if (err.name === 'ExitPromptError' || err.message?.includes('force closed')) {
|
|
122
|
-
throw new UserCancelledError('Provider selection cancelled');
|
|
105
|
+
if (!provider?.apiKey) {
|
|
106
|
+
log.warn('API key not configured. Use: sylphx-flow settings');
|
|
107
|
+
return;
|
|
123
108
|
}
|
|
124
|
-
|
|
109
|
+
|
|
110
|
+
configureProviderEnv(selectedProvider, provider.apiKey);
|
|
125
111
|
}
|
|
126
112
|
}
|
|
127
113
|
|
|
@@ -221,11 +207,11 @@ export async function executeFlowV2(
|
|
|
221
207
|
|
|
222
208
|
if (!installedTargets.includes(selectedTargetId)) {
|
|
223
209
|
const installation = targetInstaller.getInstallationInfo(selectedTargetId);
|
|
224
|
-
|
|
210
|
+
log.warn(`${installation?.name} not installed`);
|
|
225
211
|
const installed = await targetInstaller.install(selectedTargetId, true);
|
|
226
212
|
|
|
227
213
|
if (!installed) {
|
|
228
|
-
|
|
214
|
+
log.error('Cannot proceed: installation failed');
|
|
229
215
|
process.exit(1);
|
|
230
216
|
}
|
|
231
217
|
}
|
|
@@ -313,7 +299,7 @@ export async function executeFlowV2(
|
|
|
313
299
|
} catch (error) {
|
|
314
300
|
// Handle user cancellation gracefully
|
|
315
301
|
if (error instanceof UserCancelledError) {
|
|
316
|
-
|
|
302
|
+
log.warn('Cancelled');
|
|
317
303
|
try {
|
|
318
304
|
await executor.cleanup(projectPath);
|
|
319
305
|
} catch {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import chalk from 'chalk';
|
|
7
|
-
import
|
|
7
|
+
import { log, type MultiselectOption, promptMultiselect } from '../../utils/prompts/index.js';
|
|
8
8
|
|
|
9
9
|
// ============================================================================
|
|
10
10
|
// Types
|
|
@@ -47,16 +47,16 @@ export const getEnabledKeys = (config: ConfigMap): string[] =>
|
|
|
47
47
|
Object.keys(config).filter((key) => config[key]?.enabled);
|
|
48
48
|
|
|
49
49
|
/**
|
|
50
|
-
* Build
|
|
50
|
+
* Build multiselect options from available items
|
|
51
51
|
*/
|
|
52
|
-
export const
|
|
52
|
+
export const buildOptions = <T extends string>(
|
|
53
53
|
available: Record<T, string>,
|
|
54
54
|
enabledKeys: string[]
|
|
55
|
-
):
|
|
55
|
+
): MultiselectOption<T>[] =>
|
|
56
56
|
Object.entries(available).map(([key, name]) => ({
|
|
57
|
-
|
|
57
|
+
label: name as string,
|
|
58
58
|
value: key as T,
|
|
59
|
-
|
|
59
|
+
hint: enabledKeys.includes(key) ? 'enabled' : undefined,
|
|
60
60
|
}));
|
|
61
61
|
|
|
62
62
|
/**
|
|
@@ -82,11 +82,11 @@ export const printHeader = (icon: string, title: string): void => {
|
|
|
82
82
|
};
|
|
83
83
|
|
|
84
84
|
/**
|
|
85
|
-
* Print confirmation message
|
|
85
|
+
* Print confirmation message using Clack log
|
|
86
86
|
*/
|
|
87
87
|
export const printConfirmation = (itemType: string, count: number): void => {
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
log.success(`${itemType} configuration saved`);
|
|
89
|
+
log.info(`Enabled ${itemType.toLowerCase()}: ${count}`);
|
|
90
90
|
};
|
|
91
91
|
|
|
92
92
|
// ============================================================================
|
|
@@ -108,15 +108,15 @@ export const handleCheckboxConfig = async <T extends string>(
|
|
|
108
108
|
// Get current enabled items
|
|
109
109
|
const enabledKeys = getEnabledKeys(current);
|
|
110
110
|
|
|
111
|
-
//
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
111
|
+
// Build options for multiselect
|
|
112
|
+
const multiselectOptions = buildOptions(available, enabledKeys);
|
|
113
|
+
|
|
114
|
+
// Show multiselect prompt
|
|
115
|
+
const selected = await promptMultiselect<T>({
|
|
116
|
+
message,
|
|
117
|
+
options: multiselectOptions,
|
|
118
|
+
initialValues: enabledKeys as T[],
|
|
119
|
+
});
|
|
120
120
|
|
|
121
121
|
// Update config
|
|
122
122
|
const updated = updateConfig(available, selected);
|