@sylphx/flow 2.1.3 → 2.1.5

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.
Files changed (73) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +44 -0
  3. package/package.json +79 -73
  4. package/src/commands/flow/execute-v2.ts +37 -29
  5. package/src/commands/flow/prompt.ts +5 -3
  6. package/src/commands/flow/types.ts +0 -2
  7. package/src/commands/flow-command.ts +20 -13
  8. package/src/commands/hook-command.ts +1 -3
  9. package/src/commands/settings/checkbox-config.ts +128 -0
  10. package/src/commands/settings/index.ts +6 -0
  11. package/src/commands/settings-command.ts +84 -156
  12. package/src/config/ai-config.ts +60 -41
  13. package/src/core/agent-loader.ts +11 -6
  14. package/src/core/attach/file-attacher.ts +172 -0
  15. package/src/core/attach/index.ts +5 -0
  16. package/src/core/attach-manager.ts +117 -171
  17. package/src/core/backup-manager.ts +35 -29
  18. package/src/core/cleanup-handler.ts +11 -8
  19. package/src/core/error-handling.ts +23 -30
  20. package/src/core/flow-executor.ts +58 -76
  21. package/src/core/formatting/bytes.ts +2 -4
  22. package/src/core/functional/async.ts +5 -4
  23. package/src/core/functional/error-handler.ts +2 -2
  24. package/src/core/git-stash-manager.ts +21 -10
  25. package/src/core/installers/file-installer.ts +0 -1
  26. package/src/core/installers/mcp-installer.ts +0 -1
  27. package/src/core/project-manager.ts +24 -18
  28. package/src/core/secrets-manager.ts +54 -73
  29. package/src/core/session-manager.ts +20 -22
  30. package/src/core/state-detector.ts +139 -80
  31. package/src/core/template-loader.ts +13 -31
  32. package/src/core/upgrade-manager.ts +122 -69
  33. package/src/index.ts +8 -5
  34. package/src/services/auto-upgrade.ts +1 -1
  35. package/src/services/config-service.ts +41 -29
  36. package/src/services/global-config.ts +3 -3
  37. package/src/services/target-installer.ts +11 -26
  38. package/src/targets/claude-code.ts +35 -81
  39. package/src/targets/opencode.ts +28 -68
  40. package/src/targets/shared/index.ts +7 -0
  41. package/src/targets/shared/mcp-transforms.ts +132 -0
  42. package/src/targets/shared/target-operations.ts +135 -0
  43. package/src/types/cli.types.ts +2 -2
  44. package/src/types/provider.types.ts +1 -7
  45. package/src/types/session.types.ts +11 -11
  46. package/src/types/target.types.ts +3 -1
  47. package/src/types/todo.types.ts +1 -1
  48. package/src/types.ts +1 -1
  49. package/src/utils/__tests__/package-manager-detector.test.ts +6 -6
  50. package/src/utils/agent-enhancer.ts +4 -4
  51. package/src/utils/config/paths.ts +3 -1
  52. package/src/utils/config/target-utils.ts +2 -2
  53. package/src/utils/display/banner.ts +2 -2
  54. package/src/utils/display/notifications.ts +58 -45
  55. package/src/utils/display/status.ts +29 -12
  56. package/src/utils/files/file-operations.ts +1 -1
  57. package/src/utils/files/sync-utils.ts +38 -41
  58. package/src/utils/index.ts +19 -27
  59. package/src/utils/package-manager-detector.ts +15 -5
  60. package/src/utils/security/security.ts +8 -4
  61. package/src/utils/target-selection.ts +6 -8
  62. package/src/utils/version.ts +4 -2
  63. package/src/commands/flow-orchestrator.ts +0 -328
  64. package/src/commands/init-command.ts +0 -92
  65. package/src/commands/init-core.ts +0 -331
  66. package/src/core/agent-manager.ts +0 -174
  67. package/src/core/loop-controller.ts +0 -200
  68. package/src/core/rule-loader.ts +0 -147
  69. package/src/core/rule-manager.ts +0 -240
  70. package/src/services/claude-config-service.ts +0 -252
  71. package/src/services/first-run-setup.ts +0 -220
  72. package/src/services/smart-config-service.ts +0 -269
  73. package/src/types/api.types.ts +0 -9
