polydev-ai 1.9.24 → 1.9.25

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 CHANGED
@@ -1180,14 +1180,10 @@ This is a known issue with @google/gemini-cli@0.3.4 and older Node.js versions.`
1180
1180
  const parseCodexOutput = (output) => {
1181
1181
  if (!output || !output.trim()) return null;
1182
1182
 
1183
- // Strip ANSI escape codes first — Codex CLI wraps markers like 'codex' and
1184
- // 'tokens used' in bold/color codes which break regex matching
1185
- const cleanOutput = output.replace(/\x1b\[[0-9;]*m/g, '');
1186
-
1187
1183
  // First, try to extract the response between "codex" marker and "tokens used"
1188
1184
  // IMPORTANT: Use (?:^|\n) to match "codex" only at the start of a line
1189
1185
  // This prevents matching "codex" in model names like "gpt-5.2-codex"
1190
- const codexMarkerMatch = cleanOutput.match(/(?:^|\n)codex\s*\n([\s\S]*?)(?:\n\s*tokens used|\n\s*$)/i);
1186
+ const codexMarkerMatch = output.match(/(?:^|\n)codex\s*\n([\s\S]*?)(?:\n\s*tokens used|\n\s*$)/i);
1191
1187
  if (codexMarkerMatch && codexMarkerMatch[1]) {
1192
1188
  const extracted = codexMarkerMatch[1].trim();
1193
1189
  if (extracted.length > 0 && !extracted.startsWith('ERROR')) {
@@ -1196,7 +1192,7 @@ This is a known issue with @google/gemini-cli@0.3.4 and older Node.js versions.`
1196
1192
  }
1197
1193
 
1198
1194
  // Fallback: Try to find bullet point responses
