@adhdev/daemon-core 0.6.57 → 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 +17 -0
- package/dist/index.js +252 -78
- 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 +223 -48
- 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.d.ts
CHANGED
|
@@ -18,6 +18,7 @@ interface ActiveChatData {
|
|
|
18
18
|
message: string;
|
|
19
19
|
buttons: string[];
|
|
20
20
|
} | null;
|
|
21
|
+
terminalHistory?: string;
|
|
21
22
|
inputContent?: string;
|
|
22
23
|
}
|
|
23
24
|
/** Standardized error reasons across all provider categories */
|
|
@@ -1653,6 +1654,8 @@ declare class ChatHistoryWriter {
|
|
|
1653
1654
|
private lastSeenCounts;
|
|
1654
1655
|
/** Last seen message hash per agent (deduplication) */
|
|
1655
1656
|
private lastSeenHashes;
|
|
1657
|
+
/** Last seen append-only terminal transcript per agent */
|
|
1658
|
+
private lastSeenTerminal;
|
|
1656
1659
|
private rotated;
|
|
1657
1660
|
/**
|
|
1658
1661
|
* Append new messages to history
|
|
@@ -1667,6 +1670,7 @@ declare class ChatHistoryWriter {
|
|
|
1667
1670
|
content: string;
|
|
1668
1671
|
receivedAt?: number;
|
|
1669
1672
|
}>, sessionTitle?: string, instanceId?: string): void;
|
|
1673
|
+
appendTerminalHistory(agentType: string, terminalHistory: string, sessionTitle?: string, instanceId?: string): void;
|
|
1670
1674
|
/** Called when agent session is explicitly changed */
|
|
1671
1675
|
onSessionChange(agentType: string): void;
|
|
1672
1676
|
/** Delete history files older than 30 days */
|
|
@@ -2563,6 +2567,7 @@ interface CliSessionStatus {
|
|
|
2563
2567
|
message: string;
|
|
2564
2568
|
buttons: string[];
|
|
2565
2569
|
} | null;
|
|
2570
|
+
terminalHistory?: string;
|
|
2566
2571
|
}
|
|
2567
2572
|
/**
|
|
2568
2573
|
* CLI Script Functions.
|
|
@@ -2597,6 +2602,7 @@ interface CliScriptInput {
|
|
|
2597
2602
|
rawBuffer: string;
|
|
2598
2603
|
recentBuffer: string;
|
|
2599
2604
|
screenText: string;
|
|
2605
|
+
terminalHistory?: string;
|
|
2600
2606
|
messages: CliChatMessage[];
|
|
2601
2607
|
partialResponse: string;
|
|
2602
2608
|
}
|
|
@@ -2607,6 +2613,7 @@ interface CliProviderModule {
|
|
|
2607
2613
|
binary: string;
|
|
2608
2614
|
sendDelayMs?: number;
|
|
2609
2615
|
sendKey?: string;
|
|
2616
|
+
submitStrategy?: 'wait_for_echo' | 'immediate';
|
|
2610
2617
|
spawn: {
|
|
2611
2618
|
command: string;
|
|
2612
2619
|
args: string[];
|
|
@@ -2640,6 +2647,7 @@ declare class ProviderCliAdapter implements CliAdapter {
|
|
|
2640
2647
|
private provider;
|
|
2641
2648
|
private ptyProcess;
|
|
2642
2649
|
private messages;
|
|
2650
|
+
private committedMessages;
|
|
2643
2651
|
private structuredMessages;
|
|
2644
2652
|
private currentStatus;
|
|
2645
2653
|
private onStatusChange;
|
|
@@ -2678,13 +2686,20 @@ declare class ProviderCliAdapter implements CliAdapter {
|
|
|
2678
2686
|
private accumulatedRawBuffer;
|
|
2679
2687
|
/** Current visible terminal screen snapshot */
|
|
2680
2688
|
private terminalScreen;
|
|
2689
|
+
/** Rolling append-only terminal transcript built from screen snapshots */
|
|
2690
|
+
private terminalHistory;
|
|
2681
2691
|
/** Max accumulated buffer size (last 50KB) */
|
|
2682
2692
|
private static readonly MAX_ACCUMULATED_BUFFER;
|
|
2693
|
+
private currentTurnScope;
|
|
2694
|
+
private syncMessageViews;
|
|
2695
|
+
private sliceFromOffset;
|
|
2696
|
+
private buildParseInput;
|
|
2683
2697
|
private setStatus;
|
|
2684
2698
|
private readonly timeouts;
|
|
2685
2699
|
private readonly approvalKeys;
|
|
2686
2700
|
private readonly sendDelayMs;
|
|
2687
2701
|
private readonly sendKey;
|
|
2702
|
+
private readonly submitStrategy;
|
|
2688
2703
|
constructor(provider: CliProviderModule, workingDir: string, extraArgs?: string[]);
|
|
2689
2704
|
/** Inject CLI scripts after construction (e.g. when resolved by ProviderLoader) */
|
|
2690
2705
|
setCliScripts(scripts: CliScripts): void;
|
|
@@ -2697,6 +2712,7 @@ declare class ProviderCliAdapter implements CliAdapter {
|
|
|
2697
2712
|
private armApprovalExitTimeout;
|
|
2698
2713
|
private evaluateSettled;
|
|
2699
2714
|
private finishResponse;
|
|
2715
|
+
private commitCurrentTranscript;
|
|
2700
2716
|
private runDetectStatus;
|
|
2701
2717
|
private runParseApproval;
|
|
2702
2718
|
getStatus(): CliSessionStatus;
|
|
@@ -2705,6 +2721,7 @@ declare class ProviderCliAdapter implements CliAdapter {
|
|
|
2705
2721
|
* Called by command handler / dashboard for rich content rendering.
|
|
2706
2722
|
*/
|
|
2707
2723
|
getScriptParsedStatus(): any;
|
|
2724
|
+
private parseCurrentTranscript;
|
|
2708
2725
|
/** Whether this adapter has CLI scripts loaded */
|
|
2709
2726
|
hasCliScripts(): boolean;
|
|
2710
2727
|
/**
|
package/dist/index.js
CHANGED
|
@@ -750,6 +750,36 @@ function promptLikelyVisible(screenText, promptSnippet) {
|
|
|
750
750
|
).length;
|
|
751
751
|
return matched >= required;
|
|
752
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
|
+
}
|
|
753
783
|
function parsePatternEntry(x) {
|
|
754
784
|
if (x instanceof RegExp) return x;
|
|
755
785
|
if (x && typeof x === "object" && typeof x.source === "string") {
|
|
@@ -826,6 +856,7 @@ var init_provider_cli_adapter = __esm({
|
|
|
826
856
|
this.approvalKeys = rawKeys && typeof rawKeys === "object" ? rawKeys : {};
|
|
827
857
|
this.sendDelayMs = typeof provider.sendDelayMs === "number" ? Math.max(0, provider.sendDelayMs) : 0;
|
|
828
858
|
this.sendKey = typeof provider.sendKey === "string" && provider.sendKey.length > 0 ? provider.sendKey : "\r";
|
|
859
|
+
this.submitStrategy = provider.submitStrategy === "immediate" ? "immediate" : "wait_for_echo";
|
|
829
860
|
this.cliScripts = provider.scripts || {};
|
|
830
861
|
const scriptNames = Object.keys(this.cliScripts).filter((k) => typeof this.cliScripts[k] === "function");
|
|
831
862
|
if (scriptNames.length > 0) {
|
|
@@ -840,6 +871,7 @@ var init_provider_cli_adapter = __esm({
|
|
|
840
871
|
provider;
|
|
841
872
|
ptyProcess = null;
|
|
842
873
|
messages = [];
|
|
874
|
+
committedMessages = [];
|
|
843
875
|
structuredMessages = [];
|
|
844
876
|
currentStatus = "starting";
|
|
845
877
|
onStatusChange = null;
|
|
@@ -886,8 +918,35 @@ var init_provider_cli_adapter = __esm({
|
|
|
886
918
|
accumulatedRawBuffer = "";
|
|
887
919
|
/** Current visible terminal screen snapshot */
|
|
888
920
|
terminalScreen = new TerminalScreen(40, 120);
|
|
921
|
+
/** Rolling append-only terminal transcript built from screen snapshots */
|
|
922
|
+
terminalHistory = "";
|
|
889
923
|
/** Max accumulated buffer size (last 50KB) */
|
|
890
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
|
+
}
|
|
891
950
|
setStatus(status, trigger) {
|
|
892
951
|
const prev = this.currentStatus;
|
|
893
952
|
if (prev === status) return;
|
|
@@ -902,6 +961,7 @@ var init_provider_cli_adapter = __esm({
|
|
|
902
961
|
approvalKeys;
|
|
903
962
|
sendDelayMs;
|
|
904
963
|
sendKey;
|
|
964
|
+
submitStrategy;
|
|
905
965
|
/** Inject CLI scripts after construction (e.g. when resolved by ProviderLoader) */
|
|
906
966
|
setCliScripts(scripts) {
|
|
907
967
|
this.cliScripts = scripts;
|
|
@@ -997,6 +1057,8 @@ var init_provider_cli_adapter = __esm({
|
|
|
997
1057
|
this.startupParseGate = true;
|
|
998
1058
|
this.startupBuffer = "";
|
|
999
1059
|
this.terminalScreen.reset(40, 120);
|
|
1060
|
+
this.terminalHistory = "";
|
|
1061
|
+
this.currentTurnScope = null;
|
|
1000
1062
|
this.ready = false;
|
|
1001
1063
|
this.setStatus("idle", "pty_ready");
|
|
1002
1064
|
this.onStatusChange?.();
|
|
@@ -1008,6 +1070,7 @@ var init_provider_cli_adapter = __esm({
|
|
|
1008
1070
|
this.ptyProcess?.write("\x1B[1;1R");
|
|
1009
1071
|
}
|
|
1010
1072
|
this.terminalScreen.write(rawData);
|
|
1073
|
+
this.terminalHistory = mergeTerminalHistory(this.terminalHistory, this.terminalScreen.getText());
|
|
1011
1074
|
const cleanData = stripAnsi(rawData);
|
|
1012
1075
|
if (this.isWaitingForResponse && cleanData) {
|
|
1013
1076
|
this.responseBuffer = (this.responseBuffer + cleanData).slice(-8e3);
|
|
@@ -1152,6 +1215,7 @@ var init_provider_cli_adapter = __esm({
|
|
|
1152
1215
|
finishResponse() {
|
|
1153
1216
|
if (this.submitPendingUntil > Date.now()) return;
|
|
1154
1217
|
if (this.responseSettleIgnoreUntil > Date.now()) return;
|
|
1218
|
+
this.commitCurrentTranscript();
|
|
1155
1219
|
if (this.responseTimeout) {
|
|
1156
1220
|
clearTimeout(this.responseTimeout);
|
|
1157
1221
|
this.responseTimeout = null;
|
|
@@ -1173,10 +1237,58 @@ var init_provider_cli_adapter = __esm({
|
|
|
1173
1237
|
this.responseSettleIgnoreUntil = 0;
|
|
1174
1238
|
this.submitRetryUsed = false;
|
|
1175
1239
|
this.submitRetryPromptSnippet = "";
|
|
1240
|
+
this.currentTurnScope = null;
|
|
1176
1241
|
this.activeModal = null;
|
|
1177
1242
|
this.setStatus("idle", "response_finished");
|
|
1178
1243
|
this.onStatusChange?.();
|
|
1179
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
|
+
}
|
|
1180
1292
|
// ─── Script Execution ──────────────────────────
|
|
1181
1293
|
runDetectStatus(text) {
|
|
1182
1294
|
if (!this.cliScripts?.detectStatus) return null;
|
|
@@ -1206,24 +1318,12 @@ var init_provider_cli_adapter = __esm({
|
|
|
1206
1318
|
}
|
|
1207
1319
|
// ─── Public API (CliAdapter) ───────────────────
|
|
1208
1320
|
getStatus() {
|
|
1209
|
-
const scriptResult = this.getScriptParsedStatus();
|
|
1210
|
-
if (scriptResult) {
|
|
1211
|
-
return {
|
|
1212
|
-
status: this.currentStatus,
|
|
1213
|
-
messages: (scriptResult.messages || []).map((m) => ({
|
|
1214
|
-
role: m.role,
|
|
1215
|
-
content: m.content,
|
|
1216
|
-
timestamp: m.timestamp
|
|
1217
|
-
})),
|
|
1218
|
-
workingDir: this.workingDir,
|
|
1219
|
-
activeModal: this.activeModal
|
|
1220
|
-
};
|
|
1221
|
-
}
|
|
1222
1321
|
return {
|
|
1223
1322
|
status: this.currentStatus,
|
|
1224
|
-
messages: [...this.
|
|
1323
|
+
messages: [...this.committedMessages],
|
|
1225
1324
|
workingDir: this.workingDir,
|
|
1226
|
-
activeModal: this.activeModal
|
|
1325
|
+
activeModal: this.activeModal,
|
|
1326
|
+
terminalHistory: this.terminalHistory
|
|
1227
1327
|
};
|
|
1228
1328
|
}
|
|
1229
1329
|
/**
|
|
@@ -1231,31 +1331,32 @@ var init_provider_cli_adapter = __esm({
|
|
|
1231
1331
|
* Called by command handler / dashboard for rich content rendering.
|
|
1232
1332
|
*/
|
|
1233
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) {
|
|
1234
1352
|
if (!this.cliScripts?.parseOutput) return null;
|
|
1235
1353
|
try {
|
|
1236
|
-
const input =
|
|
1237
|
-
|
|
1238
|
-
rawBuffer: this.accumulatedRawBuffer,
|
|
1239
|
-
recentBuffer: this.recentOutputBuffer,
|
|
1240
|
-
screenText: this.terminalScreen.getText(),
|
|
1241
|
-
messages: [...this.structuredMessages.length > 0 ? this.structuredMessages : this.messages],
|
|
1242
|
-
partialResponse: this.responseBuffer
|
|
1243
|
-
};
|
|
1244
|
-
const result = this.cliScripts.parseOutput(input);
|
|
1245
|
-
if (result && typeof result === "object") {
|
|
1246
|
-
if (Array.isArray(result.messages)) {
|
|
1247
|
-
this.structuredMessages = result.messages.map((m) => ({
|
|
1248
|
-
role: m.role,
|
|
1249
|
-
content: m.content,
|
|
1250
|
-
timestamp: m.timestamp
|
|
1251
|
-
}));
|
|
1252
|
-
}
|
|
1253
|
-
return result;
|
|
1254
|
-
}
|
|
1354
|
+
const input = this.buildParseInput(baseMessages, partialResponse, scope);
|
|
1355
|
+
return this.cliScripts.parseOutput(input);
|
|
1255
1356
|
} catch (e) {
|
|
1256
1357
|
LOG.warn("CLI", `[${this.cliType}] parseOutput error: ${e.message}`);
|
|
1358
|
+
return null;
|
|
1257
1359
|
}
|
|
1258
|
-
return null;
|
|
1259
1360
|
}
|
|
1260
1361
|
/** Whether this adapter has CLI scripts loaded */
|
|
1261
1362
|
hasCliScripts() {
|
|
@@ -1295,10 +1396,18 @@ ${data.message || ""}`.trim();
|
|
|
1295
1396
|
}
|
|
1296
1397
|
if (!this.ready) throw new Error(`${this.cliName} not ready (status: ${this.currentStatus})`);
|
|
1297
1398
|
if (this.isWaitingForResponse) return;
|
|
1298
|
-
this.
|
|
1299
|
-
this.
|
|
1399
|
+
this.committedMessages.push({ role: "user", content: text, timestamp: Date.now() });
|
|
1400
|
+
this.syncMessageViews();
|
|
1300
1401
|
this.isWaitingForResponse = true;
|
|
1301
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)}`);
|
|
1302
1411
|
this.submitRetryUsed = false;
|
|
1303
1412
|
this.submitRetryPromptSnippet = extractPromptRetrySnippet(text);
|
|
1304
1413
|
const normalizedPromptSnippet = normalizePromptText(this.submitRetryPromptSnippet);
|
|
@@ -1318,10 +1427,12 @@ ${data.message || ""}`.trim();
|
|
|
1318
1427
|
this.responseSettleIgnoreUntil = Date.now() + submitDelayMs + this.timeouts.outputSettle + 250;
|
|
1319
1428
|
this.setStatus("generating", "sendMessage");
|
|
1320
1429
|
this.onStatusChange?.();
|
|
1321
|
-
|
|
1322
|
-
this.
|
|
1323
|
-
|
|
1324
|
-
|
|
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
|
+
};
|
|
1325
1436
|
const submit = () => {
|
|
1326
1437
|
if (!this.ptyProcess) return;
|
|
1327
1438
|
this.submitPendingUntil = 0;
|
|
@@ -1344,10 +1455,30 @@ ${data.message || ""}`.trim();
|
|
|
1344
1455
|
this.submitRetryTimer = setTimeout(() => retrySubmitIfStuck(attempt + 1), retryDelayMs);
|
|
1345
1456
|
};
|
|
1346
1457
|
this.submitRetryTimer = setTimeout(() => retrySubmitIfStuck(1), retryDelayMs);
|
|
1347
|
-
|
|
1348
|
-
if (this.isWaitingForResponse) this.finishResponse();
|
|
1349
|
-
}, this.timeouts.maxResponse);
|
|
1458
|
+
startResponseTimeout();
|
|
1350
1459
|
};
|
|
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;
|
|
1477
|
+
}
|
|
1478
|
+
if (submitDelayMs > 0) {
|
|
1479
|
+
this.submitPendingUntil = Date.now() + submitDelayMs;
|
|
1480
|
+
}
|
|
1481
|
+
this.ptyProcess.write(text);
|
|
1351
1482
|
const submitStartedAt = Date.now();
|
|
1352
1483
|
let lastNormalizedScreen = "";
|
|
1353
1484
|
let lastScreenChangeAt = submitStartedAt;
|
|
@@ -1414,10 +1545,12 @@ ${data.message || ""}`.trim();
|
|
|
1414
1545
|
}
|
|
1415
1546
|
}
|
|
1416
1547
|
clearHistory() {
|
|
1417
|
-
this.
|
|
1418
|
-
this.
|
|
1548
|
+
this.committedMessages = [];
|
|
1549
|
+
this.syncMessageViews();
|
|
1419
1550
|
this.accumulatedBuffer = "";
|
|
1420
1551
|
this.accumulatedRawBuffer = "";
|
|
1552
|
+
this.terminalHistory = "";
|
|
1553
|
+
this.currentTurnScope = null;
|
|
1421
1554
|
this.submitRetryUsed = false;
|
|
1422
1555
|
this.submitRetryPromptSnippet = "";
|
|
1423
1556
|
this.terminalScreen.reset();
|
|
@@ -1471,9 +1604,12 @@ ${data.message || ""}`.trim();
|
|
|
1471
1604
|
spawnAt: this.spawnAt,
|
|
1472
1605
|
workingDir: this.workingDir,
|
|
1473
1606
|
messages: this.messages.slice(-20),
|
|
1607
|
+
committedMessages: this.committedMessages.slice(-20),
|
|
1474
1608
|
structuredMessages: this.structuredMessages.slice(-20),
|
|
1475
|
-
messageCount: this.
|
|
1609
|
+
messageCount: this.committedMessages.length,
|
|
1476
1610
|
screenText: this.terminalScreen.getText().slice(-4e3),
|
|
1611
|
+
terminalHistory: this.terminalHistory.slice(-8e3),
|
|
1612
|
+
currentTurnScope: this.currentTurnScope,
|
|
1477
1613
|
startupBuffer: this.startupBuffer.slice(-4e3),
|
|
1478
1614
|
recentOutputBuffer: this.recentOutputBuffer.slice(-500),
|
|
1479
1615
|
settledBuffer: this.settledBuffer.slice(-500),
|
|
@@ -1486,6 +1622,7 @@ ${data.message || ""}`.trim();
|
|
|
1486
1622
|
lastApprovalResolvedAt: this.lastApprovalResolvedAt,
|
|
1487
1623
|
sendDelayMs: this.sendDelayMs,
|
|
1488
1624
|
sendKey: this.sendKey,
|
|
1625
|
+
submitStrategy: this.submitStrategy,
|
|
1489
1626
|
submitPendingUntil: this.submitPendingUntil,
|
|
1490
1627
|
responseSettleIgnoreUntil: this.responseSettleIgnoreUntil,
|
|
1491
1628
|
resizeSuppressUntil: this.resizeSuppressUntil,
|
|
@@ -3278,6 +3415,8 @@ var ChatHistoryWriter = class {
|
|
|
3278
3415
|
lastSeenCounts = /* @__PURE__ */ new Map();
|
|
3279
3416
|
/** Last seen message hash per agent (deduplication) */
|
|
3280
3417
|
lastSeenHashes = /* @__PURE__ */ new Map();
|
|
3418
|
+
/** Last seen append-only terminal transcript per agent */
|
|
3419
|
+
lastSeenTerminal = /* @__PURE__ */ new Map();
|
|
3281
3420
|
rotated = false;
|
|
3282
3421
|
/**
|
|
3283
3422
|
* Append new messages to history
|
|
@@ -3335,10 +3474,51 @@ var ChatHistoryWriter = class {
|
|
|
3335
3474
|
} catch {
|
|
3336
3475
|
}
|
|
3337
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
|
+
}
|
|
3338
3517
|
/** Called when agent session is explicitly changed */
|
|
3339
3518
|
onSessionChange(agentType) {
|
|
3340
3519
|
this.lastSeenHashes.delete(agentType);
|
|
3341
3520
|
this.lastSeenCounts.delete(agentType);
|
|
3521
|
+
this.lastSeenTerminal.delete(`${agentType}:terminal`);
|
|
3342
3522
|
}
|
|
3343
3523
|
/** Delete history files older than 30 days */
|
|
3344
3524
|
async rotateOldFiles() {
|
|
@@ -3348,7 +3528,7 @@ var ChatHistoryWriter = class {
|
|
|
3348
3528
|
const agentDirs = fs3.readdirSync(HISTORY_DIR, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
3349
3529
|
for (const dir of agentDirs) {
|
|
3350
3530
|
const dirPath = path4.join(HISTORY_DIR, dir.name);
|
|
3351
|
-
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"));
|
|
3352
3532
|
for (const file of files) {
|
|
3353
3533
|
const filePath = path4.join(dirPath, file);
|
|
3354
3534
|
const stat = fs3.statSync(filePath);
|
|
@@ -4256,7 +4436,13 @@ async function handleReadChat(h, args) {
|
|
|
4256
4436
|
_log(`${provider.category} adapter: ${adapter.cliType}`);
|
|
4257
4437
|
const status = adapter.getStatus?.();
|
|
4258
4438
|
if (status) {
|
|
4259
|
-
return {
|
|
4439
|
+
return {
|
|
4440
|
+
success: true,
|
|
4441
|
+
messages: status.messages || [],
|
|
4442
|
+
status: status.status,
|
|
4443
|
+
activeModal: status.activeModal,
|
|
4444
|
+
terminalHistory: status.terminalHistory || ""
|
|
4445
|
+
};
|
|
4260
4446
|
}
|
|
4261
4447
|
}
|
|
4262
4448
|
return { success: false, error: `${provider.category} adapter not found` };
|
|
@@ -8136,31 +8322,12 @@ var CliProviderInstance = class {
|
|
|
8136
8322
|
async onTick() {
|
|
8137
8323
|
}
|
|
8138
8324
|
getState() {
|
|
8139
|
-
const
|
|
8140
|
-
const parsedStatus = this.adapter.getScriptParsedStatus();
|
|
8141
|
-
const adapterStatus = parsedStatus ? {
|
|
8142
|
-
...rawStatus,
|
|
8143
|
-
messages: parsedStatus.messages || rawStatus.messages,
|
|
8144
|
-
activeModal: parsedStatus.activeModal || rawStatus.activeModal
|
|
8145
|
-
} : rawStatus;
|
|
8325
|
+
const adapterStatus = this.adapter.getStatus();
|
|
8146
8326
|
const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
|
|
8147
8327
|
const recentMessages = adapterStatus.messages.slice(-50).map((m) => {
|
|
8148
8328
|
const content = typeof m.content === "string" && m.content.length > 8e3 ? m.content.slice(0, 8e3) + "\n... (truncated)" : m.content;
|
|
8149
8329
|
return { ...m, content };
|
|
8150
8330
|
});
|
|
8151
|
-
const partial = this.adapter.getPartialResponse();
|
|
8152
|
-
const shouldAppendRawPartial = !parsedStatus;
|
|
8153
|
-
if (shouldAppendRawPartial && adapterStatus.status === "generating" && partial) {
|
|
8154
|
-
const cleaned = partial.trim();
|
|
8155
|
-
if (cleaned && cleaned !== "(generating...)") {
|
|
8156
|
-
recentMessages.push({
|
|
8157
|
-
role: "assistant",
|
|
8158
|
-
content: (cleaned.length > 8e3 ? cleaned.slice(0, 8e3) + "..." : cleaned) + "...",
|
|
8159
|
-
timestamp: Date.now(),
|
|
8160
|
-
meta: { streaming: true }
|
|
8161
|
-
});
|
|
8162
|
-
}
|
|
8163
|
-
}
|
|
8164
8331
|
if (recentMessages.length > 0) {
|
|
8165
8332
|
const dirName2 = this.workingDir.split("/").filter(Boolean).pop() || "session";
|
|
8166
8333
|
this.historyWriter.appendNewMessages(
|
|
@@ -8170,6 +8337,14 @@ var CliProviderInstance = class {
|
|
|
8170
8337
|
this.instanceId
|
|
8171
8338
|
);
|
|
8172
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
|
+
}
|
|
8173
8348
|
return {
|
|
8174
8349
|
type: this.type,
|
|
8175
8350
|
name: this.provider.name,
|
|
@@ -8182,6 +8357,7 @@ var CliProviderInstance = class {
|
|
|
8182
8357
|
status: adapterStatus.status,
|
|
8183
8358
|
messages: recentMessages,
|
|
8184
8359
|
activeModal: adapterStatus.activeModal,
|
|
8360
|
+
terminalHistory: adapterStatus.terminalHistory,
|
|
8185
8361
|
inputContent: ""
|
|
8186
8362
|
},
|
|
8187
8363
|
workspace: this.workingDir,
|
|
@@ -10342,7 +10518,8 @@ async function detectAllVersions(loader, archive) {
|
|
|
10342
10518
|
binary: null,
|
|
10343
10519
|
detectedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
10344
10520
|
};
|
|
10345
|
-
const
|
|
10521
|
+
const verCmdConfig = provider.versionCommand;
|
|
10522
|
+
const versionCommand = typeof verCmdConfig === "object" && verCmdConfig !== null ? verCmdConfig[currentOs] : verCmdConfig;
|
|
10346
10523
|
if (provider.category === "ide") {
|
|
10347
10524
|
const osPaths = provider.paths?.[currentOs] || [];
|
|
10348
10525
|
const appPath = checkPathExists2(osPaths);
|
|
@@ -11754,11 +11931,7 @@ var DevServer = class _DevServer {
|
|
|
11754
11931
|
return;
|
|
11755
11932
|
}
|
|
11756
11933
|
let targetDir;
|
|
11757
|
-
|
|
11758
|
-
targetDir = this.providerLoader.getUserProviderDir(category, type);
|
|
11759
|
-
} else {
|
|
11760
|
-
targetDir = this.providerLoader.getBuiltinProviderDir(category, type);
|
|
11761
|
-
}
|
|
11934
|
+
targetDir = this.providerLoader.getUserProviderDir(category, type);
|
|
11762
11935
|
const jsonPath = path12.join(targetDir, "provider.json");
|
|
11763
11936
|
if (fs9.existsSync(jsonPath)) {
|
|
11764
11937
|
this.json(res, 409, { error: `Provider already exists at ${targetDir}`, path: targetDir });
|
|
@@ -12556,8 +12729,7 @@ var DevServer = class _DevServer {
|
|
|
12556
12729
|
}
|
|
12557
12730
|
loadAutoImplReferenceScripts(category, referenceType) {
|
|
12558
12731
|
if (!referenceType) return {};
|
|
12559
|
-
const
|
|
12560
|
-
const refDir = path12.join(builtinDir, category, referenceType);
|
|
12732
|
+
const refDir = this.providerLoader.getUpstreamProviderDir(category, referenceType);
|
|
12561
12733
|
if (!fs9.existsSync(refDir)) return {};
|
|
12562
12734
|
const referenceScripts = {};
|
|
12563
12735
|
const scriptsDir = path12.join(refDir, "scripts");
|
|
@@ -12796,7 +12968,7 @@ var DevServer = class _DevServer {
|
|
|
12796
12968
|
}
|
|
12797
12969
|
if (model) args.push("--model", model);
|
|
12798
12970
|
const escapedArgs = args.map((a) => `'${a.replace(/'/g, "'\\''")}'`).join(" ");
|
|
12799
|
-
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.`;
|
|
12800
12972
|
shellCmd = `${command} ${escapedArgs} "${metaPrompt}"`;
|
|
12801
12973
|
} else {
|
|
12802
12974
|
const escapedArgs = baseArgs.map((a) => `'${a.replace(/'/g, "'\\''")}'`).join(" ");
|
|
@@ -13059,6 +13231,8 @@ var DevServer = class _DevServer {
|
|
|
13059
13231
|
lines.push("5. Do NOT modify `scripts.js` router \u2014 only edit individual `*.js` files");
|
|
13060
13232
|
lines.push("6. All scripts run in the browser (CDP evaluate) \u2014 use DOM APIs only");
|
|
13061
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.");
|
|
13062
13236
|
lines.push("");
|
|
13063
13237
|
lines.push("## Required Return Format");
|
|
13064
13238
|
lines.push("| Function | Return JSON |");
|