@@ -3,57 +3,49 @@
3
3
  * Feature-based organization for better modularity
4
4
  */
5
5
 
6
+ // ============================================================================
7
+ // SHARED UTILITIES
8
+ // ============================================================================
9
+ export * from '../shared/index.js';
10
+ // ============================================================================
11
+ // AGENTS
12
+ // ============================================================================
13
+ export * from './agent-enhancer.js';
14
+ export * from './config/mcp-config.js';
15
+ export * from './config/paths.js';
6
16
  // ============================================================================
7
17
  // CONFIG & SETTINGS
8
18
  // ============================================================================
9
19
  export * from './config/settings.js';
10
- export * from './config/mcp-config.js';
11
20
  export * from './config/target-config.js';
12
21
  export * from './config/target-utils.js';
13
- export * from './config/paths.js';
14
-
15
22
  // ============================================================================
16
23
  // DISPLAY & OUTPUT
17
24
  // ============================================================================
18
25
  export * from './display/banner.js';
19
- export * from './display/status.js';
20
26
  export * from './display/cli-output.js';
21
27
  export * from './display/logger.js';
22
28
  export * from './display/notifications.js';
23
-
29
+ export * from './display/status.js';
30
+ // ============================================================================
31
+ // ERROR HANDLING
32
+ // ============================================================================
33
+ export * from './error-handler.js';
24
34
  // ============================================================================
25
35
  // FILES & SYNC
26
36
  // ============================================================================
27
37
  export * from './files/file-operations.js';
28
38
  export * from './files/sync-utils.js';
29
-
30
39
  // ============================================================================
31
- // SECURITY
40
+ // FUNCTIONAL PROGRAMMING
32
41
  // ============================================================================
33
- export * from './security/security.js';
42
+ export * from './functional.js';
34
43
  export * from './security/secret-utils.js';
35
-
36
44
  // ============================================================================
37
- // ERROR HANDLING
45
+ // SECURITY
38
46
  // ============================================================================
39
- export * from './error-handler.js';
40
-
47
+ export * from './security/security.js';
41
48
  // ============================================================================
42
49
  // VERSIONING
43
50
  // ============================================================================
44
51
  export * from './version.js';
45
-
46
- // ============================================================================
47
- // AGENTS
48
- // ============================================================================
49
- export * from './agent-enhancer.js';
50
-
51
- // ============================================================================
52
- // FUNCTIONAL PROGRAMMING
53
- // ============================================================================
54
- export * from './functional.js';
55
-
56
- // ============================================================================
57
- // SHARED UTILITIES
58
- // ============================================================================
59
- export * from '../shared/index.js';
@@ -27,10 +27,18 @@ export function detectPackageManagerFromUserAgent(): PackageManager | null {
27
27
  return null;
28
28
  }
29
29
 
30
- if (userAgent.includes('bun')) return 'bun';
31
- if (userAgent.includes('pnpm')) return 'pnpm';
32
- if (userAgent.includes('yarn')) return 'yarn';
33
- if (userAgent.includes('npm')) return 'npm';
30
+ if (userAgent.includes('bun')) {
31
+ return 'bun';
32
+ }
33
+ if (userAgent.includes('pnpm')) {
34
+ return 'pnpm';
35
+ }
36
+ if (userAgent.includes('yarn')) {
37
+ return 'yarn';
38
+ }
39
+ if (userAgent.includes('npm')) {
40
+ return 'npm';
41
+ }
34
42
 
35
43
  return null;
36
44
  }
