superclaude-kiro 1.1.0 → 1.2.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/README.md +72 -49
- package/bin/superclaude-kiro.js +7 -0
- package/package.json +4 -3
- package/src/cli.js +9 -2
- package/src/installer.js +179 -60
- package/src/mcp-servers.js +157 -0
- package/src/prompts.js +182 -0
package/README.md
CHANGED
|
@@ -10,7 +10,13 @@ Easy installation of [SuperClaude Framework](https://superclaude.netlify.app/) f
|
|
|
10
10
|
npx superclaude-kiro install
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
The installer will guide you through selecting which MCP servers to install. By default, 4 core servers are pre-selected and ready to use immediately.
|
|
14
|
+
|
|
15
|
+
**Want MorphLLM Fast Apply?** Select it during installation or add it later:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npx superclaude-kiro install --with-morph
|
|
19
|
+
```
|
|
14
20
|
|
|
15
21
|
## Usage
|
|
16
22
|
|
|
@@ -55,17 +61,26 @@ Reference SuperClaude commands using `#sc-*` syntax:
|
|
|
55
61
|
## CLI Commands
|
|
56
62
|
|
|
57
63
|
```bash
|
|
58
|
-
# Install SuperClaude
|
|
64
|
+
# Install SuperClaude (interactive MCP server selection)
|
|
59
65
|
npx superclaude-kiro install
|
|
60
66
|
|
|
61
67
|
# Install with options
|
|
62
|
-
npx superclaude-kiro install --force
|
|
63
|
-
npx superclaude-kiro install --
|
|
64
|
-
npx superclaude-kiro install --
|
|
68
|
+
npx superclaude-kiro install --force # Overwrite existing
|
|
69
|
+
npx superclaude-kiro install --minimal # Core servers only, no prompts
|
|
70
|
+
npx superclaude-kiro install --with-morph # Include MorphLLM (prompts for API key)
|
|
71
|
+
npx superclaude-kiro install --no-interactive # Skip prompts, use defaults
|
|
72
|
+
npx superclaude-kiro install --no-mcp # Skip MCP server config entirely
|
|
73
|
+
npx superclaude-kiro install --no-default # Don't set as default agent
|
|
74
|
+
|
|
75
|
+
# Install with MorphLLM API key (for CI/CD)
|
|
76
|
+
npx superclaude-kiro install --morph-api-key "your-api-key"
|
|
65
77
|
|
|
66
|
-
# Update to latest version
|
|
78
|
+
# Update to latest version (preserves your MCP server selections)
|
|
67
79
|
npx superclaude-kiro update
|
|
68
80
|
|
|
81
|
+
# Add MorphLLM during update
|
|
82
|
+
npx superclaude-kiro update --with-morph
|
|
83
|
+
|
|
69
84
|
# Check installation status
|
|
70
85
|
npx superclaude-kiro status
|
|
71
86
|
|
|
@@ -81,9 +96,44 @@ npx superclaude-kiro uninstall
|
|
|
81
96
|
- `sc-pm` - Project Manager agent
|
|
82
97
|
- `sc-implement` - Implementation agent
|
|
83
98
|
- `sc-analyze` - Analysis agent
|
|
84
|
-
- **MCP servers** -
|
|
99
|
+
- **MCP servers** - Your selected servers in `~/.kiro/settings/mcp.json`
|
|
85
100
|
- **Default agent** - Set to `superclaude` in `~/.kiro/settings/cli.json`
|
|
86
101
|
|
|
102
|
+
## MCP Server Selection
|
|
103
|
+
|
|
104
|
+
During installation, you can choose which MCP servers to install:
|
|
105
|
+
|
|
106
|
+
| Server | Description | Default |
|
|
107
|
+
|--------|-------------|---------|
|
|
108
|
+
| `sequential-thinking` | Structured reasoning and problem-solving | Yes |
|
|
109
|
+
| `context7` | Library documentation lookup | Yes |
|
|
110
|
+
| `playwright` | Browser automation and testing | Yes |
|
|
111
|
+
| `serena` | Semantic code analysis and editing | Yes |
|
|
112
|
+
| `morphllm-fast-apply` | Ultra-fast file editing (requires API key) | No |
|
|
113
|
+
|
|
114
|
+
### MorphLLM Fast Apply
|
|
115
|
+
|
|
116
|
+
MorphLLM provides ultra-fast file editing at 10,500+ tokens/sec.
|
|
117
|
+
|
|
118
|
+
**To install with MorphLLM:**
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
npx superclaude-kiro install --with-morph
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
The installer will guide you through:
|
|
125
|
+
1. Creating a free account at [morphllm.com](https://www.morphllm.com)
|
|
126
|
+
2. Getting your API key from [dashboard/api-keys](https://morphllm.com/dashboard/api-keys)
|
|
127
|
+
3. Entering your API key securely
|
|
128
|
+
|
|
129
|
+
**For CI/CD (non-interactive):**
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
npx superclaude-kiro install --morph-api-key "your-api-key"
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
**Pricing**: Free tier includes 500 requests/month. Paid usage is ~$1/million tokens.
|
|
136
|
+
|
|
87
137
|
## Configuration
|
|
88
138
|
|
|
89
139
|
All agents are configured with:
|
|
@@ -156,46 +206,6 @@ npm version patch
|
|
|
156
206
|
npm publish
|
|
157
207
|
```
|
|
158
208
|
|
|
159
|
-
## MCP Server Setup
|
|
160
|
-
|
|
161
|
-
SuperClaude includes 4 pre-configured MCP servers that work out of the box:
|
|
162
|
-
|
|
163
|
-
| Server | Purpose |
|
|
164
|
-
|--------|---------|
|
|
165
|
-
| `sequential-thinking` | Structured reasoning and problem-solving |
|
|
166
|
-
| `context7` | Library documentation lookup |
|
|
167
|
-
| `playwright` | Browser automation and testing |
|
|
168
|
-
| `serena` | Semantic code analysis and editing |
|
|
169
|
-
|
|
170
|
-
### MorphLLM Fast Apply (Optional - Manual Setup Required)
|
|
171
|
-
|
|
172
|
-
The `morphllm-fast-apply` MCP server provides ultra-fast file editing (10,500+ tokens/sec). **It is NOT included by default** due to Kiro CLI environment variable limitations.
|
|
173
|
-
|
|
174
|
-
To add MorphLLM support:
|
|
175
|
-
|
|
176
|
-
1. **Create a free account** at [morphllm.com](https://www.morphllm.com)
|
|
177
|
-
2. **Get your API key** from [dashboard/api-keys](https://www.morphllm.com/dashboard/api-keys)
|
|
178
|
-
3. **Add to your mcp.json** (`~/.kiro/settings/mcp.json`):
|
|
179
|
-
|
|
180
|
-
```json
|
|
181
|
-
{
|
|
182
|
-
"mcpServers": {
|
|
183
|
-
"morphllm-fast-apply": {
|
|
184
|
-
"command": "npx",
|
|
185
|
-
"args": ["-y", "@morph-llm/morph-fast-apply"],
|
|
186
|
-
"env": {
|
|
187
|
-
"MORPH_API_KEY": "your-actual-api-key-here"
|
|
188
|
-
},
|
|
189
|
-
"autoApprove": ["edit_file"]
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
**Important**: Replace `"your-actual-api-key-here"` with your actual API key. The `${MORPH_API_KEY}` environment variable syntax does not work reliably in Kiro CLI ([known issue](https://github.com/kirodotdev/Kiro/issues/3909)).
|
|
196
|
-
|
|
197
|
-
**Pricing**: Free tier includes 500 requests/month. Paid usage is ~$1/million tokens.
|
|
198
|
-
|
|
199
209
|
## Requirements
|
|
200
210
|
|
|
201
211
|
- Node.js 18+
|
|
@@ -221,14 +231,27 @@ kiro-cli mcp list
|
|
|
221
231
|
|
|
222
232
|
# Check config
|
|
223
233
|
cat ~/.kiro/settings/mcp.json
|
|
234
|
+
|
|
235
|
+
# Check status
|
|
236
|
+
npx superclaude-kiro status
|
|
224
237
|
```
|
|
225
238
|
|
|
226
239
|
### MorphLLM not working
|
|
227
240
|
|
|
228
|
-
|
|
241
|
+
Run the installer with `--with-morph` to set up MorphLLM:
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
npx superclaude-kiro install --force --with-morph
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
Or check your current status:
|
|
248
|
+
|
|
249
|
+
```bash
|
|
250
|
+
npx superclaude-kiro status
|
|
251
|
+
```
|
|
229
252
|
|
|
230
253
|
**Common issues:**
|
|
231
|
-
- API key must be
|
|
254
|
+
- API key must be provided during installation (environment variable expansion doesn't work reliably in Kiro CLI)
|
|
232
255
|
- Get your API key from [morphllm.com/dashboard/api-keys](https://www.morphllm.com/dashboard/api-keys)
|
|
233
256
|
|
|
234
257
|
### Reinstall from scratch
|
package/bin/superclaude-kiro.js
CHANGED
|
@@ -17,11 +17,18 @@ program
|
|
|
17
17
|
.option('-f, --force', 'Overwrite existing installation')
|
|
18
18
|
.option('--no-mcp', 'Skip MCP server configuration')
|
|
19
19
|
.option('--no-default', 'Do not set superclaude as default agent')
|
|
20
|
+
.option('-i, --interactive', 'Force interactive mode for MCP selection')
|
|
21
|
+
.option('--no-interactive', 'Skip interactive prompts (use defaults)')
|
|
22
|
+
.option('--minimal', 'Install only core MCP servers (no prompts)')
|
|
23
|
+
.option('--with-morph', 'Include MorphLLM Fast Apply (prompts for API key)')
|
|
24
|
+
.option('--morph-api-key <key>', 'Include MorphLLM with this API key (for CI/CD)')
|
|
20
25
|
.action(install);
|
|
21
26
|
|
|
22
27
|
program
|
|
23
28
|
.command('update')
|
|
24
29
|
.description('Update SuperClaude to latest version')
|
|
30
|
+
.option('--with-morph', 'Add MorphLLM during update (prompts for API key)')
|
|
31
|
+
.option('--morph-api-key <key>', 'Add MorphLLM with this API key during update')
|
|
25
32
|
.action(update);
|
|
26
33
|
|
|
27
34
|
program
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "superclaude-kiro",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "SuperClaude Framework for Kiro CLI - Easy installation for teams",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -36,10 +36,11 @@
|
|
|
36
36
|
"node": ">=18.0.0"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"commander": "^12.1.0",
|
|
40
39
|
"chalk": "^5.3.0",
|
|
40
|
+
"commander": "^12.1.0",
|
|
41
41
|
"fs-extra": "^11.2.0",
|
|
42
|
-
"ora": "^8.1.0"
|
|
42
|
+
"ora": "^8.1.0",
|
|
43
|
+
"prompts": "^2.4.2"
|
|
43
44
|
},
|
|
44
45
|
"files": [
|
|
45
46
|
"bin/",
|
package/src/cli.js
CHANGED
|
@@ -4,12 +4,19 @@ export async function install(options) {
|
|
|
4
4
|
await installSuperClaude({
|
|
5
5
|
force: options.force || false,
|
|
6
6
|
mcp: options.mcp !== false,
|
|
7
|
-
default: options.default !== false
|
|
7
|
+
default: options.default !== false,
|
|
8
|
+
interactive: options.interactive,
|
|
9
|
+
minimal: options.minimal || false,
|
|
10
|
+
withMorph: options.withMorph || false,
|
|
11
|
+
morphApiKey: options.morphApiKey || null
|
|
8
12
|
});
|
|
9
13
|
}
|
|
10
14
|
|
|
11
15
|
export async function update(options) {
|
|
12
|
-
await updateSuperClaude(
|
|
16
|
+
await updateSuperClaude({
|
|
17
|
+
withMorph: options.withMorph || false,
|
|
18
|
+
morphApiKey: options.morphApiKey || null
|
|
19
|
+
});
|
|
13
20
|
}
|
|
14
21
|
|
|
15
22
|
export async function uninstall(options) {
|
package/src/installer.js
CHANGED
|
@@ -5,6 +5,19 @@ import chalk from 'chalk';
|
|
|
5
5
|
import ora from 'ora';
|
|
6
6
|
import { fileURLToPath } from 'url';
|
|
7
7
|
import { createRequire } from 'module';
|
|
8
|
+
import {
|
|
9
|
+
MCP_SERVERS,
|
|
10
|
+
CORE_SERVERS,
|
|
11
|
+
MANAGED_SERVERS,
|
|
12
|
+
buildServerConfig
|
|
13
|
+
} from './mcp-servers.js';
|
|
14
|
+
import {
|
|
15
|
+
isInteractive,
|
|
16
|
+
selectMcpServers,
|
|
17
|
+
promptMorphLLMSetup,
|
|
18
|
+
promptMorphApiKeyQuick,
|
|
19
|
+
confirmInstallation
|
|
20
|
+
} from './prompts.js';
|
|
8
21
|
|
|
9
22
|
const __filename = fileURLToPath(import.meta.url);
|
|
10
23
|
const __dirname = path.dirname(__filename);
|
|
@@ -15,51 +28,107 @@ const KIRO_DIR = path.join(os.homedir(), '.kiro');
|
|
|
15
28
|
const DIST_DIR = path.join(__dirname, '..', 'dist');
|
|
16
29
|
|
|
17
30
|
export async function installSuperClaude(options = {}) {
|
|
18
|
-
const spinner = ora('Installing SuperClaude for Kiro...').start();
|
|
19
|
-
|
|
20
31
|
try {
|
|
21
|
-
// 1. Verify Kiro CLI directory exists
|
|
32
|
+
// 1. Verify Kiro CLI directory exists (before any prompts)
|
|
22
33
|
if (!await fs.pathExists(KIRO_DIR)) {
|
|
23
|
-
|
|
24
|
-
console.log(chalk.yellow('\
|
|
25
|
-
console.log(chalk.cyan('
|
|
26
|
-
console.log(chalk.yellow('
|
|
34
|
+
console.log(chalk.red('\n Kiro CLI not found.'));
|
|
35
|
+
console.log(chalk.yellow('\n Please install Kiro CLI first:'));
|
|
36
|
+
console.log(chalk.cyan(' npm install -g @anthropic-ai/kiro-cli'));
|
|
37
|
+
console.log(chalk.yellow(' or visit: https://kiro.dev/docs/cli/'));
|
|
27
38
|
process.exit(1);
|
|
28
39
|
}
|
|
29
40
|
|
|
30
|
-
// 2. Check for existing installation
|
|
41
|
+
// 2. Check for existing installation (before any prompts)
|
|
31
42
|
const steeringDir = path.join(KIRO_DIR, 'steering', 'superclaude');
|
|
32
43
|
if (await fs.pathExists(steeringDir) && !options.force) {
|
|
33
|
-
|
|
34
|
-
console.log(chalk.yellow('\
|
|
35
|
-
console.log(chalk.cyan('
|
|
44
|
+
console.log(chalk.red('\n SuperClaude already installed.'));
|
|
45
|
+
console.log(chalk.yellow('\n To overwrite, run:'));
|
|
46
|
+
console.log(chalk.cyan(' npx superclaude-kiro install --force'));
|
|
36
47
|
process.exit(1);
|
|
37
48
|
}
|
|
38
49
|
|
|
39
50
|
// 3. Verify dist directory exists
|
|
40
51
|
if (!await fs.pathExists(DIST_DIR)) {
|
|
41
|
-
|
|
42
|
-
console.log(chalk.yellow('\
|
|
43
|
-
console.log(chalk.cyan('
|
|
44
|
-
console.log(chalk.cyan('
|
|
52
|
+
console.log(chalk.red('\n Distribution files not found.'));
|
|
53
|
+
console.log(chalk.yellow('\n Package may be corrupted. Try reinstalling:'));
|
|
54
|
+
console.log(chalk.cyan(' npm cache clean --force'));
|
|
55
|
+
console.log(chalk.cyan(' npx superclaude-kiro@latest install'));
|
|
45
56
|
process.exit(1);
|
|
46
57
|
}
|
|
47
58
|
|
|
48
|
-
// 4.
|
|
59
|
+
// 4. Determine MCP server selection and API keys
|
|
60
|
+
let selectedServers = options.servers || null;
|
|
61
|
+
let apiKeys = options.apiKeys || {};
|
|
62
|
+
|
|
63
|
+
// Handle MCP configuration based on options
|
|
64
|
+
if (options.mcp !== false) {
|
|
65
|
+
// If --minimal flag, use only core servers
|
|
66
|
+
if (options.minimal) {
|
|
67
|
+
selectedServers = CORE_SERVERS;
|
|
68
|
+
}
|
|
69
|
+
// If --morph-api-key provided via CLI
|
|
70
|
+
else if (options.morphApiKey) {
|
|
71
|
+
selectedServers = [...CORE_SERVERS, 'morphllm-fast-apply'];
|
|
72
|
+
apiKeys['morphllm-fast-apply'] = options.morphApiKey;
|
|
73
|
+
}
|
|
74
|
+
// If --with-morph flag, prompt for API key
|
|
75
|
+
else if (options.withMorph) {
|
|
76
|
+
selectedServers = [...CORE_SERVERS, 'morphllm-fast-apply'];
|
|
77
|
+
if (isInteractive()) {
|
|
78
|
+
const morphKey = await promptMorphApiKeyQuick();
|
|
79
|
+
if (morphKey) {
|
|
80
|
+
apiKeys['morphllm-fast-apply'] = morphKey;
|
|
81
|
+
} else {
|
|
82
|
+
// User didn't provide key, remove morphllm from selection
|
|
83
|
+
selectedServers = CORE_SERVERS;
|
|
84
|
+
console.log(chalk.gray('\n Skipping MorphLLM (no API key provided).\n'));
|
|
85
|
+
}
|
|
86
|
+
} else {
|
|
87
|
+
console.log(chalk.yellow('\n Warning: --with-morph requires interactive mode or --morph-api-key'));
|
|
88
|
+
selectedServers = CORE_SERVERS;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// If interactive and no specific flags, show selection UI
|
|
92
|
+
else if (options.interactive !== false && isInteractive()) {
|
|
93
|
+
selectedServers = await selectMcpServers();
|
|
94
|
+
|
|
95
|
+
// If morphllm was selected, prompt for API key
|
|
96
|
+
if (selectedServers.includes('morphllm-fast-apply')) {
|
|
97
|
+
const morphKey = await promptMorphLLMSetup();
|
|
98
|
+
if (morphKey) {
|
|
99
|
+
apiKeys['morphllm-fast-apply'] = morphKey;
|
|
100
|
+
} else {
|
|
101
|
+
// User didn't provide key, remove morphllm from selection
|
|
102
|
+
selectedServers = selectedServers.filter(s => s !== 'morphllm-fast-apply');
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
await confirmInstallation(selectedServers, !!apiKeys['morphllm-fast-apply']);
|
|
107
|
+
}
|
|
108
|
+
// Non-interactive default: core servers only
|
|
109
|
+
else {
|
|
110
|
+
selectedServers = CORE_SERVERS;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Start the spinner after all prompts are done
|
|
115
|
+
const spinner = ora('Installing SuperClaude for Kiro...').start();
|
|
116
|
+
|
|
117
|
+
// 5. Create directories
|
|
49
118
|
spinner.text = 'Creating directories...';
|
|
50
119
|
await fs.ensureDir(path.join(KIRO_DIR, 'steering', 'superclaude'));
|
|
51
120
|
await fs.ensureDir(path.join(KIRO_DIR, 'agents'));
|
|
52
121
|
await fs.ensureDir(path.join(KIRO_DIR, 'settings'));
|
|
53
122
|
await fs.ensureDir(path.join(KIRO_DIR, 'docs'));
|
|
54
123
|
|
|
55
|
-
//
|
|
124
|
+
// 6. Copy steering files
|
|
56
125
|
spinner.text = 'Installing steering files...';
|
|
57
126
|
const steeringSrc = path.join(DIST_DIR, 'steering', 'superclaude');
|
|
58
127
|
if (await fs.pathExists(steeringSrc)) {
|
|
59
128
|
await fs.copy(steeringSrc, path.join(KIRO_DIR, 'steering', 'superclaude'));
|
|
60
129
|
}
|
|
61
130
|
|
|
62
|
-
//
|
|
131
|
+
// 7. Copy agents
|
|
63
132
|
spinner.text = 'Installing agents...';
|
|
64
133
|
const agentsSrc = path.join(DIST_DIR, 'agents');
|
|
65
134
|
if (await fs.pathExists(agentsSrc)) {
|
|
@@ -74,19 +143,19 @@ export async function installSuperClaude(options = {}) {
|
|
|
74
143
|
}
|
|
75
144
|
}
|
|
76
145
|
|
|
77
|
-
//
|
|
78
|
-
if (options.mcp !== false) {
|
|
146
|
+
// 8. Configure MCP servers (with selected servers)
|
|
147
|
+
if (options.mcp !== false && selectedServers) {
|
|
79
148
|
spinner.text = 'Configuring MCP servers...';
|
|
80
|
-
await configureMcpServers();
|
|
149
|
+
await configureMcpServers(selectedServers, apiKeys);
|
|
81
150
|
}
|
|
82
151
|
|
|
83
|
-
//
|
|
152
|
+
// 9. Set default agent (optional)
|
|
84
153
|
if (options.default !== false) {
|
|
85
154
|
spinner.text = 'Setting default agent...';
|
|
86
155
|
await setDefaultAgent();
|
|
87
156
|
}
|
|
88
157
|
|
|
89
|
-
//
|
|
158
|
+
// 10. Create version file
|
|
90
159
|
spinner.text = 'Finalizing installation...';
|
|
91
160
|
const pkg = require('../package.json');
|
|
92
161
|
await fs.writeJson(
|
|
@@ -94,7 +163,8 @@ export async function installSuperClaude(options = {}) {
|
|
|
94
163
|
{
|
|
95
164
|
version: pkg.version,
|
|
96
165
|
installedAt: new Date().toISOString(),
|
|
97
|
-
source: 'npm:superclaude-kiro'
|
|
166
|
+
source: 'npm:superclaude-kiro',
|
|
167
|
+
mcpServers: selectedServers || []
|
|
98
168
|
},
|
|
99
169
|
{ spaces: 2 }
|
|
100
170
|
);
|
|
@@ -109,6 +179,9 @@ export async function installSuperClaude(options = {}) {
|
|
|
109
179
|
console.log(chalk.gray(' Installed:'));
|
|
110
180
|
console.log(chalk.gray(` - ${steeringFiles} steering files`));
|
|
111
181
|
console.log(chalk.gray(` - ${agentFiles + 1} agents`));
|
|
182
|
+
if (selectedServers) {
|
|
183
|
+
console.log(chalk.gray(` - ${selectedServers.length} MCP servers`));
|
|
184
|
+
}
|
|
112
185
|
console.log('');
|
|
113
186
|
console.log(chalk.cyan('Quick Start:'));
|
|
114
187
|
console.log(' 1. Run: ' + chalk.yellow('kiro-cli chat'));
|
|
@@ -116,12 +189,12 @@ export async function installSuperClaude(options = {}) {
|
|
|
116
189
|
console.log('');
|
|
117
190
|
|
|
118
191
|
} catch (error) {
|
|
119
|
-
|
|
192
|
+
console.log(chalk.red('\n Installation failed: ' + error.message));
|
|
120
193
|
process.exit(1);
|
|
121
194
|
}
|
|
122
195
|
}
|
|
123
196
|
|
|
124
|
-
export async function updateSuperClaude() {
|
|
197
|
+
export async function updateSuperClaude(options = {}) {
|
|
125
198
|
const spinner = ora('Checking for updates...').start();
|
|
126
199
|
|
|
127
200
|
try {
|
|
@@ -134,11 +207,22 @@ export async function updateSuperClaude() {
|
|
|
134
207
|
process.exit(1);
|
|
135
208
|
}
|
|
136
209
|
|
|
210
|
+
// Read existing version info to preserve MCP server selections
|
|
211
|
+
const versionInfo = await fs.readJson(versionFile);
|
|
212
|
+
const existingServers = versionInfo.mcpServers || CORE_SERVERS;
|
|
213
|
+
|
|
137
214
|
// Stop this spinner before installSuperClaude starts its own
|
|
138
215
|
spinner.stop();
|
|
139
216
|
|
|
140
|
-
// Perform fresh install with force
|
|
141
|
-
await installSuperClaude({
|
|
217
|
+
// Perform fresh install with force, preserving server selection
|
|
218
|
+
await installSuperClaude({
|
|
219
|
+
force: true,
|
|
220
|
+
mcp: true,
|
|
221
|
+
default: true,
|
|
222
|
+
servers: existingServers,
|
|
223
|
+
interactive: false, // Don't re-prompt during update
|
|
224
|
+
...options
|
|
225
|
+
});
|
|
142
226
|
|
|
143
227
|
} catch (error) {
|
|
144
228
|
spinner.fail(chalk.red('Update failed: ' + error.message));
|
|
@@ -238,12 +322,34 @@ export async function getStatus() {
|
|
|
238
322
|
console.log(chalk.green(` ✔ Steering files (${steeringFiles})`));
|
|
239
323
|
console.log(chalk.green(` ✔ Agents (${agentFiles + 1})`));
|
|
240
324
|
|
|
241
|
-
// Check MCP
|
|
325
|
+
// Check MCP servers
|
|
242
326
|
const mcpPath = path.join(KIRO_DIR, 'settings', 'mcp.json');
|
|
243
327
|
if (await fs.pathExists(mcpPath)) {
|
|
244
328
|
const mcpConfig = await fs.readJson(mcpPath);
|
|
245
329
|
const mcpCount = Object.keys(mcpConfig.mcpServers || {}).length;
|
|
330
|
+
const installedServers = versionInfo.mcpServers || [];
|
|
331
|
+
|
|
246
332
|
console.log(chalk.green(` ✔ MCP servers (${mcpCount})`));
|
|
333
|
+
|
|
334
|
+
// Show which servers are installed
|
|
335
|
+
if (installedServers.length > 0) {
|
|
336
|
+
console.log(chalk.gray(' Installed:'));
|
|
337
|
+
for (const serverName of installedServers) {
|
|
338
|
+
const server = MCP_SERVERS[serverName];
|
|
339
|
+
const displayName = server?.displayName || serverName;
|
|
340
|
+
console.log(chalk.gray(` - ${displayName}`));
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// Check if morphllm is configured
|
|
345
|
+
if (mcpConfig.mcpServers?.['morphllm-fast-apply']) {
|
|
346
|
+
const hasApiKey = mcpConfig.mcpServers['morphllm-fast-apply']?.env?.MORPH_API_KEY;
|
|
347
|
+
if (hasApiKey && !hasApiKey.startsWith('${')) {
|
|
348
|
+
console.log(chalk.green(' ✔ MorphLLM API key configured'));
|
|
349
|
+
} else {
|
|
350
|
+
console.log(chalk.yellow(' ○ MorphLLM needs API key'));
|
|
351
|
+
}
|
|
352
|
+
}
|
|
247
353
|
} else {
|
|
248
354
|
console.log(chalk.yellow(' ○ MCP servers (not configured)'));
|
|
249
355
|
}
|
|
@@ -264,48 +370,61 @@ export async function getStatus() {
|
|
|
264
370
|
|
|
265
371
|
// Helper functions
|
|
266
372
|
|
|
267
|
-
async function configureMcpServers() {
|
|
373
|
+
async function configureMcpServers(selectedServers, apiKeys = {}) {
|
|
268
374
|
const mcpPath = path.join(KIRO_DIR, 'settings', 'mcp.json');
|
|
269
|
-
const templatePath = path.join(DIST_DIR, 'mcp', 'mcp-servers.json');
|
|
270
375
|
|
|
376
|
+
// Read existing config to preserve user's custom servers
|
|
271
377
|
let existingConfig = { mcpServers: {} };
|
|
272
378
|
if (await fs.pathExists(mcpPath)) {
|
|
273
379
|
existingConfig = await fs.readJson(mcpPath);
|
|
274
380
|
}
|
|
275
381
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
382
|
+
// Build new config from selected servers
|
|
383
|
+
const newServers = {};
|
|
384
|
+
for (const serverName of selectedServers) {
|
|
385
|
+
const apiKey = apiKeys[serverName] || null;
|
|
386
|
+
const config = buildServerConfig(serverName, apiKey);
|
|
387
|
+
if (config) {
|
|
388
|
+
newServers[serverName] = config;
|
|
389
|
+
}
|
|
279
390
|
}
|
|
280
391
|
|
|
281
|
-
//
|
|
392
|
+
// Merge: preserve user's custom servers, update managed servers
|
|
282
393
|
const mergedServers = {};
|
|
283
394
|
|
|
284
|
-
//
|
|
285
|
-
const
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
395
|
+
// First, add all user's non-managed servers
|
|
396
|
+
for (const [name, config] of Object.entries(existingConfig.mcpServers || {})) {
|
|
397
|
+
if (!MANAGED_SERVERS.includes(name)) {
|
|
398
|
+
mergedServers[name] = config;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// Then add/update selected managed servers
|
|
403
|
+
for (const [name, config] of Object.entries(newServers)) {
|
|
404
|
+
const existingServer = existingConfig.mcpServers?.[name];
|
|
405
|
+
|
|
406
|
+
if (existingServer) {
|
|
407
|
+
// Preserve user's env settings (especially API keys) if they exist
|
|
408
|
+
const mergedEnv = {
|
|
409
|
+
...(config.env || {}),
|
|
410
|
+
...(existingServer.env || {})
|
|
411
|
+
};
|
|
412
|
+
|
|
413
|
+
// But if we have a new API key from this install, use it
|
|
414
|
+
if (apiKeys[name]) {
|
|
415
|
+
const server = MCP_SERVERS[name];
|
|
416
|
+
if (server?.apiKeyEnvVar) {
|
|
417
|
+
mergedEnv[server.apiKeyEnvVar] = apiKeys[name];
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
mergedServers[name] = {
|
|
422
|
+
...config,
|
|
423
|
+
...(Object.keys(mergedEnv).length > 0 ? { env: mergedEnv } : {})
|
|
424
|
+
};
|
|
425
|
+
} else {
|
|
426
|
+
mergedServers[name] = config;
|
|
427
|
+
}
|
|
309
428
|
}
|
|
310
429
|
|
|
311
430
|
const mergedConfig = { mcpServers: mergedServers };
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Server Definitions for SuperClaude
|
|
3
|
+
*
|
|
4
|
+
* Each server has metadata for the interactive installer:
|
|
5
|
+
* - displayName: Human-readable name
|
|
6
|
+
* - description: Short description for selection UI
|
|
7
|
+
* - requiresApiKey: Whether user needs to provide an API key
|
|
8
|
+
* - defaultEnabled: Pre-selected in interactive mode
|
|
9
|
+
* - config: The actual MCP server configuration
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
export const MCP_SERVERS = {
|
|
13
|
+
'sequential-thinking': {
|
|
14
|
+
name: 'sequential-thinking',
|
|
15
|
+
displayName: 'Sequential Thinking',
|
|
16
|
+
description: 'Structured reasoning and problem-solving',
|
|
17
|
+
requiresApiKey: false,
|
|
18
|
+
defaultEnabled: true,
|
|
19
|
+
config: {
|
|
20
|
+
command: 'npx',
|
|
21
|
+
args: ['-y', '@modelcontextprotocol/server-sequential-thinking'],
|
|
22
|
+
autoApprove: ['sequentialthinking']
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
'context7': {
|
|
27
|
+
name: 'context7',
|
|
28
|
+
displayName: 'Context7',
|
|
29
|
+
description: 'Library documentation lookup',
|
|
30
|
+
requiresApiKey: false,
|
|
31
|
+
defaultEnabled: true,
|
|
32
|
+
config: {
|
|
33
|
+
command: 'npx',
|
|
34
|
+
args: ['-y', '@upstash/context7-mcp'],
|
|
35
|
+
autoApprove: ['resolve-library-id', 'get-library-docs']
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
'playwright': {
|
|
40
|
+
name: 'playwright',
|
|
41
|
+
displayName: 'Playwright',
|
|
42
|
+
description: 'Browser automation and testing',
|
|
43
|
+
requiresApiKey: false,
|
|
44
|
+
defaultEnabled: true,
|
|
45
|
+
config: {
|
|
46
|
+
command: 'npx',
|
|
47
|
+
args: ['-y', '@playwright/mcp@latest'],
|
|
48
|
+
autoApprove: [
|
|
49
|
+
'browser_close', 'browser_resize', 'browser_console_messages',
|
|
50
|
+
'browser_handle_dialog', 'browser_evaluate', 'browser_file_upload',
|
|
51
|
+
'browser_fill_form', 'browser_install', 'browser_press_key',
|
|
52
|
+
'browser_type', 'browser_navigate', 'browser_navigate_back',
|
|
53
|
+
'browser_network_requests', 'browser_run_code', 'browser_take_screenshot',
|
|
54
|
+
'browser_snapshot', 'browser_click', 'browser_drag', 'browser_hover',
|
|
55
|
+
'browser_select_option', 'browser_tabs', 'browser_wait_for'
|
|
56
|
+
]
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
'serena': {
|
|
61
|
+
name: 'serena',
|
|
62
|
+
displayName: 'Serena',
|
|
63
|
+
description: 'Semantic code analysis and editing',
|
|
64
|
+
requiresApiKey: false,
|
|
65
|
+
defaultEnabled: true,
|
|
66
|
+
config: {
|
|
67
|
+
command: 'uvx',
|
|
68
|
+
args: [
|
|
69
|
+
'--from', 'git+https://github.com/oraios/serena',
|
|
70
|
+
'serena', 'start-mcp-server',
|
|
71
|
+
'--context', 'ide-assistant',
|
|
72
|
+
'--enable-web-dashboard', 'false',
|
|
73
|
+
'--enable-gui-log-window', 'false'
|
|
74
|
+
],
|
|
75
|
+
autoApprove: [
|
|
76
|
+
'list_dir', 'find_file', 'search_for_pattern', 'get_symbols_overview',
|
|
77
|
+
'find_symbol', 'find_referencing_symbols', 'replace_symbol_body',
|
|
78
|
+
'insert_after_symbol', 'insert_before_symbol', 'rename_symbol',
|
|
79
|
+
'write_memory', 'read_memory', 'list_memories', 'delete_memory',
|
|
80
|
+
'edit_memory', 'activate_project', 'get_current_config',
|
|
81
|
+
'check_onboarding_performed', 'onboarding', 'think_about_collected_information',
|
|
82
|
+
'think_about_task_adherence', 'think_about_whether_you_are_done', 'initial_instructions'
|
|
83
|
+
]
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
'morphllm-fast-apply': {
|
|
88
|
+
name: 'morphllm-fast-apply',
|
|
89
|
+
displayName: 'MorphLLM Fast Apply',
|
|
90
|
+
description: 'Ultra-fast file editing (10,500+ tokens/sec) - requires API key',
|
|
91
|
+
requiresApiKey: true,
|
|
92
|
+
apiKeyEnvVar: 'MORPH_API_KEY',
|
|
93
|
+
defaultEnabled: false,
|
|
94
|
+
signupUrl: 'https://www.morphllm.com',
|
|
95
|
+
apiKeyUrl: 'https://morphllm.com/dashboard/api-keys',
|
|
96
|
+
pricing: 'Free tier: 500 requests/month. Paid: ~$1/million tokens.',
|
|
97
|
+
setupInstructions: [
|
|
98
|
+
'1. Create a free account at https://www.morphllm.com',
|
|
99
|
+
'2. Get your API key at https://morphllm.com/dashboard/api-keys',
|
|
100
|
+
'3. Paste your API key when prompted'
|
|
101
|
+
],
|
|
102
|
+
config: {
|
|
103
|
+
command: 'npx',
|
|
104
|
+
args: ['-y', '@morph-llm/morph-fast-apply'],
|
|
105
|
+
autoApprove: ['edit_file']
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
// List of server names that are managed by SuperClaude installer
|
|
111
|
+
export const MANAGED_SERVERS = Object.keys(MCP_SERVERS);
|
|
112
|
+
|
|
113
|
+
// Get core servers (no API key required)
|
|
114
|
+
export const CORE_SERVERS = Object.entries(MCP_SERVERS)
|
|
115
|
+
.filter(([_, server]) => !server.requiresApiKey)
|
|
116
|
+
.map(([name]) => name);
|
|
117
|
+
|
|
118
|
+
// Get servers that require API keys
|
|
119
|
+
export const API_KEY_SERVERS = Object.entries(MCP_SERVERS)
|
|
120
|
+
.filter(([_, server]) => server.requiresApiKey)
|
|
121
|
+
.map(([name]) => name);
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Build MCP config for a server, optionally with API key
|
|
125
|
+
*/
|
|
126
|
+
export function buildServerConfig(serverName, apiKey = null) {
|
|
127
|
+
const server = MCP_SERVERS[serverName];
|
|
128
|
+
if (!server) return null;
|
|
129
|
+
|
|
130
|
+
const config = { ...server.config };
|
|
131
|
+
|
|
132
|
+
// Add API key to env if provided
|
|
133
|
+
if (apiKey && server.requiresApiKey) {
|
|
134
|
+
config.env = {
|
|
135
|
+
[server.apiKeyEnvVar]: apiKey
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return config;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Build complete MCP config from selected servers
|
|
144
|
+
*/
|
|
145
|
+
export function buildMcpConfig(selectedServers, apiKeys = {}) {
|
|
146
|
+
const mcpServers = {};
|
|
147
|
+
|
|
148
|
+
for (const serverName of selectedServers) {
|
|
149
|
+
const apiKey = apiKeys[serverName] || null;
|
|
150
|
+
const config = buildServerConfig(serverName, apiKey);
|
|
151
|
+
if (config) {
|
|
152
|
+
mcpServers[serverName] = config;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return { mcpServers };
|
|
157
|
+
}
|
package/src/prompts.js
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import prompts from 'prompts';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { MCP_SERVERS, CORE_SERVERS } from './mcp-servers.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Check if running in interactive TTY
|
|
7
|
+
*/
|
|
8
|
+
export function isInteractive() {
|
|
9
|
+
return process.stdin.isTTY && process.stdout.isTTY;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Display a header box
|
|
14
|
+
*/
|
|
15
|
+
function showHeader(title) {
|
|
16
|
+
const line = '─'.repeat(title.length + 4);
|
|
17
|
+
console.log('');
|
|
18
|
+
console.log(chalk.cyan(`┌${line}┐`));
|
|
19
|
+
console.log(chalk.cyan(`│ ${chalk.bold(title)} │`));
|
|
20
|
+
console.log(chalk.cyan(`└${line}┘`));
|
|
21
|
+
console.log('');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Prompt user to select which MCP servers to install
|
|
26
|
+
*/
|
|
27
|
+
export async function selectMcpServers() {
|
|
28
|
+
showHeader('MCP Server Setup');
|
|
29
|
+
|
|
30
|
+
const choices = Object.entries(MCP_SERVERS).map(([name, server]) => {
|
|
31
|
+
const apiKeyNote = server.requiresApiKey ? chalk.yellow(' (requires API key)') : '';
|
|
32
|
+
return {
|
|
33
|
+
title: `${server.displayName}${apiKeyNote}`,
|
|
34
|
+
description: server.description,
|
|
35
|
+
value: name,
|
|
36
|
+
selected: server.defaultEnabled
|
|
37
|
+
};
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const response = await prompts({
|
|
41
|
+
type: 'multiselect',
|
|
42
|
+
name: 'servers',
|
|
43
|
+
message: 'Select MCP servers to install',
|
|
44
|
+
choices,
|
|
45
|
+
hint: '- Space to toggle, Enter to confirm',
|
|
46
|
+
instructions: false
|
|
47
|
+
}, {
|
|
48
|
+
onCancel: () => {
|
|
49
|
+
console.log(chalk.yellow('\nInstallation cancelled.'));
|
|
50
|
+
process.exit(0);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
return response.servers || CORE_SERVERS;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Prompt for MorphLLM API key setup
|
|
59
|
+
*/
|
|
60
|
+
export async function promptMorphLLMSetup() {
|
|
61
|
+
const server = MCP_SERVERS['morphllm-fast-apply'];
|
|
62
|
+
|
|
63
|
+
showHeader('MorphLLM Fast Apply Setup');
|
|
64
|
+
|
|
65
|
+
console.log(chalk.white('MorphLLM provides ultra-fast file editing (10,500+ tokens/sec).'));
|
|
66
|
+
console.log(chalk.gray(server.pricing));
|
|
67
|
+
console.log('');
|
|
68
|
+
console.log(chalk.white('Setup steps:'));
|
|
69
|
+
server.setupInstructions.forEach(step => {
|
|
70
|
+
console.log(chalk.gray(` ${step}`));
|
|
71
|
+
});
|
|
72
|
+
console.log('');
|
|
73
|
+
|
|
74
|
+
// Ask if user has an API key
|
|
75
|
+
const hasKey = await prompts({
|
|
76
|
+
type: 'confirm',
|
|
77
|
+
name: 'value',
|
|
78
|
+
message: 'Do you have a MorphLLM API key?',
|
|
79
|
+
initial: false
|
|
80
|
+
}, {
|
|
81
|
+
onCancel: () => {
|
|
82
|
+
return { value: false };
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
if (!hasKey.value) {
|
|
87
|
+
console.log('');
|
|
88
|
+
console.log(chalk.cyan('To get your free API key:'));
|
|
89
|
+
console.log(chalk.white(` 1. Sign up at: ${chalk.underline(server.signupUrl)}`));
|
|
90
|
+
console.log(chalk.white(` 2. Get key at: ${chalk.underline(server.apiKeyUrl)}`));
|
|
91
|
+
console.log('');
|
|
92
|
+
|
|
93
|
+
const wannaWait = await prompts({
|
|
94
|
+
type: 'confirm',
|
|
95
|
+
name: 'value',
|
|
96
|
+
message: 'Would you like to enter an API key now? (open the URL above first)',
|
|
97
|
+
initial: true
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
if (!wannaWait.value) {
|
|
101
|
+
console.log('');
|
|
102
|
+
console.log(chalk.gray('No worries! You can add MorphLLM later by running:'));
|
|
103
|
+
console.log(chalk.cyan(' npx superclaude-kiro install --with-morph'));
|
|
104
|
+
console.log('');
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Prompt for the API key
|
|
110
|
+
const apiKeyResponse = await prompts({
|
|
111
|
+
type: 'password',
|
|
112
|
+
name: 'apiKey',
|
|
113
|
+
message: 'Enter your MorphLLM API key',
|
|
114
|
+
validate: value => {
|
|
115
|
+
if (!value || value.trim().length === 0) {
|
|
116
|
+
return 'API key cannot be empty';
|
|
117
|
+
}
|
|
118
|
+
if (value.trim().length < 10) {
|
|
119
|
+
return 'API key seems too short';
|
|
120
|
+
}
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
}, {
|
|
124
|
+
onCancel: () => {
|
|
125
|
+
return { apiKey: null };
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
if (apiKeyResponse.apiKey) {
|
|
130
|
+
console.log(chalk.green(' API key saved.'));
|
|
131
|
+
return apiKeyResponse.apiKey.trim();
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Quick prompt for MorphLLM key when using --with-morph flag
|
|
139
|
+
*/
|
|
140
|
+
export async function promptMorphApiKeyQuick() {
|
|
141
|
+
const server = MCP_SERVERS['morphllm-fast-apply'];
|
|
142
|
+
|
|
143
|
+
console.log('');
|
|
144
|
+
console.log(chalk.cyan.bold('MorphLLM Fast Apply'));
|
|
145
|
+
console.log(chalk.gray(server.pricing));
|
|
146
|
+
console.log('');
|
|
147
|
+
console.log(chalk.white(`Sign up: ${chalk.underline(server.signupUrl)}`));
|
|
148
|
+
console.log(chalk.white(`Get key: ${chalk.underline(server.apiKeyUrl)}`));
|
|
149
|
+
console.log('');
|
|
150
|
+
|
|
151
|
+
const response = await prompts({
|
|
152
|
+
type: 'password',
|
|
153
|
+
name: 'apiKey',
|
|
154
|
+
message: 'Enter your MorphLLM API key (or press Enter to skip)',
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
if (response.apiKey && response.apiKey.trim().length > 0) {
|
|
158
|
+
return response.apiKey.trim();
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Confirm installation with selected servers
|
|
166
|
+
*/
|
|
167
|
+
export async function confirmInstallation(servers, hasMorph) {
|
|
168
|
+
console.log('');
|
|
169
|
+
console.log(chalk.white('Will install the following MCP servers:'));
|
|
170
|
+
servers.forEach(name => {
|
|
171
|
+
const server = MCP_SERVERS[name];
|
|
172
|
+
const icon = server?.requiresApiKey ? chalk.yellow('*') : chalk.green('✓');
|
|
173
|
+
console.log(` ${icon} ${server?.displayName || name}`);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
if (hasMorph) {
|
|
177
|
+
console.log(chalk.gray(' * requires API key'));
|
|
178
|
+
}
|
|
179
|
+
console.log('');
|
|
180
|
+
|
|
181
|
+
return true; // Auto-confirm for now, can add prompt if needed
|
|
182
|
+
}
|