@adhdev/daemon-core 0.8.70 → 0.8.72
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/chat/chat-signatures.d.ts +34 -0
- package/dist/chat/chat-signatures.js +96 -0
- package/dist/chat/chat-signatures.js.map +1 -0
- package/dist/chat/chat-signatures.mjs +68 -0
- package/dist/chat/chat-signatures.mjs.map +1 -0
- package/dist/chat/subscription-updates.d.ts +50 -0
- package/dist/commands/provider-script-resolver.d.ts +2 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +305 -54
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +297 -54
- package/dist/index.mjs.map +1 -1
- package/dist/providers/provider-session-id.d.ts +2 -0
- package/node_modules/@adhdev/session-host-core/package.json +2 -2
- package/package.json +8 -2
- package/src/chat/chat-signatures.ts +95 -0
- package/src/chat/subscription-updates.ts +218 -0
- package/src/commands/chat-commands.ts +2 -28
- package/src/commands/handler.ts +2 -28
- package/src/commands/provider-script-resolver.ts +40 -0
- package/src/config/state-store.ts +25 -4
- package/src/daemon/dev-server.ts +16 -14
- package/src/index.ts +25 -0
- package/src/providers/cli-provider-instance.ts +9 -6
- package/src/providers/provider-session-id.ts +22 -0
- package/src/session-host/app-name.ts +12 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adhdev/session-host-core",
|
|
3
|
-
"version": "0.8.
|
|
4
|
-
"description": "ADHDev local session host core
|
|
3
|
+
"version": "0.8.72",
|
|
4
|
+
"description": "ADHDev local session host core — session registry, protocol, buffers",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"exports": {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adhdev/daemon-core",
|
|
3
|
-
"version": "0.8.
|
|
4
|
-
"description": "ADHDev daemon core
|
|
3
|
+
"version": "0.8.72",
|
|
4
|
+
"description": "ADHDev daemon core — CDP, IDE detection, providers, command execution",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"exports": {
|
|
@@ -16,6 +16,12 @@
|
|
|
16
16
|
"import": "./dist/status/normalize.mjs",
|
|
17
17
|
"require": "./dist/status/normalize.js",
|
|
18
18
|
"default": "./dist/status/normalize.js"
|
|
19
|
+
},
|
|
20
|
+
"./chat/chat-signatures": {
|
|
21
|
+
"types": "./dist/chat/chat-signatures.d.ts",
|
|
22
|
+
"import": "./dist/chat/chat-signatures.mjs",
|
|
23
|
+
"require": "./dist/chat/chat-signatures.js",
|
|
24
|
+
"default": "./dist/chat/chat-signatures.js"
|
|
19
25
|
}
|
|
20
26
|
},
|
|
21
27
|
"scripts": {
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
export interface ChatMessageSignatureInput {
|
|
2
|
+
id?: string | number | null
|
|
3
|
+
index?: number | null
|
|
4
|
+
role?: string | null
|
|
5
|
+
receivedAt?: string | number | null
|
|
6
|
+
timestamp?: string | number | null
|
|
7
|
+
content?: unknown
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface ChatTailDeliverySignatureInput {
|
|
11
|
+
sessionId: string
|
|
12
|
+
historySessionId?: string
|
|
13
|
+
messages: unknown[]
|
|
14
|
+
status: string
|
|
15
|
+
title?: string
|
|
16
|
+
activeModal?: { message: string; buttons: string[] } | null
|
|
17
|
+
syncMode: string
|
|
18
|
+
replaceFrom: number
|
|
19
|
+
totalMessages: number
|
|
20
|
+
lastMessageSignature: string
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface SessionModalDeliverySignatureInput {
|
|
24
|
+
sessionId: string
|
|
25
|
+
status: string
|
|
26
|
+
title?: string
|
|
27
|
+
modalMessage?: string
|
|
28
|
+
modalButtons?: string[]
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function hashSignatureParts(parts: string[]): string {
|
|
32
|
+
let hash = 0x811c9dc5
|
|
33
|
+
for (const part of parts) {
|
|
34
|
+
const text = String(part || '')
|
|
35
|
+
for (let i = 0; i < text.length; i += 1) {
|
|
36
|
+
hash ^= text.charCodeAt(i)
|
|
37
|
+
hash = Math.imul(hash, 0x01000193) >>> 0
|
|
38
|
+
}
|
|
39
|
+
hash ^= 0xff
|
|
40
|
+
hash = Math.imul(hash, 0x01000193) >>> 0
|
|
41
|
+
}
|
|
42
|
+
return hash.toString(16).padStart(8, '0')
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function stringifySignatureContent(content: unknown): string {
|
|
46
|
+
try {
|
|
47
|
+
return JSON.stringify(content ?? '')
|
|
48
|
+
} catch {
|
|
49
|
+
return String(content ?? '')
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function stringifySignatureMessages(messages: unknown[]): string {
|
|
54
|
+
try {
|
|
55
|
+
return JSON.stringify(messages)
|
|
56
|
+
} catch {
|
|
57
|
+
return String(messages.length)
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function buildChatMessageSignature(message: ChatMessageSignatureInput | null | undefined): string {
|
|
62
|
+
if (!message) return ''
|
|
63
|
+
return hashSignatureParts([
|
|
64
|
+
String(message.id || ''),
|
|
65
|
+
String(message.index ?? ''),
|
|
66
|
+
String(message.role || ''),
|
|
67
|
+
String(message.receivedAt ?? message.timestamp ?? ''),
|
|
68
|
+
stringifySignatureContent(message.content),
|
|
69
|
+
])
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function buildChatTailDeliverySignature(payload: ChatTailDeliverySignatureInput): string {
|
|
73
|
+
return hashSignatureParts([
|
|
74
|
+
payload.sessionId,
|
|
75
|
+
payload.historySessionId || '',
|
|
76
|
+
payload.status,
|
|
77
|
+
payload.title || '',
|
|
78
|
+
payload.syncMode,
|
|
79
|
+
String(payload.replaceFrom),
|
|
80
|
+
String(payload.totalMessages),
|
|
81
|
+
payload.lastMessageSignature,
|
|
82
|
+
payload.activeModal ? `${payload.activeModal.message}|${payload.activeModal.buttons.join('\u001f')}` : '',
|
|
83
|
+
stringifySignatureMessages(payload.messages),
|
|
84
|
+
])
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function buildSessionModalDeliverySignature(payload: SessionModalDeliverySignatureInput): string {
|
|
88
|
+
return hashSignatureParts([
|
|
89
|
+
payload.sessionId,
|
|
90
|
+
payload.status,
|
|
91
|
+
payload.title || '',
|
|
92
|
+
payload.modalMessage || '',
|
|
93
|
+
Array.isArray(payload.modalButtons) ? payload.modalButtons.join('\u001f') : '',
|
|
94
|
+
])
|
|
95
|
+
}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ReadChatCursor,
|
|
3
|
+
ReadChatSyncMode,
|
|
4
|
+
ReadChatSyncResult,
|
|
5
|
+
SessionChatTailUpdate,
|
|
6
|
+
SessionModalUpdate,
|
|
7
|
+
} from '../shared-types.js'
|
|
8
|
+
import {
|
|
9
|
+
buildChatTailDeliverySignature,
|
|
10
|
+
buildSessionModalDeliverySignature,
|
|
11
|
+
} from './chat-signatures.js'
|
|
12
|
+
|
|
13
|
+
export interface ChatTailSubscriptionCursor extends Pick<ReadChatCursor, 'knownMessageCount' | 'lastMessageSignature' | 'tailLimit'> {}
|
|
14
|
+
|
|
15
|
+
export type SessionChatTailCommandResult = Partial<Omit<ReadChatSyncResult, 'activeModal'>> & {
|
|
16
|
+
success?: boolean
|
|
17
|
+
activeModal?: unknown
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface PrepareSessionChatTailUpdateInput {
|
|
21
|
+
key: string
|
|
22
|
+
sessionId: string
|
|
23
|
+
historySessionId?: string
|
|
24
|
+
seq: number
|
|
25
|
+
timestamp: number
|
|
26
|
+
interactionId?: string
|
|
27
|
+
cursor: ChatTailSubscriptionCursor
|
|
28
|
+
lastDeliveredSignature: string
|
|
29
|
+
result: SessionChatTailCommandResult | null | undefined
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface PreparedSessionChatTailUpdate {
|
|
33
|
+
cursor: ChatTailSubscriptionCursor
|
|
34
|
+
seq: number
|
|
35
|
+
lastDeliveredSignature: string
|
|
36
|
+
update: SessionChatTailUpdate | null
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface PrepareSessionModalUpdateInput {
|
|
40
|
+
key: string
|
|
41
|
+
sessionId: string
|
|
42
|
+
status: string
|
|
43
|
+
title?: string
|
|
44
|
+
activeModal?: unknown
|
|
45
|
+
seq: number
|
|
46
|
+
timestamp: number
|
|
47
|
+
interactionId?: string
|
|
48
|
+
lastDeliveredSignature: string
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface PreparedSessionModalUpdate {
|
|
52
|
+
seq: number
|
|
53
|
+
lastDeliveredSignature: string
|
|
54
|
+
update: SessionModalUpdate | null
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function normalizeSyncMode(syncMode: string | undefined): ReadChatSyncMode {
|
|
58
|
+
return syncMode === 'append'
|
|
59
|
+
|| syncMode === 'replace_tail'
|
|
60
|
+
|| syncMode === 'noop'
|
|
61
|
+
|| syncMode === 'full'
|
|
62
|
+
? syncMode
|
|
63
|
+
: 'full'
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function normalizeModalButtons(value: unknown): string[] {
|
|
67
|
+
return Array.isArray(value)
|
|
68
|
+
? value.filter((button): button is string => typeof button === 'string')
|
|
69
|
+
: []
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function normalizeModalMessage(value: unknown): string | undefined {
|
|
73
|
+
return typeof value === 'string' ? value : undefined
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function normalizeChatTailActiveModal(activeModal: unknown): { message: string; buttons: string[] } | null {
|
|
77
|
+
if (!activeModal || typeof activeModal !== 'object') return null
|
|
78
|
+
const message = normalizeModalMessage((activeModal as { message?: unknown }).message)
|
|
79
|
+
if (!message) return null
|
|
80
|
+
const rawButtons = (activeModal as { buttons?: unknown }).buttons
|
|
81
|
+
if (!Array.isArray(rawButtons)) return null
|
|
82
|
+
return {
|
|
83
|
+
message,
|
|
84
|
+
buttons: normalizeModalButtons(rawButtons),
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function normalizeSessionModalFields(activeModal: unknown): { modalMessage?: string; modalButtons: string[] } {
|
|
89
|
+
if (!activeModal || typeof activeModal !== 'object') {
|
|
90
|
+
return { modalButtons: [] }
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
modalMessage: normalizeModalMessage((activeModal as { message?: unknown }).message),
|
|
95
|
+
modalButtons: normalizeModalButtons((activeModal as { buttons?: unknown }).buttons),
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function buildNextChatCursor(
|
|
100
|
+
cursor: ChatTailSubscriptionCursor,
|
|
101
|
+
result: SessionChatTailCommandResult,
|
|
102
|
+
): ChatTailSubscriptionCursor {
|
|
103
|
+
return {
|
|
104
|
+
knownMessageCount: Math.max(0, Number(result.totalMessages || cursor.knownMessageCount)),
|
|
105
|
+
lastMessageSignature: typeof result.lastMessageSignature === 'string'
|
|
106
|
+
? result.lastMessageSignature
|
|
107
|
+
: cursor.lastMessageSignature,
|
|
108
|
+
tailLimit: cursor.tailLimit,
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function prepareSessionChatTailUpdate(
|
|
113
|
+
input: PrepareSessionChatTailUpdateInput,
|
|
114
|
+
): PreparedSessionChatTailUpdate {
|
|
115
|
+
const result = input.result
|
|
116
|
+
if (!result?.success || result.syncMode === 'noop') {
|
|
117
|
+
return {
|
|
118
|
+
cursor: result?.success ? buildNextChatCursor(input.cursor, result) : input.cursor,
|
|
119
|
+
seq: input.seq,
|
|
120
|
+
lastDeliveredSignature: input.lastDeliveredSignature,
|
|
121
|
+
update: null,
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const syncMode = normalizeSyncMode(result.syncMode)
|
|
126
|
+
const cursor = {
|
|
127
|
+
knownMessageCount: Math.max(0, Number(result.totalMessages || 0)),
|
|
128
|
+
lastMessageSignature: typeof result.lastMessageSignature === 'string' ? result.lastMessageSignature : '',
|
|
129
|
+
tailLimit: input.cursor.tailLimit,
|
|
130
|
+
}
|
|
131
|
+
const title = typeof result.title === 'string' ? result.title : undefined
|
|
132
|
+
const activeModal = normalizeChatTailActiveModal(result.activeModal)
|
|
133
|
+
const status = typeof result.status === 'string' ? result.status : 'idle'
|
|
134
|
+
const deliverySignature = buildChatTailDeliverySignature({
|
|
135
|
+
sessionId: input.sessionId,
|
|
136
|
+
...(input.historySessionId ? { historySessionId: input.historySessionId } : {}),
|
|
137
|
+
messages: Array.isArray(result.messages) ? result.messages : [],
|
|
138
|
+
status,
|
|
139
|
+
...(title ? { title } : {}),
|
|
140
|
+
...(activeModal ? { activeModal } : {}),
|
|
141
|
+
syncMode,
|
|
142
|
+
replaceFrom: Number(result.replaceFrom || 0),
|
|
143
|
+
totalMessages: Number(result.totalMessages || 0),
|
|
144
|
+
lastMessageSignature: typeof result.lastMessageSignature === 'string' ? result.lastMessageSignature : '',
|
|
145
|
+
})
|
|
146
|
+
const seq = input.seq + 1
|
|
147
|
+
|
|
148
|
+
if (deliverySignature === input.lastDeliveredSignature) {
|
|
149
|
+
return {
|
|
150
|
+
cursor,
|
|
151
|
+
seq,
|
|
152
|
+
lastDeliveredSignature: input.lastDeliveredSignature,
|
|
153
|
+
update: null,
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return {
|
|
158
|
+
cursor,
|
|
159
|
+
seq,
|
|
160
|
+
lastDeliveredSignature: deliverySignature,
|
|
161
|
+
update: {
|
|
162
|
+
topic: 'session.chat_tail',
|
|
163
|
+
key: input.key,
|
|
164
|
+
sessionId: input.sessionId,
|
|
165
|
+
...(input.historySessionId ? { historySessionId: input.historySessionId } : {}),
|
|
166
|
+
...(input.interactionId ? { interactionId: input.interactionId } : {}),
|
|
167
|
+
seq,
|
|
168
|
+
timestamp: input.timestamp,
|
|
169
|
+
messages: Array.isArray(result.messages) ? result.messages : [],
|
|
170
|
+
status,
|
|
171
|
+
...(title ? { title } : {}),
|
|
172
|
+
...(activeModal ? { activeModal } : {}),
|
|
173
|
+
syncMode,
|
|
174
|
+
replaceFrom: Number(result.replaceFrom || 0),
|
|
175
|
+
totalMessages: Number(result.totalMessages || 0),
|
|
176
|
+
lastMessageSignature: typeof result.lastMessageSignature === 'string' ? result.lastMessageSignature : '',
|
|
177
|
+
},
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export function prepareSessionModalUpdate(
|
|
182
|
+
input: PrepareSessionModalUpdateInput,
|
|
183
|
+
): PreparedSessionModalUpdate {
|
|
184
|
+
const { modalMessage, modalButtons } = normalizeSessionModalFields(input.activeModal)
|
|
185
|
+
const deliverySignature = buildSessionModalDeliverySignature({
|
|
186
|
+
sessionId: input.sessionId,
|
|
187
|
+
status: input.status,
|
|
188
|
+
...(input.title ? { title: input.title } : {}),
|
|
189
|
+
...(modalMessage ? { modalMessage } : {}),
|
|
190
|
+
...(modalButtons.length > 0 ? { modalButtons } : {}),
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
if (deliverySignature === input.lastDeliveredSignature) {
|
|
194
|
+
return {
|
|
195
|
+
seq: input.seq,
|
|
196
|
+
lastDeliveredSignature: input.lastDeliveredSignature,
|
|
197
|
+
update: null,
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const seq = input.seq + 1
|
|
202
|
+
return {
|
|
203
|
+
seq,
|
|
204
|
+
lastDeliveredSignature: deliverySignature,
|
|
205
|
+
update: {
|
|
206
|
+
topic: 'session.modal',
|
|
207
|
+
key: input.key,
|
|
208
|
+
sessionId: input.sessionId,
|
|
209
|
+
status: input.status,
|
|
210
|
+
...(input.title ? { title: input.title } : {}),
|
|
211
|
+
...(modalMessage ? { modalMessage } : {}),
|
|
212
|
+
...(modalButtons.length > 0 ? { modalButtons } : {}),
|
|
213
|
+
...(input.interactionId ? { interactionId: input.interactionId } : {}),
|
|
214
|
+
seq,
|
|
215
|
+
timestamp: input.timestamp,
|
|
216
|
+
},
|
|
217
|
+
}
|
|
218
|
+
}
|
|
@@ -12,6 +12,7 @@ import type { ProviderInstance } from '../providers/provider-instance.js';
|
|
|
12
12
|
import { readChatHistory } from '../config/chat-history.js';
|
|
13
13
|
import { LOG } from '../logging/logger.js';
|
|
14
14
|
import { recordDebugTrace } from '../logging/debug-trace.js';
|
|
15
|
+
import { buildChatMessageSignature } from '../chat/chat-signatures.js';
|
|
15
16
|
import type { ChatMessage } from '../types.js';
|
|
16
17
|
import type { ReadChatCursor, ReadChatSyncMode, SessionTransport } from '../shared-types.js';
|
|
17
18
|
import { normalizeChatMessages } from '../providers/chat-message-normalization.js';
|
|
@@ -19,20 +20,6 @@ import { normalizeChatMessages } from '../providers/chat-message-normalization.j
|
|
|
19
20
|
const RECENT_SEND_WINDOW_MS = 1200;
|
|
20
21
|
const recentSendByTarget = new Map<string, number>();
|
|
21
22
|
|
|
22
|
-
function hashSignatureParts(parts: string[]): string {
|
|
23
|
-
let hash = 0x811c9dc5;
|
|
24
|
-
for (const part of parts) {
|
|
25
|
-
const text = String(part || '');
|
|
26
|
-
for (let i = 0; i < text.length; i += 1) {
|
|
27
|
-
hash ^= text.charCodeAt(i);
|
|
28
|
-
hash = Math.imul(hash, 0x01000193) >>> 0;
|
|
29
|
-
}
|
|
30
|
-
hash ^= 0xff;
|
|
31
|
-
hash = Math.imul(hash, 0x01000193) >>> 0;
|
|
32
|
-
}
|
|
33
|
-
return hash.toString(16).padStart(8, '0');
|
|
34
|
-
}
|
|
35
|
-
|
|
36
23
|
interface ApprovalSelectableInstance extends ProviderInstance {
|
|
37
24
|
recordApprovalSelection?(buttonText: string): void;
|
|
38
25
|
}
|
|
@@ -171,20 +158,7 @@ function parseMaybeJson(value: any): any {
|
|
|
171
158
|
}
|
|
172
159
|
|
|
173
160
|
function getChatMessageSignature(message: ChatMessage | null | undefined): string {
|
|
174
|
-
|
|
175
|
-
let content = '';
|
|
176
|
-
try {
|
|
177
|
-
content = JSON.stringify(message.content ?? '');
|
|
178
|
-
} catch {
|
|
179
|
-
content = String(message.content ?? '');
|
|
180
|
-
}
|
|
181
|
-
return hashSignatureParts([
|
|
182
|
-
String(message.id || ''),
|
|
183
|
-
String(message.index ?? ''),
|
|
184
|
-
String(message.role || ''),
|
|
185
|
-
String(message.receivedAt ?? message.timestamp ?? ''),
|
|
186
|
-
content,
|
|
187
|
-
]);
|
|
161
|
+
return buildChatMessageSignature(message);
|
|
188
162
|
}
|
|
189
163
|
|
|
190
164
|
function normalizeReadChatCursor(args: any): Required<ReadChatCursor> {
|
package/src/commands/handler.ts
CHANGED
|
@@ -24,6 +24,7 @@ import { ChatHistoryWriter } from '../config/chat-history.js';
|
|
|
24
24
|
import type { SessionRegistry, SessionRuntimeTarget } from '../sessions/registry.js';
|
|
25
25
|
import { reconcileIdeRuntimeSessions } from '../sessions/reconcile.js';
|
|
26
26
|
import { LOG } from '../logging/logger.js';
|
|
27
|
+
import { resolveLegacyProviderScript, type LegacyStringScript } from './provider-script-resolver.js';
|
|
27
28
|
|
|
28
29
|
// Sub-module imports
|
|
29
30
|
import * as Chat from './chat-commands.js';
|
|
@@ -68,8 +69,6 @@ export interface CommandHelpers {
|
|
|
68
69
|
readonly historyWriter: ChatHistoryWriter;
|
|
69
70
|
}
|
|
70
71
|
|
|
71
|
-
type LegacyStringScript = (params?: Record<string, unknown> | string) => string;
|
|
72
|
-
|
|
73
72
|
const COMMAND_DEBUG_LEVELS = new Set([
|
|
74
73
|
'pty_input',
|
|
75
74
|
'pty_resize',
|
|
@@ -220,32 +219,7 @@ export class DaemonCommandHandler implements CommandHelpers {
|
|
|
220
219
|
if (provider?.scripts) {
|
|
221
220
|
const fn = provider.scripts[scriptName];
|
|
222
221
|
if (typeof fn === 'function') {
|
|
223
|
-
|
|
224
|
-
if (params && Object.keys(params).length > 0) {
|
|
225
|
-
const firstVal = Object.values(params)[0];
|
|
226
|
-
if (scriptName === 'sendMessage' && typeof firstVal === 'string') {
|
|
227
|
-
const legacyScript = callScript(firstVal);
|
|
228
|
-
if (legacyScript) return legacyScript;
|
|
229
|
-
}
|
|
230
|
-
const script = callScript(params);
|
|
231
|
-
if (script) {
|
|
232
|
-
const likelyLegacyObjectLeak =
|
|
233
|
-
typeof script === 'string'
|
|
234
|
-
&& script.includes('[object Object]')
|
|
235
|
-
&& typeof firstVal === 'string';
|
|
236
|
-
if (!likelyLegacyObjectLeak) return script;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
if (firstVal !== undefined) {
|
|
240
|
-
const legacyScript = callScript(firstVal);
|
|
241
|
-
if (legacyScript) return legacyScript;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
if (script) return script;
|
|
245
|
-
} else {
|
|
246
|
-
const script = callScript();
|
|
247
|
-
if (script) return script;
|
|
248
|
-
}
|
|
222
|
+
return resolveLegacyProviderScript(fn as LegacyStringScript, scriptName, params);
|
|
249
223
|
}
|
|
250
224
|
}
|
|
251
225
|
return null;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export type LegacyStringScript = (params?: Record<string, unknown> | string) => string | null | undefined
|
|
2
|
+
|
|
3
|
+
export function resolveLegacyProviderScript(
|
|
4
|
+
fn: LegacyStringScript | null | undefined,
|
|
5
|
+
scriptName: string,
|
|
6
|
+
params?: Record<string, unknown> | string,
|
|
7
|
+
): string | null {
|
|
8
|
+
if (typeof fn !== 'function') return null
|
|
9
|
+
|
|
10
|
+
if (params && typeof params === 'object' && !Array.isArray(params) && Object.keys(params).length > 0) {
|
|
11
|
+
const firstVal = Object.values(params)[0]
|
|
12
|
+
|
|
13
|
+
if (scriptName === 'sendMessage' && typeof firstVal === 'string') {
|
|
14
|
+
const legacyScript = fn(firstVal)
|
|
15
|
+
if (legacyScript) return legacyScript
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const script = fn(params)
|
|
19
|
+
const likelyLegacyObjectLeak =
|
|
20
|
+
typeof script === 'string'
|
|
21
|
+
&& script.includes('[object Object]')
|
|
22
|
+
&& typeof firstVal === 'string'
|
|
23
|
+
if (!likelyLegacyObjectLeak && script) return script
|
|
24
|
+
|
|
25
|
+
if (firstVal !== undefined) {
|
|
26
|
+
const legacyScript = fn(firstVal as string)
|
|
27
|
+
if (legacyScript) return legacyScript
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (script) return script
|
|
31
|
+
return null
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (params !== undefined) {
|
|
35
|
+
const script = fn(params)
|
|
36
|
+
if (script) return script
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return fn() || null
|
|
40
|
+
}
|
|
@@ -12,6 +12,7 @@ import { join } from 'path';
|
|
|
12
12
|
import { getConfigDir } from './config.js';
|
|
13
13
|
import type { RecentActivityEntry } from './recent-activity.js';
|
|
14
14
|
import type { SavedProviderSessionEntry } from './saved-sessions.js';
|
|
15
|
+
import { isLegacyVolatileSessionReadKey, normalizeProviderSessionId } from '../providers/provider-session-id.js';
|
|
15
16
|
|
|
16
17
|
export interface DaemonState {
|
|
17
18
|
/** Unified recent activity across IDE / CLI / ACP launch flows */
|
|
@@ -42,18 +43,38 @@ function getStatePath(): string {
|
|
|
42
43
|
function normalizeState(raw: unknown): DaemonState {
|
|
43
44
|
const parsed = isPlainObject(raw) ? raw : {};
|
|
44
45
|
|
|
46
|
+
const recentActivity = (Array.isArray(parsed.recentActivity) ? parsed.recentActivity : [])
|
|
47
|
+
.filter((entry): entry is RecentActivityEntry => {
|
|
48
|
+
if (!isPlainObject(entry)) return false;
|
|
49
|
+
const normalizedId = normalizeProviderSessionId(
|
|
50
|
+
typeof entry.providerType === 'string' ? entry.providerType : '',
|
|
51
|
+
typeof entry.providerSessionId === 'string' ? entry.providerSessionId : '',
|
|
52
|
+
);
|
|
53
|
+
if (typeof entry.providerSessionId === 'string' && !normalizedId) return false;
|
|
54
|
+
return true;
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const savedProviderSessions = (Array.isArray(parsed.savedProviderSessions) ? parsed.savedProviderSessions : [])
|
|
58
|
+
.filter((entry): entry is SavedProviderSessionEntry => {
|
|
59
|
+
if (!isPlainObject(entry)) return false;
|
|
60
|
+
return !!normalizeProviderSessionId(
|
|
61
|
+
typeof entry.providerType === 'string' ? entry.providerType : '',
|
|
62
|
+
typeof entry.providerSessionId === 'string' ? entry.providerSessionId : '',
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
|
|
45
66
|
const sessionReads = Object.fromEntries(
|
|
46
67
|
Object.entries(isPlainObject(parsed.sessionReads) ? parsed.sessionReads : {})
|
|
47
|
-
.filter(([, value]) => typeof value === 'number' && Number.isFinite(value as number))
|
|
68
|
+
.filter(([key, value]) => !isLegacyVolatileSessionReadKey(key) && typeof value === 'number' && Number.isFinite(value as number))
|
|
48
69
|
);
|
|
49
70
|
const sessionReadMarkers = Object.fromEntries(
|
|
50
71
|
Object.entries(isPlainObject(parsed.sessionReadMarkers) ? parsed.sessionReadMarkers : {})
|
|
51
|
-
.filter(([, value]) => typeof value === 'string')
|
|
72
|
+
.filter(([key, value]) => !isLegacyVolatileSessionReadKey(key) && typeof value === 'string')
|
|
52
73
|
);
|
|
53
74
|
|
|
54
75
|
return {
|
|
55
|
-
recentActivity
|
|
56
|
-
savedProviderSessions
|
|
76
|
+
recentActivity,
|
|
77
|
+
savedProviderSessions,
|
|
57
78
|
sessionReads,
|
|
58
79
|
sessionReadMarkers,
|
|
59
80
|
};
|
package/src/daemon/dev-server.ts
CHANGED
|
@@ -33,6 +33,7 @@ import { VersionArchive, detectAllVersions } from '../providers/version-archive.
|
|
|
33
33
|
import { LOG } from '../logging/logger.js';
|
|
34
34
|
import { findCdpManager } from '../status/builders.js';
|
|
35
35
|
import { handleCdpEvaluate, handleCdpClick, handleCdpDomQuery, handleScreenshot, handleScriptsRun, handleTypeAndSend, handleTypeAndSendAt, handleScriptHints, handleCdpTargets, handleDomInspect, handleDomChildren, handleDomAnalyze, handleFindCommon, handleFindByText, handleDomContext } from './dev-cdp-handlers.js';
|
|
36
|
+
import { resolveLegacyProviderScript, type LegacyStringScript } from '../commands/provider-script-resolver.js';
|
|
36
37
|
import { handleCliStatus, handleCliLaunch, handleCliSend, handleCliStop, handleCliDebug, handleCliTrace, handleCliExercise, handleCliFixtureCapture, handleCliFixtureList, handleCliFixtureReplay, handleCliResolve, handleCliRaw, handleCliSSE } from './dev-cli-debug.js';
|
|
37
38
|
import { handleAutoImplement, handleAutoImplCancel, handleAutoImplSSE } from './dev-auto-implement.js';
|
|
38
39
|
|
|
@@ -386,7 +387,8 @@ export class DevServer implements DevServerContext {
|
|
|
386
387
|
|
|
387
388
|
public async handleRunScript(type: string, req: http.IncomingMessage, res: http.ServerResponse, parsedBody?: any): Promise<void> {
|
|
388
389
|
const body = parsedBody || await this.readBody(req);
|
|
389
|
-
const { script: scriptName, params, ideType: scriptIdeType } = body;
|
|
390
|
+
const { script: scriptName, params, args, ideType: scriptIdeType } = body;
|
|
391
|
+
const rawParams = args !== undefined ? args : params;
|
|
390
392
|
|
|
391
393
|
const provider = this.providerLoader.resolve(type);
|
|
392
394
|
if (!provider) {
|
|
@@ -407,18 +409,7 @@ export class DevServer implements DevServerContext {
|
|
|
407
409
|
}
|
|
408
410
|
|
|
409
411
|
try {
|
|
410
|
-
|
|
411
|
-
let scriptCode: string | null = null;
|
|
412
|
-
if (['sendMessage', 'webviewSendMessage', 'switchSession', 'webviewSwitchSession', 'setMode', 'webviewSetMode', 'setModel', 'webviewSetModel'].includes(scriptName)) {
|
|
413
|
-
// Production daemon's getProviderScript always unpacks the object and sends the first value
|
|
414
|
-
const firstVal = params && typeof params === 'object' && Object.keys(params).length > 0
|
|
415
|
-
? Object.values(params)[0]
|
|
416
|
-
: params;
|
|
417
|
-
scriptCode = firstVal !== undefined ? fn(firstVal) : fn();
|
|
418
|
-
} else {
|
|
419
|
-
// Scripts like resolveAction are passed the raw parameters object in production
|
|
420
|
-
scriptCode = params !== undefined ? fn(params) : fn();
|
|
421
|
-
}
|
|
412
|
+
const scriptCode = resolveLegacyProviderScript(fn as LegacyStringScript, scriptName, rawParams);
|
|
422
413
|
if (!scriptCode) {
|
|
423
414
|
this.json(res, 500, { error: 'Script function returned null' });
|
|
424
415
|
return;
|
|
@@ -429,12 +420,23 @@ export class DevServer implements DevServerContext {
|
|
|
429
420
|
const isWebviewScript = scriptName.toLowerCase().includes('webview');
|
|
430
421
|
let raw: any;
|
|
431
422
|
if (provider.category === 'extension' && !isWebviewScript) {
|
|
432
|
-
// Extension scripts: prefer
|
|
423
|
+
// Extension scripts: prefer the requested agent webview session.
|
|
433
424
|
const sessions = cdp.getAgentSessions();
|
|
434
425
|
let sessionId: string | null = null;
|
|
435
426
|
for (const [sid, target] of sessions) {
|
|
436
427
|
if (target.agentType === type) { sessionId = sid; break; }
|
|
437
428
|
}
|
|
429
|
+
if (!sessionId) {
|
|
430
|
+
try {
|
|
431
|
+
const discovered = await cdp.discoverAgentWebviews();
|
|
432
|
+
const target = discovered.find((entry) => entry.agentType === type);
|
|
433
|
+
if (target) {
|
|
434
|
+
sessionId = await cdp.attachToAgent(target);
|
|
435
|
+
}
|
|
436
|
+
} catch (error) {
|
|
437
|
+
this.log(`Extension attach fallback failed for ${type}: ${(error as Error)?.message || String(error)}`);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
438
440
|
if (sessionId) {
|
|
439
441
|
raw = await cdp.evaluateInSessionFrame(sessionId, scriptCode);
|
|
440
442
|
} else if (cdp.evaluateInWebviewFrame) {
|
package/src/index.ts
CHANGED
|
@@ -188,6 +188,31 @@ export { DEFAULT_DAEMON_PORT, DAEMON_WS_PATH } from './ipc-protocol.js';
|
|
|
188
188
|
|
|
189
189
|
// ── Chat History ──
|
|
190
190
|
export { readChatHistory } from './config/chat-history.js';
|
|
191
|
+
export {
|
|
192
|
+
hashSignatureParts,
|
|
193
|
+
buildChatMessageSignature,
|
|
194
|
+
buildChatTailDeliverySignature,
|
|
195
|
+
buildSessionModalDeliverySignature,
|
|
196
|
+
} from './chat/chat-signatures.js';
|
|
197
|
+
export type {
|
|
198
|
+
ChatMessageSignatureInput,
|
|
199
|
+
ChatTailDeliverySignatureInput,
|
|
200
|
+
SessionModalDeliverySignatureInput,
|
|
201
|
+
} from './chat/chat-signatures.js';
|
|
202
|
+
export {
|
|
203
|
+
normalizeChatTailActiveModal,
|
|
204
|
+
normalizeSessionModalFields,
|
|
205
|
+
prepareSessionChatTailUpdate,
|
|
206
|
+
prepareSessionModalUpdate,
|
|
207
|
+
} from './chat/subscription-updates.js';
|
|
208
|
+
export type {
|
|
209
|
+
ChatTailSubscriptionCursor,
|
|
210
|
+
PrepareSessionChatTailUpdateInput,
|
|
211
|
+
PreparedSessionChatTailUpdate,
|
|
212
|
+
PrepareSessionModalUpdateInput,
|
|
213
|
+
PreparedSessionModalUpdate,
|
|
214
|
+
SessionChatTailCommandResult,
|
|
215
|
+
} from './chat/subscription-updates.js';
|
|
191
216
|
|
|
192
217
|
// ── Agent Stream ──
|
|
193
218
|
export { DaemonAgentStreamManager } from './agent-stream/index.js';
|
|
@@ -24,6 +24,7 @@ import { buildPersistedProviderEffectMessage, normalizeProviderEffects } from '.
|
|
|
24
24
|
import { formatAutoApprovalMessage, pickApprovalButton } from './approval-utils.js';
|
|
25
25
|
import { getCliScriptCommand, parseCliScriptResult } from './cli-script-results.js';
|
|
26
26
|
import { mergeProviderPatchState, resolveProviderStateSurface } from './provider-patch-state.js';
|
|
27
|
+
import { normalizeProviderSessionId } from './provider-session-id.js';
|
|
27
28
|
import { buildChatMessage, buildRuntimeSystemChatMessage, normalizeChatMessages } from './chat-message-normalization.js';
|
|
28
29
|
|
|
29
30
|
let CachedDatabaseSync: (new (path: string, options?: { readOnly?: boolean }) => {
|
|
@@ -304,9 +305,10 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
304
305
|
const parsedStatus = this.adapter.getScriptParsedStatus?.() || null;
|
|
305
306
|
const autoApproveActive = adapterStatus.status === 'waiting_approval' && this.shouldAutoApprove();
|
|
306
307
|
const visibleStatus = autoApproveActive ? 'generating' : adapterStatus.status;
|
|
307
|
-
const parsedProviderSessionId =
|
|
308
|
-
|
|
309
|
-
: ''
|
|
308
|
+
const parsedProviderSessionId = normalizeProviderSessionId(
|
|
309
|
+
this.type,
|
|
310
|
+
typeof parsedStatus?.providerSessionId === 'string' ? parsedStatus.providerSessionId : '',
|
|
311
|
+
);
|
|
310
312
|
if (parsedProviderSessionId) {
|
|
311
313
|
this.promoteProviderSessionId(parsedProviderSessionId);
|
|
312
314
|
}
|
|
@@ -598,9 +600,10 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
598
600
|
private applyProviderResponse(data: any, options: { phase: 'immediate' | 'turn_completed' }): void {
|
|
599
601
|
if (!data || typeof data !== 'object') return;
|
|
600
602
|
|
|
601
|
-
const patchedProviderSessionId =
|
|
602
|
-
|
|
603
|
-
: ''
|
|
603
|
+
const patchedProviderSessionId = normalizeProviderSessionId(
|
|
604
|
+
this.type,
|
|
605
|
+
typeof data.providerSessionId === 'string' ? data.providerSessionId : '',
|
|
606
|
+
);
|
|
604
607
|
if (patchedProviderSessionId) {
|
|
605
608
|
this.promoteProviderSessionId(patchedProviderSessionId);
|
|
606
609
|
}
|