@@ -38,7 +46,9 @@ export function detectPackageManagerFromUserAgent(): PackageManager | null {
38
46
  /**
39
47
  * Detect package manager from lock files in directory
40
48
  */
41
- export function detectPackageManagerFromLockFiles(dir: string = process.cwd()): PackageManager | null {
49
+ export function detectPackageManagerFromLockFiles(
50
+ dir: string = process.cwd()
51
+ ): PackageManager | null {
42
52
  const lockFiles: Record<PackageManager, string[]> = {
43
53
  bun: ['bun.lockb', 'bun.lock'],
44
54
  pnpm: ['pnpm-lock.yaml'],
@@ -209,11 +209,15 @@ export const commandSecurity = {
209
209
 
210
210
  try {
211
211
  return await execFileAsync(command, validatedArgs, secureOptions);
212
- } catch (error: any) {
212
+ } catch (error: unknown) {
213
213
  // Sanitize error message to prevent information disclosure
214
- const sanitizedError = new Error(`Command execution failed: ${command}`);
215
- sanitizedError.code = error.code;
216
- sanitizedError.signal = error.signal;
214
+ const err = error as NodeJS.ErrnoException & { signal?: string };
215
+ const sanitizedError = new Error(`Command execution failed: ${command}`) as Error & {
216
+ code?: string;
217
+ signal?: string;
218
+ };
219
+ sanitizedError.code = err.code;
220
+ sanitizedError.signal = err.signal;
217
221
  throw sanitizedError;
218
222
  }
219
223
  },
@@ -5,7 +5,7 @@
5
5
 
6
6
  import chalk from 'chalk';
7
7
  import inquirer from 'inquirer';
8
- import { TargetInstaller } from '../services/target-installer.js';
8
+ import type { TargetInstaller } from '../services/target-installer.js';
9
9
  import { handlePromptError } from './prompt-helpers.js';
10
10
 
11
11
  /**
@@ -15,7 +15,7 @@ export interface TargetChoice {
15
15
  /** Display name of the target */
16
16
  name: string;
17
17
  /** Target identifier */
18
- value: 'claude-code' | 'opencode' | 'cursor';
18
+ value: 'claude-code' | 'opencode';
19
19
  /** Whether the target is currently installed */
20
20
  installed: boolean;
21
21
  }
@@ -37,11 +37,6 @@ export function buildAvailableTargets(installedTargets: string[]): TargetChoice[
37
37
  value: 'opencode',
38
38
  installed: installedTargets.includes('opencode'),
39
39
  },
40
- {
41
- name: 'Cursor',
42
- value: 'cursor',
43
- installed: installedTargets.includes('cursor'),
44
- },
45
40
  ];
46
41
  }
47
42
 
@@ -51,7 +46,10 @@ export function buildAvailableTargets(installedTargets: string[]): TargetChoice[
51
46
  * @param context - Context where choice is displayed (affects status message)
52
47
  * @returns Formatted string with target name and installation status
53
48
  */
54
- export function formatTargetChoice(target: TargetChoice, context: 'execution' | 'settings'): string {
49
+ export function formatTargetChoice(
50
+ target: TargetChoice,
51
+ context: 'execution' | 'settings'
52
+ ): string {
55
53
  const status = target.installed
56
54
  ? chalk.green(' āœ“ installed')
57
55
  : context === 'execution'
@@ -34,9 +34,11 @@ export function isVersionOutdated(current: string, latest: string): boolean {
34
34
  /**
35
35
  * Parse version string into components
36
36
  */
37
- export function parseVersion(version: string): { major: number; minor: number; patch: number } | null {
37
+ export function parseVersion(
38
+ version: string
39
+ ): { major: number; minor: number; patch: number } | null {
38
40
  const parts = version.split('.').map(Number);
39
- if (parts.length < 3 || parts.some(isNaN)) {
41
+ if (parts.length < 3 || parts.some(Number.isNaN)) {
40
42
  return null;
41
43
  }
42
44
  return {
@@ -1,328 +0,0 @@
1
- /**
2
- * Flow Orchestrator - Simplified flow management
3
- * Separates concerns and reduces complexity
4
- */
5
-
6
- import chalk from 'chalk';
7
- import type { FlowOptions } from './flow/types.js';
8
- import { StateDetector, type ProjectState } from '../core/state-detector.js';
9
- import { UpgradeManager } from '../core/upgrade-manager.js';
10
- import { targetManager } from '../core/target-manager.js';
11
- import { detectPackageManager, getUpgradeCommand } from '../utils/package-manager-detector.js';
12
-
13
- /**
14
- * Step 1: Check for available upgrades
15
- */
16
- export async function checkUpgrades(
17
- state: ProjectState,
18
- options: FlowOptions
19
- ): Promise<void> {
20
- if (options.initOnly || options.runOnly) return;
21
-
22
- const upgradeManager = new UpgradeManager();
23
- const updates = await upgradeManager.checkUpdates();
24
- const packageManager = detectPackageManager();
25
-
26
- // Check Flow upgrade
27
- if (updates.flowUpdate && updates.flowVersion) {
28
- const upgradeCmd = getUpgradeCommand('@sylphx/flow', packageManager);
29
- console.log(
30
- chalk.yellow(
31
- `šŸ“¦ Sylphx Flow update available: ${updates.flowVersion.current} → ${updates.flowVersion.latest}`
32
- )
33
- );
34
- console.log(chalk.dim(` Quick upgrade: ${chalk.cyan('sylphx-flow upgrade --auto')}`));
35
- console.log(chalk.dim(` Or run: ${chalk.cyan(upgradeCmd)}\n`));
36
- }
37
-
38
- // Check target upgrade
39
- if (updates.targetUpdate && updates.targetVersion) {
40
- console.log(
41
- chalk.yellow(
42
- `šŸ“¦ Target update available: ${updates.targetVersion.current} → ${updates.targetVersion.latest}`
43
- )
44
- );
45
- console.log(chalk.dim(` Run: ${chalk.cyan('sylphx-flow upgrade --target --auto')}\n`));
46
- }
47
- }
48
-
49
-
50
- /**
51
- * Step 2: Check component integrity and prompt for repair
52
- */
53
- export async function checkComponentIntegrity(
54
- state: ProjectState,
55
- options: FlowOptions
56
- ): Promise<void> {
57
- // Skip if not initialized or cleaning or init-only
58
- if (!state.initialized || options.clean || options.initOnly) return;
59
-
60
- // Skip in quick mode
61
- if (options.quick) return;
62
-
63
- // Find missing components (target-aware)
64
- const missing: string[] = [];
65
-
66
- // Agents are always required
67
- if (!state.components.agents.installed) missing.push('agents');
68
-
69
- // For OpenCode: check rules (separate AGENTS.md file)
70
- // For Claude Code: rules are included in agent files, so skip this check
71
- if (state.target === 'opencode' && !state.components.rules.installed) {
72
- missing.push('rules');
73
- }
74
-
75
- // Hooks are optional - don't check
76
- // Claude Code can have hooks in .claude/hooks/*.js but they're optional
77
- // OpenCode doesn't have separate hooks
78
-
79
- // MCP is optional now - many users don't use MCP
80
- // if (!state.components.mcp.installed) missing.push('mcp');
81
-
82
- // Output styles:
83
- // - Claude Code: included in agent files, so skip check
84
- // - OpenCode: included in AGENTS.md, so skip check
85
-
86
- // Slash commands are optional
87
- // if (!state.components.slashCommands.installed) missing.push('slash commands');
88
-
89
- // If no missing components, we're good
90
- if (missing.length === 0) return;
91
-
92
- // Prompt user to repair
93
- console.log(chalk.yellow(`\nāš ļø Missing components detected: ${missing.join(', ')}\n`));
94
- const { default: inquirer } = await import('inquirer');
95
- const { repair } = await inquirer.prompt([
96
- {
97
- type: 'confirm',
98
- name: 'repair',
99
- message: 'Install missing components now?',
100
- default: true,
101
- },
102
- ]);
103
-
104
- if (repair) {
105
- // Set repair mode - will trigger component installation without full re-init
106
- options.repair = true;
107
- console.log(chalk.cyan('\nšŸ”§ Repairing components...\n'));
108
- } else {
109
- console.log(chalk.dim('Skipping repair. Components may not work correctly.\n'));
110
- }
111
- }
112
-
113
- /**
114
- * Step 2.5: Check sync status (new templates available)
115
- * Only checks for missing templates, ignores unknown files
116
- */
117
- export async function checkSyncStatus(
118
- state: ProjectState,
119
- options: FlowOptions
120
- ): Promise<void> {
121
- // Skip if not initialized, syncing, or init-only
122
- if (!state.initialized || options.sync || options.initOnly) return;
123
-
124
- // Skip in quick mode
125
- if (options.quick) return;
126
-
127
- // Need target to check sync status
128
- if (!state.target) return;
129
-
130
- try {
131
- const { buildSyncManifest } = await import('../utils/files/sync-utils.js');
132
- const target = targetManager.getTarget(state.target);
133
-
134
- if (target._tag === 'None') return;
135
-
136
- const manifest = await buildSyncManifest(process.cwd(), target.value);
137
-
138
- // Count missing templates (new templates not installed locally)
139
- const missingCount =
140
- manifest.agents.missing.length +
141
- manifest.slashCommands.missing.length +
142
- manifest.rules.missing.length;
143
-
144
- // Only prompt if there are missing templates
145
- if (missingCount > 0) {
146
- const missing: string[] = [];
147
-
148
- if (manifest.agents.missing.length > 0) {
149
- missing.push(`${manifest.agents.missing.length} agent${manifest.agents.missing.length > 1 ? 's' : ''}`);
150
- }
151
- if (manifest.slashCommands.missing.length > 0) {
152
- missing.push(`${manifest.slashCommands.missing.length} command${manifest.slashCommands.missing.length > 1 ? 's' : ''}`);
153
- }
154
- if (manifest.rules.missing.length > 0) {
155
- missing.push(`${manifest.rules.missing.length} rule${manifest.rules.missing.length > 1 ? 's' : ''}`);
156
- }
157
-
158
- console.log(chalk.yellow(`\nšŸ“¦ New templates available: ${missing.join(', ')}\n`));
159
- console.log(chalk.dim(` Run ${chalk.cyan('sylphx-flow --sync')} to install new templates\n`));
160
- }
161
- } catch (error) {
162
- // Silently ignore sync check errors - don't block execution
163
- }
164
- }
165
-
166
- /**
167
- * Step 3: Handle target selection
168
- * Returns the selected target ID
169
- */
170
- export async function selectTarget(
171
- state: ProjectState,
172
- options: FlowOptions
173
- ): Promise<string | undefined> {
174
- // Force target selection when cleaning
175
- if (options.clean) {
176
- try {
177
- const targetId = await targetManager.promptForTargetSelection();
178
- console.log(chalk.green(`āœ… Selected target: ${targetId}`));
179
- return targetId;
180
- } catch (error) {
181
- // User cancelled with Ctrl+C - exit gracefully
182
- if (error instanceof Error && error.name === 'ExitPromptError') {
183
- console.log('\n');
184
- process.exit(0);
185
- }
186
- throw error;
187
- }
188
- }
189
-
190
- // Use existing target or option
191
- return options.target || state.target;
192
- }
193
-
194
- /**
195
- * Step 3: Initialize project
196
- */
197
- export async function initializeProject(
198
- targetId: string | undefined,
199
- options: FlowOptions
200
- ): Promise<void> {
201
- if (options.runOnly && !options.clean) return;
202
-
203
- console.log(chalk.cyan.bold('━ Initializing Project\n'));
204
-
205
- const { runInit } = await import('./init-command.js');
206
-
207
- const initOptions = {
208
- target: targetId,
209
- verbose: options.verbose,
210
- dryRun: options.dryRun,
211
- clear: options.clean || false,
212
- mcp: options.mcp !== false,
213
- agents: options.agents !== false,
214
- rules: options.rules !== false,
215
- outputStyles: options.outputStyles !== false,
216
- slashCommands: options.slashCommands !== false,
217
- hooks: options.hooks !== false,
218
- helpOption: () => {},
219
- };
220
-
221
- try {
222
- await runInit(initOptions);
223
-
224
- if (!options.dryRun) {
225
- console.log(chalk.green.bold('\nāœ“ Initialization complete\n'));
226
- } else {
227
- console.log(chalk.dim('\nāœ“ Dry run complete - skipping execution\n'));
228
- }
229
- } catch (error) {
230
- console.error(chalk.red.bold('\nāœ— Initialization failed:'), error);
231
- throw error;
232
- }
233
- }
234
-
235
- /**
236
- * Step 4: Launch target
237
- */
238
- export async function launchTarget(
239
- targetId: string | undefined,
240
- prompt: string | undefined,
241
- options: FlowOptions,
242
- state: ProjectState
243
- ): Promise<void> {
244
- if (options.initOnly) return;
245
-
246
- // Resolve target
247
- const resolvedTarget = await targetManager.resolveTarget({
248
- target: targetId || state.target,
249
- allowSelection: false,
250
- });
251
-
252
- console.log(chalk.cyan.bold(`━ Launching ${resolvedTarget}\n`));
253
-
254
- // Check if target supports command execution
255
- const { getTargetsWithCommandSupport } = await import('../config/targets.js');
256
- const supportedTargets = getTargetsWithCommandSupport().map(t => t.id);
257
-
258
- if (!supportedTargets.includes(resolvedTarget)) {
259
- console.log(chalk.red.bold('āœ— Unsupported target platform\n'));
260
- console.log(
261
- chalk.yellow(`Target '${resolvedTarget}' does not support agent execution.`)
262
- );
263
- console.log(chalk.cyan(`Supported platforms: ${supportedTargets.join(', ')}\n`));
264
- throw new Error(`Unsupported target: ${resolvedTarget}`);
265
- }
266
-
267
- // Handle Claude Code specific setup
268
- if (resolvedTarget === 'claude-code') {
269
- await setupClaudeCode(options);
270
- }
271
-
272
- // Execute command
273
- await executeCommand(resolvedTarget, prompt, options);
274
- }
275
-
276
- /**
277
- * Setup Claude Code (provider + agent selection)
278
- */
279
- async function setupClaudeCode(options: FlowOptions): Promise<void> {
280
- const { SmartConfigService } = await import('../services/smart-config-service.js');
281
- const { ConfigService } = await import('../services/config-service.js');
282
-
283
- // Check if API keys are configured
284
- if (!(await ConfigService.hasInitialSetup())) {
285
- console.log(chalk.cyan('\nšŸ”‘ First-time setup for Claude Code:\n'));
286
- await SmartConfigService.initialSetup();
287
- console.log(chalk.green('\nāœ… Claude Code setup complete!\n'));
288
- }
289
-
290
- // Select provider and agent
291
- const runtimeChoices = await SmartConfigService.selectRuntimeChoices({
292
- selectProvider: options.selectProvider,
293
- selectAgent: options.selectAgent,
294
- useDefaults: options.useDefaults,
295
- provider: options.provider,
296
- agent: options.agent,
297
- });
298
-
299
- // Setup environment
300
- await SmartConfigService.setupEnvironment(runtimeChoices.provider!);
301
-
302
- // Store selected agent
303
- options.agent = runtimeChoices.agent;
304
- }
305
-
306
- /**
307
- * Execute the target command
308
- */
309
- async function executeCommand(
310
- targetId: string,
311
- prompt: string | undefined,
312
- options: FlowOptions
313
- ): Promise<void> {
314
- const agent = options.agent || 'coder';
315
- const verbose = options.verbose || false;
316
-
317
- if (verbose || options.runOnly) {
318
- console.log(`šŸ¤– Agent: ${agent}`);
319
- console.log(`šŸŽÆ Target: ${targetId}`);
320
- if (prompt) {
321
- console.log(`šŸ’¬ Prompt: ${prompt}\n`);
322
- }
323
- }
324
-
325
- // Run the command
326
- const { runCommand } = await import('./run-command.js');
327
- await runCommand({ target: targetId, agent, prompt, verbose });
328
- }
@@ -1,92 +0,0 @@
1
- import boxen from 'boxen';
2
- import chalk from 'chalk';
3
- import gradient from 'gradient-string';
4
- import {
5
- selectAndValidateTarget,
6
- previewDryRun,
7
- installComponents,
8
- type InitOptions,
9
- } from './init-core.js';
10
-
11
- /**
12
- * Legacy init with full UI - used by setup command for backward compatibility
13
- * The flow command uses init-core functions directly for better integration
14
- */
15
- export async function runInit(options: InitOptions): Promise<void> {
16
- // Create ASCII art title
17
- const title = `
18
- ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•—ā–ˆā–ˆā•— ā–ˆā–ˆā•—ā–ˆā–ˆā•— ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā•— ā–ˆā–ˆā•—ā–ˆā–ˆā•— ā–ˆā–ˆā•— ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•—ā–ˆā–ˆā•— ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā•— ā–ˆā–ˆā•—
19
- ā–ˆā–ˆā•”ā•ā•ā•ā•ā•ā•šā–ˆā–ˆā•— ā–ˆā–ˆā•”ā•ā–ˆā–ˆā•‘ ā–ˆā–ˆā•”ā•ā•ā–ˆā–ˆā•—ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ā•šā–ˆā–ˆā•—ā–ˆā–ˆā•”ā• ā–ˆā–ˆā•”ā•ā•ā•ā•ā•ā–ˆā–ˆā•‘ ā–ˆā–ˆā•”ā•ā•ā•ā–ˆā–ˆā•—ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘
20
- ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā•šā–ˆā–ˆā–ˆā–ˆā•”ā• ā–ˆā–ˆā•‘ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•”ā•ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•‘ ā•šā–ˆā–ˆā–ˆā•”ā• ā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ā–ˆā–ˆā•‘ ā–ˆā•— ā–ˆā–ˆā•‘
21
- ā•šā•ā•ā•ā•ā–ˆā–ˆā•‘ ā•šā–ˆā–ˆā•”ā• ā–ˆā–ˆā•‘ ā–ˆā–ˆā•”ā•ā•ā•ā• ā–ˆā–ˆā•”ā•ā•ā–ˆā–ˆā•‘ ā–ˆā–ˆā•”ā–ˆā–ˆā•— ā–ˆā–ˆā•”ā•ā•ā• ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ā–ˆā–ˆā•‘ā–ˆā–ˆā–ˆā•—ā–ˆā–ˆā•‘
22
- ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•—ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ā–ˆā–ˆā•”ā• ā–ˆā–ˆā•— ā–ˆā–ˆā•‘ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•—ā•šā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•”ā•ā•šā–ˆā–ˆā–ˆā•”ā–ˆā–ˆā–ˆā•”ā•
23
- ā•šā•ā•ā•ā•ā•ā•ā• ā•šā•ā• ā•šā•ā•ā•ā•ā•ā•ā•ā•šā•ā• ā•šā•ā• ā•šā•ā•ā•šā•ā• ā•šā•ā• ā•šā•ā• ā•šā•ā•ā•ā•ā•ā•ā• ā•šā•ā•ā•ā•ā•ā• ā•šā•ā•ā•ā•šā•ā•ā•
24
- `;
25
-
26
- console.log(gradient(['cyan', 'blue'])(title));
27
- console.log(chalk.dim.cyan(' Project Initialization\n'));
28
-
29
- // Select and validate target using core function
30
- const targetId = await selectAndValidateTarget(options);
31
-
32
- // Dry run preview
33
- if (options.dryRun) {
34
- console.log(
35
- boxen(
36
- chalk.yellow('⚠ Dry Run Mode') + chalk.dim('\nNo changes will be made to your project'),
37
- {
38
- padding: 1,
39
- margin: { top: 0, bottom: 1, left: 0, right: 0 },
40
- borderStyle: 'round',
41
- borderColor: 'yellow',
42
- }
43
- )
44
- );
45
-
46
- await previewDryRun(targetId, options);
47
-
48
- console.log(
49
- '\n' +
50
- boxen(chalk.green.bold('āœ“ Dry run complete'), {
51
- padding: { top: 0, bottom: 0, left: 2, right: 2 },
52
- margin: 0,
53
- borderStyle: 'round',
54
- borderColor: 'green',
55
- }) +
56
- '\n'
57
- );
58
- return;
59
- }
60
-
61
- console.log(chalk.cyan.bold('\n━━━ Installing Core Components ━━━\n'));
62
-
63
- // Install components using core function
64
- const result = await installComponents(targetId, options);
65
-
66
- // Success summary
67
- console.log(
68
- '\n' +
69
- boxen(
70
- chalk.green.bold('āœ“ Setup complete!') +
71
- '\n\n' +
72
- chalk.dim(`Target: ${result.targetName}`) +
73
- '\n\n' +
74
- chalk.cyan('Ready to code with Sylphx Flow'),
75
- {
76
- padding: 1,
77
- margin: 0,
78
- borderStyle: 'round',
79
- borderColor: 'green',
80
- }
81
- ) +
82
- '\n'
83
- );
84
- }
85
-
86
- /**
87
- * LEGACY: init command has been integrated into the flow command.
88
- * Use `flow --init-only` instead of standalone `init` command.
89
- *
90
- * This export is kept for backward compatibility but will be removed in future versions.
91
- * The runInit() function is the core implementation used by flow command.
92
- */