@adhdev/daemon-core 0.9.82-rc.9 → 0.9.82-rc.90
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli-adapters/provider-cli-adapter.d.ts +2 -0
- package/dist/cli-adapters/provider-cli-parse.d.ts +1 -0
- package/dist/cli-adapters/provider-cli-shared.d.ts +2 -0
- package/dist/commands/router.d.ts +22 -0
- package/dist/config/mesh-config.d.ts +66 -1
- package/dist/index.d.ts +13 -6
- package/dist/index.js +5395 -1197
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +5359 -1183
- package/dist/index.mjs.map +1 -1
- package/dist/installer.d.ts +1 -4
- package/dist/launch.d.ts +1 -1
- package/dist/logging/async-batch-writer.d.ts +10 -0
- package/dist/mesh/beads-db.d.ts +18 -0
- package/dist/mesh/mesh-active-work.d.ts +60 -0
- package/dist/mesh/mesh-events.d.ts +29 -5
- package/dist/mesh/mesh-fast-forward.d.ts +39 -0
- package/dist/mesh/mesh-host-ownership.d.ts +9 -0
- package/dist/mesh/mesh-ledger.d.ts +38 -1
- package/dist/mesh/mesh-work-queue.d.ts +27 -5
- package/dist/mesh/refine-config.d.ts +176 -0
- package/dist/providers/chat-message-normalization.d.ts +1 -0
- package/dist/providers/cli-provider-instance.d.ts +2 -1
- package/dist/repo-mesh-types.d.ts +46 -0
- package/dist/status/reporter.d.ts +2 -0
- package/package.json +3 -1
- package/src/boot/daemon-lifecycle.ts +1 -0
- package/src/cli-adapters/provider-cli-adapter.ts +91 -3
- package/src/cli-adapters/provider-cli-parse.d.ts +1 -0
- package/src/cli-adapters/provider-cli-parse.ts +4 -0
- package/src/cli-adapters/provider-cli-runtime.ts +3 -1
- package/src/cli-adapters/provider-cli-shared.d.ts +2 -0
- package/src/cli-adapters/provider-cli-shared.ts +20 -10
- package/src/commands/chat-commands.ts +454 -15
- package/src/commands/cli-manager.ts +126 -0
- package/src/commands/handler.ts +8 -1
- package/src/commands/mesh-coordinator.ts +13 -143
- package/src/commands/router.ts +2687 -435
- package/src/config/chat-history.ts +9 -7
- package/src/config/mesh-config.ts +245 -1
- package/src/daemon/dev-cli-debug.ts +10 -1
- package/src/detection/ide-detector.ts +26 -16
- package/src/index.ts +31 -5
- package/src/installer.d.ts +1 -1
- package/src/installer.ts +8 -6
- package/src/launch.d.ts +1 -1
- package/src/launch.ts +37 -28
- package/src/logging/async-batch-writer.ts +55 -0
- package/src/logging/logger.ts +2 -1
- package/src/mesh/beads-db.ts +176 -0
- package/src/mesh/coordinator-prompt.ts +30 -7
- package/src/mesh/mesh-active-work.ts +243 -0
- package/src/mesh/mesh-events.ts +400 -47
- package/src/mesh/mesh-fast-forward.ts +430 -0
- package/src/mesh/mesh-host-ownership.ts +73 -0
- package/src/mesh/mesh-ledger.ts +138 -1
- package/src/mesh/mesh-work-queue.ts +199 -137
- package/src/mesh/refine-config.ts +356 -0
- package/src/providers/chat-message-normalization.ts +3 -1
- package/src/providers/cli-provider-instance.ts +91 -13
- package/src/providers/ide-provider-instance.ts +17 -3
- package/src/providers/provider-loader.ts +10 -4
- package/src/providers/read-chat-contract.ts +1 -1
- package/src/providers/version-archive.ts +38 -20
- package/src/repo-mesh-types.ts +51 -0
- package/src/status/reporter.ts +15 -0
- package/src/system/host-memory.ts +29 -12
|
@@ -13,7 +13,7 @@ import { flattenContent, normalizeInputEnvelope, type InputEnvelope, type Provid
|
|
|
13
13
|
import { assertProviderSupportsDeclaredInput, assertTextOnlyInput } from '../providers/provider-input-support.js';
|
|
14
14
|
import { validateReadChatResultPayload } from '../providers/read-chat-contract.js';
|
|
15
15
|
import type { ProviderInstance } from '../providers/provider-instance.js';
|
|
16
|
-
import { readProviderChatHistory } from '../config/chat-history.js';
|
|
16
|
+
import { isNativeSourceCanonicalHistory, readProviderChatHistory } from '../config/chat-history.js';
|
|
17
17
|
import { LOG, getRecentLogs } from '../logging/logger.js';
|
|
18
18
|
import { getRecentDebugTrace, recordDebugTrace } from '../logging/debug-trace.js';
|
|
19
19
|
import { buildChatMessageSignature, hashSignatureParts } from '../chat/chat-signatures.js';
|
|
@@ -24,6 +24,8 @@ import { filterUserFacingChatMessages, normalizeChatMessages } from '../provider
|
|
|
24
24
|
const RECENT_SEND_WINDOW_MS = 1200;
|
|
25
25
|
export const READ_CHAT_PROVIDER_EVAL_TIMEOUT_MS = 25_000;
|
|
26
26
|
const HERMES_CLI_STARTING_SEND_SETTLE_MS = 2_000;
|
|
27
|
+
const CLI_NATIVE_HISTORY_FRESH_MS = 5 * 60_000;
|
|
28
|
+
const CLI_NATIVE_TRANSCRIPT_PROVIDERS = new Set(['codex-cli', 'claude-cli']);
|
|
27
29
|
const recentSendByTarget = new Map<string, number>();
|
|
28
30
|
|
|
29
31
|
interface ApprovalSelectableInstance extends ProviderInstance {
|
|
@@ -151,7 +153,17 @@ function getHistorySessionId(h: CommandHelpers, args: any): string | undefined {
|
|
|
151
153
|
const instance = h.ctx.instanceManager?.getInstance(targetSessionId);
|
|
152
154
|
const state = instance?.getState?.();
|
|
153
155
|
const providerSessionId = typeof state?.providerSessionId === 'string' ? state.providerSessionId.trim() : '';
|
|
154
|
-
|
|
156
|
+
if (providerSessionId) return providerSessionId;
|
|
157
|
+
|
|
158
|
+
const currentSession = h.currentSession as any;
|
|
159
|
+
if (currentSession?.sessionId === targetSessionId) {
|
|
160
|
+
const currentProviderSessionId = typeof currentSession.providerSessionId === 'string'
|
|
161
|
+
? currentSession.providerSessionId.trim()
|
|
162
|
+
: '';
|
|
163
|
+
if (currentProviderSessionId) return currentProviderSessionId;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return targetSessionId;
|
|
155
167
|
}
|
|
156
168
|
|
|
157
169
|
function getInteractionId(args: any): string | undefined {
|
|
@@ -221,6 +233,212 @@ function normalizeReadChatMessages(payload: Record<string, any>): ChatMessage[]
|
|
|
221
233
|
return normalizeChatMessages(messages);
|
|
222
234
|
}
|
|
223
235
|
|
|
236
|
+
function getMessageNewestReceivedAt(messages: Array<{ receivedAt?: unknown; timestamp?: unknown }>): number {
|
|
237
|
+
let newest = 0;
|
|
238
|
+
for (const message of messages) {
|
|
239
|
+
const receivedAt = Number(message?.receivedAt ?? message?.timestamp ?? 0);
|
|
240
|
+
if (Number.isFinite(receivedAt) && receivedAt > newest) newest = receivedAt;
|
|
241
|
+
}
|
|
242
|
+
return newest;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function readHistorySessionIdFromMessages(messages: ChatMessage[]): string | undefined {
|
|
246
|
+
for (const message of messages as Array<ChatMessage & { historySessionId?: unknown }>) {
|
|
247
|
+
const historySessionId = typeof message?.historySessionId === 'string' ? message.historySessionId.trim() : '';
|
|
248
|
+
if (historySessionId) return historySessionId;
|
|
249
|
+
}
|
|
250
|
+
return undefined;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function normalizeNativeHistoryMessages(providerType: string, messages: ChatMessage[]): ChatMessage[] {
|
|
254
|
+
let turnIndex = 0;
|
|
255
|
+
return normalizeChatMessages(messages).map((message, index) => {
|
|
256
|
+
const role = typeof message.role === 'string' ? message.role.trim().toLowerCase() : '';
|
|
257
|
+
const kind = typeof message.kind === 'string' && message.kind.trim() ? message.kind.trim() : (role === 'system' ? 'system' : 'standard');
|
|
258
|
+
if ((role === 'user' || role === 'human') && index > 0) turnIndex += 1;
|
|
259
|
+
const historySessionId = typeof (message as any).historySessionId === 'string'
|
|
260
|
+
? (message as any).historySessionId.trim()
|
|
261
|
+
: '';
|
|
262
|
+
const contentHash = hashSignatureParts([
|
|
263
|
+
providerType,
|
|
264
|
+
historySessionId,
|
|
265
|
+
String(message.receivedAt || message.timestamp || index),
|
|
266
|
+
role,
|
|
267
|
+
kind,
|
|
268
|
+
flattenContent(message.content),
|
|
269
|
+
]).slice(0, 12);
|
|
270
|
+
const providerUnitKey = typeof message.providerUnitKey === 'string' && message.providerUnitKey.trim()
|
|
271
|
+
? message.providerUnitKey.trim()
|
|
272
|
+
: `${providerType}:native:${historySessionId || 'workspace'}:${index}:${role || 'message'}:${kind}:${contentHash}`;
|
|
273
|
+
const meta = message.meta && typeof message.meta === 'object' ? message.meta as Record<string, unknown> : undefined;
|
|
274
|
+
const isSystemSessionStart = role === 'system' || kind === 'system' || kind === 'session_start';
|
|
275
|
+
const isActivity = role === 'assistant' && (kind === 'tool' || kind === 'terminal' || kind === 'thought');
|
|
276
|
+
return {
|
|
277
|
+
...message,
|
|
278
|
+
role: role === 'human' ? 'user' : (role || 'assistant'),
|
|
279
|
+
kind: isSystemSessionStart ? 'system' : kind,
|
|
280
|
+
providerUnitKey,
|
|
281
|
+
bubbleId: typeof message.bubbleId === 'string' && message.bubbleId.trim()
|
|
282
|
+
? message.bubbleId.trim()
|
|
283
|
+
: `bubble:${providerUnitKey}`,
|
|
284
|
+
_turnKey: typeof message._turnKey === 'string' && message._turnKey.trim()
|
|
285
|
+
? message._turnKey.trim()
|
|
286
|
+
: `${providerType}:native-turn:${historySessionId || 'workspace'}:${turnIndex}`,
|
|
287
|
+
bubbleState: message.bubbleState || 'final',
|
|
288
|
+
...(isSystemSessionStart ? {
|
|
289
|
+
visibility: message.visibility || 'hidden',
|
|
290
|
+
transcriptVisibility: message.transcriptVisibility || 'hidden',
|
|
291
|
+
audience: message.audience || 'internal',
|
|
292
|
+
source: message.source || 'runtime_status',
|
|
293
|
+
} : isActivity ? {
|
|
294
|
+
source: message.source || (kind === 'terminal' ? 'terminal_command' : 'tool_call'),
|
|
295
|
+
meta: { ...meta, label: message.senderName || meta?.label || (kind === 'terminal' ? 'Terminal' : 'Tool') },
|
|
296
|
+
} : {
|
|
297
|
+
source: message.source || (role === 'assistant' ? 'assistant_text' : undefined),
|
|
298
|
+
}),
|
|
299
|
+
} as ChatMessage;
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
function buildCliMessageSourceProvenance(args: {
|
|
304
|
+
selected: 'native-history' | 'pty-parser';
|
|
305
|
+
provider: string;
|
|
306
|
+
nativeHandle?: string;
|
|
307
|
+
fallbackReason?: string;
|
|
308
|
+
nativeSource?: string;
|
|
309
|
+
sourcePath?: string;
|
|
310
|
+
sourceMtimeMs?: number;
|
|
311
|
+
nativeMessages?: ChatMessage[];
|
|
312
|
+
ptyMessages?: ChatMessage[];
|
|
313
|
+
returnedMessages?: ChatMessage[];
|
|
314
|
+
safeMapping?: boolean;
|
|
315
|
+
freshEnough?: boolean;
|
|
316
|
+
ptyStatusApprovalOnly?: boolean;
|
|
317
|
+
}): Record<string, unknown> {
|
|
318
|
+
const sourceMtimeMs = Number(args.sourceMtimeMs || 0);
|
|
319
|
+
const sourceMtimeAgeMs = sourceMtimeMs > 0 ? Math.max(0, Date.now() - sourceMtimeMs) : undefined;
|
|
320
|
+
const nativeMessages = args.nativeMessages || [];
|
|
321
|
+
const ptyMessages = args.ptyMessages || [];
|
|
322
|
+
const returnedMessages = args.returnedMessages || [];
|
|
323
|
+
return {
|
|
324
|
+
selected: args.selected,
|
|
325
|
+
provider: args.provider,
|
|
326
|
+
providerType: args.provider,
|
|
327
|
+
...(args.nativeHandle ? { nativeHandle: args.nativeHandle } : {}),
|
|
328
|
+
...(args.nativeHandle ? { nativeSessionId: args.nativeHandle } : {}),
|
|
329
|
+
...(args.fallbackReason ? { fallbackReason: args.fallbackReason } : {}),
|
|
330
|
+
...(args.nativeSource ? { nativeSource: args.nativeSource } : {}),
|
|
331
|
+
...(args.sourcePath ? { sourcePath: args.sourcePath } : {}),
|
|
332
|
+
ptyStatusApprovalOnly: args.ptyStatusApprovalOnly === true,
|
|
333
|
+
staleness: {
|
|
334
|
+
sourceMtimeMs: sourceMtimeMs || undefined,
|
|
335
|
+
sourceMtimeAgeMs,
|
|
336
|
+
nativeNewestMessageAt: getMessageNewestReceivedAt(nativeMessages),
|
|
337
|
+
ptyNewestMessageAt: getMessageNewestReceivedAt(ptyMessages),
|
|
338
|
+
freshEnough: args.freshEnough === true,
|
|
339
|
+
},
|
|
340
|
+
coverage: {
|
|
341
|
+
nativeMessageCount: nativeMessages.length,
|
|
342
|
+
ptyMessageCount: ptyMessages.length,
|
|
343
|
+
returnedMessageCount: returnedMessages.length,
|
|
344
|
+
safeMapping: args.safeMapping === true,
|
|
345
|
+
},
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
function buildNativeHistoryFallbackReason(args: {
|
|
350
|
+
providerType: string;
|
|
351
|
+
provider?: ProviderModule;
|
|
352
|
+
nativeSource?: string;
|
|
353
|
+
nativeMessageCount: number;
|
|
354
|
+
safeMapping: boolean;
|
|
355
|
+
freshEnough: boolean;
|
|
356
|
+
}): string {
|
|
357
|
+
if (!supportsCliNativeTranscript(args.providerType, args.provider)) return 'provider_native_transcript_not_supported';
|
|
358
|
+
if (args.nativeSource === 'native-unavailable') return 'native_history_unavailable';
|
|
359
|
+
if (args.nativeSource && args.nativeSource !== 'provider-native') return `native_history_source_${args.nativeSource}`;
|
|
360
|
+
if (args.nativeMessageCount <= 0) return 'native_history_empty';
|
|
361
|
+
if (!args.safeMapping) return 'native_history_not_safely_mapped';
|
|
362
|
+
if (!args.freshEnough) return 'native_history_stale';
|
|
363
|
+
return 'native_history_not_selected';
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
function supportsCliNativeTranscript(providerType: string, provider?: ProviderModule): boolean {
|
|
367
|
+
if (CLI_NATIVE_TRANSCRIPT_PROVIDERS.has(providerType)) return true;
|
|
368
|
+
return provider?.category === 'cli' && isNativeSourceCanonicalHistory(provider?.canonicalHistory);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
function hasSafeNativeHistoryMapping(args: {
|
|
372
|
+
historySessionId?: string;
|
|
373
|
+
providerSessionId?: string;
|
|
374
|
+
workspace?: string;
|
|
375
|
+
nativeMessages: ChatMessage[];
|
|
376
|
+
}): boolean {
|
|
377
|
+
const explicitSessionId = String(args.historySessionId || args.providerSessionId || '').trim();
|
|
378
|
+
if (explicitSessionId) {
|
|
379
|
+
const messageSessionIds = args.nativeMessages
|
|
380
|
+
.map((message: any) => typeof message?.historySessionId === 'string' ? message.historySessionId.trim() : '')
|
|
381
|
+
.filter(Boolean);
|
|
382
|
+
if (messageSessionIds.length === 0) return true;
|
|
383
|
+
return messageSessionIds.some((id) => id === explicitSessionId);
|
|
384
|
+
}
|
|
385
|
+
const workspace = String(args.workspace || '').trim();
|
|
386
|
+
if (!workspace) return false;
|
|
387
|
+
return args.nativeMessages.some((message: any) => String(message?.workspace || '').trim() === workspace);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
function readCliProviderNativeHistory(agentStr: string, args: {
|
|
391
|
+
canonicalHistory?: ProviderModule['canonicalHistory'];
|
|
392
|
+
historySessionId?: string;
|
|
393
|
+
workspace?: string;
|
|
394
|
+
offset: number;
|
|
395
|
+
limit: number;
|
|
396
|
+
excludeRecentCount: number;
|
|
397
|
+
historyBehavior?: ProviderModule['historyBehavior'];
|
|
398
|
+
scripts?: ProviderScripts;
|
|
399
|
+
}): ReturnType<typeof readProviderChatHistory> & { lookup: 'session' | 'workspace' } {
|
|
400
|
+
const sessionHistory = readProviderChatHistory(agentStr, {
|
|
401
|
+
canonicalHistory: args.canonicalHistory,
|
|
402
|
+
historySessionId: args.historySessionId,
|
|
403
|
+
workspace: args.workspace,
|
|
404
|
+
offset: args.offset,
|
|
405
|
+
limit: args.limit,
|
|
406
|
+
excludeRecentCount: args.excludeRecentCount,
|
|
407
|
+
historyBehavior: args.historyBehavior,
|
|
408
|
+
scripts: args.scripts as any,
|
|
409
|
+
});
|
|
410
|
+
if ((sessionHistory as any).source !== 'native-unavailable' || !args.historySessionId || !args.workspace) {
|
|
411
|
+
return { ...(sessionHistory as any), lookup: 'session' };
|
|
412
|
+
}
|
|
413
|
+
const workspaceHistory = readProviderChatHistory(agentStr, {
|
|
414
|
+
canonicalHistory: args.canonicalHistory,
|
|
415
|
+
historySessionId: undefined,
|
|
416
|
+
workspace: args.workspace,
|
|
417
|
+
offset: args.offset,
|
|
418
|
+
limit: args.limit,
|
|
419
|
+
excludeRecentCount: args.excludeRecentCount,
|
|
420
|
+
historyBehavior: args.historyBehavior,
|
|
421
|
+
scripts: args.scripts as any,
|
|
422
|
+
});
|
|
423
|
+
return { ...(workspaceHistory as any), lookup: 'workspace' };
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
function isNativeHistoryFreshEnough(args: {
|
|
427
|
+
sourceMtimeMs?: number;
|
|
428
|
+
nativeMessages: ChatMessage[];
|
|
429
|
+
ptyMessages: ChatMessage[];
|
|
430
|
+
}): boolean {
|
|
431
|
+
const nativeNewest = getMessageNewestReceivedAt(args.nativeMessages);
|
|
432
|
+
const ptyNewest = getMessageNewestReceivedAt(args.ptyMessages);
|
|
433
|
+
if (nativeNewest > 0 && nativeNewest >= ptyNewest) return true;
|
|
434
|
+
const sourceMtimeMs = Number(args.sourceMtimeMs || 0);
|
|
435
|
+
if (sourceMtimeMs > 0 && Date.now() - sourceMtimeMs <= CLI_NATIVE_HISTORY_FRESH_MS) return true;
|
|
436
|
+
return ptyNewest === 0 && nativeNewest > 0;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
function shouldPreserveReadChatPayloadField(key: string): boolean {
|
|
440
|
+
return key === 'messageSource' || key === 'transcriptProvenance';
|
|
441
|
+
}
|
|
224
442
|
|
|
225
443
|
function deriveHistoryDedupKey(message: ChatMessage & { _unitKey?: string; _turnKey?: string }): string | undefined {
|
|
226
444
|
const unitKey = typeof message._unitKey === 'string' ? message._unitKey.trim() : '';
|
|
@@ -281,7 +499,7 @@ function normalizeReadChatCommandStatus(status: unknown, activeModal: unknown):
|
|
|
281
499
|
}
|
|
282
500
|
switch (raw) {
|
|
283
501
|
case 'starting':
|
|
284
|
-
return hasNonEmptyModalButtons(activeModal) ? 'waiting_approval' : '
|
|
502
|
+
return hasNonEmptyModalButtons(activeModal) ? 'waiting_approval' : 'starting';
|
|
285
503
|
case 'stopped':
|
|
286
504
|
case 'disconnected':
|
|
287
505
|
case 'not_monitored':
|
|
@@ -295,6 +513,16 @@ function isGeneratingLikeStatus(status: unknown): boolean {
|
|
|
295
513
|
return status === 'generating' || status === 'streaming' || status === 'long_generating' || status === 'starting';
|
|
296
514
|
}
|
|
297
515
|
|
|
516
|
+
function hasVisibleAssistantMessage(messages: unknown[] | undefined): boolean {
|
|
517
|
+
if (!Array.isArray(messages)) return false;
|
|
518
|
+
return messages.some((message: any) => {
|
|
519
|
+
if (!message || message.role !== 'assistant') return false;
|
|
520
|
+
const kind = typeof message.kind === 'string' ? message.kind : 'standard';
|
|
521
|
+
if (kind !== 'standard') return false;
|
|
522
|
+
return String(message.content || '').trim().length > 0;
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
|
|
298
526
|
function shouldTrustCliAdapterTerminalStatus(parsedStatus: unknown, activeModal: unknown, adapter: CliAdapter, adapterStatus: any): boolean {
|
|
299
527
|
if (!isGeneratingLikeStatus(parsedStatus)) return false;
|
|
300
528
|
if (hasNonEmptyModalButtons(activeModal)) return false;
|
|
@@ -304,7 +532,26 @@ function shouldTrustCliAdapterTerminalStatus(parsedStatus: unknown, activeModal:
|
|
|
304
532
|
return true;
|
|
305
533
|
}
|
|
306
534
|
|
|
307
|
-
function normalizeCliReadChatStatus(parsedStatus: unknown, activeModal: unknown, adapter: CliAdapter, adapterStatus: any): string {
|
|
535
|
+
function normalizeCliReadChatStatus(parsedStatus: unknown, activeModal: unknown, adapter: CliAdapter, adapterStatus: any, parsedMessages?: unknown[]): string {
|
|
536
|
+
const adapterRawStatus = typeof adapterStatus?.status === 'string' ? adapterStatus.status.trim() : '';
|
|
537
|
+
if (adapterRawStatus === 'starting'
|
|
538
|
+
&& isGeneratingLikeStatus(parsedStatus)
|
|
539
|
+
&& !hasNonEmptyModalButtons(activeModal)
|
|
540
|
+
&& Array.isArray(parsedMessages)
|
|
541
|
+
&& parsedMessages.length === 0
|
|
542
|
+
&& Array.isArray(adapterStatus?.messages)
|
|
543
|
+
&& adapterStatus.messages.length === 0
|
|
544
|
+
&& !(typeof adapter.isProcessing === 'function' && adapter.isProcessing())) {
|
|
545
|
+
return 'starting';
|
|
546
|
+
}
|
|
547
|
+
if (
|
|
548
|
+
isGeneratingLikeStatus(adapterRawStatus)
|
|
549
|
+
&& parsedStatus === 'idle'
|
|
550
|
+
&& !hasNonEmptyModalButtons(activeModal)
|
|
551
|
+
&& !hasVisibleAssistantMessage(parsedMessages)
|
|
552
|
+
) {
|
|
553
|
+
return adapterRawStatus;
|
|
554
|
+
}
|
|
308
555
|
if (shouldTrustCliAdapterTerminalStatus(parsedStatus, activeModal, adapter, adapterStatus)) return 'idle';
|
|
309
556
|
return typeof parsedStatus === 'string' && parsedStatus.trim() ? parsedStatus : 'idle';
|
|
310
557
|
}
|
|
@@ -356,6 +603,7 @@ function buildReadChatCommandResult(payload: Record<string, any>, args: any): Co
|
|
|
356
603
|
return {
|
|
357
604
|
success: true,
|
|
358
605
|
...validatedPayload,
|
|
606
|
+
...Object.fromEntries(Object.entries(payload).filter(([key]) => shouldPreserveReadChatPayloadField(key))),
|
|
359
607
|
messages: sync.messages,
|
|
360
608
|
totalMessages: sync.totalMessages,
|
|
361
609
|
...(returnedDebugReadChat ? { debugReadChat: returnedDebugReadChat } : {}),
|
|
@@ -584,6 +832,8 @@ function buildChatDebugBundleSummary(bundle: Record<string, unknown>): Record<st
|
|
|
584
832
|
adapterStatus: debugReadChat.adapterStatus,
|
|
585
833
|
parsedStatus: debugReadChat.parsedStatus,
|
|
586
834
|
returnedStatus: debugReadChat.returnedStatus,
|
|
835
|
+
selectedMessageSource: debugReadChat.selectedMessageSource,
|
|
836
|
+
messageSource: debugReadChat.messageSource,
|
|
587
837
|
parsedMsgCount: debugReadChat.parsedMsgCount,
|
|
588
838
|
returnedMsgCount: debugReadChat.returnedMsgCount,
|
|
589
839
|
shouldPreferAdapterMessages: debugReadChat.shouldPreferAdapterMessages,
|
|
@@ -646,6 +896,8 @@ export async function handleGetChatDebugBundle(h: CommandHelpers, args: any): Pr
|
|
|
646
896
|
providerSessionId: readResult.providerSessionId,
|
|
647
897
|
transcriptAuthority: readResult.transcriptAuthority,
|
|
648
898
|
coverage: readResult.coverage,
|
|
899
|
+
messageSource: readResult.messageSource,
|
|
900
|
+
transcriptProvenance: readResult.transcriptProvenance,
|
|
649
901
|
activeModal: readResult.activeModal,
|
|
650
902
|
messagesTail: Array.isArray(readResult.messages) ? readResult.messages.slice(-20) : [],
|
|
651
903
|
debugReadChat: readResult.debugReadChat,
|
|
@@ -874,7 +1126,7 @@ export async function handleReadChat(h: CommandHelpers, args: any): Promise<Comm
|
|
|
874
1126
|
? parsedRecord.coverage
|
|
875
1127
|
: undefined;
|
|
876
1128
|
const activeModal = parsedRecord.activeModal ?? parsedRecord.modal ?? null;
|
|
877
|
-
const returnedStatus = normalizeCliReadChatStatus(parsedRecord.status, activeModal, adapter, adapterStatus);
|
|
1129
|
+
const returnedStatus = normalizeCliReadChatStatus(parsedRecord.status, activeModal, adapter, adapterStatus, parsedRecord.messages);
|
|
878
1130
|
const runtimeMessageMerger = getTargetInstance(h, args) as RuntimeChatMessageMerger | null;
|
|
879
1131
|
const parsedMessages = finalizeStreamingMessagesWhenIdle(parsedRecord.messages as ChatMessage[], returnedStatus);
|
|
880
1132
|
const returnedMessages = runtimeMessageMerger?.category === 'cli'
|
|
@@ -882,25 +1134,148 @@ export async function handleReadChat(h: CommandHelpers, args: any): Promise<Comm
|
|
|
882
1134
|
&& typeof runtimeMessageMerger.mergeRuntimeChatMessages === 'function'
|
|
883
1135
|
? runtimeMessageMerger.mergeRuntimeChatMessages(parsedMessages)
|
|
884
1136
|
: parsedMessages;
|
|
1137
|
+
const providerType = provider?.type || adapter.cliType;
|
|
1138
|
+
let selectedMessages = returnedMessages;
|
|
1139
|
+
let selectedTitle = title;
|
|
1140
|
+
let selectedProviderSessionId = providerSessionId;
|
|
1141
|
+
let selectedTranscriptAuthority = transcriptAuthority;
|
|
1142
|
+
let selectedCoverage = coverage;
|
|
1143
|
+
let messageSource = buildCliMessageSourceProvenance({
|
|
1144
|
+
selected: 'pty-parser',
|
|
1145
|
+
provider: adapter.cliType,
|
|
1146
|
+
fallbackReason: supportsCliNativeTranscript(providerType, provider) ? 'native_history_not_checked' : 'provider_native_transcript_not_supported',
|
|
1147
|
+
ptyMessages: returnedMessages,
|
|
1148
|
+
returnedMessages,
|
|
1149
|
+
ptyStatusApprovalOnly: false,
|
|
1150
|
+
});
|
|
1151
|
+
|
|
1152
|
+
if (supportsCliNativeTranscript(providerType, provider) && isNativeSourceCanonicalHistory(provider?.canonicalHistory)) {
|
|
1153
|
+
const agentStr = provider?.type || args?.agentType || getCurrentProviderType(h, adapter.cliType);
|
|
1154
|
+
const workspace = typeof args?.workspace === 'string'
|
|
1155
|
+
? args.workspace
|
|
1156
|
+
: typeof (h.currentSession as any)?.workspace === 'string'
|
|
1157
|
+
? (h.currentSession as any).workspace
|
|
1158
|
+
: typeof adapter.workingDir === 'string'
|
|
1159
|
+
? adapter.workingDir
|
|
1160
|
+
: undefined;
|
|
1161
|
+
const nativeHistoryLimit = Math.max(
|
|
1162
|
+
normalizeReadChatTailLimit(args) || 0,
|
|
1163
|
+
returnedMessages.length,
|
|
1164
|
+
200,
|
|
1165
|
+
);
|
|
1166
|
+
let nativeHistory: (ReturnType<typeof readProviderChatHistory> & { lookup?: 'session' | 'workspace' }) | null = null;
|
|
1167
|
+
try {
|
|
1168
|
+
nativeHistory = readCliProviderNativeHistory(agentStr, {
|
|
1169
|
+
canonicalHistory: provider?.canonicalHistory,
|
|
1170
|
+
historySessionId,
|
|
1171
|
+
workspace,
|
|
1172
|
+
offset: 0,
|
|
1173
|
+
limit: nativeHistoryLimit,
|
|
1174
|
+
excludeRecentCount: 0,
|
|
1175
|
+
historyBehavior: provider?.historyBehavior,
|
|
1176
|
+
scripts: provider?.scripts as any,
|
|
1177
|
+
});
|
|
1178
|
+
} catch (error: any) {
|
|
1179
|
+
const fallbackReason = `native_history_error:${error?.message || String(error)}`;
|
|
1180
|
+
messageSource = buildCliMessageSourceProvenance({
|
|
1181
|
+
selected: 'pty-parser',
|
|
1182
|
+
provider: adapter.cliType,
|
|
1183
|
+
fallbackReason,
|
|
1184
|
+
ptyMessages: returnedMessages,
|
|
1185
|
+
returnedMessages,
|
|
1186
|
+
ptyStatusApprovalOnly: false,
|
|
1187
|
+
});
|
|
1188
|
+
nativeHistory = null;
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
if (nativeHistory) {
|
|
1192
|
+
const nativeMessages = Array.isArray((nativeHistory as any).messages)
|
|
1193
|
+
? normalizeNativeHistoryMessages(agentStr, (nativeHistory as any).messages as ChatMessage[])
|
|
1194
|
+
: [];
|
|
1195
|
+
const historyProviderSessionId = typeof (nativeHistory as any)?.providerSessionId === 'string'
|
|
1196
|
+
? (nativeHistory as any).providerSessionId
|
|
1197
|
+
: readHistorySessionIdFromMessages(nativeMessages) || historySessionId;
|
|
1198
|
+
const lookup = (nativeHistory as any).lookup === 'workspace' ? 'workspace' : 'session';
|
|
1199
|
+
const safeMapping = hasSafeNativeHistoryMapping({
|
|
1200
|
+
historySessionId: lookup === 'workspace' ? undefined : historySessionId,
|
|
1201
|
+
providerSessionId: lookup === 'workspace' ? undefined : providerSessionId,
|
|
1202
|
+
workspace,
|
|
1203
|
+
nativeMessages,
|
|
1204
|
+
});
|
|
1205
|
+
const freshEnough = isNativeHistoryFreshEnough({
|
|
1206
|
+
sourceMtimeMs: (nativeHistory as any).sourceMtimeMs,
|
|
1207
|
+
nativeMessages,
|
|
1208
|
+
ptyMessages: returnedMessages,
|
|
1209
|
+
});
|
|
1210
|
+
if ((nativeHistory as any).source === 'provider-native' && nativeMessages.length > 0 && safeMapping && freshEnough) {
|
|
1211
|
+
selectedMessages = finalizeStreamingMessagesWhenIdle(nativeMessages, returnedStatus);
|
|
1212
|
+
selectedProviderSessionId = historyProviderSessionId || providerSessionId;
|
|
1213
|
+
selectedTranscriptAuthority = 'provider';
|
|
1214
|
+
selectedCoverage = (nativeHistory as any).hasMore ? 'tail' : 'full';
|
|
1215
|
+
messageSource = buildCliMessageSourceProvenance({
|
|
1216
|
+
selected: 'native-history',
|
|
1217
|
+
provider: adapter.cliType,
|
|
1218
|
+
nativeHandle: selectedProviderSessionId || historySessionId,
|
|
1219
|
+
nativeSource: (nativeHistory as any).source,
|
|
1220
|
+
sourcePath: (nativeHistory as any).sourcePath,
|
|
1221
|
+
sourceMtimeMs: (nativeHistory as any).sourceMtimeMs,
|
|
1222
|
+
nativeMessages,
|
|
1223
|
+
ptyMessages: returnedMessages,
|
|
1224
|
+
returnedMessages: selectedMessages,
|
|
1225
|
+
safeMapping,
|
|
1226
|
+
freshEnough,
|
|
1227
|
+
ptyStatusApprovalOnly: true,
|
|
1228
|
+
});
|
|
1229
|
+
} else {
|
|
1230
|
+
const fallbackReason = buildNativeHistoryFallbackReason({
|
|
1231
|
+
providerType,
|
|
1232
|
+
provider,
|
|
1233
|
+
nativeSource: (nativeHistory as any).source,
|
|
1234
|
+
nativeMessageCount: nativeMessages.length,
|
|
1235
|
+
safeMapping,
|
|
1236
|
+
freshEnough,
|
|
1237
|
+
});
|
|
1238
|
+
messageSource = buildCliMessageSourceProvenance({
|
|
1239
|
+
selected: 'pty-parser',
|
|
1240
|
+
provider: adapter.cliType,
|
|
1241
|
+
nativeHandle: historyProviderSessionId || historySessionId,
|
|
1242
|
+
fallbackReason,
|
|
1243
|
+
nativeSource: (nativeHistory as any).source,
|
|
1244
|
+
sourcePath: (nativeHistory as any).sourcePath,
|
|
1245
|
+
sourceMtimeMs: (nativeHistory as any).sourceMtimeMs,
|
|
1246
|
+
nativeMessages,
|
|
1247
|
+
ptyMessages: returnedMessages,
|
|
1248
|
+
returnedMessages,
|
|
1249
|
+
safeMapping,
|
|
1250
|
+
freshEnough,
|
|
1251
|
+
ptyStatusApprovalOnly: false,
|
|
1252
|
+
});
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
885
1256
|
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} returnedMsgCount=${returnedMessages.length}`);
|
|
886
1257
|
return buildReadChatCommandResult({
|
|
887
|
-
messages:
|
|
1258
|
+
messages: selectedMessages,
|
|
888
1259
|
status: returnedStatus,
|
|
889
1260
|
activeModal,
|
|
1261
|
+
messageSource,
|
|
1262
|
+
transcriptProvenance: messageSource,
|
|
890
1263
|
debugReadChat: {
|
|
891
1264
|
provider: adapter.cliType,
|
|
892
1265
|
targetSessionId: String(args?.targetSessionId || ''),
|
|
893
1266
|
adapterStatus: String(adapterStatus.status || ''),
|
|
894
1267
|
parsedStatus: String(parsedRecord.status || ''),
|
|
895
1268
|
returnedStatus: String(returnedStatus || ''),
|
|
896
|
-
|
|
1269
|
+
selectedMessageSource: (messageSource as any).selected,
|
|
1270
|
+
messageSource,
|
|
1271
|
+
shouldPreferAdapterMessages: supportsCliNativeTranscript(providerType, provider) && (messageSource as any).selected !== 'native-history',
|
|
897
1272
|
parsedMsgCount: parsedRecord.messages.length,
|
|
898
|
-
returnedMsgCount:
|
|
1273
|
+
returnedMsgCount: selectedMessages.length,
|
|
899
1274
|
},
|
|
900
|
-
...(
|
|
901
|
-
...(
|
|
902
|
-
...(
|
|
903
|
-
...(
|
|
1275
|
+
...(selectedTitle ? { title: selectedTitle } : {}),
|
|
1276
|
+
...(selectedProviderSessionId ? { providerSessionId: selectedProviderSessionId } : {}),
|
|
1277
|
+
...(selectedTranscriptAuthority ? { transcriptAuthority: selectedTranscriptAuthority } : {}),
|
|
1278
|
+
...(selectedCoverage ? { coverage: selectedCoverage } : {}),
|
|
904
1279
|
}, args);
|
|
905
1280
|
}
|
|
906
1281
|
const historyLimit = normalizeReadChatTailLimit(args);
|
|
@@ -911,7 +1286,18 @@ export async function handleReadChat(h: CommandHelpers, args: any): Promise<Comm
|
|
|
911
1286
|
: typeof (h.currentSession as any)?.workspace === 'string'
|
|
912
1287
|
? (h.currentSession as any).workspace
|
|
913
1288
|
: undefined;
|
|
914
|
-
const history =
|
|
1289
|
+
const history = supportsCliNativeTranscript(agentStr, provider) && isNativeSourceCanonicalHistory(provider?.canonicalHistory)
|
|
1290
|
+
? readCliProviderNativeHistory(agentStr, {
|
|
1291
|
+
canonicalHistory: provider?.canonicalHistory,
|
|
1292
|
+
historySessionId,
|
|
1293
|
+
workspace,
|
|
1294
|
+
offset: 0,
|
|
1295
|
+
limit: historyLimit,
|
|
1296
|
+
excludeRecentCount: 0,
|
|
1297
|
+
historyBehavior: provider?.historyBehavior,
|
|
1298
|
+
scripts: provider?.scripts as any,
|
|
1299
|
+
})
|
|
1300
|
+
: readProviderChatHistory(agentStr, {
|
|
915
1301
|
canonicalHistory: provider?.canonicalHistory,
|
|
916
1302
|
historySessionId,
|
|
917
1303
|
workspace,
|
|
@@ -921,12 +1307,65 @@ export async function handleReadChat(h: CommandHelpers, args: any): Promise<Comm
|
|
|
921
1307
|
historyBehavior: provider?.historyBehavior,
|
|
922
1308
|
scripts: provider?.scripts as any,
|
|
923
1309
|
});
|
|
1310
|
+
const lookup = (history as any).lookup === 'workspace' ? 'workspace' : 'session';
|
|
1311
|
+
const historyMessages = Array.isArray((history as any)?.messages)
|
|
1312
|
+
? normalizeNativeHistoryMessages(agentStr, (history as any).messages as ChatMessage[])
|
|
1313
|
+
: [];
|
|
924
1314
|
const historyProviderSessionId = typeof (history as any)?.providerSessionId === 'string'
|
|
925
1315
|
? (history as any).providerSessionId
|
|
926
|
-
: historySessionId;
|
|
1316
|
+
: readHistorySessionIdFromMessages(historyMessages) || historySessionId;
|
|
1317
|
+
const safeMapping = supportsCliNativeTranscript(agentStr, provider)
|
|
1318
|
+
? hasSafeNativeHistoryMapping({
|
|
1319
|
+
historySessionId: lookup === 'workspace' ? undefined : historySessionId,
|
|
1320
|
+
providerSessionId: lookup === 'workspace' ? undefined : historyProviderSessionId,
|
|
1321
|
+
workspace,
|
|
1322
|
+
nativeMessages: historyMessages,
|
|
1323
|
+
})
|
|
1324
|
+
: false;
|
|
1325
|
+
const nativeSelected = supportsCliNativeTranscript(agentStr, provider)
|
|
1326
|
+
&& (history as any).source === 'provider-native'
|
|
1327
|
+
&& historyMessages.length > 0
|
|
1328
|
+
&& safeMapping;
|
|
1329
|
+
const messageSource = buildCliMessageSourceProvenance({
|
|
1330
|
+
selected: nativeSelected ? 'native-history' : 'pty-parser',
|
|
1331
|
+
provider: agentStr,
|
|
1332
|
+
nativeHandle: historyProviderSessionId || historySessionId,
|
|
1333
|
+
fallbackReason: nativeSelected
|
|
1334
|
+
? undefined
|
|
1335
|
+
: buildNativeHistoryFallbackReason({
|
|
1336
|
+
providerType: agentStr,
|
|
1337
|
+
provider,
|
|
1338
|
+
nativeSource: (history as any).source,
|
|
1339
|
+
nativeMessageCount: historyMessages.length,
|
|
1340
|
+
safeMapping,
|
|
1341
|
+
freshEnough: true,
|
|
1342
|
+
}),
|
|
1343
|
+
nativeSource: (history as any).source,
|
|
1344
|
+
sourcePath: (history as any).sourcePath,
|
|
1345
|
+
sourceMtimeMs: (history as any).sourceMtimeMs,
|
|
1346
|
+
nativeMessages: historyMessages,
|
|
1347
|
+
returnedMessages: historyMessages,
|
|
1348
|
+
safeMapping,
|
|
1349
|
+
freshEnough: true,
|
|
1350
|
+
ptyStatusApprovalOnly: false,
|
|
1351
|
+
});
|
|
1352
|
+
const requiresNativeSource = supportsCliNativeTranscript(agentStr, provider)
|
|
1353
|
+
&& isNativeSourceCanonicalHistory(provider?.canonicalHistory);
|
|
1354
|
+
if (requiresNativeSource && !nativeSelected) {
|
|
1355
|
+
return {
|
|
1356
|
+
success: false,
|
|
1357
|
+
code: 'native_history_not_safely_available',
|
|
1358
|
+
error: 'Provider-native history was not safely available for the requested CLI session.',
|
|
1359
|
+
providerSessionId: historyProviderSessionId,
|
|
1360
|
+
messageSource,
|
|
1361
|
+
transcriptProvenance: messageSource,
|
|
1362
|
+
};
|
|
1363
|
+
}
|
|
927
1364
|
return buildReadChatCommandResult({
|
|
928
|
-
messages:
|
|
1365
|
+
messages: historyMessages,
|
|
929
1366
|
status: 'idle',
|
|
1367
|
+
messageSource,
|
|
1368
|
+
transcriptProvenance: messageSource,
|
|
930
1369
|
...(typeof (history as any)?.title === 'string' ? { title: (history as any).title } : {}),
|
|
931
1370
|
...(historyProviderSessionId ? { providerSessionId: historyProviderSessionId } : {}),
|
|
932
1371
|
...(((provider?.historyBehavior as any)?.transcriptAuthority === 'provider' || (provider?.historyBehavior as any)?.transcriptAuthority === 'daemon')
|