@adhdev/daemon-core 0.9.63 → 0.9.65
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 +0 -4
- package/dist/chat/chat-signatures.js +0 -4
- package/dist/chat/chat-signatures.js.map +1 -1
- package/dist/chat/chat-signatures.mjs +0 -4
- package/dist/chat/chat-signatures.mjs.map +1 -1
- package/dist/chat/subscription-updates.d.ts +0 -2
- package/dist/cli-adapters/provider-cli-adapter.d.ts +2 -30
- package/dist/cli-adapters/provider-cli-parse.d.ts +1 -8
- package/dist/cli-adapters/provider-cli-shared.d.ts +8 -3
- package/dist/commands/chat-commands.d.ts +0 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +646 -1687
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +646 -1687
- package/dist/index.mjs.map +1 -1
- package/dist/shared-types.d.ts +0 -7
- package/node_modules/@adhdev/session-host-core/package.json +1 -1
- package/package.json +1 -1
- package/src/chat/chat-signatures.ts +0 -8
- package/src/chat/subscription-updates.ts +7 -46
- package/src/cli-adapters/provider-cli-adapter.d.ts +2 -10
- package/src/cli-adapters/provider-cli-adapter.ts +66 -692
- package/src/cli-adapters/provider-cli-parse.d.ts +0 -7
- package/src/cli-adapters/provider-cli-parse.ts +2 -226
- package/src/cli-adapters/provider-cli-shared.d.ts +0 -1
- package/src/cli-adapters/provider-cli-shared.ts +8 -3
- package/src/commands/chat-commands.ts +54 -338
- package/src/daemon/dev-auto-implement.ts +3 -3
- package/src/daemon/dev-server.ts +3 -3
- package/src/index.d.ts +1 -1
- package/src/index.ts +0 -1
- package/src/launch.ts +10 -3
- package/src/providers/cli-provider-instance.ts +2 -39
- package/src/shared-types.d.ts +0 -7
- package/src/shared-types.ts +0 -8
|
@@ -18,8 +18,7 @@ import { LOG, getRecentLogs } from '../logging/logger.js';
|
|
|
18
18
|
import { getRecentDebugTrace, recordDebugTrace } from '../logging/debug-trace.js';
|
|
19
19
|
import { buildChatMessageSignature } from '../chat/chat-signatures.js';
|
|
20
20
|
import type { ChatMessage } from '../types.js';
|
|
21
|
-
import type {
|
|
22
|
-
import { normalizeChatMessages } from '../providers/chat-message-normalization.js';
|
|
21
|
+
import type { SessionTransport } from '../shared-types.js';
|
|
23
22
|
|
|
24
23
|
const RECENT_SEND_WINDOW_MS = 1200;
|
|
25
24
|
export const READ_CHAT_PROVIDER_EVAL_TIMEOUT_MS = 25_000;
|
|
@@ -168,137 +167,16 @@ function getChatMessageSignature(message: ChatMessage | null | undefined): strin
|
|
|
168
167
|
return buildChatMessageSignature(message);
|
|
169
168
|
}
|
|
170
169
|
|
|
171
|
-
function
|
|
172
|
-
const
|
|
173
|
-
|
|
174
|
-
? args.lastMessageSignature
|
|
175
|
-
: '';
|
|
176
|
-
const tailLimit = Math.max(0, Number(args?.tailLimit || 0));
|
|
177
|
-
return { knownMessageCount, lastMessageSignature, tailLimit };
|
|
170
|
+
function normalizeReadChatTailLimit(args: any): number {
|
|
171
|
+
const value = Number(args?.tailLimit || 0);
|
|
172
|
+
return Number.isFinite(value) ? Math.max(0, value) : 0;
|
|
178
173
|
}
|
|
179
174
|
|
|
180
175
|
function normalizeReadChatMessages(payload: Record<string, any>): ChatMessage[] {
|
|
181
176
|
const messages = Array.isArray(payload.messages) ? payload.messages as ChatMessage[] : [];
|
|
182
|
-
return
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
interface ReadChatReplayCollapseInfo {
|
|
186
|
-
role: string;
|
|
187
|
-
kind: string;
|
|
188
|
-
senderName: string;
|
|
189
|
-
content: string;
|
|
190
|
-
signature: string;
|
|
191
|
-
collapsible: boolean;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
function normalizeReadChatReplayTextContent(content: ChatMessage['content'] | undefined): string {
|
|
195
|
-
return flattenContent(content || '').replace(/\s+/g, ' ').trim();
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
function getReadChatReplayCollapseInfo(message: ChatMessage | null | undefined): ReadChatReplayCollapseInfo | null {
|
|
199
|
-
if (!message) return null;
|
|
200
|
-
const role = typeof message.role === 'string' ? message.role.trim().toLowerCase() : '';
|
|
201
|
-
const kind = typeof message.kind === 'string' ? message.kind.trim().toLowerCase() : 'standard';
|
|
202
|
-
const senderName = typeof message.senderName === 'string' ? message.senderName.trim().toLowerCase() : '';
|
|
203
|
-
const collapsible = role === 'assistant' || role === 'system';
|
|
204
|
-
if (!collapsible) return { role, kind, senderName, content: '', signature: '', collapsible };
|
|
205
|
-
const content = normalizeReadChatReplayTextContent(message.content);
|
|
206
|
-
return {
|
|
207
|
-
role,
|
|
208
|
-
kind,
|
|
209
|
-
senderName,
|
|
210
|
-
content,
|
|
211
|
-
signature: `${role}:${kind}:${senderName}:${content}`,
|
|
212
|
-
collapsible,
|
|
213
|
-
};
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
function isStableReadChatAssistantAnswerInfo(info: ReadChatReplayCollapseInfo | null): boolean {
|
|
217
|
-
if (!info) return false;
|
|
218
|
-
if (info.role !== 'assistant') return false;
|
|
219
|
-
if (info.kind && info.kind !== 'standard') return false;
|
|
220
|
-
if (info.content.length < 160) return false;
|
|
221
|
-
|
|
222
|
-
// A provider may surface expanded command output as a standard assistant bubble
|
|
223
|
-
// (for example Claude Code's "Bash command ..." block). That is live work output,
|
|
224
|
-
// not a stable final answer. Treating it as a terminal answer would hide the
|
|
225
|
-
// real final response and violate read_chat fidelity.
|
|
226
|
-
if (/^(bash|shell|terminal) command\b/i.test(info.content)) return false;
|
|
227
|
-
return true;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
function isReplayedAssistantAnswerAfterStableAnswerInfo(
|
|
231
|
-
info: ReadChatReplayCollapseInfo | null,
|
|
232
|
-
stableContent: string,
|
|
233
|
-
): boolean {
|
|
234
|
-
if (!info || !stableContent) return false;
|
|
235
|
-
if (info.role !== 'assistant') return false;
|
|
236
|
-
if (info.kind && info.kind !== 'standard') return false;
|
|
237
|
-
const content = info.content;
|
|
238
|
-
if (content.length < 80 || stableContent.length < 80) return false;
|
|
239
|
-
return content === stableContent || content.startsWith(stableContent) || stableContent.startsWith(content);
|
|
177
|
+
return messages;
|
|
240
178
|
}
|
|
241
179
|
|
|
242
|
-
export function collapseReplayDuplicatesFromReadChat(messages: ChatMessage[]): ChatMessage[] {
|
|
243
|
-
const collapsed: ChatMessage[] = [];
|
|
244
|
-
const replaySignaturesInCurrentTurn = new Set<string>();
|
|
245
|
-
let stableAssistantAnswerContentInCurrentTurn = '';
|
|
246
|
-
let stableAssistantAnswerCollapsedIndex = -1;
|
|
247
|
-
let stableAssistantAnswerHadInterveningActivity = false;
|
|
248
|
-
let previousReplaySignature = '';
|
|
249
|
-
|
|
250
|
-
for (const message of messages) {
|
|
251
|
-
const info = getReadChatReplayCollapseInfo(message);
|
|
252
|
-
if (info?.role === 'user') {
|
|
253
|
-
replaySignaturesInCurrentTurn.clear();
|
|
254
|
-
stableAssistantAnswerContentInCurrentTurn = '';
|
|
255
|
-
stableAssistantAnswerCollapsedIndex = -1;
|
|
256
|
-
stableAssistantAnswerHadInterveningActivity = false;
|
|
257
|
-
previousReplaySignature = '';
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
if (info?.collapsible && info.signature) {
|
|
261
|
-
if (previousReplaySignature === info.signature) continue;
|
|
262
|
-
if (replaySignaturesInCurrentTurn.has(info.signature)) continue;
|
|
263
|
-
if (isReplayedAssistantAnswerAfterStableAnswerInfo(info, stableAssistantAnswerContentInCurrentTurn)) {
|
|
264
|
-
const isAdjacentFullerAssistantAnswer =
|
|
265
|
-
info.role === 'assistant'
|
|
266
|
-
&& (!info.kind || info.kind === 'standard')
|
|
267
|
-
&& stableAssistantAnswerCollapsedIndex >= 0
|
|
268
|
-
&& stableAssistantAnswerCollapsedIndex === collapsed.length - 1
|
|
269
|
-
&& !stableAssistantAnswerHadInterveningActivity
|
|
270
|
-
&& info.content.length > stableAssistantAnswerContentInCurrentTurn.length
|
|
271
|
-
&& info.content.startsWith(stableAssistantAnswerContentInCurrentTurn);
|
|
272
|
-
if (isAdjacentFullerAssistantAnswer) {
|
|
273
|
-
collapsed[stableAssistantAnswerCollapsedIndex] = message;
|
|
274
|
-
replaySignaturesInCurrentTurn.add(info.signature);
|
|
275
|
-
stableAssistantAnswerContentInCurrentTurn = info.content;
|
|
276
|
-
previousReplaySignature = info.signature;
|
|
277
|
-
}
|
|
278
|
-
continue;
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
collapsed.push(message);
|
|
283
|
-
previousReplaySignature = info?.collapsible ? info.signature : '';
|
|
284
|
-
if (info?.collapsible && info.signature) {
|
|
285
|
-
replaySignaturesInCurrentTurn.add(info.signature);
|
|
286
|
-
}
|
|
287
|
-
if (isStableReadChatAssistantAnswerInfo(info)) {
|
|
288
|
-
stableAssistantAnswerContentInCurrentTurn = info?.content || '';
|
|
289
|
-
stableAssistantAnswerCollapsedIndex = collapsed.length - 1;
|
|
290
|
-
stableAssistantAnswerHadInterveningActivity = false;
|
|
291
|
-
} else if (
|
|
292
|
-
stableAssistantAnswerContentInCurrentTurn
|
|
293
|
-
&& info?.role === 'assistant'
|
|
294
|
-
&& (!info.kind || info.kind !== 'standard')
|
|
295
|
-
) {
|
|
296
|
-
stableAssistantAnswerHadInterveningActivity = true;
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
return collapsed;
|
|
301
|
-
}
|
|
302
180
|
|
|
303
181
|
function deriveHistoryDedupKey(message: ChatMessage & { _unitKey?: string; _turnKey?: string }): string | undefined {
|
|
304
182
|
const unitKey = typeof message._unitKey === 'string' ? message._unitKey.trim() : '';
|
|
@@ -334,125 +212,15 @@ function toHistoryPersistedMessages(messages: ChatMessage[]): Array<{
|
|
|
334
212
|
}));
|
|
335
213
|
}
|
|
336
214
|
|
|
337
|
-
function
|
|
338
|
-
if (!signature) return -1;
|
|
339
|
-
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
340
|
-
if (getChatMessageSignature(messages[index]) === signature) {
|
|
341
|
-
return index;
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
return -1;
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
function buildBoundedTailSync(messages: ChatMessage[], cursor: Required<ReadChatCursor>): {
|
|
348
|
-
syncMode: ReadChatSyncMode;
|
|
349
|
-
replaceFrom: number;
|
|
215
|
+
function buildFullTail(messages: ChatMessage[], tailLimit: number): {
|
|
350
216
|
messages: ChatMessage[];
|
|
351
217
|
totalMessages: number;
|
|
352
|
-
lastMessageSignature: string;
|
|
353
218
|
} {
|
|
354
219
|
const totalMessages = messages.length;
|
|
355
|
-
const tailMessages =
|
|
356
|
-
? messages.slice(-cursor.tailLimit)
|
|
357
|
-
: messages;
|
|
220
|
+
const tailMessages = tailLimit > 0 ? messages.slice(-tailLimit) : messages;
|
|
358
221
|
return {
|
|
359
|
-
syncMode: 'full',
|
|
360
|
-
replaceFrom: 0,
|
|
361
222
|
messages: tailMessages,
|
|
362
223
|
totalMessages,
|
|
363
|
-
lastMessageSignature: getChatMessageSignature(messages[totalMessages - 1]),
|
|
364
|
-
};
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
function computeReadChatSync(messages: ChatMessage[], cursor: Required<ReadChatCursor>): {
|
|
368
|
-
syncMode: ReadChatSyncMode;
|
|
369
|
-
replaceFrom: number;
|
|
370
|
-
messages: ChatMessage[];
|
|
371
|
-
totalMessages: number;
|
|
372
|
-
lastMessageSignature: string;
|
|
373
|
-
} {
|
|
374
|
-
const totalMessages = messages.length;
|
|
375
|
-
const lastMessageSignature = getChatMessageSignature(messages[totalMessages - 1]);
|
|
376
|
-
const { knownMessageCount, lastMessageSignature: knownSignature } = cursor;
|
|
377
|
-
|
|
378
|
-
if (!knownMessageCount || !knownSignature) {
|
|
379
|
-
return {
|
|
380
|
-
syncMode: 'full',
|
|
381
|
-
replaceFrom: 0,
|
|
382
|
-
messages,
|
|
383
|
-
totalMessages,
|
|
384
|
-
lastMessageSignature,
|
|
385
|
-
};
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
if (knownMessageCount > totalMessages) {
|
|
389
|
-
return {
|
|
390
|
-
syncMode: 'full',
|
|
391
|
-
replaceFrom: 0,
|
|
392
|
-
messages,
|
|
393
|
-
totalMessages,
|
|
394
|
-
lastMessageSignature,
|
|
395
|
-
};
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
if (knownMessageCount === totalMessages && knownSignature === lastMessageSignature) {
|
|
399
|
-
return {
|
|
400
|
-
syncMode: 'noop',
|
|
401
|
-
replaceFrom: totalMessages,
|
|
402
|
-
messages: [],
|
|
403
|
-
totalMessages,
|
|
404
|
-
lastMessageSignature,
|
|
405
|
-
};
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
if (cursor.tailLimit > 0 && knownSignature === lastMessageSignature) {
|
|
409
|
-
const requestedTailCount = Math.min(totalMessages, cursor.tailLimit);
|
|
410
|
-
if (knownMessageCount >= requestedTailCount) {
|
|
411
|
-
return {
|
|
412
|
-
syncMode: 'noop',
|
|
413
|
-
replaceFrom: totalMessages,
|
|
414
|
-
messages: [],
|
|
415
|
-
totalMessages,
|
|
416
|
-
lastMessageSignature,
|
|
417
|
-
};
|
|
418
|
-
}
|
|
419
|
-
return buildBoundedTailSync(messages, cursor);
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
if (knownMessageCount < totalMessages) {
|
|
423
|
-
const anchorSignature = getChatMessageSignature(messages[knownMessageCount - 1]);
|
|
424
|
-
if (anchorSignature === knownSignature) {
|
|
425
|
-
return {
|
|
426
|
-
syncMode: 'append',
|
|
427
|
-
replaceFrom: knownMessageCount,
|
|
428
|
-
messages: messages.slice(knownMessageCount),
|
|
429
|
-
totalMessages,
|
|
430
|
-
lastMessageSignature,
|
|
431
|
-
};
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
if (cursor.tailLimit > 0) {
|
|
435
|
-
const signatureIndex = findLastMessageIndexBySignature(messages, knownSignature);
|
|
436
|
-
if (signatureIndex >= 0) {
|
|
437
|
-
return {
|
|
438
|
-
syncMode: 'append',
|
|
439
|
-
replaceFrom: knownMessageCount,
|
|
440
|
-
messages: messages.slice(signatureIndex + 1),
|
|
441
|
-
totalMessages,
|
|
442
|
-
lastMessageSignature,
|
|
443
|
-
};
|
|
444
|
-
}
|
|
445
|
-
return buildBoundedTailSync(messages, cursor);
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
const replaceFrom = Math.max(0, Math.min(knownMessageCount - 1, totalMessages));
|
|
450
|
-
return {
|
|
451
|
-
syncMode: replaceFrom === 0 ? 'full' : 'replace_tail',
|
|
452
|
-
replaceFrom,
|
|
453
|
-
messages: replaceFrom === 0 ? messages : messages.slice(replaceFrom),
|
|
454
|
-
totalMessages,
|
|
455
|
-
lastMessageSignature,
|
|
456
224
|
};
|
|
457
225
|
}
|
|
458
226
|
|
|
@@ -492,31 +260,13 @@ function buildReadChatCommandResult(payload: Record<string, any>, args: any): Co
|
|
|
492
260
|
} catch (error: any) {
|
|
493
261
|
return { success: false, error: error?.message || String(error) };
|
|
494
262
|
}
|
|
495
|
-
const messages =
|
|
496
|
-
const
|
|
497
|
-
if (!cursor.knownMessageCount && !cursor.lastMessageSignature && cursor.tailLimit > 0 && messages.length > cursor.tailLimit) {
|
|
498
|
-
const tailMessages = messages.slice(-cursor.tailLimit);
|
|
499
|
-
const lastMessageSignature = getChatMessageSignature(tailMessages[tailMessages.length - 1]);
|
|
500
|
-
return {
|
|
501
|
-
success: true,
|
|
502
|
-
...validatedPayload,
|
|
503
|
-
messages: tailMessages,
|
|
504
|
-
syncMode: 'full',
|
|
505
|
-
replaceFrom: 0,
|
|
506
|
-
totalMessages: messages.length,
|
|
507
|
-
lastMessageSignature,
|
|
508
|
-
...(debugReadChat ? { debugReadChat } : {}),
|
|
509
|
-
};
|
|
510
|
-
}
|
|
511
|
-
const sync = computeReadChatSync(messages, cursor);
|
|
263
|
+
const messages = normalizeReadChatMessages(validatedPayload);
|
|
264
|
+
const sync = buildFullTail(messages, normalizeReadChatTailLimit(args));
|
|
512
265
|
return {
|
|
513
266
|
success: true,
|
|
514
267
|
...validatedPayload,
|
|
515
268
|
messages: sync.messages,
|
|
516
|
-
syncMode: sync.syncMode,
|
|
517
|
-
replaceFrom: sync.replaceFrom,
|
|
518
269
|
totalMessages: sync.totalMessages,
|
|
519
|
-
lastMessageSignature: sync.lastMessageSignature,
|
|
520
270
|
...(debugReadChat ? { debugReadChat } : {}),
|
|
521
271
|
};
|
|
522
272
|
}
|
|
@@ -776,10 +526,6 @@ export async function handleGetChatDebugBundle(h: CommandHelpers, args: any): Pr
|
|
|
776
526
|
status: readResult.status,
|
|
777
527
|
title: readResult.title,
|
|
778
528
|
totalMessages: readResult.totalMessages,
|
|
779
|
-
returnedMessages: Array.isArray(readResult.messages) ? readResult.messages.length : undefined,
|
|
780
|
-
syncMode: readResult.syncMode,
|
|
781
|
-
replaceFrom: readResult.replaceFrom,
|
|
782
|
-
lastMessageSignature: readResult.lastMessageSignature,
|
|
783
529
|
providerSessionId: readResult.providerSessionId,
|
|
784
530
|
transcriptAuthority: readResult.transcriptAuthority,
|
|
785
531
|
coverage: readResult.coverage,
|
|
@@ -903,25 +649,13 @@ function toNonNegativeNumber(value: any): number {
|
|
|
903
649
|
}
|
|
904
650
|
|
|
905
651
|
function getCliVisibleTranscriptCount(adapter: any): number {
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
parsedRecord = parsed && typeof parsed === 'object' ? parsed as Record<string, any> : null;
|
|
913
|
-
} catch {
|
|
914
|
-
parsedRecord = null;
|
|
915
|
-
}
|
|
652
|
+
if (typeof adapter?.getScriptParsedStatus !== 'function') return 0;
|
|
653
|
+
try {
|
|
654
|
+
const parsed = parseMaybeJson(adapter.getScriptParsedStatus());
|
|
655
|
+
return Array.isArray(parsed?.messages) ? parsed.messages.length : 0;
|
|
656
|
+
} catch {
|
|
657
|
+
return 0;
|
|
916
658
|
}
|
|
917
|
-
const parsedMessages = Array.isArray(parsedRecord?.messages) ? parsedRecord.messages : [];
|
|
918
|
-
if (!parsedRecord) return adapterMessages.length;
|
|
919
|
-
const parsedIsProviderAuthoritative = parsedRecord.transcriptAuthority === 'provider'
|
|
920
|
-
|| parsedRecord.coverage === 'full';
|
|
921
|
-
const shouldPreferAdapterMessages = !parsedIsProviderAuthoritative
|
|
922
|
-
&& adapterMessages.length > 0
|
|
923
|
-
&& adapterMessages.length > parsedMessages.length;
|
|
924
|
-
return shouldPreferAdapterMessages ? adapterMessages.length : parsedMessages.length;
|
|
925
659
|
}
|
|
926
660
|
|
|
927
661
|
async function getStableExtensionBaseline(h: CommandHelpers): Promise<any | null> {
|
|
@@ -994,74 +728,56 @@ export async function handleReadChat(h: CommandHelpers, args: any): Promise<Comm
|
|
|
994
728
|
const adapter = getTargetedCliAdapter(h, args, provider?.type);
|
|
995
729
|
if (adapter) {
|
|
996
730
|
_log(`${transport} adapter: ${adapter.cliType}`);
|
|
731
|
+
if (typeof adapter.getScriptParsedStatus !== 'function') {
|
|
732
|
+
return { success: false, error: `${transport} adapter parseSession unavailable` };
|
|
733
|
+
}
|
|
997
734
|
let parsedStatus: any = null;
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
return { success: false, error: error?.message || String(error) };
|
|
1003
|
-
}
|
|
735
|
+
try {
|
|
736
|
+
parsedStatus = parseMaybeJson(adapter.getScriptParsedStatus());
|
|
737
|
+
} catch (error: any) {
|
|
738
|
+
return { success: false, error: error?.message || String(error) };
|
|
1004
739
|
}
|
|
1005
740
|
const parsedRecord = parsedStatus && typeof parsedStatus === 'object'
|
|
1006
741
|
? parsedStatus as Record<string, any>
|
|
1007
742
|
: null;
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
const
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
&& adapterStatus.messages.length > parsedRecord.messages.length;
|
|
1017
|
-
const parsedShowsApproval = hasNonEmptyModalButtons(parsedRecord?.activeModal)
|
|
1018
|
-
&& parsedRecord?.status === 'waiting_approval';
|
|
1019
|
-
const status = parsedRecord
|
|
1020
|
-
? {
|
|
1021
|
-
...parsedRecord,
|
|
1022
|
-
messages: shouldPreferAdapterMessages ? adapterStatus.messages : parsedRecord.messages,
|
|
1023
|
-
status: parsedShowsApproval
|
|
1024
|
-
? parsedRecord.status
|
|
1025
|
-
: (adapterStatus.status !== 'idle'
|
|
1026
|
-
? adapterStatus.status
|
|
1027
|
-
: (parsedRecord.status || adapterStatus.status)),
|
|
1028
|
-
activeModal: parsedRecord.activeModal || adapterStatus.activeModal,
|
|
1029
|
-
}
|
|
1030
|
-
: adapterStatus;
|
|
1031
|
-
|
|
1032
|
-
const title = typeof parsedRecord?.title === 'string' ? parsedRecord.title : undefined;
|
|
1033
|
-
const providerSessionId = typeof parsedRecord?.providerSessionId === 'string'
|
|
743
|
+
if (!parsedRecord || !Array.isArray(parsedRecord.messages)) {
|
|
744
|
+
return { success: false, error: `${transport} parser did not return messages` };
|
|
745
|
+
}
|
|
746
|
+
const adapterStatus = typeof adapter.getStatus === 'function'
|
|
747
|
+
? adapter.getStatus()
|
|
748
|
+
: {};
|
|
749
|
+
const title = typeof parsedRecord.title === 'string' ? parsedRecord.title : undefined;
|
|
750
|
+
const providerSessionId = typeof parsedRecord.providerSessionId === 'string'
|
|
1034
751
|
? parsedRecord.providerSessionId
|
|
1035
752
|
: undefined;
|
|
1036
|
-
const transcriptAuthority = parsedRecord
|
|
753
|
+
const transcriptAuthority = parsedRecord.transcriptAuthority === 'provider' || parsedRecord.transcriptAuthority === 'daemon'
|
|
1037
754
|
? parsedRecord.transcriptAuthority
|
|
1038
755
|
: undefined;
|
|
1039
|
-
const coverage = parsedRecord
|
|
756
|
+
const coverage = parsedRecord.coverage === 'full' || parsedRecord.coverage === 'tail' || parsedRecord.coverage === 'current-turn'
|
|
1040
757
|
? parsedRecord.coverage
|
|
1041
758
|
: undefined;
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
}
|
|
759
|
+
const activeModal = parsedRecord.activeModal ?? parsedRecord.modal ?? null;
|
|
760
|
+
const returnedStatus = parsedRecord.status || 'idle';
|
|
761
|
+
LOG.debug('Command', `[read_chat] cli-like parsed provider=${adapter.cliType} target=${String(args?.targetSessionId || '')} adapterStatus=${String(adapterStatus.status || '')} parsedStatus=${String(parsedRecord.status || '')} parsedMsgCount=${parsedRecord.messages.length}`);
|
|
762
|
+
return buildReadChatCommandResult({
|
|
763
|
+
messages: parsedRecord.messages,
|
|
764
|
+
status: returnedStatus,
|
|
765
|
+
activeModal,
|
|
766
|
+
debugReadChat: {
|
|
767
|
+
provider: adapter.cliType,
|
|
768
|
+
targetSessionId: String(args?.targetSessionId || ''),
|
|
769
|
+
adapterStatus: String(adapterStatus.status || ''),
|
|
770
|
+
parsedStatus: String(parsedRecord.status || ''),
|
|
771
|
+
returnedStatus: String(returnedStatus || ''),
|
|
772
|
+
shouldPreferAdapterMessages: false,
|
|
773
|
+
parsedMsgCount: parsedRecord.messages.length,
|
|
774
|
+
returnedMsgCount: parsedRecord.messages.length,
|
|
775
|
+
},
|
|
776
|
+
...(title ? { title } : {}),
|
|
777
|
+
...(providerSessionId ? { providerSessionId } : {}),
|
|
778
|
+
...(transcriptAuthority ? { transcriptAuthority } : {}),
|
|
779
|
+
...(coverage ? { coverage } : {}),
|
|
780
|
+
}, args);
|
|
1065
781
|
}
|
|
1066
782
|
return { success: false, error: `${transport} adapter not found` };
|
|
1067
783
|
}
|
|
@@ -1098,7 +1098,7 @@ export function buildCliAutoImplPrompt(ctx: DevServerContext,
|
|
|
1098
1098
|
lines.push('');
|
|
1099
1099
|
|
|
1100
1100
|
const funcToFile: Record<string, string> = {
|
|
1101
|
-
|
|
1101
|
+
parseSession: 'parse_session.js',
|
|
1102
1102
|
detectStatus: 'detect_status.js',
|
|
1103
1103
|
parseApproval: 'parse_approval.js',
|
|
1104
1104
|
};
|
|
@@ -1200,7 +1200,7 @@ export function buildCliAutoImplPrompt(ctx: DevServerContext,
|
|
|
1200
1200
|
lines.push('');
|
|
1201
1201
|
lines.push('| Function | Input | Return |');
|
|
1202
1202
|
lines.push('|---|---|---|');
|
|
1203
|
-
lines.push('| `
|
|
1203
|
+
lines.push('| `parseSession` | `{ buffer, rawBuffer, recentBuffer, screenText, messages, partialResponse }` | `{ id, status, title, messages, activeModal }` |');
|
|
1204
1204
|
lines.push('| `detectStatus` | `{ tail, screenText, rawBuffer }` | `idle`, `generating`, `waiting_approval`, or `error` |');
|
|
1205
1205
|
lines.push('| `parseApproval` | `{ buffer, rawBuffer, tail }` | `{ message, buttons }` or `null` |');
|
|
1206
1206
|
lines.push('');
|
|
@@ -1434,7 +1434,7 @@ export function buildCliAutoImplPrompt(ctx: DevServerContext,
|
|
|
1434
1434
|
|
|
1435
1435
|
lines.push('## Required Validation');
|
|
1436
1436
|
lines.push('1. Confirm `detectStatus` changes sensibly between startup, generating, approval, and idle.');
|
|
1437
|
-
lines.push('2. Confirm `
|
|
1437
|
+
lines.push('2. Confirm `parseSession` produces a stable transcript without duplicating past turns when the PTY redraws.');
|
|
1438
1438
|
lines.push('3. Confirm the latest assistant message streams through `partialResponse` while generation is in progress.');
|
|
1439
1439
|
lines.push('4. Confirm approval parsing returns meaningful button labels when the CLI requests permission.');
|
|
1440
1440
|
lines.push('5. Confirm the Python file was actually created and executed, not just described in chat text.');
|
package/src/daemon/dev-server.ts
CHANGED
|
@@ -1367,7 +1367,7 @@ export class DevServer implements DevServerContext {
|
|
|
1367
1367
|
lines.push('');
|
|
1368
1368
|
|
|
1369
1369
|
const funcToFile: Record<string, string> = {
|
|
1370
|
-
|
|
1370
|
+
parseSession: 'parse_session.js',
|
|
1371
1371
|
detectStatus: 'detect_status.js',
|
|
1372
1372
|
parseApproval: 'parse_approval.js',
|
|
1373
1373
|
};
|
|
@@ -1469,7 +1469,7 @@ export class DevServer implements DevServerContext {
|
|
|
1469
1469
|
lines.push('');
|
|
1470
1470
|
lines.push('| Function | Input | Return |');
|
|
1471
1471
|
lines.push('|---|---|---|');
|
|
1472
|
-
lines.push('| `
|
|
1472
|
+
lines.push('| `parseSession` | `{ buffer, rawBuffer, recentBuffer, screenText, messages, partialResponse }` | `{ id, status, title, messages, activeModal }` |');
|
|
1473
1473
|
lines.push('| `detectStatus` | `{ tail, screenText, rawBuffer }` | `idle`, `generating`, `waiting_approval`, or `error` |');
|
|
1474
1474
|
lines.push('| `parseApproval` | `{ buffer, rawBuffer, tail }` | `{ message, buttons }` or `null` |');
|
|
1475
1475
|
lines.push('');
|
|
@@ -1568,7 +1568,7 @@ export class DevServer implements DevServerContext {
|
|
|
1568
1568
|
|
|
1569
1569
|
lines.push('## Required Validation');
|
|
1570
1570
|
lines.push('1. Confirm `detectStatus` changes sensibly between startup, generating, approval, and idle.');
|
|
1571
|
-
lines.push('2. Confirm `
|
|
1571
|
+
lines.push('2. Confirm `parseSession` produces a stable transcript without duplicating past turns when the PTY redraws.');
|
|
1572
1572
|
lines.push('3. Confirm the latest assistant message streams through `partialResponse` while generation is in progress.');
|
|
1573
1573
|
lines.push('4. Confirm approval parsing returns meaningful button labels when the CLI requests permission.');
|
|
1574
1574
|
lines.push('5. Confirm the Python file was actually created and executed, not just described in chat text.');
|
package/src/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Core logic for daemon: CDP, Provider, IDE detection, CLI/ACP adapters and more.
|
|
5
5
|
*/
|
|
6
6
|
export type { ChatBubbleState, ChatMessage, ExtensionInfo, CommandResult as CoreCommandResult, ProviderConfig, DaemonEvent, StatusResponse, SystemInfo, DetectedIde, ProviderInfo, AgentEntry, } from './types.js';
|
|
7
|
-
export type { SessionEntry, CompactSessionEntry, CompactDaemonEntry, SessionTransport, SessionKind, SessionCapability, AgentSessionStream, ReadChatCursor,
|
|
7
|
+
export type { SessionEntry, CompactSessionEntry, CompactDaemonEntry, SessionTransport, SessionKind, SessionCapability, AgentSessionStream, ReadChatCursor, ReadChatSyncResult, TransportTopic, SessionChatTailSubscriptionParams, SessionRuntimeOutputSubscriptionParams, MachineRuntimeSubscriptionParams, SessionHostDiagnosticsSubscriptionParams, SessionModalSubscriptionParams, DaemonMetadataSubscriptionParams, SessionChatTailUpdate, SessionRuntimeOutputUpdate, MachineRuntimeUpdate, SessionHostDiagnosticsUpdate, SessionModalUpdate, DaemonMetadataUpdate, TopicUpdateEnvelope, SubscribeRequest, UnsubscribeRequest, StandaloneWsStatusPayload, AvailableProviderInfo, AcpConfigOption, AcpMode, ProviderControlSchema, StatusReportPayload, MachineInfo, SessionHostDiagnosticsSnapshot, SessionHostRecord, SessionHostWriteOwner, SessionHostAttachedClient, SessionHostLogEntry, SessionHostRequestTrace, SessionHostRuntimeTransition, DetectedIdeInfo, WorkspaceEntry, ProviderSummaryItem, ProviderSummaryMetadata, ProviderState, ProviderStatus, ProviderErrorReason, ActiveChatData, IdeProviderState, CliProviderState, AcpProviderState, ExtensionProviderState, } from './shared-types.js';
|
|
8
8
|
import type { RuntimeWriteOwner as _RuntimeWriteOwner } from './shared-types-extra.js';
|
|
9
9
|
import type { RuntimeAttachedClient as _RuntimeAttachedClient } from './shared-types-extra.js';
|
|
10
10
|
import type { RecentLaunchEntry as _RecentLaunchEntry } from './shared-types.js';
|
package/src/index.ts
CHANGED
package/src/launch.ts
CHANGED
|
@@ -433,12 +433,19 @@ export async function launchWithCdp(options: LaunchOptions = {}): Promise<Launch
|
|
|
433
433
|
}
|
|
434
434
|
}
|
|
435
435
|
|
|
436
|
+
if (!cdpReady) {
|
|
437
|
+
return {
|
|
438
|
+
success: false, ideId: targetIde.id, ideName: targetIde.displayName,
|
|
439
|
+
port, action: 'failed',
|
|
440
|
+
message: '',
|
|
441
|
+
error: `${targetIde.displayName} launched but CDP did not become available on port ${port}`,
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
|
|
436
445
|
return {
|
|
437
446
|
success: true, ideId: targetIde.id, ideName: targetIde.displayName,
|
|
438
447
|
port, action: alreadyRunning ? 'restarted' : 'started',
|
|
439
|
-
message:
|
|
440
|
-
? `${targetIde.displayName} launched with CDP on port ${port}`
|
|
441
|
-
: `${targetIde.displayName} launched (CDP may take a moment to initialize)`,
|
|
448
|
+
message: `${targetIde.displayName} launched with CDP on port ${port}`,
|
|
442
449
|
};
|
|
443
450
|
} catch (e: any) {
|
|
444
451
|
return {
|
|
@@ -378,9 +378,7 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
378
378
|
this.maybeAppendRuntimeRecoveryMessage(runtime);
|
|
379
379
|
let parsedMessages = Array.isArray(parsedStatus?.messages)
|
|
380
380
|
? parsedStatus.messages
|
|
381
|
-
:
|
|
382
|
-
? normalizeChatMessages(Array.isArray(adapterStatus.messages) ? adapterStatus.messages as any : [])
|
|
383
|
-
: []);
|
|
381
|
+
: [];
|
|
384
382
|
const historyMessageCount = Number.isFinite(parsedStatus?.historyMessageCount)
|
|
385
383
|
? Math.max(0, Number(parsedStatus.historyMessageCount))
|
|
386
384
|
: null;
|
|
@@ -389,25 +387,6 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
389
387
|
? parsedMessages.slice(-historyMessageCount)
|
|
390
388
|
: [];
|
|
391
389
|
}
|
|
392
|
-
// committedMessages (adapterStatus.messages) is the adapter's accumulated
|
|
393
|
-
// conversation history — use it as a floor to prevent history from disappearing.
|
|
394
|
-
//
|
|
395
|
-
// waiting_approval: always override — the approval dialog fills the terminal,
|
|
396
|
-
// pushing prior conversation out of view; parsedMessages will be partial or empty
|
|
397
|
-
// regardless of historyMessageCount.
|
|
398
|
-
//
|
|
399
|
-
// Other active states (generating, long_generating, error): apply floor only
|
|
400
|
-
// when the script has not explicitly windowed via historyMessageCount, so
|
|
401
|
-
// intentional windowing is preserved. Excludes idle — scripts may legitimately
|
|
402
|
-
// return messages:[] when the CLI exits or a new session begins.
|
|
403
|
-
const committedMessages = Array.isArray(adapterStatus.messages) ? adapterStatus.messages : [];
|
|
404
|
-
const isActiveNonIdle = adapterStatus.status !== 'idle';
|
|
405
|
-
const shouldApplyCommittedFloor = parsedMessages.length < committedMessages.length
|
|
406
|
-
&& (adapterStatus.status === 'waiting_approval'
|
|
407
|
-
|| (isActiveNonIdle && historyMessageCount === null));
|
|
408
|
-
if (shouldApplyCommittedFloor) {
|
|
409
|
-
parsedMessages = normalizeChatMessages(committedMessages as any);
|
|
410
|
-
}
|
|
411
390
|
const mergedMessages = this.mergeConversationMessages(parsedMessages);
|
|
412
391
|
const canonicalBackedHistory = this.syncCanonicalSavedHistoryIfNeeded();
|
|
413
392
|
|
|
@@ -516,13 +495,9 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
516
495
|
const autoApproveActive = adapterStatus.status === 'waiting_approval' && this.shouldAutoApprove();
|
|
517
496
|
const visibleStatus = autoApproveActive ? 'generating' : adapterStatus.status;
|
|
518
497
|
const runtime = this.adapter.getRuntimeMetadata();
|
|
519
|
-
const lastCommittedMessageActivityAt = typeof this.adapter.getLastCommittedMessageActivityAt === 'function'
|
|
520
|
-
? this.adapter.getLastCommittedMessageActivityAt()
|
|
521
|
-
: 0;
|
|
522
498
|
return {
|
|
523
499
|
id: this.instanceId,
|
|
524
500
|
status: visibleStatus,
|
|
525
|
-
lastMessageAt: lastCommittedMessageActivityAt || undefined,
|
|
526
501
|
runtimeLifecycle: runtime?.lifecycle ?? null,
|
|
527
502
|
runtimeSurfaceKind: runtime?.surfaceKind,
|
|
528
503
|
runtimeRestoredFromStorage: runtime?.restoredFromStorage === true,
|
|
@@ -643,7 +618,7 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
643
618
|
const chatTitle = `${this.provider.name} · ${dirName}`;
|
|
644
619
|
const partial = this.adapter.getPartialResponse();
|
|
645
620
|
const progressFingerprint = newStatus === 'generating'
|
|
646
|
-
? `${partial || ''}
|
|
621
|
+
? `${partial || ''}`.slice(-2000)
|
|
647
622
|
: undefined;
|
|
648
623
|
|
|
649
624
|
const previousStatus = this.lastStatus;
|
|
@@ -1136,18 +1111,6 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
1136
1111
|
receivedAt: message.receivedAt,
|
|
1137
1112
|
}));
|
|
1138
1113
|
this.suppressIdleHistoryReplay = restoredHistory.messages.length > 0;
|
|
1139
|
-
if (restoredHistory.messages.length > 0) {
|
|
1140
|
-
this.adapter.seedCommittedMessages(
|
|
1141
|
-
restoredHistory.messages.map((message) => ({
|
|
1142
|
-
role: message.role,
|
|
1143
|
-
content: message.content,
|
|
1144
|
-
timestamp: message.receivedAt,
|
|
1145
|
-
receivedAt: message.receivedAt,
|
|
1146
|
-
kind: message.kind,
|
|
1147
|
-
senderName: message.senderName,
|
|
1148
|
-
})),
|
|
1149
|
-
);
|
|
1150
|
-
}
|
|
1151
1114
|
}
|
|
1152
1115
|
|
|
1153
1116
|
|