@viberaven/mcp 1.1.8 → 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 +1 -0
- package/dist/lib/attribution.js +35 -0
- package/dist/lib/cli-runner.js +150 -0
- package/dist/server.js +342 -0
- package/dist/tools/index.js +331 -0
- package/package.json +15 -3
- package/bin/server.js +0 -407
- package/bin/viberaven-mcp.js +0 -175
package/bin/server.js
DELETED
|
@@ -1,407 +0,0 @@
|
|
|
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.1.7' };
|
|
6
|
-
const CLI_PACKAGE = '@viberaven/cli';
|
|
7
|
-
|
|
8
|
-
const cwdSchema = {
|
|
9
|
-
type: 'object',
|
|
10
|
-
properties: {
|
|
11
|
-
cwd: { type: 'string', description: 'Project root. Defaults to the MCP server working directory.' }
|
|
12
|
-
},
|
|
13
|
-
additionalProperties: false
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
const healSchema = {
|
|
17
|
-
type: 'object',
|
|
18
|
-
properties: {
|
|
19
|
-
cwd: { type: 'string' },
|
|
20
|
-
target: { type: 'string' },
|
|
21
|
-
gap: { type: 'string' },
|
|
22
|
-
yes: { type: 'boolean' }
|
|
23
|
-
},
|
|
24
|
-
additionalProperties: false
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
const TOOLS = [
|
|
28
|
-
{
|
|
29
|
-
name: 'viberaven_check_readiness',
|
|
30
|
-
description: 'Run the VibeRaven agent-mode production-readiness check and write .viberaven artifacts.',
|
|
31
|
-
inputSchema: cwdSchema
|
|
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.',
|
|
81
|
-
inputSchema: cwdSchema
|
|
82
|
-
},
|
|
83
|
-
{
|
|
84
|
-
name: 'viberaven_actions',
|
|
85
|
-
description: 'Read the current VibeRaven chat-native action surface from .viberaven/actions.json.',
|
|
86
|
-
inputSchema: cwdSchema
|
|
87
|
-
},
|
|
88
|
-
{
|
|
89
|
-
name: 'viberaven_verify_action',
|
|
90
|
-
description: 'Verify or explain the lifecycle state for a stable VibeRaven action ID.',
|
|
91
|
-
inputSchema: {
|
|
92
|
-
type: 'object',
|
|
93
|
-
properties: {
|
|
94
|
-
cwd: { type: 'string' },
|
|
95
|
-
actionId: { type: 'string' }
|
|
96
|
-
},
|
|
97
|
-
required: ['actionId'],
|
|
98
|
-
additionalProperties: false
|
|
99
|
-
}
|
|
100
|
-
},
|
|
101
|
-
{
|
|
102
|
-
name: 'viberaven_heal_plan',
|
|
103
|
-
description: 'Write a non-destructive VibeRaven heal plan for a target file or gap.',
|
|
104
|
-
inputSchema: healSchema
|
|
105
|
-
},
|
|
106
|
-
{
|
|
107
|
-
name: 'viberaven_heal_prompt',
|
|
108
|
-
description: 'Write an agent-ready VibeRaven heal prompt for a target file or gap.',
|
|
109
|
-
inputSchema: healSchema
|
|
110
|
-
},
|
|
111
|
-
{
|
|
112
|
-
name: 'viberaven_heal_apply',
|
|
113
|
-
description: 'Apply a guarded VibeRaven repo-code heal recipe when supported.',
|
|
114
|
-
inputSchema: healSchema
|
|
115
|
-
},
|
|
116
|
-
{
|
|
117
|
-
name: 'viberaven_validate_npm_package',
|
|
118
|
-
description:
|
|
119
|
-
'Check whether an npm package name exists and looks safe before install. Always run viberaven --agent-mode after adding dependencies.',
|
|
120
|
-
inputSchema: {
|
|
121
|
-
type: 'object',
|
|
122
|
-
properties: {
|
|
123
|
-
packageName: { type: 'string', description: 'Single npm package name to validate.' },
|
|
124
|
-
packageNames: {
|
|
125
|
-
type: 'array',
|
|
126
|
-
items: { type: 'string' },
|
|
127
|
-
description: 'Multiple npm package names to validate in one call.'
|
|
128
|
-
}
|
|
129
|
-
},
|
|
130
|
-
additionalProperties: false
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
];
|
|
134
|
-
|
|
135
|
-
let buffer = Buffer.alloc(0);
|
|
136
|
-
|
|
137
|
-
function main() {
|
|
138
|
-
if (process.argv.includes('--help') || process.argv.includes('-h')) {
|
|
139
|
-
console.log(`${SERVER_INFO.name} ${SERVER_INFO.version}`);
|
|
140
|
-
console.log(`MCP stdio server wrapping npx -y ${CLI_PACKAGE}.`);
|
|
141
|
-
process.exit(0);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
process.stdin.on('data', (chunk) => {
|
|
145
|
-
buffer = Buffer.concat([buffer, chunk]);
|
|
146
|
-
drainMessages();
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
function drainMessages() {
|
|
151
|
-
while (true) {
|
|
152
|
-
const headerEnd = buffer.indexOf('\r\n\r\n');
|
|
153
|
-
if (headerEnd === -1) return;
|
|
154
|
-
|
|
155
|
-
const header = buffer.slice(0, headerEnd).toString('utf8');
|
|
156
|
-
const match = header.match(/content-length:\s*(\d+)/i);
|
|
157
|
-
if (!match) {
|
|
158
|
-
buffer = buffer.slice(headerEnd + 4);
|
|
159
|
-
continue;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
const length = Number(match[1]);
|
|
163
|
-
const messageStart = headerEnd + 4;
|
|
164
|
-
const messageEnd = messageStart + length;
|
|
165
|
-
if (buffer.length < messageEnd) return;
|
|
166
|
-
|
|
167
|
-
const raw = buffer.slice(messageStart, messageEnd).toString('utf8');
|
|
168
|
-
buffer = buffer.slice(messageEnd);
|
|
169
|
-
void handleRawMessage(raw);
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
async function handleRawMessage(raw) {
|
|
174
|
-
let message;
|
|
175
|
-
try {
|
|
176
|
-
message = JSON.parse(raw);
|
|
177
|
-
} catch {
|
|
178
|
-
return;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
if (!message || typeof message.method !== 'string') return;
|
|
182
|
-
if (message.id === undefined || message.id === null) return;
|
|
183
|
-
|
|
184
|
-
try {
|
|
185
|
-
const result = await handleRequest(message.method, message.params || {});
|
|
186
|
-
send({ jsonrpc: '2.0', id: message.id, result });
|
|
187
|
-
} catch (error) {
|
|
188
|
-
send({
|
|
189
|
-
jsonrpc: '2.0',
|
|
190
|
-
id: message.id,
|
|
191
|
-
error: {
|
|
192
|
-
code: -32000,
|
|
193
|
-
message: error instanceof Error ? error.message : String(error)
|
|
194
|
-
}
|
|
195
|
-
});
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
async function handleRequest(method, params) {
|
|
200
|
-
if (method === 'initialize') {
|
|
201
|
-
return {
|
|
202
|
-
protocolVersion: params.protocolVersion || '2024-11-05',
|
|
203
|
-
capabilities: { tools: {} },
|
|
204
|
-
serverInfo: SERVER_INFO
|
|
205
|
-
};
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
if (method === 'tools/list') {
|
|
209
|
-
return { tools: TOOLS };
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
if (method === 'tools/call') {
|
|
213
|
-
const name = params.name;
|
|
214
|
-
const args = params.arguments || {};
|
|
215
|
-
const text = await callTool(name, args);
|
|
216
|
-
const parsed = parseJsonObjectFromToolText(text);
|
|
217
|
-
return {
|
|
218
|
-
content: [{ type: 'text', text }],
|
|
219
|
-
...(parsed ? { structuredContent: parsed } : {})
|
|
220
|
-
};
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
throw new Error(`Unsupported MCP method: ${method}`);
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
async function callTool(name, args) {
|
|
227
|
-
return runVibeRaven(['-y', CLI_PACKAGE, ...buildToolArgs(name, args || {})], args && args.cwd);
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
function buildToolArgs(name, args) {
|
|
231
|
-
if (name === 'viberaven_check_readiness') {
|
|
232
|
-
return ['--agent-mode'];
|
|
233
|
-
}
|
|
234
|
-
if (name === 'viberaven_verify') {
|
|
235
|
-
return ['--verify'];
|
|
236
|
-
}
|
|
237
|
-
if (name === 'viberaven_audit') {
|
|
238
|
-
return ['audit', '--vercel-supabase', ...(args.json ? ['--json'] : [])];
|
|
239
|
-
}
|
|
240
|
-
if (name === 'viberaven_init_rules') {
|
|
241
|
-
const cliArgs = ['init'];
|
|
242
|
-
if (args.agents) cliArgs.push('--agents', safeStringArg(args.agents, 'agents'));
|
|
243
|
-
if (args.dryRun) cliArgs.push('--dry-run');
|
|
244
|
-
return cliArgs;
|
|
245
|
-
}
|
|
246
|
-
if (name === 'viberaven_clean_plan') {
|
|
247
|
-
return ['clean', '--plan'];
|
|
248
|
-
}
|
|
249
|
-
if (name === 'viberaven_strict_gate') {
|
|
250
|
-
return ['--agent-mode', '--strict', '--json'];
|
|
251
|
-
}
|
|
252
|
-
if (name === 'viberaven_gate_result') {
|
|
253
|
-
return ['--agent-mode', '--json'];
|
|
254
|
-
}
|
|
255
|
-
if (name === 'viberaven_context_map') {
|
|
256
|
-
return ['--condense'];
|
|
257
|
-
}
|
|
258
|
-
if (name === 'viberaven_actions') {
|
|
259
|
-
return ['actions'];
|
|
260
|
-
}
|
|
261
|
-
if (name === 'viberaven_verify_action') {
|
|
262
|
-
return ['--verify', '--action', safeStringArg(args.actionId, 'actionId')];
|
|
263
|
-
}
|
|
264
|
-
if (name === 'viberaven_heal_plan') {
|
|
265
|
-
return buildHealArgs(['--heal', '--plan'], args);
|
|
266
|
-
}
|
|
267
|
-
if (name === 'viberaven_heal_prompt') {
|
|
268
|
-
return buildHealArgs(['--heal', '--prompt'], args);
|
|
269
|
-
}
|
|
270
|
-
if (name === 'viberaven_heal_apply') {
|
|
271
|
-
const cliArgs = buildHealArgs(['--heal', '--apply'], args);
|
|
272
|
-
if (args.yes === true) cliArgs.push('--yes');
|
|
273
|
-
return cliArgs;
|
|
274
|
-
}
|
|
275
|
-
if (name === 'viberaven_validate_npm_package') {
|
|
276
|
-
const names = [];
|
|
277
|
-
if (args.packageName) {
|
|
278
|
-
names.push(safeStringArg(args.packageName, 'packageName'));
|
|
279
|
-
}
|
|
280
|
-
if (Array.isArray(args.packageNames)) {
|
|
281
|
-
for (const entry of args.packageNames) {
|
|
282
|
-
names.push(safeStringArg(entry, 'packageName'));
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
if (names.length === 0) {
|
|
286
|
-
throw new Error('packageName or packageNames is required');
|
|
287
|
-
}
|
|
288
|
-
return ['validate-npm-package', '--json', ...names];
|
|
289
|
-
}
|
|
290
|
-
throw new Error(`Unknown VibeRaven tool: ${name}`);
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
function buildHealArgs(prefix, args) {
|
|
294
|
-
const cliArgs = [...prefix];
|
|
295
|
-
if (args.target) cliArgs.push('--target', safeStringArg(args.target, 'target'));
|
|
296
|
-
if (args.gap) cliArgs.push('--gap', safeStringArg(args.gap, 'gap'));
|
|
297
|
-
return cliArgs;
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
function safeStringArg(value, label) {
|
|
301
|
-
if (typeof value !== 'string') {
|
|
302
|
-
throw new Error(`Invalid ${label}: expected string`);
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
if (!value.trim()) {
|
|
306
|
-
throw new Error(`Invalid ${label}: expected non-empty string`);
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
if (/[&|<>^%!"\r\n]/.test(value)) {
|
|
310
|
-
throw new Error(`Unsafe characters in ${label}`);
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
return value;
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
function resolveCwd(cwd) {
|
|
317
|
-
if (cwd === undefined || cwd === null) {
|
|
318
|
-
return process.cwd();
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
if (typeof cwd !== 'string') {
|
|
322
|
-
throw new Error('Invalid cwd: expected string');
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
if (!cwd.trim()) {
|
|
326
|
-
throw new Error('Invalid cwd: expected non-empty string');
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
return cwd;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
function buildNpxCommand(args) {
|
|
333
|
-
if (process.platform === 'win32') {
|
|
334
|
-
return {
|
|
335
|
-
command: 'cmd.exe',
|
|
336
|
-
args: ['/d', '/s', '/c', 'npx', ...args],
|
|
337
|
-
options: { shell: false }
|
|
338
|
-
};
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
return {
|
|
342
|
-
command: 'npx',
|
|
343
|
-
args,
|
|
344
|
-
options: { shell: false }
|
|
345
|
-
};
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
function runVibeRaven(args, cwd) {
|
|
349
|
-
return new Promise((resolve) => {
|
|
350
|
-
const built = buildNpxCommand(args);
|
|
351
|
-
const child = spawnChild(built.command, built.args, {
|
|
352
|
-
cwd: resolveCwd(cwd),
|
|
353
|
-
env: process.env,
|
|
354
|
-
shell: built.options.shell,
|
|
355
|
-
stdio: ['ignore', 'pipe', 'pipe']
|
|
356
|
-
});
|
|
357
|
-
let stdout = '';
|
|
358
|
-
let stderr = '';
|
|
359
|
-
child.stdout.on('data', (chunk) => {
|
|
360
|
-
stdout += chunk.toString();
|
|
361
|
-
});
|
|
362
|
-
child.stderr.on('data', (chunk) => {
|
|
363
|
-
stderr += chunk.toString();
|
|
364
|
-
});
|
|
365
|
-
child.on('error', (error) => {
|
|
366
|
-
resolve(`ERROR: ${error.message}`);
|
|
367
|
-
});
|
|
368
|
-
child.on('close', (code) => {
|
|
369
|
-
const combined = `${stdout}${stderr}`.trim();
|
|
370
|
-
resolve(`exit ${code ?? 1}${combined ? `\n${combined}` : ''}`);
|
|
371
|
-
});
|
|
372
|
-
});
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
function parseJsonObjectFromToolText(text) {
|
|
376
|
-
const jsonStart = text.indexOf('{');
|
|
377
|
-
if (jsonStart === -1) return undefined;
|
|
378
|
-
try {
|
|
379
|
-
return JSON.parse(text.slice(jsonStart));
|
|
380
|
-
} catch {
|
|
381
|
-
return undefined;
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
function send(message) {
|
|
386
|
-
const body = JSON.stringify(message);
|
|
387
|
-
process.stdout.write(`Content-Length: ${Buffer.byteLength(body, 'utf8')}\r\n\r\n${body}`);
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
if (require.main === module) {
|
|
391
|
-
main();
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
module.exports = {
|
|
395
|
-
TOOLS,
|
|
396
|
-
buildNpxCommand,
|
|
397
|
-
callTool,
|
|
398
|
-
handleRequest,
|
|
399
|
-
parseJsonObjectFromToolText,
|
|
400
|
-
safeStringArg,
|
|
401
|
-
__setSpawnForTest(spawnForTest) {
|
|
402
|
-
spawnChild = spawnForTest;
|
|
403
|
-
},
|
|
404
|
-
__resetSpawnForTest() {
|
|
405
|
-
spawnChild = spawn;
|
|
406
|
-
}
|
|
407
|
-
};
|
package/bin/viberaven-mcp.js
DELETED
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
const { spawn } = require('node:child_process');
|
|
3
|
-
const readline = require('node:readline');
|
|
4
|
-
|
|
5
|
-
const serverInfo = {
|
|
6
|
-
name: 'viberaven-mcp',
|
|
7
|
-
version: '0.1.0-beta.0',
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
const tools = [
|
|
11
|
-
{
|
|
12
|
-
name: 'viberaven_scan',
|
|
13
|
-
description: 'Scan an AI-built app for launch-readiness gaps and write .viberaven artifacts.',
|
|
14
|
-
inputSchema: {
|
|
15
|
-
type: 'object',
|
|
16
|
-
properties: {
|
|
17
|
-
cwd: { type: 'string', description: 'Workspace directory to scan. Defaults to the MCP process cwd.' },
|
|
18
|
-
json: { type: 'boolean', description: 'Return CLI JSON output when supported.' },
|
|
19
|
-
},
|
|
20
|
-
},
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
name: 'viberaven_next',
|
|
24
|
-
description: 'Return the next recommended launch-readiness action from the last scan.',
|
|
25
|
-
inputSchema: {
|
|
26
|
-
type: 'object',
|
|
27
|
-
properties: {
|
|
28
|
-
cwd: { type: 'string', description: 'Workspace directory. Defaults to the MCP process cwd.' },
|
|
29
|
-
},
|
|
30
|
-
},
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
name: 'viberaven_prompt',
|
|
34
|
-
description: 'Return a copy-ready coding-agent prompt for a launch gap.',
|
|
35
|
-
inputSchema: {
|
|
36
|
-
type: 'object',
|
|
37
|
-
properties: {
|
|
38
|
-
cwd: { type: 'string', description: 'Workspace directory. Defaults to the MCP process cwd.' },
|
|
39
|
-
gap: { type: 'string', description: 'Gap id from .viberaven/last-scan.json or viberaven_next.' },
|
|
40
|
-
area: { type: 'string', description: 'Optional production area such as auth, database, payments, deployment.' },
|
|
41
|
-
provider: { type: 'string', description: 'Optional provider such as clerk, supabase, stripe, vercel.' },
|
|
42
|
-
},
|
|
43
|
-
},
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
name: 'viberaven_status',
|
|
47
|
-
description: 'Return VibeRaven account and scan quota status.',
|
|
48
|
-
inputSchema: {
|
|
49
|
-
type: 'object',
|
|
50
|
-
properties: {
|
|
51
|
-
cwd: { type: 'string', description: 'Workspace directory. Defaults to the MCP process cwd.' },
|
|
52
|
-
},
|
|
53
|
-
},
|
|
54
|
-
},
|
|
55
|
-
{
|
|
56
|
-
name: 'viberaven_report',
|
|
57
|
-
description: 'Rebuild .viberaven/report.html from the last scan without consuming scan quota.',
|
|
58
|
-
inputSchema: {
|
|
59
|
-
type: 'object',
|
|
60
|
-
properties: {
|
|
61
|
-
cwd: { type: 'string', description: 'Workspace directory. Defaults to the MCP process cwd.' },
|
|
62
|
-
},
|
|
63
|
-
},
|
|
64
|
-
},
|
|
65
|
-
];
|
|
66
|
-
|
|
67
|
-
function write(message) {
|
|
68
|
-
process.stdout.write(`${JSON.stringify(message)}\n`);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function runCli(args, cwd) {
|
|
72
|
-
return new Promise((resolve) => {
|
|
73
|
-
const child = spawn('npx', ['-y', '@viberaven/cli@beta', ...args], {
|
|
74
|
-
cwd: cwd || process.cwd(),
|
|
75
|
-
shell: process.platform === 'win32',
|
|
76
|
-
env: process.env,
|
|
77
|
-
});
|
|
78
|
-
let stdout = '';
|
|
79
|
-
let stderr = '';
|
|
80
|
-
child.stdout.on('data', (chunk) => {
|
|
81
|
-
stdout += chunk.toString();
|
|
82
|
-
});
|
|
83
|
-
child.stderr.on('data', (chunk) => {
|
|
84
|
-
stderr += chunk.toString();
|
|
85
|
-
});
|
|
86
|
-
child.on('close', (code) => {
|
|
87
|
-
resolve({ code, stdout, stderr });
|
|
88
|
-
});
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function textResult(text, isError = false) {
|
|
93
|
-
return {
|
|
94
|
-
content: [{ type: 'text', text: text || '(no output)' }],
|
|
95
|
-
isError,
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
async function callTool(name, input = {}) {
|
|
100
|
-
const cwd = typeof input.cwd === 'string' && input.cwd.trim() ? input.cwd : undefined;
|
|
101
|
-
if (name === 'viberaven_scan') {
|
|
102
|
-
const args = ['scan'];
|
|
103
|
-
if (input.json) args.push('--json');
|
|
104
|
-
const result = await runCli(args, cwd);
|
|
105
|
-
return textResult(`${result.stdout}${result.stderr ? `\n${result.stderr}` : ''}`.trim(), result.code !== 0);
|
|
106
|
-
}
|
|
107
|
-
if (name === 'viberaven_next') {
|
|
108
|
-
const result = await runCli(['next', '--json'], cwd);
|
|
109
|
-
return textResult(`${result.stdout}${result.stderr ? `\n${result.stderr}` : ''}`.trim(), result.code !== 0);
|
|
110
|
-
}
|
|
111
|
-
if (name === 'viberaven_prompt') {
|
|
112
|
-
const args = ['prompt', '--no-copy'];
|
|
113
|
-
if (input.gap) args.push('--gap', String(input.gap));
|
|
114
|
-
if (input.area) args.push('--area', String(input.area));
|
|
115
|
-
if (input.provider) args.push('--provider', String(input.provider));
|
|
116
|
-
const result = await runCli(args, cwd);
|
|
117
|
-
return textResult(`${result.stdout}${result.stderr ? `\n${result.stderr}` : ''}`.trim(), result.code !== 0);
|
|
118
|
-
}
|
|
119
|
-
if (name === 'viberaven_status') {
|
|
120
|
-
const result = await runCli(['status', '--json'], cwd);
|
|
121
|
-
return textResult(`${result.stdout}${result.stderr ? `\n${result.stderr}` : ''}`.trim(), result.code !== 0);
|
|
122
|
-
}
|
|
123
|
-
if (name === 'viberaven_report') {
|
|
124
|
-
const result = await runCli(['report'], cwd);
|
|
125
|
-
return textResult(`${result.stdout}${result.stderr ? `\n${result.stderr}` : ''}`.trim(), result.code !== 0);
|
|
126
|
-
}
|
|
127
|
-
return textResult(`Unknown VibeRaven MCP tool: ${name}`, true);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
const rl = readline.createInterface({ input: process.stdin });
|
|
131
|
-
|
|
132
|
-
rl.on('line', async (line) => {
|
|
133
|
-
if (!line.trim()) return;
|
|
134
|
-
let request;
|
|
135
|
-
try {
|
|
136
|
-
request = JSON.parse(line);
|
|
137
|
-
} catch {
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
if (request.method === 'initialize') {
|
|
142
|
-
write({
|
|
143
|
-
jsonrpc: '2.0',
|
|
144
|
-
id: request.id,
|
|
145
|
-
result: {
|
|
146
|
-
protocolVersion: '2024-11-05',
|
|
147
|
-
capabilities: { tools: {} },
|
|
148
|
-
serverInfo,
|
|
149
|
-
},
|
|
150
|
-
});
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
if (request.method === 'notifications/initialized') {
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
if (request.method === 'tools/list') {
|
|
159
|
-
write({ jsonrpc: '2.0', id: request.id, result: { tools } });
|
|
160
|
-
return;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
if (request.method === 'tools/call') {
|
|
164
|
-
const params = request.params || {};
|
|
165
|
-
const result = await callTool(params.name, params.arguments || {});
|
|
166
|
-
write({ jsonrpc: '2.0', id: request.id, result });
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
write({
|
|
171
|
-
jsonrpc: '2.0',
|
|
172
|
-
id: request.id,
|
|
173
|
-
error: { code: -32601, message: `Method not found: ${request.method}` },
|
|
174
|
-
});
|
|
175
|
-
});
|