polydev-ai 1.8.9 → 1.8.11

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.
Files changed (2) hide show
  1. package/lib/cliManager.js +144 -49
  2. package/package.json +1 -1
package/lib/cliManager.js CHANGED
@@ -443,38 +443,76 @@ This is a known issue with @google/gemini-cli@0.3.4 and older Node.js versions.`
443
443
 
444
444
  if (providerId === 'codex_cli') {
445
445
  const execArgs = promptVariants.find(args => args.includes('exec')) || promptVariants[0];
446
- try {
447
- const result = await this.executeCodexExec(provider.command, execArgs, prompt, timeoutMs, model);
448
- // executeCodexExec now returns { content, detectedModel, rawStdout, rawStderr }
449
- const content = result.content;
450
- const detectedModel = result.detectedModel;
451
-
452
- // Use detected model if available, otherwise fall back to what was requested or 'cli_default'
453
- const actualModel = detectedModel || model || 'cli_default';
454
-
455
- if (detectedModel && detectedModel !== model) {
456
- console.log(`[Polydev CLI] Codex CLI detected model: ${detectedModel} (requested: ${model || 'none'})`);
446
+
447
+ // Try with specified model first, fallback to CLI default if model fails
448
+ let modelToUse = model;
449
+ let attempts = 0;
450
+ const maxAttempts = model ? 2 : 1; // Only retry if model was specified
451
+
452
+ while (attempts < maxAttempts) {
453
+ attempts++;
454
+ try {
455
+ const result = await this.executeCodexExec(provider.command, execArgs, prompt, timeoutMs, modelToUse);
456
+ // executeCodexExec now returns { content, detectedModel, rawStdout, rawStderr }
457
+ const content = result.content;
458
+ const detectedModel = result.detectedModel;
459
+
460
+ // Check if the response contains a model error
461
+ const modelError = content && (
462
+ content.includes('model is not supported') ||
463
+ content.includes('model not found') ||
464
+ content.includes('invalid model') ||
465
+ content.includes("doesn't exist")
466
+ );
467
+
468
+ if (modelError && modelToUse && attempts < maxAttempts) {
469
+ console.log(`[Polydev CLI] Model '${modelToUse}' failed for Codex CLI, retrying with CLI default...`);
470
+ modelToUse = null; // Retry without model flag
471
+ continue;
472
+ }
473
+
474
+ // Use detected model if available, otherwise fall back to what was requested or 'cli_default'
475
+ const actualModel = detectedModel || modelToUse || 'cli_default';
476
+
477
+ if (detectedModel && detectedModel !== model) {
478
+ console.log(`[Polydev CLI] Codex CLI detected model: ${detectedModel} (requested: ${model || 'none'})`);
479
+ }
480
+
481
+ return {
482
+ success: true,
483
+ content,
484
+ tokens_used: this.estimateTokens(prompt + content),
485
+ latency_ms: Date.now() - startTime,
486
+ provider: providerId,
487
+ mode: 'args',
488
+ model_used: actualModel,
489
+ timestamp: new Date()
490
+ };
491
+ } catch (error) {
492
+ const errorMsg = error instanceof Error ? error.message : String(error);
493
+
494
+ // Check if error is model-related and we can retry
495
+ const isModelError = errorMsg.includes('model') && (
496
+ errorMsg.includes('not supported') ||
497
+ errorMsg.includes('not found') ||
498
+ errorMsg.includes('invalid')
499
+ );
500
+
501
+ if (isModelError && modelToUse && attempts < maxAttempts) {
502
+ console.log(`[Polydev CLI] Model '${modelToUse}' error for Codex CLI, retrying with CLI default...`);
503
+ modelToUse = null; // Retry without model flag
504
+ continue;
505
+ }
506
+
507
+ return {
508
+ success: false,
509
+ error: `CLI execution failed: ${errorMsg}`,
510
+ latency_ms: Date.now() - startTime,
511
+ provider: providerId,
512
+ mode,
513
+ timestamp: new Date()
514
+ };
457
515
  }
458
-
459
- return {
460
- success: true,
461
- content,
462
- tokens_used: this.estimateTokens(prompt + content),
463
- latency_ms: Date.now() - startTime,
464
- provider: providerId,
465
- mode: 'args',
466
- model_used: actualModel,
467
- timestamp: new Date()
468
- };
469
- } catch (error) {
470
- return {
471
- success: false,
472
- error: `CLI execution failed: ${error instanceof Error ? error.message : String(error)}`,
473
- latency_ms: Date.now() - startTime,
474
- provider: providerId,
475
- mode,
476
- timestamp: new Date()
477
- };
478
516
  }
479
517
  }
480
518
 
@@ -644,9 +682,50 @@ This is a known issue with @google/gemini-cli@0.3.4 and older Node.js versions.`
644
682
 
