@adhdev/daemon-core 0.9.82-rc.9 → 0.9.82-rc.91
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 +5417 -1207
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +5381 -1193
- 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 +472 -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 +255 -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 +7 -12
- package/src/providers/cli-provider-instance.ts +93 -14
- 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,217 @@ 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
|
+
exactSessionScoped?: boolean;
|
|
400
|
+
}): ReturnType<typeof readProviderChatHistory> & { lookup: 'session' | 'workspace' } {
|
|
401
|
+
const sessionHistory = readProviderChatHistory(agentStr, {
|
|
402
|
+
canonicalHistory: args.canonicalHistory,
|
|
403
|
+
historySessionId: args.historySessionId,
|
|
404
|
+
workspace: args.workspace,
|
|
405
|
+
offset: args.offset,
|
|
406
|
+
limit: args.limit,
|
|
407
|
+
excludeRecentCount: args.excludeRecentCount,
|
|
408
|
+
historyBehavior: args.historyBehavior,
|
|
409
|
+
scripts: args.scripts as any,
|
|
410
|
+
});
|
|
411
|
+
// Exact runtime/provider transcript reads must not silently fall back to the
|
|
412
|
+
// workspace's active or most recent native transcript: multiple Hermes/Gemini/
|
|
413
|
+
// Codex sessions can run in the same workspace, and workspace fallback can make
|
|
414
|
+
// read_chat/completion evidence point at a different runtime's prompt.
|
|
415
|
+
if ((sessionHistory as any).source !== 'native-unavailable' || args.exactSessionScoped || !args.historySessionId || !args.workspace) {
|
|
416
|
+
return { ...(sessionHistory as any), lookup: args.historySessionId ? 'session' : 'workspace' };
|
|
417
|
+
}
|
|
418
|
+
const workspaceHistory = readProviderChatHistory(agentStr, {
|
|
419
|
+
canonicalHistory: args.canonicalHistory,
|
|
420
|
+
historySessionId: undefined,
|
|
421
|
+
workspace: args.workspace,
|
|
422
|
+
offset: args.offset,
|
|
423
|
+
limit: args.limit,
|
|
424
|
+
excludeRecentCount: args.excludeRecentCount,
|
|
425
|
+
historyBehavior: args.historyBehavior,
|
|
426
|
+
scripts: args.scripts as any,
|
|
427
|
+
});
|
|
428
|
+
return { ...(workspaceHistory as any), lookup: 'workspace' };
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
function isNativeHistoryFreshEnough(args: {
|
|
432
|
+
sourceMtimeMs?: number;
|
|
433
|
+
nativeMessages: ChatMessage[];
|
|
434
|
+
ptyMessages: ChatMessage[];
|
|
435
|
+
}): boolean {
|
|
436
|
+
const nativeNewest = getMessageNewestReceivedAt(args.nativeMessages);
|
|
437
|
+
const ptyNewest = getMessageNewestReceivedAt(args.ptyMessages);
|
|
438
|
+
if (nativeNewest > 0 && nativeNewest >= ptyNewest) return true;
|
|
439
|
+
const sourceMtimeMs = Number(args.sourceMtimeMs || 0);
|
|
440
|
+
if (sourceMtimeMs > 0 && Date.now() - sourceMtimeMs <= CLI_NATIVE_HISTORY_FRESH_MS) return true;
|
|
441
|
+
return ptyNewest === 0 && nativeNewest > 0;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
function shouldPreserveReadChatPayloadField(key: string): boolean {
|
|
445
|
+
return key === 'messageSource' || key === 'transcriptProvenance';
|
|
446
|
+
}
|
|
224
447
|
|
|
225
448
|
function deriveHistoryDedupKey(message: ChatMessage & { _unitKey?: string; _turnKey?: string }): string | undefined {
|
|
226
449
|
const unitKey = typeof message._unitKey === 'string' ? message._unitKey.trim() : '';
|
|
@@ -281,7 +504,7 @@ function normalizeReadChatCommandStatus(status: unknown, activeModal: unknown):
|
|
|
281
504
|
}
|
|
282
505
|
switch (raw) {
|
|
283
506
|
case 'starting':
|
|
284
|
-
return hasNonEmptyModalButtons(activeModal) ? 'waiting_approval' : '
|
|
507
|
+
return hasNonEmptyModalButtons(activeModal) ? 'waiting_approval' : 'starting';
|
|
285
508
|
case 'stopped':
|
|
286
509
|
case 'disconnected':
|
|
287
510
|
case 'not_monitored':
|
|
@@ -295,6 +518,16 @@ function isGeneratingLikeStatus(status: unknown): boolean {
|
|
|
295
518
|
return status === 'generating' || status === 'streaming' || status === 'long_generating' || status === 'starting';
|
|
296
519
|
}
|
|
297
520
|
|
|
521
|
+
function hasVisibleAssistantMessage(messages: unknown[] | undefined): boolean {
|
|
522
|
+
if (!Array.isArray(messages)) return false;
|
|
523
|
+
return messages.some((message: any) => {
|
|
524
|
+
if (!message || message.role !== 'assistant') return false;
|
|
525
|
+
const kind = typeof message.kind === 'string' ? message.kind : 'standard';
|
|
526
|
+
if (kind !== 'standard') return false;
|
|
527
|
+
return String(message.content || '').trim().length > 0;
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
|
|
298
531
|
function shouldTrustCliAdapterTerminalStatus(parsedStatus: unknown, activeModal: unknown, adapter: CliAdapter, adapterStatus: any): boolean {
|
|
299
532
|
if (!isGeneratingLikeStatus(parsedStatus)) return false;
|
|
300
533
|
if (hasNonEmptyModalButtons(activeModal)) return false;
|
|
@@ -304,7 +537,26 @@ function shouldTrustCliAdapterTerminalStatus(parsedStatus: unknown, activeModal:
|
|
|
304
537
|
return true;
|
|
305
538
|
}
|
|
306
539
|
|
|
307
|
-
function normalizeCliReadChatStatus(parsedStatus: unknown, activeModal: unknown, adapter: CliAdapter, adapterStatus: any): string {
|
|
540
|
+
function normalizeCliReadChatStatus(parsedStatus: unknown, activeModal: unknown, adapter: CliAdapter, adapterStatus: any, parsedMessages?: unknown[]): string {
|
|
541
|
+
const adapterRawStatus = typeof adapterStatus?.status === 'string' ? adapterStatus.status.trim() : '';
|
|
542
|
+
if (adapterRawStatus === 'starting'
|
|
543
|
+
&& isGeneratingLikeStatus(parsedStatus)
|
|
544
|
+
&& !hasNonEmptyModalButtons(activeModal)
|
|
545
|
+
&& Array.isArray(parsedMessages)
|
|
546
|
+
&& parsedMessages.length === 0
|
|
547
|
+
&& Array.isArray(adapterStatus?.messages)
|
|
548
|
+
&& adapterStatus.messages.length === 0
|
|
549
|
+
&& !(typeof adapter.isProcessing === 'function' && adapter.isProcessing())) {
|
|
550
|
+
return 'starting';
|
|
551
|
+
}
|
|
552
|
+
if (
|
|
553
|
+
isGeneratingLikeStatus(adapterRawStatus)
|
|
554
|
+
&& parsedStatus === 'idle'
|
|
555
|
+
&& !hasNonEmptyModalButtons(activeModal)
|
|
556
|
+
&& !hasVisibleAssistantMessage(parsedMessages)
|
|
557
|
+
) {
|
|
558
|
+
return adapterRawStatus;
|
|
559
|
+
}
|
|
308
560
|
if (shouldTrustCliAdapterTerminalStatus(parsedStatus, activeModal, adapter, adapterStatus)) return 'idle';
|
|
309
561
|
return typeof parsedStatus === 'string' && parsedStatus.trim() ? parsedStatus : 'idle';
|
|
310
562
|
}
|
|
@@ -356,6 +608,7 @@ function buildReadChatCommandResult(payload: Record<string, any>, args: any): Co
|
|
|
356
608
|
return {
|
|
357
609
|
success: true,
|
|
358
610
|
...validatedPayload,
|
|
611
|
+
...Object.fromEntries(Object.entries(payload).filter(([key]) => shouldPreserveReadChatPayloadField(key))),
|
|
359
612
|
messages: sync.messages,
|
|
360
613
|
totalMessages: sync.totalMessages,
|
|
361
614
|
...(returnedDebugReadChat ? { debugReadChat: returnedDebugReadChat } : {}),
|
|
@@ -584,6 +837,8 @@ function buildChatDebugBundleSummary(bundle: Record<string, unknown>): Record<st
|
|
|
584
837
|
adapterStatus: debugReadChat.adapterStatus,
|
|
585
838
|
parsedStatus: debugReadChat.parsedStatus,
|
|
586
839
|
returnedStatus: debugReadChat.returnedStatus,
|
|
840
|
+
selectedMessageSource: debugReadChat.selectedMessageSource,
|
|
841
|
+
messageSource: debugReadChat.messageSource,
|
|
587
842
|
parsedMsgCount: debugReadChat.parsedMsgCount,
|
|
588
843
|
returnedMsgCount: debugReadChat.returnedMsgCount,
|
|
589
844
|
shouldPreferAdapterMessages: debugReadChat.shouldPreferAdapterMessages,
|
|
@@ -646,6 +901,8 @@ export async function handleGetChatDebugBundle(h: CommandHelpers, args: any): Pr
|
|
|
646
901
|
providerSessionId: readResult.providerSessionId,
|
|
647
902
|
transcriptAuthority: readResult.transcriptAuthority,
|
|
648
903
|
coverage: readResult.coverage,
|
|
904
|
+
messageSource: readResult.messageSource,
|
|
905
|
+
transcriptProvenance: readResult.transcriptProvenance,
|
|
649
906
|
activeModal: readResult.activeModal,
|
|
650
907
|
messagesTail: Array.isArray(readResult.messages) ? readResult.messages.slice(-20) : [],
|
|
651
908
|
debugReadChat: readResult.debugReadChat,
|
|
@@ -874,7 +1131,7 @@ export async function handleReadChat(h: CommandHelpers, args: any): Promise<Comm
|
|
|
874
1131
|
? parsedRecord.coverage
|
|
875
1132
|
: undefined;
|
|
876
1133
|
const activeModal = parsedRecord.activeModal ?? parsedRecord.modal ?? null;
|
|
877
|
-
const returnedStatus = normalizeCliReadChatStatus(parsedRecord.status, activeModal, adapter, adapterStatus);
|
|
1134
|
+
const returnedStatus = normalizeCliReadChatStatus(parsedRecord.status, activeModal, adapter, adapterStatus, parsedRecord.messages);
|
|
878
1135
|
const runtimeMessageMerger = getTargetInstance(h, args) as RuntimeChatMessageMerger | null;
|
|
879
1136
|
const parsedMessages = finalizeStreamingMessagesWhenIdle(parsedRecord.messages as ChatMessage[], returnedStatus);
|
|
880
1137
|
const returnedMessages = runtimeMessageMerger?.category === 'cli'
|
|
@@ -882,25 +1139,155 @@ export async function handleReadChat(h: CommandHelpers, args: any): Promise<Comm
|
|
|
882
1139
|
&& typeof runtimeMessageMerger.mergeRuntimeChatMessages === 'function'
|
|
883
1140
|
? runtimeMessageMerger.mergeRuntimeChatMessages(parsedMessages)
|
|
884
1141
|
: parsedMessages;
|
|
1142
|
+
const providerType = provider?.type || adapter.cliType;
|
|
1143
|
+
let selectedMessages = returnedMessages;
|
|
1144
|
+
let selectedTitle = title;
|
|
1145
|
+
let selectedProviderSessionId = providerSessionId;
|
|
1146
|
+
let selectedTranscriptAuthority = transcriptAuthority;
|
|
1147
|
+
let selectedCoverage = coverage;
|
|
1148
|
+
let messageSource = buildCliMessageSourceProvenance({
|
|
1149
|
+
selected: 'pty-parser',
|
|
1150
|
+
provider: adapter.cliType,
|
|
1151
|
+
fallbackReason: supportsCliNativeTranscript(providerType, provider) ? 'native_history_not_checked' : 'provider_native_transcript_not_supported',
|
|
1152
|
+
ptyMessages: returnedMessages,
|
|
1153
|
+
returnedMessages,
|
|
1154
|
+
ptyStatusApprovalOnly: false,
|
|
1155
|
+
});
|
|
1156
|
+
|
|
1157
|
+
if (supportsCliNativeTranscript(providerType, provider) && isNativeSourceCanonicalHistory(provider?.canonicalHistory)) {
|
|
1158
|
+
const agentStr = provider?.type || args?.agentType || getCurrentProviderType(h, adapter.cliType);
|
|
1159
|
+
const workspace = typeof args?.workspace === 'string'
|
|
1160
|
+
? args.workspace
|
|
1161
|
+
: typeof (h.currentSession as any)?.workspace === 'string'
|
|
1162
|
+
? (h.currentSession as any).workspace
|
|
1163
|
+
: typeof adapter.workingDir === 'string'
|
|
1164
|
+
? adapter.workingDir
|
|
1165
|
+
: undefined;
|
|
1166
|
+
const nativeHistoryLimit = Math.max(
|
|
1167
|
+
normalizeReadChatTailLimit(args) || 0,
|
|
1168
|
+
returnedMessages.length,
|
|
1169
|
+
200,
|
|
1170
|
+
);
|
|
1171
|
+
const exactNativeHistoryScope = Boolean(
|
|
1172
|
+
(typeof args?.historySessionId === 'string' && args.historySessionId.trim())
|
|
1173
|
+
|| (typeof args?.providerSessionId === 'string' && args.providerSessionId.trim())
|
|
1174
|
+
|| providerSessionId
|
|
1175
|
+
|| ((h.currentSession as any)?.sessionId === args?.targetSessionId && typeof (h.currentSession as any)?.providerSessionId === 'string' && (h.currentSession as any).providerSessionId.trim())
|
|
1176
|
+
);
|
|
1177
|
+
let nativeHistory: (ReturnType<typeof readProviderChatHistory> & { lookup?: 'session' | 'workspace' }) | null = null;
|
|
1178
|
+
try {
|
|
1179
|
+
nativeHistory = readCliProviderNativeHistory(agentStr, {
|
|
1180
|
+
canonicalHistory: provider?.canonicalHistory,
|
|
1181
|
+
historySessionId,
|
|
1182
|
+
workspace,
|
|
1183
|
+
offset: 0,
|
|
1184
|
+
limit: nativeHistoryLimit,
|
|
1185
|
+
excludeRecentCount: 0,
|
|
1186
|
+
historyBehavior: provider?.historyBehavior,
|
|
1187
|
+
scripts: provider?.scripts as any,
|
|
1188
|
+
exactSessionScoped: exactNativeHistoryScope,
|
|
1189
|
+
});
|
|
1190
|
+
} catch (error: any) {
|
|
1191
|
+
const fallbackReason = `native_history_error:${error?.message || String(error)}`;
|
|
1192
|
+
messageSource = buildCliMessageSourceProvenance({
|
|
1193
|
+
selected: 'pty-parser',
|
|
1194
|
+
provider: adapter.cliType,
|
|
1195
|
+
fallbackReason,
|
|
1196
|
+
ptyMessages: returnedMessages,
|
|
1197
|
+
returnedMessages,
|
|
1198
|
+
ptyStatusApprovalOnly: false,
|
|
1199
|
+
});
|
|
1200
|
+
nativeHistory = null;
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
if (nativeHistory) {
|
|
1204
|
+
const nativeMessages = Array.isArray((nativeHistory as any).messages)
|
|
1205
|
+
? normalizeNativeHistoryMessages(agentStr, (nativeHistory as any).messages as ChatMessage[])
|
|
1206
|
+
: [];
|
|
1207
|
+
const historyProviderSessionId = typeof (nativeHistory as any)?.providerSessionId === 'string'
|
|
1208
|
+
? (nativeHistory as any).providerSessionId
|
|
1209
|
+
: readHistorySessionIdFromMessages(nativeMessages) || historySessionId;
|
|
1210
|
+
const lookup = (nativeHistory as any).lookup === 'workspace' ? 'workspace' : 'session';
|
|
1211
|
+
const safeMapping = hasSafeNativeHistoryMapping({
|
|
1212
|
+
historySessionId: lookup === 'workspace' ? undefined : historySessionId,
|
|
1213
|
+
providerSessionId: lookup === 'workspace' ? undefined : providerSessionId,
|
|
1214
|
+
workspace,
|
|
1215
|
+
nativeMessages,
|
|
1216
|
+
});
|
|
1217
|
+
const freshEnough = isNativeHistoryFreshEnough({
|
|
1218
|
+
sourceMtimeMs: (nativeHistory as any).sourceMtimeMs,
|
|
1219
|
+
nativeMessages,
|
|
1220
|
+
ptyMessages: returnedMessages,
|
|
1221
|
+
});
|
|
1222
|
+
if ((nativeHistory as any).source === 'provider-native' && nativeMessages.length > 0 && safeMapping && freshEnough) {
|
|
1223
|
+
selectedMessages = finalizeStreamingMessagesWhenIdle(nativeMessages, returnedStatus);
|
|
1224
|
+
selectedProviderSessionId = historyProviderSessionId || providerSessionId;
|
|
1225
|
+
selectedTranscriptAuthority = 'provider';
|
|
1226
|
+
selectedCoverage = (nativeHistory as any).hasMore ? 'tail' : 'full';
|
|
1227
|
+
messageSource = buildCliMessageSourceProvenance({
|
|
1228
|
+
selected: 'native-history',
|
|
1229
|
+
provider: adapter.cliType,
|
|
1230
|
+
nativeHandle: selectedProviderSessionId || historySessionId,
|
|
1231
|
+
nativeSource: (nativeHistory as any).source,
|
|
1232
|
+
sourcePath: (nativeHistory as any).sourcePath,
|
|
1233
|
+
sourceMtimeMs: (nativeHistory as any).sourceMtimeMs,
|
|
1234
|
+
nativeMessages,
|
|
1235
|
+
ptyMessages: returnedMessages,
|
|
1236
|
+
returnedMessages: selectedMessages,
|
|
1237
|
+
safeMapping,
|
|
1238
|
+
freshEnough,
|
|
1239
|
+
ptyStatusApprovalOnly: true,
|
|
1240
|
+
});
|
|
1241
|
+
} else {
|
|
1242
|
+
const fallbackReason = buildNativeHistoryFallbackReason({
|
|
1243
|
+
providerType,
|
|
1244
|
+
provider,
|
|
1245
|
+
nativeSource: (nativeHistory as any).source,
|
|
1246
|
+
nativeMessageCount: nativeMessages.length,
|
|
1247
|
+
safeMapping,
|
|
1248
|
+
freshEnough,
|
|
1249
|
+
});
|
|
1250
|
+
messageSource = buildCliMessageSourceProvenance({
|
|
1251
|
+
selected: 'pty-parser',
|
|
1252
|
+
provider: adapter.cliType,
|
|
1253
|
+
nativeHandle: historyProviderSessionId || historySessionId,
|
|
1254
|
+
fallbackReason,
|
|
1255
|
+
nativeSource: (nativeHistory as any).source,
|
|
1256
|
+
sourcePath: (nativeHistory as any).sourcePath,
|
|
1257
|
+
sourceMtimeMs: (nativeHistory as any).sourceMtimeMs,
|
|
1258
|
+
nativeMessages,
|
|
1259
|
+
ptyMessages: returnedMessages,
|
|
1260
|
+
returnedMessages,
|
|
1261
|
+
safeMapping,
|
|
1262
|
+
freshEnough,
|
|
1263
|
+
ptyStatusApprovalOnly: false,
|
|
1264
|
+
});
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
885
1268
|
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
1269
|
return buildReadChatCommandResult({
|
|
887
|
-
messages:
|
|
1270
|
+
messages: selectedMessages,
|
|
888
1271
|
status: returnedStatus,
|
|
889
1272
|
activeModal,
|
|
1273
|
+
messageSource,
|
|
1274
|
+
transcriptProvenance: messageSource,
|
|
890
1275
|
debugReadChat: {
|
|
891
1276
|
provider: adapter.cliType,
|
|
892
1277
|
targetSessionId: String(args?.targetSessionId || ''),
|
|
893
1278
|
adapterStatus: String(adapterStatus.status || ''),
|
|
894
1279
|
parsedStatus: String(parsedRecord.status || ''),
|
|
895
1280
|
returnedStatus: String(returnedStatus || ''),
|
|
896
|
-
|
|
1281
|
+
selectedMessageSource: (messageSource as any).selected,
|
|
1282
|
+
messageSource,
|
|
1283
|
+
shouldPreferAdapterMessages: supportsCliNativeTranscript(providerType, provider) && (messageSource as any).selected !== 'native-history',
|
|
897
1284
|
parsedMsgCount: parsedRecord.messages.length,
|
|
898
|
-
returnedMsgCount:
|
|
1285
|
+
returnedMsgCount: selectedMessages.length,
|
|
899
1286
|
},
|
|
900
|
-
...(
|
|
901
|
-
...(
|
|
902
|
-
...(
|
|
903
|
-
...(
|
|
1287
|
+
...(selectedTitle ? { title: selectedTitle } : {}),
|
|
1288
|
+
...(selectedProviderSessionId ? { providerSessionId: selectedProviderSessionId } : {}),
|
|
1289
|
+
...(selectedTranscriptAuthority ? { transcriptAuthority: selectedTranscriptAuthority } : {}),
|
|
1290
|
+
...(selectedCoverage ? { coverage: selectedCoverage } : {}),
|
|
904
1291
|
}, args);
|
|
905
1292
|
}
|
|
906
1293
|
const historyLimit = normalizeReadChatTailLimit(args);
|
|
@@ -911,7 +1298,24 @@ export async function handleReadChat(h: CommandHelpers, args: any): Promise<Comm
|
|
|
911
1298
|
: typeof (h.currentSession as any)?.workspace === 'string'
|
|
912
1299
|
? (h.currentSession as any).workspace
|
|
913
1300
|
: undefined;
|
|
914
|
-
const
|
|
1301
|
+
const exactNativeHistoryScope = Boolean(
|
|
1302
|
+
(typeof args?.historySessionId === 'string' && args.historySessionId.trim())
|
|
1303
|
+
|| (typeof args?.providerSessionId === 'string' && args.providerSessionId.trim())
|
|
1304
|
+
|| ((h.currentSession as any)?.sessionId === args?.targetSessionId && typeof (h.currentSession as any)?.providerSessionId === 'string' && (h.currentSession as any).providerSessionId.trim())
|
|
1305
|
+
);
|
|
1306
|
+
const history = supportsCliNativeTranscript(agentStr, provider) && isNativeSourceCanonicalHistory(provider?.canonicalHistory)
|
|
1307
|
+
? readCliProviderNativeHistory(agentStr, {
|
|
1308
|
+
canonicalHistory: provider?.canonicalHistory,
|
|
1309
|
+
historySessionId,
|
|
1310
|
+
workspace,
|
|
1311
|
+
offset: 0,
|
|
1312
|
+
limit: historyLimit,
|
|
1313
|
+
excludeRecentCount: 0,
|
|
1314
|
+
historyBehavior: provider?.historyBehavior,
|
|
1315
|
+
scripts: provider?.scripts as any,
|
|
1316
|
+
exactSessionScoped: exactNativeHistoryScope,
|
|
1317
|
+
})
|
|
1318
|
+
: readProviderChatHistory(agentStr, {
|
|
915
1319
|
canonicalHistory: provider?.canonicalHistory,
|
|
916
1320
|
historySessionId,
|
|
917
1321
|
workspace,
|
|
@@ -921,12 +1325,65 @@ export async function handleReadChat(h: CommandHelpers, args: any): Promise<Comm
|
|
|
921
1325
|
historyBehavior: provider?.historyBehavior,
|
|
922
1326
|
scripts: provider?.scripts as any,
|
|
923
1327
|
});
|
|
1328
|
+
const lookup = (history as any).lookup === 'workspace' ? 'workspace' : 'session';
|
|
1329
|
+
const historyMessages = Array.isArray((history as any)?.messages)
|
|
1330
|
+
? normalizeNativeHistoryMessages(agentStr, (history as any).messages as ChatMessage[])
|
|
1331
|
+
: [];
|
|
924
1332
|
const historyProviderSessionId = typeof (history as any)?.providerSessionId === 'string'
|
|
925
1333
|
? (history as any).providerSessionId
|
|
926
|
-
: historySessionId;
|
|
1334
|
+
: readHistorySessionIdFromMessages(historyMessages) || historySessionId;
|
|
1335
|
+
const safeMapping = supportsCliNativeTranscript(agentStr, provider)
|
|
1336
|
+
? hasSafeNativeHistoryMapping({
|
|
1337
|
+
historySessionId: lookup === 'workspace' ? undefined : historySessionId,
|
|
1338
|
+
providerSessionId: lookup === 'workspace' ? undefined : historyProviderSessionId,
|
|
1339
|
+
workspace,
|
|
1340
|
+
nativeMessages: historyMessages,
|
|
1341
|
+
})
|
|
1342
|
+
: false;
|
|
1343
|
+
const nativeSelected = supportsCliNativeTranscript(agentStr, provider)
|
|
1344
|
+
&& (history as any).source === 'provider-native'
|
|
1345
|
+
&& historyMessages.length > 0
|
|
1346
|
+
&& safeMapping;
|
|
1347
|
+
const messageSource = buildCliMessageSourceProvenance({
|
|
1348
|
+
selected: nativeSelected ? 'native-history' : 'pty-parser',
|
|
1349
|
+
provider: agentStr,
|
|
1350
|
+
nativeHandle: historyProviderSessionId || historySessionId,
|
|
1351
|
+
fallbackReason: nativeSelected
|
|
1352
|
+
? undefined
|
|
1353
|
+
: buildNativeHistoryFallbackReason({
|
|
1354
|
+
providerType: agentStr,
|
|
1355
|
+
provider,
|
|
1356
|
+
nativeSource: (history as any).source,
|
|
1357
|
+
nativeMessageCount: historyMessages.length,
|
|
1358
|
+
safeMapping,
|
|
1359
|
+
freshEnough: true,
|
|
1360
|
+
}),
|
|
1361
|
+
nativeSource: (history as any).source,
|
|
1362
|
+
sourcePath: (history as any).sourcePath,
|
|
1363
|
+
sourceMtimeMs: (history as any).sourceMtimeMs,
|
|
1364
|
+
nativeMessages: historyMessages,
|
|
1365
|
+
returnedMessages: historyMessages,
|
|
1366
|
+
safeMapping,
|
|
1367
|
+
freshEnough: true,
|
|
1368
|
+
ptyStatusApprovalOnly: false,
|
|
1369
|
+
});
|
|
1370
|
+
const requiresNativeSource = supportsCliNativeTranscript(agentStr, provider)
|
|
1371
|
+
&& isNativeSourceCanonicalHistory(provider?.canonicalHistory);
|
|
1372
|
+
if (requiresNativeSource && !nativeSelected) {
|
|
1373
|
+
return {
|
|
1374
|
+
success: false,
|
|
1375
|
+
code: 'native_history_not_safely_available',
|
|
1376
|
+
error: 'Provider-native history was not safely available for the requested CLI session.',
|
|
1377
|
+
providerSessionId: historyProviderSessionId,
|
|
1378
|
+
messageSource,
|
|
1379
|
+
transcriptProvenance: messageSource,
|
|
1380
|
+
};
|
|
1381
|
+
}
|
|
927
1382
|
return buildReadChatCommandResult({
|
|
928
|
-
messages:
|
|
1383
|
+
messages: historyMessages,
|
|
929
1384
|
status: 'idle',
|
|
1385
|
+
messageSource,
|
|
1386
|
+
transcriptProvenance: messageSource,
|
|
930
1387
|
...(typeof (history as any)?.title === 'string' ? { title: (history as any).title } : {}),
|
|
931
1388
|
...(historyProviderSessionId ? { providerSessionId: historyProviderSessionId } : {}),
|
|
932
1389
|
...(((provider?.historyBehavior as any)?.transcriptAuthority === 'provider' || (provider?.historyBehavior as any)?.transcriptAuthority === 'daemon')
|