@sylphx/flow 1.8.1 → 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 CHANGED
@@ -1,5 +1,84 @@
1
1
  # @sylphx/flow
2
2
 
3
+ ## 2.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - aaadcaa: Settings-based configuration and improved user experience
8
+
9
+ **New Features:**
10
+
11
+ - **Settings management**: Configure agents, rules, and output styles via `sylphx-flow settings`
12
+ - Select which agents are enabled
13
+ - Set default agent to use
14
+ - Enable/disable specific rules (core, code-standards, workspace)
15
+ - Enable/disable output styles (silent)
16
+ - **Settings-driven execution**: Flow respects your settings and only loads enabled components
17
+ - **Config files**: All settings stored in `~/.sylphx-flow/` (settings.json, flow-config.json, provider-config.json, mcp-config.json)
18
+ - **Git skip-worktree integration**: Flow automatically hides `.claude/` and `.opencode/` changes from git
19
+ - Uses `git update-index --skip-worktree` to hide Flow's temporary modifications
20
+ - Prevents LLM from seeing or committing Flow's settings changes
21
+ - Automatically restores git tracking after execution
22
+ - Works seamlessly with version-controlled settings
23
+
24
+ **Breaking Changes:**
25
+
26
+ - Removed `--quick` flag - no longer needed
27
+ - Removed first-run setup wizard - configs are created automatically with sensible defaults
28
+ - Agent loading now respects enabled rules and output styles from settings
29
+
30
+ **Improvements:**
31
+
32
+ - Config files are automatically initialized on first use with default values
33
+ - Provider selection happens inline when needed (if set to "ask-every-time")
34
+ - Fixed Ctrl+C handling to ensure settings are restored immediately
35
+ - Simplified CLI options - only `--merge` flag for attach strategy
36
+ - Default agent can be set in settings (falls back to 'coder' if not set)
37
+
38
+ **Ctrl+C Fix:**
39
+ When users press Ctrl+C during interactive prompts, the application now:
40
+
41
+ - Catches the cancellation gracefully
42
+ - Runs cleanup (restores backed-up settings)
43
+ - Shows a friendly cancellation message
44
+ - Exits cleanly
45
+
46
+ Previously, pressing Ctrl+C would exit immediately without restoring settings, requiring recovery on the next run.
47
+
48
+ ### Minor Changes
49
+
50
+ - 9fa65d4: Add automatic upgrade detection with smart package manager support
51
+
52
+ - Auto-detect updates on startup with non-intrusive notifications
53
+ - Enhanced `upgrade` command with `--auto` flag for automatic installation
54
+ - Smart package manager detection (npm, bun, pnpm, yarn)
55
+ - Version checking against npm registry for both Flow and target platforms
56
+ - Package-manager-specific upgrade commands in notifications
57
+ - New UPGRADE.md documentation with package manager support
58
+ - Silent background checks that don't block execution
59
+ - Support for both interactive and automatic upgrade flows
60
+ - Comprehensive test coverage for package manager detection
61
+
62
+ ## 1.8.2
63
+
64
+ ### Patch Changes
65
+
66
+ - 9059450: Enhance Next Actions section with suggestions when no clear next step
67
+
68
+ Updated completion report structure to include proactive suggestions in Next Actions section:
69
+
70
+ - Remaining work (existing functionality)
71
+ - Suggestions when no clear next step (new)
72
+
73
+ Benefits:
74
+
75
+ - Guides user on potential improvements
76
+ - Provides proactive recommendations
77
+ - Helps prevent "what's next?" moments
78
+ - Encourages continuous iteration
79
+
80
+ Example updated to show suggestion format: "Consider adding rate limiting, implement refresh token rotation, add logging for security events"
81
+
3
82
  ## 1.8.1
4
83
 
5
84
  ### Patch Changes
