polydev-ai 1.0.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 +359 -0
- package/lib/cliManager.js +541 -0
- package/lib/cliManager.ts +428 -0
- package/mcp/manifest.json +462 -0
- package/mcp/package.json +46 -0
- package/mcp/server.js +598 -0
- package/mcp/stdio-wrapper.js +472 -0
- package/package.json +83 -0
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// Lightweight stdio wrapper with local CLI functionality and remote Polydev MCP server fallback
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const CLIManager = require('../lib/cliManager').default;
|
|
7
|
+
|
|
8
|
+
class StdioMCPWrapper {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.userToken = process.env.POLYDEV_USER_TOKEN;
|
|
11
|
+
if (!this.userToken) {
|
|
12
|
+
console.error('POLYDEV_USER_TOKEN environment variable is required');
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Initialize CLI Manager for local CLI functionality
|
|
17
|
+
this.cliManager = new CLIManager();
|
|
18
|
+
|
|
19
|
+
// Load manifest for tool definitions
|
|
20
|
+
this.loadManifest();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
loadManifest() {
|
|
24
|
+
try {
|
|
25
|
+
const manifestPath = path.join(__dirname, 'manifest.json');
|
|
26
|
+
this.manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
|
|
27
|
+
} catch (error) {
|
|
28
|
+
console.error('Failed to load manifest:', error);
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async handleRequest(request) {
|
|
34
|
+
const { method, params, id } = request;
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
switch (method) {
|
|
38
|
+
case 'initialize':
|
|
39
|
+
return {
|
|
40
|
+
jsonrpc: '2.0',
|
|
41
|
+
id,
|
|
42
|
+
result: {
|
|
43
|
+
protocolVersion: '2024-11-05',
|
|
44
|
+
capabilities: { tools: {} },
|
|
45
|
+
serverInfo: {
|
|
46
|
+
name: this.manifest.name,
|
|
47
|
+
version: this.manifest.version
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
case 'tools/list':
|
|
53
|
+
const tools = this.manifest.tools.map(tool => ({
|
|
54
|
+
name: tool.name,
|
|
55
|
+
description: tool.description,
|
|
56
|
+
inputSchema: tool.inputSchema
|
|
57
|
+
}));
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
jsonrpc: '2.0',
|
|
61
|
+
id,
|
|
62
|
+
result: { tools }
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
case 'tools/call':
|
|
66
|
+
// Handle CLI tools locally, forward others to remote server
|
|
67
|
+
const toolName = params.name;
|
|
68
|
+
if (toolName.startsWith('polydev.') && this.isCliTool(toolName)) {
|
|
69
|
+
return await this.handleLocalCliTool(request);
|
|
70
|
+
} else {
|
|
71
|
+
// Forward non-CLI tools to remote server
|
|
72
|
+
const result = await this.forwardToRemoteServer(request);
|
|
73
|
+
return result;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
default:
|
|
77
|
+
return {
|
|
78
|
+
jsonrpc: '2.0',
|
|
79
|
+
id,
|
|
80
|
+
error: {
|
|
81
|
+
code: -32601,
|
|
82
|
+
message: 'Method not found'
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
} catch (error) {
|
|
87
|
+
return {
|
|
88
|
+
jsonrpc: '2.0',
|
|
89
|
+
id,
|
|
90
|
+
error: {
|
|
91
|
+
code: -32603,
|
|
92
|
+
message: error.message
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async forwardToRemoteServer(request) {
|
|
99
|
+
console.error(`[Stdio Wrapper] Forwarding request to remote server`);
|
|
100
|
+
|
|
101
|
+
const response = await fetch('https://www.polydev.ai/api/mcp', {
|
|
102
|
+
method: 'POST',
|
|
103
|
+
headers: {
|
|
104
|
+
'Content-Type': 'application/json',
|
|
105
|
+
'Authorization': `Bearer ${this.userToken}`,
|
|
106
|
+
'User-Agent': 'polydev-stdio-wrapper/1.0.0'
|
|
107
|
+
},
|
|
108
|
+
body: JSON.stringify(request)
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
if (!response.ok) {
|
|
112
|
+
const errorText = await response.text();
|
|
113
|
+
console.error(`[Stdio Wrapper] Remote server error: ${response.status} - ${errorText}`);
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
jsonrpc: '2.0',
|
|
117
|
+
id: request.id,
|
|
118
|
+
error: {
|
|
119
|
+
code: -32603,
|
|
120
|
+
message: `Remote server error: ${response.status} - ${errorText}`
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const result = await response.json();
|
|
126
|
+
console.error(`[Stdio Wrapper] Got response from remote server`);
|
|
127
|
+
return result;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Check if a tool is a CLI tool that should be handled locally
|
|
132
|
+
*/
|
|
133
|
+
isCliTool(toolName) {
|
|
134
|
+
const cliTools = [
|
|
135
|
+
'polydev.force_cli_detection',
|
|
136
|
+
'polydev.get_cli_status',
|
|
137
|
+
'polydev.send_cli_prompt'
|
|
138
|
+
];
|
|
139
|
+
return cliTools.includes(toolName);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Handle CLI tools locally without remote server calls
|
|
144
|
+
*/
|
|
145
|
+
async handleLocalCliTool(request) {
|
|
146
|
+
const { method, params, id } = request;
|
|
147
|
+
const { name: toolName, arguments: args } = params;
|
|
148
|
+
|
|
149
|
+
console.error(`[Stdio Wrapper] Handling local CLI tool: ${toolName}`);
|
|
150
|
+
|
|
151
|
+
try {
|
|
152
|
+
let result;
|
|
153
|
+
|
|
154
|
+
switch (toolName) {
|
|
155
|
+
case 'polydev.force_cli_detection':
|
|
156
|
+
result = await this.localForceCliDetection(args);
|
|
157
|
+
break;
|
|
158
|
+
|
|
159
|
+
case 'polydev.get_cli_status':
|
|
160
|
+
result = await this.localGetCliStatus(args);
|
|
161
|
+
break;
|
|
162
|
+
|
|
163
|
+
case 'polydev.send_cli_prompt':
|
|
164
|
+
result = await this.localSendCliPrompt(args);
|
|
165
|
+
break;
|
|
166
|
+
|
|
167
|
+
default:
|
|
168
|
+
throw new Error(`Unknown CLI tool: ${toolName}`);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return {
|
|
172
|
+
jsonrpc: '2.0',
|
|
173
|
+
id,
|
|
174
|
+
result: {
|
|
175
|
+
content: [
|
|
176
|
+
{
|
|
177
|
+
type: 'text',
|
|
178
|
+
text: this.formatCliResponse(result)
|
|
179
|
+
}
|
|
180
|
+
]
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
} catch (error) {
|
|
185
|
+
console.error(`[Stdio Wrapper] CLI tool error:`, error);
|
|
186
|
+
return {
|
|
187
|
+
jsonrpc: '2.0',
|
|
188
|
+
id,
|
|
189
|
+
error: {
|
|
190
|
+
code: -32603,
|
|
191
|
+
message: error.message
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Local CLI detection implementation
|
|
199
|
+
*/
|
|
200
|
+
async localForceCliDetection(args) {
|
|
201
|
+
console.error(`[Stdio Wrapper] Local CLI detection started`);
|
|
202
|
+
|
|
203
|
+
try {
|
|
204
|
+
const providerId = args.provider_id; // Optional - detect specific provider
|
|
205
|
+
|
|
206
|
+
// Force detection using CLI Manager (no remote API calls)
|
|
207
|
+
const results = await this.cliManager.forceCliDetection(null, providerId);
|
|
208
|
+
|
|
209
|
+
// Save status locally to file-based cache
|
|
210
|
+
await this.saveLocalCliStatus(results);
|
|
211
|
+
|
|
212
|
+
return {
|
|
213
|
+
success: true,
|
|
214
|
+
results,
|
|
215
|
+
message: `Local CLI detection completed for ${providerId || 'all providers'}`,
|
|
216
|
+
timestamp: new Date().toISOString(),
|
|
217
|
+
local_only: true
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
} catch (error) {
|
|
221
|
+
console.error('[Stdio Wrapper] Local CLI detection error:', error);
|
|
222
|
+
return {
|
|
223
|
+
success: false,
|
|
224
|
+
error: error.message,
|
|
225
|
+
timestamp: new Date().toISOString(),
|
|
226
|
+
local_only: true
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Local CLI status retrieval
|
|
233
|
+
*/
|
|
234
|
+
async localGetCliStatus(args) {
|
|
235
|
+
console.error(`[Stdio Wrapper] Local CLI status retrieval`);
|
|
236
|
+
|
|
237
|
+
try {
|
|
238
|
+
const providerId = args.provider_id;
|
|
239
|
+
let results = {};
|
|
240
|
+
|
|
241
|
+
if (providerId) {
|
|
242
|
+
// Get specific provider status
|
|
243
|
+
const status = await this.cliManager.getCliStatus(providerId);
|
|
244
|
+
results[providerId] = status;
|
|
245
|
+
} else {
|
|
246
|
+
// Get all providers status
|
|
247
|
+
const providers = this.cliManager.getProviders();
|
|
248
|
+
for (const provider of providers) {
|
|
249
|
+
const status = await this.cliManager.getCliStatus(provider.id);
|
|
250
|
+
results[provider.id] = status;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return {
|
|
255
|
+
success: true,
|
|
256
|
+
results,
|
|
257
|
+
message: 'Local CLI status retrieved successfully',
|
|
258
|
+
timestamp: new Date().toISOString(),
|
|
259
|
+
local_only: true
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
} catch (error) {
|
|
263
|
+
console.error('[Stdio Wrapper] Local CLI status error:', error);
|
|
264
|
+
return {
|
|
265
|
+
success: false,
|
|
266
|
+
error: error.message,
|
|
267
|
+
timestamp: new Date().toISOString(),
|
|
268
|
+
local_only: true
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Local CLI prompt sending
|
|
275
|
+
*/
|
|
276
|
+
async localSendCliPrompt(args) {
|
|
277
|
+
console.error(`[Stdio Wrapper] Local CLI prompt sending`);
|
|
278
|
+
|
|
279
|
+
try {
|
|
280
|
+
const { provider_id, prompt, mode = 'args', timeout_ms = 30000 } = args;
|
|
281
|
+
|
|
282
|
+
if (!provider_id || !prompt) {
|
|
283
|
+
throw new Error('provider_id and prompt are required');
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// Send prompt using CLI Manager (local execution)
|
|
287
|
+
const response = await this.cliManager.sendCliPrompt(
|
|
288
|
+
provider_id,
|
|
289
|
+
prompt,
|
|
290
|
+
mode,
|
|
291
|
+
timeout_ms
|
|
292
|
+
);
|
|
293
|
+
|
|
294
|
+
// Record usage locally (file-based analytics)
|
|
295
|
+
await this.recordLocalUsage(provider_id, prompt, response);
|
|
296
|
+
|
|
297
|
+
return {
|
|
298
|
+
success: response.success,
|
|
299
|
+
content: response.content,
|
|
300
|
+
error: response.error,
|
|
301
|
+
tokens_used: response.tokensUsed,
|
|
302
|
+
latency_ms: response.latencyMs,
|
|
303
|
+
provider: provider_id,
|
|
304
|
+
mode,
|
|
305
|
+
timestamp: new Date().toISOString(),
|
|
306
|
+
local_only: true
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
} catch (error) {
|
|
310
|
+
console.error('[Stdio Wrapper] Local CLI prompt error:', error);
|
|
311
|
+
return {
|
|
312
|
+
success: false,
|
|
313
|
+
error: error.message,
|
|
314
|
+
timestamp: new Date().toISOString(),
|
|
315
|
+
local_only: true
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Save CLI status to local file cache
|
|
322
|
+
*/
|
|
323
|
+
async saveLocalCliStatus(results) {
|
|
324
|
+
try {
|
|
325
|
+
const homeDir = require('os').homedir();
|
|
326
|
+
const polydevevDir = path.join(homeDir, '.polydev');
|
|
327
|
+
const statusFile = path.join(polydevevDir, 'cli-status.json');
|
|
328
|
+
|
|
329
|
+
// Ensure directory exists
|
|
330
|
+
if (!fs.existsSync(polydevevDir)) {
|
|
331
|
+
fs.mkdirSync(polydevevDir, { recursive: true });
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// Save status with timestamp
|
|
335
|
+
const statusData = {
|
|
336
|
+
last_updated: new Date().toISOString(),
|
|
337
|
+
results
|
|
338
|
+
};
|
|
339
|
+
|
|
340
|
+
fs.writeFileSync(statusFile, JSON.stringify(statusData, null, 2));
|
|
341
|
+
console.error(`[Stdio Wrapper] CLI status saved to ${statusFile}`);
|
|
342
|
+
|
|
343
|
+
} catch (error) {
|
|
344
|
+
console.error('[Stdio Wrapper] Failed to save local CLI status:', error);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Record local usage for analytics
|
|
350
|
+
*/
|
|
351
|
+
async recordLocalUsage(providerId, prompt, response) {
|
|
352
|
+
try {
|
|
353
|
+
const homeDir = require('os').homedir();
|
|
354
|
+
const polydevevDir = path.join(homeDir, '.polydev');
|
|
355
|
+
const usageFile = path.join(polydevevDir, 'cli-usage.json');
|
|
356
|
+
|
|
357
|
+
// Load existing usage data
|
|
358
|
+
let usageData = [];
|
|
359
|
+
if (fs.existsSync(usageFile)) {
|
|
360
|
+
usageData = JSON.parse(fs.readFileSync(usageFile, 'utf8'));
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// Add new usage record
|
|
364
|
+
usageData.push({
|
|
365
|
+
timestamp: new Date().toISOString(),
|
|
366
|
+
provider: providerId,
|
|
367
|
+
prompt_length: prompt.length,
|
|
368
|
+
success: response.success,
|
|
369
|
+
latency_ms: response.latencyMs,
|
|
370
|
+
tokens_used: response.tokensUsed || 0
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
// Keep only last 1000 records
|
|
374
|
+
if (usageData.length > 1000) {
|
|
375
|
+
usageData = usageData.slice(-1000);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
fs.writeFileSync(usageFile, JSON.stringify(usageData, null, 2));
|
|
379
|
+
console.error(`[Stdio Wrapper] Usage recorded locally`);
|
|
380
|
+
|
|
381
|
+
} catch (error) {
|
|
382
|
+
console.error('[Stdio Wrapper] Failed to record local usage:', error);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Format CLI response for MCP output
|
|
388
|
+
*/
|
|
389
|
+
formatCliResponse(result) {
|
|
390
|
+
if (!result.success) {
|
|
391
|
+
return `❌ **CLI Error**\n\n${result.error}\n\n*Timestamp: ${result.timestamp}*`;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
if (result.content) {
|
|
395
|
+
// Prompt response
|
|
396
|
+
return `✅ **CLI Response** (${result.provider || 'Unknown'} - ${result.mode || 'unknown'} mode)\n\n${result.content}\n\n*Latency: ${result.latency_ms || 0}ms | Tokens: ${result.tokens_used || 0} | ${result.timestamp}*`;
|
|
397
|
+
} else {
|
|
398
|
+
// Status/detection response
|
|
399
|
+
let formatted = `✅ **CLI Operation Success**\n\n`;
|
|
400
|
+
formatted += `${result.message}\n\n`;
|
|
401
|
+
|
|
402
|
+
if (result.results) {
|
|
403
|
+
formatted += `**Results:**\n`;
|
|
404
|
+
for (const [providerId, status] of Object.entries(result.results)) {
|
|
405
|
+
const icon = status.available ? '🟢' : '🔴';
|
|
406
|
+
const authIcon = status.authenticated ? '🔐' : '🔓';
|
|
407
|
+
formatted += `- ${icon} ${authIcon} **${providerId}**: ${status.available ? 'Available' : 'Not Available'}`;
|
|
408
|
+
if (status.version) formatted += ` (${status.version})`;
|
|
409
|
+
if (status.error) formatted += ` - ${status.error}`;
|
|
410
|
+
formatted += `\n`;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
formatted += `\n*${result.local_only ? 'Local execution' : 'Remote execution'} | ${result.timestamp}*`;
|
|
415
|
+
return formatted;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
async start() {
|
|
420
|
+
console.log('Starting Polydev Stdio MCP Wrapper...');
|
|
421
|
+
|
|
422
|
+
process.stdin.setEncoding('utf8');
|
|
423
|
+
let buffer = '';
|
|
424
|
+
|
|
425
|
+
process.stdin.on('data', async (chunk) => {
|
|
426
|
+
buffer += chunk;
|
|
427
|
+
|
|
428
|
+
const lines = buffer.split('\n');
|
|
429
|
+
buffer = lines.pop() || '';
|
|
430
|
+
|
|
431
|
+
for (const line of lines) {
|
|
432
|
+
if (line.trim()) {
|
|
433
|
+
try {
|
|
434
|
+
const request = JSON.parse(line);
|
|
435
|
+
const response = await this.handleRequest(request);
|
|
436
|
+
process.stdout.write(JSON.stringify(response) + '\n');
|
|
437
|
+
} catch (error) {
|
|
438
|
+
console.error('Failed to process request:', error);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
process.stdin.on('end', () => {
|
|
445
|
+
console.log('Stdio MCP Wrapper shutting down...');
|
|
446
|
+
process.exit(0);
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
// Handle process signals
|
|
450
|
+
process.on('SIGINT', () => {
|
|
451
|
+
console.log('Received SIGINT, shutting down...');
|
|
452
|
+
process.exit(0);
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
process.on('SIGTERM', () => {
|
|
456
|
+
console.log('Received SIGTERM, shutting down...');
|
|
457
|
+
process.exit(0);
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
console.log('Stdio MCP Wrapper ready and listening on stdin...');
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
if (require.main === module) {
|
|
465
|
+
const wrapper = new StdioMCPWrapper();
|
|
466
|
+
wrapper.start().catch(error => {
|
|
467
|
+
console.error('Failed to start wrapper:', error);
|
|
468
|
+
process.exit(1);
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
module.exports = StdioMCPWrapper;
|
package/package.json
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "polydev-ai",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Agentic workflow assistant with CLI integration - get diverse perspectives from multiple LLMs when stuck or need enhanced reasoning",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"mcp",
|
|
7
|
+
"model-context-protocol",
|
|
8
|
+
"ai",
|
|
9
|
+
"claude",
|
|
10
|
+
"openai",
|
|
11
|
+
"perspectives",
|
|
12
|
+
"cli",
|
|
13
|
+
"agent",
|
|
14
|
+
"assistant"
|
|
15
|
+
],
|
|
16
|
+
"author": "Polydev AI",
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"private": false,
|
|
19
|
+
"main": "mcp/server.js",
|
|
20
|
+
"bin": {
|
|
21
|
+
"polydev-stdio": "mcp/stdio-wrapper.js"
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"mcp/",
|
|
25
|
+
"lib/",
|
|
26
|
+
"README.md",
|
|
27
|
+
"LICENSE"
|
|
28
|
+
],
|
|
29
|
+
"scripts": {
|
|
30
|
+
"dev": "next dev",
|
|
31
|
+
"build": "next build",
|
|
32
|
+
"start": "next start",
|
|
33
|
+
"lint": "next lint",
|
|
34
|
+
"mcp": "node mcp/server.js",
|
|
35
|
+
"mcp-stdio": "node mcp/stdio-wrapper.js",
|
|
36
|
+
"cli-detect": "node -e \"const CLIManager = require('./lib/cliManager').default; const m = new CLIManager(); m.forceCliDetection().then(console.log);\""
|
|
37
|
+
},
|
|
38
|
+
"repository": {
|
|
39
|
+
"type": "git",
|
|
40
|
+
"url": "https://github.com/polydev-ai/perspectives-mcp.git"
|
|
41
|
+
},
|
|
42
|
+
"homepage": "https://polydev.ai",
|
|
43
|
+
"bugs": {
|
|
44
|
+
"url": "https://github.com/polydev-ai/perspectives-mcp/issues"
|
|
45
|
+
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@hello-pangea/dnd": "^18.0.1",
|
|
48
|
+
"@radix-ui/react-dialog": "^1.1.15",
|
|
49
|
+
"@radix-ui/react-progress": "^1.1.7",
|
|
50
|
+
"@radix-ui/react-slot": "^1.2.3",
|
|
51
|
+
"@radix-ui/react-tabs": "^1.1.13",
|
|
52
|
+
"@supabase/ssr": "^0.4.0",
|
|
53
|
+
"@supabase/supabase-js": "^2.45.0",
|
|
54
|
+
"@upstash/redis": "^1.34.0",
|
|
55
|
+
"class-variance-authority": "^0.7.1",
|
|
56
|
+
"clsx": "^2.1.1",
|
|
57
|
+
"date-fns": "^4.1.0",
|
|
58
|
+
"dotenv": "^17.2.2",
|
|
59
|
+
"lucide-react": "^0.542.0",
|
|
60
|
+
"marked": "^16.2.1",
|
|
61
|
+
"next": "15.0.0",
|
|
62
|
+
"posthog-js": "^1.157.2",
|
|
63
|
+
"react": "^18.3.1",
|
|
64
|
+
"react-dom": "^18.3.1",
|
|
65
|
+
"resend": "^6.0.2",
|
|
66
|
+
"shelljs": "^0.8.5",
|
|
67
|
+
"sonner": "^2.0.7",
|
|
68
|
+
"stripe": "^18.5.0",
|
|
69
|
+
"tailwind-merge": "^3.3.1",
|
|
70
|
+
"which": "^5.0.0"
|
|
71
|
+
},
|
|
72
|
+
"devDependencies": {
|
|
73
|
+
"@types/node": "^20.16.1",
|
|
74
|
+
"@types/react": "^18.3.3",
|
|
75
|
+
"@types/react-dom": "^18.3.0",
|
|
76
|
+
"autoprefixer": "^10.4.20",
|
|
77
|
+
"eslint": "^8.57.0",
|
|
78
|
+
"eslint-config-next": "15.0.0",
|
|
79
|
+
"postcss": "^8.4.41",
|
|
80
|
+
"tailwindcss": "^3.4.10",
|
|
81
|
+
"typescript": "^5.5.4"
|
|
82
|
+
}
|
|
83
|
+
}
|