@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
|
@@ -138,8 +138,11 @@ export declare class ProviderCliAdapter implements CliAdapter {
|
|
|
138
138
|
private getStartupConfirmationModal;
|
|
139
139
|
private shouldResolveModalWithEnter;
|
|
140
140
|
private waitForInteractivePrompt;
|
|
141
|
+
private clearStaleIdleResponseGuard;
|
|
142
|
+
private hasMeaningfulResponseBuffer;
|
|
141
143
|
private evaluateSettled;
|
|
142
144
|
private finishResponse;
|
|
145
|
+
private maybeCommitVisibleIdleTranscript;
|
|
143
146
|
private commitCurrentTranscript;
|
|
144
147
|
private runDetectStatus;
|
|
145
148
|
private runParseApproval;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type SessionHostEndpoint, type SessionHostCategory } from '@adhdev/session-host-core';
|
|
1
|
+
import { type SessionHostEndpoint, type SessionHostCategory, type SessionHostRecord } from '@adhdev/session-host-core';
|
|
2
2
|
import type { PtyRuntimeTransport, PtySpawnOptions, PtyTransportFactory } from './pty-transport.js';
|
|
3
3
|
interface SessionHostPtyTransportFactoryOptions {
|
|
4
4
|
endpoint?: SessionHostEndpoint;
|
|
@@ -12,6 +12,7 @@ interface SessionHostPtyTransportFactoryOptions {
|
|
|
12
12
|
meta?: Record<string, unknown>;
|
|
13
13
|
attachExisting?: boolean;
|
|
14
14
|
}
|
|
15
|
+
export declare function shouldResumeAttachedSession(record: SessionHostRecord | null | undefined): boolean;
|
|
15
16
|
export declare class SessionHostPtyTransportFactory implements PtyTransportFactory {
|
|
16
17
|
private readonly options;
|
|
17
18
|
constructor(options: SessionHostPtyTransportFactoryOptions);
|
|
@@ -102,4 +102,5 @@ export declare function listSavedHistorySessions(agentType: string, options?: {
|
|
|
102
102
|
sessions: SavedHistorySessionSummary[];
|
|
103
103
|
hasMore: boolean;
|
|
104
104
|
};
|
|
105
|
+
export declare function rebuildHermesSavedHistoryFromCanonicalSession(historySessionId: string): boolean;
|
|
105
106
|
export {};
|
package/dist/index.js
CHANGED
|
@@ -2501,6 +2501,58 @@ var init_provider_cli_adapter = __esm({
|
|
|
2501
2501
|
`[${this.cliType}] Interactive prompt wait timed out after ${maxWaitMs}ms; proceeding with screen=${JSON.stringify(summarizeCliTraceText(finalScreenText, 240)).slice(0, 280)}`
|
|
2502
2502
|
);
|
|
2503
2503
|
}
|
|
2504
|
+
clearStaleIdleResponseGuard(reason) {
|
|
2505
|
+
const screenText = this.terminalScreen.getText() || "";
|
|
2506
|
+
const visibleIdlePrompt = this.looksLikeVisibleIdlePrompt(screenText);
|
|
2507
|
+
const blockingModal = this.activeModal || this.getStartupConfirmationModal(screenText);
|
|
2508
|
+
if (!this.isWaitingForResponse || this.currentStatus !== "idle" || !visibleIdlePrompt || !!blockingModal) {
|
|
2509
|
+
return false;
|
|
2510
|
+
}
|
|
2511
|
+
if (this.responseTimeout) {
|
|
2512
|
+
clearTimeout(this.responseTimeout);
|
|
2513
|
+
this.responseTimeout = null;
|
|
2514
|
+
}
|
|
2515
|
+
if (this.idleTimeout) {
|
|
2516
|
+
clearTimeout(this.idleTimeout);
|
|
2517
|
+
this.idleTimeout = null;
|
|
2518
|
+
}
|
|
2519
|
+
if (this.approvalExitTimeout) {
|
|
2520
|
+
clearTimeout(this.approvalExitTimeout);
|
|
2521
|
+
this.approvalExitTimeout = null;
|
|
2522
|
+
}
|
|
2523
|
+
if (this.finishRetryTimer) {
|
|
2524
|
+
clearTimeout(this.finishRetryTimer);
|
|
2525
|
+
this.finishRetryTimer = null;
|
|
2526
|
+
}
|
|
2527
|
+
this.clearIdleFinishCandidate(reason);
|
|
2528
|
+
this.responseBuffer = "";
|
|
2529
|
+
this.isWaitingForResponse = false;
|
|
2530
|
+
this.responseSettleIgnoreUntil = 0;
|
|
2531
|
+
this.submitRetryUsed = false;
|
|
2532
|
+
this.submitRetryPromptSnippet = "";
|
|
2533
|
+
this.finishRetryCount = 0;
|
|
2534
|
+
this.currentTurnScope = null;
|
|
2535
|
+
this.activeModal = null;
|
|
2536
|
+
this.recordTrace("stale_idle_response_cleared", {
|
|
2537
|
+
reason,
|
|
2538
|
+
screenText: summarizeCliTraceText(screenText, 240)
|
|
2539
|
+
});
|
|
2540
|
+
return true;
|
|
2541
|
+
}
|
|
2542
|
+
hasMeaningfulResponseBuffer(promptSnippet) {
|
|
2543
|
+
const raw = String(this.responseBuffer || "").trim();
|
|
2544
|
+
if (!raw) return false;
|
|
2545
|
+
const normalizedPrompt = compactPromptText(promptSnippet);
|
|
2546
|
+
if (!normalizedPrompt) return true;
|
|
2547
|
+
const normalizedBuffer = compactPromptText(raw);
|
|
2548
|
+
if (!normalizedBuffer) return false;
|
|
2549
|
+
if (normalizedBuffer === normalizedPrompt) return false;
|
|
2550
|
+
if (normalizedBuffer.startsWith(normalizedPrompt)) {
|
|
2551
|
+
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();
|
|
2552
|
+
return remainder.length > 0;
|
|
2553
|
+
}
|
|
2554
|
+
return true;
|
|
2555
|
+
}
|
|
2504
2556
|
evaluateSettled() {
|
|
2505
2557
|
const now = Date.now();
|
|
2506
2558
|
if (this.submitPendingUntil > now || this.responseSettleIgnoreUntil > now) {
|
|
@@ -2533,7 +2585,11 @@ var init_provider_cli_adapter = __esm({
|
|
|
2533
2585
|
scope: this.currentTurnScope,
|
|
2534
2586
|
lastOutputAt: this.lastOutputAt
|
|
2535
2587
|
}) : [];
|
|
2588
|
+
if (this.maybeCommitVisibleIdleTranscript(parsedTranscript)) {
|
|
2589
|
+
return;
|
|
2590
|
+
}
|
|
2536
2591
|
const lastParsedAssistant = [...parsedMessages].reverse().find((message) => message.role === "assistant");
|
|
2592
|
+
const normalizedPromptSnippet = normalizePromptText(this.submitRetryPromptSnippet || this.currentTurnScope?.prompt || "");
|
|
2537
2593
|
this.recordTrace("settled", {
|
|
2538
2594
|
tail: summarizeCliTraceText(tail, 500),
|
|
2539
2595
|
screenText: summarizeCliTraceText(screenText, 1200),
|
|
@@ -2551,6 +2607,24 @@ var init_provider_cli_adapter = __esm({
|
|
|
2551
2607
|
scope: this.currentTurnScope
|
|
2552
2608
|
})
|
|
2553
2609
|
});
|
|
2610
|
+
if (this.currentTurnScope && !lastParsedAssistant && !this.submitRetryUsed && this.ptyProcess && this.currentStatus !== "waiting_approval" && promptLikelyVisible(screenText, normalizedPromptSnippet) && !this.hasMeaningfulResponseBuffer(normalizedPromptSnippet)) {
|
|
2611
|
+
this.submitRetryUsed = true;
|
|
2612
|
+
this.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
|
|
2613
|
+
LOG.info("CLI", `[${this.cliType}] Retrying submit key from settled parser (no assistant yet)`);
|
|
2614
|
+
this.recordTrace("submit_write", {
|
|
2615
|
+
mode: "settled_retry",
|
|
2616
|
+
sendKey: this.sendKey,
|
|
2617
|
+
screenText: summarizeCliTraceText(screenText, 500)
|
|
2618
|
+
});
|
|
2619
|
+
this.ptyProcess.write(this.sendKey);
|
|
2620
|
+
if (this.settleTimer) clearTimeout(this.settleTimer);
|
|
2621
|
+
this.settleTimer = setTimeout(() => {
|
|
2622
|
+
this.settleTimer = null;
|
|
2623
|
+
this.settledBuffer = this.recentOutputBuffer;
|
|
2624
|
+
this.evaluateSettled();
|
|
2625
|
+
}, this.timeouts.outputSettle + 150);
|
|
2626
|
+
return;
|
|
2627
|
+
}
|
|
2554
2628
|
if (this.currentTurnScope && !lastParsedAssistant) {
|
|
2555
2629
|
LOG.info(
|
|
2556
2630
|
"CLI",
|
|
@@ -2593,7 +2667,15 @@ var init_provider_cli_adapter = __esm({
|
|
|
2593
2667
|
}
|
|
2594
2668
|
const recentInteractiveActivity = this.hasRecentInteractiveActivity(now);
|
|
2595
2669
|
const statusActivityHoldMs = this.getStatusActivityHoldMs();
|
|
2596
|
-
const
|
|
2670
|
+
const visibleIdlePrompt = this.looksLikeVisibleIdlePrompt(screenText);
|
|
2671
|
+
const visibleAssistantCandidate = this.looksLikeVisibleAssistantCandidate(screenText);
|
|
2672
|
+
if (this.currentTurnScope && this.cliType === "claude-cli") {
|
|
2673
|
+
LOG.info(
|
|
2674
|
+
"CLI",
|
|
2675
|
+
`[${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)}`
|
|
2676
|
+
);
|
|
2677
|
+
}
|
|
2678
|
+
const shouldHoldGenerating = scriptStatus === "idle" && this.isWaitingForResponse && !modal && recentInteractiveActivity && !(visibleIdlePrompt && visibleAssistantCandidate);
|
|
2597
2679
|
if (shouldHoldGenerating) {
|
|
2598
2680
|
this.clearIdleFinishCandidate("hold_generating_recent_activity");
|
|
2599
2681
|
this.setStatus("generating", "recent_activity_hold");
|
|
@@ -2624,8 +2706,8 @@ var init_provider_cli_adapter = __esm({
|
|
|
2624
2706
|
if (scriptStatus === "waiting_approval") {
|
|
2625
2707
|
this.clearIdleFinishCandidate("waiting_approval");
|
|
2626
2708
|
const inCooldown = this.lastApprovalResolvedAt && Date.now() - this.lastApprovalResolvedAt < this.timeouts.approvalCooldown;
|
|
2627
|
-
const
|
|
2628
|
-
if ((inCooldown ||
|
|
2709
|
+
const visibleIdlePrompt2 = this.looksLikeVisibleIdlePrompt(screenText);
|
|
2710
|
+
if ((inCooldown || visibleIdlePrompt2) && !modal) {
|
|
2629
2711
|
if (this.approvalExitTimeout) {
|
|
2630
2712
|
clearTimeout(this.approvalExitTimeout);
|
|
2631
2713
|
this.approvalExitTimeout = null;
|
|
@@ -2697,7 +2779,7 @@ var init_provider_cli_adapter = __esm({
|
|
|
2697
2779
|
this.lastApprovalResolvedAt = Date.now();
|
|
2698
2780
|
}
|
|
2699
2781
|
if (this.isWaitingForResponse) {
|
|
2700
|
-
const
|
|
2782
|
+
const visibleIdlePrompt2 = this.looksLikeVisibleIdlePrompt(screenText);
|
|
2701
2783
|
const quietForMs = this.lastNonEmptyOutputAt ? now - this.lastNonEmptyOutputAt : Number.MAX_SAFE_INTEGER;
|
|
2702
2784
|
const screenStableMs = this.lastScreenChangeAt ? now - this.lastScreenChangeAt : 0;
|
|
2703
2785
|
const hasAssistantTurn = !!lastParsedAssistant;
|
|
@@ -2705,12 +2787,12 @@ var init_provider_cli_adapter = __esm({
|
|
|
2705
2787
|
const idleFinishConfirmMs = this.getIdleFinishConfirmMs();
|
|
2706
2788
|
const idleQuietThresholdMs = Math.max(idleFinishConfirmMs, this.timeouts.outputSettle);
|
|
2707
2789
|
const idleStableThresholdMs = idleFinishConfirmMs;
|
|
2708
|
-
const idleReady =
|
|
2790
|
+
const idleReady = visibleIdlePrompt2 && !modal && hasAssistantTurn && quietForMs >= idleQuietThresholdMs && screenStableMs >= idleStableThresholdMs;
|
|
2709
2791
|
const candidate = this.idleFinishCandidate;
|
|
2710
2792
|
const candidateQuiet = !!candidate && candidate.responseEpoch === this.responseEpoch && candidate.lastOutputAt === this.lastOutputAt && candidate.lastScreenChangeAt === this.lastScreenChangeAt && assistantLength >= candidate.assistantLength && now - candidate.armedAt >= idleFinishConfirmMs;
|
|
2711
2793
|
const canFinishImmediately = idleReady && candidateQuiet;
|
|
2712
2794
|
this.recordTrace("idle_decision", {
|
|
2713
|
-
visibleIdlePrompt,
|
|
2795
|
+
visibleIdlePrompt: visibleIdlePrompt2,
|
|
2714
2796
|
quietForMs,
|
|
2715
2797
|
screenStableMs,
|
|
2716
2798
|
hasAssistantTurn,
|
|
@@ -2830,6 +2912,70 @@ var init_provider_cli_adapter = __esm({
|
|
|
2830
2912
|
this.setStatus("idle", "response_finished");
|
|
2831
2913
|
this.onStatusChange?.();
|
|
2832
2914
|
}
|
|
2915
|
+
maybeCommitVisibleIdleTranscript(parsed, options) {
|
|
2916
|
+
const allowImmediateScriptIdleCommit = this.provider.allowInputDuringGeneration === true;
|
|
2917
|
+
if (!allowImmediateScriptIdleCommit) return false;
|
|
2918
|
+
if (!parsed || !Array.isArray(parsed.messages) || parsed.status !== "idle" || !this.isWaitingForResponse || !this.currentTurnScope || this.activeModal || parsed.activeModal) {
|
|
2919
|
+
return false;
|
|
2920
|
+
}
|
|
2921
|
+
if (options?.requireVisibleAssistantCandidate) {
|
|
2922
|
+
const candidateText = options.screenText || this.terminalScreen.getText() || "";
|
|
2923
|
+
if (!this.looksLikeVisibleAssistantCandidate(candidateText)) {
|
|
2924
|
+
return false;
|
|
2925
|
+
}
|
|
2926
|
+
}
|
|
2927
|
+
const hydratedForIdleCommit = normalizeCliParsedMessages(parsed.messages, {
|
|
2928
|
+
committedMessages: this.committedMessages,
|
|
2929
|
+
scope: this.currentTurnScope,
|
|
2930
|
+
lastOutputAt: this.lastOutputAt
|
|
2931
|
+
});
|
|
2932
|
+
const visibleAssistant = [...hydratedForIdleCommit].reverse().find((message) => message.role === "assistant" && message.content.trim());
|
|
2933
|
+
if (!visibleAssistant) return false;
|
|
2934
|
+
this.committedMessages = hydratedForIdleCommit;
|
|
2935
|
+
const promptForTrim = this.currentTurnScope?.prompt || getLastUserPromptText(this.committedMessages);
|
|
2936
|
+
if (promptForTrim) {
|
|
2937
|
+
const lastAssistantForTrim = [...this.committedMessages].reverse().find((message) => message.role === "assistant");
|
|
2938
|
+
if (lastAssistantForTrim) {
|
|
2939
|
+
lastAssistantForTrim.content = trimPromptEchoPrefix(lastAssistantForTrim.content, promptForTrim);
|
|
2940
|
+
}
|
|
2941
|
+
}
|
|
2942
|
+
if (this.responseTimeout) {
|
|
2943
|
+
clearTimeout(this.responseTimeout);
|
|
2944
|
+
this.responseTimeout = null;
|
|
2945
|
+
}
|
|
2946
|
+
if (this.idleTimeout) {
|
|
2947
|
+
clearTimeout(this.idleTimeout);
|
|
2948
|
+
this.idleTimeout = null;
|
|
2949
|
+
}
|
|
2950
|
+
if (this.approvalExitTimeout) {
|
|
2951
|
+
clearTimeout(this.approvalExitTimeout);
|
|
2952
|
+
this.approvalExitTimeout = null;
|
|
2953
|
+
}
|
|
2954
|
+
if (this.submitRetryTimer) {
|
|
2955
|
+
clearTimeout(this.submitRetryTimer);
|
|
2956
|
+
this.submitRetryTimer = null;
|
|
2957
|
+
}
|
|
2958
|
+
if (this.finishRetryTimer) {
|
|
2959
|
+
clearTimeout(this.finishRetryTimer);
|
|
2960
|
+
this.finishRetryTimer = null;
|
|
2961
|
+
}
|
|
2962
|
+
this.syncMessageViews();
|
|
2963
|
+
this.responseBuffer = "";
|
|
2964
|
+
this.isWaitingForResponse = false;
|
|
2965
|
+
this.responseSettleIgnoreUntil = 0;
|
|
2966
|
+
this.submitRetryUsed = false;
|
|
2967
|
+
this.submitRetryPromptSnippet = "";
|
|
2968
|
+
this.finishRetryCount = 0;
|
|
2969
|
+
this.currentTurnScope = null;
|
|
2970
|
+
this.activeModal = null;
|
|
2971
|
+
this.setStatus("idle", "script_idle_commit");
|
|
2972
|
+
this.onStatusChange?.();
|
|
2973
|
+
this.recordTrace("script_idle_commit", {
|
|
2974
|
+
messageCount: this.committedMessages.length,
|
|
2975
|
+
lastAssistant: summarizeCliTraceText(visibleAssistant.content, 320)
|
|
2976
|
+
});
|
|
2977
|
+
return true;
|
|
2978
|
+
}
|
|
2833
2979
|
commitCurrentTranscript() {
|
|
2834
2980
|
const parsed = this.parseCurrentTranscript(
|
|
2835
2981
|
this.committedMessages,
|
|
@@ -2851,6 +2997,12 @@ var init_provider_cli_adapter = __esm({
|
|
|
2851
2997
|
}
|
|
2852
2998
|
this.syncMessageViews();
|
|
2853
2999
|
const lastAssistant = [...this.committedMessages].reverse().find((message) => message.role === "assistant");
|
|
3000
|
+
if (this.currentTurnScope) {
|
|
3001
|
+
LOG.info(
|
|
3002
|
+
"CLI",
|
|
3003
|
+
`[${this.cliType}] commitCurrentTranscript committedMessages=${this.committedMessages.length} finalLastAssistant=${JSON.stringify(summarizeCliTraceText(lastAssistant?.content || "", 220)).slice(0, 260)}`
|
|
3004
|
+
);
|
|
3005
|
+
}
|
|
2854
3006
|
this.recordTrace("commit_transcript", {
|
|
2855
3007
|
parsedStatus: parsed.status || null,
|
|
2856
3008
|
messageCount: this.committedMessages.length,
|
|
@@ -2870,11 +3022,18 @@ var init_provider_cli_adapter = __esm({
|
|
|
2870
3022
|
`[${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 || "-"}`
|
|
2871
3023
|
);
|
|
2872
3024
|
}
|
|
3025
|
+
const hasAssistant = !!lastAssistant;
|
|
2873
3026
|
return {
|
|
2874
|
-
hasAssistant
|
|
3027
|
+
hasAssistant,
|
|
2875
3028
|
assistantContent: lastAssistant?.content || ""
|
|
2876
3029
|
};
|
|
2877
3030
|
}
|
|
3031
|
+
if (this.currentTurnScope) {
|
|
3032
|
+
LOG.info(
|
|
3033
|
+
"CLI",
|
|
3034
|
+
`[${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 || "-"}`
|
|
3035
|
+
);
|
|
3036
|
+
}
|
|
2878
3037
|
return {
|
|
2879
3038
|
hasAssistant: false,
|
|
2880
3039
|
assistantContent: ""
|
|
@@ -2960,19 +3119,25 @@ var init_provider_cli_adapter = __esm({
|
|
|
2960
3119
|
this.currentTurnScope,
|
|
2961
3120
|
screenText
|
|
2962
3121
|
);
|
|
2963
|
-
|
|
3122
|
+
if (this.maybeCommitVisibleIdleTranscript(parsed)) {
|
|
3123
|
+
return this.getScriptParsedStatus();
|
|
3124
|
+
}
|
|
3125
|
+
const shouldPreferCommittedMessages = !this.currentTurnScope && !this.activeModal && this.currentStatus === "idle";
|
|
2964
3126
|
let result;
|
|
2965
3127
|
if (parsed && Array.isArray(parsed.messages)) {
|
|
2966
|
-
const
|
|
2967
|
-
...message,
|
|
2968
|
-
id: message.id || `msg_${index}`,
|
|
2969
|
-
index: typeof message.index === "number" ? message.index : index,
|
|
2970
|
-
receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp
|
|
2971
|
-
})) : hydrateCliParsedMessages(parsed.messages, {
|
|
3128
|
+
const parsedHydratedMessages = hydrateCliParsedMessages(parsed.messages, {
|
|
2972
3129
|
committedMessages: this.committedMessages,
|
|
2973
3130
|
scope: this.currentTurnScope,
|
|
2974
3131
|
lastOutputAt: this.lastOutputAt
|
|
2975
3132
|
});
|
|
3133
|
+
const committedHydratedMessages = this.committedMessages.map((message, index) => buildChatMessage({
|
|
3134
|
+
...message,
|
|
3135
|
+
id: message.id || `msg_${index}`,
|
|
3136
|
+
index: typeof message.index === "number" ? message.index : index,
|
|
3137
|
+
receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp
|
|
3138
|
+
}));
|
|
3139
|
+
const shouldPreferCommittedHistoryReplay = !this.currentTurnScope && !this.activeModal && committedHydratedMessages.length > parsedHydratedMessages.length;
|
|
3140
|
+
const hydratedMessages = shouldPreferCommittedMessages || shouldPreferCommittedHistoryReplay ? committedHydratedMessages : parsedHydratedMessages;
|
|
2976
3141
|
result = {
|
|
2977
3142
|
id: parsed.id || "cli_session",
|
|
2978
3143
|
status: parsed.status || this.currentStatus,
|
|
@@ -2996,6 +3161,23 @@ var init_provider_cli_adapter = __esm({
|
|
|
2996
3161
|
activeModal: this.activeModal
|
|
2997
3162
|
};
|
|
2998
3163
|
}
|
|
3164
|
+
const hasVisibleAssistantMessage = Array.isArray(result?.messages) && result.messages.some((message) => message?.role === "assistant" && typeof message?.content === "string" && message.content.trim());
|
|
3165
|
+
const shouldClampStaleGeneratingToIdle = result?.status === "generating" && this.currentStatus === "idle" && !this.currentTurnScope && !result?.activeModal && hasVisibleAssistantMessage;
|
|
3166
|
+
if (shouldClampStaleGeneratingToIdle) {
|
|
3167
|
+
result = {
|
|
3168
|
+
...result,
|
|
3169
|
+
status: "idle",
|
|
3170
|
+
messages: Array.isArray(result.messages) ? result.messages.map((message) => {
|
|
3171
|
+
if (message?.role !== "assistant" || !message?.meta?.streaming) return message;
|
|
3172
|
+
const nextMeta = { ...message.meta || {} };
|
|
3173
|
+
delete nextMeta.streaming;
|
|
3174
|
+
return {
|
|
3175
|
+
...message,
|
|
3176
|
+
...Object.keys(nextMeta).length > 0 ? { meta: nextMeta } : { meta: void 0 }
|
|
3177
|
+
};
|
|
3178
|
+
}) : result.messages
|
|
3179
|
+
};
|
|
3180
|
+
}
|
|
2999
3181
|
this.parsedStatusCache = {
|
|
3000
3182
|
committedMessagesRef: this.committedMessages,
|
|
3001
3183
|
responseBuffer: this.responseBuffer,
|
|
@@ -3128,9 +3310,27 @@ ${data.message || ""}`.trim();
|
|
|
3128
3310
|
}
|
|
3129
3311
|
}
|
|
3130
3312
|
if (!this.ready) throw new Error(`${this.cliName} not ready (status: ${this.currentStatus})`);
|
|
3131
|
-
|
|
3313
|
+
const parsedStatusBeforeSend = !allowInputDuringGeneration ? (() => {
|
|
3314
|
+
try {
|
|
3315
|
+
return this.getScriptParsedStatus?.() || null;
|
|
3316
|
+
} catch {
|
|
3317
|
+
return null;
|
|
3318
|
+
}
|
|
3319
|
+
})() : null;
|
|
3320
|
+
const parsedSessionStatus = typeof parsedStatusBeforeSend?.status === "string" ? String(parsedStatusBeforeSend.status) : "";
|
|
3321
|
+
const parsedMessagesBeforeSend = Array.isArray(parsedStatusBeforeSend?.messages) ? parsedStatusBeforeSend.messages.filter((message) => message && (message.role === "user" || message.role === "assistant")) : [];
|
|
3322
|
+
const shouldCommitParsedIdleBeforeSend = !allowInputDuringGeneration && parsedSessionStatus === "idle" && parsedMessagesBeforeSend.length > this.committedMessages.length && parsedMessagesBeforeSend.some((message) => message?.role === "assistant" && typeof message?.content === "string" && message.content.trim());
|
|
3323
|
+
if (shouldCommitParsedIdleBeforeSend) {
|
|
3324
|
+
this.commitCurrentTranscript();
|
|
3325
|
+
}
|
|
3326
|
+
if (!allowInputDuringGeneration && (parsedSessionStatus === "generating" || parsedSessionStatus === "long_generating")) {
|
|
3132
3327
|
throw new Error(`${this.cliName} is still processing the previous prompt`);
|
|
3133
3328
|
}
|
|
3329
|
+
if (this.isWaitingForResponse && !allowInputDuringGeneration) {
|
|
3330
|
+
if (!this.clearStaleIdleResponseGuard("send_message_guard")) {
|
|
3331
|
+
throw new Error(`${this.cliName} is still processing the previous prompt`);
|
|
3332
|
+
}
|
|
3333
|
+
}
|
|
3134
3334
|
const blockingModal = this.activeModal || this.getStartupConfirmationModal(this.terminalScreen.getText() || "");
|
|
3135
3335
|
if (blockingModal || this.currentStatus === "waiting_approval") {
|
|
3136
3336
|
throw new Error(`${this.cliName} is awaiting confirmation before it can accept a prompt`);
|
|
@@ -3210,7 +3410,7 @@ ${data.message || ""}`.trim();
|
|
|
3210
3410
|
this.submitRetryTimer = null;
|
|
3211
3411
|
if (!this.ptyProcess || !this.isWaitingForResponse || this.submitRetryUsed) return;
|
|
3212
3412
|
if (this.currentStatus === "waiting_approval") return;
|
|
3213
|
-
if (
|
|
3413
|
+
if (this.hasMeaningfulResponseBuffer(normalizedPromptSnippet)) return;
|
|
3214
3414
|
const screenText2 = this.terminalScreen.getText();
|
|
3215
3415
|
if (!promptLikelyVisible(screenText2, normalizedPromptSnippet)) return;
|
|
3216
3416
|
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;
|
|
@@ -3247,7 +3447,7 @@ ${data.message || ""}`.trim();
|
|
|
3247
3447
|
this.submitRetryTimer = null;
|
|
3248
3448
|
if (!this.ptyProcess || !this.isWaitingForResponse || this.submitRetryUsed) return;
|
|
3249
3449
|
if (this.currentStatus === "waiting_approval") return;
|
|
3250
|
-
if (
|
|
3450
|
+
if (this.hasMeaningfulResponseBuffer(normalizedPromptSnippet)) return;
|
|
3251
3451
|
const screenText = this.terminalScreen.getText();
|
|
3252
3452
|
if (!promptLikelyVisible(screenText, normalizedPromptSnippet)) return;
|
|
3253
3453
|
LOG.info("CLI", `[${this.cliType}] Retrying submit key for stuck prompt (attempt 1)`);
|
|
@@ -9748,6 +9948,7 @@ function normalizeReadChatCommandStatus(status, activeModal) {
|
|
|
9748
9948
|
}
|
|
9749
9949
|
function buildReadChatCommandResult(payload, args) {
|
|
9750
9950
|
let validatedPayload;
|
|
9951
|
+
const debugReadChat = payload?.debugReadChat && typeof payload.debugReadChat === "object" ? payload.debugReadChat : void 0;
|
|
9751
9952
|
try {
|
|
9752
9953
|
validatedPayload = validateReadChatResultPayload({
|
|
9753
9954
|
...payload,
|
|
@@ -9768,7 +9969,8 @@ function buildReadChatCommandResult(payload, args) {
|
|
|
9768
9969
|
syncMode: "full",
|
|
9769
9970
|
replaceFrom: 0,
|
|
9770
9971
|
totalMessages: messages.length,
|
|
9771
|
-
lastMessageSignature
|
|
9972
|
+
lastMessageSignature,
|
|
9973
|
+
...debugReadChat ? { debugReadChat } : {}
|
|
9772
9974
|
};
|
|
9773
9975
|
}
|
|
9774
9976
|
const sync = computeReadChatSync(messages, cursor);
|
|
@@ -9779,7 +9981,8 @@ function buildReadChatCommandResult(payload, args) {
|
|
|
9779
9981
|
syncMode: sync.syncMode,
|
|
9780
9982
|
replaceFrom: sync.replaceFrom,
|
|
9781
9983
|
totalMessages: sync.totalMessages,
|
|
9782
|
-
lastMessageSignature: sync.lastMessageSignature
|
|
9984
|
+
lastMessageSignature: sync.lastMessageSignature,
|
|
9985
|
+
...debugReadChat ? { debugReadChat } : {}
|
|
9783
9986
|
};
|
|
9784
9987
|
}
|
|
9785
9988
|
function didProviderConfirmSend(result) {
|
|
@@ -9870,14 +10073,33 @@ async function handleReadChat(h, args) {
|
|
|
9870
10073
|
}
|
|
9871
10074
|
}
|
|
9872
10075
|
const parsedRecord = parsedStatus && typeof parsedStatus === "object" ? parsedStatus : null;
|
|
9873
|
-
const
|
|
10076
|
+
const adapterStatus = adapter.getStatus();
|
|
10077
|
+
const shouldPreferAdapterMessages = Array.isArray(adapterStatus.messages) && adapterStatus.messages.length > 0 && Array.isArray(parsedRecord?.messages) && adapterStatus.messages.length > parsedRecord.messages.length;
|
|
10078
|
+
const status = parsedRecord ? {
|
|
10079
|
+
...parsedRecord,
|
|
10080
|
+
messages: shouldPreferAdapterMessages ? adapterStatus.messages : parsedRecord.messages,
|
|
10081
|
+
status: adapterStatus.status !== "idle" ? adapterStatus.status : parsedRecord.status || adapterStatus.status,
|
|
10082
|
+
activeModal: parsedRecord.activeModal || adapterStatus.activeModal
|
|
10083
|
+
} : adapterStatus;
|
|
9874
10084
|
const title = typeof parsedRecord?.title === "string" ? parsedRecord.title : void 0;
|
|
9875
10085
|
const providerSessionId = typeof parsedRecord?.providerSessionId === "string" ? parsedRecord.providerSessionId : void 0;
|
|
9876
10086
|
if (status) {
|
|
10087
|
+
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}`);
|
|
9877
10088
|
return buildReadChatCommandResult({
|
|
9878
10089
|
messages: status.messages || [],
|
|
9879
10090
|
status: status.status,
|
|
9880
10091
|
activeModal: status.activeModal,
|
|
10092
|
+
debugReadChat: {
|
|
10093
|
+
provider: adapter.cliType,
|
|
10094
|
+
targetSessionId: String(args?.targetSessionId || ""),
|
|
10095
|
+
adapterStatus: String(adapterStatus.status || ""),
|
|
10096
|
+
parsedStatus: String(parsedRecord?.status || ""),
|
|
10097
|
+
returnedStatus: String(status.status || ""),
|
|
10098
|
+
shouldPreferAdapterMessages,
|
|
10099
|
+
adapterMsgCount: Array.isArray(adapterStatus.messages) ? adapterStatus.messages.length : 0,
|
|
10100
|
+
parsedMsgCount: Array.isArray(parsedRecord?.messages) ? parsedRecord.messages.length : 0,
|
|
10101
|
+
returnedMsgCount: Array.isArray(status.messages) ? status.messages.length : 0
|
|
10102
|
+
},
|
|
9881
10103
|
...title ? { title } : {},
|
|
9882
10104
|
...providerSessionId ? { providerSessionId } : {}
|
|
9883
10105
|
}, args);
|
|
@@ -12123,6 +12345,30 @@ init_contracts();
|
|
|
12123
12345
|
init_provider_cli_adapter();
|
|
12124
12346
|
init_logger();
|
|
12125
12347
|
init_chat_message_normalization();
|
|
12348
|
+
function normalizePersistableCliHistoryContent(content) {
|
|
12349
|
+
return flattenContent(content).replace(/\s+/g, " ").trim();
|
|
12350
|
+
}
|
|
12351
|
+
function buildPersistableCliHistorySignature(message) {
|
|
12352
|
+
return [
|
|
12353
|
+
String(message.role || ""),
|
|
12354
|
+
String(message.kind || ""),
|
|
12355
|
+
String(message.senderName || ""),
|
|
12356
|
+
normalizePersistableCliHistoryContent(message.content)
|
|
12357
|
+
].join("|");
|
|
12358
|
+
}
|
|
12359
|
+
function buildIncrementalHistoryAppendMessages(previousMessages, currentMessages) {
|
|
12360
|
+
if (!Array.isArray(currentMessages) || currentMessages.length === 0) return [];
|
|
12361
|
+
if (!Array.isArray(previousMessages) || previousMessages.length === 0) return currentMessages;
|
|
12362
|
+
const previousSignatures = previousMessages.map(buildPersistableCliHistorySignature);
|
|
12363
|
+
const currentSignatures = currentMessages.map(buildPersistableCliHistorySignature);
|
|
12364
|
+
let sharedPrefixLength = 0;
|
|
12365
|
+
while (sharedPrefixLength < previousSignatures.length && sharedPrefixLength < currentSignatures.length && previousSignatures[sharedPrefixLength] === currentSignatures[sharedPrefixLength]) {
|
|
12366
|
+
sharedPrefixLength += 1;
|
|
12367
|
+
}
|
|
12368
|
+
if (sharedPrefixLength === currentSignatures.length) return [];
|
|
12369
|
+
if (sharedPrefixLength === previousSignatures.length) return currentMessages.slice(sharedPrefixLength);
|
|
12370
|
+
return currentMessages;
|
|
12371
|
+
}
|
|
12126
12372
|
var CachedDatabaseSync = null;
|
|
12127
12373
|
function getDatabaseSync() {
|
|
12128
12374
|
if (CachedDatabaseSync) return CachedDatabaseSync;
|
|
@@ -12200,6 +12446,7 @@ var CliProviderInstance = class {
|
|
|
12200
12446
|
appliedEffectKeys = /* @__PURE__ */ new Set();
|
|
12201
12447
|
historyWriter;
|
|
12202
12448
|
runtimeMessages = [];
|
|
12449
|
+
lastPersistedHistoryMessages = [];
|
|
12203
12450
|
instanceId;
|
|
12204
12451
|
suppressIdleHistoryReplay = false;
|
|
12205
12452
|
errorMessage = void 0;
|
|
@@ -12240,6 +12487,13 @@ var CliProviderInstance = class {
|
|
|
12240
12487
|
this.providerSessionId,
|
|
12241
12488
|
this.instanceId
|
|
12242
12489
|
);
|
|
12490
|
+
this.lastPersistedHistoryMessages = restoredHistory.messages.map((message) => ({
|
|
12491
|
+
role: message.role,
|
|
12492
|
+
content: message.content,
|
|
12493
|
+
kind: message.kind,
|
|
12494
|
+
senderName: message.senderName,
|
|
12495
|
+
receivedAt: message.receivedAt
|
|
12496
|
+
}));
|
|
12243
12497
|
this.suppressIdleHistoryReplay = restoredHistory.messages.length > 0;
|
|
12244
12498
|
if (restoredHistory.messages.length > 0) {
|
|
12245
12499
|
this.adapter.seedCommittedMessages(
|
|
@@ -12371,15 +12625,24 @@ var CliProviderInstance = class {
|
|
|
12371
12625
|
messagesToSave = messagesToSave.slice(0, lastIdx);
|
|
12372
12626
|
}
|
|
12373
12627
|
}
|
|
12374
|
-
|
|
12628
|
+
const normalizedMessagesToSave = messagesToSave.map((message) => ({
|
|
12629
|
+
role: message.role,
|
|
12630
|
+
content: flattenContent(message.content),
|
|
12631
|
+
kind: typeof message.kind === "string" ? message.kind : void 0,
|
|
12632
|
+
senderName: typeof message.senderName === "string" ? message.senderName : void 0,
|
|
12633
|
+
receivedAt: typeof message.receivedAt === "number" ? message.receivedAt : message.timestamp
|
|
12634
|
+
}));
|
|
12635
|
+
if (!shouldSkipReplayPersist && normalizedMessagesToSave.length > 0) {
|
|
12636
|
+
const incrementalMessages = buildIncrementalHistoryAppendMessages(this.lastPersistedHistoryMessages, normalizedMessagesToSave);
|
|
12375
12637
|
this.historyWriter.appendNewMessages(
|
|
12376
12638
|
this.type,
|
|
12377
|
-
|
|
12639
|
+
incrementalMessages,
|
|
12378
12640
|
parsedStatus?.title || dirName,
|
|
12379
12641
|
this.instanceId,
|
|
12380
12642
|
this.providerSessionId
|
|
12381
12643
|
);
|
|
12382
12644
|
}
|
|
12645
|
+
this.lastPersistedHistoryMessages = normalizedMessagesToSave;
|
|
12383
12646
|
}
|
|
12384
12647
|
this.applyProviderResponse(parsedStatus, { phase: "immediate" });
|
|
12385
12648
|
const surface = resolveProviderStateSurface({
|
|
@@ -12395,7 +12658,7 @@ var CliProviderInstance = class {
|
|
|
12395
12658
|
activeChat: {
|
|
12396
12659
|
id: `${this.type}_${this.workingDir}`,
|
|
12397
12660
|
title: parsedStatus?.title || dirName,
|
|
12398
|
-
status: parseErrorMessage ? "error" : autoApproveActive && parsedStatus?.status === "waiting_approval" ? "generating" : parsedStatus?.status || visibleStatus,
|
|
12661
|
+
status: parseErrorMessage ? "error" : autoApproveActive && parsedStatus?.status === "waiting_approval" ? "generating" : adapterStatus.status !== "idle" ? visibleStatus : parsedStatus?.status || visibleStatus,
|
|
12399
12662
|
messages: mergedMessages,
|
|
12400
12663
|
activeModal: autoApproveActive ? null : parsedStatus?.activeModal ?? adapterStatus.activeModal,
|
|
12401
12664
|
inputContent: ""
|
|
@@ -12627,6 +12890,7 @@ var CliProviderInstance = class {
|
|
|
12627
12890
|
}
|
|
12628
12891
|
if (data.sessionEvent === "new_session") {
|
|
12629
12892
|
this.runtimeMessages = [];
|
|
12893
|
+
this.lastPersistedHistoryMessages = [];
|
|
12630
12894
|
this.suppressIdleHistoryReplay = false;
|
|
12631
12895
|
this.adapter.clearHistory();
|
|
12632
12896
|
}
|
|
@@ -24834,6 +25098,13 @@ init_pty_transport();
|
|
|
24834
25098
|
// src/cli-adapters/session-host-transport.ts
|
|
24835
25099
|
var import_session_host_core2 = require("@adhdev/session-host-core");
|
|
24836
25100
|
init_logger();
|
|
25101
|
+
function shouldResumeAttachedSession(record) {
|
|
25102
|
+
if (!record) return false;
|
|
25103
|
+
if (record.lifecycle === "interrupted") return true;
|
|
25104
|
+
if (record.lifecycle !== "stopped") return false;
|
|
25105
|
+
if (record.meta?.restoredFromStorage === true) return true;
|
|
25106
|
+
return typeof record.meta?.runtimeRecoveryState === "string" && String(record.meta.runtimeRecoveryState).trim().length > 0;
|
|
25107
|
+
}
|
|
24837
25108
|
var SessionHostRuntimeTransport = class {
|
|
24838
25109
|
constructor(options) {
|
|
24839
25110
|
this.options = options;
|
|
@@ -25007,7 +25278,7 @@ var SessionHostRuntimeTransport = class {
|
|
|
25007
25278
|
payload: {}
|
|
25008
25279
|
});
|
|
25009
25280
|
const existingRecord = existingRecords.success && existingRecords.result ? existingRecords.result.find((item) => item.sessionId === this.options.runtimeId) || null : null;
|
|
25010
|
-
if (existingRecord
|
|
25281
|
+
if (shouldResumeAttachedSession(existingRecord)) {
|
|
25011
25282
|
const resumeResponse = await this.client.request({
|
|
25012
25283
|
type: "resume_session",
|
|
25013
25284
|
payload: {
|
|
@@ -25303,6 +25574,8 @@ async function listHostedCliRuntimes(endpoint) {
|
|
|
25303
25574
|
// src/session-host/startup-restore-policy.js
|
|
25304
25575
|
function shouldAutoRestoreHostedSessionsOnStartup(env = process.env) {
|
|
25305
25576
|
const raw = typeof env.ADHDEV_RESTORE_HOSTED_SESSIONS_ON_STARTUP === "string" ? env.ADHDEV_RESTORE_HOSTED_SESSIONS_ON_STARTUP.trim().toLowerCase() : "";
|
|
25577
|
+
if (!raw) return true;
|
|
25578
|
+
if (raw === "0" || raw === "false" || raw === "no") return false;
|
|
25306
25579
|
return raw === "1" || raw === "true" || raw === "yes";
|
|
25307
25580
|
}
|
|
25308
25581
|
|