package/UPGRADE.md ADDED
@@ -0,0 +1,140 @@
1
+ # Upgrade Guide
2
+
3
+ Sylphx Flow includes built-in upgrade detection and automatic update capabilities with **smart package manager detection**.
4
+
5
+ ## Auto-Detection on Startup
6
+
7
+ Every time you run Sylphx Flow, it automatically checks for available updates in the background. If an update is available, you'll see a notification like:
8
+
9
+ ```
10
+ 📦 Sylphx Flow update available: 1.8.1 → 1.9.0
11
+ Quick upgrade: sylphx-flow upgrade --auto
12
+ Or run: bun install -g @sylphx/flow@latest
13
+ ```
14
+
15
+ The upgrade command is automatically tailored to your detected package manager (npm, bun, pnpm, or yarn).
16
+
17
+ This check is non-intrusive and won't block your workflow. Use `--quick` mode to skip the check entirely.
18
+
19
+ ## Manual Upgrade Check
20
+
21
+ Check for available updates without installing:
22
+
23
+ ```bash
24
+ sylphx-flow upgrade --check
25
+ ```
26
+
27
+ ## Upgrade Commands
28
+
29
+ ### Upgrade Sylphx Flow
30
+
31
+ Upgrade to the latest version:
32
+
33
+ ```bash
34
+ # Interactive upgrade (manual installation required)
35
+ sylphx-flow upgrade
36
+
37
+ # Automatic installation via npm
38
+ sylphx-flow upgrade --auto
39
+ ```
40
+
41
+ ### Upgrade Target Platform
42
+
43
+ Upgrade Claude Code or other target platforms:
44
+
45
+ ```bash
46
+ # Interactive upgrade
47
+ sylphx-flow upgrade --target
48
+
49
+ # Automatic installation via npm
50
+ sylphx-flow upgrade --target --auto
51
+ ```
52
+
53
+ ### Combined Upgrade
54
+
55
+ Upgrade both Sylphx Flow and target platform:
56
+
57
+ ```bash
58
+ sylphx-flow upgrade --target --auto
59
+ ```
60
+
61
+ ## Options
62
+
63
+ - `--check` - Only check for updates, don't install
64
+ - `--auto` - Automatically install updates via npm (no manual steps)
65
+ - `--target` - Include target platform (Claude Code/OpenCode) upgrade
66
+ - `--verbose` - Show detailed installation output
67
+
68
+ ## Package Manager Detection
69
+
70
+ Sylphx Flow automatically detects which package manager you're using:
71
+
72
+ 1. **From Environment** (`npm_config_user_agent`): Most reliable when running as npm script
73
+ 2. **From Lock Files**: Checks for `bun.lock`, `pnpm-lock.yaml`, `yarn.lock`, or `package-lock.json`
74
+ 3. **Default**: Falls back to `npm` if no detection method works
75
+
76
+ **Priority Order**: bun > pnpm > yarn > npm
77
+
78
+ ### Supported Package Managers
79
+
80
+ | Package Manager | Global Install Command |
81
+ |----------------|------------------------|
82
+ | npm | `npm install -g @sylphx/flow@latest` |
83
+ | bun | `bun install -g @sylphx/flow@latest` |
84
+ | pnpm | `pnpm install -g @sylphx/flow@latest` |
85
+ | yarn | `yarn global add @sylphx/flow@latest` |
86
+
87
+ ## How It Works
88
+
89
+ 1. **Version Detection**: Checks npm registry for latest published versions
90
+ 2. **Comparison**: Compares installed version with latest available
91
+ 3. **Package Manager Detection**: Automatically detects npm/bun/pnpm/yarn
92
+ 4. **Notification**: Shows update availability with package-manager-specific command
93
+ 5. **Installation**:
94
+ - Without `--auto`: Shows manual install command for your package manager
95
+ - With `--auto`: Runs the appropriate install command automatically
96
+
97
+ ## Disabling Auto-Check
98
+
99
+ Use `--quick` mode to skip automatic update checks:
100
+
101
+ ```bash
102
+ sylphx-flow --quick "your prompt here"
103
+ ```
104
+
105
+ ## Troubleshooting
106
+
107
+ ### Auto-Install Fails
108
+
109
+ If `--auto` installation fails, the error message will show the exact command to run manually. The command is tailored to your package manager:
110
+
111
+ ```bash
112
+ # Example for bun users
113
+ bun install -g @sylphx/flow@latest
114
+
115
+ # Example for npm users
116
+ npm install -g @sylphx/flow@latest
117
+ ```
118
+
119
+ ### Version Mismatch
120
+
121
+ If you see version mismatches after upgrade, try:
122
+
123
+ ```bash
124
+ # Re-sync components with latest templates
125
+ sylphx-flow --sync
126
+ ```
127
+
128
+ ### Offline Mode
129
+
130
+ Update checks require internet connection. If offline, checks will fail silently and won't block execution.
131
+
132
+ ## Version Compatibility
133
+
134
+ Sylphx Flow follows semantic versioning:
135
+
136
+ - **Patch** (1.8.x): Bug fixes, safe to upgrade
137
+ - **Minor** (1.x.0): New features, backward compatible
138
+ - **Major** (x.0.0): Breaking changes, check migration guide
139
+
140
+ Always check CHANGELOG.md for breaking changes before upgrading major versions.
@@ -68,6 +68,7 @@ Report what was accomplished. Structured, comprehensive, reviewable.
68
68
 
