@viberaven/mcp 1.0.5 → 1.0.7
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 +20 -3
- package/bin/server.js +381 -366
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# @viberaven/mcp
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/@viberaven/mcp)
|
|
4
|
+
[](https://www.npmjs.com/package/@viberaven/mcp)
|
|
5
|
+
[](https://www.npmjs.com/package/@viberaven/mcp)
|
|
6
|
+
|
|
3
7
|
Thin MCP wrapper for VibeRaven.
|
|
4
8
|
|
|
5
9
|
This package exposes VibeRaven CLI actions as MCP tools for Codex, Claude Code, Cursor, and other agent runtimes. It does not contain VibeRaven backend logic and does not bypass VibeRaven login or scan quotas.
|
|
@@ -32,9 +36,22 @@ npx -y viberaven mcp
|
|
|
32
36
|
- `viberaven_heal_prompt` -> `npx -y viberaven --heal --prompt`
|
|
33
37
|
- `viberaven_heal_apply` -> `npx -y viberaven --heal --apply`
|
|
34
38
|
|
|
35
|
-
`viberaven_check_readiness` is the canonical entrypoint. It runs VibeRaven as the Agent Context + Production Gate and writes `.viberaven/agent-tasklist.md`, `.viberaven/gate-result.json`,
|
|
36
|
-
|
|
37
|
-
|
|
39
|
+
`viberaven_check_readiness` is the canonical entrypoint. It runs VibeRaven as the Agent Context + Production Gate and writes `.viberaven/agent-tasklist.md`, `.viberaven/gate-result.json`, `.viberaven/context-map.json`, and Launch Autopilot artifacts.
|
|
40
|
+
|
|
41
|
+
Launch Autopilot keeps the canonical agent command:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npx -y viberaven --agent-mode
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
MCP clients may pass `launchMode` to `viberaven_check_readiness`:
|
|
48
|
+
|
|
49
|
+
- `manual`: show links and commands only
|
|
50
|
+
- `ask`: default, ask before provider actions
|
|
51
|
+
- `safe`: read-only provider checks and safe repo fixes
|
|
52
|
+
- `full`: approved session mode; production deploy still needs final confirmation
|
|
53
|
+
|
|
54
|
+
After one fix, call `viberaven_verify`. Before deploy or CI pass, call `viberaven_strict_gate` or run:
|
|
38
55
|
|
|
39
56
|
```bash
|
|
40
57
|
npx -y viberaven --strict
|
package/bin/server.js
CHANGED
|
@@ -1,383 +1,398 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
const { spawn } = require('node:child_process');
|
|
3
|
-
let spawnChild = spawn;
|
|
4
|
-
|
|
5
|
-
const SERVER_INFO = { name: 'viberaven-mcp', version: '1.0.
|
|
6
|
-
const CLI_PACKAGE = '@viberaven/cli';
|
|
7
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const { spawn } = require('node:child_process');
|
|
3
|
+
let spawnChild = spawn;
|
|
4
|
+
|
|
5
|
+
const SERVER_INFO = { name: 'viberaven-mcp', version: '1.0.7' };
|
|
6
|
+
const CLI_PACKAGE = '@viberaven/cli';
|
|
7
|
+
|
|
8
8
|
const cwdSchema = {
|
|
9
9
|
type: 'object',
|
|
10
10
|
properties: {
|
|
11
|
-
cwd: { type: 'string', description: 'Project root. Defaults to the MCP server working directory.' }
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
type: 'object',
|
|
18
|
-
properties: {
|
|
19
|
-
cwd: { type: 'string' },
|
|
20
|
-
target: { type: 'string' },
|
|
21
|
-
gap: { type: 'string' },
|
|
22
|
-
yes: { type: 'boolean' }
|
|
11
|
+
cwd: { type: 'string', description: 'Project root. Defaults to the MCP server working directory.' },
|
|
12
|
+
launchMode: {
|
|
13
|
+
type: 'string',
|
|
14
|
+
enum: ['manual', 'ask', 'safe', 'full'],
|
|
15
|
+
description: 'Launch Autopilot permission mode. Defaults to ask.'
|
|
16
|
+
}
|
|
23
17
|
},
|
|
24
18
|
additionalProperties: false
|
|
25
19
|
};
|
|
26
|
-
|
|
27
|
-
const
|
|
20
|
+
|
|
21
|
+
const healSchema = {
|
|
22
|
+
type: 'object',
|
|
23
|
+
properties: {
|
|
24
|
+
cwd: { type: 'string' },
|
|
25
|
+
target: { type: 'string' },
|
|
26
|
+
gap: { type: 'string' },
|
|
27
|
+
yes: { type: 'boolean' }
|
|
28
|
+
},
|
|
29
|
+
additionalProperties: false
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const TOOLS = [
|
|
28
33
|
{
|
|
29
34
|
name: 'viberaven_check_readiness',
|
|
30
|
-
description:
|
|
31
|
-
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
name: 'viberaven_verify',
|
|
35
|
-
description: 'Rescan and refresh VibeRaven production-readiness artifacts after a fix.',
|
|
36
|
-
inputSchema: cwdSchema
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
name: 'viberaven_audit',
|
|
40
|
-
description: 'Run local Vercel/Supabase production checks for RLS, service-role boundaries, and Vercel pooler usage.',
|
|
41
|
-
inputSchema: {
|
|
42
|
-
type: 'object',
|
|
43
|
-
properties: {
|
|
44
|
-
cwd: { type: 'string', description: 'Project root. Defaults to current working directory.' },
|
|
45
|
-
json: { type: 'boolean', description: 'Return JSON output.' }
|
|
46
|
-
},
|
|
47
|
-
additionalProperties: false
|
|
48
|
-
}
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
name: 'viberaven_init_rules',
|
|
52
|
-
description: 'Install bounded VibeRaven rules into native AI instruction files.',
|
|
53
|
-
inputSchema: {
|
|
54
|
-
type: 'object',
|
|
55
|
-
properties: {
|
|
56
|
-
cwd: { type: 'string', description: 'Project root. Defaults to current working directory.' },
|
|
57
|
-
agents: { type: 'string', description: 'Comma-separated agent targets, or all.' },
|
|
58
|
-
dryRun: { type: 'boolean', description: 'Preview changes without writing files.' }
|
|
59
|
-
},
|
|
60
|
-
additionalProperties: false
|
|
61
|
-
}
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
name: 'viberaven_clean_plan',
|
|
65
|
-
description: 'Write a non-destructive context cleanup plan for generated artifacts and logs.',
|
|
66
|
-
inputSchema: cwdSchema
|
|
67
|
-
},
|
|
68
|
-
{
|
|
69
|
-
name: 'viberaven_strict_gate',
|
|
70
|
-
description: 'Run VibeRaven agent-mode strict gate and return the machine verdict.',
|
|
71
|
-
inputSchema: cwdSchema
|
|
72
|
-
},
|
|
73
|
-
{
|
|
74
|
-
name: 'viberaven_gate_result',
|
|
75
|
-
description: 'Run VibeRaven agent-mode JSON output and return gate-result.json content.',
|
|
76
|
-
inputSchema: cwdSchema
|
|
77
|
-
},
|
|
78
|
-
{
|
|
79
|
-
name: 'viberaven_context_map',
|
|
80
|
-
description: 'Refresh .viberaven/context-map.json from the last scan.',
|
|
35
|
+
description:
|
|
36
|
+
'Run VibeRaven agent-mode production-readiness and Launch Autopilot; writes .viberaven artifacts and one next launch action.',
|
|
81
37
|
inputSchema: cwdSchema
|
|
82
38
|
},
|
|
83
|
-
{
|
|
84
|
-
name: '
|
|
85
|
-
description: '
|
|
86
|
-
inputSchema:
|
|
87
|
-
},
|
|
88
|
-
{
|
|
89
|
-
name: '
|
|
90
|
-
description: '
|
|
91
|
-
inputSchema:
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
const
|
|
196
|
-
const
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
39
|
+
{
|
|
40
|
+
name: 'viberaven_verify',
|
|
41
|
+
description: 'Rescan and refresh VibeRaven production-readiness artifacts after a fix.',
|
|
42
|
+
inputSchema: cwdSchema
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: 'viberaven_audit',
|
|
46
|
+
description: 'Run local Vercel/Supabase production checks for RLS, service-role boundaries, and Vercel pooler usage.',
|
|
47
|
+
inputSchema: {
|
|
48
|
+
type: 'object',
|
|
49
|
+
properties: {
|
|
50
|
+
cwd: { type: 'string', description: 'Project root. Defaults to current working directory.' },
|
|
51
|
+
json: { type: 'boolean', description: 'Return JSON output.' }
|
|
52
|
+
},
|
|
53
|
+
additionalProperties: false
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: 'viberaven_init_rules',
|
|
58
|
+
description: 'Install bounded VibeRaven rules into native AI instruction files.',
|
|
59
|
+
inputSchema: {
|
|
60
|
+
type: 'object',
|
|
61
|
+
properties: {
|
|
62
|
+
cwd: { type: 'string', description: 'Project root. Defaults to current working directory.' },
|
|
63
|
+
agents: { type: 'string', description: 'Comma-separated agent targets, or all.' },
|
|
64
|
+
dryRun: { type: 'boolean', description: 'Preview changes without writing files.' }
|
|
65
|
+
},
|
|
66
|
+
additionalProperties: false
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
name: 'viberaven_clean_plan',
|
|
71
|
+
description: 'Write a non-destructive context cleanup plan for generated artifacts and logs.',
|
|
72
|
+
inputSchema: cwdSchema
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
name: 'viberaven_strict_gate',
|
|
76
|
+
description: 'Run VibeRaven agent-mode strict gate and return the machine verdict.',
|
|
77
|
+
inputSchema: cwdSchema
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
name: 'viberaven_gate_result',
|
|
81
|
+
description: 'Run VibeRaven agent-mode JSON output and return gate-result.json content.',
|
|
82
|
+
inputSchema: cwdSchema
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
name: 'viberaven_context_map',
|
|
86
|
+
description: 'Refresh .viberaven/context-map.json from the last scan.',
|
|
87
|
+
inputSchema: cwdSchema
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
name: 'viberaven_heal_plan',
|
|
91
|
+
description: 'Write a non-destructive VibeRaven heal plan for a target file or gap.',
|
|
92
|
+
inputSchema: healSchema
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
name: 'viberaven_heal_prompt',
|
|
96
|
+
description: 'Write an agent-ready VibeRaven heal prompt for a target file or gap.',
|
|
97
|
+
inputSchema: healSchema
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
name: 'viberaven_heal_apply',
|
|
101
|
+
description: 'Apply a guarded VibeRaven repo-code heal recipe when supported.',
|
|
102
|
+
inputSchema: healSchema
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
name: 'viberaven_validate_npm_package',
|
|
106
|
+
description:
|
|
107
|
+
'Check whether an npm package name exists and looks safe before install. Always run viberaven --agent-mode after adding dependencies.',
|
|
108
|
+
inputSchema: {
|
|
109
|
+
type: 'object',
|
|
110
|
+
properties: {
|
|
111
|
+
packageName: { type: 'string', description: 'Single npm package name to validate.' },
|
|
112
|
+
packageNames: {
|
|
113
|
+
type: 'array',
|
|
114
|
+
items: { type: 'string' },
|
|
115
|
+
description: 'Multiple npm package names to validate in one call.'
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
additionalProperties: false
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
];
|
|
122
|
+
|
|
123
|
+
let buffer = Buffer.alloc(0);
|
|
124
|
+
|
|
125
|
+
function main() {
|
|
126
|
+
if (process.argv.includes('--help') || process.argv.includes('-h')) {
|
|
127
|
+
console.log(`${SERVER_INFO.name} ${SERVER_INFO.version}`);
|
|
128
|
+
console.log(`MCP stdio server wrapping npx -y ${CLI_PACKAGE}.`);
|
|
129
|
+
process.exit(0);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
process.stdin.on('data', (chunk) => {
|
|
133
|
+
buffer = Buffer.concat([buffer, chunk]);
|
|
134
|
+
drainMessages();
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function drainMessages() {
|
|
139
|
+
while (true) {
|
|
140
|
+
const headerEnd = buffer.indexOf('\r\n\r\n');
|
|
141
|
+
if (headerEnd === -1) return;
|
|
142
|
+
|
|
143
|
+
const header = buffer.slice(0, headerEnd).toString('utf8');
|
|
144
|
+
const match = header.match(/content-length:\s*(\d+)/i);
|
|
145
|
+
if (!match) {
|
|
146
|
+
buffer = buffer.slice(headerEnd + 4);
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const length = Number(match[1]);
|
|
151
|
+
const messageStart = headerEnd + 4;
|
|
152
|
+
const messageEnd = messageStart + length;
|
|
153
|
+
if (buffer.length < messageEnd) return;
|
|
154
|
+
|
|
155
|
+
const raw = buffer.slice(messageStart, messageEnd).toString('utf8');
|
|
156
|
+
buffer = buffer.slice(messageEnd);
|
|
157
|
+
void handleRawMessage(raw);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
async function handleRawMessage(raw) {
|
|
162
|
+
let message;
|
|
163
|
+
try {
|
|
164
|
+
message = JSON.parse(raw);
|
|
165
|
+
} catch {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (!message || typeof message.method !== 'string') return;
|
|
170
|
+
if (message.id === undefined || message.id === null) return;
|
|
171
|
+
|
|
172
|
+
try {
|
|
173
|
+
const result = await handleRequest(message.method, message.params || {});
|
|
174
|
+
send({ jsonrpc: '2.0', id: message.id, result });
|
|
175
|
+
} catch (error) {
|
|
176
|
+
send({
|
|
177
|
+
jsonrpc: '2.0',
|
|
178
|
+
id: message.id,
|
|
179
|
+
error: {
|
|
180
|
+
code: -32000,
|
|
181
|
+
message: error instanceof Error ? error.message : String(error)
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
async function handleRequest(method, params) {
|
|
188
|
+
if (method === 'initialize') {
|
|
189
|
+
return {
|
|
190
|
+
protocolVersion: params.protocolVersion || '2024-11-05',
|
|
191
|
+
capabilities: { tools: {} },
|
|
192
|
+
serverInfo: SERVER_INFO
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (method === 'tools/list') {
|
|
197
|
+
return { tools: TOOLS };
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (method === 'tools/call') {
|
|
201
|
+
const name = params.name;
|
|
202
|
+
const args = params.arguments || {};
|
|
203
|
+
const text = await callTool(name, args);
|
|
204
|
+
const parsed = parseJsonObjectFromToolText(text);
|
|
205
|
+
return {
|
|
206
|
+
content: [{ type: 'text', text }],
|
|
207
|
+
...(parsed ? { structuredContent: parsed } : {})
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
throw new Error(`Unsupported MCP method: ${method}`);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
async function callTool(name, args) {
|
|
215
|
+
return runVibeRaven(['-y', CLI_PACKAGE, ...buildToolArgs(name, args || {})], args && args.cwd);
|
|
216
|
+
}
|
|
217
|
+
|
|
212
218
|
function buildToolArgs(name, args) {
|
|
213
219
|
if (name === 'viberaven_check_readiness') {
|
|
214
|
-
return ['--agent-mode'];
|
|
215
|
-
}
|
|
216
|
-
if (name === 'viberaven_verify') {
|
|
217
|
-
return ['--verify'];
|
|
218
|
-
}
|
|
219
|
-
if (name === 'viberaven_audit') {
|
|
220
|
-
return ['audit', '--vercel-supabase', ...(args.json ? ['--json'] : [])];
|
|
221
|
-
}
|
|
222
|
-
if (name === 'viberaven_init_rules') {
|
|
223
|
-
const cliArgs = ['init'];
|
|
224
|
-
if (args.agents) cliArgs.push('--agents', safeStringArg(args.agents, 'agents'));
|
|
225
|
-
if (args.dryRun) cliArgs.push('--dry-run');
|
|
226
|
-
return cliArgs;
|
|
227
|
-
}
|
|
228
|
-
if (name === 'viberaven_clean_plan') {
|
|
229
|
-
return ['clean', '--plan'];
|
|
230
|
-
}
|
|
231
|
-
if (name === 'viberaven_strict_gate') {
|
|
232
|
-
return ['--agent-mode', '--strict', '--json'];
|
|
233
|
-
}
|
|
234
|
-
if (name === 'viberaven_gate_result') {
|
|
235
|
-
return ['--agent-mode', '--json'];
|
|
236
|
-
}
|
|
237
|
-
if (name === 'viberaven_context_map') {
|
|
238
|
-
return ['--condense'];
|
|
239
|
-
}
|
|
240
|
-
if (name === 'viberaven_heal_plan') {
|
|
241
|
-
return buildHealArgs(['--heal', '--plan'], args);
|
|
242
|
-
}
|
|
243
|
-
if (name === 'viberaven_heal_prompt') {
|
|
244
|
-
return buildHealArgs(['--heal', '--prompt'], args);
|
|
245
|
-
}
|
|
246
|
-
if (name === 'viberaven_heal_apply') {
|
|
247
|
-
const cliArgs = buildHealArgs(['--heal', '--apply'], args);
|
|
248
|
-
if (args.yes === true) cliArgs.push('--yes');
|
|
249
|
-
return cliArgs;
|
|
250
|
-
}
|
|
251
|
-
if (name === 'viberaven_validate_npm_package') {
|
|
252
|
-
const names = [];
|
|
253
|
-
if (args.packageName) {
|
|
254
|
-
names.push(safeStringArg(args.packageName, 'packageName'));
|
|
255
|
-
}
|
|
256
|
-
if (Array.isArray(args.packageNames)) {
|
|
257
|
-
for (const entry of args.packageNames) {
|
|
258
|
-
names.push(safeStringArg(entry, 'packageName'));
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
if (names.length === 0) {
|
|
262
|
-
throw new Error('packageName or packageNames is required');
|
|
263
|
-
}
|
|
264
|
-
return ['validate-npm-package', '--json', ...names];
|
|
265
|
-
}
|
|
266
|
-
throw new Error(`Unknown VibeRaven tool: ${name}`);
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
function buildHealArgs(prefix, args) {
|
|
270
|
-
const cliArgs = [...prefix];
|
|
271
|
-
if (args.target) cliArgs.push('--target', safeStringArg(args.target, 'target'));
|
|
272
|
-
if (args.gap) cliArgs.push('--gap', safeStringArg(args.gap, 'gap'));
|
|
273
|
-
return cliArgs;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
function safeStringArg(value, label) {
|
|
277
|
-
if (typeof value !== 'string') {
|
|
278
|
-
throw new Error(`Invalid ${label}: expected string`);
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
if (!value.trim()) {
|
|
282
|
-
throw new Error(`Invalid ${label}: expected non-empty string`);
|
|
220
|
+
return ['--agent-mode', ...launchModeArgs(args)];
|
|
283
221
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
222
|
+
if (name === 'viberaven_verify') {
|
|
223
|
+
return ['--verify'];
|
|
224
|
+
}
|
|
225
|
+
if (name === 'viberaven_audit') {
|
|
226
|
+
return ['audit', '--vercel-supabase', ...(args.json ? ['--json'] : [])];
|
|
227
|
+
}
|
|
228
|
+
if (name === 'viberaven_init_rules') {
|
|
229
|
+
const cliArgs = ['init'];
|
|
230
|
+
if (args.agents) cliArgs.push('--agents', safeStringArg(args.agents, 'agents'));
|
|
231
|
+
if (args.dryRun) cliArgs.push('--dry-run');
|
|
232
|
+
return cliArgs;
|
|
233
|
+
}
|
|
234
|
+
if (name === 'viberaven_clean_plan') {
|
|
235
|
+
return ['clean', '--plan'];
|
|
236
|
+
}
|
|
237
|
+
if (name === 'viberaven_strict_gate') {
|
|
238
|
+
return ['--agent-mode', '--strict', '--json'];
|
|
239
|
+
}
|
|
240
|
+
if (name === 'viberaven_gate_result') {
|
|
241
|
+
return ['--agent-mode', '--json'];
|
|
242
|
+
}
|
|
243
|
+
if (name === 'viberaven_context_map') {
|
|
244
|
+
return ['--condense'];
|
|
245
|
+
}
|
|
246
|
+
if (name === 'viberaven_heal_plan') {
|
|
247
|
+
return buildHealArgs(['--heal', '--plan'], args);
|
|
248
|
+
}
|
|
249
|
+
if (name === 'viberaven_heal_prompt') {
|
|
250
|
+
return buildHealArgs(['--heal', '--prompt'], args);
|
|
251
|
+
}
|
|
252
|
+
if (name === 'viberaven_heal_apply') {
|
|
253
|
+
const cliArgs = buildHealArgs(['--heal', '--apply'], args);
|
|
254
|
+
if (args.yes === true) cliArgs.push('--yes');
|
|
255
|
+
return cliArgs;
|
|
256
|
+
}
|
|
257
|
+
if (name === 'viberaven_validate_npm_package') {
|
|
258
|
+
const names = [];
|
|
259
|
+
if (args.packageName) {
|
|
260
|
+
names.push(safeStringArg(args.packageName, 'packageName'));
|
|
261
|
+
}
|
|
262
|
+
if (Array.isArray(args.packageNames)) {
|
|
263
|
+
for (const entry of args.packageNames) {
|
|
264
|
+
names.push(safeStringArg(entry, 'packageName'));
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
if (names.length === 0) {
|
|
268
|
+
throw new Error('packageName or packageNames is required');
|
|
269
|
+
}
|
|
270
|
+
return ['validate-npm-package', '--json', ...names];
|
|
271
|
+
}
|
|
272
|
+
throw new Error(`Unknown VibeRaven tool: ${name}`);
|
|
290
273
|
}
|
|
291
274
|
|
|
292
|
-
function
|
|
293
|
-
if (
|
|
294
|
-
|
|
275
|
+
function launchModeArgs(args) {
|
|
276
|
+
if (!args.launchMode) return [];
|
|
277
|
+
const allowed = new Set(['manual', 'ask', 'safe', 'full']);
|
|
278
|
+
if (!allowed.has(args.launchMode)) {
|
|
279
|
+
throw new Error('Invalid launchMode');
|
|
295
280
|
}
|
|
296
|
-
|
|
297
|
-
if (typeof cwd !== 'string') {
|
|
298
|
-
throw new Error('Invalid cwd: expected string');
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
if (!cwd.trim()) {
|
|
302
|
-
throw new Error('Invalid cwd: expected non-empty string');
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
return cwd;
|
|
281
|
+
return ['--launch-mode', args.launchMode];
|
|
306
282
|
}
|
|
307
|
-
|
|
308
|
-
function
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
283
|
+
|
|
284
|
+
function buildHealArgs(prefix, args) {
|
|
285
|
+
const cliArgs = [...prefix];
|
|
286
|
+
if (args.target) cliArgs.push('--target', safeStringArg(args.target, 'target'));
|
|
287
|
+
if (args.gap) cliArgs.push('--gap', safeStringArg(args.gap, 'gap'));
|
|
288
|
+
return cliArgs;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
function safeStringArg(value, label) {
|
|
292
|
+
if (typeof value !== 'string') {
|
|
293
|
+
throw new Error(`Invalid ${label}: expected string`);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
if (!value.trim()) {
|
|
297
|
+
throw new Error(`Invalid ${label}: expected non-empty string`);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
if (/[&|<>^%!"\r\n]/.test(value)) {
|
|
301
|
+
throw new Error(`Unsafe characters in ${label}`);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
return value;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function resolveCwd(cwd) {
|
|
308
|
+
if (cwd === undefined || cwd === null) {
|
|
309
|
+
return process.cwd();
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (typeof cwd !== 'string') {
|
|
313
|
+
throw new Error('Invalid cwd: expected string');
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (!cwd.trim()) {
|
|
317
|
+
throw new Error('Invalid cwd: expected non-empty string');
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
return cwd;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function buildNpxCommand(args) {
|
|
324
|
+
if (process.platform === 'win32') {
|
|
325
|
+
return {
|
|
326
|
+
command: 'cmd.exe',
|
|
327
|
+
args: ['/d', '/s', '/c', 'npx', ...args],
|
|
328
|
+
options: { shell: false }
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
return {
|
|
333
|
+
command: 'npx',
|
|
334
|
+
args,
|
|
335
|
+
options: { shell: false }
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
function runVibeRaven(args, cwd) {
|
|
340
|
+
return new Promise((resolve) => {
|
|
341
|
+
const built = buildNpxCommand(args);
|
|
342
|
+
const child = spawnChild(built.command, built.args, {
|
|
343
|
+
cwd: resolveCwd(cwd),
|
|
344
|
+
env: process.env,
|
|
345
|
+
shell: built.options.shell,
|
|
346
|
+
stdio: ['ignore', 'pipe', 'pipe']
|
|
347
|
+
});
|
|
348
|
+
let stdout = '';
|
|
349
|
+
let stderr = '';
|
|
350
|
+
child.stdout.on('data', (chunk) => {
|
|
351
|
+
stdout += chunk.toString();
|
|
352
|
+
});
|
|
353
|
+
child.stderr.on('data', (chunk) => {
|
|
354
|
+
stderr += chunk.toString();
|
|
355
|
+
});
|
|
356
|
+
child.on('error', (error) => {
|
|
357
|
+
resolve(`ERROR: ${error.message}`);
|
|
358
|
+
});
|
|
359
|
+
child.on('close', (code) => {
|
|
360
|
+
const combined = `${stdout}${stderr}`.trim();
|
|
361
|
+
resolve(`exit ${code ?? 1}${combined ? `\n${combined}` : ''}`);
|
|
362
|
+
});
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
function parseJsonObjectFromToolText(text) {
|
|
367
|
+
const jsonStart = text.indexOf('{');
|
|
368
|
+
if (jsonStart === -1) return undefined;
|
|
369
|
+
try {
|
|
370
|
+
return JSON.parse(text.slice(jsonStart));
|
|
371
|
+
} catch {
|
|
372
|
+
return undefined;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
function send(message) {
|
|
377
|
+
const body = JSON.stringify(message);
|
|
378
|
+
process.stdout.write(`Content-Length: ${Buffer.byteLength(body, 'utf8')}\r\n\r\n${body}`);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
if (require.main === module) {
|
|
382
|
+
main();
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
module.exports = {
|
|
386
|
+
TOOLS,
|
|
387
|
+
buildNpxCommand,
|
|
388
|
+
callTool,
|
|
389
|
+
handleRequest,
|
|
390
|
+
parseJsonObjectFromToolText,
|
|
391
|
+
safeStringArg,
|
|
392
|
+
__setSpawnForTest(spawnForTest) {
|
|
393
|
+
spawnChild = spawnForTest;
|
|
394
|
+
},
|
|
395
|
+
__resetSpawnForTest() {
|
|
396
|
+
spawnChild = spawn;
|
|
397
|
+
}
|
|
398
|
+
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@viberaven/mcp",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.0.7",
|
|
4
|
+
"description": "MCP server for VibeRaven production-readiness: check_readiness, verify, heal, audit, and strict gate tools for Cursor, Claude Code, and Codex.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"author": "VibeRaven",
|
|
7
7
|
"mcpName": "io.github.ohad6k/viberaven",
|