viben 0.1.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 +181 -0
- package/bin/viben.js +386 -0
- package/dist/index.cjs +1142 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +94 -0
- package/dist/index.d.ts +94 -0
- package/dist/index.js +1102 -0
- package/dist/index.js.map +1 -0
- package/package.json +72 -0
package/README.md
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# Viben CLI
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/viben)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
6
|
+
Command-line interface for Viben - orchestrate AI agent clusters in your local workspace.
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
### Quick Start with npx (Recommended)
|
|
11
|
+
|
|
12
|
+
No installation needed - just run:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npx viben --help
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### Global Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install -g viben
|
|
22
|
+
viben --help
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Commands
|
|
26
|
+
|
|
27
|
+
### Workspace Commands
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
# Initialize a workspace
|
|
31
|
+
viben init
|
|
32
|
+
viben init --from <template>
|
|
33
|
+
|
|
34
|
+
# Manage configuration (git-style)
|
|
35
|
+
viben config list # List all config
|
|
36
|
+
viben config list --show-origin # Show config sources
|
|
37
|
+
viben config get <key> # Get a value
|
|
38
|
+
viben config set <key> <value> # Set a value
|
|
39
|
+
viben config unset <key> # Remove a value
|
|
40
|
+
viben config edit # Open in editor
|
|
41
|
+
|
|
42
|
+
# Manage agents
|
|
43
|
+
viben agent list # List all agents
|
|
44
|
+
viben agent create -n <id> # Create new agent
|
|
45
|
+
viben agent show -n <id> # Show agent details
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Server Commands
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# Start MCP server (wraps browse-mcp Python package)
|
|
52
|
+
viben serve # Start in stdio mode
|
|
53
|
+
viben serve -t sse --port 8080 # Start SSE server
|
|
54
|
+
viben mcp # Alias for serve
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Global Options
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
--json Output in JSON format (for agent consumption)
|
|
61
|
+
-g, --global Use global scope (~/.viben/)
|
|
62
|
+
-w, --workspace Use workspace scope (.viben/)
|
|
63
|
+
--verbose Enable verbose output
|
|
64
|
+
-q, --quiet Suppress non-essential output
|
|
65
|
+
-v, --version Show version
|
|
66
|
+
-h, --help Show help
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Configuration
|
|
70
|
+
|
|
71
|
+
### File Locations
|
|
72
|
+
|
|
73
|
+
- **Global config**: `~/.viben/config.yaml`
|
|
74
|
+
- **Workspace config**: `<project>/.viben/config.yaml`
|
|
75
|
+
- **Global agents**: `~/.viben/agents/*.yaml`
|
|
76
|
+
- **Workspace agents**: `<project>/.viben/agents/*.yaml`
|
|
77
|
+
|
|
78
|
+
### Environment Variables
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
VIBEN_STATE_DIR # Override state directory (default: ~/.viben)
|
|
82
|
+
VIBEN_AGENT # Current agent ID
|
|
83
|
+
VIBEN_SCOPE # Default scope (global/workspace)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Config File Format
|
|
87
|
+
|
|
88
|
+
```yaml
|
|
89
|
+
# .viben/config.yaml
|
|
90
|
+
version: 1
|
|
91
|
+
|
|
92
|
+
settings:
|
|
93
|
+
editor: code
|
|
94
|
+
pager: less
|
|
95
|
+
color: auto
|
|
96
|
+
|
|
97
|
+
agents:
|
|
98
|
+
- main
|
|
99
|
+
|
|
100
|
+
mcp:
|
|
101
|
+
enabled:
|
|
102
|
+
- filesystem
|
|
103
|
+
- git
|
|
104
|
+
|
|
105
|
+
skills:
|
|
106
|
+
enabled:
|
|
107
|
+
- code-review
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## JSON Output Mode
|
|
111
|
+
|
|
112
|
+
All commands support `--json` for structured output:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
# Human-readable (default)
|
|
116
|
+
viben agent list
|
|
117
|
+
# ID Name Model Source
|
|
118
|
+
# main Main Agent (default) workspace
|
|
119
|
+
|
|
120
|
+
# JSON output
|
|
121
|
+
viben --json agent list
|
|
122
|
+
# {
|
|
123
|
+
# "success": true,
|
|
124
|
+
# "data": {
|
|
125
|
+
# "agents": [{ "id": "main", "name": "Main Agent", ... }],
|
|
126
|
+
# "count": 1
|
|
127
|
+
# }
|
|
128
|
+
# }
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## MCP Server
|
|
132
|
+
|
|
133
|
+
The `serve` command wraps the [browse-mcp](https://pypi.org/project/browse-mcp/) Python package.
|
|
134
|
+
|
|
135
|
+
### Requirements
|
|
136
|
+
|
|
137
|
+
- **Node.js 18+** - For the CLI
|
|
138
|
+
- **Python 3.10+** - For the MCP server
|
|
139
|
+
- **pip or uv** - For Python package installation
|
|
140
|
+
|
|
141
|
+
### MCP Client Configuration
|
|
142
|
+
|
|
143
|
+
#### Claude Desktop
|
|
144
|
+
|
|
145
|
+
Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
|
|
146
|
+
|
|
147
|
+
```json
|
|
148
|
+
{
|
|
149
|
+
"mcpServers": {
|
|
150
|
+
"viben": {
|
|
151
|
+
"command": "npx",
|
|
152
|
+
"args": ["viben", "serve"]
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
#### Claude Code
|
|
159
|
+
|
|
160
|
+
Add to `~/.config/claude/config.json`:
|
|
161
|
+
|
|
162
|
+
```json
|
|
163
|
+
{
|
|
164
|
+
"mcpServers": {
|
|
165
|
+
"viben": {
|
|
166
|
+
"command": "npx",
|
|
167
|
+
"args": ["viben", "serve"]
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## Links
|
|
174
|
+
|
|
175
|
+
- [GitHub Repository](https://github.com/LinXueyuanStdio/viben)
|
|
176
|
+
- [PyPI Package (browse-mcp)](https://pypi.org/project/browse-mcp/)
|
|
177
|
+
- [Documentation](https://github.com/LinXueyuanStdio/viben#readme)
|
|
178
|
+
|
|
179
|
+
## License
|
|
180
|
+
|
|
181
|
+
MIT
|
package/bin/viben.js
ADDED
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Viben CLI Entry Point
|
|
5
|
+
*
|
|
6
|
+
* This script serves as the main entry point for the Viben CLI.
|
|
7
|
+
* It routes to either:
|
|
8
|
+
* - The TypeScript CLI (Commander.js) for workspace management commands
|
|
9
|
+
* - The Python browse-mcp wrapper for MCP server functionality
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* viben init # Initialize workspace (TypeScript CLI)
|
|
13
|
+
* viben config list # List config (TypeScript CLI)
|
|
14
|
+
* viben agent list # List agents (TypeScript CLI)
|
|
15
|
+
* viben serve # Start MCP server (Python wrapper)
|
|
16
|
+
* viben mcp # Start MCP server (Python wrapper, alias)
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { createRequire } from 'module';
|
|
20
|
+
import { fileURLToPath } from 'url';
|
|
21
|
+
import { dirname, join } from 'path';
|
|
22
|
+
import { spawnSync, execSync } from 'child_process';
|
|
23
|
+
import { platform } from 'os';
|
|
24
|
+
|
|
25
|
+
const require = createRequire(import.meta.url);
|
|
26
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
27
|
+
const __dirname = dirname(__filename);
|
|
28
|
+
|
|
29
|
+
// Configuration for Python wrapper
|
|
30
|
+
const PYTHON_PACKAGE = 'browse-mcp';
|
|
31
|
+
const MIN_PYTHON_VERSION = '3.10';
|
|
32
|
+
const BRAND_NAME = 'Viben';
|
|
33
|
+
|
|
34
|
+
// Commands that should be handled by the TypeScript CLI
|
|
35
|
+
const TS_CLI_COMMANDS = ['init', 'config', 'agent'];
|
|
36
|
+
|
|
37
|
+
// Commands that should be handled by the Python wrapper
|
|
38
|
+
const PYTHON_COMMANDS = ['serve', 'mcp'];
|
|
39
|
+
|
|
40
|
+
// ANSI colors
|
|
41
|
+
const colors = {
|
|
42
|
+
reset: '\x1b[0m',
|
|
43
|
+
red: '\x1b[31m',
|
|
44
|
+
green: '\x1b[32m',
|
|
45
|
+
yellow: '\x1b[33m',
|
|
46
|
+
blue: '\x1b[34m',
|
|
47
|
+
cyan: '\x1b[36m',
|
|
48
|
+
bold: '\x1b[1m',
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
function info(message) {
|
|
52
|
+
console.log(`${colors.blue}[INFO]${colors.reset} ${message}`);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function success(message) {
|
|
56
|
+
console.log(`${colors.green}[OK]${colors.reset} ${message}`);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function warn(message) {
|
|
60
|
+
console.log(`${colors.yellow}[WARN]${colors.reset} ${message}`);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function error(message) {
|
|
64
|
+
console.error(`${colors.red}[ERROR]${colors.reset} ${message}`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function commandExists(cmd) {
|
|
68
|
+
try {
|
|
69
|
+
const isWindows = platform() === 'win32';
|
|
70
|
+
const checkCmd = isWindows ? `where ${cmd}` : `command -v ${cmd}`;
|
|
71
|
+
execSync(checkCmd, { stdio: 'ignore' });
|
|
72
|
+
return true;
|
|
73
|
+
} catch {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function getPythonVersion(pythonCmd) {
|
|
79
|
+
try {
|
|
80
|
+
const result = execSync(
|
|
81
|
+
`${pythonCmd} -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')"`,
|
|
82
|
+
{ encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] }
|
|
83
|
+
);
|
|
84
|
+
return result.trim();
|
|
85
|
+
} catch {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function versionGte(version, minVersion) {
|
|
91
|
+
const v1 = version.split('.').map(Number);
|
|
92
|
+
const v2 = minVersion.split('.').map(Number);
|
|
93
|
+
|
|
94
|
+
for (let i = 0; i < Math.max(v1.length, v2.length); i++) {
|
|
95
|
+
const a = v1[i] || 0;
|
|
96
|
+
const b = v2[i] || 0;
|
|
97
|
+
if (a > b) return true;
|
|
98
|
+
if (a < b) return false;
|
|
99
|
+
}
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function findPython() {
|
|
104
|
+
const candidates = ['python3', 'python'];
|
|
105
|
+
|
|
106
|
+
for (const cmd of candidates) {
|
|
107
|
+
if (commandExists(cmd)) {
|
|
108
|
+
const version = getPythonVersion(cmd);
|
|
109
|
+
if (version && versionGte(version, MIN_PYTHON_VERSION)) {
|
|
110
|
+
return { cmd, version };
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function isBrowseMcpInstalled(pythonCmd) {
|
|
119
|
+
try {
|
|
120
|
+
execSync(`${pythonCmd} -c "import browse_mcp"`, {
|
|
121
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
122
|
+
});
|
|
123
|
+
return true;
|
|
124
|
+
} catch {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function browseMcpCommandExists() {
|
|
130
|
+
return commandExists('browse-mcp');
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function installBrowseMcp(pythonCmd) {
|
|
134
|
+
info(`Installing ${PYTHON_PACKAGE}...`);
|
|
135
|
+
|
|
136
|
+
if (commandExists('uv')) {
|
|
137
|
+
info('Using uv for installation...');
|
|
138
|
+
let result = spawnSync('uv', ['pip', 'install', PYTHON_PACKAGE], {
|
|
139
|
+
stdio: 'inherit',
|
|
140
|
+
});
|
|
141
|
+
if (result.status === 0) {
|
|
142
|
+
success(`${PYTHON_PACKAGE} installed successfully`);
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
145
|
+
result = spawnSync('uv', ['pip', 'install', '--system', PYTHON_PACKAGE], {
|
|
146
|
+
stdio: 'inherit',
|
|
147
|
+
});
|
|
148
|
+
if (result.status === 0) {
|
|
149
|
+
success(`${PYTHON_PACKAGE} installed successfully`);
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (commandExists('pip3')) {
|
|
155
|
+
info('Using pip3 for installation...');
|
|
156
|
+
const result = spawnSync('pip3', ['install', PYTHON_PACKAGE], {
|
|
157
|
+
stdio: 'inherit',
|
|
158
|
+
});
|
|
159
|
+
if (result.status === 0) {
|
|
160
|
+
success(`${PYTHON_PACKAGE} installed successfully`);
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (commandExists('pip')) {
|
|
166
|
+
info('Using pip for installation...');
|
|
167
|
+
const result = spawnSync('pip', ['install', PYTHON_PACKAGE], {
|
|
168
|
+
stdio: 'inherit',
|
|
169
|
+
});
|
|
170
|
+
if (result.status === 0) {
|
|
171
|
+
success(`${PYTHON_PACKAGE} installed successfully`);
|
|
172
|
+
return true;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (pythonCmd) {
|
|
177
|
+
info(`Using ${pythonCmd} -m pip for installation...`);
|
|
178
|
+
const result = spawnSync(pythonCmd, ['-m', 'pip', 'install', PYTHON_PACKAGE], {
|
|
179
|
+
stdio: 'inherit',
|
|
180
|
+
});
|
|
181
|
+
if (result.status === 0) {
|
|
182
|
+
success(`${PYTHON_PACKAGE} installed successfully`);
|
|
183
|
+
return true;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function runBrowseMcp(args, pythonCmd) {
|
|
191
|
+
if (browseMcpCommandExists()) {
|
|
192
|
+
const result = spawnSync('browse-mcp', args, { stdio: 'inherit' });
|
|
193
|
+
process.exit(result.status || 0);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (pythonCmd) {
|
|
197
|
+
const result = spawnSync(pythonCmd, ['-m', 'browse_mcp', ...args], {
|
|
198
|
+
stdio: 'inherit',
|
|
199
|
+
});
|
|
200
|
+
process.exit(result.status || 0);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
error('Could not run browse-mcp');
|
|
204
|
+
process.exit(1);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
async function runTypeScriptCli(args) {
|
|
208
|
+
try {
|
|
209
|
+
const { run } = await import('../dist/index.js');
|
|
210
|
+
await run(['node', 'viben', ...args]);
|
|
211
|
+
} catch (err) {
|
|
212
|
+
// If dist doesn't exist, try running from source (development mode)
|
|
213
|
+
try {
|
|
214
|
+
const { run } = await import('../src/index.ts');
|
|
215
|
+
await run(['node', 'viben', ...args]);
|
|
216
|
+
} catch {
|
|
217
|
+
error('CLI not built. Run "npm run build" in packages/cli first.');
|
|
218
|
+
console.error(err);
|
|
219
|
+
process.exit(1);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function handlePythonCommand(args) {
|
|
225
|
+
// Remove 'serve' or 'mcp' from args if present
|
|
226
|
+
const filteredArgs = args.filter((a) => a !== 'serve' && a !== 'mcp');
|
|
227
|
+
|
|
228
|
+
const python = findPython();
|
|
229
|
+
if (!python) {
|
|
230
|
+
error(`Python ${MIN_PYTHON_VERSION}+ is required but not found.`);
|
|
231
|
+
console.log('');
|
|
232
|
+
console.log('Please install Python:');
|
|
233
|
+
if (platform() === 'darwin') {
|
|
234
|
+
console.log(' brew install python@3.12');
|
|
235
|
+
} else if (platform() === 'linux') {
|
|
236
|
+
console.log(' sudo apt install python3 python3-pip');
|
|
237
|
+
} else {
|
|
238
|
+
console.log(' https://www.python.org/downloads/');
|
|
239
|
+
}
|
|
240
|
+
process.exit(1);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const isInstalled = browseMcpCommandExists() || isBrowseMcpInstalled(python.cmd);
|
|
244
|
+
|
|
245
|
+
if (!isInstalled) {
|
|
246
|
+
warn(`${PYTHON_PACKAGE} is not installed.`);
|
|
247
|
+
console.log('');
|
|
248
|
+
info('Installing automatically...');
|
|
249
|
+
if (!installBrowseMcp(python.cmd)) {
|
|
250
|
+
error('Automatic installation failed.');
|
|
251
|
+
console.log('');
|
|
252
|
+
console.log('Please install manually:');
|
|
253
|
+
console.log(` pip install ${PYTHON_PACKAGE}`);
|
|
254
|
+
console.log('');
|
|
255
|
+
console.log('Or with uv:');
|
|
256
|
+
console.log(` uv pip install ${PYTHON_PACKAGE}`);
|
|
257
|
+
process.exit(1);
|
|
258
|
+
}
|
|
259
|
+
console.log('');
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
runBrowseMcp(filteredArgs, python.cmd);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function printHelp() {
|
|
266
|
+
const pkg = require('../package.json');
|
|
267
|
+
console.log(`
|
|
268
|
+
${colors.cyan}${colors.bold}${BRAND_NAME} CLI${colors.reset} v${pkg.version}
|
|
269
|
+
|
|
270
|
+
Orchestrate AI agent clusters in your local workspace.
|
|
271
|
+
|
|
272
|
+
${colors.bold}Usage:${colors.reset}
|
|
273
|
+
viben <command> [options]
|
|
274
|
+
|
|
275
|
+
${colors.bold}Workspace Commands:${colors.reset}
|
|
276
|
+
init Initialize a Viben workspace
|
|
277
|
+
config <subcommand> Manage configuration (get, set, list, edit, unset)
|
|
278
|
+
agent <subcommand> Manage agents (list, create, show)
|
|
279
|
+
|
|
280
|
+
${colors.bold}Server Commands:${colors.reset}
|
|
281
|
+
serve Start the MCP server (browse-mcp)
|
|
282
|
+
mcp Alias for serve
|
|
283
|
+
|
|
284
|
+
${colors.bold}Global Options:${colors.reset}
|
|
285
|
+
--json Output in JSON format
|
|
286
|
+
-g, --global Use global scope
|
|
287
|
+
-w, --workspace Use workspace scope
|
|
288
|
+
--verbose Enable verbose output
|
|
289
|
+
-q, --quiet Suppress non-essential output
|
|
290
|
+
-v, --version Show version
|
|
291
|
+
-h, --help Show help
|
|
292
|
+
|
|
293
|
+
${colors.bold}Examples:${colors.reset}
|
|
294
|
+
viben init # Initialize workspace
|
|
295
|
+
viben config list # List all config
|
|
296
|
+
viben config set settings.editor vim
|
|
297
|
+
viben agent list # List all agents
|
|
298
|
+
viben agent create -n my-agent
|
|
299
|
+
viben serve # Start MCP server
|
|
300
|
+
viben serve -t sse --port 8080
|
|
301
|
+
|
|
302
|
+
${colors.bold}Environment Variables:${colors.reset}
|
|
303
|
+
VIBEN_STATE_DIR State directory (default: ~/.viben)
|
|
304
|
+
VIBEN_AGENT Current agent ID
|
|
305
|
+
VIBEN_SCOPE Default scope (global/workspace)
|
|
306
|
+
|
|
307
|
+
${colors.bold}More information:${colors.reset}
|
|
308
|
+
https://github.com/LinXueyuanStdio/viben
|
|
309
|
+
`);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Find the first command (non-flag) argument
|
|
314
|
+
*/
|
|
315
|
+
function findCommand(args) {
|
|
316
|
+
for (const arg of args) {
|
|
317
|
+
if (!arg.startsWith('-')) {
|
|
318
|
+
return arg;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
return null;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
async function main() {
|
|
325
|
+
const args = process.argv.slice(2);
|
|
326
|
+
const firstArg = args[0];
|
|
327
|
+
|
|
328
|
+
// Handle --install (Python package installation)
|
|
329
|
+
if (args.includes('--install')) {
|
|
330
|
+
const python = findPython();
|
|
331
|
+
if (!python) {
|
|
332
|
+
error(`Python ${MIN_PYTHON_VERSION}+ is required`);
|
|
333
|
+
process.exit(1);
|
|
334
|
+
}
|
|
335
|
+
if (installBrowseMcp(python.cmd)) {
|
|
336
|
+
success('Installation complete');
|
|
337
|
+
process.exit(0);
|
|
338
|
+
} else {
|
|
339
|
+
error('Installation failed');
|
|
340
|
+
process.exit(1);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// Handle version (only if it's the only argument)
|
|
345
|
+
if (args.length === 1 && (firstArg === '-v' || firstArg === '--version')) {
|
|
346
|
+
const pkg = require('../package.json');
|
|
347
|
+
console.log(`${BRAND_NAME} CLI v${pkg.version}`);
|
|
348
|
+
process.exit(0);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// Handle help (only if no command is present)
|
|
352
|
+
if (args.length === 0) {
|
|
353
|
+
printHelp();
|
|
354
|
+
process.exit(0);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// Find the first command argument (skip flags)
|
|
358
|
+
const command = findCommand(args);
|
|
359
|
+
|
|
360
|
+
// If only help flag and no command
|
|
361
|
+
if (!command && (args.includes('-h') || args.includes('--help'))) {
|
|
362
|
+
printHelp();
|
|
363
|
+
process.exit(0);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// Route to appropriate handler based on command
|
|
367
|
+
if (command && TS_CLI_COMMANDS.includes(command)) {
|
|
368
|
+
// TypeScript CLI commands (pass all args including global flags)
|
|
369
|
+
await runTypeScriptCli(args);
|
|
370
|
+
} else if (command && PYTHON_COMMANDS.includes(command)) {
|
|
371
|
+
// Python wrapper commands
|
|
372
|
+
handlePythonCommand(args);
|
|
373
|
+
} else if (command) {
|
|
374
|
+
// Unknown command - try TypeScript CLI (it will show proper error)
|
|
375
|
+
await runTypeScriptCli(args);
|
|
376
|
+
} else {
|
|
377
|
+
// No command found - show help
|
|
378
|
+
printHelp();
|
|
379
|
+
process.exit(0);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
main().catch((err) => {
|
|
384
|
+
error(err.message || 'Unknown error');
|
|
385
|
+
process.exit(1);
|
|
386
|
+
});
|