69
69
  ## Next Actions
70
70
  - [ ] [Remaining work]
71
+ - [Suggestions when no clear next step]
71
72
  ```
72
73
 
73
74
  #### 🔵 Tier 3: Major Changes Only
@@ -138,6 +139,9 @@ Refactored authentication system to use JWT tokens instead of sessions.
138
139
  - Added: jsonwebtoken@9.0.0 (JWT signing/verification)
139
140
  - Removed: express-session@1.17.0 (replaced by JWT)
140
141
 
142
+ ## Next Actions
143
+ - Suggestions: Consider adding rate limiting, implement refresh token rotation, add logging for security events
144
+
141
145
  ## Migration
142
146
  Users need to:
143
147
  1. Update client to store tokens: `localStorage.setItem('token', response.token)`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sylphx/flow",
3
- "version": "1.8.1",
3
+ "version": "2.0.0",
4
4
  "description": "AI-powered development workflow automation with autonomous loop mode and smart configuration",
5
5
  "type": "module",
6
6
  "bin": {
@@ -43,6 +43,7 @@
43
43
  "README.md",
44
44
  "CHANGELOG.md",
45
45
  "LOOP_MODE.md",
46
+ "UPGRADE.md",
46
47
  "package.json"
47
48
  ],
48
49
  "keywords": [
@@ -0,0 +1,278 @@
1
+ /**
2
+ * Execution Logic for Flow Command (V2 - Attach Mode)
3
+ * New execution flow with attach-mode lifecycle
4
+ */
5
+
6
+ import chalk from 'chalk';
7
+ import inquirer from 'inquirer';
8
+ import { FlowExecutor } from '../../core/flow-executor.js';
9
+ import { targetManager } from '../../core/target-manager.js';
10
+ import { UpgradeManager } from '../../core/upgrade-manager.js';
11
+ import { showWelcome } from '../../utils/display/banner.js';
12
+ import { loadAgentContent, extractAgentInstructions } from '../run-command.js';
13
+ import { CLIError } from '../../utils/error-handler.js';
14
+ import type { RunCommandOptions } from '../../types.js';
15
+ import type { FlowOptions } from './types.js';
16
+ import { resolvePrompt } from './prompt.js';
17
+ import { GlobalConfigService } from '../../services/global-config.js';
18
+ import { UserCancelledError } from '../../utils/errors.js';
19
+
20
+ /**
21
+ * Select and configure provider for Claude Code
22
+ */
23
+ async function selectProvider(
24
+ configService: GlobalConfigService
25
+ ): Promise<void> {
26
+ try {
27
+ const providerConfig = await configService.loadProviderConfig();
28
+ const defaultProvider = providerConfig.claudeCode.defaultProvider;
29
+
30
+ // If not "ask-every-time", use the default provider
31
+ if (defaultProvider !== 'ask-every-time') {
32
+ // Configure environment variables for the selected provider
33
+ if (defaultProvider === 'kimi' || defaultProvider === 'zai') {
34
+ const provider = providerConfig.claudeCode.providers[defaultProvider];
35
+ if (provider?.apiKey) {
36
+ if (defaultProvider === 'kimi') {
37
+ process.env.ANTHROPIC_BASE_URL = 'https://api.moonshot.cn/v1';
38
+ process.env.ANTHROPIC_API_KEY = provider.apiKey;
39
+ } else if (defaultProvider === 'zai') {
40
+ process.env.ANTHROPIC_BASE_URL = 'https://api.z.ai/v1';
41
+ process.env.ANTHROPIC_API_KEY = provider.apiKey;
42
+ }
43
+ }
44
+ }
45
+ return;
46
+ }
47
+
48
+ // Ask user which provider to use for this session
49
+ const { selectedProvider } = await inquirer.prompt([
50
+ {
51
+ type: 'list',
52
+ name: 'selectedProvider',
53
+ message: 'Select provider for this session:',
54
+ choices: [
55
+ { name: 'Default (Claude Code built-in)', value: 'default' },
56
+ { name: 'Kimi', value: 'kimi' },
57
+ { name: 'Z.ai', value: 'zai' },
58
+ ],
59
+ default: 'default',
60
+ },
61
+ ]);
62
+
63
+ // Configure environment variables based on selection
64
+ if (selectedProvider === 'kimi' || selectedProvider === 'zai') {
65
+ const provider = providerConfig.claudeCode.providers[selectedProvider];
66
+
67
+ if (!provider?.apiKey) {
68
+ console.log(chalk.yellow('⚠ API key not configured. Use: sylphx-flow settings\n'));
69
+ return;
70
+ }
71
+
72
+ if (selectedProvider === 'kimi') {
73
+ process.env.ANTHROPIC_BASE_URL = 'https://api.moonshot.cn/v1';
74
+ process.env.ANTHROPIC_API_KEY = provider.apiKey;
75
+ console.log(chalk.green('✓ Using Kimi provider\n'));
76
+ } else if (selectedProvider === 'zai') {
77
+ process.env.ANTHROPIC_BASE_URL = 'https://api.z.ai/v1';
78
+ process.env.ANTHROPIC_API_KEY = provider.apiKey;
79
+ console.log(chalk.green('✓ Using Z.ai provider\n'));
80
+ }
81
+ } else {
82
+ console.log(chalk.green('✓ Using default Claude Code provider\n'));
83
+ }
84
+ } catch (error: any) {
85
+ // Handle user cancellation (Ctrl+C)
86
+ if (error.name === 'ExitPromptError' || error.message?.includes('force closed')) {
87
+ throw new UserCancelledError('Provider selection cancelled');
88
+ }
89
+ throw error;
90
+ }
91
+ }
92
+
93
+ /**
94
+ * Execute command using target's executeCommand method
95
+ */
96
+ async function executeTargetCommand(
97
+ targetId: string,
98
+ systemPrompt: string,
99
+ userPrompt: string,
100
+ options: RunCommandOptions
101
+ ): Promise<void> {
102
+ const targetOption = targetManager.getTarget(targetId);
103
+
104
+ if (targetOption._tag === 'None') {
105
+ throw new CLIError(`Target not found: ${targetId}`, 'TARGET_NOT_FOUND');
106
+ }
107
+
108
+ const target = targetOption.value;
109
+
110
+ if (!target.isImplemented || !target.executeCommand) {
111
+ throw new CLIError(
112
+ `Target '${targetId}' does not support command execution`,
113
+ 'EXECUTION_NOT_SUPPORTED'
114
+ );
115
+ }
116
+
117
+ return target.executeCommand(systemPrompt, userPrompt, options);
118
+ }
119
+
120
+ /**
121
+ * Main flow execution with attach mode (V2)
122
+ */
123
+ export async function executeFlowV2(
124
+ prompt: string | undefined,
125
+ options: FlowOptions
126
+ ): Promise<void> {
127
+ const projectPath = process.cwd();
128
+
129
+ // Show welcome banner
130
+ showWelcome();
131
+
132
+ // Mode info
133
+ if (options.merge) {
134
+ console.log(chalk.cyan('🔗 Merge mode: Flow settings will be merged with your existing settings'));
135
+ console.log(chalk.dim(' Settings will be restored after execution\n'));
136
+ } else {
137
+ console.log(chalk.yellow('🔄 Replace mode (default): All settings will use Flow configuration'));
138
+ console.log(chalk.dim(' Use --merge to keep your existing settings\n'));
139
+ }
140
+
141
+ // Initialize config service
142
+ const configService = new GlobalConfigService();
143
+ await configService.initialize();
144
+
145
+ // Create executor
146
+ const executor = new FlowExecutor();
147
+ const projectManager = executor.getProjectManager();
148
+
149
+ // Step 1: Check for upgrades (non-intrusive)
150
+ const upgradeManager = new UpgradeManager();
151
+ const updates = await upgradeManager.checkUpdates();
152
+
153
+ if (updates.flowUpdate || updates.targetUpdate) {
154
+ console.log(
155
+ chalk.yellow('📦 Updates available! Run: sylphx-flow upgrade --auto\n')
156
+ );
157
+ }
158
+
159
+ // Step 2: Execute attach mode lifecycle
160
+ try {
161
+ // Attach Flow environment (backup → attach → register cleanup)
162
+ await executor.execute(projectPath, {
163
+ verbose: options.verbose,
164
+ skipBackup: false,
165
+ skipSecrets: false,
166
+ merge: options.merge || false,
167
+ });
168
+
169
+ // Step 3: Detect target and load agent
170
+ const projectHash = projectManager.getProjectHash(projectPath);
171
+ const target = await projectManager.detectTarget(projectPath);
172
+
173
+ // Map target to targetManager's target IDs
174
+ const targetId = target === 'claude-code' ? 'claude-code' : 'opencode';
175
+
176
+ // Step 3.5: Provider selection (Claude Code only)
177
+ if (targetId === 'claude-code') {
178
+ await selectProvider(configService);
179
+ }
180
+
181
+ // Step 3.6: Load Flow settings and determine agent to use
182
+ const settings = await configService.loadSettings();
183
+ const flowConfig = await configService.loadFlowConfig();
184
+
185
+ // Determine which agent to use (CLI option > settings default > 'coder')
186
+ const agent = options.agent || settings.defaultAgent || 'coder';
187
+
188
+ // Check if agent is enabled
189
+ if (!flowConfig.agents[agent]?.enabled) {
190
+ console.log(chalk.yellow(`⚠️ Agent '${agent}' is not enabled in settings`));
191
+ console.log(chalk.yellow(` Enable it with: sylphx-flow settings`));
192
+ console.log(chalk.yellow(` Using 'coder' agent instead\n`));
193
+ // Fallback to first enabled agent or coder
194
+ const enabledAgents = await configService.getEnabledAgents();
195
+ const fallbackAgent = enabledAgents.length > 0 ? enabledAgents[0] : 'coder';
196
+ options.agent = fallbackAgent;
197
+ }
198
+
199
+ console.log(chalk.cyan(`🤖 Running agent: ${agent}\n`));
200
+
201
+ // Load enabled rules and output styles from config
202
+ const enabledRules = await configService.getEnabledRules();
203
+ const enabledOutputStyles = await configService.getEnabledOutputStyles();
204
+
205
+ console.log(chalk.dim(` Enabled rules: ${enabledRules.join(', ')}`));
206
+ console.log(chalk.dim(` Enabled output styles: ${enabledOutputStyles.join(', ')}\n`));
207
+
208
+ // Load agent content with only enabled rules and styles
209
+ const agentContent = await loadAgentContent(
210
+ agent,
211
+ options.agentFile,
212
+ enabledRules,
213
+ enabledOutputStyles
214
+ );
215
+ const agentInstructions = extractAgentInstructions(agentContent);
216
+
217
+ const systemPrompt = `AGENT INSTRUCTIONS:\n${agentInstructions}`;
218
+
219
+ const userPrompt = prompt?.trim() || '';
220
+
221
+ // Prepare run options
222
+ const runOptions: RunCommandOptions = {
223
+ target: targetId,
224
+ verbose: options.verbose || false,
225
+ dryRun: options.dryRun || false,
226
+ agent,
227
+ agentFile: options.agentFile,
228
+ prompt,
229
+ print: options.print,
230
+ continue: options.continue,
231
+ };
232
+
233
+ // Step 4: Execute command
234
+ await executeTargetCommand(targetId, systemPrompt, userPrompt, runOptions);
235
+
236
+ // Step 5: Cleanup (restore environment)
237
+ await executor.cleanup(projectPath);
238
+
239
+ console.log(chalk.green('✓ Session complete\n'));
240
+ } catch (error) {
241
+ // Handle user cancellation gracefully
242
+ if (error instanceof UserCancelledError) {
243
+ console.log(chalk.yellow('\n⚠️ Operation cancelled by user'));
244
+ try {
245
+ await executor.cleanup(projectPath);
246
+ console.log(chalk.green(' ✓ Settings restored\n'));
247
+ } catch (cleanupError) {
248
+ console.error(chalk.red(' ✗ Cleanup failed:'), cleanupError);
249
+ }
250
+ process.exit(0);
251
+ }
252
+
253
+ console.error(chalk.red.bold('\n✗ Execution failed:'), error);
254
+
255
+ // Ensure cleanup even on error
256
+ try {
257
+ await executor.cleanup(projectPath);
258
+ } catch (cleanupError) {
259
+ console.error(chalk.red('✗ Cleanup failed:'), cleanupError);
260
+ }
261
+
262
+ throw error;
263
+ }
264
+ }
265
+
266
+ /**
267
+ * Main flow execution entry point
268
+ */
269
+ export async function executeFlow(
270
+ prompt: string | undefined,
271
+ options: FlowOptions
272
+ ): Promise<void> {
273
+ // Resolve prompt (handle file input)
274
+ const resolvedPrompt = await resolvePrompt(prompt);
275
+
276
+ // Use V2 attach mode execution
277
+ await executeFlowV2(resolvedPrompt, options);
278
+ }
@@ -124,28 +124,11 @@ export async function executeFlowOnce(prompt: string | undefined, options: FlowO
124
124
  await showStatus(state);
125
125
  }
126
126
 
127
- // Step 1: Check for upgrades
127
+ // Step 1: Check for upgrades (non-intrusive notification)
128
128
  if (!options.quick) {
129
129
  await checkUpgrades(state, options);
130
130
  }
131
131
 
132
- // Step 1: Upgrade (if requested)
133
- if (options.upgrade && state.outdated && state.latestVersion) {
134
- console.log(chalk.cyan.bold('━━━ 📦 Upgrading Flow\n'));
135
- await upgradeManager.upgradeFlow(state);
136
- console.log(chalk.green('✓ Upgrade complete\n'));
137
- // Re-detect after upgrade
138
- state.version = state.latestVersion;
139
- state.outdated = false;
140
- }
141
-
142
- // Step 2: Upgrade target (if requested)
143
- if (options.upgradeTarget && state.target) {
144
- console.log(chalk.cyan.bold(`━━━ 🎯 Upgrading ${state.target}\n`));
145
- await upgradeManager.upgradeTarget(state);
146
- console.log(chalk.green('✓ Target upgrade complete\n'));
147
- }
148
-
149
132
  // Step 2.5: Check component integrity (only if we have valid state)
150
133
  await checkComponentIntegrity(state, options);
151
134
 
@@ -26,14 +26,15 @@ export interface FlowOptions {
26
26
  // Smart configuration options
27
27
  selectProvider?: boolean;
28
28
  selectAgent?: boolean;
29
- useDefaults?: boolean;
30
29
  provider?: string;
31
- quick?: boolean;
32
30
 
33
31
  // Execution modes
34
32
  print?: boolean;
35
33
  continue?: boolean;
36
34
 
35
+ // Attach strategy
36
+ merge?: boolean; // Merge with user settings instead of replacing (default: replace)
37
+
37
38
  // Loop mode
38
39
  loop?: number;
39
40
  maxRuns?: number;