@adhdev/daemon-core 0.8.83 → 0.8.85
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/cli-adapters/provider-cli-adapter.d.ts +3 -0
- package/dist/cli-adapters/session-host-transport.d.ts +2 -1
- package/dist/config/chat-history.d.ts +1 -0
- package/dist/index.js +297 -24
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +297 -24
- package/dist/index.mjs.map +1 -1
- package/dist/providers/cli-provider-instance.d.ts +10 -0
- package/node_modules/@adhdev/session-host-core/package.json +1 -1
- package/package.json +1 -1
- package/src/cli-adapters/provider-cli-adapter.ts +252 -21
- package/src/cli-adapters/session-host-transport.ts +9 -1
- package/src/commands/chat-commands.ts +35 -2
- package/src/config/chat-history.ts +137 -0
- package/src/providers/cli-provider-instance.ts +68 -3
- package/src/session-host/startup-restore-policy.js +2 -0
- package/src/session-host/startup-restore-policy.ts +2 -0
package/dist/index.mjs
CHANGED
|
@@ -2498,6 +2498,58 @@ var init_provider_cli_adapter = __esm({
|
|
|
2498
2498
|
`[${this.cliType}] Interactive prompt wait timed out after ${maxWaitMs}ms; proceeding with screen=${JSON.stringify(summarizeCliTraceText(finalScreenText, 240)).slice(0, 280)}`
|
|
2499
2499
|
);
|
|
2500
2500
|
}
|
|
2501
|
+
clearStaleIdleResponseGuard(reason) {
|
|
2502
|
+
const screenText = this.terminalScreen.getText() || "";
|
|
2503
|
+
const visibleIdlePrompt = this.looksLikeVisibleIdlePrompt(screenText);
|
|
2504
|
+
const blockingModal = this.activeModal || this.getStartupConfirmationModal(screenText);
|
|
2505
|
+
if (!this.isWaitingForResponse || this.currentStatus !== "idle" || !visibleIdlePrompt || !!blockingModal) {
|
|
2506
|
+
return false;
|
|
2507
|
+
}
|
|
2508
|
+
if (this.responseTimeout) {
|
|
2509
|
+
clearTimeout(this.responseTimeout);
|
|
2510
|
+
this.responseTimeout = null;
|
|
2511
|
+
}
|
|
2512
|
+
if (this.idleTimeout) {
|
|
2513
|
+
clearTimeout(this.idleTimeout);
|
|
2514
|
+
this.idleTimeout = null;
|
|
2515
|
+
}
|
|
2516
|
+
if (this.approvalExitTimeout) {
|
|
2517
|
+
clearTimeout(this.approvalExitTimeout);
|
|
2518
|
+
this.approvalExitTimeout = null;
|
|
2519
|
+
}
|
|
2520
|
+
if (this.finishRetryTimer) {
|
|
2521
|
+
clearTimeout(this.finishRetryTimer);
|
|
2522
|
+
this.finishRetryTimer = null;
|
|
2523
|
+
}
|
|
2524
|
+
this.clearIdleFinishCandidate(reason);
|
|
2525
|
+
this.responseBuffer = "";
|
|
2526
|
+
this.isWaitingForResponse = false;
|
|
2527
|
+
this.responseSettleIgnoreUntil = 0;
|
|
2528
|
+
this.submitRetryUsed = false;
|
|
2529
|
+
this.submitRetryPromptSnippet = "";
|
|
2530
|
+
this.finishRetryCount = 0;
|
|
2531
|
+
this.currentTurnScope = null;
|
|
2532
|
+
this.activeModal = null;
|
|
2533
|
+
this.recordTrace("stale_idle_response_cleared", {
|
|
2534
|
+
reason,
|
|
2535
|
+
screenText: summarizeCliTraceText(screenText, 240)
|
|
2536
|
+
});
|
|
2537
|
+
return true;
|
|
2538
|
+
}
|
|
2539
|
+
hasMeaningfulResponseBuffer(promptSnippet) {
|
|
2540
|
+
const raw = String(this.responseBuffer || "").trim();
|
|
2541
|
+
if (!raw) return false;
|
|
2542
|
+
const normalizedPrompt = compactPromptText(promptSnippet);
|
|
2543
|
+
if (!normalizedPrompt) return true;
|
|
2544
|
+
const normalizedBuffer = compactPromptText(raw);
|
|
2545
|
+
if (!normalizedBuffer) return false;
|
|
2546
|
+
if (normalizedBuffer === normalizedPrompt) return false;
|
|
2547
|
+
if (normalizedBuffer.startsWith(normalizedPrompt)) {
|
|
2548
|
+
const remainder = normalizedBuffer.slice(normalizedPrompt.length).replace(/[─═\-]+/g, "").replace(/⏵⏵accepteditson\([^)]*\)/gi, "").replace(/accepteditson\([^)]*\)/gi, "").replace(/(?:◐|◑|◒|◓|◔|◕|◉|●|·)?(?:x?high|medium|low|max)·?\/effort/gi, "").replace(/updateavailable!run:[a-z0-9:._\-/]+/gi, "").replace(/esctointerrupt/gi, "").replace(/❯/g, "").replace(/^[\s\-–—:;,.!/?]+/, "").trim();
|
|
2549
|
+
return remainder.length > 0;
|
|
2550
|
+
}
|
|
2551
|
+
return true;
|
|
2552
|
+
}
|
|
2501
2553
|
evaluateSettled() {
|
|
2502
2554
|
const now = Date.now();
|
|
2503
2555
|
if (this.submitPendingUntil > now || this.responseSettleIgnoreUntil > now) {
|
|
@@ -2530,7 +2582,11 @@ var init_provider_cli_adapter = __esm({
|
|
|
2530
2582
|
scope: this.currentTurnScope,
|
|
2531
2583
|
lastOutputAt: this.lastOutputAt
|
|
2532
2584
|
}) : [];
|
|
2585
|
+
if (this.maybeCommitVisibleIdleTranscript(parsedTranscript)) {
|
|
2586
|
+
return;
|
|
2587
|
+
}
|
|
2533
2588
|
const lastParsedAssistant = [...parsedMessages].reverse().find((message) => message.role === "assistant");
|
|
2589
|
+
const normalizedPromptSnippet = normalizePromptText(this.submitRetryPromptSnippet || this.currentTurnScope?.prompt || "");
|
|
2534
2590
|
this.recordTrace("settled", {
|
|
2535
2591
|
tail: summarizeCliTraceText(tail, 500),
|
|
2536
2592
|
screenText: summarizeCliTraceText(screenText, 1200),
|
|
@@ -2548,6 +2604,24 @@ var init_provider_cli_adapter = __esm({
|
|
|
2548
2604
|
scope: this.currentTurnScope
|
|
2549
2605
|
})
|
|
2550
2606
|
});
|
|
2607
|
+
if (this.currentTurnScope && !lastParsedAssistant && !this.submitRetryUsed && this.ptyProcess && this.currentStatus !== "waiting_approval" && promptLikelyVisible(screenText, normalizedPromptSnippet) && !this.hasMeaningfulResponseBuffer(normalizedPromptSnippet)) {
|
|
2608
|
+
this.submitRetryUsed = true;
|
|
2609
|
+
this.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
|
|
2610
|
+
LOG.info("CLI", `[${this.cliType}] Retrying submit key from settled parser (no assistant yet)`);
|
|
2611
|
+
this.recordTrace("submit_write", {
|
|
2612
|
+
mode: "settled_retry",
|
|
2613
|
+
sendKey: this.sendKey,
|
|
2614
|
+
screenText: summarizeCliTraceText(screenText, 500)
|
|
2615
|
+
});
|
|
2616
|
+
this.ptyProcess.write(this.sendKey);
|
|
2617
|
+
if (this.settleTimer) clearTimeout(this.settleTimer);
|
|
2618
|
+
this.settleTimer = setTimeout(() => {
|
|
2619
|
+
this.settleTimer = null;
|
|
2620
|
+
this.settledBuffer = this.recentOutputBuffer;
|
|
2621
|
+
this.evaluateSettled();
|
|
2622
|
+
}, this.timeouts.outputSettle + 150);
|
|
2623
|
+
return;
|
|
2624
|
+
}
|
|
2551
2625
|
if (this.currentTurnScope && !lastParsedAssistant) {
|
|
2552
2626
|
LOG.info(
|
|
2553
2627
|
"CLI",
|
|
@@ -2590,7 +2664,15 @@ var init_provider_cli_adapter = __esm({
|
|
|
2590
2664
|
}
|
|
2591
2665
|
const recentInteractiveActivity = this.hasRecentInteractiveActivity(now);
|
|
2592
2666
|
const statusActivityHoldMs = this.getStatusActivityHoldMs();
|
|
2593
|
-
const
|
|
2667
|
+
const visibleIdlePrompt = this.looksLikeVisibleIdlePrompt(screenText);
|
|
2668
|
+
const visibleAssistantCandidate = this.looksLikeVisibleAssistantCandidate(screenText);
|
|
2669
|
+
if (this.currentTurnScope && this.cliType === "claude-cli") {
|
|
2670
|
+
LOG.info(
|
|
2671
|
+
"CLI",
|
|
2672
|
+
`[${this.cliType}] settled diagnostics prompt=${JSON.stringify(this.currentTurnScope.prompt).slice(0, 140)} scriptStatus=${String(scriptStatus || "")} parsedStatus=${String(parsedTranscript?.status || "")} parsedMsgCount=${parsedMessages.length} lastParsedAssistant=${JSON.stringify(summarizeCliTraceText(lastParsedAssistant?.content || "", 120)).slice(0, 160)} visibleIdlePrompt=${String(visibleIdlePrompt)} visibleAssistantCandidate=${String(visibleAssistantCandidate)} responseBuffer=${JSON.stringify(summarizeCliTraceText(this.responseBuffer, 160)).slice(0, 220)} screen=${JSON.stringify(summarizeCliTraceText(screenText, 160)).slice(0, 220)}`
|
|
2673
|
+
);
|
|
2674
|
+
}
|
|
2675
|
+
const shouldHoldGenerating = scriptStatus === "idle" && this.isWaitingForResponse && !modal && recentInteractiveActivity && !(visibleIdlePrompt && visibleAssistantCandidate);
|
|
2594
2676
|
if (shouldHoldGenerating) {
|
|
2595
2677
|
this.clearIdleFinishCandidate("hold_generating_recent_activity");
|
|
2596
2678
|
this.setStatus("generating", "recent_activity_hold");
|
|
@@ -2621,8 +2703,8 @@ var init_provider_cli_adapter = __esm({
|
|
|
2621
2703
|
if (scriptStatus === "waiting_approval") {
|
|
2622
2704
|
this.clearIdleFinishCandidate("waiting_approval");
|
|
2623
2705
|
const inCooldown = this.lastApprovalResolvedAt && Date.now() - this.lastApprovalResolvedAt < this.timeouts.approvalCooldown;
|
|
2624
|
-
const
|
|
2625
|
-
if ((inCooldown ||
|
|
2706
|
+
const visibleIdlePrompt2 = this.looksLikeVisibleIdlePrompt(screenText);
|
|
2707
|
+
if ((inCooldown || visibleIdlePrompt2) && !modal) {
|
|
2626
2708
|
if (this.approvalExitTimeout) {
|
|
2627
2709
|
clearTimeout(this.approvalExitTimeout);
|
|
2628
2710
|
this.approvalExitTimeout = null;
|
|
@@ -2694,7 +2776,7 @@ var init_provider_cli_adapter = __esm({
|
|
|
2694
2776
|
this.lastApprovalResolvedAt = Date.now();
|
|
2695
2777
|
}
|
|
2696
2778
|
if (this.isWaitingForResponse) {
|
|
2697
|
-
const
|
|
2779
|
+
const visibleIdlePrompt2 = this.looksLikeVisibleIdlePrompt(screenText);
|
|
2698
2780
|
const quietForMs = this.lastNonEmptyOutputAt ? now - this.lastNonEmptyOutputAt : Number.MAX_SAFE_INTEGER;
|
|
2699
2781
|
const screenStableMs = this.lastScreenChangeAt ? now - this.lastScreenChangeAt : 0;
|
|
2700
2782
|
const hasAssistantTurn = !!lastParsedAssistant;
|
|
@@ -2702,12 +2784,12 @@ var init_provider_cli_adapter = __esm({
|
|
|
2702
2784
|
const idleFinishConfirmMs = this.getIdleFinishConfirmMs();
|
|
2703
2785
|
const idleQuietThresholdMs = Math.max(idleFinishConfirmMs, this.timeouts.outputSettle);
|
|
2704
2786
|
const idleStableThresholdMs = idleFinishConfirmMs;
|
|
2705
|
-
const idleReady =
|
|
2787
|
+
const idleReady = visibleIdlePrompt2 && !modal && hasAssistantTurn && quietForMs >= idleQuietThresholdMs && screenStableMs >= idleStableThresholdMs;
|
|
2706
2788
|
const candidate = this.idleFinishCandidate;
|
|
2707
2789
|
const candidateQuiet = !!candidate && candidate.responseEpoch === this.responseEpoch && candidate.lastOutputAt === this.lastOutputAt && candidate.lastScreenChangeAt === this.lastScreenChangeAt && assistantLength >= candidate.assistantLength && now - candidate.armedAt >= idleFinishConfirmMs;
|
|
2708
2790
|
const canFinishImmediately = idleReady && candidateQuiet;
|
|
2709
2791
|
this.recordTrace("idle_decision", {
|
|
2710
|
-
visibleIdlePrompt,
|
|
2792
|
+
visibleIdlePrompt: visibleIdlePrompt2,
|
|
2711
2793
|
quietForMs,
|
|
2712
2794
|
screenStableMs,
|
|
2713
2795
|
hasAssistantTurn,
|
|
@@ -2827,6 +2909,70 @@ var init_provider_cli_adapter = __esm({
|
|
|
2827
2909
|
this.setStatus("idle", "response_finished");
|
|
2828
2910
|
this.onStatusChange?.();
|
|
2829
2911
|
}
|
|
2912
|
+
maybeCommitVisibleIdleTranscript(parsed, options) {
|
|
2913
|
+
const allowImmediateScriptIdleCommit = this.provider.allowInputDuringGeneration === true;
|
|
2914
|
+
if (!allowImmediateScriptIdleCommit) return false;
|
|
2915
|
+
if (!parsed || !Array.isArray(parsed.messages) || parsed.status !== "idle" || !this.isWaitingForResponse || !this.currentTurnScope || this.activeModal || parsed.activeModal) {
|
|
2916
|
+
return false;
|
|
2917
|
+
}
|
|
2918
|
+
if (options?.requireVisibleAssistantCandidate) {
|
|
2919
|
+
const candidateText = options.screenText || this.terminalScreen.getText() || "";
|
|
2920
|
+
if (!this.looksLikeVisibleAssistantCandidate(candidateText)) {
|
|
2921
|
+
return false;
|
|
2922
|
+
}
|
|
2923
|
+
}
|
|
2924
|
+
const hydratedForIdleCommit = normalizeCliParsedMessages(parsed.messages, {
|
|
2925
|
+
committedMessages: this.committedMessages,
|
|
2926
|
+
scope: this.currentTurnScope,
|
|
2927
|
+
lastOutputAt: this.lastOutputAt
|
|
2928
|
+
});
|
|
2929
|
+
const visibleAssistant = [...hydratedForIdleCommit].reverse().find((message) => message.role === "assistant" && message.content.trim());
|
|
2930
|
+
if (!visibleAssistant) return false;
|
|
2931
|
+
this.committedMessages = hydratedForIdleCommit;
|
|
2932
|
+
const promptForTrim = this.currentTurnScope?.prompt || getLastUserPromptText(this.committedMessages);
|
|
2933
|
+
if (promptForTrim) {
|
|
2934
|
+
const lastAssistantForTrim = [...this.committedMessages].reverse().find((message) => message.role === "assistant");
|
|
2935
|
+
if (lastAssistantForTrim) {
|
|
2936
|
+
lastAssistantForTrim.content = trimPromptEchoPrefix(lastAssistantForTrim.content, promptForTrim);
|
|
2937
|
+
}
|
|
2938
|
+
}
|
|
2939
|
+
if (this.responseTimeout) {
|
|
2940
|
+
clearTimeout(this.responseTimeout);
|
|
2941
|
+
this.responseTimeout = null;
|
|
2942
|
+
}
|
|
2943
|
+
if (this.idleTimeout) {
|
|
2944
|
+
clearTimeout(this.idleTimeout);
|
|
2945
|
+
this.idleTimeout = null;
|
|
2946
|
+
}
|
|
2947
|
+
if (this.approvalExitTimeout) {
|
|
2948
|
+
clearTimeout(this.approvalExitTimeout);
|
|
2949
|
+
this.approvalExitTimeout = null;
|
|
2950
|
+
}
|
|
2951
|
+
if (this.submitRetryTimer) {
|
|
2952
|
+
clearTimeout(this.submitRetryTimer);
|
|
2953
|
+
this.submitRetryTimer = null;
|
|
2954
|
+
}
|
|
2955
|
+
if (this.finishRetryTimer) {
|
|
2956
|
+
clearTimeout(this.finishRetryTimer);
|
|
2957
|
+
this.finishRetryTimer = null;
|
|
2958
|
+
}
|
|
2959
|
+
this.syncMessageViews();
|
|
2960
|
+
this.responseBuffer = "";
|
|
2961
|
+
this.isWaitingForResponse = false;
|
|
2962
|
+
this.responseSettleIgnoreUntil = 0;
|
|
2963
|
+
this.submitRetryUsed = false;
|
|
2964
|
+
this.submitRetryPromptSnippet = "";
|
|
2965
|
+
this.finishRetryCount = 0;
|
|
2966
|
+
this.currentTurnScope = null;
|
|
2967
|
+
this.activeModal = null;
|
|
2968
|
+
this.setStatus("idle", "script_idle_commit");
|
|
2969
|
+
this.onStatusChange?.();
|
|
2970
|
+
this.recordTrace("script_idle_commit", {
|
|
2971
|
+
messageCount: this.committedMessages.length,
|
|
2972
|
+
lastAssistant: summarizeCliTraceText(visibleAssistant.content, 320)
|
|
2973
|
+
});
|
|
2974
|
+
return true;
|
|
2975
|
+
}
|
|
2830
2976
|
commitCurrentTranscript() {
|
|
2831
2977
|
const parsed = this.parseCurrentTranscript(
|
|
2832
2978
|
this.committedMessages,
|
|
@@ -2848,6 +2994,12 @@ var init_provider_cli_adapter = __esm({
|
|
|
2848
2994
|
}
|
|
2849
2995
|
this.syncMessageViews();
|
|
2850
2996
|
const lastAssistant = [...this.committedMessages].reverse().find((message) => message.role === "assistant");
|
|
2997
|
+
if (this.currentTurnScope) {
|
|
2998
|
+
LOG.info(
|
|
2999
|
+
"CLI",
|
|
3000
|
+
`[${this.cliType}] commitCurrentTranscript committedMessages=${this.committedMessages.length} finalLastAssistant=${JSON.stringify(summarizeCliTraceText(lastAssistant?.content || "", 220)).slice(0, 260)}`
|
|
3001
|
+
);
|
|
3002
|
+
}
|
|
2851
3003
|
this.recordTrace("commit_transcript", {
|
|
2852
3004
|
parsedStatus: parsed.status || null,
|
|
2853
3005
|
messageCount: this.committedMessages.length,
|
|
@@ -2867,11 +3019,18 @@ var init_provider_cli_adapter = __esm({
|
|
|
2867
3019
|
`[${this.cliType}] Commit without assistant turn: prompt=${JSON.stringify(this.currentTurnScope.prompt).slice(0, 140)} responseBuffer=${JSON.stringify(summarizeCliTraceText(this.responseBuffer, 220)).slice(0, 260)} providerDir=${this.providerResolutionMeta.providerDir || "-"} scriptDir=${this.providerResolutionMeta.scriptDir || "-"} scriptsPath=${this.providerResolutionMeta.scriptsPath || "-"}`
|
|
2868
3020
|
);
|
|
2869
3021
|
}
|
|
3022
|
+
const hasAssistant = !!lastAssistant;
|
|
2870
3023
|
return {
|
|
2871
|
-
hasAssistant
|
|
3024
|
+
hasAssistant,
|
|
2872
3025
|
assistantContent: lastAssistant?.content || ""
|
|
2873
3026
|
};
|
|
2874
3027
|
}
|
|
3028
|
+
if (this.currentTurnScope) {
|
|
3029
|
+
LOG.info(
|
|
3030
|
+
"CLI",
|
|
3031
|
+
`[${this.cliType}] commitCurrentTranscript parsed.messages=none responseBufferLen=${this.responseBuffer.length} accumulatedBufferLen=${this.accumulatedBuffer.length} parsedStatus=${parsed?.status || "-"} providerDir=${this.providerResolutionMeta.providerDir || "-"} scriptDir=${this.providerResolutionMeta.scriptDir || "-"}`
|
|
3032
|
+
);
|
|
3033
|
+
}
|
|
2875
3034
|
return {
|
|
2876
3035
|
hasAssistant: false,
|
|
2877
3036
|
assistantContent: ""
|
|
@@ -2957,19 +3116,25 @@ var init_provider_cli_adapter = __esm({
|
|
|
2957
3116
|
this.currentTurnScope,
|
|
2958
3117
|
screenText
|
|
2959
3118
|
);
|
|
2960
|
-
|
|
3119
|
+
if (this.maybeCommitVisibleIdleTranscript(parsed)) {
|
|
3120
|
+
return this.getScriptParsedStatus();
|
|
3121
|
+
}
|
|
3122
|
+
const shouldPreferCommittedMessages = !this.currentTurnScope && !this.activeModal && this.currentStatus === "idle";
|
|
2961
3123
|
let result;
|
|
2962
3124
|
if (parsed && Array.isArray(parsed.messages)) {
|
|
2963
|
-
const
|
|
2964
|
-
...message,
|
|
2965
|
-
id: message.id || `msg_${index}`,
|
|
2966
|
-
index: typeof message.index === "number" ? message.index : index,
|
|
2967
|
-
receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp
|
|
2968
|
-
})) : hydrateCliParsedMessages(parsed.messages, {
|
|
3125
|
+
const parsedHydratedMessages = hydrateCliParsedMessages(parsed.messages, {
|
|
2969
3126
|
committedMessages: this.committedMessages,
|
|
2970
3127
|
scope: this.currentTurnScope,
|
|
2971
3128
|
lastOutputAt: this.lastOutputAt
|
|
2972
3129
|
});
|
|
3130
|
+
const committedHydratedMessages = this.committedMessages.map((message, index) => buildChatMessage({
|
|
3131
|
+
...message,
|
|
3132
|
+
id: message.id || `msg_${index}`,
|
|
3133
|
+
index: typeof message.index === "number" ? message.index : index,
|
|
3134
|
+
receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp
|
|
3135
|
+
}));
|
|
3136
|
+
const shouldPreferCommittedHistoryReplay = !this.currentTurnScope && !this.activeModal && committedHydratedMessages.length > parsedHydratedMessages.length;
|
|
3137
|
+
const hydratedMessages = shouldPreferCommittedMessages || shouldPreferCommittedHistoryReplay ? committedHydratedMessages : parsedHydratedMessages;
|
|
2973
3138
|
result = {
|
|
2974
3139
|
id: parsed.id || "cli_session",
|
|
2975
3140
|
status: parsed.status || this.currentStatus,
|
|
@@ -2993,6 +3158,23 @@ var init_provider_cli_adapter = __esm({
|
|
|
2993
3158
|
activeModal: this.activeModal
|
|
2994
3159
|
};
|
|
2995
3160
|
}
|
|
3161
|
+
const hasVisibleAssistantMessage = Array.isArray(result?.messages) && result.messages.some((message) => message?.role === "assistant" && typeof message?.content === "string" && message.content.trim());
|
|
3162
|
+
const shouldClampStaleGeneratingToIdle = result?.status === "generating" && this.currentStatus === "idle" && !this.currentTurnScope && !result?.activeModal && hasVisibleAssistantMessage;
|
|
3163
|
+
if (shouldClampStaleGeneratingToIdle) {
|
|
3164
|
+
result = {
|
|
3165
|
+
...result,
|
|
3166
|
+
status: "idle",
|
|
3167
|
+
messages: Array.isArray(result.messages) ? result.messages.map((message) => {
|
|
3168
|
+
if (message?.role !== "assistant" || !message?.meta?.streaming) return message;
|
|
3169
|
+
const nextMeta = { ...message.meta || {} };
|
|
3170
|
+
delete nextMeta.streaming;
|
|
3171
|
+
return {
|
|
3172
|
+
...message,
|
|
3173
|
+
...Object.keys(nextMeta).length > 0 ? { meta: nextMeta } : { meta: void 0 }
|
|
3174
|
+
};
|
|
3175
|
+
}) : result.messages
|
|
3176
|
+
};
|
|
3177
|
+
}
|
|
2996
3178
|
this.parsedStatusCache = {
|
|
2997
3179
|
committedMessagesRef: this.committedMessages,
|
|
2998
3180
|
responseBuffer: this.responseBuffer,
|
|
@@ -3125,9 +3307,27 @@ ${data.message || ""}`.trim();
|
|
|
3125
3307
|
}
|
|
3126
3308
|
}
|
|
3127
3309
|
if (!this.ready) throw new Error(`${this.cliName} not ready (status: ${this.currentStatus})`);
|
|
3128
|
-
|
|
3310
|
+
const parsedStatusBeforeSend = !allowInputDuringGeneration ? (() => {
|
|
3311
|
+
try {
|
|
3312
|
+
return this.getScriptParsedStatus?.() || null;
|
|
3313
|
+
} catch {
|
|
3314
|
+
return null;
|
|
3315
|
+
}
|
|
3316
|
+
})() : null;
|
|
3317
|
+
const parsedSessionStatus = typeof parsedStatusBeforeSend?.status === "string" ? String(parsedStatusBeforeSend.status) : "";
|
|
3318
|
+
const parsedMessagesBeforeSend = Array.isArray(parsedStatusBeforeSend?.messages) ? parsedStatusBeforeSend.messages.filter((message) => message && (message.role === "user" || message.role === "assistant")) : [];
|
|
3319
|
+
const shouldCommitParsedIdleBeforeSend = !allowInputDuringGeneration && parsedSessionStatus === "idle" && parsedMessagesBeforeSend.length > this.committedMessages.length && parsedMessagesBeforeSend.some((message) => message?.role === "assistant" && typeof message?.content === "string" && message.content.trim());
|
|
3320
|
+
if (shouldCommitParsedIdleBeforeSend) {
|
|
3321
|
+
this.commitCurrentTranscript();
|
|
3322
|
+
}
|
|
3323
|
+
if (!allowInputDuringGeneration && (parsedSessionStatus === "generating" || parsedSessionStatus === "long_generating")) {
|
|
3129
3324
|
throw new Error(`${this.cliName} is still processing the previous prompt`);
|
|
3130
3325
|
}
|
|
3326
|
+
if (this.isWaitingForResponse && !allowInputDuringGeneration) {
|
|
3327
|
+
if (!this.clearStaleIdleResponseGuard("send_message_guard")) {
|
|
3328
|
+
throw new Error(`${this.cliName} is still processing the previous prompt`);
|
|
3329
|
+
}
|
|
3330
|
+
}
|
|
3131
3331
|
const blockingModal = this.activeModal || this.getStartupConfirmationModal(this.terminalScreen.getText() || "");
|
|
3132
3332
|
if (blockingModal || this.currentStatus === "waiting_approval") {
|
|
3133
3333
|
throw new Error(`${this.cliName} is awaiting confirmation before it can accept a prompt`);
|
|
@@ -3207,7 +3407,7 @@ ${data.message || ""}`.trim();
|
|
|
3207
3407
|
this.submitRetryTimer = null;
|
|
3208
3408
|
if (!this.ptyProcess || !this.isWaitingForResponse || this.submitRetryUsed) return;
|
|
3209
3409
|
if (this.currentStatus === "waiting_approval") return;
|
|
3210
|
-
if (
|
|
3410
|
+
if (this.hasMeaningfulResponseBuffer(normalizedPromptSnippet)) return;
|
|
3211
3411
|
const screenText2 = this.terminalScreen.getText();
|
|
3212
3412
|
if (!promptLikelyVisible(screenText2, normalizedPromptSnippet)) return;
|
|
3213
3413
|
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(screenText2)) return;
|
|
@@ -3244,7 +3444,7 @@ ${data.message || ""}`.trim();
|
|
|
3244
3444
|
this.submitRetryTimer = null;
|
|
3245
3445
|
if (!this.ptyProcess || !this.isWaitingForResponse || this.submitRetryUsed) return;
|
|
3246
3446
|
if (this.currentStatus === "waiting_approval") return;
|
|
3247
|
-
if (
|
|
3447
|
+
if (this.hasMeaningfulResponseBuffer(normalizedPromptSnippet)) return;
|
|
3248
3448
|
const screenText = this.terminalScreen.getText();
|
|
3249
3449
|
if (!promptLikelyVisible(screenText, normalizedPromptSnippet)) return;
|
|
3250
3450
|
LOG.info("CLI", `[${this.cliType}] Retrying submit key for stuck prompt (attempt 1)`);
|
|
@@ -9609,6 +9809,7 @@ function normalizeReadChatCommandStatus(status, activeModal) {
|
|
|
9609
9809
|
}
|
|
9610
9810
|
function buildReadChatCommandResult(payload, args) {
|
|
9611
9811
|
let validatedPayload;
|
|
9812
|
+
const debugReadChat = payload?.debugReadChat && typeof payload.debugReadChat === "object" ? payload.debugReadChat : void 0;
|
|
9612
9813
|
try {
|
|
9613
9814
|
validatedPayload = validateReadChatResultPayload({
|
|
9614
9815
|
...payload,
|
|
@@ -9629,7 +9830,8 @@ function buildReadChatCommandResult(payload, args) {
|
|
|
9629
9830
|
syncMode: "full",
|
|
9630
9831
|
replaceFrom: 0,
|
|
9631
9832
|
totalMessages: messages.length,
|
|
9632
|
-
lastMessageSignature
|
|
9833
|
+
lastMessageSignature,
|
|
9834
|
+
...debugReadChat ? { debugReadChat } : {}
|
|
9633
9835
|
};
|
|
9634
9836
|
}
|
|
9635
9837
|
const sync = computeReadChatSync(messages, cursor);
|
|
@@ -9640,7 +9842,8 @@ function buildReadChatCommandResult(payload, args) {
|
|
|
9640
9842
|
syncMode: sync.syncMode,
|
|
9641
9843
|
replaceFrom: sync.replaceFrom,
|
|
9642
9844
|
totalMessages: sync.totalMessages,
|
|
9643
|
-
lastMessageSignature: sync.lastMessageSignature
|
|
9845
|
+
lastMessageSignature: sync.lastMessageSignature,
|
|
9846
|
+
...debugReadChat ? { debugReadChat } : {}
|
|
9644
9847
|
};
|
|
9645
9848
|
}
|
|
9646
9849
|
function didProviderConfirmSend(result) {
|
|
@@ -9731,14 +9934,33 @@ async function handleReadChat(h, args) {
|
|
|
9731
9934
|
}
|
|
9732
9935
|
}
|
|
9733
9936
|
const parsedRecord = parsedStatus && typeof parsedStatus === "object" ? parsedStatus : null;
|
|
9734
|
-
const
|
|
9937
|
+
const adapterStatus = adapter.getStatus();
|
|
9938
|
+
const shouldPreferAdapterMessages = Array.isArray(adapterStatus.messages) && adapterStatus.messages.length > 0 && Array.isArray(parsedRecord?.messages) && adapterStatus.messages.length > parsedRecord.messages.length;
|
|
9939
|
+
const status = parsedRecord ? {
|
|
9940
|
+
...parsedRecord,
|
|
9941
|
+
messages: shouldPreferAdapterMessages ? adapterStatus.messages : parsedRecord.messages,
|
|
9942
|
+
status: adapterStatus.status !== "idle" ? adapterStatus.status : parsedRecord.status || adapterStatus.status,
|
|
9943
|
+
activeModal: parsedRecord.activeModal || adapterStatus.activeModal
|
|
9944
|
+
} : adapterStatus;
|
|
9735
9945
|
const title = typeof parsedRecord?.title === "string" ? parsedRecord.title : void 0;
|
|
9736
9946
|
const providerSessionId = typeof parsedRecord?.providerSessionId === "string" ? parsedRecord.providerSessionId : void 0;
|
|
9737
9947
|
if (status) {
|
|
9948
|
+
LOG.info("Command", `[read_chat] cli-like resolved provider=${adapter.cliType} target=${String(args?.targetSessionId || "")} adapterStatus=${String(adapterStatus.status || "")} parsedStatus=${String(parsedRecord?.status || "")} shouldPreferAdapterMessages=${String(shouldPreferAdapterMessages)} adapterMsgCount=${Array.isArray(adapterStatus.messages) ? adapterStatus.messages.length : 0} parsedMsgCount=${Array.isArray(parsedRecord?.messages) ? parsedRecord.messages.length : 0} returnedMsgCount=${Array.isArray(status.messages) ? status.messages.length : 0}`);
|
|
9738
9949
|
return buildReadChatCommandResult({
|
|
9739
9950
|
messages: status.messages || [],
|
|
9740
9951
|
status: status.status,
|
|
9741
9952
|
activeModal: status.activeModal,
|
|
9953
|
+
debugReadChat: {
|
|
9954
|
+
provider: adapter.cliType,
|
|
9955
|
+
targetSessionId: String(args?.targetSessionId || ""),
|
|
9956
|
+
adapterStatus: String(adapterStatus.status || ""),
|
|
9957
|
+
parsedStatus: String(parsedRecord?.status || ""),
|
|
9958
|
+
returnedStatus: String(status.status || ""),
|
|
9959
|
+
shouldPreferAdapterMessages,
|
|
9960
|
+
adapterMsgCount: Array.isArray(adapterStatus.messages) ? adapterStatus.messages.length : 0,
|
|
9961
|
+
parsedMsgCount: Array.isArray(parsedRecord?.messages) ? parsedRecord.messages.length : 0,
|
|
9962
|
+
returnedMsgCount: Array.isArray(status.messages) ? status.messages.length : 0
|
|
9963
|
+
},
|
|
9742
9964
|
...title ? { title } : {},
|
|
9743
9965
|
...providerSessionId ? { providerSessionId } : {}
|
|
9744
9966
|
}, args);
|
|
@@ -11984,6 +12206,30 @@ import { createRequire } from "module";
|
|
|
11984
12206
|
init_provider_cli_adapter();
|
|
11985
12207
|
init_logger();
|
|
11986
12208
|
init_chat_message_normalization();
|
|
12209
|
+
function normalizePersistableCliHistoryContent(content) {
|
|
12210
|
+
return flattenContent(content).replace(/\s+/g, " ").trim();
|
|
12211
|
+
}
|
|
12212
|
+
function buildPersistableCliHistorySignature(message) {
|
|
12213
|
+
return [
|
|
12214
|
+
String(message.role || ""),
|
|
12215
|
+
String(message.kind || ""),
|
|
12216
|
+
String(message.senderName || ""),
|
|
12217
|
+
normalizePersistableCliHistoryContent(message.content)
|
|
12218
|
+
].join("|");
|
|
12219
|
+
}
|
|
12220
|
+
function buildIncrementalHistoryAppendMessages(previousMessages, currentMessages) {
|
|
12221
|
+
if (!Array.isArray(currentMessages) || currentMessages.length === 0) return [];
|
|
12222
|
+
if (!Array.isArray(previousMessages) || previousMessages.length === 0) return currentMessages;
|
|
12223
|
+
const previousSignatures = previousMessages.map(buildPersistableCliHistorySignature);
|
|
12224
|
+
const currentSignatures = currentMessages.map(buildPersistableCliHistorySignature);
|
|
12225
|
+
let sharedPrefixLength = 0;
|
|
12226
|
+
while (sharedPrefixLength < previousSignatures.length && sharedPrefixLength < currentSignatures.length && previousSignatures[sharedPrefixLength] === currentSignatures[sharedPrefixLength]) {
|
|
12227
|
+
sharedPrefixLength += 1;
|
|
12228
|
+
}
|
|
12229
|
+
if (sharedPrefixLength === currentSignatures.length) return [];
|
|
12230
|
+
if (sharedPrefixLength === previousSignatures.length) return currentMessages.slice(sharedPrefixLength);
|
|
12231
|
+
return currentMessages;
|
|
12232
|
+
}
|
|
11987
12233
|
var CachedDatabaseSync = null;
|
|
11988
12234
|
function getDatabaseSync() {
|
|
11989
12235
|
if (CachedDatabaseSync) return CachedDatabaseSync;
|
|
@@ -12061,6 +12307,7 @@ var CliProviderInstance = class {
|
|
|
12061
12307
|
appliedEffectKeys = /* @__PURE__ */ new Set();
|
|
12062
12308
|
historyWriter;
|
|
12063
12309
|
runtimeMessages = [];
|
|
12310
|
+
lastPersistedHistoryMessages = [];
|
|
12064
12311
|
instanceId;
|
|
12065
12312
|
suppressIdleHistoryReplay = false;
|
|
12066
12313
|
errorMessage = void 0;
|
|
@@ -12101,6 +12348,13 @@ var CliProviderInstance = class {
|
|
|
12101
12348
|
this.providerSessionId,
|
|
12102
12349
|
this.instanceId
|
|
12103
12350
|
);
|
|
12351
|
+
this.lastPersistedHistoryMessages = restoredHistory.messages.map((message) => ({
|
|
12352
|
+
role: message.role,
|
|
12353
|
+
content: message.content,
|
|
12354
|
+
kind: message.kind,
|
|
12355
|
+
senderName: message.senderName,
|
|
12356
|
+
receivedAt: message.receivedAt
|
|
12357
|
+
}));
|
|
12104
12358
|
this.suppressIdleHistoryReplay = restoredHistory.messages.length > 0;
|
|
12105
12359
|
if (restoredHistory.messages.length > 0) {
|
|
12106
12360
|
this.adapter.seedCommittedMessages(
|
|
@@ -12232,15 +12486,24 @@ var CliProviderInstance = class {
|
|
|
12232
12486
|
messagesToSave = messagesToSave.slice(0, lastIdx);
|
|
12233
12487
|
}
|
|
12234
12488
|
}
|
|
12235
|
-
|
|
12489
|
+
const normalizedMessagesToSave = messagesToSave.map((message) => ({
|
|
12490
|
+
role: message.role,
|
|
12491
|
+
content: flattenContent(message.content),
|
|
12492
|
+
kind: typeof message.kind === "string" ? message.kind : void 0,
|
|
12493
|
+
senderName: typeof message.senderName === "string" ? message.senderName : void 0,
|
|
12494
|
+
receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp
|
|
12495
|
+
}));
|
|
12496
|
+
if (!shouldSkipReplayPersist && normalizedMessagesToSave.length > 0) {
|
|
12497
|
+
const incrementalMessages = buildIncrementalHistoryAppendMessages(this.lastPersistedHistoryMessages, normalizedMessagesToSave);
|
|
12236
12498
|
this.historyWriter.appendNewMessages(
|
|
12237
12499
|
this.type,
|
|
12238
|
-
|
|
12500
|
+
incrementalMessages,
|
|
12239
12501
|
parsedStatus?.title || dirName,
|
|
12240
12502
|
this.instanceId,
|
|
12241
12503
|
this.providerSessionId
|
|
12242
12504
|
);
|
|
12243
12505
|
}
|
|
12506
|
+
this.lastPersistedHistoryMessages = normalizedMessagesToSave;
|
|
12244
12507
|
}
|
|
12245
12508
|
this.applyProviderResponse(parsedStatus, { phase: "immediate" });
|
|
12246
12509
|
const surface = resolveProviderStateSurface({
|
|
@@ -12256,7 +12519,7 @@ var CliProviderInstance = class {
|
|
|
12256
12519
|
activeChat: {
|
|
12257
12520
|
id: `${this.type}_${this.workingDir}`,
|
|
12258
12521
|
title: parsedStatus?.title || dirName,
|
|
12259
|
-
status: parseErrorMessage ? "error" : autoApproveActive && parsedStatus?.status === "waiting_approval" ? "generating" : parsedStatus?.status || visibleStatus,
|
|
12522
|
+
status: parseErrorMessage ? "error" : autoApproveActive && parsedStatus?.status === "waiting_approval" ? "generating" : adapterStatus.status !== "idle" ? visibleStatus : parsedStatus?.status || visibleStatus,
|
|
12260
12523
|
messages: mergedMessages,
|
|
12261
12524
|
activeModal: autoApproveActive ? null : parsedStatus?.activeModal ?? adapterStatus.activeModal,
|
|
12262
12525
|
inputContent: ""
|
|
@@ -12488,6 +12751,7 @@ var CliProviderInstance = class {
|
|
|
12488
12751
|
}
|
|
12489
12752
|
if (data.sessionEvent === "new_session") {
|
|
12490
12753
|
this.runtimeMessages = [];
|
|
12754
|
+
this.lastPersistedHistoryMessages = [];
|
|
12491
12755
|
this.suppressIdleHistoryReplay = false;
|
|
12492
12756
|
this.adapter.clearHistory();
|
|
12493
12757
|
}
|
|
@@ -24702,6 +24966,13 @@ init_logger();
|
|
|
24702
24966
|
import {
|
|
24703
24967
|
SessionHostClient
|
|
24704
24968
|
} from "@adhdev/session-host-core";
|
|
24969
|
+
function shouldResumeAttachedSession(record) {
|
|
24970
|
+
if (!record) return false;
|
|
24971
|
+
if (record.lifecycle === "interrupted") return true;
|
|
24972
|
+
if (record.lifecycle !== "stopped") return false;
|
|
24973
|
+
if (record.meta?.restoredFromStorage === true) return true;
|
|
24974
|
+
return typeof record.meta?.runtimeRecoveryState === "string" && String(record.meta.runtimeRecoveryState).trim().length > 0;
|
|
24975
|
+
}
|
|
24705
24976
|
var SessionHostRuntimeTransport = class {
|
|
24706
24977
|
constructor(options) {
|
|
24707
24978
|
this.options = options;
|
|
@@ -24875,7 +25146,7 @@ var SessionHostRuntimeTransport = class {
|
|
|
24875
25146
|
payload: {}
|
|
24876
25147
|
});
|
|
24877
25148
|
const existingRecord = existingRecords.success && existingRecords.result ? existingRecords.result.find((item) => item.sessionId === this.options.runtimeId) || null : null;
|
|
24878
|
-
if (existingRecord
|
|
25149
|
+
if (shouldResumeAttachedSession(existingRecord)) {
|
|
24879
25150
|
const resumeResponse = await this.client.request({
|
|
24880
25151
|
type: "resume_session",
|
|
24881
25152
|
payload: {
|
|
@@ -25174,6 +25445,8 @@ async function listHostedCliRuntimes(endpoint) {
|
|
|
25174
25445
|
// src/session-host/startup-restore-policy.js
|
|
25175
25446
|
function shouldAutoRestoreHostedSessionsOnStartup(env = process.env) {
|
|
25176
25447
|
const raw = typeof env.ADHDEV_RESTORE_HOSTED_SESSIONS_ON_STARTUP === "string" ? env.ADHDEV_RESTORE_HOSTED_SESSIONS_ON_STARTUP.trim().toLowerCase() : "";
|
|
25448
|
+
if (!raw) return true;
|
|
25449
|
+
if (raw === "0" || raw === "false" || raw === "no") return false;
|
|
25177
25450
|
return raw === "1" || raw === "true" || raw === "yes";
|
|
25178
25451
|
}
|
|
25179
25452
|
|