polydev-ai 1.2.12 → 1.2.14
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/lib/cliManager.js +3 -3
- package/lib/zeroKnowledgeEncryption.js +3 -3
- package/mcp/manifest.json +1 -1
- package/mcp/stdio-wrapper-fixed.js +169 -0
- package/mcp/stdio-wrapper.js +55 -17
- package/package.json +1 -1
package/lib/cliManager.js
CHANGED
|
@@ -100,7 +100,7 @@ class CLIManager {
|
|
|
100
100
|
* Updates status cache and reports to MCP server via Supabase
|
|
101
101
|
*/
|
|
102
102
|
async forceCliDetection(userId, providerId) {
|
|
103
|
-
console.
|
|
103
|
+
console.error(`[CLI Manager] Force detection started for ${providerId || 'all providers'}`);
|
|
104
104
|
const results = {};
|
|
105
105
|
const providersToCheck = providerId ? [providerId] : Array.from(this.providers.keys());
|
|
106
106
|
for (const id of providersToCheck) {
|
|
@@ -115,7 +115,7 @@ class CLIManager {
|
|
|
115
115
|
if (userId) {
|
|
116
116
|
await this.updateCliStatusInDatabase(userId, id, status);
|
|
117
117
|
}
|
|
118
|
-
console.
|
|
118
|
+
console.error(`[CLI Manager] ${provider.name}: ${status.available ? 'Available' : 'Not Available'}`);
|
|
119
119
|
}
|
|
120
120
|
catch (error) {
|
|
121
121
|
console.error(`[CLI Manager] Error detecting ${provider.name}:`, error);
|
|
@@ -363,7 +363,7 @@ class CLIManager {
|
|
|
363
363
|
throw new Error(`Failed to update CLI status: ${response.status}`);
|
|
364
364
|
}
|
|
365
365
|
const result = await response.json();
|
|
366
|
-
console.
|
|
366
|
+
console.error(`[CLI Manager] Updated database via MCP Supabase for ${providerId}: ${status.available}`);
|
|
367
367
|
}
|
|
368
368
|
catch (error) {
|
|
369
369
|
console.error(`[CLI Manager] Failed to update database via MCP Supabase:`, error);
|
|
@@ -81,7 +81,7 @@ class ZeroKnowledgeEncryption {
|
|
|
81
81
|
const keyData = cursor.value;
|
|
82
82
|
// Check if key needs rotation
|
|
83
83
|
if (new Date() > new Date(keyData.rotationDue)) {
|
|
84
|
-
console.
|
|
84
|
+
console.error('[ZK Encryption] Key rotation needed, generating new key');
|
|
85
85
|
await this.createAndStoreKey();
|
|
86
86
|
}
|
|
87
87
|
else {
|
|
@@ -214,7 +214,7 @@ class ZeroKnowledgeEncryption {
|
|
|
214
214
|
*/
|
|
215
215
|
async rotateKeys() {
|
|
216
216
|
await this.createAndStoreKey();
|
|
217
|
-
console.
|
|
217
|
+
console.error('[ZK Encryption] Key rotation completed');
|
|
218
218
|
}
|
|
219
219
|
/**
|
|
220
220
|
* Generate unique key ID
|
|
@@ -274,7 +274,7 @@ class ZeroKnowledgeEncryption {
|
|
|
274
274
|
await transaction.objectStore('keys').clear();
|
|
275
275
|
await transaction.objectStore('cache').clear();
|
|
276
276
|
this.activeKey = null;
|
|
277
|
-
console.
|
|
277
|
+
console.error('[ZK Encryption] All keys cleared');
|
|
278
278
|
}
|
|
279
279
|
}
|
|
280
280
|
exports.ZeroKnowledgeEncryption = ZeroKnowledgeEncryption;
|
package/mcp/manifest.json
CHANGED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// MINIMAL MCP stdio wrapper - NO stdout pollution, JSON only
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
|
|
7
|
+
class MinimalStdioWrapper {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.userToken = process.env.POLYDEV_USER_TOKEN;
|
|
10
|
+
|
|
11
|
+
// Load manifest
|
|
12
|
+
try {
|
|
13
|
+
const manifestPath = path.join(__dirname, 'manifest.json');
|
|
14
|
+
this.manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
|
|
15
|
+
} catch (error) {
|
|
16
|
+
// Use stderr for errors
|
|
17
|
+
console.error('Failed to load manifest:', error);
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async handleRequest(request) {
|
|
23
|
+
const { method, params, id } = request;
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
switch (method) {
|
|
27
|
+
case 'initialize':
|
|
28
|
+
return {
|
|
29
|
+
jsonrpc: '2.0',
|
|
30
|
+
id,
|
|
31
|
+
result: {
|
|
32
|
+
protocolVersion: '2024-11-05',
|
|
33
|
+
capabilities: { tools: {} },
|
|
34
|
+
serverInfo: {
|
|
35
|
+
name: 'polydev-ai',
|
|
36
|
+
version: '1.2.13'
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
case 'tools/list':
|
|
42
|
+
const tools = this.manifest.tools.map(tool => ({
|
|
43
|
+
name: tool.name,
|
|
44
|
+
description: tool.description,
|
|
45
|
+
inputSchema: tool.inputSchema
|
|
46
|
+
}));
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
jsonrpc: '2.0',
|
|
50
|
+
id,
|
|
51
|
+
result: { tools }
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
case 'tools/call':
|
|
55
|
+
// Check token
|
|
56
|
+
if (!this.userToken) {
|
|
57
|
+
return {
|
|
58
|
+
jsonrpc: '2.0',
|
|
59
|
+
id,
|
|
60
|
+
error: {
|
|
61
|
+
code: -32603,
|
|
62
|
+
message: 'POLYDEV_USER_TOKEN environment variable is required'
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Forward to remote server
|
|
68
|
+
const response = await fetch('https://www.polydev.ai/api/mcp', {
|
|
69
|
+
method: 'POST',
|
|
70
|
+
headers: {
|
|
71
|
+
'Content-Type': 'application/json',
|
|
72
|
+
'Authorization': `Bearer ${this.userToken}`
|
|
73
|
+
},
|
|
74
|
+
body: JSON.stringify(request)
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
if (!response.ok) {
|
|
78
|
+
const errorText = await response.text();
|
|
79
|
+
return {
|
|
80
|
+
jsonrpc: '2.0',
|
|
81
|
+
id: request.id,
|
|
82
|
+
error: {
|
|
83
|
+
code: -32603,
|
|
84
|
+
message: `Remote server error: ${response.status}`
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return await response.json();
|
|
90
|
+
|
|
91
|
+
default:
|
|
92
|
+
return {
|
|
93
|
+
jsonrpc: '2.0',
|
|
94
|
+
id,
|
|
95
|
+
error: {
|
|
96
|
+
code: -32601,
|
|
97
|
+
message: 'Method not found'
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
} catch (error) {
|
|
102
|
+
return {
|
|
103
|
+
jsonrpc: '2.0',
|
|
104
|
+
id,
|
|
105
|
+
error: {
|
|
106
|
+
code: -32603,
|
|
107
|
+
message: error.message
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async start() {
|
|
114
|
+
// NO console.log to stdout!
|
|
115
|
+
// Use stderr for debug messages if needed
|
|
116
|
+
console.error('[MCP] Starting...');
|
|
117
|
+
|
|
118
|
+
process.stdin.setEncoding('utf8');
|
|
119
|
+
let buffer = '';
|
|
120
|
+
|
|
121
|
+
process.stdin.on('data', async (chunk) => {
|
|
122
|
+
buffer += chunk;
|
|
123
|
+
|
|
124
|
+
const lines = buffer.split('\n');
|
|
125
|
+
buffer = lines.pop() || '';
|
|
126
|
+
|
|
127
|
+
for (const line of lines) {
|
|
128
|
+
if (line.trim()) {
|
|
129
|
+
try {
|
|
130
|
+
const request = JSON.parse(line);
|
|
131
|
+
const response = await this.handleRequest(request);
|
|
132
|
+
// ONLY output JSON to stdout
|
|
133
|
+
process.stdout.write(JSON.stringify(response) + '\n');
|
|
134
|
+
} catch (error) {
|
|
135
|
+
console.error('Failed to process request:', error);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
process.stdin.on('end', () => {
|
|
142
|
+
console.error('[MCP] Shutting down...');
|
|
143
|
+
process.exit(0);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
process.on('SIGINT', () => {
|
|
147
|
+
console.error('[MCP] SIGINT received');
|
|
148
|
+
process.exit(0);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
process.on('SIGTERM', () => {
|
|
152
|
+
console.error('[MCP] SIGTERM received');
|
|
153
|
+
process.exit(0);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
console.error('[MCP] Ready');
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Start the server
|
|
161
|
+
if (require.main === module) {
|
|
162
|
+
const wrapper = new MinimalStdioWrapper();
|
|
163
|
+
wrapper.start().catch(error => {
|
|
164
|
+
console.error('Failed to start:', error);
|
|
165
|
+
process.exit(1);
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
module.exports = MinimalStdioWrapper;
|
package/mcp/stdio-wrapper.js
CHANGED
|
@@ -20,6 +20,10 @@ class StdioMCPWrapper {
|
|
|
20
20
|
|
|
21
21
|
// Smart refresh scheduler (will be started after initialization)
|
|
22
22
|
this.refreshScheduler = null;
|
|
23
|
+
|
|
24
|
+
// Track if initial CLI detection has been done
|
|
25
|
+
this.initialDetectionDone = false;
|
|
26
|
+
this.initialDetectionPromise = null;
|
|
23
27
|
}
|
|
24
28
|
|
|
25
29
|
loadManifest() {
|
|
@@ -226,6 +230,10 @@ class StdioMCPWrapper {
|
|
|
226
230
|
// Update database with CLI status
|
|
227
231
|
await this.updateCliStatusInDatabase(results);
|
|
228
232
|
|
|
233
|
+
// Mark initial detection as done
|
|
234
|
+
this.initialDetectionDone = true;
|
|
235
|
+
this.initialDetectionPromise = null;
|
|
236
|
+
|
|
229
237
|
return {
|
|
230
238
|
success: true,
|
|
231
239
|
results,
|
|
@@ -236,6 +244,10 @@ class StdioMCPWrapper {
|
|
|
236
244
|
|
|
237
245
|
} catch (error) {
|
|
238
246
|
console.error('[Stdio Wrapper] Local CLI detection error:', error);
|
|
247
|
+
// Mark as done even on error to prevent blocking
|
|
248
|
+
this.initialDetectionDone = true;
|
|
249
|
+
this.initialDetectionPromise = null;
|
|
250
|
+
|
|
239
251
|
return {
|
|
240
252
|
success: false,
|
|
241
253
|
error: error.message,
|
|
@@ -297,6 +309,16 @@ class StdioMCPWrapper {
|
|
|
297
309
|
console.error(`[Stdio Wrapper] Local CLI prompt sending with perspectives`);
|
|
298
310
|
|
|
299
311
|
try {
|
|
312
|
+
// Ensure initial CLI detection has completed before sending prompts
|
|
313
|
+
if (!this.initialDetectionDone && this.initialDetectionPromise) {
|
|
314
|
+
console.error('[Stdio Wrapper] Waiting for initial CLI detection to complete...');
|
|
315
|
+
await this.initialDetectionPromise;
|
|
316
|
+
} else if (!this.initialDetectionDone && !this.initialDetectionPromise) {
|
|
317
|
+
console.error('[Stdio Wrapper] Running initial CLI detection before sending prompt...');
|
|
318
|
+
this.initialDetectionPromise = this.localForceCliDetection({});
|
|
319
|
+
await this.initialDetectionPromise;
|
|
320
|
+
}
|
|
321
|
+
|
|
300
322
|
let { provider_id, prompt, mode = 'args', timeout_ms = 30000 } = args;
|
|
301
323
|
|
|
302
324
|
// Ensure timeout_ms is valid (not undefined, null, Infinity, or negative)
|
|
@@ -380,7 +402,18 @@ class StdioMCPWrapper {
|
|
|
380
402
|
*/
|
|
381
403
|
async getAllAvailableProviders() {
|
|
382
404
|
try {
|
|
383
|
-
|
|
405
|
+
// Try to load from cache first to avoid re-detection
|
|
406
|
+
const cachedStatus = await this.loadLocalCliStatus();
|
|
407
|
+
let results;
|
|
408
|
+
|
|
409
|
+
if (cachedStatus && Object.keys(cachedStatus).length > 0) {
|
|
410
|
+
console.error('[Stdio Wrapper] Using cached CLI status');
|
|
411
|
+
results = cachedStatus;
|
|
412
|
+
} else {
|
|
413
|
+
console.error('[Stdio Wrapper] No cached status, running detection');
|
|
414
|
+
results = await this.cliManager.forceCliDetection();
|
|
415
|
+
}
|
|
416
|
+
|
|
384
417
|
const availableProviders = [];
|
|
385
418
|
|
|
386
419
|
// Priority order: claude_code > codex_cli > gemini_cli
|
|
@@ -863,22 +896,6 @@ class StdioMCPWrapper {
|
|
|
863
896
|
async start() {
|
|
864
897
|
console.error('[Stdio Wrapper] Starting Polydev Stdio MCP Wrapper...');
|
|
865
898
|
|
|
866
|
-
// Only run initial CLI detection if we have a token
|
|
867
|
-
if (this.userToken && this.cliManager) {
|
|
868
|
-
console.error('[Stdio Wrapper] Running initial CLI detection...');
|
|
869
|
-
try {
|
|
870
|
-
await this.localForceCliDetection({});
|
|
871
|
-
console.error('[Stdio Wrapper] Initial CLI detection completed');
|
|
872
|
-
} catch (error) {
|
|
873
|
-
console.error('[Stdio Wrapper] Initial CLI detection failed:', error);
|
|
874
|
-
}
|
|
875
|
-
|
|
876
|
-
// Start smart refresh scheduler for automatic updates
|
|
877
|
-
this.startSmartRefreshScheduler();
|
|
878
|
-
} else {
|
|
879
|
-
console.error('[Stdio Wrapper] No token provided - CLI detection disabled');
|
|
880
|
-
}
|
|
881
|
-
|
|
882
899
|
process.stdin.setEncoding('utf8');
|
|
883
900
|
let buffer = '';
|
|
884
901
|
|
|
@@ -921,6 +938,27 @@ class StdioMCPWrapper {
|
|
|
921
938
|
});
|
|
922
939
|
|
|
923
940
|
console.error('[Stdio Wrapper] Ready and listening on stdin...');
|
|
941
|
+
|
|
942
|
+
// Run initial CLI detection AFTER stdin handler is set up
|
|
943
|
+
if (this.userToken && this.cliManager) {
|
|
944
|
+
console.error('[Stdio Wrapper] Scheduling initial CLI detection...');
|
|
945
|
+
// Run asynchronously after a short delay to not block initialization
|
|
946
|
+
setTimeout(async () => {
|
|
947
|
+
console.error('[Stdio Wrapper] Running initial CLI detection...');
|
|
948
|
+
try {
|
|
949
|
+
this.initialDetectionPromise = this.localForceCliDetection({});
|
|
950
|
+
await this.initialDetectionPromise;
|
|
951
|
+
console.error('[Stdio Wrapper] Initial CLI detection completed');
|
|
952
|
+
} catch (error) {
|
|
953
|
+
console.error('[Stdio Wrapper] Initial CLI detection failed:', error);
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
// Start smart refresh scheduler for automatic updates
|
|
957
|
+
this.startSmartRefreshScheduler();
|
|
958
|
+
}, 100);
|
|
959
|
+
} else {
|
|
960
|
+
console.error('[Stdio Wrapper] No token provided - CLI detection disabled');
|
|
961
|
+
}
|
|
924
962
|
}
|
|
925
963
|
}
|
|
926
964
|
|
package/package.json
CHANGED