@adhdev/daemon-core 0.6.56 → 0.6.58
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 +23 -0
- package/dist/index.js +423 -95
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/providers/_builtin/cli/aider-cli/scripts/1.0/parse_output.js +51 -3
- package/providers/_builtin/cli/claude-cli/provider.json +18 -6
- package/providers/_builtin/cli/claude-cli/scripts/1.0/detect_status.js +68 -16
- package/providers/_builtin/cli/claude-cli/scripts/1.0/parse_approval.js +81 -22
- package/providers/_builtin/cli/claude-cli/scripts/1.0/parse_output.js +347 -94
- package/providers/_builtin/cli/codex-cli/provider.json +2 -0
- package/providers/_builtin/cli/codex-cli/scripts/1.0/detect_status.js +44 -10
- package/providers/_builtin/cli/codex-cli/scripts/1.0/parse_approval.js +83 -7
- package/providers/_builtin/cli/codex-cli/scripts/1.0/parse_output.js +501 -47
- package/providers/_builtin/cli/cursor-cli/scripts/1.0/parse_output.js +1 -1
- package/providers/_builtin/cli/github-copilot-cli/scripts/1.0/parse_output.js +1 -1
- package/providers/_builtin/cli/goose-cli/scripts/1.0/parse_output.js +1 -1
- package/providers/_builtin/cli/opencode-cli/scripts/1.0/parse_output.js +1 -1
- package/providers/_builtin/ide/vscode/provider.json +5 -1
- package/providers/_builtin/ide/vscode/scripts/1.0/focus_editor.js +1 -0
- package/providers/_builtin/ide/vscode/scripts/1.0/list_models.js +1 -0
- package/providers/_builtin/ide/vscode/scripts/1.0/list_sessions.js +1 -0
- package/providers/_builtin/ide/vscode/scripts/1.0/new_session.js +1 -0
- package/providers/_builtin/ide/vscode/scripts/1.0/open_panel.js +1 -0
- package/providers/_builtin/ide/vscode/scripts/1.0/read_chat.js +1 -0
- package/providers/_builtin/ide/vscode/scripts/1.0/resolve_action.js +1 -0
- package/providers/_builtin/ide/vscode/scripts/1.0/scripts.js +25 -0
- package/providers/_builtin/ide/vscode/scripts/1.0/send_message.js +1 -0
- package/providers/_builtin/ide/vscode/scripts/1.0/set_model.js +1 -0
- package/providers/_builtin/ide/vscode/scripts/1.0/switch_session.js +1 -0
- package/providers/_builtin/registry.json +1 -1
- package/src/cli-adapters/provider-cli-adapter.ts +410 -65
- package/src/commands/chat-commands.ts +7 -1
- package/src/config/chat-history.ts +53 -1
- package/src/daemon/dev-server.ts +7 -9
- package/src/providers/cli-provider-instance.ts +10 -23
- package/src/providers/provider-instance.ts +1 -0
- package/src/providers/version-archive.ts +4 -1
package/dist/index.js
CHANGED
|
@@ -718,6 +718,68 @@ function shSingleQuote(arg) {
|
|
|
718
718
|
if (/^[a-zA-Z0-9@%_+=:,./-]+$/.test(arg)) return arg;
|
|
719
719
|
return `'${arg.replace(/'/g, `'\\''`)}'`;
|
|
720
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
|
+
}
|
|
753
|
+
function splitHistoryLines(text) {
|
|
754
|
+
return String(text || "").split("\n").map((line) => line.replace(/\s+$/, ""));
|
|
755
|
+
}
|
|
756
|
+
function normalizeHistoryLine(line) {
|
|
757
|
+
return String(line || "").replace(/\s+/g, " ").trim();
|
|
758
|
+
}
|
|
759
|
+
function mergeTerminalHistory(existing, snapshot) {
|
|
760
|
+
const next = String(snapshot || "").trim();
|
|
761
|
+
if (!next) return existing;
|
|
762
|
+
const prev = String(existing || "").trim();
|
|
763
|
+
if (!prev) return next;
|
|
764
|
+
if (prev === next || prev.endsWith(next)) return prev;
|
|
765
|
+
const prevLines = splitHistoryLines(prev);
|
|
766
|
+
const nextLines = splitHistoryLines(next);
|
|
767
|
+
const prevNorm = prevLines.map(normalizeHistoryLine);
|
|
768
|
+
const nextNorm = nextLines.map(normalizeHistoryLine);
|
|
769
|
+
const maxOverlap = Math.min(prevLines.length, nextLines.length);
|
|
770
|
+
for (let overlap = maxOverlap; overlap >= 1; overlap -= 1) {
|
|
771
|
+
const prevTail = prevNorm.slice(prevNorm.length - overlap);
|
|
772
|
+
const nextHead = nextNorm.slice(0, overlap);
|
|
773
|
+
if (prevTail.every((line, index) => line === nextHead[index])) {
|
|
774
|
+
return [...prevLines, ...nextLines.slice(overlap)].join("\n").trim();
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
const compactPrev = prevNorm.join("\n");
|
|
778
|
+
const compactNext = nextNorm.join("\n");
|
|
779
|
+
if (compactPrev.includes(compactNext)) return prev;
|
|
780
|
+
return `${prev}
|
|
781
|
+
${next}`.trim();
|
|
782
|
+
}
|
|
721
783
|
function parsePatternEntry(x) {
|
|
722
784
|
if (x instanceof RegExp) return x;
|
|
723
785
|
if (x && typeof x === "object" && typeof x.source === "string") {
|
|
@@ -794,6 +856,7 @@ var init_provider_cli_adapter = __esm({
|
|
|
794
856
|
this.approvalKeys = rawKeys && typeof rawKeys === "object" ? rawKeys : {};
|
|
795
857
|
this.sendDelayMs = typeof provider.sendDelayMs === "number" ? Math.max(0, provider.sendDelayMs) : 0;
|
|
796
858
|
this.sendKey = typeof provider.sendKey === "string" && provider.sendKey.length > 0 ? provider.sendKey : "\r";
|
|
859
|
+
this.submitStrategy = provider.submitStrategy === "immediate" ? "immediate" : "wait_for_echo";
|
|
797
860
|
this.cliScripts = provider.scripts || {};
|
|
798
861
|
const scriptNames = Object.keys(this.cliScripts).filter((k) => typeof this.cliScripts[k] === "function");
|
|
799
862
|
if (scriptNames.length > 0) {
|
|
@@ -808,6 +871,7 @@ var init_provider_cli_adapter = __esm({
|
|
|
808
871
|
provider;
|
|
809
872
|
ptyProcess = null;
|
|
810
873
|
messages = [];
|
|
874
|
+
committedMessages = [];
|
|
811
875
|
structuredMessages = [];
|
|
812
876
|
currentStatus = "starting";
|
|
813
877
|
onStatusChange = null;
|
|
@@ -837,6 +901,11 @@ var init_provider_cli_adapter = __esm({
|
|
|
837
901
|
settleTimer = null;
|
|
838
902
|
settledBuffer = "";
|
|
839
903
|
submitPendingUntil = 0;
|
|
904
|
+
responseSettleIgnoreUntil = 0;
|
|
905
|
+
responseEpoch = 0;
|
|
906
|
+
submitRetryTimer = null;
|
|
907
|
+
submitRetryUsed = false;
|
|
908
|
+
submitRetryPromptSnippet = "";
|
|
840
909
|
// Resize redraw suppression
|
|
841
910
|
resizeSuppressUntil = 0;
|
|
842
911
|
// Debug: status transition history
|
|
@@ -849,8 +918,35 @@ var init_provider_cli_adapter = __esm({
|
|
|
849
918
|
accumulatedRawBuffer = "";
|
|
850
919
|
/** Current visible terminal screen snapshot */
|
|
851
920
|
terminalScreen = new TerminalScreen(40, 120);
|
|
921
|
+
/** Rolling append-only terminal transcript built from screen snapshots */
|
|
922
|
+
terminalHistory = "";
|
|
852
923
|
/** Max accumulated buffer size (last 50KB) */
|
|
853
924
|
static MAX_ACCUMULATED_BUFFER = 5e4;
|
|
925
|
+
currentTurnScope = null;
|
|
926
|
+
syncMessageViews() {
|
|
927
|
+
this.messages = [...this.committedMessages];
|
|
928
|
+
this.structuredMessages = [...this.committedMessages];
|
|
929
|
+
}
|
|
930
|
+
sliceFromOffset(text, start) {
|
|
931
|
+
if (!text) return "";
|
|
932
|
+
if (!Number.isFinite(start) || start <= 0) return text;
|
|
933
|
+
if (start >= text.length) return "";
|
|
934
|
+
return text.slice(start);
|
|
935
|
+
}
|
|
936
|
+
buildParseInput(baseMessages, partialResponse, scope) {
|
|
937
|
+
const buffer = scope ? this.sliceFromOffset(this.terminalHistory, scope.terminalHistoryStart) || this.sliceFromOffset(this.accumulatedBuffer, scope.bufferStart) || this.accumulatedBuffer : this.accumulatedBuffer;
|
|
938
|
+
const rawBuffer = scope ? this.sliceFromOffset(this.accumulatedRawBuffer, scope.rawBufferStart) || this.accumulatedRawBuffer : this.accumulatedRawBuffer;
|
|
939
|
+
const terminalHistory = scope ? this.sliceFromOffset(this.terminalHistory, scope.terminalHistoryStart) || this.terminalHistory : this.terminalHistory;
|
|
940
|
+
return {
|
|
941
|
+
buffer,
|
|
942
|
+
rawBuffer,
|
|
943
|
+
recentBuffer: buffer.slice(-1e3) || this.recentOutputBuffer,
|
|
944
|
+
screenText: this.terminalScreen.getText(),
|
|
945
|
+
terminalHistory,
|
|
946
|
+
messages: [...baseMessages],
|
|
947
|
+
partialResponse
|
|
948
|
+
};
|
|
949
|
+
}
|
|
854
950
|
setStatus(status, trigger) {
|
|
855
951
|
const prev = this.currentStatus;
|
|
856
952
|
if (prev === status) return;
|
|
@@ -865,6 +961,7 @@ var init_provider_cli_adapter = __esm({
|
|
|
865
961
|
approvalKeys;
|
|
866
962
|
sendDelayMs;
|
|
867
963
|
sendKey;
|
|
964
|
+
submitStrategy;
|
|
868
965
|
/** Inject CLI scripts after construction (e.g. when resolved by ProviderLoader) */
|
|
869
966
|
setCliScripts(scripts) {
|
|
870
967
|
this.cliScripts = scripts;
|
|
@@ -960,7 +1057,9 @@ var init_provider_cli_adapter = __esm({
|
|
|
960
1057
|
this.startupParseGate = true;
|
|
961
1058
|
this.startupBuffer = "";
|
|
962
1059
|
this.terminalScreen.reset(40, 120);
|
|
963
|
-
this.
|
|
1060
|
+
this.terminalHistory = "";
|
|
1061
|
+
this.currentTurnScope = null;
|
|
1062
|
+
this.ready = false;
|
|
964
1063
|
this.setStatus("idle", "pty_ready");
|
|
965
1064
|
this.onStatusChange?.();
|
|
966
1065
|
}
|
|
@@ -971,6 +1070,7 @@ var init_provider_cli_adapter = __esm({
|
|
|
971
1070
|
this.ptyProcess?.write("\x1B[1;1R");
|
|
972
1071
|
}
|
|
973
1072
|
this.terminalScreen.write(rawData);
|
|
1073
|
+
this.terminalHistory = mergeTerminalHistory(this.terminalHistory, this.terminalScreen.getText());
|
|
974
1074
|
const cleanData = stripAnsi(rawData);
|
|
975
1075
|
if (this.isWaitingForResponse && cleanData) {
|
|
976
1076
|
this.responseBuffer = (this.responseBuffer + cleanData).slice(-8e3);
|
|
@@ -1005,7 +1105,9 @@ var init_provider_cli_adapter = __esm({
|
|
|
1005
1105
|
const isReady = scriptStatus === "idle" || elapsed > 8e3 || bufCap;
|
|
1006
1106
|
if (isReady) {
|
|
1007
1107
|
this.startupParseGate = false;
|
|
1108
|
+
this.ready = true;
|
|
1008
1109
|
LOG.info("CLI", `[${this.cliType}] Startup gate end (${elapsed}ms, scriptStatus=${scriptStatus})`);
|
|
1110
|
+
this.onStatusChange?.();
|
|
1009
1111
|
} else {
|
|
1010
1112
|
return;
|
|
1011
1113
|
}
|
|
@@ -1014,19 +1116,45 @@ var init_provider_cli_adapter = __esm({
|
|
|
1014
1116
|
}
|
|
1015
1117
|
scheduleSettle() {
|
|
1016
1118
|
if (this.settleTimer) clearTimeout(this.settleTimer);
|
|
1119
|
+
const settleEpoch = this.responseEpoch;
|
|
1017
1120
|
const delay = Math.max(
|
|
1018
1121
|
this.timeouts.outputSettle,
|
|
1019
1122
|
this.submitPendingUntil > Date.now() ? this.submitPendingUntil - Date.now() + this.timeouts.outputSettle : 0
|
|
1020
1123
|
);
|
|
1021
1124
|
this.settleTimer = setTimeout(() => {
|
|
1022
1125
|
this.settleTimer = null;
|
|
1126
|
+
if (settleEpoch !== this.responseEpoch) return;
|
|
1023
1127
|
this.settledBuffer = this.recentOutputBuffer;
|
|
1024
1128
|
this.evaluateSettled();
|
|
1025
1129
|
}, delay);
|
|
1026
1130
|
}
|
|
1131
|
+
armApprovalExitTimeout() {
|
|
1132
|
+
if (this.approvalExitTimeout) clearTimeout(this.approvalExitTimeout);
|
|
1133
|
+
this.approvalExitTimeout = setTimeout(() => {
|
|
1134
|
+
if (this.currentStatus !== "waiting_approval") return;
|
|
1135
|
+
const tail = this.recentOutputBuffer;
|
|
1136
|
+
const modal = this.runParseApproval(tail);
|
|
1137
|
+
const stillWaiting = this.runDetectStatus(tail) === "waiting_approval" || !!modal;
|
|
1138
|
+
if (stillWaiting) {
|
|
1139
|
+
this.activeModal = modal || this.activeModal || { message: "Approval required", buttons: ["Allow", "Deny"] };
|
|
1140
|
+
this.onStatusChange?.();
|
|
1141
|
+
this.armApprovalExitTimeout();
|
|
1142
|
+
return;
|
|
1143
|
+
}
|
|
1144
|
+
LOG.warn("CLI", `[${this.cliType}] Approval timeout \u2014 auto-clearing`);
|
|
1145
|
+
this.activeModal = null;
|
|
1146
|
+
this.lastApprovalResolvedAt = Date.now();
|
|
1147
|
+
this.setStatus("idle", "approval_timeout");
|
|
1148
|
+
this.onStatusChange?.();
|
|
1149
|
+
}, 6e4);
|
|
1150
|
+
}
|
|
1027
1151
|
evaluateSettled() {
|
|
1152
|
+
if (this.submitPendingUntil > Date.now()) return;
|
|
1153
|
+
if (this.responseSettleIgnoreUntil > Date.now()) return;
|
|
1028
1154
|
const tail = this.settledBuffer;
|
|
1029
|
-
const
|
|
1155
|
+
const modal = this.runParseApproval(tail);
|
|
1156
|
+
const rawScriptStatus = this.runDetectStatus(tail);
|
|
1157
|
+
const scriptStatus = rawScriptStatus === "waiting_approval" || modal ? "waiting_approval" : rawScriptStatus;
|
|
1030
1158
|
if (!scriptStatus) return;
|
|
1031
1159
|
const prevStatus = this.currentStatus;
|
|
1032
1160
|
if (scriptStatus === "waiting_approval") {
|
|
@@ -1034,19 +1162,9 @@ var init_provider_cli_adapter = __esm({
|
|
|
1034
1162
|
if (!inCooldown) {
|
|
1035
1163
|
this.isWaitingForResponse = true;
|
|
1036
1164
|
this.setStatus("waiting_approval", "script_detect");
|
|
1037
|
-
const modal = this.runParseApproval(tail);
|
|
1038
1165
|
this.activeModal = modal || { message: "Approval required", buttons: ["Allow", "Deny"] };
|
|
1039
1166
|
if (this.idleTimeout) clearTimeout(this.idleTimeout);
|
|
1040
|
-
|
|
1041
|
-
this.approvalExitTimeout = setTimeout(() => {
|
|
1042
|
-
if (this.currentStatus === "waiting_approval") {
|
|
1043
|
-
LOG.warn("CLI", `[${this.cliType}] Approval timeout \u2014 auto-clearing`);
|
|
1044
|
-
this.activeModal = null;
|
|
1045
|
-
this.lastApprovalResolvedAt = Date.now();
|
|
1046
|
-
this.setStatus("idle", "approval_timeout");
|
|
1047
|
-
this.onStatusChange?.();
|
|
1048
|
-
}
|
|
1049
|
-
}, 6e4);
|
|
1167
|
+
this.armApprovalExitTimeout();
|
|
1050
1168
|
this.onStatusChange?.();
|
|
1051
1169
|
return;
|
|
1052
1170
|
}
|
|
@@ -1082,7 +1200,12 @@ var init_provider_cli_adapter = __esm({
|
|
|
1082
1200
|
this.lastApprovalResolvedAt = Date.now();
|
|
1083
1201
|
}
|
|
1084
1202
|
if (this.isWaitingForResponse) {
|
|
1085
|
-
this.
|
|
1203
|
+
if (this.idleTimeout) clearTimeout(this.idleTimeout);
|
|
1204
|
+
this.idleTimeout = setTimeout(() => {
|
|
1205
|
+
if (this.isWaitingForResponse && this.currentStatus !== "waiting_approval") {
|
|
1206
|
+
this.finishResponse();
|
|
1207
|
+
}
|
|
1208
|
+
}, this.timeouts.idleFinish);
|
|
1086
1209
|
} else if (prevStatus !== "idle") {
|
|
1087
1210
|
this.setStatus("idle", "script_detect");
|
|
1088
1211
|
this.onStatusChange?.();
|
|
@@ -1090,6 +1213,9 @@ var init_provider_cli_adapter = __esm({
|
|
|
1090
1213
|
}
|
|
1091
1214
|
}
|
|
1092
1215
|
finishResponse() {
|
|
1216
|
+
if (this.submitPendingUntil > Date.now()) return;
|
|
1217
|
+
if (this.responseSettleIgnoreUntil > Date.now()) return;
|
|
1218
|
+
this.commitCurrentTranscript();
|
|
1093
1219
|
if (this.responseTimeout) {
|
|
1094
1220
|
clearTimeout(this.responseTimeout);
|
|
1095
1221
|
this.responseTimeout = null;
|
|
@@ -1102,12 +1228,67 @@ var init_provider_cli_adapter = __esm({
|
|
|
1102
1228
|
clearTimeout(this.approvalExitTimeout);
|
|
1103
1229
|
this.approvalExitTimeout = null;
|
|
1104
1230
|
}
|
|
1231
|
+
if (this.submitRetryTimer) {
|
|
1232
|
+
clearTimeout(this.submitRetryTimer);
|
|
1233
|
+
this.submitRetryTimer = null;
|
|
1234
|
+
}
|
|
1105
1235
|
this.responseBuffer = "";
|
|
1106
1236
|
this.isWaitingForResponse = false;
|
|
1237
|
+
this.responseSettleIgnoreUntil = 0;
|
|
1238
|
+
this.submitRetryUsed = false;
|
|
1239
|
+
this.submitRetryPromptSnippet = "";
|
|
1240
|
+
this.currentTurnScope = null;
|
|
1107
1241
|
this.activeModal = null;
|
|
1108
1242
|
this.setStatus("idle", "response_finished");
|
|
1109
1243
|
this.onStatusChange?.();
|
|
1110
1244
|
}
|
|
1245
|
+
commitCurrentTranscript() {
|
|
1246
|
+
const baseMessages = [...this.committedMessages];
|
|
1247
|
+
const parsed = this.parseCurrentTranscript(baseMessages, "", this.currentTurnScope);
|
|
1248
|
+
if (parsed && Array.isArray(parsed.messages) && parsed.messages.length > 0) {
|
|
1249
|
+
const parsedMessages = parsed.messages.filter((m) => m && (m.role === "user" || m.role === "assistant")).map((m) => ({
|
|
1250
|
+
role: m.role,
|
|
1251
|
+
content: typeof m.content === "string" ? m.content : String(m.content || ""),
|
|
1252
|
+
timestamp: m.timestamp
|
|
1253
|
+
}));
|
|
1254
|
+
const latestAssistant = [...parsedMessages].reverse().find((m) => m.role === "assistant" && m.content.trim());
|
|
1255
|
+
if (latestAssistant) {
|
|
1256
|
+
LOG.info("CLI", `[${this.cliType}] commitCurrentTranscript parsed assistant len=${latestAssistant.content.length} scopePrompt=${JSON.stringify(this.currentTurnScope?.prompt || "").slice(0, 120)}`);
|
|
1257
|
+
const nextMessages = [...baseMessages];
|
|
1258
|
+
const last2 = nextMessages[nextMessages.length - 1];
|
|
1259
|
+
if (last2?.role === "assistant") {
|
|
1260
|
+
last2.content = latestAssistant.content;
|
|
1261
|
+
last2.timestamp = latestAssistant.timestamp || last2.timestamp;
|
|
1262
|
+
} else if (last2?.role === "user") {
|
|
1263
|
+
nextMessages.push({
|
|
1264
|
+
role: "assistant",
|
|
1265
|
+
content: latestAssistant.content,
|
|
1266
|
+
timestamp: latestAssistant.timestamp || Date.now()
|
|
1267
|
+
});
|
|
1268
|
+
} else {
|
|
1269
|
+
nextMessages.push({
|
|
1270
|
+
role: "assistant",
|
|
1271
|
+
content: latestAssistant.content,
|
|
1272
|
+
timestamp: latestAssistant.timestamp || Date.now()
|
|
1273
|
+
});
|
|
1274
|
+
}
|
|
1275
|
+
this.committedMessages = nextMessages;
|
|
1276
|
+
this.syncMessageViews();
|
|
1277
|
+
return;
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
const fallback = String(this.responseBuffer || "").trim();
|
|
1281
|
+
LOG.info("CLI", `[${this.cliType}] commitCurrentTranscript fallback len=${fallback.length} scopePrompt=${JSON.stringify(this.currentTurnScope?.prompt || "").slice(0, 120)}`);
|
|
1282
|
+
if (!fallback) return;
|
|
1283
|
+
const last = baseMessages[baseMessages.length - 1];
|
|
1284
|
+
if (last?.role === "assistant") {
|
|
1285
|
+
last.content = fallback;
|
|
1286
|
+
} else {
|
|
1287
|
+
baseMessages.push({ role: "assistant", content: fallback, timestamp: Date.now() });
|
|
1288
|
+
}
|
|
1289
|
+
this.committedMessages = baseMessages;
|
|
1290
|
+
this.syncMessageViews();
|
|
1291
|
+
}
|
|
1111
1292
|
// ─── Script Execution ──────────────────────────
|
|
1112
1293
|
runDetectStatus(text) {
|
|
1113
1294
|
if (!this.cliScripts?.detectStatus) return null;
|
|
@@ -1137,24 +1318,12 @@ var init_provider_cli_adapter = __esm({
|
|
|
1137
1318
|
}
|
|
1138
1319
|
// ─── Public API (CliAdapter) ───────────────────
|
|
1139
1320
|
getStatus() {
|
|
1140
|
-
const scriptResult = this.getScriptParsedStatus();
|
|
1141
|
-
if (scriptResult) {
|
|
1142
|
-
return {
|
|
1143
|
-
status: this.currentStatus,
|
|
1144
|
-
messages: (scriptResult.messages || []).map((m) => ({
|
|
1145
|
-
role: m.role,
|
|
1146
|
-
content: m.content,
|
|
1147
|
-
timestamp: m.timestamp
|
|
1148
|
-
})),
|
|
1149
|
-
workingDir: this.workingDir,
|
|
1150
|
-
activeModal: this.activeModal
|
|
1151
|
-
};
|
|
1152
|
-
}
|
|
1153
1321
|
return {
|
|
1154
1322
|
status: this.currentStatus,
|
|
1155
|
-
messages: [...this.
|
|
1323
|
+
messages: [...this.committedMessages],
|
|
1156
1324
|
workingDir: this.workingDir,
|
|
1157
|
-
activeModal: this.activeModal
|
|
1325
|
+
activeModal: this.activeModal,
|
|
1326
|
+
terminalHistory: this.terminalHistory
|
|
1158
1327
|
};
|
|
1159
1328
|
}
|
|
1160
1329
|
/**
|
|
@@ -1162,31 +1331,32 @@ var init_provider_cli_adapter = __esm({
|
|
|
1162
1331
|
* Called by command handler / dashboard for rich content rendering.
|
|
1163
1332
|
*/
|
|
1164
1333
|
getScriptParsedStatus() {
|
|
1334
|
+
const messages = [...this.committedMessages];
|
|
1335
|
+
return {
|
|
1336
|
+
id: "cli_session",
|
|
1337
|
+
status: this.currentStatus,
|
|
1338
|
+
title: this.cliName,
|
|
1339
|
+
terminalHistory: this.terminalHistory,
|
|
1340
|
+
messages: messages.slice(-50).map((message, index) => ({
|
|
1341
|
+
id: `msg_${index}`,
|
|
1342
|
+
role: message.role,
|
|
1343
|
+
content: message.content,
|
|
1344
|
+
timestamp: message.timestamp,
|
|
1345
|
+
index,
|
|
1346
|
+
kind: "standard"
|
|
1347
|
+
})),
|
|
1348
|
+
activeModal: this.activeModal
|
|
1349
|
+
};
|
|
1350
|
+
}
|
|
1351
|
+
parseCurrentTranscript(baseMessages, partialResponse, scope) {
|
|
1165
1352
|
if (!this.cliScripts?.parseOutput) return null;
|
|
1166
1353
|
try {
|
|
1167
|
-
const input =
|
|
1168
|
-
|
|
1169
|
-
rawBuffer: this.accumulatedRawBuffer,
|
|
1170
|
-
recentBuffer: this.recentOutputBuffer,
|
|
1171
|
-
screenText: this.terminalScreen.getText(),
|
|
1172
|
-
messages: [...this.structuredMessages.length > 0 ? this.structuredMessages : this.messages],
|
|
1173
|
-
partialResponse: this.responseBuffer
|
|
1174
|
-
};
|
|
1175
|
-
const result = this.cliScripts.parseOutput(input);
|
|
1176
|
-
if (result && typeof result === "object") {
|
|
1177
|
-
if (Array.isArray(result.messages)) {
|
|
1178
|
-
this.structuredMessages = result.messages.map((m) => ({
|
|
1179
|
-
role: m.role,
|
|
1180
|
-
content: m.content,
|
|
1181
|
-
timestamp: m.timestamp
|
|
1182
|
-
}));
|
|
1183
|
-
}
|
|
1184
|
-
return result;
|
|
1185
|
-
}
|
|
1354
|
+
const input = this.buildParseInput(baseMessages, partialResponse, scope);
|
|
1355
|
+
return this.cliScripts.parseOutput(input);
|
|
1186
1356
|
} catch (e) {
|
|
1187
1357
|
LOG.warn("CLI", `[${this.cliType}] parseOutput error: ${e.message}`);
|
|
1358
|
+
return null;
|
|
1188
1359
|
}
|
|
1189
|
-
return null;
|
|
1190
1360
|
}
|
|
1191
1361
|
/** Whether this adapter has CLI scripts loaded */
|
|
1192
1362
|
hasCliScripts() {
|
|
@@ -1218,29 +1388,125 @@ ${data.message || ""}`.trim();
|
|
|
1218
1388
|
}
|
|
1219
1389
|
async sendMessage(text) {
|
|
1220
1390
|
if (!this.ptyProcess) throw new Error(`${this.cliName} is not running`);
|
|
1391
|
+
if (this.startupParseGate) {
|
|
1392
|
+
const deadline = Date.now() + 1e4;
|
|
1393
|
+
while (this.startupParseGate && Date.now() < deadline) {
|
|
1394
|
+
await new Promise((resolve8) => setTimeout(resolve8, 50));
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1221
1397
|
if (!this.ready) throw new Error(`${this.cliName} not ready (status: ${this.currentStatus})`);
|
|
1222
1398
|
if (this.isWaitingForResponse) return;
|
|
1223
|
-
this.
|
|
1224
|
-
this.
|
|
1399
|
+
this.committedMessages.push({ role: "user", content: text, timestamp: Date.now() });
|
|
1400
|
+
this.syncMessageViews();
|
|
1225
1401
|
this.isWaitingForResponse = true;
|
|
1226
1402
|
this.responseBuffer = "";
|
|
1403
|
+
this.currentTurnScope = {
|
|
1404
|
+
prompt: text,
|
|
1405
|
+
startedAt: Date.now(),
|
|
1406
|
+
bufferStart: this.accumulatedBuffer.length,
|
|
1407
|
+
rawBufferStart: this.accumulatedRawBuffer.length,
|
|
1408
|
+
terminalHistoryStart: this.terminalHistory.length
|
|
1409
|
+
};
|
|
1410
|
+
LOG.info("CLI", `[${this.cliType}] sendMessage turn scope buffer=${this.currentTurnScope.bufferStart} raw=${this.currentTurnScope.rawBufferStart} terminal=${this.currentTurnScope.terminalHistoryStart} prompt=${JSON.stringify(text).slice(0, 120)}`);
|
|
1411
|
+
this.submitRetryUsed = false;
|
|
1412
|
+
this.submitRetryPromptSnippet = extractPromptRetrySnippet(text);
|
|
1413
|
+
const normalizedPromptSnippet = normalizePromptText(this.submitRetryPromptSnippet);
|
|
1414
|
+
if (this.submitRetryTimer) {
|
|
1415
|
+
clearTimeout(this.submitRetryTimer);
|
|
1416
|
+
this.submitRetryTimer = null;
|
|
1417
|
+
}
|
|
1418
|
+
const estimatedLines = estimatePromptDisplayLines(text);
|
|
1419
|
+
const submitDelayMs = this.sendDelayMs + Math.min(2e3, Math.max(0, estimatedLines - 1) * 350);
|
|
1420
|
+
const maxEchoWaitMs = submitDelayMs + Math.max(1500, Math.min(5e3, estimatedLines * 500));
|
|
1421
|
+
const retryDelayMs = Math.max(350, Math.min(1500, Math.max(this.sendDelayMs, submitDelayMs)));
|
|
1422
|
+
if (this.settleTimer) {
|
|
1423
|
+
clearTimeout(this.settleTimer);
|
|
1424
|
+
this.settleTimer = null;
|
|
1425
|
+
}
|
|
1426
|
+
this.responseEpoch += 1;
|
|
1427
|
+
this.responseSettleIgnoreUntil = Date.now() + submitDelayMs + this.timeouts.outputSettle + 250;
|
|
1227
1428
|
this.setStatus("generating", "sendMessage");
|
|
1228
1429
|
this.onStatusChange?.();
|
|
1229
|
-
|
|
1430
|
+
const startResponseTimeout = () => {
|
|
1431
|
+
if (this.responseTimeout) clearTimeout(this.responseTimeout);
|
|
1432
|
+
this.responseTimeout = setTimeout(() => {
|
|
1433
|
+
if (this.isWaitingForResponse) this.finishResponse();
|
|
1434
|
+
}, this.timeouts.maxResponse);
|
|
1435
|
+
};
|
|
1230
1436
|
const submit = () => {
|
|
1231
1437
|
if (!this.ptyProcess) return;
|
|
1232
1438
|
this.submitPendingUntil = 0;
|
|
1233
1439
|
this.ptyProcess.write(this.sendKey);
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1440
|
+
const retrySubmitIfStuck = (attempt) => {
|
|
1441
|
+
this.submitRetryTimer = null;
|
|
1442
|
+
if (!this.ptyProcess || !this.isWaitingForResponse || this.submitRetryUsed) return;
|
|
1443
|
+
if (this.currentStatus !== "generating") return;
|
|
1444
|
+
if ((this.responseBuffer || "").trim()) return;
|
|
1445
|
+
const screenText = this.terminalScreen.getText();
|
|
1446
|
+
if (!promptLikelyVisible(screenText, normalizedPromptSnippet)) return;
|
|
1447
|
+
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;
|
|
1448
|
+
this.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
|
|
1449
|
+
LOG.info("CLI", `[${this.cliType}] Retrying submit key for stuck prompt (attempt ${attempt})`);
|
|
1450
|
+
this.ptyProcess.write(this.sendKey);
|
|
1451
|
+
if (attempt >= 3) {
|
|
1452
|
+
this.submitRetryUsed = true;
|
|
1453
|
+
return;
|
|
1454
|
+
}
|
|
1455
|
+
this.submitRetryTimer = setTimeout(() => retrySubmitIfStuck(attempt + 1), retryDelayMs);
|
|
1456
|
+
};
|
|
1457
|
+
this.submitRetryTimer = setTimeout(() => retrySubmitIfStuck(1), retryDelayMs);
|
|
1458
|
+
startResponseTimeout();
|
|
1237
1459
|
};
|
|
1238
|
-
if (this.
|
|
1239
|
-
this.submitPendingUntil =
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1460
|
+
if (this.submitStrategy === "immediate") {
|
|
1461
|
+
this.submitPendingUntil = 0;
|
|
1462
|
+
this.ptyProcess.write(text + this.sendKey);
|
|
1463
|
+
this.submitRetryTimer = setTimeout(() => {
|
|
1464
|
+
this.submitRetryTimer = null;
|
|
1465
|
+
if (!this.ptyProcess || !this.isWaitingForResponse || this.submitRetryUsed) return;
|
|
1466
|
+
if (this.currentStatus !== "generating") return;
|
|
1467
|
+
if ((this.responseBuffer || "").trim()) return;
|
|
1468
|
+
const screenText = this.terminalScreen.getText();
|
|
1469
|
+
if (!promptLikelyVisible(screenText, normalizedPromptSnippet)) return;
|
|
1470
|
+
LOG.info("CLI", `[${this.cliType}] Retrying submit key for stuck prompt (attempt 1)`);
|
|
1471
|
+
this.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
|
|
1472
|
+
this.ptyProcess.write(this.sendKey);
|
|
1473
|
+
this.submitRetryUsed = true;
|
|
1474
|
+
}, retryDelayMs);
|
|
1475
|
+
startResponseTimeout();
|
|
1476
|
+
return;
|
|
1243
1477
|
}
|
|
1478
|
+
if (submitDelayMs > 0) {
|
|
1479
|
+
this.submitPendingUntil = Date.now() + submitDelayMs;
|
|
1480
|
+
}
|
|
1481
|
+
this.ptyProcess.write(text);
|
|
1482
|
+
const submitStartedAt = Date.now();
|
|
1483
|
+
let lastNormalizedScreen = "";
|
|
1484
|
+
let lastScreenChangeAt = submitStartedAt;
|
|
1485
|
+
const waitForEchoAndSubmit = () => {
|
|
1486
|
+
if (!this.ptyProcess) return;
|
|
1487
|
+
const now = Date.now();
|
|
1488
|
+
const elapsed = now - submitStartedAt;
|
|
1489
|
+
const screenText = this.terminalScreen.getText();
|
|
1490
|
+
const normalizedScreen = normalizePromptText(screenText);
|
|
1491
|
+
if (normalizedScreen !== lastNormalizedScreen) {
|
|
1492
|
+
lastNormalizedScreen = normalizedScreen;
|
|
1493
|
+
lastScreenChangeAt = now;
|
|
1494
|
+
}
|
|
1495
|
+
const echoVisible = !normalizedPromptSnippet || promptLikelyVisible(screenText, normalizedPromptSnippet);
|
|
1496
|
+
if (echoVisible) {
|
|
1497
|
+
const screenSettled = now - lastScreenChangeAt >= 500;
|
|
1498
|
+
if (elapsed >= submitDelayMs && screenSettled) {
|
|
1499
|
+
submit();
|
|
1500
|
+
return;
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
if (elapsed >= maxEchoWaitMs) {
|
|
1504
|
+
submit();
|
|
1505
|
+
return;
|
|
1506
|
+
}
|
|
1507
|
+
setTimeout(waitForEchoAndSubmit, 50);
|
|
1508
|
+
};
|
|
1509
|
+
waitForEchoAndSubmit();
|
|
1244
1510
|
}
|
|
1245
1511
|
getPartialResponse() {
|
|
1246
1512
|
if (!this.isWaitingForResponse) return "";
|
|
@@ -1258,6 +1524,10 @@ ${data.message || ""}`.trim();
|
|
|
1258
1524
|
clearTimeout(this.approvalExitTimeout);
|
|
1259
1525
|
this.approvalExitTimeout = null;
|
|
1260
1526
|
}
|
|
1527
|
+
if (this.submitRetryTimer) {
|
|
1528
|
+
clearTimeout(this.submitRetryTimer);
|
|
1529
|
+
this.submitRetryTimer = null;
|
|
1530
|
+
}
|
|
1261
1531
|
if (this.ptyProcess) {
|
|
1262
1532
|
this.ptyProcess.write("");
|
|
1263
1533
|
setTimeout(() => {
|
|
@@ -1275,10 +1545,14 @@ ${data.message || ""}`.trim();
|
|
|
1275
1545
|
}
|
|
1276
1546
|
}
|
|
1277
1547
|
clearHistory() {
|
|
1278
|
-
this.
|
|
1279
|
-
this.
|
|
1548
|
+
this.committedMessages = [];
|
|
1549
|
+
this.syncMessageViews();
|
|
1280
1550
|
this.accumulatedBuffer = "";
|
|
1281
1551
|
this.accumulatedRawBuffer = "";
|
|
1552
|
+
this.terminalHistory = "";
|
|
1553
|
+
this.currentTurnScope = null;
|
|
1554
|
+
this.submitRetryUsed = false;
|
|
1555
|
+
this.submitRetryPromptSnippet = "";
|
|
1282
1556
|
this.terminalScreen.reset();
|
|
1283
1557
|
this.onStatusChange?.();
|
|
1284
1558
|
}
|
|
@@ -1292,7 +1566,16 @@ ${data.message || ""}`.trim();
|
|
|
1292
1566
|
this.ptyProcess?.write(data);
|
|
1293
1567
|
}
|
|
1294
1568
|
resolveModal(buttonIndex) {
|
|
1295
|
-
if (!this.ptyProcess || this.currentStatus !== "waiting_approval") return;
|
|
1569
|
+
if (!this.ptyProcess || this.currentStatus !== "waiting_approval" && !this.activeModal) return;
|
|
1570
|
+
this.activeModal = null;
|
|
1571
|
+
this.lastApprovalResolvedAt = Date.now();
|
|
1572
|
+
this.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
|
|
1573
|
+
if (this.approvalExitTimeout) {
|
|
1574
|
+
clearTimeout(this.approvalExitTimeout);
|
|
1575
|
+
this.approvalExitTimeout = null;
|
|
1576
|
+
}
|
|
1577
|
+
this.setStatus("generating", "approval_resolved");
|
|
1578
|
+
this.onStatusChange?.();
|
|
1296
1579
|
if (buttonIndex in this.approvalKeys) {
|
|
1297
1580
|
this.ptyProcess.write(this.approvalKeys[buttonIndex]);
|
|
1298
1581
|
} else {
|
|
@@ -1321,9 +1604,12 @@ ${data.message || ""}`.trim();
|
|
|
1321
1604
|
spawnAt: this.spawnAt,
|
|
1322
1605
|
workingDir: this.workingDir,
|
|
1323
1606
|
messages: this.messages.slice(-20),
|
|
1607
|
+
committedMessages: this.committedMessages.slice(-20),
|
|
1324
1608
|
structuredMessages: this.structuredMessages.slice(-20),
|
|
1325
|
-
messageCount: this.
|
|
1609
|
+
messageCount: this.committedMessages.length,
|
|
1326
1610
|
screenText: this.terminalScreen.getText().slice(-4e3),
|
|
1611
|
+
terminalHistory: this.terminalHistory.slice(-8e3),
|
|
1612
|
+
currentTurnScope: this.currentTurnScope,
|
|
1327
1613
|
startupBuffer: this.startupBuffer.slice(-4e3),
|
|
1328
1614
|
recentOutputBuffer: this.recentOutputBuffer.slice(-500),
|
|
1329
1615
|
settledBuffer: this.settledBuffer.slice(-500),
|
|
@@ -1334,6 +1620,11 @@ ${data.message || ""}`.trim();
|
|
|
1334
1620
|
isWaitingForResponse: this.isWaitingForResponse,
|
|
1335
1621
|
activeModal: this.activeModal,
|
|
1336
1622
|
lastApprovalResolvedAt: this.lastApprovalResolvedAt,
|
|
1623
|
+
sendDelayMs: this.sendDelayMs,
|
|
1624
|
+
sendKey: this.sendKey,
|
|
1625
|
+
submitStrategy: this.submitStrategy,
|
|
1626
|
+
submitPendingUntil: this.submitPendingUntil,
|
|
1627
|
+
responseSettleIgnoreUntil: this.responseSettleIgnoreUntil,
|
|
1337
1628
|
resizeSuppressUntil: this.resizeSuppressUntil,
|
|
1338
1629
|
hasCliScripts: this.hasCliScripts(),
|
|
1339
1630
|
scriptNames: Object.keys(this.cliScripts).filter((k) => typeof this.cliScripts[k] === "function"),
|
|
@@ -3124,6 +3415,8 @@ var ChatHistoryWriter = class {
|
|
|
3124
3415
|
lastSeenCounts = /* @__PURE__ */ new Map();
|
|
3125
3416
|
/** Last seen message hash per agent (deduplication) */
|
|
3126
3417
|
lastSeenHashes = /* @__PURE__ */ new Map();
|
|
3418
|
+
/** Last seen append-only terminal transcript per agent */
|
|
3419
|
+
lastSeenTerminal = /* @__PURE__ */ new Map();
|
|
3127
3420
|
rotated = false;
|
|
3128
3421
|
/**
|
|
3129
3422
|
* Append new messages to history
|
|
@@ -3181,10 +3474,51 @@ var ChatHistoryWriter = class {
|
|
|
3181
3474
|
} catch {
|
|
3182
3475
|
}
|
|
3183
3476
|
}
|
|
3477
|
+
appendTerminalHistory(agentType, terminalHistory, sessionTitle, instanceId) {
|
|
3478
|
+
const next = String(terminalHistory || "");
|
|
3479
|
+
if (!next.trim()) return;
|
|
3480
|
+
try {
|
|
3481
|
+
const dedupKey = instanceId ? `${agentType}:${instanceId}:terminal` : `${agentType}:terminal`;
|
|
3482
|
+
const prev = this.lastSeenTerminal.get(dedupKey) || "";
|
|
3483
|
+
if (prev === next) return;
|
|
3484
|
+
let delta = "";
|
|
3485
|
+
if (!prev) {
|
|
3486
|
+
delta = next;
|
|
3487
|
+
} else if (next.startsWith(prev)) {
|
|
3488
|
+
delta = next.slice(prev.length);
|
|
3489
|
+
} else if (prev.includes(next)) {
|
|
3490
|
+
this.lastSeenTerminal.set(dedupKey, next);
|
|
3491
|
+
return;
|
|
3492
|
+
} else {
|
|
3493
|
+
delta = `
|
|
3494
|
+
|
|
3495
|
+
[terminal snapshot reset ${(/* @__PURE__ */ new Date()).toISOString()} | ${sessionTitle || agentType}]
|
|
3496
|
+
${next}`;
|
|
3497
|
+
}
|
|
3498
|
+
if (!delta) {
|
|
3499
|
+
this.lastSeenTerminal.set(dedupKey, next);
|
|
3500
|
+
return;
|
|
3501
|
+
}
|
|
3502
|
+
const dir = path4.join(HISTORY_DIR, this.sanitize(agentType));
|
|
3503
|
+
fs3.mkdirSync(dir, { recursive: true });
|
|
3504
|
+
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
3505
|
+
const filePrefix = instanceId ? `${this.sanitize(instanceId)}_` : "";
|
|
3506
|
+
const filePath = path4.join(dir, `${filePrefix}${date}.terminal.log`);
|
|
3507
|
+
fs3.appendFileSync(filePath, delta, "utf-8");
|
|
3508
|
+
this.lastSeenTerminal.set(dedupKey, next);
|
|
3509
|
+
if (!this.rotated) {
|
|
3510
|
+
this.rotated = true;
|
|
3511
|
+
this.rotateOldFiles().catch(() => {
|
|
3512
|
+
});
|
|
3513
|
+
}
|
|
3514
|
+
} catch {
|
|
3515
|
+
}
|
|
3516
|
+
}
|
|
3184
3517
|
/** Called when agent session is explicitly changed */
|
|
3185
3518
|
onSessionChange(agentType) {
|
|
3186
3519
|
this.lastSeenHashes.delete(agentType);
|
|
3187
3520
|
this.lastSeenCounts.delete(agentType);
|
|
3521
|
+
this.lastSeenTerminal.delete(`${agentType}:terminal`);
|
|
3188
3522
|
}
|
|
3189
3523
|
/** Delete history files older than 30 days */
|
|
3190
3524
|
async rotateOldFiles() {
|
|
@@ -3194,7 +3528,7 @@ var ChatHistoryWriter = class {
|
|
|
3194
3528
|
const agentDirs = fs3.readdirSync(HISTORY_DIR, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
3195
3529
|
for (const dir of agentDirs) {
|
|
3196
3530
|
const dirPath = path4.join(HISTORY_DIR, dir.name);
|
|
3197
|
-
const files = fs3.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
|
|
3531
|
+
const files = fs3.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl") || f.endsWith(".terminal.log"));
|
|
3198
3532
|
for (const file of files) {
|
|
3199
3533
|
const filePath = path4.join(dirPath, file);
|
|
3200
3534
|
const stat = fs3.statSync(filePath);
|
|
@@ -4102,7 +4436,13 @@ async function handleReadChat(h, args) {
|
|
|
4102
4436
|
_log(`${provider.category} adapter: ${adapter.cliType}`);
|
|
4103
4437
|
const status = adapter.getStatus?.();
|
|
4104
4438
|
if (status) {
|
|
4105
|
-
return {
|
|
4439
|
+
return {
|
|
4440
|
+
success: true,
|
|
4441
|
+
messages: status.messages || [],
|
|
4442
|
+
status: status.status,
|
|
4443
|
+
activeModal: status.activeModal,
|
|
4444
|
+
terminalHistory: status.terminalHistory || ""
|
|
4445
|
+
};
|
|
4106
4446
|
}
|
|
4107
4447
|
}
|
|
4108
4448
|
return { success: false, error: `${provider.category} adapter not found` };
|
|
@@ -7982,31 +8322,12 @@ var CliProviderInstance = class {
|
|
|
7982
8322
|
async onTick() {
|
|
7983
8323
|
}
|
|
7984
8324
|
getState() {
|
|
7985
|
-
const
|
|
7986
|
-
const parsedStatus = this.adapter.getScriptParsedStatus();
|
|
7987
|
-
const adapterStatus = parsedStatus ? {
|
|
7988
|
-
...rawStatus,
|
|
7989
|
-
messages: parsedStatus.messages || rawStatus.messages,
|
|
7990
|
-
activeModal: parsedStatus.activeModal || rawStatus.activeModal
|
|
7991
|
-
} : rawStatus;
|
|
8325
|
+
const adapterStatus = this.adapter.getStatus();
|
|
7992
8326
|
const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
|
|
7993
8327
|
const recentMessages = adapterStatus.messages.slice(-50).map((m) => {
|
|
7994
8328
|
const content = typeof m.content === "string" && m.content.length > 8e3 ? m.content.slice(0, 8e3) + "\n... (truncated)" : m.content;
|
|
7995
8329
|
return { ...m, content };
|
|
7996
8330
|
});
|
|
7997
|
-
const partial = this.adapter.getPartialResponse();
|
|
7998
|
-
const shouldAppendRawPartial = !parsedStatus;
|
|
7999
|
-
if (shouldAppendRawPartial && adapterStatus.status === "generating" && partial) {
|
|
8000
|
-
const cleaned = partial.trim();
|
|
8001
|
-
if (cleaned && cleaned !== "(generating...)") {
|
|
8002
|
-
recentMessages.push({
|
|
8003
|
-
role: "assistant",
|
|
8004
|
-
content: (cleaned.length > 8e3 ? cleaned.slice(0, 8e3) + "..." : cleaned) + "...",
|
|
8005
|
-
timestamp: Date.now(),
|
|
8006
|
-
meta: { streaming: true }
|
|
8007
|
-
});
|
|
8008
|
-
}
|
|
8009
|
-
}
|
|
8010
8331
|
if (recentMessages.length > 0) {
|
|
8011
8332
|
const dirName2 = this.workingDir.split("/").filter(Boolean).pop() || "session";
|
|
8012
8333
|
this.historyWriter.appendNewMessages(
|
|
@@ -8016,6 +8337,14 @@ var CliProviderInstance = class {
|
|
|
8016
8337
|
this.instanceId
|
|
8017
8338
|
);
|
|
8018
8339
|
}
|
|
8340
|
+
if (adapterStatus.terminalHistory?.trim()) {
|
|
8341
|
+
this.historyWriter.appendTerminalHistory(
|
|
8342
|
+
this.type,
|
|
8343
|
+
adapterStatus.terminalHistory,
|
|
8344
|
+
`${this.provider.name} \xB7 ${dirName}`,
|
|
8345
|
+
this.instanceId
|
|
8346
|
+
);
|
|
8347
|
+
}
|
|
8019
8348
|
return {
|
|
8020
8349
|
type: this.type,
|
|
8021
8350
|
name: this.provider.name,
|
|
@@ -8028,6 +8357,7 @@ var CliProviderInstance = class {
|
|
|
8028
8357
|
status: adapterStatus.status,
|
|
8029
8358
|
messages: recentMessages,
|
|
8030
8359
|
activeModal: adapterStatus.activeModal,
|
|
8360
|
+
terminalHistory: adapterStatus.terminalHistory,
|
|
8031
8361
|
inputContent: ""
|
|
8032
8362
|
},
|
|
8033
8363
|
workspace: this.workingDir,
|
|
@@ -10188,7 +10518,8 @@ async function detectAllVersions(loader, archive) {
|
|
|
10188
10518
|
binary: null,
|
|
10189
10519
|
detectedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
10190
10520
|
};
|
|
10191
|
-
const
|
|
10521
|
+
const verCmdConfig = provider.versionCommand;
|
|
10522
|
+
const versionCommand = typeof verCmdConfig === "object" && verCmdConfig !== null ? verCmdConfig[currentOs] : verCmdConfig;
|
|
10192
10523
|
if (provider.category === "ide") {
|
|
10193
10524
|
const osPaths = provider.paths?.[currentOs] || [];
|
|
10194
10525
|
const appPath = checkPathExists2(osPaths);
|
|
@@ -11600,11 +11931,7 @@ var DevServer = class _DevServer {
|
|
|
11600
11931
|
return;
|
|
11601
11932
|
}
|
|
11602
11933
|
let targetDir;
|
|
11603
|
-
|
|
11604
|
-
targetDir = this.providerLoader.getUserProviderDir(category, type);
|
|
11605
|
-
} else {
|
|
11606
|
-
targetDir = this.providerLoader.getBuiltinProviderDir(category, type);
|
|
11607
|
-
}
|
|
11934
|
+
targetDir = this.providerLoader.getUserProviderDir(category, type);
|
|
11608
11935
|
const jsonPath = path12.join(targetDir, "provider.json");
|
|
11609
11936
|
if (fs9.existsSync(jsonPath)) {
|
|
11610
11937
|
this.json(res, 409, { error: `Provider already exists at ${targetDir}`, path: targetDir });
|
|
@@ -12402,8 +12729,7 @@ var DevServer = class _DevServer {
|
|
|
12402
12729
|
}
|
|
12403
12730
|
loadAutoImplReferenceScripts(category, referenceType) {
|
|
12404
12731
|
if (!referenceType) return {};
|
|
12405
|
-
const
|
|
12406
|
-
const refDir = path12.join(builtinDir, category, referenceType);
|
|
12732
|
+
const refDir = this.providerLoader.getUpstreamProviderDir(category, referenceType);
|
|
12407
12733
|
if (!fs9.existsSync(refDir)) return {};
|
|
12408
12734
|
const referenceScripts = {};
|
|
12409
12735
|
const scriptsDir = path12.join(refDir, "scripts");
|
|
@@ -12642,7 +12968,7 @@ var DevServer = class _DevServer {
|
|
|
12642
12968
|
}
|
|
12643
12969
|
if (model) args.push("--model", model);
|
|
12644
12970
|
const escapedArgs = args.map((a) => `'${a.replace(/'/g, "'\\''")}'`).join(" ");
|
|
12645
|
-
const metaPrompt = `Read the file at ${promptFile} and follow ALL instructions
|
|
12971
|
+
const metaPrompt = `Read the file at ${promptFile} and follow ALL instructions strictly. DO NOT spend time exploring the filesystem or other providers. You have full authority to implement ALL required script files and independently test them against 127.0.0.1:19280 via CDP CURL. Upon complete validation of ALL assigned files, print exactly "_PIPELINE_COMPLETE_SIGNAL_" to gracefully close the pipeline. DO NOT WAIT FOR APPROVAL, execute completely autonomously.`;
|
|
12646
12972
|
shellCmd = `${command} ${escapedArgs} "${metaPrompt}"`;
|
|
12647
12973
|
} else {
|
|
12648
12974
|
const escapedArgs = baseArgs.map((a) => `'${a.replace(/'/g, "'\\''")}'`).join(" ");
|
|
@@ -12905,6 +13231,8 @@ var DevServer = class _DevServer {
|
|
|
12905
13231
|
lines.push("5. Do NOT modify `scripts.js` router \u2014 only edit individual `*.js` files");
|
|
12906
13232
|
lines.push("6. All scripts run in the browser (CDP evaluate) \u2014 use DOM APIs only");
|
|
12907
13233
|
lines.push('7. **Cross-Platform Compatibility**: If you use ARIA labels that contain keyboard shortcuts (e.g., `Cascade (\u2318L)`), you MUST use substring matches (`aria-label*="Cascade"`) or handle both macOS (`\u2318`, `Cmd`) and Windows (`Ctrl`) so the script does not break on other operating systems.');
|
|
13234
|
+
lines.push("8. **CRITICAL: DO NOT explore the filesystem or read other providers.** The reference implementation pattern is already provided below. Do not run `find`, `rg`, or `cat` on upstream providers. Doing so wastes context tokens and will crash the agent session. Focus entirely on modifying the target files.");
|
|
13235
|
+
lines.push("9. Do NOT delete any files. Implement the logic by replacing the empty stubs.");
|
|
12908
13236
|
lines.push("");
|
|
12909
13237
|
lines.push("## Required Return Format");
|
|
12910
13238
|
lines.push("| Function | Return JSON |");
|