@adhdev/daemon-core 0.6.55 → 0.6.57
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/dist/index.d.ts +14 -0
- package/dist/index.js +313 -276
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
- package/src/cli-adapters/provider-cli-adapter.ts +230 -22
- package/src/cli-adapters/terminal-screen.ts +66 -239
- package/src/daemon/dev-server.ts +69 -35
- package/src/providers/cli-provider-instance.ts +2 -1
package/dist/index.js
CHANGED
|
@@ -592,240 +592,67 @@ var init_logger = __esm({
|
|
|
592
592
|
});
|
|
593
593
|
|
|
594
594
|
// src/cli-adapters/terminal-screen.ts
|
|
595
|
-
function
|
|
596
|
-
|
|
595
|
+
function loadTerminalCtor() {
|
|
596
|
+
if (!TerminalCtor) {
|
|
597
|
+
const mod = require("@xterm/xterm");
|
|
598
|
+
TerminalCtor = mod.Terminal || mod.default?.Terminal || mod.default;
|
|
599
|
+
if (!TerminalCtor) {
|
|
600
|
+
throw new Error("@xterm/xterm Terminal export not found");
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
return TerminalCtor;
|
|
597
604
|
}
|
|
598
|
-
var TerminalScreen;
|
|
605
|
+
var TerminalCtor, TerminalScreen;
|
|
599
606
|
var init_terminal_screen = __esm({
|
|
600
607
|
"src/cli-adapters/terminal-screen.ts"() {
|
|
601
608
|
"use strict";
|
|
609
|
+
TerminalCtor = null;
|
|
602
610
|
TerminalScreen = class {
|
|
603
611
|
rows;
|
|
604
612
|
cols;
|
|
605
|
-
|
|
606
|
-
cursorCol = 0;
|
|
607
|
-
savedRow = 0;
|
|
608
|
-
savedCol = 0;
|
|
609
|
-
lines;
|
|
613
|
+
terminal;
|
|
610
614
|
constructor(rows = 40, cols = 120) {
|
|
611
|
-
this.rows = rows;
|
|
612
|
-
this.cols = cols;
|
|
613
|
-
this.
|
|
615
|
+
this.rows = Math.max(1, rows | 0);
|
|
616
|
+
this.cols = Math.max(1, cols | 0);
|
|
617
|
+
this.terminal = this.createTerminal();
|
|
614
618
|
}
|
|
615
619
|
reset(rows = this.rows, cols = this.cols) {
|
|
616
|
-
this.rows = rows;
|
|
617
|
-
this.cols = cols;
|
|
618
|
-
this.
|
|
619
|
-
this.
|
|
620
|
-
this.savedRow = 0;
|
|
621
|
-
this.savedCol = 0;
|
|
622
|
-
this.lines = this.makeLines(rows, cols);
|
|
620
|
+
this.rows = Math.max(1, rows | 0);
|
|
621
|
+
this.cols = Math.max(1, cols | 0);
|
|
622
|
+
this.terminal.dispose();
|
|
623
|
+
this.terminal = this.createTerminal();
|
|
623
624
|
}
|
|
624
625
|
resize(rows, cols) {
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
const copyRows = Math.min(this.rows, nextRows);
|
|
629
|
-
const copyCols = Math.min(this.cols, nextCols);
|
|
630
|
-
for (let r = 0; r < copyRows; r++) {
|
|
631
|
-
for (let c = 0; c < copyCols; c++) {
|
|
632
|
-
next[r][c] = this.lines[r][c];
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
this.rows = nextRows;
|
|
636
|
-
this.cols = nextCols;
|
|
637
|
-
this.lines = next;
|
|
638
|
-
this.cursorRow = clamp(this.cursorRow, 0, this.rows - 1);
|
|
639
|
-
this.cursorCol = clamp(this.cursorCol, 0, this.cols - 1);
|
|
640
|
-
this.savedRow = clamp(this.savedRow, 0, this.rows - 1);
|
|
641
|
-
this.savedCol = clamp(this.savedCol, 0, this.cols - 1);
|
|
626
|
+
this.rows = Math.max(1, rows | 0);
|
|
627
|
+
this.cols = Math.max(1, cols | 0);
|
|
628
|
+
this.terminal.resize(this.cols, this.rows);
|
|
642
629
|
}
|
|
643
630
|
write(data) {
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
const ch = data[i];
|
|
647
|
-
if (ch === "\x1B") {
|
|
648
|
-
const consumed = this.consumeEscape(data, i);
|
|
649
|
-
i = consumed > i ? consumed : i + 1;
|
|
650
|
-
continue;
|
|
651
|
-
}
|
|
652
|
-
if (ch === "\r") {
|
|
653
|
-
this.cursorCol = 0;
|
|
654
|
-
i++;
|
|
655
|
-
continue;
|
|
656
|
-
}
|
|
657
|
-
if (ch === "\n") {
|
|
658
|
-
this.newLine();
|
|
659
|
-
i++;
|
|
660
|
-
continue;
|
|
661
|
-
}
|
|
662
|
-
if (ch === "\b") {
|
|
663
|
-
this.cursorCol = Math.max(0, this.cursorCol - 1);
|
|
664
|
-
i++;
|
|
665
|
-
continue;
|
|
666
|
-
}
|
|
667
|
-
if (ch === " ") {
|
|
668
|
-
const nextStop = Math.min(this.cols - 1, this.cursorCol + (8 - (this.cursorCol % 8 || 8)));
|
|
669
|
-
while (this.cursorCol < nextStop) this.putChar(" ");
|
|
670
|
-
i++;
|
|
671
|
-
continue;
|
|
672
|
-
}
|
|
673
|
-
if (ch >= " " && ch !== "\x7F") {
|
|
674
|
-
this.putChar(ch);
|
|
675
|
-
}
|
|
676
|
-
i++;
|
|
677
|
-
}
|
|
631
|
+
if (!data) return;
|
|
632
|
+
this.terminal.write(data);
|
|
678
633
|
}
|
|
679
634
|
getText() {
|
|
680
|
-
const
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
if (data[end] === "\x1B" && data[end + 1] === "\\") return end + 2;
|
|
702
|
-
end++;
|
|
703
|
-
}
|
|
704
|
-
return data.length;
|
|
705
|
-
}
|
|
706
|
-
if (next === "7") {
|
|
707
|
-
this.savedRow = this.cursorRow;
|
|
708
|
-
this.savedCol = this.cursorCol;
|
|
709
|
-
return start + 2;
|
|
710
|
-
}
|
|
711
|
-
if (next === "8") {
|
|
712
|
-
this.cursorRow = this.savedRow;
|
|
713
|
-
this.cursorCol = this.savedCol;
|
|
714
|
-
return start + 2;
|
|
715
|
-
}
|
|
716
|
-
return start + 2;
|
|
717
|
-
}
|
|
718
|
-
applyCsi(paramText, finalChar) {
|
|
719
|
-
const privateMode = paramText.startsWith("?");
|
|
720
|
-
const normalized = privateMode ? paramText.slice(1) : paramText;
|
|
721
|
-
const params = normalized.length > 0 ? normalized.split(";").map((p) => parseInt(p || "0", 10) || 0) : [0];
|
|
722
|
-
switch (finalChar) {
|
|
723
|
-
case "A":
|
|
724
|
-
this.cursorRow = clamp(this.cursorRow - (params[0] || 1), 0, this.rows - 1);
|
|
725
|
-
return;
|
|
726
|
-
case "B":
|
|
727
|
-
this.cursorRow = clamp(this.cursorRow + (params[0] || 1), 0, this.rows - 1);
|
|
728
|
-
return;
|
|
729
|
-
case "C":
|
|
730
|
-
this.cursorCol = clamp(this.cursorCol + (params[0] || 1), 0, this.cols - 1);
|
|
731
|
-
return;
|
|
732
|
-
case "D":
|
|
733
|
-
this.cursorCol = clamp(this.cursorCol - (params[0] || 1), 0, this.cols - 1);
|
|
734
|
-
return;
|
|
735
|
-
case "E":
|
|
736
|
-
this.cursorRow = clamp(this.cursorRow + (params[0] || 1), 0, this.rows - 1);
|
|
737
|
-
this.cursorCol = 0;
|
|
738
|
-
return;
|
|
739
|
-
case "F":
|
|
740
|
-
this.cursorRow = clamp(this.cursorRow - (params[0] || 1), 0, this.rows - 1);
|
|
741
|
-
this.cursorCol = 0;
|
|
742
|
-
return;
|
|
743
|
-
case "G":
|
|
744
|
-
this.cursorCol = clamp((params[0] || 1) - 1, 0, this.cols - 1);
|
|
745
|
-
return;
|
|
746
|
-
case "H":
|
|
747
|
-
case "f": {
|
|
748
|
-
const row = (params[0] || 1) - 1;
|
|
749
|
-
const col = (params[1] || 1) - 1;
|
|
750
|
-
this.cursorRow = clamp(row, 0, this.rows - 1);
|
|
751
|
-
this.cursorCol = clamp(col, 0, this.cols - 1);
|
|
752
|
-
return;
|
|
753
|
-
}
|
|
754
|
-
case "J": {
|
|
755
|
-
const mode = params[0] || 0;
|
|
756
|
-
if (mode === 2 || mode === 3) {
|
|
757
|
-
this.reset(this.rows, this.cols);
|
|
758
|
-
} else if (mode === 0) {
|
|
759
|
-
this.clearToEndOfScreen();
|
|
760
|
-
} else if (mode === 1) {
|
|
761
|
-
this.clearToStartOfScreen();
|
|
762
|
-
}
|
|
763
|
-
return;
|
|
764
|
-
}
|
|
765
|
-
case "K": {
|
|
766
|
-
const mode = params[0] || 0;
|
|
767
|
-
if (mode === 2) this.clearLine(this.cursorRow, 0, this.cols - 1);
|
|
768
|
-
else if (mode === 1) this.clearLine(this.cursorRow, 0, this.cursorCol);
|
|
769
|
-
else this.clearLine(this.cursorRow, this.cursorCol, this.cols - 1);
|
|
770
|
-
return;
|
|
771
|
-
}
|
|
772
|
-
case "m":
|
|
773
|
-
return;
|
|
774
|
-
case "s":
|
|
775
|
-
this.savedRow = this.cursorRow;
|
|
776
|
-
this.savedCol = this.cursorCol;
|
|
777
|
-
return;
|
|
778
|
-
case "u":
|
|
779
|
-
this.cursorRow = this.savedRow;
|
|
780
|
-
this.cursorCol = this.savedCol;
|
|
781
|
-
return;
|
|
782
|
-
case "h":
|
|
783
|
-
case "l":
|
|
784
|
-
if (privateMode && (normalized === "1049" || normalized === "47")) {
|
|
785
|
-
this.reset(this.rows, this.cols);
|
|
786
|
-
}
|
|
787
|
-
return;
|
|
788
|
-
default:
|
|
789
|
-
return;
|
|
790
|
-
}
|
|
791
|
-
}
|
|
792
|
-
putChar(ch) {
|
|
793
|
-
if (this.cursorRow < 0 || this.cursorRow >= this.rows) return;
|
|
794
|
-
if (this.cursorCol < 0) this.cursorCol = 0;
|
|
795
|
-
if (this.cursorCol >= this.cols) this.newLine();
|
|
796
|
-
this.lines[this.cursorRow][this.cursorCol] = ch;
|
|
797
|
-
this.cursorCol++;
|
|
798
|
-
if (this.cursorCol >= this.cols) this.newLine();
|
|
799
|
-
}
|
|
800
|
-
newLine() {
|
|
801
|
-
this.cursorCol = 0;
|
|
802
|
-
if (this.cursorRow >= this.rows - 1) {
|
|
803
|
-
this.lines.shift();
|
|
804
|
-
this.lines.push(Array.from({ length: this.cols }, () => " "));
|
|
805
|
-
} else {
|
|
806
|
-
this.cursorRow++;
|
|
807
|
-
}
|
|
808
|
-
}
|
|
809
|
-
clearLine(row, start, end) {
|
|
810
|
-
if (row < 0 || row >= this.rows) return;
|
|
811
|
-
for (let c = clamp(start, 0, this.cols - 1); c <= clamp(end, 0, this.cols - 1); c++) {
|
|
812
|
-
this.lines[row][c] = " ";
|
|
813
|
-
}
|
|
814
|
-
}
|
|
815
|
-
clearToEndOfScreen() {
|
|
816
|
-
this.clearLine(this.cursorRow, this.cursorCol, this.cols - 1);
|
|
817
|
-
for (let r = this.cursorRow + 1; r < this.rows; r++) {
|
|
818
|
-
this.clearLine(r, 0, this.cols - 1);
|
|
819
|
-
}
|
|
820
|
-
}
|
|
821
|
-
clearToStartOfScreen() {
|
|
822
|
-
for (let r = 0; r < this.cursorRow; r++) {
|
|
823
|
-
this.clearLine(r, 0, this.cols - 1);
|
|
824
|
-
}
|
|
825
|
-
this.clearLine(this.cursorRow, 0, this.cursorCol);
|
|
826
|
-
}
|
|
827
|
-
makeLines(rows, cols) {
|
|
828
|
-
return Array.from({ length: rows }, () => Array.from({ length: cols }, () => " "));
|
|
635
|
+
const buffer = this.terminal.buffer.active;
|
|
636
|
+
const start = Math.max(0, buffer.viewportY || 0);
|
|
637
|
+
const end = Math.max(start, Math.min(buffer.length || 0, start + this.rows));
|
|
638
|
+
const lines = [];
|
|
639
|
+
for (let i = start; i < end; i++) {
|
|
640
|
+
const line = buffer.getLine(i);
|
|
641
|
+
lines.push(line ? line.translateToString(true) : "");
|
|
642
|
+
}
|
|
643
|
+
let first = 0;
|
|
644
|
+
let last = lines.length;
|
|
645
|
+
while (first < last && !lines[first]?.trim()) first++;
|
|
646
|
+
while (last > first && !lines[last - 1]?.trim()) last--;
|
|
647
|
+
return lines.slice(first, last).join("\n");
|
|
648
|
+
}
|
|
649
|
+
createTerminal() {
|
|
650
|
+
const Terminal = loadTerminalCtor();
|
|
651
|
+
return new Terminal({
|
|
652
|
+
cols: this.cols,
|
|
653
|
+
rows: this.rows,
|
|
654
|
+
scrollback: 2e3
|
|
655
|
+
});
|
|
829
656
|
}
|
|
830
657
|
};
|
|
831
658
|
}
|
|
@@ -891,6 +718,38 @@ function shSingleQuote(arg) {
|
|
|
891
718
|
if (/^[a-zA-Z0-9@%_+=:,./-]+$/.test(arg)) return arg;
|
|
892
719
|
return `'${arg.replace(/'/g, `'\\''`)}'`;
|
|
893
720
|
}
|
|
721
|
+
function estimatePromptDisplayLines(text, cols = 100) {
|
|
722
|
+
const normalized = String(text || "").replace(/\r/g, "");
|
|
723
|
+
if (!normalized) return 1;
|
|
724
|
+
return normalized.split("\n").reduce((sum, line) => sum + Math.max(1, Math.ceil(Math.max(1, line.length) / cols)), 0);
|
|
725
|
+
}
|
|
726
|
+
function extractPromptRetrySnippet(text) {
|
|
727
|
+
const lines = String(text || "").replace(/\r/g, "").split("\n").map((line) => line.trim()).filter(Boolean);
|
|
728
|
+
const candidate = lines[lines.length - 1] || lines[0] || "";
|
|
729
|
+
return candidate.slice(-120);
|
|
730
|
+
}
|
|
731
|
+
function normalizePromptText(text) {
|
|
732
|
+
return String(text || "").replace(/\s+/g, " ").trim();
|
|
733
|
+
}
|
|
734
|
+
function compactPromptText(text) {
|
|
735
|
+
return String(text || "").replace(/\s+/g, "").trim();
|
|
736
|
+
}
|
|
737
|
+
function promptLikelyVisible(screenText, promptSnippet) {
|
|
738
|
+
const snippet = normalizePromptText(promptSnippet);
|
|
739
|
+
if (!snippet) return false;
|
|
740
|
+
const normalizedScreen = normalizePromptText(screenText);
|
|
741
|
+
if (normalizedScreen.includes(snippet)) return true;
|
|
742
|
+
const compactScreen = compactPromptText(screenText);
|
|
743
|
+
const compactSnippet = compactPromptText(promptSnippet);
|
|
744
|
+
if (compactSnippet && compactScreen.includes(compactSnippet)) return true;
|
|
745
|
+
const tokens = snippet.split(/[^A-Za-z0-9_.:/-]+/).map((token) => token.trim()).filter((token) => token.length >= 4);
|
|
746
|
+
if (tokens.length === 0) return false;
|
|
747
|
+
const required = Math.min(tokens.length, 3);
|
|
748
|
+
const matched = tokens.filter(
|
|
749
|
+
(token) => normalizedScreen.includes(token) || compactScreen.includes(compactPromptText(token))
|
|
750
|
+
).length;
|
|
751
|
+
return matched >= required;
|
|
752
|
+
}
|
|
894
753
|
function parsePatternEntry(x) {
|
|
895
754
|
if (x instanceof RegExp) return x;
|
|
896
755
|
if (x && typeof x === "object" && typeof x.source === "string") {
|
|
@@ -965,6 +824,8 @@ var init_provider_cli_adapter = __esm({
|
|
|
965
824
|
};
|
|
966
825
|
const rawKeys = provider.approvalKeys;
|
|
967
826
|
this.approvalKeys = rawKeys && typeof rawKeys === "object" ? rawKeys : {};
|
|
827
|
+
this.sendDelayMs = typeof provider.sendDelayMs === "number" ? Math.max(0, provider.sendDelayMs) : 0;
|
|
828
|
+
this.sendKey = typeof provider.sendKey === "string" && provider.sendKey.length > 0 ? provider.sendKey : "\r";
|
|
968
829
|
this.cliScripts = provider.scripts || {};
|
|
969
830
|
const scriptNames = Object.keys(this.cliScripts).filter((k) => typeof this.cliScripts[k] === "function");
|
|
970
831
|
if (scriptNames.length > 0) {
|
|
@@ -1007,6 +868,12 @@ var init_provider_cli_adapter = __esm({
|
|
|
1007
868
|
// Output settle debounce — fires after PTY output goes quiet
|
|
1008
869
|
settleTimer = null;
|
|
1009
870
|
settledBuffer = "";
|
|
871
|
+
submitPendingUntil = 0;
|
|
872
|
+
responseSettleIgnoreUntil = 0;
|
|
873
|
+
responseEpoch = 0;
|
|
874
|
+
submitRetryTimer = null;
|
|
875
|
+
submitRetryUsed = false;
|
|
876
|
+
submitRetryPromptSnippet = "";
|
|
1010
877
|
// Resize redraw suppression
|
|
1011
878
|
resizeSuppressUntil = 0;
|
|
1012
879
|
// Debug: status transition history
|
|
@@ -1033,6 +900,8 @@ var init_provider_cli_adapter = __esm({
|
|
|
1033
900
|
timeouts;
|
|
1034
901
|
// Provider approval key mapping
|
|
1035
902
|
approvalKeys;
|
|
903
|
+
sendDelayMs;
|
|
904
|
+
sendKey;
|
|
1036
905
|
/** Inject CLI scripts after construction (e.g. when resolved by ProviderLoader) */
|
|
1037
906
|
setCliScripts(scripts) {
|
|
1038
907
|
this.cliScripts = scripts;
|
|
@@ -1128,13 +997,16 @@ var init_provider_cli_adapter = __esm({
|
|
|
1128
997
|
this.startupParseGate = true;
|
|
1129
998
|
this.startupBuffer = "";
|
|
1130
999
|
this.terminalScreen.reset(40, 120);
|
|
1131
|
-
this.ready =
|
|
1000
|
+
this.ready = false;
|
|
1132
1001
|
this.setStatus("idle", "pty_ready");
|
|
1133
1002
|
this.onStatusChange?.();
|
|
1134
1003
|
}
|
|
1135
1004
|
// ─── Output Handling ────────────────────────────
|
|
1136
1005
|
handleOutput(rawData) {
|
|
1137
1006
|
if (Date.now() < this.resizeSuppressUntil) return;
|
|
1007
|
+
if (rawData.includes("\x1B[6n") || rawData.includes("\x1B[?6n")) {
|
|
1008
|
+
this.ptyProcess?.write("\x1B[1;1R");
|
|
1009
|
+
}
|
|
1138
1010
|
this.terminalScreen.write(rawData);
|
|
1139
1011
|
const cleanData = stripAnsi(rawData);
|
|
1140
1012
|
if (this.isWaitingForResponse && cleanData) {
|
|
@@ -1170,7 +1042,9 @@ var init_provider_cli_adapter = __esm({
|
|
|
1170
1042
|
const isReady = scriptStatus === "idle" || elapsed > 8e3 || bufCap;
|
|
1171
1043
|
if (isReady) {
|
|
1172
1044
|
this.startupParseGate = false;
|
|
1045
|
+
this.ready = true;
|
|
1173
1046
|
LOG.info("CLI", `[${this.cliType}] Startup gate end (${elapsed}ms, scriptStatus=${scriptStatus})`);
|
|
1047
|
+
this.onStatusChange?.();
|
|
1174
1048
|
} else {
|
|
1175
1049
|
return;
|
|
1176
1050
|
}
|
|
@@ -1179,15 +1053,45 @@ var init_provider_cli_adapter = __esm({
|
|
|
1179
1053
|
}
|
|
1180
1054
|
scheduleSettle() {
|
|
1181
1055
|
if (this.settleTimer) clearTimeout(this.settleTimer);
|
|
1056
|
+
const settleEpoch = this.responseEpoch;
|
|
1057
|
+
const delay = Math.max(
|
|
1058
|
+
this.timeouts.outputSettle,
|
|
1059
|
+
this.submitPendingUntil > Date.now() ? this.submitPendingUntil - Date.now() + this.timeouts.outputSettle : 0
|
|
1060
|
+
);
|
|
1182
1061
|
this.settleTimer = setTimeout(() => {
|
|
1183
1062
|
this.settleTimer = null;
|
|
1063
|
+
if (settleEpoch !== this.responseEpoch) return;
|
|
1184
1064
|
this.settledBuffer = this.recentOutputBuffer;
|
|
1185
1065
|
this.evaluateSettled();
|
|
1186
|
-
},
|
|
1066
|
+
}, delay);
|
|
1067
|
+
}
|
|
1068
|
+
armApprovalExitTimeout() {
|
|
1069
|
+
if (this.approvalExitTimeout) clearTimeout(this.approvalExitTimeout);
|
|
1070
|
+
this.approvalExitTimeout = setTimeout(() => {
|
|
1071
|
+
if (this.currentStatus !== "waiting_approval") return;
|
|
1072
|
+
const tail = this.recentOutputBuffer;
|
|
1073
|
+
const modal = this.runParseApproval(tail);
|
|
1074
|
+
const stillWaiting = this.runDetectStatus(tail) === "waiting_approval" || !!modal;
|
|
1075
|
+
if (stillWaiting) {
|
|
1076
|
+
this.activeModal = modal || this.activeModal || { message: "Approval required", buttons: ["Allow", "Deny"] };
|
|
1077
|
+
this.onStatusChange?.();
|
|
1078
|
+
this.armApprovalExitTimeout();
|
|
1079
|
+
return;
|
|
1080
|
+
}
|
|
1081
|
+
LOG.warn("CLI", `[${this.cliType}] Approval timeout \u2014 auto-clearing`);
|
|
1082
|
+
this.activeModal = null;
|
|
1083
|
+
this.lastApprovalResolvedAt = Date.now();
|
|
1084
|
+
this.setStatus("idle", "approval_timeout");
|
|
1085
|
+
this.onStatusChange?.();
|
|
1086
|
+
}, 6e4);
|
|
1187
1087
|
}
|
|
1188
1088
|
evaluateSettled() {
|
|
1089
|
+
if (this.submitPendingUntil > Date.now()) return;
|
|
1090
|
+
if (this.responseSettleIgnoreUntil > Date.now()) return;
|
|
1189
1091
|
const tail = this.settledBuffer;
|
|
1190
|
-
const
|
|
1092
|
+
const modal = this.runParseApproval(tail);
|
|
1093
|
+
const rawScriptStatus = this.runDetectStatus(tail);
|
|
1094
|
+
const scriptStatus = rawScriptStatus === "waiting_approval" || modal ? "waiting_approval" : rawScriptStatus;
|
|
1191
1095
|
if (!scriptStatus) return;
|
|
1192
1096
|
const prevStatus = this.currentStatus;
|
|
1193
1097
|
if (scriptStatus === "waiting_approval") {
|
|
@@ -1195,19 +1099,9 @@ var init_provider_cli_adapter = __esm({
|
|
|
1195
1099
|
if (!inCooldown) {
|
|
1196
1100
|
this.isWaitingForResponse = true;
|
|
1197
1101
|
this.setStatus("waiting_approval", "script_detect");
|
|
1198
|
-
const modal = this.runParseApproval(tail);
|
|
1199
1102
|
this.activeModal = modal || { message: "Approval required", buttons: ["Allow", "Deny"] };
|
|
1200
1103
|
if (this.idleTimeout) clearTimeout(this.idleTimeout);
|
|
1201
|
-
|
|
1202
|
-
this.approvalExitTimeout = setTimeout(() => {
|
|
1203
|
-
if (this.currentStatus === "waiting_approval") {
|
|
1204
|
-
LOG.warn("CLI", `[${this.cliType}] Approval timeout \u2014 auto-clearing`);
|
|
1205
|
-
this.activeModal = null;
|
|
1206
|
-
this.lastApprovalResolvedAt = Date.now();
|
|
1207
|
-
this.setStatus("idle", "approval_timeout");
|
|
1208
|
-
this.onStatusChange?.();
|
|
1209
|
-
}
|
|
1210
|
-
}, 6e4);
|
|
1104
|
+
this.armApprovalExitTimeout();
|
|
1211
1105
|
this.onStatusChange?.();
|
|
1212
1106
|
return;
|
|
1213
1107
|
}
|
|
@@ -1243,7 +1137,12 @@ var init_provider_cli_adapter = __esm({
|
|
|
1243
1137
|
this.lastApprovalResolvedAt = Date.now();
|
|
1244
1138
|
}
|
|
1245
1139
|
if (this.isWaitingForResponse) {
|
|
1246
|
-
this.
|
|
1140
|
+
if (this.idleTimeout) clearTimeout(this.idleTimeout);
|
|
1141
|
+
this.idleTimeout = setTimeout(() => {
|
|
1142
|
+
if (this.isWaitingForResponse && this.currentStatus !== "waiting_approval") {
|
|
1143
|
+
this.finishResponse();
|
|
1144
|
+
}
|
|
1145
|
+
}, this.timeouts.idleFinish);
|
|
1247
1146
|
} else if (prevStatus !== "idle") {
|
|
1248
1147
|
this.setStatus("idle", "script_detect");
|
|
1249
1148
|
this.onStatusChange?.();
|
|
@@ -1251,6 +1150,8 @@ var init_provider_cli_adapter = __esm({
|
|
|
1251
1150
|
}
|
|
1252
1151
|
}
|
|
1253
1152
|
finishResponse() {
|
|
1153
|
+
if (this.submitPendingUntil > Date.now()) return;
|
|
1154
|
+
if (this.responseSettleIgnoreUntil > Date.now()) return;
|
|
1254
1155
|
if (this.responseTimeout) {
|
|
1255
1156
|
clearTimeout(this.responseTimeout);
|
|
1256
1157
|
this.responseTimeout = null;
|
|
@@ -1263,8 +1164,15 @@ var init_provider_cli_adapter = __esm({
|
|
|
1263
1164
|
clearTimeout(this.approvalExitTimeout);
|
|
1264
1165
|
this.approvalExitTimeout = null;
|
|
1265
1166
|
}
|
|
1167
|
+
if (this.submitRetryTimer) {
|
|
1168
|
+
clearTimeout(this.submitRetryTimer);
|
|
1169
|
+
this.submitRetryTimer = null;
|
|
1170
|
+
}
|
|
1266
1171
|
this.responseBuffer = "";
|
|
1267
1172
|
this.isWaitingForResponse = false;
|
|
1173
|
+
this.responseSettleIgnoreUntil = 0;
|
|
1174
|
+
this.submitRetryUsed = false;
|
|
1175
|
+
this.submitRetryPromptSnippet = "";
|
|
1268
1176
|
this.activeModal = null;
|
|
1269
1177
|
this.setStatus("idle", "response_finished");
|
|
1270
1178
|
this.onStatusChange?.();
|
|
@@ -1273,7 +1181,11 @@ var init_provider_cli_adapter = __esm({
|
|
|
1273
1181
|
runDetectStatus(text) {
|
|
1274
1182
|
if (!this.cliScripts?.detectStatus) return null;
|
|
1275
1183
|
try {
|
|
1276
|
-
return this.cliScripts.detectStatus({
|
|
1184
|
+
return this.cliScripts.detectStatus({
|
|
1185
|
+
tail: text.slice(-500),
|
|
1186
|
+
screenText: this.terminalScreen.getText(),
|
|
1187
|
+
rawBuffer: this.accumulatedRawBuffer
|
|
1188
|
+
});
|
|
1277
1189
|
} catch (e) {
|
|
1278
1190
|
LOG.warn("CLI", `[${this.cliType}] detectStatus error: ${e.message}`);
|
|
1279
1191
|
return null;
|
|
@@ -1375,18 +1287,95 @@ ${data.message || ""}`.trim();
|
|
|
1375
1287
|
}
|
|
1376
1288
|
async sendMessage(text) {
|
|
1377
1289
|
if (!this.ptyProcess) throw new Error(`${this.cliName} is not running`);
|
|
1290
|
+
if (this.startupParseGate) {
|
|
1291
|
+
const deadline = Date.now() + 1e4;
|
|
1292
|
+
while (this.startupParseGate && Date.now() < deadline) {
|
|
1293
|
+
await new Promise((resolve8) => setTimeout(resolve8, 50));
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1378
1296
|
if (!this.ready) throw new Error(`${this.cliName} not ready (status: ${this.currentStatus})`);
|
|
1379
1297
|
if (this.isWaitingForResponse) return;
|
|
1380
1298
|
this.messages.push({ role: "user", content: text, timestamp: Date.now() });
|
|
1381
1299
|
this.structuredMessages.push({ role: "user", content: text, timestamp: Date.now() });
|
|
1382
1300
|
this.isWaitingForResponse = true;
|
|
1383
1301
|
this.responseBuffer = "";
|
|
1302
|
+
this.submitRetryUsed = false;
|
|
1303
|
+
this.submitRetryPromptSnippet = extractPromptRetrySnippet(text);
|
|
1304
|
+
const normalizedPromptSnippet = normalizePromptText(this.submitRetryPromptSnippet);
|
|
1305
|
+
if (this.submitRetryTimer) {
|
|
1306
|
+
clearTimeout(this.submitRetryTimer);
|
|
1307
|
+
this.submitRetryTimer = null;
|
|
1308
|
+
}
|
|
1309
|
+
const estimatedLines = estimatePromptDisplayLines(text);
|
|
1310
|
+
const submitDelayMs = this.sendDelayMs + Math.min(2e3, Math.max(0, estimatedLines - 1) * 350);
|
|
1311
|
+
const maxEchoWaitMs = submitDelayMs + Math.max(1500, Math.min(5e3, estimatedLines * 500));
|
|
1312
|
+
const retryDelayMs = Math.max(350, Math.min(1500, Math.max(this.sendDelayMs, submitDelayMs)));
|
|
1313
|
+
if (this.settleTimer) {
|
|
1314
|
+
clearTimeout(this.settleTimer);
|
|
1315
|
+
this.settleTimer = null;
|
|
1316
|
+
}
|
|
1317
|
+
this.responseEpoch += 1;
|
|
1318
|
+
this.responseSettleIgnoreUntil = Date.now() + submitDelayMs + this.timeouts.outputSettle + 250;
|
|
1384
1319
|
this.setStatus("generating", "sendMessage");
|
|
1385
1320
|
this.onStatusChange?.();
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1321
|
+
if (submitDelayMs > 0) {
|
|
1322
|
+
this.submitPendingUntil = Date.now() + submitDelayMs;
|
|
1323
|
+
}
|
|
1324
|
+
this.ptyProcess.write(text);
|
|
1325
|
+
const submit = () => {
|
|
1326
|
+
if (!this.ptyProcess) return;
|
|
1327
|
+
this.submitPendingUntil = 0;
|
|
1328
|
+
this.ptyProcess.write(this.sendKey);
|
|
1329
|
+
const retrySubmitIfStuck = (attempt) => {
|
|
1330
|
+
this.submitRetryTimer = null;
|
|
1331
|
+
if (!this.ptyProcess || !this.isWaitingForResponse || this.submitRetryUsed) return;
|
|
1332
|
+
if (this.currentStatus !== "generating") return;
|
|
1333
|
+
if ((this.responseBuffer || "").trim()) return;
|
|
1334
|
+
const screenText = this.terminalScreen.getText();
|
|
1335
|
+
if (!promptLikelyVisible(screenText, normalizedPromptSnippet)) return;
|
|
1336
|
+
if (/Esc to interrupt|Do you want to proceed|This command requires approval|Allow Codex to|Approve and run now|Always approve this session|Running…|Running\.\.\./i.test(screenText)) return;
|
|
1337
|
+
this.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
|
|
1338
|
+
LOG.info("CLI", `[${this.cliType}] Retrying submit key for stuck prompt (attempt ${attempt})`);
|
|
1339
|
+
this.ptyProcess.write(this.sendKey);
|
|
1340
|
+
if (attempt >= 3) {
|
|
1341
|
+
this.submitRetryUsed = true;
|
|
1342
|
+
return;
|
|
1343
|
+
}
|
|
1344
|
+
this.submitRetryTimer = setTimeout(() => retrySubmitIfStuck(attempt + 1), retryDelayMs);
|
|
1345
|
+
};
|
|
1346
|
+
this.submitRetryTimer = setTimeout(() => retrySubmitIfStuck(1), retryDelayMs);
|
|
1347
|
+
this.responseTimeout = setTimeout(() => {
|
|
1348
|
+
if (this.isWaitingForResponse) this.finishResponse();
|
|
1349
|
+
}, this.timeouts.maxResponse);
|
|
1350
|
+
};
|
|
1351
|
+
const submitStartedAt = Date.now();
|
|
1352
|
+
let lastNormalizedScreen = "";
|
|
1353
|
+
let lastScreenChangeAt = submitStartedAt;
|
|
1354
|
+
const waitForEchoAndSubmit = () => {
|
|
1355
|
+
if (!this.ptyProcess) return;
|
|
1356
|
+
const now = Date.now();
|
|
1357
|
+
const elapsed = now - submitStartedAt;
|
|
1358
|
+
const screenText = this.terminalScreen.getText();
|
|
1359
|
+
const normalizedScreen = normalizePromptText(screenText);
|
|
1360
|
+
if (normalizedScreen !== lastNormalizedScreen) {
|
|
1361
|
+
lastNormalizedScreen = normalizedScreen;
|
|
1362
|
+
lastScreenChangeAt = now;
|
|
1363
|
+
}
|
|
1364
|
+
const echoVisible = !normalizedPromptSnippet || promptLikelyVisible(screenText, normalizedPromptSnippet);
|
|
1365
|
+
if (echoVisible) {
|
|
1366
|
+
const screenSettled = now - lastScreenChangeAt >= 500;
|
|
1367
|
+
if (elapsed >= submitDelayMs && screenSettled) {
|
|
1368
|
+
submit();
|
|
1369
|
+
return;
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
if (elapsed >= maxEchoWaitMs) {
|
|
1373
|
+
submit();
|
|
1374
|
+
return;
|
|
1375
|
+
}
|
|
1376
|
+
setTimeout(waitForEchoAndSubmit, 50);
|
|
1377
|
+
};
|
|
1378
|
+
waitForEchoAndSubmit();
|
|
1390
1379
|
}
|
|
1391
1380
|
getPartialResponse() {
|
|
1392
1381
|
if (!this.isWaitingForResponse) return "";
|
|
@@ -1404,6 +1393,10 @@ ${data.message || ""}`.trim();
|
|
|
1404
1393
|
clearTimeout(this.approvalExitTimeout);
|
|
1405
1394
|
this.approvalExitTimeout = null;
|
|
1406
1395
|
}
|
|
1396
|
+
if (this.submitRetryTimer) {
|
|
1397
|
+
clearTimeout(this.submitRetryTimer);
|
|
1398
|
+
this.submitRetryTimer = null;
|
|
1399
|
+
}
|
|
1407
1400
|
if (this.ptyProcess) {
|
|
1408
1401
|
this.ptyProcess.write("");
|
|
1409
1402
|
setTimeout(() => {
|
|
@@ -1425,6 +1418,8 @@ ${data.message || ""}`.trim();
|
|
|
1425
1418
|
this.structuredMessages = [];
|
|
1426
1419
|
this.accumulatedBuffer = "";
|
|
1427
1420
|
this.accumulatedRawBuffer = "";
|
|
1421
|
+
this.submitRetryUsed = false;
|
|
1422
|
+
this.submitRetryPromptSnippet = "";
|
|
1428
1423
|
this.terminalScreen.reset();
|
|
1429
1424
|
this.onStatusChange?.();
|
|
1430
1425
|
}
|
|
@@ -1438,7 +1433,16 @@ ${data.message || ""}`.trim();
|
|
|
1438
1433
|
this.ptyProcess?.write(data);
|
|
1439
1434
|
}
|
|
1440
1435
|
resolveModal(buttonIndex) {
|
|
1441
|
-
if (!this.ptyProcess || this.currentStatus !== "waiting_approval") return;
|
|
1436
|
+
if (!this.ptyProcess || this.currentStatus !== "waiting_approval" && !this.activeModal) return;
|
|
1437
|
+
this.activeModal = null;
|
|
1438
|
+
this.lastApprovalResolvedAt = Date.now();
|
|
1439
|
+
this.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
|
|
1440
|
+
if (this.approvalExitTimeout) {
|
|
1441
|
+
clearTimeout(this.approvalExitTimeout);
|
|
1442
|
+
this.approvalExitTimeout = null;
|
|
1443
|
+
}
|
|
1444
|
+
this.setStatus("generating", "approval_resolved");
|
|
1445
|
+
this.onStatusChange?.();
|
|
1442
1446
|
if (buttonIndex in this.approvalKeys) {
|
|
1443
1447
|
this.ptyProcess.write(this.approvalKeys[buttonIndex]);
|
|
1444
1448
|
} else {
|
|
@@ -1469,13 +1473,21 @@ ${data.message || ""}`.trim();
|
|
|
1469
1473
|
messages: this.messages.slice(-20),
|
|
1470
1474
|
structuredMessages: this.structuredMessages.slice(-20),
|
|
1471
1475
|
messageCount: this.messages.length,
|
|
1476
|
+
screenText: this.terminalScreen.getText().slice(-4e3),
|
|
1472
1477
|
startupBuffer: this.startupBuffer.slice(-4e3),
|
|
1473
1478
|
recentOutputBuffer: this.recentOutputBuffer.slice(-500),
|
|
1474
1479
|
settledBuffer: this.settledBuffer.slice(-500),
|
|
1475
1480
|
accumulatedBufferLength: this.accumulatedBuffer.length,
|
|
1481
|
+
accumulatedRawBufferLength: this.accumulatedRawBuffer.length,
|
|
1482
|
+
rawBufferPreview: this.accumulatedRawBuffer.slice(-1e3),
|
|
1483
|
+
responseBuffer: this.responseBuffer.slice(-1e3),
|
|
1476
1484
|
isWaitingForResponse: this.isWaitingForResponse,
|
|
1477
1485
|
activeModal: this.activeModal,
|
|
1478
1486
|
lastApprovalResolvedAt: this.lastApprovalResolvedAt,
|
|
1487
|
+
sendDelayMs: this.sendDelayMs,
|
|
1488
|
+
sendKey: this.sendKey,
|
|
1489
|
+
submitPendingUntil: this.submitPendingUntil,
|
|
1490
|
+
responseSettleIgnoreUntil: this.responseSettleIgnoreUntil,
|
|
1479
1491
|
resizeSuppressUntil: this.resizeSuppressUntil,
|
|
1480
1492
|
hasCliScripts: this.hasCliScripts(),
|
|
1481
1493
|
scriptNames: Object.keys(this.cliScripts).filter((k) => typeof this.cliScripts[k] === "function"),
|
|
@@ -8137,7 +8149,8 @@ var CliProviderInstance = class {
|
|
|
8137
8149
|
return { ...m, content };
|
|
8138
8150
|
});
|
|
8139
8151
|
const partial = this.adapter.getPartialResponse();
|
|
8140
|
-
|
|
8152
|
+
const shouldAppendRawPartial = !parsedStatus;
|
|
8153
|
+
if (shouldAppendRawPartial && adapterStatus.status === "generating" && partial) {
|
|
8141
8154
|
const cleaned = partial.trim();
|
|
8142
8155
|
if (cleaned && cleaned !== "(generating...)") {
|
|
8143
8156
|
recentMessages.push({
|
|
@@ -13236,7 +13249,7 @@ var DevServer = class _DevServer {
|
|
|
13236
13249
|
lines.push("| Function | Input | Return |");
|
|
13237
13250
|
lines.push("|---|---|---|");
|
|
13238
13251
|
lines.push("| `parseOutput` | `{ buffer, rawBuffer, recentBuffer, screenText, messages, partialResponse }` | `{ id, status, title, messages, activeModal }` |");
|
|
13239
|
-
lines.push("| `detectStatus` | `{ tail }` | `idle`, `generating`, `waiting_approval`, or `error` |");
|
|
13252
|
+
lines.push("| `detectStatus` | `{ tail, screenText, rawBuffer }` | `idle`, `generating`, `waiting_approval`, or `error` |");
|
|
13240
13253
|
lines.push("| `parseApproval` | `{ buffer, rawBuffer, tail }` | `{ message, buttons }` or `null` |");
|
|
13241
13254
|
lines.push("");
|
|
13242
13255
|
lines.push("## Rules");
|
|
@@ -13249,6 +13262,7 @@ var DevServer = class _DevServer {
|
|
|
13249
13262
|
lines.push("7. Use `rawBuffer` only when ANSI/control-sequence artifacts matter. Do not depend on raw escape noise unless necessary.");
|
|
13250
13263
|
lines.push("8. Keep exports compatible with the existing `scripts.js` router (`module.exports = function ...`).");
|
|
13251
13264
|
lines.push("9. Do not rewrite unrelated provider config. Only touch the scripts needed for this task unless a tiny supporting change is required.");
|
|
13265
|
+
lines.push("10. When the verification API returns `instanceId`, keep using that exact instance for follow-up `send`, `resolve`, `raw`, and `stop` calls. Do not assume type-only routing is safe if multiple sessions exist.");
|
|
13252
13266
|
lines.push("");
|
|
13253
13267
|
lines.push("## Task");
|
|
13254
13268
|
lines.push(`Edit files in \`${providerDir}\` to implement: **${functions.join(", ")}**`);
|
|
@@ -13269,25 +13283,38 @@ var DevServer = class _DevServer {
|
|
|
13269
13283
|
lines.push(`curl -sS http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/status`);
|
|
13270
13284
|
lines.push("```");
|
|
13271
13285
|
lines.push("");
|
|
13272
|
-
lines.push("
|
|
13286
|
+
lines.push("Extract the current `instanceId` from the launch or status response and keep using it below.");
|
|
13287
|
+
lines.push("");
|
|
13288
|
+
lines.push("### 3. Send a realistic approval-triggering prompt");
|
|
13273
13289
|
lines.push("```bash");
|
|
13274
13290
|
lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/send \\`);
|
|
13275
13291
|
lines.push(' -H "Content-Type: application/json" \\');
|
|
13276
|
-
lines.push(` -d '{"type":"${type}","text":"
|
|
13292
|
+
lines.push(` -d '{"type":"${type}","instanceId":"<INSTANCE_ID>","text":"Create a file at tmp/adhdev_provider_fix_test.py that prints the current working directory and the squares of 1 through 5, then run python3 tmp/adhdev_provider_fix_test.py and tell me the exact output."}'`);
|
|
13277
13293
|
lines.push("```");
|
|
13278
13294
|
lines.push("");
|
|
13279
|
-
lines.push("### 4. If approval appears, resolve it");
|
|
13295
|
+
lines.push("### 4. If approval appears, resolve it until the CLI reaches idle");
|
|
13280
13296
|
lines.push("```bash");
|
|
13281
13297
|
lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/resolve \\`);
|
|
13282
13298
|
lines.push(' -H "Content-Type: application/json" \\');
|
|
13283
|
-
lines.push(` -d '{"type":"${type}","buttonIndex":0}'`);
|
|
13299
|
+
lines.push(` -d '{"type":"${type}","instanceId":"<INSTANCE_ID>","buttonIndex":0}'`);
|
|
13300
|
+
lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/raw \\`);
|
|
13301
|
+
lines.push(' -H "Content-Type: application/json" \\');
|
|
13302
|
+
lines.push(` -d '{"type":"${type}","instanceId":"<INSTANCE_ID>","keys":"1"}'`);
|
|
13303
|
+
lines.push("```");
|
|
13304
|
+
lines.push("");
|
|
13305
|
+
lines.push("Use `resolve` when the parsed modal buttons are correct. Use `raw` when the CLI expects a literal keystroke like `1`, `y`, or Enter. Repeat until idle.");
|
|
13306
|
+
lines.push("");
|
|
13307
|
+
lines.push("### 5. Verify the side effects outside the CLI");
|
|
13308
|
+
lines.push("```bash");
|
|
13309
|
+
lines.push("test -f tmp/adhdev_provider_fix_test.py");
|
|
13310
|
+
lines.push("python3 tmp/adhdev_provider_fix_test.py");
|
|
13284
13311
|
lines.push("```");
|
|
13285
13312
|
lines.push("");
|
|
13286
|
-
lines.push("###
|
|
13313
|
+
lines.push("### 6. Stop the CLI when finished");
|
|
13287
13314
|
lines.push("```bash");
|
|
13288
13315
|
lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/stop \\`);
|
|
13289
13316
|
lines.push(' -H "Content-Type: application/json" \\');
|
|
13290
|
-
lines.push(` -d '{"type":"${type}"}'`);
|
|
13317
|
+
lines.push(` -d '{"type":"${type}","instanceId":"<INSTANCE_ID>"}'`);
|
|
13291
13318
|
lines.push("```");
|
|
13292
13319
|
lines.push("");
|
|
13293
13320
|
lines.push("## Required Validation");
|
|
@@ -13295,7 +13322,9 @@ var DevServer = class _DevServer {
|
|
|
13295
13322
|
lines.push("2. Confirm `parseOutput` produces a stable transcript without duplicating past turns when the PTY redraws.");
|
|
13296
13323
|
lines.push("3. Confirm the latest assistant message streams through `partialResponse` while generation is in progress.");
|
|
13297
13324
|
lines.push("4. Confirm approval parsing returns meaningful button labels when the CLI requests permission.");
|
|
13298
|
-
lines.push("5.
|
|
13325
|
+
lines.push("5. Confirm the Python file was actually created and executed, not just described in chat text.");
|
|
13326
|
+
lines.push("6. Confirm the final assistant transcript includes the exact Python output, including the working directory line and the five square numbers.");
|
|
13327
|
+
lines.push("7. Re-run the debug endpoints after edits. Do NOT finish until the parsed result looks correct.");
|
|
13299
13328
|
lines.push("");
|
|
13300
13329
|
if (userComment) {
|
|
13301
13330
|
lines.push("## \u26A0\uFE0F User Instructions (HIGH PRIORITY)");
|
|
@@ -13417,6 +13446,14 @@ data: ${JSON.stringify(msg.data)}
|
|
|
13417
13446
|
}));
|
|
13418
13447
|
this.json(res, 200, { instances: result, count: result.length });
|
|
13419
13448
|
}
|
|
13449
|
+
findCliTarget(type, instanceId) {
|
|
13450
|
+
if (!this.instanceManager) return null;
|
|
13451
|
+
const cliStates = this.instanceManager.collectAllStates().filter((s) => s.category === "cli" || s.category === "acp");
|
|
13452
|
+
if (instanceId) return cliStates.find((s) => s.instanceId === instanceId) || null;
|
|
13453
|
+
if (!type) return cliStates[cliStates.length - 1] || null;
|
|
13454
|
+
const matches = cliStates.filter((s) => s.type === type);
|
|
13455
|
+
return matches[matches.length - 1] || null;
|
|
13456
|
+
}
|
|
13420
13457
|
/** POST /api/cli/launch — launch a CLI agent { type, workingDir?, args? } */
|
|
13421
13458
|
async handleCliLaunch(req, res) {
|
|
13422
13459
|
if (!this.cliManager) {
|
|
@@ -13448,10 +13485,7 @@ data: ${JSON.stringify(msg.data)}
|
|
|
13448
13485
|
this.json(res, 400, { error: "text required" });
|
|
13449
13486
|
return;
|
|
13450
13487
|
}
|
|
13451
|
-
const
|
|
13452
|
-
const target = allStates.find(
|
|
13453
|
-
(s) => (s.category === "cli" || s.category === "acp") && (instanceId ? s.instanceId === instanceId : s.type === type)
|
|
13454
|
-
);
|
|
13488
|
+
const target = this.findCliTarget(type, instanceId);
|
|
13455
13489
|
if (!target) {
|
|
13456
13490
|
this.json(res, 404, { error: `No running instance found for: ${type || instanceId}` });
|
|
13457
13491
|
return;
|
|
@@ -13471,10 +13505,7 @@ data: ${JSON.stringify(msg.data)}
|
|
|
13471
13505
|
}
|
|
13472
13506
|
const body = await this.readBody(req);
|
|
13473
13507
|
const { type, instanceId } = body;
|
|
13474
|
-
const
|
|
13475
|
-
const target = allStates.find(
|
|
13476
|
-
(s) => (s.category === "cli" || s.category === "acp") && (instanceId ? s.instanceId === instanceId : s.type === type)
|
|
13477
|
-
);
|
|
13508
|
+
const target = this.findCliTarget(type, instanceId);
|
|
13478
13509
|
if (!target) {
|
|
13479
13510
|
this.json(res, 404, { error: `No running instance found for: ${type || instanceId}` });
|
|
13480
13511
|
return;
|
|
@@ -13529,11 +13560,9 @@ data: ${JSON.stringify(msg.data)}
|
|
|
13529
13560
|
this.json(res, 503, { error: "InstanceManager not available" });
|
|
13530
13561
|
return;
|
|
13531
13562
|
}
|
|
13532
|
-
const
|
|
13533
|
-
const target = allStates.find(
|
|
13534
|
-
(s) => (s.category === "cli" || s.category === "acp") && s.type === type
|
|
13535
|
-
);
|
|
13563
|
+
const target = this.findCliTarget(type);
|
|
13536
13564
|
if (!target) {
|
|
13565
|
+
const allStates = this.instanceManager.collectAllStates();
|
|
13537
13566
|
this.json(res, 404, { error: `No running instance for: ${type}`, available: allStates.filter((s) => s.category === "cli" || s.category === "acp").map((s) => s.type) });
|
|
13538
13567
|
return;
|
|
13539
13568
|
}
|
|
@@ -13580,21 +13609,25 @@ data: ${JSON.stringify(msg.data)}
|
|
|
13580
13609
|
this.json(res, 503, { error: "CliManager not available" });
|
|
13581
13610
|
return;
|
|
13582
13611
|
}
|
|
13583
|
-
|
|
13584
|
-
|
|
13585
|
-
|
|
13586
|
-
adapter = a;
|
|
13587
|
-
break;
|
|
13588
|
-
}
|
|
13612
|
+
if (!this.instanceManager) {
|
|
13613
|
+
this.json(res, 503, { error: "InstanceManager not available" });
|
|
13614
|
+
return;
|
|
13589
13615
|
}
|
|
13590
|
-
|
|
13616
|
+
const target = this.findCliTarget(type, instanceId);
|
|
13617
|
+
if (!target) {
|
|
13591
13618
|
this.json(res, 404, { error: `No running adapter for: ${type || instanceId}` });
|
|
13592
13619
|
return;
|
|
13593
13620
|
}
|
|
13621
|
+
const instance = this.instanceManager.getInstance(target.instanceId);
|
|
13622
|
+
const adapter = instance?.getAdapter?.() || instance?.adapter;
|
|
13623
|
+
if (!adapter) {
|
|
13624
|
+
this.json(res, 404, { error: `Adapter not found for instance: ${target.instanceId}` });
|
|
13625
|
+
return;
|
|
13626
|
+
}
|
|
13594
13627
|
try {
|
|
13595
13628
|
if (typeof adapter.resolveModal === "function") {
|
|
13596
13629
|
adapter.resolveModal(buttonIndex);
|
|
13597
|
-
this.json(res, 200, { resolved: true, type, buttonIndex });
|
|
13630
|
+
this.json(res, 200, { resolved: true, type: target.type, instanceId: target.instanceId, buttonIndex });
|
|
13598
13631
|
} else {
|
|
13599
13632
|
this.json(res, 400, { error: "resolveModal not available on this adapter" });
|
|
13600
13633
|
}
|
|
@@ -13614,21 +13647,25 @@ data: ${JSON.stringify(msg.data)}
|
|
|
13614
13647
|
this.json(res, 503, { error: "CliManager not available" });
|
|
13615
13648
|
return;
|
|
13616
13649
|
}
|
|
13617
|
-
|
|
13618
|
-
|
|
13619
|
-
|
|
13620
|
-
adapter = a;
|
|
13621
|
-
break;
|
|
13622
|
-
}
|
|
13650
|
+
if (!this.instanceManager) {
|
|
13651
|
+
this.json(res, 503, { error: "InstanceManager not available" });
|
|
13652
|
+
return;
|
|
13623
13653
|
}
|
|
13624
|
-
|
|
13654
|
+
const target = this.findCliTarget(type, instanceId);
|
|
13655
|
+
if (!target) {
|
|
13625
13656
|
this.json(res, 404, { error: `No running adapter for: ${type || instanceId}` });
|
|
13626
13657
|
return;
|
|
13627
13658
|
}
|
|
13659
|
+
const instance = this.instanceManager.getInstance(target.instanceId);
|
|
13660
|
+
const adapter = instance?.getAdapter?.() || instance?.adapter;
|
|
13661
|
+
if (!adapter) {
|
|
13662
|
+
this.json(res, 404, { error: `Adapter not found for instance: ${target.instanceId}` });
|
|
13663
|
+
return;
|
|
13664
|
+
}
|
|
13628
13665
|
try {
|
|
13629
13666
|
if (typeof adapter.writeRaw === "function") {
|
|
13630
13667
|
adapter.writeRaw(keys);
|
|
13631
|
-
this.json(res, 200, { sent: true, type, keysLength: keys.length });
|
|
13668
|
+
this.json(res, 200, { sent: true, type: target.type, instanceId: target.instanceId, keysLength: keys.length });
|
|
13632
13669
|
} else {
|
|
13633
13670
|
this.json(res, 400, { error: "writeRaw not available on this adapter" });
|
|
13634
13671
|
}
|