645
683
  let stdout = '';
646
684
  let stderr = '';
685
+ let resolved = false;
686
+ let debounceTimer = null;
687
+
688
+ // Helper to check if output looks complete (for JSON output from claude code)
689
+ const looksComplete = () => {
690
+ const trimmed = stdout.trim();
691
+ // For JSON output, check if it's valid JSON
692
+ if (trimmed.startsWith('{') || trimmed.startsWith('[')) {
693
+ try {
694
+ JSON.parse(trimmed);
695
+ return true; // Valid JSON means complete
696
+ } catch {
697
+ return false;
698
+ }
699
+ }
700
+ // For text output, check if we have substantial content
701
+ return trimmed.length > 50 && trimmed.includes('\n');
702
+ };
703
+
704
+ const doResolve = () => {
705
+ if (resolved) return;
706
+ resolved = true;
707
+ if (debounceTimer) clearTimeout(debounceTimer);
708
+ if (timeoutId) clearTimeout(timeoutId);
709
+ if (!child.killed) {
710
+ try { child.kill('SIGTERM'); } catch(_) {}
711
+ }
712
+ resolve({ stdout, stderr });
713
+ };
714
+
715
+ // Schedule early return check after debounce period
716
+ const scheduleEarlyReturn = () => {
717
+ if (debounceTimer) clearTimeout(debounceTimer);
718
+ debounceTimer = setTimeout(() => {
719
+ if (!resolved && looksComplete()) {
720
+ console.log('[CLI Debug] Early return - output looks complete');
721
+ doResolve();
722
+ }
723
+ }, 2000); // Wait 2 seconds after last data for Claude Code (faster JSON parsing)
724
+ };
647
725
 
648
726
  child.stdout?.on('data', (data) => {
649
727
  stdout += data.toString();
728
+ scheduleEarlyReturn();
650
729
  });
651
730
 
652
731
  child.stderr?.on('data', (data) => {
@@ -659,6 +738,11 @@ This is a known issue with @google/gemini-cli@0.3.4 and older Node.js versions.`
659
738
  }
660
739
 
661
740
  child.on('close', (code) => {
741
+ if (resolved) return;
742
+ resolved = true;
743
+ if (debounceTimer) clearTimeout(debounceTimer);
744
+ if (timeoutId) clearTimeout(timeoutId);
745
+
662
746
  if (process.env.POLYDEV_CLI_DEBUG) {
663
747
  console.log(`[CLI Debug] Command finished with code ${code}`);
664
748
  }
@@ -679,6 +763,10 @@ This is a known issue with @google/gemini-cli@0.3.4 and older Node.js versions.`
679
763
  });
680
764
 
