@adhdev/daemon-core 0.8.68 → 0.8.70
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/agent-stream/manager.d.ts +2 -1
- package/dist/agent-stream/provider-adapter.d.ts +6 -2
- package/dist/agent-stream/types.d.ts +5 -2
- package/dist/commands/stream-commands.d.ts +2 -1
- package/dist/config/recent-activity.d.ts +4 -3
- package/dist/index.js +286 -64
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +286 -64
- package/dist/index.mjs.map +1 -1
- package/dist/providers/contracts.d.ts +10 -0
- package/dist/providers/extension-provider-instance.d.ts +1 -0
- package/dist/providers/open-panel-support.d.ts +6 -0
- package/dist/providers/provider-instance.d.ts +2 -1
- package/dist/shared-types.d.ts +1 -1
- package/dist/types.d.ts +1 -0
- package/node_modules/@adhdev/session-host-core/package.json +1 -1
- package/package.json +1 -1
- package/src/agent-stream/forward.ts +1 -0
- package/src/agent-stream/manager.d.ts +2 -1
- package/src/agent-stream/manager.ts +20 -5
- package/src/agent-stream/provider-adapter.d.ts +3 -2
- package/src/agent-stream/provider-adapter.ts +123 -4
- package/src/agent-stream/types.d.ts +3 -2
- package/src/agent-stream/types.ts +5 -2
- package/src/cli-adapters/provider-cli-adapter.ts +3 -1
- package/src/commands/cli-manager.ts +12 -0
- package/src/commands/handler.ts +4 -2
- package/src/commands/router.ts +1 -0
- package/src/commands/stream-commands.d.ts +2 -1
- package/src/commands/stream-commands.ts +74 -2
- package/src/config/recent-activity.ts +25 -15
- package/src/daemon/dev-auto-implement.ts +2 -2
- package/src/daemon/dev-server.ts +2 -2
- package/src/daemon/scaffold-template.ts +12 -5
- package/src/providers/contracts.d.ts +10 -0
- package/src/providers/contracts.ts +14 -0
- package/src/providers/extension-provider-instance.ts +15 -2
- package/src/providers/ide-provider-instance.ts +2 -0
- package/src/providers/open-panel-support.ts +40 -0
- package/src/providers/provider-instance.d.ts +2 -1
- package/src/providers/provider-instance.ts +2 -1
- package/src/providers/provider-schema.ts +10 -0
- package/src/providers/read-chat-contract.ts +1 -0
- package/src/shared-types.d.ts +1 -1
- package/src/shared-types.ts +1 -0
- package/src/status/builders.ts +9 -23
- package/src/status/snapshot.ts +2 -2
- package/src/types.ts +1 -0
|
@@ -52,7 +52,8 @@ export declare class DaemonAgentStreamManager {
|
|
|
52
52
|
newSession(cdp: DaemonCdpManager, sessionId: string): Promise<boolean>;
|
|
53
53
|
listSessionChats(cdp: DaemonCdpManager, sessionId: string): Promise<AgentChatListItem[]>;
|
|
54
54
|
switchConversation(cdp: DaemonCdpManager, sessionId: string, conversationId: string): Promise<boolean>;
|
|
55
|
-
|
|
55
|
+
selectSession(cdp: DaemonCdpManager, sessionId: string): Promise<boolean>;
|
|
56
|
+
openSessionPanel(cdp: DaemonCdpManager, sessionId: string): Promise<boolean>;
|
|
56
57
|
getConnectedSessions(parentSessionId?: string): string[];
|
|
57
58
|
getManagedSession(sessionId: string): ManagedAgent | undefined;
|
|
58
59
|
dispose(cdpManagers: Map<string, DaemonCdpManager>): Promise<void>;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Auto-configured using provider.js scripts + metadata.
|
|
6
6
|
*/
|
|
7
7
|
import type { IAgentStreamAdapter, AgentStreamState, AgentChatListItem, AgentEvaluateFn } from './types.js';
|
|
8
|
-
import type { ProviderModule } from '../providers/contracts.js';
|
|
8
|
+
import type { ProviderModule, FocusEditorResult, OpenPanelResult } from '../providers/contracts.js';
|
|
9
9
|
export declare class ProviderStreamAdapter implements IAgentStreamAdapter {
|
|
10
10
|
readonly agentType: string;
|
|
11
11
|
readonly agentName: string;
|
|
@@ -18,6 +18,9 @@ export declare class ProviderStreamAdapter implements IAgentStreamAdapter {
|
|
|
18
18
|
private hasScript;
|
|
19
19
|
private getStateTitle;
|
|
20
20
|
private parseMaybeJson;
|
|
21
|
+
private getOptionalError;
|
|
22
|
+
private normalizeFocusEditorResult;
|
|
23
|
+
private normalizeOpenPanelResult;
|
|
21
24
|
private summarizeRaw;
|
|
22
25
|
private isTransportError;
|
|
23
26
|
private titlesMatch;
|
|
@@ -31,6 +34,7 @@ export declare class ProviderStreamAdapter implements IAgentStreamAdapter {
|
|
|
31
34
|
newSession(evaluate: AgentEvaluateFn): Promise<void>;
|
|
32
35
|
listChats(evaluate: AgentEvaluateFn): Promise<AgentChatListItem[]>;
|
|
33
36
|
switchSession(evaluate: AgentEvaluateFn, sessionId: string): Promise<boolean>;
|
|
34
|
-
focusEditor(evaluate: AgentEvaluateFn): Promise<
|
|
37
|
+
focusEditor(evaluate: AgentEvaluateFn): Promise<FocusEditorResult>;
|
|
38
|
+
openPanel(evaluate: AgentEvaluateFn): Promise<OpenPanelResult>;
|
|
35
39
|
private errorState;
|
|
36
40
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Agent stream types.
|
|
5
5
|
* No vscode dependency — can be used as-is.
|
|
6
6
|
*/
|
|
7
|
-
import type { ProviderEffect } from '../providers/contracts.js';
|
|
7
|
+
import type { ProviderEffect, FocusEditorResult, OpenPanelResult } from '../providers/contracts.js';
|
|
8
8
|
import type { ProviderSummaryMetadata } from '../shared-types.js';
|
|
9
9
|
import type { ChatMessageKind } from '../providers/chat-message-normalization.js';
|
|
10
10
|
/** Agent chat message */
|
|
@@ -34,6 +34,8 @@ export interface AgentStreamState {
|
|
|
34
34
|
agentType: string;
|
|
35
35
|
agentName: string;
|
|
36
36
|
extensionId: string;
|
|
37
|
+
sessionId?: string;
|
|
38
|
+
providerSessionId?: string;
|
|
37
39
|
status: 'idle' | 'streaming' | 'waiting_approval' | 'error' | 'disconnected' | 'panel_hidden' | 'not_monitored';
|
|
38
40
|
messages: AgentChatMessage[];
|
|
39
41
|
inputContent: string;
|
|
@@ -70,7 +72,8 @@ export interface IAgentStreamAdapter {
|
|
|
70
72
|
newSession(evaluate: AgentEvaluateFn): Promise<void>;
|
|
71
73
|
listChats?(evaluate: AgentEvaluateFn): Promise<AgentChatListItem[]>;
|
|
72
74
|
switchSession?(evaluate: AgentEvaluateFn, sessionId: string): Promise<boolean>;
|
|
73
|
-
focusEditor?(evaluate: AgentEvaluateFn): Promise<
|
|
75
|
+
focusEditor?(evaluate: AgentEvaluateFn): Promise<FocusEditorResult>;
|
|
76
|
+
openPanel?(evaluate: AgentEvaluateFn): Promise<OpenPanelResult>;
|
|
74
77
|
setProvider?(provider: any): void;
|
|
75
78
|
}
|
|
76
79
|
export type AgentEvaluateFn = (expression: string, timeoutMs?: number) => Promise<unknown>;
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
* IDE Extension Settings, Extension Script Execution
|
|
4
4
|
*/
|
|
5
5
|
import type { CommandResult, CommandHelpers } from './handler.js';
|
|
6
|
-
export declare function
|
|
6
|
+
export declare function handleSelectSession(h: CommandHelpers, args: any): Promise<CommandResult>;
|
|
7
|
+
export declare function handleOpenPanel(h: CommandHelpers, args: any): Promise<CommandResult>;
|
|
7
8
|
export declare function handlePtyInput(h: CommandHelpers, args: any): CommandResult;
|
|
8
9
|
export declare function handlePtyResize(h: CommandHelpers, args: any): CommandResult;
|
|
9
10
|
export declare function handleGetProviderSettings(h: CommandHelpers, args: any): CommandResult;
|
|
@@ -25,6 +25,7 @@ export declare function appendRecentActivity(state: DaemonState, entry: Omit<Rec
|
|
|
25
25
|
lastUsedAt?: number;
|
|
26
26
|
}): DaemonState;
|
|
27
27
|
export declare function getRecentActivity(state: DaemonState, limit?: number): RecentActivityEntry[];
|
|
28
|
-
export declare function
|
|
29
|
-
export declare function
|
|
30
|
-
export declare function
|
|
28
|
+
export declare function buildSessionReadStateKey(sessionId: string, providerSessionId?: string | null): string;
|
|
29
|
+
export declare function getSessionSeenAt(state: DaemonState, sessionId: string, providerSessionId?: string | null): number;
|
|
30
|
+
export declare function getSessionSeenMarker(state: DaemonState, sessionId: string, providerSessionId?: string | null): string;
|
|
31
|
+
export declare function markSessionSeen(state: DaemonState, sessionId: string, seenAt?: number, completionMarker?: string | null, providerSessionId?: string | null): DaemonState;
|
package/dist/index.js
CHANGED
|
@@ -870,6 +870,7 @@ function validateMessage(message, source, index) {
|
|
|
870
870
|
if (isFiniteNumber(message.index)) normalized.index = message.index;
|
|
871
871
|
if (isFiniteNumber(message.timestamp)) normalized.timestamp = message.timestamp;
|
|
872
872
|
if (isFiniteNumber(message.receivedAt)) normalized.receivedAt = message.receivedAt;
|
|
873
|
+
if (typeof message._turnKey === "string") normalized._turnKey = message._turnKey;
|
|
873
874
|
if (Array.isArray(message.toolCalls)) normalized.toolCalls = message.toolCalls;
|
|
874
875
|
if (isPlainObject3(message.meta)) normalized.meta = message.meta;
|
|
875
876
|
if (typeof message.senderName === "string") normalized.senderName = message.senderName;
|
|
@@ -3024,7 +3025,9 @@ ${data.message || ""}`.trim();
|
|
|
3024
3025
|
}
|
|
3025
3026
|
}
|
|
3026
3027
|
if (!this.ready) throw new Error(`${this.cliName} not ready (status: ${this.currentStatus})`);
|
|
3027
|
-
if (this.isWaitingForResponse)
|
|
3028
|
+
if (this.isWaitingForResponse) {
|
|
3029
|
+
throw new Error(`${this.cliName} is still processing the previous prompt`);
|
|
3030
|
+
}
|
|
3028
3031
|
const blockingModal = this.activeModal || this.getStartupConfirmationModal(this.terminalScreen.getText() || "");
|
|
3029
3032
|
if (blockingModal || this.currentStatus === "waiting_approval") {
|
|
3030
3033
|
throw new Error(`${this.cliName} is awaiting confirmation before it can accept a prompt`);
|
|
@@ -3943,27 +3946,37 @@ function getRecentActivity(state, limit = 20) {
|
|
|
3943
3946
|
})
|
|
3944
3947
|
})).sort((a, b) => b.lastUsedAt - a.lastUsedAt).slice(0, limit);
|
|
3945
3948
|
}
|
|
3946
|
-
function
|
|
3947
|
-
|
|
3949
|
+
function buildSessionReadStateKey(sessionId, providerSessionId) {
|
|
3950
|
+
const normalizedProviderSessionId = typeof providerSessionId === "string" ? providerSessionId.trim() : "";
|
|
3951
|
+
if (normalizedProviderSessionId) return `provider:${normalizedProviderSessionId}`;
|
|
3952
|
+
return sessionId;
|
|
3953
|
+
}
|
|
3954
|
+
function getSessionSeenAt(state, sessionId, providerSessionId) {
|
|
3955
|
+
const providerKey = buildSessionReadStateKey(sessionId, providerSessionId);
|
|
3956
|
+
return state.sessionReads?.[providerKey] || state.sessionReads?.[sessionId] || 0;
|
|
3948
3957
|
}
|
|
3949
|
-
function getSessionSeenMarker(state, sessionId) {
|
|
3950
|
-
|
|
3958
|
+
function getSessionSeenMarker(state, sessionId, providerSessionId) {
|
|
3959
|
+
const providerKey = buildSessionReadStateKey(sessionId, providerSessionId);
|
|
3960
|
+
return state.sessionReadMarkers?.[providerKey] || state.sessionReadMarkers?.[sessionId] || "";
|
|
3951
3961
|
}
|
|
3952
|
-
function markSessionSeen(state, sessionId, seenAt = Date.now(), completionMarker) {
|
|
3962
|
+
function markSessionSeen(state, sessionId, seenAt = Date.now(), completionMarker, providerSessionId) {
|
|
3953
3963
|
const prev = state.sessionReads || {};
|
|
3954
|
-
const nextSeenAt = Math.max(prev[sessionId] || 0, seenAt);
|
|
3955
3964
|
const prevMarkers = state.sessionReadMarkers || {};
|
|
3956
3965
|
const nextMarker = typeof completionMarker === "string" ? completionMarker : "";
|
|
3966
|
+
const readKeys = Array.from(new Set([
|
|
3967
|
+
sessionId,
|
|
3968
|
+
buildSessionReadStateKey(sessionId, providerSessionId)
|
|
3969
|
+
].filter(Boolean)));
|
|
3970
|
+
const nextSessionReads = { ...prev };
|
|
3971
|
+
const nextSessionReadMarkers = { ...prevMarkers };
|
|
3972
|
+
for (const key of readKeys) {
|
|
3973
|
+
nextSessionReads[key] = Math.max(prev[key] || 0, seenAt);
|
|
3974
|
+
if (nextMarker) nextSessionReadMarkers[key] = nextMarker;
|
|
3975
|
+
}
|
|
3957
3976
|
return {
|
|
3958
3977
|
...state,
|
|
3959
|
-
sessionReads:
|
|
3960
|
-
|
|
3961
|
-
[sessionId]: nextSeenAt
|
|
3962
|
-
},
|
|
3963
|
-
sessionReadMarkers: nextMarker ? {
|
|
3964
|
-
...prevMarkers,
|
|
3965
|
-
[sessionId]: nextMarker
|
|
3966
|
-
} : prevMarkers
|
|
3978
|
+
sessionReads: nextSessionReads,
|
|
3979
|
+
sessionReadMarkers: nextMarker ? nextSessionReadMarkers : prevMarkers
|
|
3967
3980
|
};
|
|
3968
3981
|
}
|
|
3969
3982
|
|
|
@@ -6563,6 +6576,39 @@ function resolveProviderStateSurface(params) {
|
|
|
6563
6576
|
|
|
6564
6577
|
// src/providers/extension-provider-instance.ts
|
|
6565
6578
|
init_chat_message_normalization();
|
|
6579
|
+
|
|
6580
|
+
// src/providers/open-panel-support.ts
|
|
6581
|
+
var IDE_PROVIDER_SESSION_CAPABILITIES_BASE = [
|
|
6582
|
+
"read_chat",
|
|
6583
|
+
"send_message",
|
|
6584
|
+
"new_session",
|
|
6585
|
+
"list_sessions",
|
|
6586
|
+
"switch_session",
|
|
6587
|
+
"resolve_action",
|
|
6588
|
+
"change_model",
|
|
6589
|
+
"set_mode",
|
|
6590
|
+
"set_thought_level"
|
|
6591
|
+
];
|
|
6592
|
+
var EXTENSION_PROVIDER_SESSION_CAPABILITIES_BASE = [
|
|
6593
|
+
"read_chat",
|
|
6594
|
+
"send_message",
|
|
6595
|
+
"new_session",
|
|
6596
|
+
"list_sessions",
|
|
6597
|
+
"switch_session",
|
|
6598
|
+
"resolve_action",
|
|
6599
|
+
"change_model",
|
|
6600
|
+
"set_mode"
|
|
6601
|
+
];
|
|
6602
|
+
function providerHasOpenPanelSupport(provider) {
|
|
6603
|
+
if (typeof provider.scripts?.openPanel === "function") return true;
|
|
6604
|
+
if (provider.category === "ide" && typeof provider.scripts?.webviewOpenPanel === "function") return true;
|
|
6605
|
+
return false;
|
|
6606
|
+
}
|
|
6607
|
+
function getProviderSessionCapabilities(provider, baseCapabilities) {
|
|
6608
|
+
return providerHasOpenPanelSupport(provider) ? [...baseCapabilities, "open_panel"] : [...baseCapabilities];
|
|
6609
|
+
}
|
|
6610
|
+
|
|
6611
|
+
// src/providers/extension-provider-instance.ts
|
|
6566
6612
|
var ExtensionProviderInstance = class {
|
|
6567
6613
|
type;
|
|
6568
6614
|
category = "extension";
|
|
@@ -6588,6 +6634,7 @@ var ExtensionProviderInstance = class {
|
|
|
6588
6634
|
instanceId;
|
|
6589
6635
|
ideType = "";
|
|
6590
6636
|
chatId = null;
|
|
6637
|
+
providerSessionId = null;
|
|
6591
6638
|
chatTitle = null;
|
|
6592
6639
|
agentName = "";
|
|
6593
6640
|
extensionId = "";
|
|
@@ -6621,8 +6668,10 @@ var ExtensionProviderInstance = class {
|
|
|
6621
6668
|
name: this.provider.name,
|
|
6622
6669
|
category: "extension",
|
|
6623
6670
|
status: this.currentStatus,
|
|
6671
|
+
providerSessionId: this.providerSessionId || this.chatId || void 0,
|
|
6672
|
+
sessionCapabilities: getProviderSessionCapabilities(this.provider, EXTENSION_PROVIDER_SESSION_CAPABILITIES_BASE),
|
|
6624
6673
|
activeChat: this.messages.length > 0 || this.runtimeMessages.length > 0 ? {
|
|
6625
|
-
id: this.chatId || this.instanceId,
|
|
6674
|
+
id: this.providerSessionId || this.chatId || this.instanceId,
|
|
6626
6675
|
title: this.chatTitle || this.agentName || this.provider.name,
|
|
6627
6676
|
status: this.currentStatus,
|
|
6628
6677
|
messages: this.mergeConversationMessages(this.messages),
|
|
@@ -6652,7 +6701,11 @@ var ExtensionProviderInstance = class {
|
|
|
6652
6701
|
});
|
|
6653
6702
|
this.controlValues = patchedState.controlValues;
|
|
6654
6703
|
this.summaryMetadata = patchedState.summaryMetadata;
|
|
6655
|
-
|
|
6704
|
+
const nextProviderSessionId = typeof data?.providerSessionId === "string" && data.providerSessionId.trim() ? data.providerSessionId.trim() : typeof data?.sessionId === "string" && data.sessionId.trim() ? data.sessionId.trim() : "";
|
|
6705
|
+
if (nextProviderSessionId) {
|
|
6706
|
+
this.providerSessionId = nextProviderSessionId;
|
|
6707
|
+
this.chatId = nextProviderSessionId;
|
|
6708
|
+
}
|
|
6656
6709
|
if (typeof data?.title === "string" && data.title.trim()) this.chatTitle = data.title;
|
|
6657
6710
|
if (typeof data?.agentName === "string" && data.agentName.trim()) this.agentName = data.agentName;
|
|
6658
6711
|
if (typeof data?.extensionId === "string" && data.extensionId.trim()) this.extensionId = data.extensionId;
|
|
@@ -6938,6 +6991,7 @@ ${effect.notification.body || ""}`.trim();
|
|
|
6938
6991
|
this.controlValues = {};
|
|
6939
6992
|
this.currentStatus = "idle";
|
|
6940
6993
|
this.chatId = null;
|
|
6994
|
+
this.providerSessionId = null;
|
|
6941
6995
|
this.chatTitle = null;
|
|
6942
6996
|
this.agentName = "";
|
|
6943
6997
|
this.extensionId = "";
|
|
@@ -7092,6 +7146,7 @@ var IdeProviderInstance = class {
|
|
|
7092
7146
|
workspace: this.workspace || null,
|
|
7093
7147
|
extensions: extensionStates,
|
|
7094
7148
|
cdpConnected: cdp?.isConnected || false,
|
|
7149
|
+
sessionCapabilities: getProviderSessionCapabilities(this.provider, IDE_PROVIDER_SESSION_CAPABILITIES_BASE),
|
|
7095
7150
|
controlValues: surface.controlValues,
|
|
7096
7151
|
providerControls: this.provider.controls,
|
|
7097
7152
|
summaryMetadata: surface.summaryMetadata,
|
|
@@ -8118,27 +8173,8 @@ function isCdpConnected(cdpManagers, key) {
|
|
|
8118
8173
|
}
|
|
8119
8174
|
return false;
|
|
8120
8175
|
}
|
|
8121
|
-
var IDE_SESSION_CAPABILITIES = [
|
|
8122
|
-
|
|
8123
|
-
"send_message",
|
|
8124
|
-
"new_session",
|
|
8125
|
-
"list_sessions",
|
|
8126
|
-
"switch_session",
|
|
8127
|
-
"resolve_action",
|
|
8128
|
-
"change_model",
|
|
8129
|
-
"set_mode",
|
|
8130
|
-
"set_thought_level"
|
|
8131
|
-
];
|
|
8132
|
-
var EXTENSION_SESSION_CAPABILITIES = [
|
|
8133
|
-
"read_chat",
|
|
8134
|
-
"send_message",
|
|
8135
|
-
"new_session",
|
|
8136
|
-
"list_sessions",
|
|
8137
|
-
"switch_session",
|
|
8138
|
-
"resolve_action",
|
|
8139
|
-
"change_model",
|
|
8140
|
-
"set_mode"
|
|
8141
|
-
];
|
|
8176
|
+
var IDE_SESSION_CAPABILITIES = [...IDE_PROVIDER_SESSION_CAPABILITIES_BASE];
|
|
8177
|
+
var EXTENSION_SESSION_CAPABILITIES = [...EXTENSION_PROVIDER_SESSION_CAPABILITIES_BASE];
|
|
8142
8178
|
var PTY_SESSION_CAPABILITIES = [
|
|
8143
8179
|
"read_chat",
|
|
8144
8180
|
"send_message",
|
|
@@ -8182,7 +8218,7 @@ function buildIdeWorkspaceSession(state, cdpManagers, options) {
|
|
|
8182
8218
|
...includeSessionMetadata && { workspace: state.workspace || null },
|
|
8183
8219
|
activeChat,
|
|
8184
8220
|
...summaryMetadata && { summaryMetadata },
|
|
8185
|
-
...includeSessionMetadata && { capabilities: IDE_SESSION_CAPABILITIES },
|
|
8221
|
+
...includeSessionMetadata && { capabilities: state.sessionCapabilities || IDE_SESSION_CAPABILITIES },
|
|
8186
8222
|
cdpConnected: state.cdpConnected ?? isCdpConnected(cdpManagers, state.type),
|
|
8187
8223
|
...includeSessionControls && {
|
|
8188
8224
|
...controlValues && { controlValues },
|
|
@@ -8205,6 +8241,7 @@ function buildExtensionAgentSession(parent, ext, options) {
|
|
|
8205
8241
|
parentId: parent.instanceId || parent.type,
|
|
8206
8242
|
providerType: ext.type,
|
|
8207
8243
|
...includeSessionMetadata && { providerName: ext.name },
|
|
8244
|
+
providerSessionId: ext.providerSessionId,
|
|
8208
8245
|
kind: "agent",
|
|
8209
8246
|
transport: "cdp-webview",
|
|
8210
8247
|
status: normalizeManagedStatus(activeChat?.status || ext.status, {
|
|
@@ -8214,7 +8251,7 @@ function buildExtensionAgentSession(parent, ext, options) {
|
|
|
8214
8251
|
...includeSessionMetadata && { workspace: parent.workspace || null },
|
|
8215
8252
|
activeChat,
|
|
8216
8253
|
...summaryMetadata && { summaryMetadata },
|
|
8217
|
-
...includeSessionMetadata && { capabilities: EXTENSION_SESSION_CAPABILITIES },
|
|
8254
|
+
...includeSessionMetadata && { capabilities: ext.sessionCapabilities || EXTENSION_SESSION_CAPABILITIES },
|
|
8218
8255
|
...includeSessionControls && {
|
|
8219
8256
|
...controlValues && { controlValues },
|
|
8220
8257
|
providerControls: ext.providerControls
|
|
@@ -10132,13 +10169,75 @@ function getCliPresentationMode(h, targetSessionId) {
|
|
|
10132
10169
|
const mode = instance.getPresentationMode?.();
|
|
10133
10170
|
return mode === "chat" || mode === "terminal" ? mode : null;
|
|
10134
10171
|
}
|
|
10135
|
-
|
|
10172
|
+
function normalizeOpenPanelCommandResult(result) {
|
|
10173
|
+
const payload = Object.prototype.hasOwnProperty.call(result, "result") ? result.result : result;
|
|
10174
|
+
if (payload === true) return { opened: true, visible: true, focused: false };
|
|
10175
|
+
if (!payload) return { opened: false, visible: false, focused: false };
|
|
10176
|
+
if (typeof payload === "string") {
|
|
10177
|
+
const normalized = payload.trim().toLowerCase();
|
|
10178
|
+
if (normalized === "visible") return { opened: false, visible: true, focused: false };
|
|
10179
|
+
if (normalized === "focused") return { opened: false, visible: true, focused: true };
|
|
10180
|
+
if (normalized === "opened" || normalized === "open" || normalized === "true" || normalized === "ok" || normalized === "success") {
|
|
10181
|
+
return { opened: true, visible: true, focused: false };
|
|
10182
|
+
}
|
|
10183
|
+
return { opened: false, visible: false, focused: false };
|
|
10184
|
+
}
|
|
10185
|
+
if (typeof payload === "object") {
|
|
10186
|
+
const record = payload;
|
|
10187
|
+
return {
|
|
10188
|
+
opened: record.opened === true,
|
|
10189
|
+
visible: record.visible === true || record.opened === true || record.focused === true,
|
|
10190
|
+
focused: record.focused === true
|
|
10191
|
+
};
|
|
10192
|
+
}
|
|
10193
|
+
return { opened: false, visible: false, focused: false };
|
|
10194
|
+
}
|
|
10195
|
+
function normalizeFocusEditorCommandResult(result) {
|
|
10196
|
+
const payload = Object.prototype.hasOwnProperty.call(result, "result") ? result.result : result;
|
|
10197
|
+
if (payload === true) return { focused: true };
|
|
10198
|
+
if (!payload) return { focused: false };
|
|
10199
|
+
if (typeof payload === "string") {
|
|
10200
|
+
const normalized = payload.trim().toLowerCase();
|
|
10201
|
+
return { focused: normalized === "focused" || normalized === "visible" || normalized === "true" || normalized === "ok" || normalized === "success" };
|
|
10202
|
+
}
|
|
10203
|
+
if (typeof payload === "object") {
|
|
10204
|
+
const record = payload;
|
|
10205
|
+
return { focused: record.focused === true || record.visible === true || record.success === true || record.ok === true };
|
|
10206
|
+
}
|
|
10207
|
+
return { focused: false };
|
|
10208
|
+
}
|
|
10209
|
+
async function handleSelectSession(h, args) {
|
|
10136
10210
|
if (!h.agentStream || !h.getCdp()) return { success: false, error: "AgentStream or CDP not available" };
|
|
10137
10211
|
const sessionId = args?.targetSessionId || h.currentSession?.sessionId;
|
|
10138
10212
|
if (!sessionId) return { success: false, error: "targetSessionId required" };
|
|
10139
|
-
const ok = await h.agentStream.
|
|
10213
|
+
const ok = await h.agentStream.selectSession(h.getCdp(), sessionId);
|
|
10140
10214
|
return { success: ok };
|
|
10141
10215
|
}
|
|
10216
|
+
async function handleOpenPanel(h, args) {
|
|
10217
|
+
const cdp = h.getCdp();
|
|
10218
|
+
if (!cdp) return { success: false, error: "AgentStream or CDP not available" };
|
|
10219
|
+
const sessionId = args?.targetSessionId || h.currentSession?.sessionId;
|
|
10220
|
+
if (!sessionId) return { success: false, error: "targetSessionId required" };
|
|
10221
|
+
const currentTransport = h.currentSession?.transport;
|
|
10222
|
+
const shouldUseAgentStream = !!h.agentStream && currentTransport !== "cdp-page" && currentTransport !== "pty" && currentTransport !== "acp";
|
|
10223
|
+
if (shouldUseAgentStream) {
|
|
10224
|
+
const ok = await h.agentStream.openSessionPanel(cdp, sessionId);
|
|
10225
|
+
return { success: ok };
|
|
10226
|
+
}
|
|
10227
|
+
const openResult = await executeProviderScript(h, args, "openPanel");
|
|
10228
|
+
if (!openResult.success) return openResult;
|
|
10229
|
+
const revealState = normalizeOpenPanelCommandResult(openResult);
|
|
10230
|
+
let focusState = { focused: false };
|
|
10231
|
+
const focusResult = await executeProviderScript(h, args, "focusEditor");
|
|
10232
|
+
if (focusResult.success) {
|
|
10233
|
+
focusState = normalizeFocusEditorCommandResult(focusResult);
|
|
10234
|
+
}
|
|
10235
|
+
return {
|
|
10236
|
+
...openResult,
|
|
10237
|
+
...focusState.focused ? { focused: true } : {},
|
|
10238
|
+
success: revealState.visible || focusState.focused
|
|
10239
|
+
};
|
|
10240
|
+
}
|
|
10142
10241
|
function handlePtyInput(h, args) {
|
|
10143
10242
|
const { cliType, data, targetSessionId } = args || {};
|
|
10144
10243
|
if (!data) return { success: false, error: "data required" };
|
|
@@ -10828,7 +10927,8 @@ var DaemonCommandHandler = class {
|
|
|
10828
10927
|
"change_model",
|
|
10829
10928
|
"set_thought_level",
|
|
10830
10929
|
"resolve_action",
|
|
10831
|
-
"
|
|
10930
|
+
"select_session",
|
|
10931
|
+
"open_panel",
|
|
10832
10932
|
"pty_input",
|
|
10833
10933
|
"pty_resize",
|
|
10834
10934
|
"invoke_provider_script"
|
|
@@ -10926,8 +11026,10 @@ var DaemonCommandHandler = class {
|
|
|
10926
11026
|
case "refresh_scripts":
|
|
10927
11027
|
return this.handleRefreshScripts(args);
|
|
10928
11028
|
// ─── Stream commands (stream-commands.ts) ───────────
|
|
10929
|
-
case "
|
|
10930
|
-
return
|
|
11029
|
+
case "select_session":
|
|
11030
|
+
return handleSelectSession(this, args);
|
|
11031
|
+
case "open_panel":
|
|
11032
|
+
return handleOpenPanel(this, args);
|
|
10931
11033
|
// ─── PTY Raw I/O (stream-commands.ts) ─────────
|
|
10932
11034
|
case "pty_input":
|
|
10933
11035
|
return handlePtyInput(this, args);
|
|
@@ -13624,6 +13726,16 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
13624
13726
|
if (!cliType) throw new Error("cliType required");
|
|
13625
13727
|
const found = this.findAdapter(cliType, { instanceKey: args?.targetSessionId, dir });
|
|
13626
13728
|
if (found) {
|
|
13729
|
+
if (!args?.targetSessionId && !dir) {
|
|
13730
|
+
const matchCount = [...this.adapters.values()].filter((a) => a.cliType === cliType).length;
|
|
13731
|
+
if (matchCount > 1) {
|
|
13732
|
+
return {
|
|
13733
|
+
success: false,
|
|
13734
|
+
error: `Multiple ${cliType} sessions running \u2014 provide targetSessionId to stop a specific session`,
|
|
13735
|
+
code: "AMBIGUOUS_SESSION"
|
|
13736
|
+
};
|
|
13737
|
+
}
|
|
13738
|
+
}
|
|
13627
13739
|
await this.stopSessionWithMode(found.key, mode);
|
|
13628
13740
|
} else {
|
|
13629
13741
|
console.log(colorize("yellow", ` \u26A0 No adapter found for ${cliType}`));
|
|
@@ -13805,6 +13917,7 @@ function validateProviderDefinition(raw) {
|
|
|
13805
13917
|
warnings.push("disableUpstream is deprecated in provider definitions; use machine-level provider source policy instead");
|
|
13806
13918
|
}
|
|
13807
13919
|
const category = provider.category;
|
|
13920
|
+
const typedProvider = provider;
|
|
13808
13921
|
const controls = Array.isArray(provider.controls) ? provider.controls : [];
|
|
13809
13922
|
if (category === "cli" || category === "acp") {
|
|
13810
13923
|
const spawn4 = provider.spawn;
|
|
@@ -13827,6 +13940,9 @@ function validateProviderDefinition(raw) {
|
|
|
13827
13940
|
for (const control of controls) {
|
|
13828
13941
|
validateControl(control, errors);
|
|
13829
13942
|
}
|
|
13943
|
+
if ((category === "ide" || category === "extension") && typeof typedProvider.scripts?.focusEditor === "function" && !providerHasOpenPanelSupport(typedProvider)) {
|
|
13944
|
+
warnings.push("scripts.focusEditor is present without scripts.openPanel/webviewOpenPanel; open_panel capability will remain disabled");
|
|
13945
|
+
}
|
|
13830
13946
|
return { errors, warnings };
|
|
13831
13947
|
}
|
|
13832
13948
|
function validateCapabilities(provider, controls, errors) {
|
|
@@ -15902,8 +16018,8 @@ function buildStatusSnapshot(options) {
|
|
|
15902
16018
|
for (const sourceSession of unreadSourceSessions) {
|
|
15903
16019
|
const session = sessionsById.get(sourceSession.id);
|
|
15904
16020
|
if (!session) continue;
|
|
15905
|
-
const lastSeenAt = getSessionSeenAt(state, sourceSession.id);
|
|
15906
|
-
const seenCompletionMarker = getSessionSeenMarker(state, sourceSession.id);
|
|
16021
|
+
const lastSeenAt = getSessionSeenAt(state, sourceSession.id, sourceSession.providerSessionId);
|
|
16022
|
+
const seenCompletionMarker = getSessionSeenMarker(state, sourceSession.id, sourceSession.providerSessionId);
|
|
15907
16023
|
const lastUsedAt = getSessionLastUsedAt(sourceSession);
|
|
15908
16024
|
const completionMarker = getSessionCompletionMarker(sourceSession);
|
|
15909
16025
|
const { unread, inboxBucket } = sourceSession.surfaceHidden ? { unread: false, inboxBucket: "idle" } : getUnreadState(
|
|
@@ -16719,7 +16835,8 @@ var DaemonCommandRouter = class {
|
|
|
16719
16835
|
currentState,
|
|
16720
16836
|
sessionId,
|
|
16721
16837
|
typeof args?.seenAt === "number" ? args.seenAt : Date.now(),
|
|
16722
|
-
completionMarker
|
|
16838
|
+
completionMarker,
|
|
16839
|
+
targetSession?.providerSessionId
|
|
16723
16840
|
);
|
|
16724
16841
|
if (READ_DEBUG_ENABLED2) {
|
|
16725
16842
|
LOG.info("RecentRead", `mark_session_seen sessionId=${sessionId} seenAt=${String(args?.seenAt || "")} prevSeenAt=${String(prevSeenAt)} nextSeenAt=${String(next.sessionReads?.[sessionId] || 0)} marker=${completionMarker || "-"}`);
|
|
@@ -17152,6 +17269,77 @@ var ProviderStreamAdapter = class {
|
|
|
17152
17269
|
return raw;
|
|
17153
17270
|
}
|
|
17154
17271
|
}
|
|
17272
|
+
getOptionalError(raw) {
|
|
17273
|
+
return typeof raw === "string" && raw.trim() ? raw.trim() : void 0;
|
|
17274
|
+
}
|
|
17275
|
+
normalizeFocusEditorResult(raw) {
|
|
17276
|
+
const data = this.parseMaybeJson(raw);
|
|
17277
|
+
if (data === true) return { focused: true };
|
|
17278
|
+
if (data === false || data == null) return { focused: false };
|
|
17279
|
+
if (typeof data === "string") {
|
|
17280
|
+
const trimmed = data.trim();
|
|
17281
|
+
const normalized = trimmed.toLowerCase();
|
|
17282
|
+
if (normalized === "true" || normalized === "ok" || normalized === "success" || normalized === "focused" || normalized === "visible") {
|
|
17283
|
+
return { focused: true };
|
|
17284
|
+
}
|
|
17285
|
+
if (normalized === "false" || normalized === "not_found" || normalized === "not found" || normalized === "missing" || normalized === "panel_hidden" || normalized === "hidden") {
|
|
17286
|
+
return { focused: false };
|
|
17287
|
+
}
|
|
17288
|
+
return { focused: false, ...trimmed ? { error: trimmed } : {} };
|
|
17289
|
+
}
|
|
17290
|
+
if (data && typeof data === "object") {
|
|
17291
|
+
const error = this.getOptionalError(data.error);
|
|
17292
|
+
if (data.focused === true || data.success === true || data.ok === true || data.visible === true) {
|
|
17293
|
+
return { focused: true };
|
|
17294
|
+
}
|
|
17295
|
+
if (data.focused === false || data.success === false || data.ok === false || error) {
|
|
17296
|
+
return { focused: false, ...error ? { error } : {} };
|
|
17297
|
+
}
|
|
17298
|
+
}
|
|
17299
|
+
return { focused: false };
|
|
17300
|
+
}
|
|
17301
|
+
normalizeOpenPanelResult(raw) {
|
|
17302
|
+
const data = this.parseMaybeJson(raw);
|
|
17303
|
+
if (data === true) return { opened: true, visible: true };
|
|
17304
|
+
if (data === false || data == null) return { opened: false, visible: false };
|
|
17305
|
+
if (typeof data === "string") {
|
|
17306
|
+
const trimmed = data.trim();
|
|
17307
|
+
const normalized = trimmed.toLowerCase();
|
|
17308
|
+
if (normalized === "true" || normalized === "ok" || normalized === "opened" || normalized === "open" || normalized === "success") {
|
|
17309
|
+
return { opened: true, visible: true };
|
|
17310
|
+
}
|
|
17311
|
+
if (normalized === "visible") {
|
|
17312
|
+
return { opened: false, visible: true };
|
|
17313
|
+
}
|
|
17314
|
+
if (normalized === "focused") {
|
|
17315
|
+
return { opened: false, visible: true, focused: true };
|
|
17316
|
+
}
|
|
17317
|
+
if (normalized === "false" || normalized === "panel_hidden" || normalized === "hidden" || normalized === "not_found" || normalized === "not found" || normalized === "missing") {
|
|
17318
|
+
return { opened: false, visible: false };
|
|
17319
|
+
}
|
|
17320
|
+
return { opened: false, visible: false, ...trimmed ? { error: trimmed } : {} };
|
|
17321
|
+
}
|
|
17322
|
+
if (data && typeof data === "object") {
|
|
17323
|
+
const error = this.getOptionalError(data.error);
|
|
17324
|
+
const focused = data.focused === true;
|
|
17325
|
+
const visible = data.visible === true || data.opened === true || focused || data.success === true || data.ok === true;
|
|
17326
|
+
if (visible) {
|
|
17327
|
+
return {
|
|
17328
|
+
opened: data.opened === true,
|
|
17329
|
+
visible: true,
|
|
17330
|
+
...focused ? { focused: true } : {}
|
|
17331
|
+
};
|
|
17332
|
+
}
|
|
17333
|
+
if (data.opened === false || data.visible === false || data.success === false || data.ok === false || error) {
|
|
17334
|
+
return {
|
|
17335
|
+
opened: false,
|
|
17336
|
+
visible: false,
|
|
17337
|
+
...error ? { error } : {}
|
|
17338
|
+
};
|
|
17339
|
+
}
|
|
17340
|
+
}
|
|
17341
|
+
return { opened: false, visible: false };
|
|
17342
|
+
}
|
|
17155
17343
|
summarizeRaw(raw) {
|
|
17156
17344
|
try {
|
|
17157
17345
|
if (typeof raw === "string") return raw.replace(/\s+/g, " ").trim().slice(0, 240);
|
|
@@ -17238,6 +17426,11 @@ var ProviderStreamAdapter = class {
|
|
|
17238
17426
|
if (typeof validated.title === "string" && validated.title.trim()) {
|
|
17239
17427
|
state.title = validated.title.trim();
|
|
17240
17428
|
}
|
|
17429
|
+
const providerSessionId = typeof validated.providerSessionId === "string" && validated.providerSessionId.trim() ? validated.providerSessionId.trim() : "";
|
|
17430
|
+
if (providerSessionId) {
|
|
17431
|
+
state.sessionId = providerSessionId;
|
|
17432
|
+
state.providerSessionId = providerSessionId;
|
|
17433
|
+
}
|
|
17241
17434
|
const controlValues = extractProviderControlValues(this.provider.controls, validated);
|
|
17242
17435
|
const surface = resolveProviderStateSurface({
|
|
17243
17436
|
controlValues,
|
|
@@ -17360,8 +17553,15 @@ var ProviderStreamAdapter = class {
|
|
|
17360
17553
|
}
|
|
17361
17554
|
async focusEditor(evaluate) {
|
|
17362
17555
|
const script = this.callScript("focusEditor");
|
|
17363
|
-
if (!script) return;
|
|
17364
|
-
await evaluate(script);
|
|
17556
|
+
if (!script) return { focused: false };
|
|
17557
|
+
const raw = await evaluate(script);
|
|
17558
|
+
return this.normalizeFocusEditorResult(raw);
|
|
17559
|
+
}
|
|
17560
|
+
async openPanel(evaluate) {
|
|
17561
|
+
const script = this.callScript("openPanel");
|
|
17562
|
+
if (!script) return { opened: false, visible: false };
|
|
17563
|
+
const raw = await evaluate(script);
|
|
17564
|
+
return this.normalizeOpenPanelResult(raw);
|
|
17365
17565
|
}
|
|
17366
17566
|
errorState(message) {
|
|
17367
17567
|
return {
|
|
@@ -17631,19 +17831,33 @@ var DaemonAgentStreamManager = class {
|
|
|
17631
17831
|
return false;
|
|
17632
17832
|
}
|
|
17633
17833
|
}
|
|
17634
|
-
async
|
|
17834
|
+
async selectSession(cdp, sessionId) {
|
|
17635
17835
|
const target = this.getSessionTarget(sessionId);
|
|
17636
17836
|
if (!target?.parentSessionId) return false;
|
|
17637
17837
|
await this.setActiveSession(cdp, target.parentSessionId, sessionId);
|
|
17638
17838
|
await this.syncActiveSession(cdp, target.parentSessionId);
|
|
17839
|
+
return this.managedBySessionId.has(sessionId);
|
|
17840
|
+
}
|
|
17841
|
+
async openSessionPanel(cdp, sessionId) {
|
|
17842
|
+
const selected = await this.selectSession(cdp, sessionId);
|
|
17843
|
+
if (!selected) return false;
|
|
17639
17844
|
const agent = this.managedBySessionId.get(sessionId);
|
|
17640
|
-
if (!agent
|
|
17845
|
+
if (!agent) return false;
|
|
17846
|
+
let panelVisible = false;
|
|
17847
|
+
let editorFocused = false;
|
|
17641
17848
|
try {
|
|
17642
17849
|
const evaluate = (expr, timeout) => cdp.evaluateInSessionFrame(agent.cdpSessionId, expr, timeout);
|
|
17643
|
-
|
|
17644
|
-
|
|
17850
|
+
if (typeof agent.adapter.openPanel === "function") {
|
|
17851
|
+
const result = await agent.adapter.openPanel(evaluate);
|
|
17852
|
+
panelVisible = result.visible;
|
|
17853
|
+
}
|
|
17854
|
+
if (typeof agent.adapter.focusEditor === "function") {
|
|
17855
|
+
const result = await agent.adapter.focusEditor(evaluate);
|
|
17856
|
+
editorFocused = result.focused;
|
|
17857
|
+
}
|
|
17858
|
+
return panelVisible || editorFocused;
|
|
17645
17859
|
} catch (e) {
|
|
17646
|
-
this.logFn(`[AgentStream]
|
|
17860
|
+
this.logFn(`[AgentStream] openPanel(${sessionId}) error: ${e.message}`);
|
|
17647
17861
|
return false;
|
|
17648
17862
|
}
|
|
17649
17863
|
}
|
|
@@ -17869,6 +18083,7 @@ function forwardAgentStreamsToIdeInstance(instanceManager, ideType, streams) {
|
|
|
17869
18083
|
summaryMetadata: stream.summaryMetadata || void 0,
|
|
17870
18084
|
effects: stream.effects || void 0,
|
|
17871
18085
|
sessionId: stream.sessionId || stream.instanceId || void 0,
|
|
18086
|
+
providerSessionId: stream.providerSessionId || stream.sessionId || void 0,
|
|
17872
18087
|
title: stream.title || stream.agentName || void 0,
|
|
17873
18088
|
agentType: stream.agentType || void 0,
|
|
17874
18089
|
agentName: stream.agentName || void 0,
|
|
@@ -18521,9 +18736,14 @@ module.exports.setMode = (params) => {
|
|
|
18521
18736
|
(() => {
|
|
18522
18737
|
try {
|
|
18523
18738
|
const input = document.querySelector('${meta.inputSelector || '[contenteditable="true"]'}');
|
|
18524
|
-
if (input) {
|
|
18525
|
-
|
|
18526
|
-
|
|
18739
|
+
if (input) {
|
|
18740
|
+
input.focus();
|
|
18741
|
+
return JSON.stringify({ focused: true });
|
|
18742
|
+
}
|
|
18743
|
+
return JSON.stringify({ focused: false, error: 'not_found' });
|
|
18744
|
+
} catch(e) {
|
|
18745
|
+
return JSON.stringify({ focused: false, error: e.message });
|
|
18746
|
+
}
|
|
18527
18747
|
})()
|
|
18528
18748
|
`;
|
|
18529
18749
|
files[`${scriptDir}/open_panel.js`] = `/**
|
|
@@ -18534,8 +18754,10 @@ module.exports.setMode = (params) => {
|
|
|
18534
18754
|
(() => {
|
|
18535
18755
|
try {
|
|
18536
18756
|
// TODO: Check if panel visible, if not find toggle button
|
|
18537
|
-
return 'not_found';
|
|
18538
|
-
} catch(e) {
|
|
18757
|
+
return JSON.stringify({ opened: false, visible: false, error: 'not_found' });
|
|
18758
|
+
} catch(e) {
|
|
18759
|
+
return JSON.stringify({ opened: false, visible: false, error: e.message });
|
|
18760
|
+
}
|
|
18539
18761
|
})()
|
|
18540
18762
|
`;
|
|
18541
18763
|
files[`${scriptDir}/resolve_action.js`] = `/**
|
|
@@ -21347,8 +21569,8 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
21347
21569
|
lines.push("| setModel | `{ success: true/false }` |");
|
|
21348
21570
|
lines.push("| listModes | `{ modes: [{ name, id }], current }` |");
|
|
21349
21571
|
lines.push("| setMode | `{ success: true/false }` |");
|
|
21350
|
-
lines.push("| focusEditor | `{ focused: true/false }` |");
|
|
21351
|
-
lines.push("| openPanel | `{ opened: true/false }` |");
|
|
21572
|
+
lines.push("| focusEditor | `{ focused: true/false, error? }` |");
|
|
21573
|
+
lines.push("| openPanel | `{ opened: true/false, visible: true/false, focused?: true, error? }` |");
|
|
21352
21574
|
lines.push("");
|
|
21353
21575
|
lines.push("## \u{1F534} CRITICAL: readChat `status` Lifecycle");
|
|
21354
21576
|
lines.push("The `status` field in readChat controls how the dashboard and daemon auto-approve-loop behave.");
|
|
@@ -22982,8 +23204,8 @@ var DevServer = class _DevServer {
|
|
|
22982
23204
|
lines.push("| setModel | `{ success: true/false }` |");
|
|
22983
23205
|
lines.push("| listModes | `{ modes: [{ name, id }], current }` |");
|
|
22984
23206
|
lines.push("| setMode | `{ success: true/false }` |");
|
|
22985
|
-
lines.push("| focusEditor | `{ focused: true/false }` |");
|
|
22986
|
-
lines.push("| openPanel | `{ opened: true/false }` |");
|
|
23207
|
+
lines.push("| focusEditor | `{ focused: true/false, error? }` |");
|
|
23208
|
+
lines.push("| openPanel | `{ opened: true/false, visible: true/false, focused?: true, error? }` |");
|
|
22987
23209
|
lines.push("");
|
|
22988
23210
|
lines.push("## \u{1F534} CRITICAL: readChat `status` Lifecycle");
|
|
22989
23211
|
lines.push("The `status` field in readChat controls how the dashboard and daemon auto-approve-loop behave.");
|