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.
- package/lib/cliManager.js +144 -49
- 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
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
985
|
-
//
|
|
986
|
-
if (parsed && parsed.length >=
|
|
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
|
-
|
|
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
|
-
//
|
|
995
|
-
|
|
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