681
765
  child.on('error', (error) => {
766
+ if (resolved) return;
767
+ resolved = true;
768
+ if (debounceTimer) clearTimeout(debounceTimer);
769
+ if (timeoutId) clearTimeout(timeoutId);
682
770
  if (process.env.POLYDEV_CLI_DEBUG) {
683
771
  console.log(`[CLI Debug] Command error:`, error);
684
772
  }
@@ -686,15 +774,11 @@ This is a known issue with @google/gemini-cli@0.3.4 and older Node.js versions.`
686
774
  });
687
775
 
688
776
  let timeoutId;
689
- const cleanup = () => {
690
- if (timeoutId) {
691
- clearTimeout(timeoutId);
692
- timeoutId = null;
693
- }
694
- };
695
777
 
696
778
  timeoutId = setTimeout(() => {
697
- cleanup();
779
+ if (resolved) return;
780
+ resolved = true;
781
+ if (debounceTimer) clearTimeout(debounceTimer);
698
782
  if (!child.killed) {
699
783
  child.kill('SIGTERM');
700
784
  // Force kill after 2 seconds if still running
@@ -707,12 +791,8 @@ This is a known issue with @google/gemini-cli@0.3.4 and older Node.js versions.`
707
791
  reject(new Error(`Command timeout after ${timeoutMs}ms`));
708
792
  }, timeoutMs);
709
793
 
710
- child.on('close', () => {
711
- cleanup();
712
- });
713
-
714
794
  child.on('exit', () => {
715
- cleanup();
795
+ if (debounceTimer) clearTimeout(debounceTimer);
716
796
  });
717
797
  });
718
798
  }
@@ -888,10 +968,12 @@ This is a known issue with @google/gemini-cli@0.3.4 and older Node.js versions.`
888
968
  let stdout = '';
889
969
  let stderr = '';
890
970
  let resolved = false;
971
+ let debounceTimer = null; // Smart debounce timer for early return
891
972
 
892
973
  const stop = (handler) => {
893
974
  if (!resolved) {
894
975
  resolved = true;
976
+ if (debounceTimer) clearTimeout(debounceTimer);
895
977
  try { child.kill('SIGTERM'); } catch (_) {}
896
978
  handler();
897
979
  }
@@ -981,18 +1063,31 @@ This is a known issue with @google/gemini-cli@0.3.4 and older Node.js versions.`
981
1063
  // Check if we have a complete response - look for actual content
982
1064
  const flushIfComplete = () => {
983
1065
  const parsed = parseCodexOutput(stdout);
984
- // Only resolve early if we have meaningful content (at least 2 chars) and output seems done
985
- // This prevents cutting off multi-line responses
986
- if (parsed && parsed.length >= 2 && stdout.includes('\n') && !stdout.endsWith('...')) {
1066
+ // Only resolve early if we have meaningful content (at least 20 chars) and output looks complete
1067
+ // Look for signs that Codex has finished outputting (tokens used, empty lines at end, etc.)
1068
+ if (parsed && parsed.length >= 20) {
1069
+ const detectedModel = this.detectModelFromOutput('codex_cli', stdout, stderr);
987
1070
  clearTimeout(timeoutHandle);
988
- stop(() => resolve(parsed));
1071
+ if (debounceTimer) clearTimeout(debounceTimer);
1072
+ stop(() => resolve({ content: parsed, detectedModel, rawStdout: stdout.trim(), rawStderr: stderr.trim() }));
989
1073
  }
990
1074
  };
991
1075
 
1076
+ // Smart debounce: wait 3 seconds after last data received before checking for early return
1077
+ const scheduleEarlyReturn = () => {
1078
+ if (debounceTimer) clearTimeout(debounceTimer);
1079
+ debounceTimer = setTimeout(() => {
1080
+ if (!resolved) {
1081
+ console.log('[CLI Debug] Checking for early return after debounce...');
1082
+ flushIfComplete();
1083
+ }
1084
+ }, 3000); // Wait 3 seconds after last data received
1085
+ };
1086
+
992
1087
  child.stdout?.on('data', (data) => {
993
1088
  stdout += data.toString();
994
- // Don't flush too eagerly - wait a bit for more data
995
- // flushIfComplete(); // Disabled: let the process complete naturally
1089
+ // Schedule early return check after debounce period
1090
+ scheduleEarlyReturn();
996
1091
  });
997
1092
 
998
1093
  child.stderr?.on('data', (data) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "polydev-ai",
3
- "version": "1.8.9",
3
+ "version": "1.8.11",
4
4
  "description": "Agentic workflow assistant with CLI integration - get diverse perspectives from multiple LLMs when stuck or need enhanced reasoning",
5
5
  "keywords": [
6
6
  "mcp",