1199
- const bulletMatches = cleanOutput.match(/•\s*(.+)/g);
1195
+ const bulletMatches = output.match(/•\s*(.+)/g);
1200
1196
  if (bulletMatches && bulletMatches.length > 0) {
1201
1197
  const bulletContent = bulletMatches
1202
1198
  .map(m => m.replace(/^•\s*/, '').trim())
@@ -1208,9 +1204,8 @@ This is a known issue with @google/gemini-cli@0.3.4 and older Node.js versions.`
1208
1204
  }
1209
1205
 
1210
1206
  // Last resort: Filter out known noise patterns line by line
1211
- const lines = cleanOutput.split('\n');
1207
+ const lines = output.split('\n');
1212
1208
  const contentLines = [];
1213
- let seenTokensUsed = false;
1214
1209
 
1215
1210
  // Patterns to skip (Codex-specific noise)
1216
1211
  const noisePatterns = [
@@ -1230,6 +1225,7 @@ This is a known issue with @google/gemini-cli@0.3.4 and older Node.js versions.`
1230
1225
  /^thinking$/i, // "thinking" marker
1231
1226
  /^codex$/i, // "codex" marker
1232
1227
  /^tokens used$/i, // Token count header
1228
+ /^[\d,]+$/, // Just numbers (token counts)
1233
1229
  /^ERROR:\s*MCP/i, // MCP errors
1234
1230
  /MCP client for .* failed/i, // MCP client failures
1235
1231
  /handshake.*failed/i, // Handshake errors
@@ -1244,15 +1240,6 @@ This is a known issue with @google/gemini-cli@0.3.4 and older Node.js versions.`
1244
1240
  for (const line of lines) {
1245
1241
  const trimmedLine = line.trim();
1246
1242
 
1247
- // Track when we've passed the "tokens used" footer
1248
- if (/^tokens used$/i.test(trimmedLine)) {
1249
- seenTokensUsed = true;
1250
- continue;
1251
- }
1252
-
1253
- // After "tokens used", skip pure numbers (token counts like "22")
1254
- if (seenTokensUsed && /^[\d,]+$/.test(trimmedLine)) continue;
1255
-
1256
1243
  // Check if line matches any noise pattern
1257
1244
  const isNoise = noisePatterns.some(pattern => pattern.test(trimmedLine));
1258
1245
  if (isNoise) continue;
package/mcp/manifest.json CHANGED
@@ -292,6 +292,251 @@
292
292
  }
293
293
  ]
294
294
  },
295
+ {
296
+ "name": "force_cli_detection",
297
+ "description": "Force detection and status update for CLI tools (Claude Code, Codex CLI, Gemini CLI). Updates local cache and reports status to MCP server via Supabase.",
298
+ "inputSchema": {
299
+ "type": "object",
300
+ "properties": {
301
+ "user_id": {
302
+ "type": "string",
303
+ "description": "User ID for database status updates (optional for stdio-wrapper)",
304
+ "minLength": 1
305
+ },
306
+ "provider_id": {
307
+ "type": "string",
308
+ "description": "Specific CLI provider to detect (optional, detects all if not provided)",
309
+ "enum": ["claude_code", "codex_cli", "gemini_cli"]
310
+ }
311
+ }
312
+ },
313
+ "outputSchema": {
314
+ "type": "object",
315
+ "properties": {
316
+ "success": {
317
+ "type": "boolean",
318
+ "description": "Whether detection was successful"
319
+ },
320
+ "results": {
321
+ "type": "object",
322
+ "description": "Detection results for each provider",
323
+ "additionalProperties": {
324
+ "type": "object",
325
+ "properties": {
326
+ "available": {
327
+ "type": "boolean",
328
+ "description": "Whether CLI is available"
329
+ },
330
+ "authenticated": {
331
+ "type": "boolean",
332
+ "description": "Whether CLI is authenticated"
333
+ },
334
+ "version": {
335
+ "type": "string",
336
+ "description": "CLI version if available"
337
+ },
338
+ "path": {
339
+ "type": "string",
340
+ "description": "Path to CLI executable"
341
+ },
342
+ "error": {
343
+ "type": "string",
344
+ "description": "Error message if detection failed"
345
+ }
346
+ }
347
+ }
348
+ },
349
+ "message": {
350
+ "type": "string",
351
+ "description": "Human-readable result message"
352
+ },
353
+ "timestamp": {
354
+ "type": "string",
355
+ "description": "Detection timestamp"
356
+ }
357
+ },
358
+ "required": ["success", "results", "message", "timestamp"]
359
+ },
360
+ "examples": [
361
+ {
362
+ "description": "Detect all CLI providers",
363
+ "input": {
364
+ "user_id": "user_123"
365
+ },
366
+ "output": {
367
+ "success": true,
368
+ "results": {
369
+ "claude_code": {
370
+ "available": true,
371
+ "authenticated": true,
372
+ "version": "claude-code v1.2.3",
373
+ "path": "/usr/local/bin/claude"
374
+ },
375
+ "codex_cli": {
376
+ "available": false,
377
+ "authenticated": false,
378
+ "error": "Codex CLI not found in PATH. Install Codex CLI from OpenAI"
379
+ }
380
+ },
381
+ "message": "CLI detection completed for all providers",
382
+ "timestamp": "2024-01-15T10:30:00Z"
383
+ }
384
+ }
385
+ ]
386
+ },
387
+ {
388
+ "name": "get_cli_status",
389
+ "description": "Get current CLI status with caching support. Returns cached results if available and fresh, otherwise performs new detection.",
390
+ "inputSchema": {
391
+ "type": "object",
392
+ "properties": {
393
+ "user_id": {
394
+ "type": "string",
395
+ "description": "User ID for database status retrieval (optional for stdio-wrapper)",
396
+ "minLength": 1
397
+ },
398
+ "provider_id": {
399
+ "type": "string",
400
+ "description": "Specific CLI provider status to get (optional, gets all if not provided)",
401
+ "enum": ["claude_code", "codex_cli", "gemini_cli"]
402
+ }
403
+ }
404
+ },
405
+ "outputSchema": {
406
+ "type": "object",
407
+ "properties": {
408
+ "success": {
409
+ "type": "boolean",
410
+ "description": "Whether status retrieval was successful"
411
+ },
412
+ "results": {
413
+ "type": "object",
414
+ "description": "Status results for each provider",
415
+ "additionalProperties": {
416
+ "type": "object",
417
+ "properties": {
418
+ "available": {
419
+ "type": "boolean"
420
+ },
421
+ "authenticated": {
422
+ "type": "boolean"
423
+ },
424
+ "version": {
425
+ "type": "string"
426
+ },
427
+ "lastChecked": {
428
+ "type": "string",
429
+ "description": "Last status check timestamp"
430
+ }
431
+ }
432
+ }
433
+ },
434
+ "message": {
435
+ "type": "string"
436
+ },
437
+ "timestamp": {
438
+ "type": "string"
439
+ }
440
+ },
441
+ "required": ["success", "results"]
442
+ }
443
+ },
444
+ {
445
+ "name": "send_cli_prompt",
446
+ "description": "Send a prompt to a CLI provider and get response. Supports both stdin and argument modes for maximum compatibility.",
447
+ "inputSchema": {
448
+ "type": "object",
449
+ "properties": {
450
+ "provider_id": {
451
+ "type": "string",
452
+ "description": "CLI provider to send prompt to",
453
+ "enum": ["claude_code", "codex_cli", "gemini_cli"]
454
+ },
455
+ "prompt": {
456
+ "type": "string",
457
+ "description": "Prompt to send to the CLI",
458
+ "minLength": 1
459
+ },
460
+ "mode": {
461
+ "type": "string",
462
+ "description": "Prompt sending mode",
463
+ "enum": ["stdin", "args"],
464
+ "default": "args"
465
+ },
466
+ "timeout_ms": {
467
+ "type": "integer",
468
+ "description": "Timeout in milliseconds (90 seconds default for CLI-within-CLI scenarios)",
469
+ "minimum": 1000,
470
+ "maximum": 600000,
471
+ "default": 90000
472
+ },
473
+ "user_id": {
474
+ "type": "string",
475
+ "description": "User ID for usage tracking (optional)",
476
+ "minLength": 1
477
+ }
478
+ },
479
+ "required": ["prompt"]
480
+ },
481
+ "outputSchema": {
482
+ "type": "object",
483
+ "properties": {
484
+ "success": {
485
+ "type": "boolean",
486
+ "description": "Whether the prompt was sent successfully"
487
+ },
488
+ "content": {
489
+ "type": "string",
490
+ "description": "CLI response content"
491
+ },
492
+ "error": {
493
+ "type": "string",
494
+ "description": "Error message if prompt failed"
495
+ },
496
+ "tokens_used": {
497
+ "type": "integer",
498
+ "description": "Number of tokens used"
499
+ },
500
+ "latency_ms": {
501
+ "type": "integer",
502
+ "description": "Response latency in milliseconds"
503
+ },
504
+ "provider": {
505
+ "type": "string",
506
+ "description": "CLI provider used"
507
+ },
508
+ "mode": {
509
+ "type": "string",
510
+ "description": "Mode used for sending"
511
+ },
512
+ "timestamp": {
513
+ "type": "string",
514
+ "description": "Response timestamp"
515
+ }
516
+ },
517
+ "required": ["success", "provider", "timestamp"]
518
+ },
519
+ "examples": [
520
+ {
521
+ "description": "Send prompt to Claude Code",
522
+ "input": {
523
+ "provider_id": "claude_code",
524
+ "prompt": "Help me debug this TypeScript error: Property 'map' does not exist on type 'string'",
525
+ "mode": "args",
526
+ "user_id": "user_123"
527
+ },
528
+ "output": {
529
+ "success": true,
530
+ "content": "This error occurs when you're trying to use the .map() method on a string variable. The .map() method is an array method, not a string method...",
531
+ "tokens_used": 150,
532
+ "latency_ms": 1200,
533
+ "provider": "claude_code",
534
+ "mode": "args",
535
+ "timestamp": "2024-01-15T10:35:00Z"
536
+ }
537
+ }
538
+ ]
539
+ },
295
540
  {
296
541
  "name": "enable_status_reporting",
297
542
  "description": "Enable automatic CLI status reporting to polydev.ai server. Reports are sent when CLI detection runs and via periodic heartbeat. Requires a Polydev user token.",
@@ -453,11 +453,7 @@ Token will be saved automatically after login.`
453
453
  }
