claude-flow 2.0.0-alpha.32 ā 2.0.0-alpha.34
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/README.md +1 -2
- package/package.json +1 -1
- package/src/cli/formatter.ts +1 -1
- package/src/cli/simple-commands/hive-mind/db-optimizer.js +23 -9
- package/src/cli/simple-commands/hive-mind-wizard.js +1 -1
- package/src/cli/simple-commands/hive-mind.js +81 -43
- package/src/cli/simple-commands/init/index.js +3 -3
- package/src/cli/simple-commands/init/templates/claude-flow-universal +11 -3
- package/src/cli/ui/fallback-handler.ts +2 -0
- package/src/cli/utils/environment-detector.ts +33 -0
- package/src/cli/utils/interactive-detector.js +3 -0
- package/src/cli/utils/safe-interactive.js +142 -0
package/README.md
CHANGED
|
@@ -143,7 +143,6 @@ npx claude-flow hooks session-end --generate-summary --persist-state
|
|
|
143
143
|
```
|
|
144
144
|
|
|
145
145
|
---
|
|
146
|
-
|
|
147
146
|
## š **Revolutionary Hive-Mind Intelligence**
|
|
148
147
|
|
|
149
148
|
### **Queen-Led AI Coordination**
|
|
@@ -827,4 +826,4 @@ npx --y claude-flow@alpha init --force
|
|
|
827
826
|
|
|
828
827
|
*v2.0.0 Alpha - The Future of AI Orchestration*
|
|
829
828
|
|
|
830
|
-
</div>
|
|
829
|
+
</div>
|
package/package.json
CHANGED
package/src/cli/formatter.ts
CHANGED
|
@@ -256,7 +256,7 @@ export function displayVersion(version: string, buildDate: string): void {
|
|
|
256
256
|
chalk.white(' ⢠MCP Server'),
|
|
257
257
|
chalk.white(' ⢠Task Coordination'),
|
|
258
258
|
'',
|
|
259
|
-
chalk.blue('Homepage: ') + chalk.underline('https://github.com/
|
|
259
|
+
chalk.blue('Homepage: ') + chalk.underline('https://github.com/ruvnet/claude-flow'),
|
|
260
260
|
];
|
|
261
261
|
|
|
262
262
|
console.log(info.join('\n'));
|
|
@@ -583,16 +583,30 @@ export async function performMaintenance(dbPath, options = {}) {
|
|
|
583
583
|
|
|
584
584
|
// Clean up old memory entries
|
|
585
585
|
if (options.cleanMemory) {
|
|
586
|
-
|
|
587
|
-
const
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
DELETE FROM collective_memory
|
|
592
|
-
WHERE last_accessed < ? AND access_count < 5
|
|
593
|
-
`).run(cutoffDate.toISOString());
|
|
586
|
+
// Check if collective_memory table exists
|
|
587
|
+
const hasMemoryTable = db.prepare(`
|
|
588
|
+
SELECT name FROM sqlite_master
|
|
589
|
+
WHERE type='table' AND name='collective_memory'
|
|
590
|
+
`).get();
|
|
594
591
|
|
|
595
|
-
|
|
592
|
+
if (hasMemoryTable) {
|
|
593
|
+
spinner.text = 'Cleaning old memory entries...';
|
|
594
|
+
const cutoffDate = new Date();
|
|
595
|
+
cutoffDate.setDate(cutoffDate.getDate() - (options.memoryRetentionDays || 30));
|
|
596
|
+
|
|
597
|
+
try {
|
|
598
|
+
const result = db.prepare(`
|
|
599
|
+
DELETE FROM collective_memory
|
|
600
|
+
WHERE accessed_at < ? AND access_count < 5
|
|
601
|
+
`).run(cutoffDate.toISOString());
|
|
602
|
+
|
|
603
|
+
console.log(chalk.green(`ā Removed ${result.changes} old memory entries`));
|
|
604
|
+
} catch (error) {
|
|
605
|
+
console.warn(chalk.yellow(`ā Could not clean memory entries: ${error.message}`));
|
|
606
|
+
}
|
|
607
|
+
} else {
|
|
608
|
+
console.log(chalk.yellow('ā collective_memory table not found, skipping memory cleanup'));
|
|
609
|
+
}
|
|
596
610
|
}
|
|
597
611
|
|
|
598
612
|
// Archive completed tasks
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const fs = require('fs');
|
|
4
|
-
const
|
|
4
|
+
const Database = require('better-sqlite3');
|
|
5
5
|
|
|
6
6
|
// Interactive Wizard Implementation
|
|
7
7
|
async function runInteractiveWizard() {
|
|
@@ -13,6 +13,7 @@ import chalk from 'chalk';
|
|
|
13
13
|
import ora from 'ora';
|
|
14
14
|
import { args, cwd, exit, writeTextFile, readTextFile, mkdirAsync } from '../node-compat.js';
|
|
15
15
|
import { isInteractive, isRawModeSupported, warnNonInteractive, checkNonInteractiveAuth } from '../utils/interactive-detector.js';
|
|
16
|
+
import { safeInteractive, nonInteractiveProgress, nonInteractiveSelect } from '../utils/safe-interactive.js';
|
|
16
17
|
|
|
17
18
|
// Import SQLite for persistence
|
|
18
19
|
import Database from 'better-sqlite3';
|
|
@@ -222,50 +223,87 @@ async function initHiveMind(flags) {
|
|
|
222
223
|
/**
|
|
223
224
|
* Interactive wizard for hive mind operations
|
|
224
225
|
*/
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
226
|
+
// Wrapped wizard function that handles non-interactive environments
|
|
227
|
+
const hiveMindWizard = safeInteractive(
|
|
228
|
+
// Interactive version
|
|
229
|
+
async function(flags = {}) {
|
|
230
|
+
console.log(chalk.yellow('\nš§ Hive Mind Interactive Wizard\n'));
|
|
231
|
+
|
|
232
|
+
const { action } = await inquirer.prompt([
|
|
233
|
+
{
|
|
234
|
+
type: 'list',
|
|
235
|
+
name: 'action',
|
|
236
|
+
message: 'What would you like to do?',
|
|
237
|
+
choices: [
|
|
238
|
+
{ name: 'š Create new swarm', value: 'spawn' },
|
|
239
|
+
{ name: 'š View swarm status', value: 'status' },
|
|
240
|
+
{ name: 'š§ Manage collective memory', value: 'memory' },
|
|
241
|
+
{ name: 'š¤ View consensus decisions', value: 'consensus' },
|
|
242
|
+
{ name: 'š Performance metrics', value: 'metrics' },
|
|
243
|
+
{ name: 'š§ Configure hive mind', value: 'config' },
|
|
244
|
+
{ name: 'ā Exit', value: 'exit' }
|
|
245
|
+
]
|
|
246
|
+
}
|
|
247
|
+
]);
|
|
248
|
+
|
|
249
|
+
switch (action) {
|
|
250
|
+
case 'spawn':
|
|
251
|
+
await spawnSwarmWizard();
|
|
252
|
+
break;
|
|
253
|
+
case 'status':
|
|
254
|
+
await showStatus({});
|
|
255
|
+
break;
|
|
256
|
+
case 'memory':
|
|
257
|
+
await manageMemoryWizard();
|
|
258
|
+
break;
|
|
259
|
+
case 'consensus':
|
|
260
|
+
await showConsensus({});
|
|
261
|
+
break;
|
|
262
|
+
case 'metrics':
|
|
263
|
+
await showMetrics({});
|
|
264
|
+
break;
|
|
265
|
+
case 'config':
|
|
266
|
+
await configureWizard();
|
|
267
|
+
break;
|
|
268
|
+
case 'exit':
|
|
269
|
+
console.log(chalk.gray('Exiting wizard...'));
|
|
270
|
+
break;
|
|
242
271
|
}
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
272
|
+
},
|
|
273
|
+
// Non-interactive fallback
|
|
274
|
+
async function(flags = {}) {
|
|
275
|
+
console.log(chalk.yellow('\nš§ Hive Mind - Non-Interactive Mode\n'));
|
|
276
|
+
|
|
277
|
+
// Default to creating a swarm with sensible defaults
|
|
278
|
+
console.log(chalk.cyan('Creating new swarm with default settings...'));
|
|
279
|
+
console.log(chalk.gray('Use command-line flags to customize:'));
|
|
280
|
+
console.log(chalk.gray(' --objective "Your task" Set swarm objective'));
|
|
281
|
+
console.log(chalk.gray(' --queen-type strategic Set queen type'));
|
|
282
|
+
console.log(chalk.gray(' --max-workers 8 Set worker count'));
|
|
283
|
+
console.log();
|
|
284
|
+
|
|
285
|
+
const objective = flags.objective || 'General task coordination';
|
|
286
|
+
const config = {
|
|
287
|
+
name: flags.name || `swarm-${Date.now()}`,
|
|
288
|
+
queenType: flags.queenType || flags['queen-type'] || 'strategic',
|
|
289
|
+
maxWorkers: parseInt(flags.maxWorkers || flags['max-workers'] || '8'),
|
|
290
|
+
consensusAlgorithm: flags.consensus || 'majority',
|
|
291
|
+
autoScale: flags.autoScale || flags['auto-scale'] || false,
|
|
292
|
+
encryption: flags.encryption || false
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
await spawnSwarm([objective], {
|
|
296
|
+
...flags,
|
|
297
|
+
name: config.name,
|
|
298
|
+
queenType: config.queenType,
|
|
299
|
+
maxWorkers: config.maxWorkers,
|
|
300
|
+
consensusAlgorithm: config.consensusAlgorithm,
|
|
301
|
+
autoScale: config.autoScale,
|
|
302
|
+
encryption: config.encryption,
|
|
303
|
+
nonInteractive: true
|
|
304
|
+
});
|
|
267
305
|
}
|
|
268
|
-
|
|
306
|
+
);
|
|
269
307
|
|
|
270
308
|
/**
|
|
271
309
|
* Spawn swarm wizard
|
|
@@ -1179,7 +1217,7 @@ export async function hiveMindCommand(args, flags) {
|
|
|
1179
1217
|
break;
|
|
1180
1218
|
|
|
1181
1219
|
case 'wizard':
|
|
1182
|
-
await hiveMindWizard();
|
|
1220
|
+
await hiveMindWizard(flags);
|
|
1183
1221
|
break;
|
|
1184
1222
|
|
|
1185
1223
|
case 'help':
|
|
@@ -506,7 +506,7 @@ export async function initCommand(subArgs, flags) {
|
|
|
506
506
|
}
|
|
507
507
|
} else if (!initDryRun && !isClaudeCodeInstalled()) {
|
|
508
508
|
console.log('\nā ļø Claude Code CLI not detected!');
|
|
509
|
-
console.log(' š„ Install with: npm install -g @
|
|
509
|
+
console.log(' š„ Install with: npm install -g @anthropic-ai/claude-code');
|
|
510
510
|
console.log(' š Then add MCP servers manually with:');
|
|
511
511
|
console.log(' claude mcp add claude-flow claude-flow mcp start');
|
|
512
512
|
console.log(' claude mcp add ruv-swarm npx ruv-swarm mcp start');
|
|
@@ -1147,7 +1147,7 @@ ${commands.map(cmd => `- [${cmd}](./${cmd}.md)`).join('\n')}
|
|
|
1147
1147
|
} else if (!dryRun && !isClaudeCodeInstalled()) {
|
|
1148
1148
|
console.log('\nā ļø Claude Code CLI not detected!');
|
|
1149
1149
|
console.log('\n š„ To install Claude Code:');
|
|
1150
|
-
console.log(' npm install -g @
|
|
1150
|
+
console.log(' npm install -g @anthropic-ai/claude-code');
|
|
1151
1151
|
console.log('\n š After installing, add MCP servers:');
|
|
1152
1152
|
console.log(' claude mcp add claude-flow claude-flow mcp start');
|
|
1153
1153
|
console.log(' claude mcp add ruv-swarm npx ruv-swarm mcp start');
|
|
@@ -1161,7 +1161,7 @@ ${commands.map(cmd => `- [${cmd}](./${cmd}.md)`).join('\n')}
|
|
|
1161
1161
|
console.log('2. Start a swarm: npx claude-flow swarm init');
|
|
1162
1162
|
console.log('3. Use MCP tools in Claude Code for enhanced coordination');
|
|
1163
1163
|
} else {
|
|
1164
|
-
console.log('1. Install Claude Code: npm install -g @
|
|
1164
|
+
console.log('1. Install Claude Code: npm install -g @anthropic-ai/claude-code');
|
|
1165
1165
|
console.log('2. Add MCP servers (see instructions above)');
|
|
1166
1166
|
console.log('3. View available commands: ls .claude/commands/');
|
|
1167
1167
|
console.log('4. Start a swarm: npx claude-flow swarm init');
|
|
@@ -11,12 +11,20 @@
|
|
|
11
11
|
const { resolve } = await import('path');
|
|
12
12
|
const { fileURLToPath } = await import('url');
|
|
13
13
|
|
|
14
|
+
// Detect if we're running in ES module context
|
|
15
|
+
let __dirname;
|
|
14
16
|
try {
|
|
15
|
-
//
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
// Check if import.meta is available (ES modules)
|
|
18
|
+
if (typeof import.meta !== 'undefined' && import.meta.url) {
|
|
19
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
20
|
+
__dirname = resolve(__filename, '..');
|
|
21
|
+
} else {
|
|
22
|
+
// Fallback for CommonJS
|
|
23
|
+
__dirname = process.cwd();
|
|
24
|
+
}
|
|
18
25
|
} catch {
|
|
19
26
|
// Fallback for CommonJS
|
|
27
|
+
__dirname = process.cwd();
|
|
20
28
|
}
|
|
21
29
|
|
|
22
30
|
// Try multiple strategies to find claude-flow
|
|
@@ -36,6 +36,8 @@ export async function handleRawModeError(
|
|
|
36
36
|
console.log();
|
|
37
37
|
console.log(chalk.cyan('Common causes:'));
|
|
38
38
|
console.log(chalk.gray('⢠VS Code integrated terminal'));
|
|
39
|
+
console.log(chalk.gray('⢠WSL (Windows Subsystem for Linux)'));
|
|
40
|
+
console.log(chalk.gray('⢠Native Windows terminals'));
|
|
39
41
|
console.log(chalk.gray('⢠CI/CD environments'));
|
|
40
42
|
console.log(chalk.gray('⢠Docker containers'));
|
|
41
43
|
console.log(chalk.gray('⢠SSH sessions without TTY'));
|
|
@@ -14,6 +14,8 @@ export interface ExecutionEnvironment {
|
|
|
14
14
|
isSSH: boolean;
|
|
15
15
|
isGitBash: boolean;
|
|
16
16
|
isWindowsTerminal: boolean;
|
|
17
|
+
isWSL: boolean;
|
|
18
|
+
isWindows: boolean;
|
|
17
19
|
supportsRawMode: boolean;
|
|
18
20
|
supportsColor: boolean;
|
|
19
21
|
terminalType: string;
|
|
@@ -40,6 +42,8 @@ export function detectExecutionEnvironment(options: EnvironmentOptions = {}): Ex
|
|
|
40
42
|
isSSH: false,
|
|
41
43
|
isGitBash: false,
|
|
42
44
|
isWindowsTerminal: false,
|
|
45
|
+
isWSL: false,
|
|
46
|
+
isWindows: false,
|
|
43
47
|
supportsRawMode: false,
|
|
44
48
|
supportsColor: true,
|
|
45
49
|
terminalType: 'unknown',
|
|
@@ -85,6 +89,16 @@ export function detectExecutionEnvironment(options: EnvironmentOptions = {}): Ex
|
|
|
85
89
|
// Windows Terminal detection
|
|
86
90
|
env.isWindowsTerminal = Boolean(process.env.WT_SESSION);
|
|
87
91
|
|
|
92
|
+
// Windows detection
|
|
93
|
+
env.isWindows = process.platform === 'win32';
|
|
94
|
+
|
|
95
|
+
// WSL detection
|
|
96
|
+
env.isWSL = Boolean(
|
|
97
|
+
process.env.WSL_DISTRO_NAME ||
|
|
98
|
+
process.env.WSL_INTEROP ||
|
|
99
|
+
(existsSync('/proc/version') && readFileSync('/proc/version', 'utf8').toLowerCase().includes('microsoft'))
|
|
100
|
+
);
|
|
101
|
+
|
|
88
102
|
// Raw mode support check
|
|
89
103
|
env.supportsRawMode = checkRawModeSupport();
|
|
90
104
|
|
|
@@ -160,6 +174,21 @@ function generateRecommendations(env: ExecutionEnvironment): void {
|
|
|
160
174
|
env.warnings.push('Git Bash detected - some interactive features may not work correctly');
|
|
161
175
|
}
|
|
162
176
|
|
|
177
|
+
// WSL specific recommendations
|
|
178
|
+
if (env.isWSL) {
|
|
179
|
+
env.recommendedFlags.push('--no-interactive');
|
|
180
|
+
env.warnings.push('WSL detected - raw mode may cause hangs, using non-interactive mode');
|
|
181
|
+
if (!env.supportsRawMode) {
|
|
182
|
+
env.warnings.push('WSL subprocess context detected - interactive features disabled');
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Windows specific recommendations
|
|
187
|
+
if (env.isWindows && !env.isWSL) {
|
|
188
|
+
env.recommendedFlags.push('--compatible-ui');
|
|
189
|
+
env.warnings.push('Native Windows detected - using compatible UI mode');
|
|
190
|
+
}
|
|
191
|
+
|
|
163
192
|
// Raw mode not supported
|
|
164
193
|
if (!env.supportsRawMode && env.isInteractive) {
|
|
165
194
|
env.recommendedFlags.push('--compatible-ui');
|
|
@@ -242,6 +271,8 @@ export function getEnvironmentDescription(env?: ExecutionEnvironment): string {
|
|
|
242
271
|
if (environment.isSSH) parts.push('SSH');
|
|
243
272
|
if (environment.isGitBash) parts.push('Git Bash');
|
|
244
273
|
if (environment.isWindowsTerminal) parts.push('Windows Terminal');
|
|
274
|
+
if (environment.isWSL) parts.push('WSL');
|
|
275
|
+
if (environment.isWindows && !environment.isWSL) parts.push('Windows');
|
|
245
276
|
|
|
246
277
|
if (parts.length === 0) {
|
|
247
278
|
parts.push(environment.terminalType);
|
|
@@ -265,6 +296,8 @@ export function shouldUseNonInteractiveMode(options?: { force?: boolean }): bool
|
|
|
265
296
|
return !env.isInteractive ||
|
|
266
297
|
env.isCI ||
|
|
267
298
|
env.isVSCode ||
|
|
299
|
+
env.isWSL ||
|
|
300
|
+
env.isWindows ||
|
|
268
301
|
!env.supportsRawMode;
|
|
269
302
|
}
|
|
270
303
|
|
|
@@ -63,6 +63,9 @@ export function getEnvironmentType() {
|
|
|
63
63
|
if (process.env.CI) return 'ci-environment';
|
|
64
64
|
if (process.env.GITHUB_ACTIONS) return 'github-actions';
|
|
65
65
|
if (process.env.DOCKER_CONTAINER) return 'docker';
|
|
66
|
+
if (process.env.WSL_DISTRO_NAME || process.env.WSL_INTEROP) return 'wsl';
|
|
67
|
+
if (process.platform === 'win32') return 'windows';
|
|
68
|
+
if (process.env.TERM_PROGRAM === 'vscode') return 'vscode';
|
|
66
69
|
if (!isRawModeSupported()) return 'no-raw-mode';
|
|
67
70
|
return 'interactive';
|
|
68
71
|
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Safe Interactive Wrapper - Handles interactive commands in non-interactive environments
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
import { isInteractive, isRawModeSupported, getEnvironmentType } from './interactive-detector.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Wraps an interactive function with safety checks
|
|
10
|
+
* @param {Function} interactiveFn - The interactive function to wrap
|
|
11
|
+
* @param {Function} fallbackFn - The non-interactive fallback function
|
|
12
|
+
* @param {Object} options - Options for the wrapper
|
|
13
|
+
* @returns {Function} The wrapped function
|
|
14
|
+
*/
|
|
15
|
+
export function safeInteractive(interactiveFn, fallbackFn, options = {}) {
|
|
16
|
+
return async function(...args) {
|
|
17
|
+
const flags = args[args.length - 1] || {};
|
|
18
|
+
|
|
19
|
+
// Check if user explicitly requested non-interactive mode
|
|
20
|
+
if (flags.nonInteractive || flags['no-interactive']) {
|
|
21
|
+
if (fallbackFn) {
|
|
22
|
+
return fallbackFn(...args);
|
|
23
|
+
} else {
|
|
24
|
+
console.log(chalk.yellow('ā ļø Non-interactive mode requested but no fallback available'));
|
|
25
|
+
console.log(chalk.gray('This command requires interactive mode to function properly'));
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Auto-detect if we should use non-interactive mode
|
|
31
|
+
if (!isInteractive() || !isRawModeSupported()) {
|
|
32
|
+
const envType = getEnvironmentType();
|
|
33
|
+
|
|
34
|
+
if (!options.silent) {
|
|
35
|
+
console.log(chalk.yellow('\nā ļø Interactive mode not available'));
|
|
36
|
+
console.log(chalk.gray(`Detected environment: ${envType}`));
|
|
37
|
+
|
|
38
|
+
// Provide specific message based on environment
|
|
39
|
+
if (process.env.WSL_DISTRO_NAME || process.env.WSL_INTEROP) {
|
|
40
|
+
console.log(chalk.gray('WSL detected - raw mode may cause process hangs'));
|
|
41
|
+
console.log(chalk.cyan('š” Tip: Use --no-interactive flag or run in native Linux'));
|
|
42
|
+
} else if (process.platform === 'win32') {
|
|
43
|
+
console.log(chalk.gray('Windows detected - terminal compatibility issues'));
|
|
44
|
+
console.log(chalk.cyan('š” Tip: Use Windows Terminal or WSL2 for better experience'));
|
|
45
|
+
} else if (process.env.TERM_PROGRAM === 'vscode') {
|
|
46
|
+
console.log(chalk.gray('VS Code terminal detected - limited interactive support'));
|
|
47
|
+
console.log(chalk.cyan('š” Tip: Use external terminal for full functionality'));
|
|
48
|
+
} else if (!isRawModeSupported()) {
|
|
49
|
+
console.log(chalk.gray('Terminal does not support raw mode'));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
console.log();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (fallbackFn) {
|
|
56
|
+
return fallbackFn(...args);
|
|
57
|
+
} else {
|
|
58
|
+
console.log(chalk.red('ā This command requires interactive mode'));
|
|
59
|
+
console.log(chalk.gray('Please run in a compatible terminal environment'));
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Try to run the interactive function
|
|
65
|
+
try {
|
|
66
|
+
return await interactiveFn(...args);
|
|
67
|
+
} catch (error) {
|
|
68
|
+
// Check if it's a raw mode error
|
|
69
|
+
if (error.message && (
|
|
70
|
+
error.message.includes('setRawMode') ||
|
|
71
|
+
error.message.includes('raw mode') ||
|
|
72
|
+
error.message.includes('stdin') ||
|
|
73
|
+
error.message.includes('TTY')
|
|
74
|
+
)) {
|
|
75
|
+
console.log(chalk.yellow('\nā ļø Interactive mode failed'));
|
|
76
|
+
console.log(chalk.gray(error.message));
|
|
77
|
+
|
|
78
|
+
if (fallbackFn) {
|
|
79
|
+
console.log(chalk.cyan('Falling back to non-interactive mode...'));
|
|
80
|
+
return fallbackFn(...args);
|
|
81
|
+
} else {
|
|
82
|
+
console.log(chalk.red('ā No non-interactive fallback available'));
|
|
83
|
+
process.exit(1);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Re-throw other errors
|
|
88
|
+
throw error;
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Create a non-interactive version of a prompt
|
|
95
|
+
* @param {string} message - The prompt message
|
|
96
|
+
* @param {*} defaultValue - The default value to use
|
|
97
|
+
* @returns {*} The default value
|
|
98
|
+
*/
|
|
99
|
+
export function nonInteractivePrompt(message, defaultValue) {
|
|
100
|
+
console.log(chalk.gray(`š ${message}`));
|
|
101
|
+
console.log(chalk.cyan(` Using default: ${defaultValue}`));
|
|
102
|
+
return defaultValue;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Create a non-interactive version of a selection
|
|
107
|
+
* @param {string} message - The selection message
|
|
108
|
+
* @param {Array} choices - The available choices
|
|
109
|
+
* @param {*} defaultChoice - The default choice
|
|
110
|
+
* @returns {*} The default choice
|
|
111
|
+
*/
|
|
112
|
+
export function nonInteractiveSelect(message, choices, defaultChoice) {
|
|
113
|
+
console.log(chalk.gray(`š ${message}`));
|
|
114
|
+
console.log(chalk.gray(' Available choices:'));
|
|
115
|
+
choices.forEach(choice => {
|
|
116
|
+
const isDefault = choice === defaultChoice || choice.value === defaultChoice;
|
|
117
|
+
console.log(chalk.gray(` ${isDefault ? 'ā¶' : ' '} ${choice.name || choice}`));
|
|
118
|
+
});
|
|
119
|
+
console.log(chalk.cyan(` Using default: ${defaultChoice}`));
|
|
120
|
+
return defaultChoice;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Show a non-interactive progress indicator
|
|
125
|
+
* @param {string} message - The progress message
|
|
126
|
+
* @returns {Object} Progress control object
|
|
127
|
+
*/
|
|
128
|
+
export function nonInteractiveProgress(message) {
|
|
129
|
+
console.log(chalk.gray(`ā³ ${message}...`));
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
update: (newMessage) => {
|
|
133
|
+
console.log(chalk.gray(` ${newMessage}`));
|
|
134
|
+
},
|
|
135
|
+
succeed: (finalMessage) => {
|
|
136
|
+
console.log(chalk.green(`ā
${finalMessage || message}`));
|
|
137
|
+
},
|
|
138
|
+
fail: (errorMessage) => {
|
|
139
|
+
console.log(chalk.red(`ā ${errorMessage || 'Failed'}`));
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
}
|