@adhdev/daemon-core 0.9.64 → 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 -1712
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +646 -1712
- 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 -366
- 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
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Required scripts in scripts/{version}/scripts.js:
|
|
8
8
|
* - detectStatus(input) → AgentStatus string ('idle' | 'generating' | 'waiting_approval')
|
|
9
|
-
* -
|
|
9
|
+
* - parseSession(input) → ReadChatResult { messages, status, activeModal, ... }
|
|
10
10
|
* - parseApproval(input) → ModalInfo | null
|
|
11
11
|
*
|
|
12
12
|
* provider.json contract:
|
|
@@ -30,14 +30,11 @@ import {
|
|
|
30
30
|
compactPromptText,
|
|
31
31
|
estimatePromptDisplayLines,
|
|
32
32
|
extractPromptRetrySnippet,
|
|
33
|
-
getLastUserPromptText,
|
|
34
33
|
listCliScriptNames,
|
|
35
|
-
normalizeComparableMessageContent,
|
|
36
34
|
normalizePromptText,
|
|
37
35
|
normalizeScreenSnapshot,
|
|
38
36
|
promptLikelyVisible,
|
|
39
37
|
sanitizeTerminalText,
|
|
40
|
-
trimPromptEchoPrefix,
|
|
41
38
|
type CliChatMessage,
|
|
42
39
|
type CliProviderModule,
|
|
43
40
|
type CliScriptInput,
|
|
@@ -46,12 +43,9 @@ import {
|
|
|
46
43
|
type CliTraceEntry,
|
|
47
44
|
type ParsedSession,
|
|
48
45
|
} from './provider-cli-shared.js';
|
|
49
|
-
import { buildChatMessage } from '../providers/chat-message-normalization.js';
|
|
50
|
-
import { validateReadChatResultPayload } from '../providers/read-chat-contract.js';
|
|
51
46
|
import {
|
|
52
47
|
buildCliParseInput,
|
|
53
48
|
buildCliTraceParseSnapshot,
|
|
54
|
-
hydrateCliParsedMessages,
|
|
55
49
|
normalizeCliParsedMessages,
|
|
56
50
|
summarizeCliTraceMessages,
|
|
57
51
|
summarizeCliTraceText,
|
|
@@ -82,10 +76,6 @@ export {
|
|
|
82
76
|
type CliTraceEntry,
|
|
83
77
|
} from './provider-cli-shared.js';
|
|
84
78
|
|
|
85
|
-
type SeedCliChatMessage = Omit<Partial<CliChatMessage>, 'role'> & {
|
|
86
|
-
role?: string;
|
|
87
|
-
content?: string;
|
|
88
|
-
};
|
|
89
79
|
|
|
90
80
|
interface IdleFinishCandidate {
|
|
91
81
|
armedAt: number;
|
|
@@ -119,49 +109,6 @@ interface SendMessageCompletion {
|
|
|
119
109
|
rejectOnce: (error: unknown) => void;
|
|
120
110
|
}
|
|
121
111
|
|
|
122
|
-
function normalizeComparableTranscriptText(value: unknown): string {
|
|
123
|
-
return sanitizeTerminalText(String(value || ''))
|
|
124
|
-
.replace(/\s+/g, ' ')
|
|
125
|
-
.trim();
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
function hasVisibleInterruptPrompt(text: string): boolean {
|
|
129
|
-
const interruptCopyPattern = /\bEnter\s+to\s+interrupt\b(?:\s*,?\s*Ctrl\s*(?:\+|-)?\s*C\s+to\s+cancel)?/i;
|
|
130
|
-
return sanitizeTerminalText(text || '')
|
|
131
|
-
.split(/\r?\n/g)
|
|
132
|
-
.some((line) => {
|
|
133
|
-
const trimmed = line.trim();
|
|
134
|
-
if (!interruptCopyPattern.test(trimmed)) return false;
|
|
135
|
-
return /^(?:[^A-Za-z0-9\s]{1,8}\s+)?[❯›>]\s+/.test(trimmed);
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
function parsedTranscriptIsRicherThanCommitted(
|
|
140
|
-
parsedMessages: Array<{ role?: string; content?: unknown; id?: string; index?: number }> | null | undefined,
|
|
141
|
-
committedMessages: Array<{ role?: string; content?: unknown; id?: string; index?: number }> | null | undefined,
|
|
142
|
-
): boolean {
|
|
143
|
-
if (!Array.isArray(parsedMessages) || !Array.isArray(committedMessages)) return false;
|
|
144
|
-
if (parsedMessages.length > committedMessages.length) return true;
|
|
145
|
-
if (parsedMessages.length !== committedMessages.length) return false;
|
|
146
|
-
|
|
147
|
-
for (let index = 0; index < parsedMessages.length; index += 1) {
|
|
148
|
-
const parsed = parsedMessages[index];
|
|
149
|
-
const committed = committedMessages[index];
|
|
150
|
-
if (!parsed || !committed) return false;
|
|
151
|
-
if ((parsed.role || '') !== (committed.role || '')) return false;
|
|
152
|
-
if (parsed.id && committed.id && String(parsed.id) !== String(committed.id)) return false;
|
|
153
|
-
if (typeof parsed.index === 'number' && typeof committed.index === 'number' && parsed.index !== committed.index) return false;
|
|
154
|
-
|
|
155
|
-
const parsedText = normalizeComparableTranscriptText(parsed.content);
|
|
156
|
-
const committedText = normalizeComparableTranscriptText(committed.content);
|
|
157
|
-
if (!parsedText || !committedText || parsedText === committedText) continue;
|
|
158
|
-
if (parsedText.length > committedText.length && parsedText.startsWith(committedText)) return true;
|
|
159
|
-
return false;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
return false;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
112
|
export function appendBoundedText(current: string, chunk: string, maxChars: number): string {
|
|
166
113
|
if (!chunk) return current.length <= maxChars ? current : current.slice(-maxChars);
|
|
167
114
|
if (maxChars <= 0) return '';
|
|
@@ -171,88 +118,6 @@ export function appendBoundedText(current: string, chunk: string, maxChars: numb
|
|
|
171
118
|
return current.slice(-keepFromCurrent) + chunk;
|
|
172
119
|
}
|
|
173
120
|
|
|
174
|
-
const COMMITTED_ACTIVITY_PREFIX_BLOCK_RE = /^(?:📖|💻|🔎|📚|📋|✏️|📝|🔧|🛠️|⚙️)\s+(.+)$/;
|
|
175
|
-
|
|
176
|
-
function isLikelyCommittedActivityPrefixContinuation(line: string): boolean {
|
|
177
|
-
const trimmed = String(line || '').trim();
|
|
178
|
-
if (!trimmed) return false;
|
|
179
|
-
if (COMMITTED_ACTIVITY_PREFIX_BLOCK_RE.test(trimmed)) return false;
|
|
180
|
-
if (/\s/.test(trimmed)) return false;
|
|
181
|
-
if (/[가-힣]/.test(trimmed)) return false;
|
|
182
|
-
if (trimmed.length > 96) return false;
|
|
183
|
-
return /^[A-Za-z0-9_./:@+%=-]+$/.test(trimmed);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
function parseCommittedActivityPrefixBlock(lines: string[], index: number): { label: string; nextIndex: number } | null {
|
|
187
|
-
const first = String(lines[index] || '').trim();
|
|
188
|
-
if (!COMMITTED_ACTIVITY_PREFIX_BLOCK_RE.test(first)) return null;
|
|
189
|
-
const parts = [first];
|
|
190
|
-
let nextIndex = index + 1;
|
|
191
|
-
while (nextIndex < lines.length && isLikelyCommittedActivityPrefixContinuation(lines[nextIndex])) {
|
|
192
|
-
parts.push(String(lines[nextIndex] || '').trim());
|
|
193
|
-
nextIndex += 1;
|
|
194
|
-
}
|
|
195
|
-
return { label: parts.join(''), nextIndex };
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
export function sanitizeCliStandardMessageContent(content: unknown): string {
|
|
199
|
-
const source = String(content || '').trim();
|
|
200
|
-
if (!source) return '';
|
|
201
|
-
const lines = source.split(/\r?\n/);
|
|
202
|
-
if (lines.length < 4) return source;
|
|
203
|
-
|
|
204
|
-
const counts = new Map<string, number>();
|
|
205
|
-
for (let index = 0; index < lines.length; index += 1) {
|
|
206
|
-
const block = parseCommittedActivityPrefixBlock(lines, index);
|
|
207
|
-
if (!block) continue;
|
|
208
|
-
counts.set(block.label, (counts.get(block.label) || 0) + 1);
|
|
209
|
-
index = block.nextIndex - 1;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
const repeatedLabels = new Set(
|
|
213
|
-
Array.from(counts.entries())
|
|
214
|
-
.filter(([, count]) => count >= 3)
|
|
215
|
-
.map(([label]) => label),
|
|
216
|
-
);
|
|
217
|
-
if (repeatedLabels.size === 0) return source;
|
|
218
|
-
|
|
219
|
-
const stripped: string[] = [];
|
|
220
|
-
let removed = 0;
|
|
221
|
-
for (let index = 0; index < lines.length; index += 1) {
|
|
222
|
-
const block = parseCommittedActivityPrefixBlock(lines, index);
|
|
223
|
-
if (block && repeatedLabels.has(block.label)) {
|
|
224
|
-
removed += 1;
|
|
225
|
-
index = block.nextIndex - 1;
|
|
226
|
-
continue;
|
|
227
|
-
}
|
|
228
|
-
stripped.push(lines[index]);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
const next = stripped.join('\n').replace(/\n{3,}/g, '\n\n').trim();
|
|
232
|
-
return removed >= 3 && next.length >= 80 ? next : source;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
function sanitizeCommittedMessageForDisplay<T extends { role?: string; kind?: string; content?: unknown }>(message: T): T {
|
|
236
|
-
if (!message || message.role !== 'assistant' || (message.kind || 'standard') !== 'standard') return message;
|
|
237
|
-
const content = sanitizeCliStandardMessageContent(message.content);
|
|
238
|
-
if (content === message.content) return message;
|
|
239
|
-
return { ...message, content };
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
export function trimLastAssistantEchoForCliMessages(messages: CliChatMessage[], prompt: string | undefined): void {
|
|
243
|
-
if (!prompt) return;
|
|
244
|
-
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
245
|
-
const message = messages[index];
|
|
246
|
-
if (!message || message.role !== 'assistant' || typeof message.content !== 'string') continue;
|
|
247
|
-
if ((message.kind || 'standard') !== 'standard') continue;
|
|
248
|
-
message.content = trimPromptEchoPrefix(message.content, prompt);
|
|
249
|
-
if (!message.content.trim()) {
|
|
250
|
-
messages.splice(index, 1);
|
|
251
|
-
}
|
|
252
|
-
return;
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
121
|
// ─── Adapter ────────────────────────────────────────
|
|
257
122
|
|
|
258
123
|
export class ProviderCliAdapter implements CliAdapter {
|
|
@@ -263,11 +128,6 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
263
128
|
private provider: CliProviderModule;
|
|
264
129
|
private ptyProcess: PtyRuntimeTransport | null = null;
|
|
265
130
|
private transportFactory: PtyTransportFactory;
|
|
266
|
-
private messages: CliChatMessage[] = [];
|
|
267
|
-
private committedMessages: CliChatMessage[] = [];
|
|
268
|
-
private structuredMessages: CliChatMessage[] = [];
|
|
269
|
-
private committedMessagesActivitySignature = '';
|
|
270
|
-
private committedMessagesChangedAt = 0;
|
|
271
131
|
private currentStatus: CliSessionStatus['status'] = 'starting';
|
|
272
132
|
private onStatusChange: (() => void) | null = null;
|
|
273
133
|
|
|
@@ -356,7 +216,6 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
356
216
|
private traceSeq = 0;
|
|
357
217
|
private traceSessionId = '';
|
|
358
218
|
private parsedStatusCache: {
|
|
359
|
-
committedMessagesRef: CliChatMessage[];
|
|
360
219
|
responseBuffer: string;
|
|
361
220
|
currentTurnScope: TurnParseScope | null;
|
|
362
221
|
recentOutputBuffer: string;
|
|
@@ -367,11 +226,8 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
367
226
|
cliName: string;
|
|
368
227
|
result: any;
|
|
369
228
|
} | null = null;
|
|
370
|
-
private lastStatusHotPathParseAt = Number.NEGATIVE_INFINITY;
|
|
371
|
-
private static readonly STATUS_HOT_PATH_PARSE_MIN_INTERVAL_MS = 1000;
|
|
372
229
|
private static readonly SCREEN_SNAPSHOT_MIN_INTERVAL_MS = 250;
|
|
373
230
|
private static readonly MAX_TRACE_ENTRIES = 250;
|
|
374
|
-
private static readonly PARSE_MESSAGE_TAIL_LIMIT = 100;
|
|
375
231
|
|
|
376
232
|
private readonly providerResolutionMeta: ProviderResolutionMeta;
|
|
377
233
|
private static readonly FINISH_RETRY_DELAY_MS = 300;
|
|
@@ -398,37 +254,6 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
398
254
|
return Math.max(0, (previousLength + appendedLength) - nextLength);
|
|
399
255
|
}
|
|
400
256
|
|
|
401
|
-
private buildCommittedMessagesActivitySignature(): string {
|
|
402
|
-
const last = this.committedMessages[this.committedMessages.length - 1];
|
|
403
|
-
return [
|
|
404
|
-
String(this.committedMessages.length),
|
|
405
|
-
String(last?.role || ''),
|
|
406
|
-
String(last?.kind || ''),
|
|
407
|
-
String(last?.senderName || ''),
|
|
408
|
-
String(last?.timestamp || ''),
|
|
409
|
-
String(last?.receivedAt || ''),
|
|
410
|
-
normalizeComparableMessageContent(last?.content || '').slice(-240),
|
|
411
|
-
].join('|');
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
private syncMessageViews(): void {
|
|
415
|
-
const signature = this.buildCommittedMessagesActivitySignature();
|
|
416
|
-
if (signature !== this.committedMessagesActivitySignature) {
|
|
417
|
-
this.committedMessagesActivitySignature = signature;
|
|
418
|
-
this.committedMessagesChangedAt = Date.now();
|
|
419
|
-
}
|
|
420
|
-
this.messages = [...this.committedMessages];
|
|
421
|
-
this.structuredMessages = [...this.committedMessages];
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
getLastCommittedMessageActivityAt(): number {
|
|
425
|
-
const last = this.committedMessages[this.committedMessages.length - 1];
|
|
426
|
-
const messageTime = Math.max(
|
|
427
|
-
typeof last?.receivedAt === 'number' && Number.isFinite(last.receivedAt) ? last.receivedAt : 0,
|
|
428
|
-
typeof last?.timestamp === 'number' && Number.isFinite(last.timestamp) ? last.timestamp : 0,
|
|
429
|
-
);
|
|
430
|
-
return Math.max(messageTime, this.committedMessagesChangedAt || 0);
|
|
431
|
-
}
|
|
432
257
|
|
|
433
258
|
private readTerminalScreenText(now = Date.now()): string {
|
|
434
259
|
const screenText = this.terminalScreen.getText() || '';
|
|
@@ -454,7 +279,6 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
454
279
|
const cached = this.parsedStatusCache;
|
|
455
280
|
if (
|
|
456
281
|
cached
|
|
457
|
-
&& cached.committedMessagesRef === this.committedMessages
|
|
458
282
|
&& cached.responseBuffer === this.responseBuffer
|
|
459
283
|
&& cached.currentTurnScope === this.currentTurnScope
|
|
460
284
|
&& cached.recentOutputBuffer === this.recentOutputBuffer
|
|
@@ -477,58 +301,6 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
477
301
|
return this.providerOwnsTranscript() && this.provider.transcriptContext === 'full';
|
|
478
302
|
}
|
|
479
303
|
|
|
480
|
-
private selectParseBaseMessages(baseMessages: CliChatMessage[]): CliChatMessage[] {
|
|
481
|
-
if (this.shouldUseFullProviderTranscriptContext()) return baseMessages;
|
|
482
|
-
if (baseMessages.length <= ProviderCliAdapter.PARSE_MESSAGE_TAIL_LIMIT) return baseMessages;
|
|
483
|
-
return baseMessages.slice(-ProviderCliAdapter.PARSE_MESSAGE_TAIL_LIMIT);
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
private messagesShareStableIdentity(left: any, right: any): boolean {
|
|
487
|
-
if (left === right) return true;
|
|
488
|
-
if (!left || !right) return false;
|
|
489
|
-
if ((left.role || '') !== (right.role || '')) return false;
|
|
490
|
-
if (left.id && right.id && String(left.id) === String(right.id)) return true;
|
|
491
|
-
if (typeof left.index === 'number' && typeof right.index === 'number' && left.index === right.index) return true;
|
|
492
|
-
return false;
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
private messagesComparable(left: any, right: any): boolean {
|
|
496
|
-
if (this.messagesShareStableIdentity(left, right)) return true;
|
|
497
|
-
if (!left || !right) return false;
|
|
498
|
-
if ((left.role || '') !== (right.role || '')) return false;
|
|
499
|
-
const leftText = normalizeComparableTranscriptText(left.content);
|
|
500
|
-
const rightText = normalizeComparableTranscriptText(right.content);
|
|
501
|
-
return !!leftText && leftText === rightText;
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
private stitchParsedMessagesWithCommittedBase(
|
|
505
|
-
parsedMessages: any[],
|
|
506
|
-
fullBaseMessages: CliChatMessage[],
|
|
507
|
-
parseBaseMessages: CliChatMessage[],
|
|
508
|
-
): any[] {
|
|
509
|
-
if (!Array.isArray(parsedMessages) || parsedMessages.length === 0) return parsedMessages;
|
|
510
|
-
if (fullBaseMessages.length <= parseBaseMessages.length) return parsedMessages;
|
|
511
|
-
|
|
512
|
-
const parsedFirst = parsedMessages[0];
|
|
513
|
-
const fullFirst = fullBaseMessages[0];
|
|
514
|
-
if (parsedMessages.length >= fullBaseMessages.length && this.messagesComparable(parsedFirst, fullFirst)) {
|
|
515
|
-
return parsedMessages;
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
const tailFirst = parseBaseMessages[0];
|
|
519
|
-
if (tailFirst && this.messagesComparable(parsedFirst, tailFirst)) {
|
|
520
|
-
const prefixLength = fullBaseMessages.length - parseBaseMessages.length;
|
|
521
|
-
const prefix = fullBaseMessages.slice(0, prefixLength);
|
|
522
|
-
const shouldSanitizePrefix = !!this.currentTurnScope || this.currentStatus !== 'idle' || !!this.activeModal;
|
|
523
|
-
const nextPrefix = shouldSanitizePrefix
|
|
524
|
-
? prefix.map((message) => sanitizeCommittedMessageForDisplay(message))
|
|
525
|
-
: prefix;
|
|
526
|
-
return [...nextPrefix, ...parsedMessages];
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
return [...fullBaseMessages, ...parsedMessages];
|
|
530
|
-
}
|
|
531
|
-
|
|
532
304
|
private getIdleFinishConfirmMs(): number {
|
|
533
305
|
return this.timeouts.idleFinishConfirm;
|
|
534
306
|
}
|
|
@@ -1102,10 +874,6 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1102
874
|
);
|
|
1103
875
|
}
|
|
1104
876
|
|
|
1105
|
-
private trimLastAssistantEcho(messages: CliChatMessage[], prompt: string | undefined): void {
|
|
1106
|
-
trimLastAssistantEchoForCliMessages(messages, prompt);
|
|
1107
|
-
}
|
|
1108
|
-
|
|
1109
877
|
private clearAllTimers(): void {
|
|
1110
878
|
if (this.responseTimeout) { clearTimeout(this.responseTimeout); this.responseTimeout = null; }
|
|
1111
879
|
if (this.idleTimeout) { clearTimeout(this.idleTimeout); this.idleTimeout = null; }
|
|
@@ -1193,10 +961,10 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1193
961
|
const session = this.runParseSession();
|
|
1194
962
|
if (!session) return;
|
|
1195
963
|
|
|
1196
|
-
const { status, messages,
|
|
964
|
+
const { status, messages, parsedStatus } = session;
|
|
965
|
+
const modal = (session as any).activeModal ?? session.modal ?? null;
|
|
1197
966
|
const parsedMessages = normalizeCliParsedMessages(messages, {
|
|
1198
|
-
|
|
1199
|
-
scope: this.currentTurnScope,
|
|
967
|
+
scope: null,
|
|
1200
968
|
lastOutputAt: this.lastOutputAt,
|
|
1201
969
|
});
|
|
1202
970
|
|
|
@@ -1396,7 +1164,7 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1396
1164
|
const looksIdleChrome = /(^|\n)\s*[❯›>]\s*(?:\n|$)/m.test(effectiveScreenText);
|
|
1397
1165
|
const parsedShowsLiveAssistantProgress = parsedStatus === 'generating'
|
|
1398
1166
|
&& !!lastParsedAssistant
|
|
1399
|
-
|
|
1167
|
+
;
|
|
1400
1168
|
if (prevStatus === 'idle' && !this.isWaitingForResponse && noActiveTurn && !modal && looksIdleChrome && !parsedShowsLiveAssistantProgress) {
|
|
1401
1169
|
return;
|
|
1402
1170
|
}
|
|
@@ -1573,10 +1341,7 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1573
1341
|
const visibleAssistant = [...parsedMessages].reverse().find((m) => m.role === 'assistant' && m.content.trim());
|
|
1574
1342
|
if (!visibleAssistant) return false;
|
|
1575
1343
|
|
|
1576
|
-
this.committedMessages = parsedMessages;
|
|
1577
|
-
this.trimLastAssistantEcho(this.committedMessages, this.currentTurnScope?.prompt || getLastUserPromptText(this.committedMessages));
|
|
1578
1344
|
this.clearAllTimers();
|
|
1579
|
-
this.syncMessageViews();
|
|
1580
1345
|
this.responseBuffer = '';
|
|
1581
1346
|
this.isWaitingForResponse = false;
|
|
1582
1347
|
this.responseSettleIgnoreUntil = 0;
|
|
@@ -1588,7 +1353,7 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1588
1353
|
this.setStatus('idle', 'script_idle_commit');
|
|
1589
1354
|
this.onStatusChange?.();
|
|
1590
1355
|
this.recordTrace('script_idle_commit', {
|
|
1591
|
-
messageCount:
|
|
1356
|
+
messageCount: parsedMessages.length,
|
|
1592
1357
|
lastAssistant: summarizeCliTraceText(visibleAssistant.content, 320),
|
|
1593
1358
|
});
|
|
1594
1359
|
return true;
|
|
@@ -1596,30 +1361,27 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1596
1361
|
|
|
1597
1362
|
private commitCurrentTranscript(): { hasAssistant: boolean; assistantContent: string } {
|
|
1598
1363
|
const parsed = this.parseCurrentTranscript(
|
|
1599
|
-
|
|
1364
|
+
[],
|
|
1600
1365
|
this.responseBuffer,
|
|
1601
1366
|
this.currentTurnScope,
|
|
1602
1367
|
);
|
|
1603
1368
|
if (parsed && Array.isArray(parsed.messages)) {
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
scope: this.currentTurnScope,
|
|
1369
|
+
const parsedMessages = normalizeCliParsedMessages(parsed.messages, {
|
|
1370
|
+
scope: null,
|
|
1607
1371
|
lastOutputAt: this.lastOutputAt,
|
|
1608
1372
|
});
|
|
1609
|
-
|
|
1610
|
-
this.syncMessageViews();
|
|
1611
|
-
const lastAssistant = [...this.committedMessages].reverse().find((message) => message.role === 'assistant');
|
|
1373
|
+
const lastAssistant = [...parsedMessages].reverse().find((message) => message.role === 'assistant');
|
|
1612
1374
|
if (this.currentTurnScope) {
|
|
1613
1375
|
LOG.info(
|
|
1614
1376
|
'CLI',
|
|
1615
|
-
`[${this.cliType}] commitCurrentTranscript
|
|
1377
|
+
`[${this.cliType}] commitCurrentTranscript parserMessages=${parsedMessages.length} finalLastAssistant=${JSON.stringify(summarizeCliTraceText(lastAssistant?.content || '', 220)).slice(0, 260)}`
|
|
1616
1378
|
);
|
|
1617
1379
|
}
|
|
1618
1380
|
this.recordTrace('commit_transcript', {
|
|
1619
1381
|
parsedStatus: parsed.status || null,
|
|
1620
|
-
messageCount:
|
|
1382
|
+
messageCount: parsedMessages.length,
|
|
1621
1383
|
lastAssistant: lastAssistant ? summarizeCliTraceText(lastAssistant.content, 320) : '',
|
|
1622
|
-
messages: summarizeCliTraceMessages(
|
|
1384
|
+
messages: summarizeCliTraceMessages(parsedMessages),
|
|
1623
1385
|
...buildCliTraceParseSnapshot({
|
|
1624
1386
|
accumulatedBuffer: this.accumulatedBuffer,
|
|
1625
1387
|
accumulatedRawBuffer: this.accumulatedRawBuffer,
|
|
@@ -1656,71 +1418,31 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1656
1418
|
// ─── Script Execution ──────────────────────────
|
|
1657
1419
|
|
|
1658
1420
|
private runParseSession(): ParsedSession | null {
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
const screenText = this.terminalScreen.getText();
|
|
1663
|
-
const tail = this.recentOutputBuffer.slice(-500);
|
|
1664
|
-
const parseBaseMessages = this.selectParseBaseMessages(this.committedMessages);
|
|
1665
|
-
const input = buildCliParseInput({
|
|
1666
|
-
accumulatedBuffer: this.accumulatedBuffer,
|
|
1667
|
-
accumulatedRawBuffer: this.accumulatedRawBuffer,
|
|
1668
|
-
recentOutputBuffer: this.recentOutputBuffer,
|
|
1669
|
-
terminalScreenText: screenText,
|
|
1670
|
-
baseMessages: parseBaseMessages,
|
|
1671
|
-
partialResponse: this.responseBuffer,
|
|
1672
|
-
isWaitingForResponse: this.isWaitingForResponse,
|
|
1673
|
-
scope: this.currentTurnScope,
|
|
1674
|
-
runtimeSettings: this.runtimeSettings,
|
|
1675
|
-
});
|
|
1676
|
-
const session = this.cliScripts.parseSession({ ...input, tail, tailScreen: buildCliScreenSnapshot(tail) });
|
|
1677
|
-
if (session && typeof session === 'object' && Array.isArray(session.messages)) {
|
|
1678
|
-
session.messages = this.stitchParsedMessagesWithCommittedBase(
|
|
1679
|
-
session.messages,
|
|
1680
|
-
this.committedMessages,
|
|
1681
|
-
parseBaseMessages,
|
|
1682
|
-
);
|
|
1683
|
-
}
|
|
1684
|
-
this.parseErrorMessage = null;
|
|
1685
|
-
return session && typeof session === 'object' ? session : null;
|
|
1686
|
-
} catch (e: any) {
|
|
1687
|
-
const message = e?.message || String(e);
|
|
1688
|
-
this.parseErrorMessage = message;
|
|
1689
|
-
LOG.warn('CLI', `[${this.cliType}] parseSession error: ${message}`);
|
|
1690
|
-
return null;
|
|
1691
|
-
}
|
|
1421
|
+
if (typeof this.cliScripts?.parseSession !== 'function') {
|
|
1422
|
+
this.parseErrorMessage = `${this.cliType} parseSession unavailable`;
|
|
1423
|
+
return null;
|
|
1692
1424
|
}
|
|
1693
|
-
// Fallback: reconcile from the three individual scripts (for providers without parseSession)
|
|
1694
|
-
if (!this.cliScripts?.detectStatus && !this.cliScripts?.parseOutput) return null;
|
|
1695
1425
|
try {
|
|
1696
|
-
const
|
|
1697
|
-
const
|
|
1698
|
-
|
|
1699
|
-
this.
|
|
1700
|
-
this.
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
:
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
const
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
? 'waiting_approval'
|
|
1713
|
-
: (rawStatus || parsedStatus || 'idle');
|
|
1714
|
-
return {
|
|
1715
|
-
status: effectiveStatus,
|
|
1716
|
-
messages: Array.isArray(parsedTranscript?.messages) ? parsedTranscript.messages : [],
|
|
1717
|
-
modal,
|
|
1718
|
-
parsedStatus,
|
|
1719
|
-
};
|
|
1426
|
+
const screenText = this.terminalScreen.getText();
|
|
1427
|
+
const tail = this.recentOutputBuffer.slice(-500);
|
|
1428
|
+
const input = buildCliParseInput({
|
|
1429
|
+
accumulatedBuffer: this.accumulatedBuffer,
|
|
1430
|
+
accumulatedRawBuffer: this.accumulatedRawBuffer,
|
|
1431
|
+
recentOutputBuffer: this.recentOutputBuffer,
|
|
1432
|
+
terminalScreenText: screenText,
|
|
1433
|
+
baseMessages: [],
|
|
1434
|
+
partialResponse: this.responseBuffer,
|
|
1435
|
+
isWaitingForResponse: this.isWaitingForResponse,
|
|
1436
|
+
scope: this.currentTurnScope,
|
|
1437
|
+
runtimeSettings: this.runtimeSettings,
|
|
1438
|
+
});
|
|
1439
|
+
const session = this.cliScripts.parseSession({ ...input, tail, tailScreen: buildCliScreenSnapshot(tail) });
|
|
1440
|
+
this.parseErrorMessage = null;
|
|
1441
|
+
return session && typeof session === 'object' ? session : null;
|
|
1720
1442
|
} catch (e: any) {
|
|
1721
1443
|
const message = e?.message || String(e);
|
|
1722
1444
|
this.parseErrorMessage = message;
|
|
1723
|
-
LOG.warn('CLI', `[${this.cliType}] parseSession
|
|
1445
|
+
LOG.warn('CLI', `[${this.cliType}] parseSession error: ${message}`);
|
|
1724
1446
|
return null;
|
|
1725
1447
|
}
|
|
1726
1448
|
}
|
|
@@ -1775,41 +1497,6 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1775
1497
|
return this.currentStatus;
|
|
1776
1498
|
}
|
|
1777
1499
|
|
|
1778
|
-
private suppressStaleParsedApproval(
|
|
1779
|
-
parsed: any,
|
|
1780
|
-
recentBuffer: string,
|
|
1781
|
-
screenText: string,
|
|
1782
|
-
): any {
|
|
1783
|
-
const actionableParsedModal = parsed?.activeModal && Array.isArray(parsed.activeModal.buttons)
|
|
1784
|
-
&& parsed.activeModal.buttons.some((button: any) => typeof button === 'string' && button.trim())
|
|
1785
|
-
? parsed.activeModal
|
|
1786
|
-
: null;
|
|
1787
|
-
if (!parsed || parsed?.status !== 'waiting_approval' || !actionableParsedModal) {
|
|
1788
|
-
return parsed;
|
|
1789
|
-
}
|
|
1790
|
-
|
|
1791
|
-
const inApprovalCooldown = this.lastApprovalResolvedAt > 0
|
|
1792
|
-
&& (Date.now() - this.lastApprovalResolvedAt) < this.timeouts.approvalCooldown;
|
|
1793
|
-
if (!inApprovalCooldown) {
|
|
1794
|
-
return parsed;
|
|
1795
|
-
}
|
|
1796
|
-
|
|
1797
|
-
const visibleModal = this.runParseApproval(recentBuffer);
|
|
1798
|
-
if (visibleModal) {
|
|
1799
|
-
return parsed;
|
|
1800
|
-
}
|
|
1801
|
-
|
|
1802
|
-
const detectedStatus = this.runDetectStatus(recentBuffer);
|
|
1803
|
-
const resolvedStatus = detectedStatus && detectedStatus !== 'waiting_approval'
|
|
1804
|
-
? detectedStatus
|
|
1805
|
-
: ((this.isWaitingForResponse || this.currentTurnScope) ? 'generating' : (this.currentStatus === 'waiting_approval' ? 'idle' : this.currentStatus));
|
|
1806
|
-
return {
|
|
1807
|
-
...parsed,
|
|
1808
|
-
status: resolvedStatus,
|
|
1809
|
-
activeModal: null,
|
|
1810
|
-
};
|
|
1811
|
-
}
|
|
1812
|
-
|
|
1813
1500
|
// ─── Public API (CliAdapter) ───────────────────
|
|
1814
1501
|
|
|
1815
1502
|
getStatus(options: { allowParse?: boolean } = {}): CliSessionStatus {
|
|
@@ -1817,19 +1504,8 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1817
1504
|
const startupModal = allowParse && this.startupParseGate ? this.runParseApproval(this.recentOutputBuffer) : null;
|
|
1818
1505
|
let effectiveStatus = this.projectEffectiveStatus(startupModal);
|
|
1819
1506
|
let effectiveModal = startupModal || this.activeModal;
|
|
1820
|
-
if (allowParse && !startupModal && !effectiveModal
|
|
1821
|
-
|
|
1822
|
-
if (!parsed && effectiveStatus !== 'idle') {
|
|
1823
|
-
const now = Date.now();
|
|
1824
|
-
if ((now - this.lastStatusHotPathParseAt) >= ProviderCliAdapter.STATUS_HOT_PATH_PARSE_MIN_INTERVAL_MS) {
|
|
1825
|
-
this.lastStatusHotPathParseAt = now;
|
|
1826
|
-
try {
|
|
1827
|
-
parsed = this.getScriptParsedStatus();
|
|
1828
|
-
} catch {
|
|
1829
|
-
// Ignore parse errors here; getScriptParsedStatus surfaces them on richer callers.
|
|
1830
|
-
}
|
|
1831
|
-
}
|
|
1832
|
-
}
|
|
1507
|
+
if (allowParse && !startupModal && !effectiveModal) {
|
|
1508
|
+
const parsed = this.getFreshParsedStatusCache();
|
|
1833
1509
|
const parsedModal = parsed?.activeModal && Array.isArray(parsed.activeModal.buttons)
|
|
1834
1510
|
&& parsed.activeModal.buttons.some((button: any) => typeof button === 'string' && button.trim())
|
|
1835
1511
|
? parsed.activeModal
|
|
@@ -1842,7 +1518,7 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1842
1518
|
const bufferState = this.getBufferState();
|
|
1843
1519
|
return {
|
|
1844
1520
|
status: effectiveStatus,
|
|
1845
|
-
messages: [
|
|
1521
|
+
messages: [],
|
|
1846
1522
|
workingDir: this.workingDir,
|
|
1847
1523
|
activeModal: effectiveModal,
|
|
1848
1524
|
errorMessage: this.parseErrorMessage || undefined,
|
|
@@ -1851,119 +1527,6 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1851
1527
|
};
|
|
1852
1528
|
}
|
|
1853
1529
|
|
|
1854
|
-
seedCommittedMessages(messages: SeedCliChatMessage[]): void {
|
|
1855
|
-
const normalized = (Array.isArray(messages) ? messages : [])
|
|
1856
|
-
.filter((message) => message && (message.role === 'user' || message.role === 'assistant'))
|
|
1857
|
-
.map((message) => ({
|
|
1858
|
-
role: message.role as 'user' | 'assistant',
|
|
1859
|
-
content: typeof message.content === 'string' ? message.content : String(message.content || ''),
|
|
1860
|
-
timestamp: typeof message.timestamp === 'number' && Number.isFinite(message.timestamp)
|
|
1861
|
-
? message.timestamp
|
|
1862
|
-
: undefined,
|
|
1863
|
-
receivedAt: typeof message.receivedAt === 'number' && Number.isFinite(message.receivedAt)
|
|
1864
|
-
? message.receivedAt
|
|
1865
|
-
: undefined,
|
|
1866
|
-
kind: typeof message.kind === 'string' ? message.kind : undefined,
|
|
1867
|
-
id: typeof message.id === 'string' ? message.id : undefined,
|
|
1868
|
-
index: typeof message.index === 'number' ? message.index : undefined,
|
|
1869
|
-
providerUnitKey: typeof (message as any).providerUnitKey === 'string' ? (message as any).providerUnitKey : undefined,
|
|
1870
|
-
bubbleId: typeof (message as any).bubbleId === 'string' ? (message as any).bubbleId : undefined,
|
|
1871
|
-
bubbleState: typeof (message as any).bubbleState === 'string' ? (message as any).bubbleState : undefined,
|
|
1872
|
-
_turnKey: typeof (message as any)._turnKey === 'string' ? (message as any)._turnKey : undefined,
|
|
1873
|
-
meta: message.meta && typeof message.meta === 'object' ? { ...(message.meta as Record<string, any>) } : undefined,
|
|
1874
|
-
senderName: typeof message.senderName === 'string' ? message.senderName : undefined,
|
|
1875
|
-
}));
|
|
1876
|
-
this.committedMessages = normalized;
|
|
1877
|
-
this.syncMessageViews();
|
|
1878
|
-
}
|
|
1879
|
-
|
|
1880
|
-
private getSharedCommittedPrefixLength(parsedMessages: any[]): number {
|
|
1881
|
-
const committedMessages = this.committedMessages;
|
|
1882
|
-
const max = Math.min(parsedMessages.length, committedMessages.length);
|
|
1883
|
-
let index = 0;
|
|
1884
|
-
while (index < max && this.messagesShareStableIdentity(parsedMessages[index], committedMessages[index])) {
|
|
1885
|
-
index += 1;
|
|
1886
|
-
}
|
|
1887
|
-
return index;
|
|
1888
|
-
}
|
|
1889
|
-
|
|
1890
|
-
private hydrateCommittedPrefixForParsedStatus(parsedMessages: any[]): any[] | null {
|
|
1891
|
-
const sharedPrefixLength = this.getSharedCommittedPrefixLength(parsedMessages);
|
|
1892
|
-
if (sharedPrefixLength !== this.committedMessages.length) return null;
|
|
1893
|
-
|
|
1894
|
-
const committedHydratedMessages = this.committedMessages.map((message, index) => {
|
|
1895
|
-
const timestamp = typeof message.timestamp === 'number' && Number.isFinite(message.timestamp)
|
|
1896
|
-
? message.timestamp
|
|
1897
|
-
: (this.lastOutputAt || this.currentTurnScope?.startedAt || Date.now());
|
|
1898
|
-
const contentValue = message.content;
|
|
1899
|
-
return {
|
|
1900
|
-
role: message.role,
|
|
1901
|
-
content: typeof contentValue === 'string' ? contentValue : String(contentValue || ''),
|
|
1902
|
-
timestamp,
|
|
1903
|
-
receivedAt: typeof message.receivedAt === 'number' && Number.isFinite(message.receivedAt)
|
|
1904
|
-
? message.receivedAt
|
|
1905
|
-
: timestamp,
|
|
1906
|
-
kind: message.kind,
|
|
1907
|
-
id: message.id || `msg_${index}`,
|
|
1908
|
-
index: typeof message.index === 'number' ? message.index : index,
|
|
1909
|
-
providerUnitKey: (message as any).providerUnitKey,
|
|
1910
|
-
bubbleId: (message as any).bubbleId,
|
|
1911
|
-
bubbleState: (message as any).bubbleState,
|
|
1912
|
-
_turnKey: (message as any)._turnKey,
|
|
1913
|
-
meta: message.meta,
|
|
1914
|
-
senderName: message.senderName,
|
|
1915
|
-
};
|
|
1916
|
-
});
|
|
1917
|
-
const extraMessages = parsedMessages.slice(sharedPrefixLength);
|
|
1918
|
-
if (extraMessages.length === 0) return committedHydratedMessages;
|
|
1919
|
-
|
|
1920
|
-
const extraHydratedMessages = hydrateCliParsedMessages(extraMessages, {
|
|
1921
|
-
committedMessages: [],
|
|
1922
|
-
scope: this.currentTurnScope,
|
|
1923
|
-
lastOutputAt: this.lastOutputAt,
|
|
1924
|
-
}).map((message, offset) => ({
|
|
1925
|
-
...message,
|
|
1926
|
-
id: message.id || `msg_${sharedPrefixLength + offset}`,
|
|
1927
|
-
index: typeof message.index === 'number' ? message.index : sharedPrefixLength + offset,
|
|
1928
|
-
}));
|
|
1929
|
-
return [...committedHydratedMessages, ...extraHydratedMessages];
|
|
1930
|
-
}
|
|
1931
|
-
|
|
1932
|
-
private hydrateParsedMessagesForStatus(parsedMessages: any[]): any[] {
|
|
1933
|
-
return this.hydrateCommittedPrefixForParsedStatus(parsedMessages)
|
|
1934
|
-
|| hydrateCliParsedMessages(parsedMessages, {
|
|
1935
|
-
committedMessages: this.committedMessages,
|
|
1936
|
-
scope: this.currentTurnScope,
|
|
1937
|
-
lastOutputAt: this.lastOutputAt,
|
|
1938
|
-
});
|
|
1939
|
-
}
|
|
1940
|
-
|
|
1941
|
-
private buildCommittedChatMessages(): any[] {
|
|
1942
|
-
return this.committedMessages.map((message, index) => {
|
|
1943
|
-
const rawContentValue = message.content;
|
|
1944
|
-
const rawContent = typeof rawContentValue === 'string' ? rawContentValue : String(rawContentValue || '');
|
|
1945
|
-
const content = message.role === 'assistant' && (message.kind || 'standard') === 'standard'
|
|
1946
|
-
? sanitizeCliStandardMessageContent(rawContent)
|
|
1947
|
-
: rawContent;
|
|
1948
|
-
return buildChatMessage({
|
|
1949
|
-
role: message.role,
|
|
1950
|
-
content,
|
|
1951
|
-
timestamp: message.timestamp,
|
|
1952
|
-
kind: message.kind,
|
|
1953
|
-
meta: message.meta,
|
|
1954
|
-
senderName: message.senderName,
|
|
1955
|
-
id: message.id || `msg_${index}`,
|
|
1956
|
-
index: typeof message.index === 'number' ? message.index : index,
|
|
1957
|
-
providerUnitKey: (message as any).providerUnitKey,
|
|
1958
|
-
bubbleId: (message as any).bubbleId,
|
|
1959
|
-
bubbleState: (message as any).bubbleState,
|
|
1960
|
-
_turnKey: (message as any)._turnKey,
|
|
1961
|
-
receivedAt: typeof message.receivedAt === 'number'
|
|
1962
|
-
? message.receivedAt
|
|
1963
|
-
: message.timestamp,
|
|
1964
|
-
});
|
|
1965
|
-
});
|
|
1966
|
-
}
|
|
1967
1530
|
|
|
1968
1531
|
/**
|
|
1969
1532
|
* Script-based full parse — returns ReadChatResult.
|
|
@@ -1974,7 +1537,6 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1974
1537
|
const cached = this.parsedStatusCache;
|
|
1975
1538
|
if (
|
|
1976
1539
|
cached
|
|
1977
|
-
&& cached.committedMessagesRef === this.committedMessages
|
|
1978
1540
|
&& cached.responseBuffer === this.responseBuffer
|
|
1979
1541
|
&& cached.currentTurnScope === this.currentTurnScope
|
|
1980
1542
|
&& cached.recentOutputBuffer === this.recentOutputBuffer
|
|
@@ -1987,163 +1549,33 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1987
1549
|
return cached.result;
|
|
1988
1550
|
}
|
|
1989
1551
|
|
|
1990
|
-
const parsed = this.
|
|
1991
|
-
|
|
1992
|
-
this.
|
|
1993
|
-
this.currentTurnScope,
|
|
1994
|
-
screenText,
|
|
1995
|
-
);
|
|
1996
|
-
const parsedModal = parsed?.activeModal && Array.isArray(parsed.activeModal.buttons)
|
|
1997
|
-
&& parsed.activeModal.buttons.some((button: any) => typeof button === 'string' && button.trim())
|
|
1998
|
-
? parsed.activeModal
|
|
1999
|
-
: null;
|
|
2000
|
-
if (parsedModal && parsed?.status === 'waiting_approval') {
|
|
2001
|
-
this.activeModal = parsedModal;
|
|
2002
|
-
this.isWaitingForResponse = true;
|
|
2003
|
-
if (this.currentStatus !== 'waiting_approval') {
|
|
2004
|
-
this.setStatus('waiting_approval', 'parsed_waiting_approval');
|
|
2005
|
-
this.onStatusChange?.();
|
|
2006
|
-
}
|
|
2007
|
-
}
|
|
2008
|
-
if (parsed && Array.isArray(parsed.messages) && this.provider.allowInputDuringGeneration === true) {
|
|
2009
|
-
const hydratedForCommit = normalizeCliParsedMessages(parsed.messages, {
|
|
2010
|
-
committedMessages: this.committedMessages,
|
|
2011
|
-
scope: this.currentTurnScope,
|
|
2012
|
-
lastOutputAt: this.lastOutputAt,
|
|
2013
|
-
});
|
|
2014
|
-
const fakeSession: ParsedSession = {
|
|
2015
|
-
status: parsed.status || 'idle',
|
|
2016
|
-
messages: parsed.messages,
|
|
2017
|
-
modal: parsedModal,
|
|
2018
|
-
parsedStatus: parsed.status || null,
|
|
2019
|
-
};
|
|
2020
|
-
if (this.maybeCommitVisibleIdleTranscript(fakeSession, hydratedForCommit)) {
|
|
2021
|
-
return this.getScriptParsedStatus();
|
|
2022
|
-
}
|
|
2023
|
-
}
|
|
2024
|
-
const shouldPreferCommittedMessages =
|
|
2025
|
-
!this.currentTurnScope
|
|
2026
|
-
&& !this.activeModal
|
|
2027
|
-
&& this.currentStatus === 'idle';
|
|
2028
|
-
let result: any;
|
|
2029
|
-
if (parsed && Array.isArray(parsed.messages)) {
|
|
2030
|
-
const parsedHydratedMessages = this.hydrateParsedMessagesForStatus(parsed.messages);
|
|
2031
|
-
const parsedLastAssistant = [...parsedHydratedMessages].reverse().find((message) => message.role === 'assistant' && typeof message.content === 'string' && message.content.trim());
|
|
2032
|
-
const shouldAdoptParsedIdleReplay =
|
|
2033
|
-
!this.currentTurnScope
|
|
2034
|
-
&& !this.activeModal
|
|
2035
|
-
&& !!parsedLastAssistant
|
|
2036
|
-
&& parsedTranscriptIsRicherThanCommitted(parsedHydratedMessages, this.committedMessages)
|
|
2037
|
-
&& (
|
|
2038
|
-
this.currentStatus === 'idle'
|
|
2039
|
-
|| (
|
|
2040
|
-
this.currentStatus === 'generating'
|
|
2041
|
-
&& this.isWaitingForResponse
|
|
2042
|
-
&& parsed.status === 'idle'
|
|
2043
|
-
&& this.runDetectStatus(this.recentOutputBuffer) === 'idle'
|
|
2044
|
-
)
|
|
2045
|
-
);
|
|
2046
|
-
if (shouldAdoptParsedIdleReplay) {
|
|
2047
|
-
this.committedMessages = this.getSharedCommittedPrefixLength(parsed.messages) === this.committedMessages.length
|
|
2048
|
-
? parsedHydratedMessages.map((message) => ({
|
|
2049
|
-
role: message.role,
|
|
2050
|
-
content: typeof message.content === 'string' ? message.content : String(message.content || ''),
|
|
2051
|
-
timestamp: message.timestamp,
|
|
2052
|
-
receivedAt: message.receivedAt,
|
|
2053
|
-
kind: message.kind,
|
|
2054
|
-
id: message.id,
|
|
2055
|
-
index: message.index,
|
|
2056
|
-
meta: message.meta,
|
|
2057
|
-
senderName: message.senderName,
|
|
2058
|
-
}))
|
|
2059
|
-
: normalizeCliParsedMessages(parsed.messages, {
|
|
2060
|
-
committedMessages: this.committedMessages,
|
|
2061
|
-
scope: this.currentTurnScope,
|
|
2062
|
-
lastOutputAt: this.lastOutputAt,
|
|
2063
|
-
});
|
|
2064
|
-
this.syncMessageViews();
|
|
2065
|
-
if (this.currentStatus !== 'idle' || this.isWaitingForResponse) {
|
|
2066
|
-
this.responseBuffer = '';
|
|
2067
|
-
this.isWaitingForResponse = false;
|
|
2068
|
-
this.responseSettleIgnoreUntil = 0;
|
|
2069
|
-
this.submitRetryUsed = false;
|
|
2070
|
-
this.submitRetryPromptSnippet = '';
|
|
2071
|
-
this.finishRetryCount = 0;
|
|
2072
|
-
this.currentTurnScope = null;
|
|
2073
|
-
this.activeModal = null;
|
|
2074
|
-
this.setStatus('idle', 'parsed_idle_replay_commit');
|
|
2075
|
-
this.onStatusChange?.();
|
|
2076
|
-
}
|
|
2077
|
-
}
|
|
2078
|
-
const shouldPreferCommittedHistoryReplay =
|
|
2079
|
-
!this.currentTurnScope
|
|
2080
|
-
&& !this.activeModal
|
|
2081
|
-
&& this.committedMessages.length > parsedHydratedMessages.length;
|
|
2082
|
-
const shouldPreferCommittedIdleReplay =
|
|
2083
|
-
shouldPreferCommittedMessages
|
|
2084
|
-
&& !shouldAdoptParsedIdleReplay;
|
|
2085
|
-
const hydratedMessages = (shouldPreferCommittedIdleReplay || shouldPreferCommittedHistoryReplay)
|
|
2086
|
-
? this.buildCommittedChatMessages()
|
|
2087
|
-
: parsedHydratedMessages;
|
|
2088
|
-
result = {
|
|
2089
|
-
id: parsed.id || 'cli_session',
|
|
2090
|
-
status: parsed.status || this.currentStatus,
|
|
2091
|
-
title: parsed.title || this.cliName,
|
|
2092
|
-
messages: hydratedMessages,
|
|
2093
|
-
activeModal: parsed.activeModal ?? this.activeModal,
|
|
2094
|
-
providerSessionId: typeof parsed.providerSessionId === 'string' ? parsed.providerSessionId : undefined,
|
|
2095
|
-
...(this.getBufferState() ? { bufferState: this.getBufferState() } : {}),
|
|
2096
|
-
...(this.providerOwnsTranscript() ? { transcriptAuthority: 'provider', coverage: this.shouldUseFullProviderTranscriptContext() ? 'full' : 'tail' } : {}),
|
|
2097
|
-
};
|
|
2098
|
-
} else {
|
|
2099
|
-
const messages = [...this.committedMessages];
|
|
2100
|
-
const bufferState = this.getBufferState();
|
|
2101
|
-
result = {
|
|
2102
|
-
id: 'cli_session',
|
|
2103
|
-
status: this.currentStatus,
|
|
2104
|
-
title: this.cliName,
|
|
2105
|
-
messages: messages.map((message, index) => buildChatMessage({
|
|
2106
|
-
...message,
|
|
2107
|
-
id: message.id || `msg_${index}`,
|
|
2108
|
-
index: typeof message.index === 'number' ? message.index : index,
|
|
2109
|
-
receivedAt: typeof message.receivedAt === 'number'
|
|
2110
|
-
? message.receivedAt
|
|
2111
|
-
: message.timestamp,
|
|
2112
|
-
})),
|
|
2113
|
-
activeModal: this.activeModal,
|
|
2114
|
-
...(bufferState ? { bufferState } : {}),
|
|
2115
|
-
};
|
|
1552
|
+
const parsed = this.runParseSession();
|
|
1553
|
+
if (!parsed || !Array.isArray(parsed.messages)) {
|
|
1554
|
+
throw new Error(this.parseErrorMessage || `${this.cliType} parseSession did not return messages`);
|
|
2116
1555
|
}
|
|
2117
1556
|
|
|
2118
|
-
const
|
|
2119
|
-
|
|
2120
|
-
const
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
...(Object.keys(nextMeta).length > 0 ? { meta: nextMeta } : { meta: undefined }),
|
|
2139
|
-
};
|
|
2140
|
-
})
|
|
2141
|
-
: result.messages,
|
|
2142
|
-
};
|
|
2143
|
-
}
|
|
1557
|
+
const activeModal = (parsed as any).activeModal ?? parsed.modal ?? null;
|
|
1558
|
+
const bufferState = this.getBufferState();
|
|
1559
|
+
const result = {
|
|
1560
|
+
id: (parsed as any).id || 'cli_session',
|
|
1561
|
+
status: parsed.status || this.currentStatus,
|
|
1562
|
+
title: (parsed as any).title || this.cliName,
|
|
1563
|
+
messages: normalizeCliParsedMessages(parsed.messages, {
|
|
1564
|
+
scope: null,
|
|
1565
|
+
lastOutputAt: this.lastOutputAt,
|
|
1566
|
+
}),
|
|
1567
|
+
activeModal,
|
|
1568
|
+
providerSessionId: typeof (parsed as any).providerSessionId === 'string' ? (parsed as any).providerSessionId : undefined,
|
|
1569
|
+
...(bufferState ? { bufferState } : {}),
|
|
1570
|
+
...((parsed as any).transcriptAuthority === 'provider' || (parsed as any).transcriptAuthority === 'daemon'
|
|
1571
|
+
? { transcriptAuthority: (parsed as any).transcriptAuthority }
|
|
1572
|
+
: this.providerOwnsTranscript() ? { transcriptAuthority: 'provider' } : {}),
|
|
1573
|
+
...((parsed as any).coverage === 'full' || (parsed as any).coverage === 'tail' || (parsed as any).coverage === 'current-turn'
|
|
1574
|
+
? { coverage: (parsed as any).coverage }
|
|
1575
|
+
: this.providerOwnsTranscript() ? { coverage: this.shouldUseFullProviderTranscriptContext() ? 'full' : 'tail' } : {}),
|
|
1576
|
+
};
|
|
2144
1577
|
|
|
2145
1578
|
this.parsedStatusCache = {
|
|
2146
|
-
committedMessagesRef: this.committedMessages,
|
|
2147
1579
|
responseBuffer: this.responseBuffer,
|
|
2148
1580
|
currentTurnScope: this.currentTurnScope,
|
|
2149
1581
|
recentOutputBuffer: this.recentOutputBuffer,
|
|
@@ -2167,7 +1599,7 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
2167
1599
|
accumulatedRawBuffer: this.accumulatedRawBuffer,
|
|
2168
1600
|
recentOutputBuffer: this.recentOutputBuffer,
|
|
2169
1601
|
terminalScreenText: this.terminalScreen.getText(),
|
|
2170
|
-
baseMessages:
|
|
1602
|
+
baseMessages: [],
|
|
2171
1603
|
partialResponse: this.responseBuffer,
|
|
2172
1604
|
isWaitingForResponse: this.isWaitingForResponse,
|
|
2173
1605
|
scope: this.currentTurnScope,
|
|
@@ -2179,46 +1611,8 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
2179
1611
|
}));
|
|
2180
1612
|
}
|
|
2181
1613
|
|
|
2182
|
-
private parseCurrentTranscript(
|
|
2183
|
-
|
|
2184
|
-
this.parseErrorMessage = null;
|
|
2185
|
-
return null;
|
|
2186
|
-
}
|
|
2187
|
-
try {
|
|
2188
|
-
const screenText = typeof screenTextOverride === 'string' ? screenTextOverride : this.terminalScreen.getText();
|
|
2189
|
-
const parseBaseMessages = this.selectParseBaseMessages(baseMessages);
|
|
2190
|
-
const input = buildCliParseInput({
|
|
2191
|
-
accumulatedBuffer: this.accumulatedBuffer,
|
|
2192
|
-
accumulatedRawBuffer: this.accumulatedRawBuffer,
|
|
2193
|
-
recentOutputBuffer: this.recentOutputBuffer,
|
|
2194
|
-
terminalScreenText: screenText,
|
|
2195
|
-
baseMessages: parseBaseMessages,
|
|
2196
|
-
partialResponse,
|
|
2197
|
-
isWaitingForResponse: this.isWaitingForResponse,
|
|
2198
|
-
scope,
|
|
2199
|
-
runtimeSettings: this.runtimeSettings,
|
|
2200
|
-
});
|
|
2201
|
-
const parsed = this.cliScripts.parseOutput(input);
|
|
2202
|
-
if (parsed && typeof parsed === 'object') {
|
|
2203
|
-
Object.assign(parsed, validateReadChatResultPayload(parsed, `${this.cliType} parseOutput`));
|
|
2204
|
-
}
|
|
2205
|
-
const normalizedParsed = this.suppressStaleParsedApproval(parsed, input.recentBuffer, input.screenText);
|
|
2206
|
-
if (normalizedParsed && Array.isArray(normalizedParsed.messages)) {
|
|
2207
|
-
normalizedParsed.messages = this.stitchParsedMessagesWithCommittedBase(
|
|
2208
|
-
normalizedParsed.messages,
|
|
2209
|
-
baseMessages,
|
|
2210
|
-
parseBaseMessages,
|
|
2211
|
-
);
|
|
2212
|
-
this.trimLastAssistantEcho(normalizedParsed.messages, scope?.prompt || getLastUserPromptText(baseMessages));
|
|
2213
|
-
}
|
|
2214
|
-
this.parseErrorMessage = null;
|
|
2215
|
-
return normalizedParsed;
|
|
2216
|
-
} catch (e: any) {
|
|
2217
|
-
const message = e?.message || String(e);
|
|
2218
|
-
this.parseErrorMessage = message;
|
|
2219
|
-
LOG.warn('CLI', `[${this.cliType}] parseOutput error: ${message}`);
|
|
2220
|
-
throw e;
|
|
2221
|
-
}
|
|
1614
|
+
private parseCurrentTranscript(_baseMessages: CliChatMessage[], _partialResponse: string, _scope?: TurnParseScope | null, _screenTextOverride?: string): any {
|
|
1615
|
+
return this.runParseSession();
|
|
2222
1616
|
}
|
|
2223
1617
|
|
|
2224
1618
|
/** Whether this adapter has CLI scripts loaded */
|
|
@@ -2277,8 +1671,6 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
2277
1671
|
private commitSendUserTurn(state: SendMessageState): void {
|
|
2278
1672
|
if (state.didCommitUserTurn) return;
|
|
2279
1673
|
state.didCommitUserTurn = true;
|
|
2280
|
-
this.committedMessages.push({ role: 'user', content: state.text, timestamp: Date.now() });
|
|
2281
|
-
this.syncMessageViews();
|
|
2282
1674
|
}
|
|
2283
1675
|
|
|
2284
1676
|
private armResponseTimeout(): void {
|
|
@@ -2499,16 +1891,6 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
2499
1891
|
const parsedSessionStatus = typeof parsedStatusBeforeSend?.status === 'string'
|
|
2500
1892
|
? String(parsedStatusBeforeSend.status)
|
|
2501
1893
|
: '';
|
|
2502
|
-
const parsedMessagesBeforeSend = Array.isArray(parsedStatusBeforeSend?.messages)
|
|
2503
|
-
? parsedStatusBeforeSend.messages.filter((message: any) => message && (message.role === 'user' || message.role === 'assistant'))
|
|
2504
|
-
: [];
|
|
2505
|
-
const shouldCommitParsedIdleBeforeSend = !allowInputDuringGeneration
|
|
2506
|
-
&& parsedSessionStatus === 'idle'
|
|
2507
|
-
&& parsedMessagesBeforeSend.length > this.committedMessages.length
|
|
2508
|
-
&& parsedMessagesBeforeSend.some((message: any) => message?.role === 'assistant' && typeof message?.content === 'string' && message.content.trim());
|
|
2509
|
-
if (shouldCommitParsedIdleBeforeSend) {
|
|
2510
|
-
this.commitCurrentTranscript();
|
|
2511
|
-
}
|
|
2512
1894
|
if (!allowInputDuringGeneration && (parsedSessionStatus === 'generating' || parsedSessionStatus === 'long_generating')) {
|
|
2513
1895
|
throw new Error(`${this.cliName} is still processing the previous prompt`);
|
|
2514
1896
|
}
|
|
@@ -2617,9 +1999,6 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
2617
1999
|
activeModal: this.activeModal,
|
|
2618
2000
|
parseErrorMessage: this.parseErrorMessage,
|
|
2619
2001
|
messageCounts: {
|
|
2620
|
-
committed: this.committedMessages.length,
|
|
2621
|
-
structured: this.structuredMessages.length,
|
|
2622
|
-
visible: this.messages.length,
|
|
2623
2002
|
parsedCache: Array.isArray(parsedResult?.messages) ? parsedResult.messages.length : undefined,
|
|
2624
2003
|
},
|
|
2625
2004
|
buffers: {
|
|
@@ -2673,7 +2052,6 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
2673
2052
|
responseEpoch: this.responseEpoch,
|
|
2674
2053
|
resizeSuppressUntil: this.resizeSuppressUntil,
|
|
2675
2054
|
lastApprovalResolvedAt: this.lastApprovalResolvedAt,
|
|
2676
|
-
committedMessagesChangedAt: this.committedMessagesChangedAt,
|
|
2677
2055
|
},
|
|
2678
2056
|
finish: {
|
|
2679
2057
|
idleFinishCandidate: this.idleFinishCandidate,
|
|
@@ -2807,8 +2185,6 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
2807
2185
|
|
|
2808
2186
|
clearHistory(): void {
|
|
2809
2187
|
this.clearIdleFinishCandidate('clear_history');
|
|
2810
|
-
this.committedMessages = [];
|
|
2811
|
-
this.syncMessageViews();
|
|
2812
2188
|
this.accumulatedBuffer = '';
|
|
2813
2189
|
this.accumulatedRawBuffer = '';
|
|
2814
2190
|
this.currentTurnScope = null;
|
|
@@ -2839,7 +2215,7 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
2839
2215
|
|
|
2840
2216
|
resolveModal(buttonIndex: number): void {
|
|
2841
2217
|
let modal = this.activeModal || this.runParseApproval(this.recentOutputBuffer);
|
|
2842
|
-
if (!modal && typeof this.cliScripts?.
|
|
2218
|
+
if (!modal && typeof this.cliScripts?.parseSession === 'function') {
|
|
2843
2219
|
try {
|
|
2844
2220
|
const parsed = this.getScriptParsedStatus();
|
|
2845
2221
|
const parsedModal = parsed?.activeModal && Array.isArray(parsed.activeModal.buttons)
|
|
@@ -2913,10 +2289,8 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
2913
2289
|
startupParseGate: this.startupParseGate,
|
|
2914
2290
|
spawnAt: this.spawnAt,
|
|
2915
2291
|
workingDir: this.workingDir,
|
|
2916
|
-
messages:
|
|
2917
|
-
|
|
2918
|
-
structuredMessages: this.structuredMessages,
|
|
2919
|
-
messageCount: this.committedMessages.length,
|
|
2292
|
+
messages: [],
|
|
2293
|
+
messageCount: 0,
|
|
2920
2294
|
screenText: screenText.slice(-4000),
|
|
2921
2295
|
currentTurnScope: this.currentTurnScope,
|
|
2922
2296
|
startupBuffer: this.startupBuffer.slice(-4000),
|
|
@@ -2969,7 +2343,7 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
2969
2343
|
lifecycleStatus: this.isWaitingForResponse ? 'awaiting_response' : 'idle',
|
|
2970
2344
|
activeModal: this.activeModal,
|
|
2971
2345
|
currentTurnScope: this.currentTurnScope,
|
|
2972
|
-
messages:
|
|
2346
|
+
messages: [],
|
|
2973
2347
|
};
|
|
2974
2348
|
}
|
|
2975
2349
|
|