454
454
 
455
455
  // Handle get_perspectives with local CLIs + remote perspectives
456
- // Also redirect send_cli_prompt get_perspectives for backward compat
457
- // (send_cli_prompt was removed from tool list to prevent AI models from choosing it
458
- // over get_perspectives, but old clients may still call it)
459
- if (toolName === 'get_perspectives' || toolName === 'polydev.get_perspectives' ||
460
- toolName === 'send_cli_prompt' || toolName === 'polydev.send_cli_prompt') {
456
+ if (toolName === 'get_perspectives' || toolName === 'polydev.get_perspectives') {
461
457
  return await this.handleGetPerspectivesWithCLIs(params, id);
462
458
  }
463
459
 
@@ -1100,10 +1096,11 @@ To authenticate, pass your token directly:
1100
1096
  perspectivesSection += ` (${perspectiveCount} active)`;
1101
1097
 
1102
1098
  // Show providers in order with their selected models
1103
- for (const p of modelPrefs.allProviders) {
1099
+ for (let i = 0; i < modelPrefs.allProviders.length; i++) {
1100
+ const p = modelPrefs.allProviders[i];
1104
1101
  const providerName = p.provider.charAt(0).toUpperCase() + p.provider.slice(1);
1105
1102
  const source = p.cliId ? 'CLI' : (p.tier ? `Credits/${p.tier}` : 'API');
1106
- perspectivesSection += `\n ${providerName.padEnd(12)} ${p.model} [${source}]`;
1103
+ perspectivesSection += `\n ${i + 1}. ${providerName.padEnd(12)} ${p.model} [${source}]`;
1107
1104
  }
1108
1105
  } else {
1109
1106
  perspectivesSection += '\n (none configured - using defaults)';
@@ -1633,8 +1630,10 @@ To re-login: /polydev:login`
1633
1630
  const cliTools = [
1634
1631
  'force_cli_detection',
1635
1632
  'get_cli_status',
1633
+ 'send_cli_prompt',
1636
1634
  'polydev.force_cli_detection',
1637
- 'polydev.get_cli_status'
1635
+ 'polydev.get_cli_status',
1636
+ 'polydev.send_cli_prompt'
1638
1637
  ];
1639
1638
  return cliTools.includes(toolName);
1640
1639
  }
@@ -1722,6 +1721,11 @@ To re-login: /polydev:login`
1722
1721
  result = await this.localGetCliStatus(args);
1723
1722
  break;
1724
1723
 
1724
+ case 'send_cli_prompt':
1725
+ case 'polydev.send_cli_prompt':
1726
+ result = await this.localSendCliPrompt(args);
1727
+ break;
1728
+
1725
1729
  default:
1726
1730
  throw new Error(`Unknown CLI tool: ${toolName}`);
1727
1731
  }
@@ -2190,7 +2194,7 @@ To re-login: /polydev:login`
2190
2194
  if (result.success) successCount++;
2191
2195
  completedCount++;
2192
2196
 
2193
- // Resolve early if we have enough successes OR all complete
2197
+ // Resolve early if we have enough successes OR all promises done
2194
2198
  if (successCount >= needed || completedCount >= promises.length) {
2195
2199
  resolved = true;
2196
2200
  resolve([...results]); // Copy to prevent mutation from late arrivals
@@ -2458,7 +2462,7 @@ To re-login: /polydev:login`
2458
2462
  user_token: this.userToken,
2459
2463
  // Exclude providers that succeeded locally
2460
2464
  exclude_providers: excludeProviders,
2461
- // NEW: Specific providers to request (from API-only providers)
2465
+ // NEW: Specific providers to request (from API-only list)
2462
2466
  request_providers: requestProviders.length > 0 ? requestProviders : undefined,
2463
2467
  // Pass CLI responses for dashboard logging
2464
2468
  cli_responses: cliResponses,
@@ -2520,6 +2524,9 @@ To re-login: /polydev:login`
2520
2524
  }
2521
2525
  }
2522
2526
 
2527
+ /**
2528
+ * Combine multiple CLI results and remote perspectives
2529
+ */
2523
2530
  combineAllCliAndPerspectives(localResults, perspectivesResult, args) {
2524
2531
  // Ensure perspectivesResult is always an object to prevent undefined errors
2525
2532
  const safePersp = perspectivesResult || { success: false, error: 'No response from perspectives server' };
@@ -2565,8 +2572,8 @@ To re-login: /polydev:login`
2565
2572
  if (safePersp.raw) {
2566
2573
  // Raw content is already formatted - use as-is
2567
2574
  formatted += `${safePersp.content}\n\n`;
2568
- } else if (!safePersp.skipped) {
2569
- // Legacy formatting (only if not skipped — skipped means CLIs filled all slots)
2575
+ } else {
2576
+ // Legacy formatting
2570
2577
  const title = (successfulClis.length === 0) ? 'Perspectives Fallback' : 'Supplemental Multi-Model Perspectives';
2571
2578
  formatted += `${title}\n\n`;
2572
2579
  formatted += `${safePersp.content}\n\n`;
@@ -2576,10 +2583,6 @@ To re-login: /polydev:login`
2576
2583
  formatted += `❌ Perspectives request failed: ${safePersp.error || 'Unknown error'}\n\n`;
2577
2584
  }
2578
2585
 
2579
- // Strip "LOGIN SUCCESSFUL" banner that leaks from remote server responses
2580
- // It gets appended to perspective results and pollutes the output
2581
- formatted = formatted.replace(/\n*LOGIN SUCCESSFUL\n={4,}\n[\s\S]*?Dashboard:.*(\n|$)/g, '');
2582
-
2583
2586
  return formatted.trim();
2584
2587
  }
2585
2588
 
@@ -2897,6 +2900,25 @@ To re-login: /polydev:login`
2897
2900
  } else {
2898
2901
  return `CLI Response (${result.provider || 'Unknown'} - ${result.mode || 'unknown'} mode)\n\n${result.content}\n\nLatency: ${result.latency_ms || 0}ms | Tokens: ${result.tokens_used || 0} | ${result.timestamp}`;
2899
2902
  }
2903
+ } else {
2904
+ // Status/detection response
2905
+ let formatted = `CLI Operation Success\n\n`;
2906
+ formatted += `${result.message}\n\n`;
2907
+
2908
+ if (result.results) {
2909
+ formatted += `Results:\n`;
2910
+ for (const [providerId, status] of Object.entries(result.results)) {
2911
+ const icon = status.available ? '[+]' : '[-]';
2912
+ const authStatus = status.authenticated ? '[auth]' : '[no-auth]';
2913
+ formatted += `- ${icon} ${authStatus} ${providerId}: ${status.available ? 'Available' : 'Not Available'}`;
2914
+ if (status.version) formatted += ` (${status.version})`;
2915
+ if (status.error) formatted += ` - ${status.error}`;
2916
+ formatted += `\n`;
2917
+ }
2918
+ }
2919
+
2920
+ formatted += `\n${result.local_only ? 'Local execution' : 'Remote execution'} | ${result.timestamp}`;
2921
+ return formatted;
2900
2922
  }
2901
2923
  }
2902
2924
 
@@ -2941,7 +2963,7 @@ To re-login: /polydev:login`
2941
2963
  this.userModelPreferences = result.modelPreferences;
2942
2964
  this.modelPreferencesCacheTime = Date.now();
2943
2965
 
2944
- // Also cache perspectivesPerMessage setting (default 2)
2966
+ // Also cache perspectives_per_message setting (default 2)
2945
2967
  this.perspectivesPerMessage = result.perspectivesPerMessage || 2;
2946
2968
 
2947
2969
  // Cache provider order from user's dashboard (respects display_order)
@@ -3119,7 +3141,6 @@ To re-login: /polydev:login`
3119
3141
  return this.localForceCliDetection({});
3120
3142
  }).then(() => {
3121
3143
  this._cliDetectionComplete = true;
3122
- // Display CLI status after detection
3123
3144
  return this.displayCliStatus();
3124
3145
  }).catch((error) => {
3125
3146
  console.error('[Polydev] Auto-login flow error:', error.message);
@@ -3395,6 +3416,37 @@ function createSandboxServer() {
3395
3416
  required: ['prompt']
3396
3417
  }
3397
3418
  },
3419
+ {
3420
+ name: 'get_cli_status',
3421
+ description: 'Check status of local CLI tools (Claude Code, Codex CLI, Gemini CLI)',
3422
+ inputSchema: {
3423
+ type: 'object',
3424
+ properties: {
3425
+ provider_id: {
3426
+ type: 'string',
3427
+ description: 'Optional specific provider to check'
3428
+ }
3429
+ }
3430
+ }
3431
+ },
3432
+ {
3433
+ name: 'force_cli_detection',
3434
+ description: 'Force re-detection of installed local CLI tools',
3435
+ inputSchema: { type: 'object', properties: {} }
3436
+ },
3437
+ {
3438
+ name: 'send_cli_prompt',
3439
+ description: 'Send prompt to local CLI with perspectives fallback',
3440
+ inputSchema: {
3441
+ type: 'object',
3442
+ properties: {
3443
+ provider_id: { type: 'string', description: 'CLI provider ID' },
3444
+ prompt: { type: 'string', description: 'Prompt to send' },
3445
+ mode: { type: 'string', enum: ['args', 'stdin'], default: 'args' }
3446
+ },
3447
+ required: ['provider_id', 'prompt']
3448
+ }
3449
+ }
3398
3450
  ]
3399
3451
  };
3400
3452
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "polydev-ai",
3
- "version": "1.9.24",
3
+ "version": "1.9.25",
4
4
  "engines": {
5
5
  "node": ">=20.x <=22.x"
6
6
  },