@adhdev/daemon-core 0.9.82-rc.186 → 0.9.82-rc.187

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.
@@ -68,5 +68,6 @@ export declare class BeadsDB {
68
68
  }>;
69
69
  updateDirectDispatchStatus(meshId: string, sessionId: string, status: 'acked' | 'completed' | 'failed' | 'stale'): void;
70
70
  cleanupTerminalDirectDispatches(olderThanMs: number): void;
71
+ deleteDirectDispatches(meshId: string): void;
71
72
  markStaleDirectDispatches(meshId: string, olderThanMs: number): void;
72
73
  }
@@ -1,4 +1,5 @@
1
1
  import type { DaemonComponents } from '../boot/daemon-lifecycle.js';
2
+ import type { MeshLedgerKind } from './mesh-ledger.js';
2
3
  export declare function __resetIdleAutoFastForwardForTests(): void;
3
4
  export interface PendingMeshCoordinatorEvent {
4
5
  event: string;
@@ -23,12 +24,56 @@ export declare function drainPendingMeshCoordinatorEvents(meshId?: string, coord
23
24
  export declare function getPendingMeshCoordinatorEvents(meshId?: string, coordinatorDaemonId?: string): readonly PendingMeshCoordinatorEvent[];
24
25
  /** Explicitly clear all pending coordinator events for a mesh (and coordinator if scoped). */
25
26
  export declare function clearPendingMeshCoordinatorEvents(meshId?: string, coordinatorDaemonId?: string): void;
27
+ export declare function reconcileDirectDispatchCompletionFromTranscript(args: {
28
+ meshId: string;
29
+ nodeId?: string;
30
+ sessionId: string;
31
+ providerType?: string;
32
+ providerSessionId?: string;
33
+ taskId: string;
34
+ finalSummary: string;
35
+ transcriptMessageAt?: string;
36
+ completedAt?: string;
37
+ targetCoordinatorDaemonId?: string;
38
+ source?: string;
39
+ }): {
40
+ reconciled: boolean;
41
+ kind?: MeshLedgerKind;
42
+ alreadyTerminal?: boolean;
43
+ workerResult?: unknown;
44
+ ledgerEntryId?: string;
45
+ reason?: string;
46
+ };
26
47
  export declare function tryAssignQueueTask(components: DaemonComponents, meshId: string, nodeId: string, sessionId: string, providerType: string): boolean;
48
+ export interface MeshQueueTriggerResult {
49
+ success: true;
50
+ meshId: string;
51
+ pendingBefore: number;
52
+ assignedBefore: number;
53
+ pendingAfter: number;
54
+ assignedAfter: number;
55
+ claimed: boolean;
56
+ newlyAssignedTasks: Array<{
57
+ id: string;
58
+ nodeId?: string;
59
+ sessionId?: string;
60
+ }>;
61
+ localIdleSessionsChecked: number;
62
+ remoteIdleSessionsChecked: number;
63
+ skippedSessions: Array<{
64
+ nodeId?: string;
65
+ sessionId?: string;
66
+ reason: string;
67
+ status?: string;
68
+ }>;
69
+ autoLaunchStarted: boolean;
70
+ noIdleMeshSessionAvailable?: boolean;
71
+ }
27
72
  /**
28
73
  * Triggers a queue check for all nodes in the mesh.
29
74
  * Called when a new task is enqueued, in case nodes are already idle.
30
75
  */
31
- export declare function triggerMeshQueue(components: DaemonComponents, meshId: string): Promise<void>;
76
+ export declare function triggerMeshQueue(components: DaemonComponents, meshId: string): Promise<MeshQueueTriggerResult>;
32
77
  export declare function handleMeshForwardEvent(components: DaemonComponents, payload: Record<string, unknown>): {
33
78
  success: boolean;
34
79
  forwarded: number;
@@ -136,6 +136,7 @@ export interface MeshWorkQueueStats {
136
136
  export declare function getMeshQueueStats(meshId: string): MeshWorkQueueStats;
137
137
  export declare function __replaceMeshQueueForTests(meshId: string, queue: MeshWorkQueueEntry[]): void;
138
138
  export declare function __clearMeshQueueForTests(meshId: string): void;
139
+ export declare function __clearDirectDispatchesForTests(meshId: string): void;
139
140
  export declare function __resetBeadsDBForTests(): void;
140
141
  export type DirectDispatchRecord = ReturnType<BeadsDB['getActiveDirectDispatches']>[number];
141
142
  export declare function insertDirectDispatch(meshId: string, data: {
@@ -302,7 +302,7 @@ export interface ProviderMeshCoordinatorConfig {
302
302
  requiresRestart?: boolean;
303
303
  /** User-facing setup explanation for manual modes. */
304
304
  instructions?: string;
305
- /** Copyable setup template. Supports {{meshId}}, {{adhdevMcpCommand}}, {{workspace}}, {{serverName}}. */
305
+ /** Copyable setup template. Supports {{meshId}}, {{adhdevMcpCommand}}, {{adhdevMcpArgs}}, {{workspace}}, {{serverName}}. */
306
306
  template?: string;
307
307
  };
308
308
  /**
@@ -5,6 +5,7 @@ export interface NativeHistoryInput {
5
5
  providerSessionId?: string;
6
6
  historySessionId?: string;
7
7
  workspace?: string;
8
+ sessionStartedAtMs?: number;
8
9
  format?: string;
9
10
  watchPath?: string;
10
11
  forceRefresh?: boolean;
@@ -16,6 +17,7 @@ export interface NativeHistoryResult {
16
17
  content: string;
17
18
  receivedAt?: number;
18
19
  kind?: string;
20
+ workspace?: string;
19
21
  }>;
20
22
  providerSessionId?: string;
21
23
  sourcePath: string;
@@ -90,6 +90,7 @@ export declare class SpecCliAdapter implements CliAdapter {
90
90
  private handleEvent;
91
91
  private detectInteractivePromptFromPtyChunk;
92
92
  private readCurrentScreenSections;
93
+ private extractProviderSessionIdFromScreen;
93
94
  private readClaudeScreenAssistantMessages;
94
95
  private maybeCaptureClaudeTuiPrompt;
95
96
  private readClaudeTuiHeaders;
@@ -28,6 +28,7 @@ export interface NativeHistoryMessage {
28
28
  content: string;
29
29
  receivedAt: number;
30
30
  kind?: string;
31
+ workspace?: string;
31
32
  }
32
33
  export interface NativeHistoryResult {
33
34
  messages: NativeHistoryMessage[];
@@ -35,5 +36,6 @@ export interface NativeHistoryResult {
35
36
  sourcePath: string;
36
37
  sourceMtimeMs: number;
37
38
  nativeHistoryCoverage?: 'full' | 'partial' | 'best-effort';
39
+ workspace?: string;
38
40
  }
39
41
  export declare function executeNativeHistory(cfg: NativeHistoryConfig, input: NativeHistoryInput): NativeHistoryResult | null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhdev/daemon-core",
3
- "version": "0.9.82-rc.186",
3
+ "version": "0.9.82-rc.187",
4
4
  "description": "ADHDev daemon core — CDP, IDE detection, providers, command execution",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -222,6 +222,41 @@ function resolveCliNativeHistorySessionId(args: any, currentHistorySessionId: st
222
222
  return current || parsed || undefined;
223
223
  }
224
224
 
225
+ function shouldSkipLiveCliNativeHistoryWithoutProviderSession(args: {
226
+ adapter?: CliAdapter | null;
227
+ providerType?: string;
228
+ readChatArgs: any;
229
+ nativeHistorySessionId?: string;
230
+ parsedProviderSessionId?: string;
231
+ }): boolean {
232
+ const explicit = getExplicitHistorySessionId(args.readChatArgs);
233
+ if (explicit) return false;
234
+
235
+ const targetSessionId = typeof args.readChatArgs?.targetSessionId === 'string'
236
+ ? args.readChatArgs.targetSessionId.trim()
237
+ : '';
238
+ if (!targetSessionId) return false;
239
+
240
+ const resolved = typeof args.nativeHistorySessionId === 'string'
241
+ ? args.nativeHistorySessionId.trim()
242
+ : '';
243
+ if (!resolved || resolved !== targetSessionId) return false;
244
+
245
+ const parsed = typeof args.parsedProviderSessionId === 'string'
246
+ ? args.parsedProviderSessionId.trim()
247
+ : '';
248
+ if (parsed) return false;
249
+
250
+ const cliType = args.adapter?.cliType || args.providerType || '';
251
+ if (cliType !== 'codex-cli') return false;
252
+
253
+ // A live Codex session starts with only the daemon runtime UUID. That UUID
254
+ // is not the provider-native rollout id, so using it for native history
255
+ // lets the file picker fall back to the newest same-workspace transcript
256
+ // and makes concurrent fresh sessions all show the same old conversation.
257
+ return !!args.adapter;
258
+ }
259
+
225
260
  function getInteractionId(args: any): string | undefined {
226
261
  return typeof args?._interactionId === 'string' && args._interactionId.trim()
227
262
  ? args._interactionId.trim()
@@ -444,6 +479,7 @@ function normalizeNativeHistoryMessages(providerType: string, messages: ChatMess
444
479
  ...message,
445
480
  role: role === 'human' ? 'user' : (role || 'assistant'),
446
481
  kind: isSystemSessionStart ? 'system' : kind,
482
+ ...(nativeIdentitySessionId ? { historySessionId: nativeIdentitySessionId } : {}),
447
483
  providerUnitKey,
448
484
  bubbleId: typeof message.bubbleId === 'string' && message.bubbleId.trim()
449
485
  && preserveNativeIdentity
@@ -604,6 +640,7 @@ function decideCliReadChatSource(args: {
604
640
  nativeHistoryResult: any | null;
605
641
  nativeHistoryError?: unknown;
606
642
  safeMapping: boolean;
643
+ trustedExactNativeIdentity?: boolean;
607
644
  sessionWorkspace?: string;
608
645
  intendedWorkspace?: string;
609
646
  ptyMessages: ChatMessage[];
@@ -617,7 +654,26 @@ function decideCliReadChatSource(args: {
617
654
  const supportsNative = supportsCliNativeTranscript(args.providerType, args.provider);
618
655
  const observation = buildObservationForCli(args, supportsNative);
619
656
  const sessionKey = chatSourceSessionKey(args.providerType, args.sessionId);
620
- const decision = CHAT_SOURCE_REGISTRY.observe(sessionKey, observation);
657
+ let decision = CHAT_SOURCE_REGISTRY.observe(sessionKey, observation);
658
+
659
+ // A restored runtime can briefly expose different native slices while the
660
+ // provider transcript settles (for example, startup/system rows may be
661
+ // filtered after the first read). The source machine correctly treats a
662
+ // shrinking slice as regression, but an exact provider-session lookup with
663
+ // no PTY transcript has no safer fallback. Re-bootstrap only this proven
664
+ // identity so the chat does not disappear after daemon restart.
665
+ if (
666
+ decision.selected === 'pty-parser'
667
+ && args.trustedExactNativeIdentity === true
668
+ && args.safeMapping
669
+ && args.ptyMessages.length === 0
670
+ && observation.kind === 'native_present'
671
+ && observation.coverage !== 'partial'
672
+ && observation.messages.length > 0
673
+ ) {
674
+ CHAT_SOURCE_REGISTRY.clear(sessionKey);
675
+ decision = CHAT_SOURCE_REGISTRY.observe(sessionKey, observation);
676
+ }
621
677
 
622
678
  const nativeMessages: ChatMessage[] = observation.kind === 'native_present'
623
679
  ? extractNativeMessagesFromResult(args.providerType, args.nativeHistoryResult)
@@ -1034,6 +1090,17 @@ function hasSafeNativeHistoryMapping(args: {
1034
1090
 
1035
1091
  const explicitSessionId = String(args.historySessionId || args.providerSessionId || '').trim();
1036
1092
  if (explicitSessionId) {
1093
+ const expectedWorkspace = normalizeComparableWorkspace(args.workspace);
1094
+ const declaredWorkspaces = args.nativeMessages
1095
+ .map((message: any) => normalizeComparableWorkspace(message?.workspace))
1096
+ .filter(Boolean);
1097
+ if (
1098
+ expectedWorkspace
1099
+ && declaredWorkspaces.length > 0
1100
+ && !declaredWorkspaces.some((workspace) => workspace === expectedWorkspace)
1101
+ ) {
1102
+ return false;
1103
+ }
1037
1104
  const messageSessionIds = args.nativeMessages
1038
1105
  .map((message: any) => typeof message?.historySessionId === 'string' ? message.historySessionId.trim() : '')
1039
1106
  .filter(Boolean);
@@ -1128,7 +1195,12 @@ function readCliProviderNativeHistory(agentStr: string, args: {
1128
1195
  sessionStartedAtMs?: number;
1129
1196
  envOverrides?: Record<string, string>;
1130
1197
  }): ReturnType<typeof readProviderChatHistory> & { lookup: 'session' | 'workspace' } {
1131
- if (!args.historySessionId) {
1198
+ const canBindFromLiveSession = !args.historySessionId
1199
+ && typeof args.sessionStartedAtMs === 'number'
1200
+ && args.sessionStartedAtMs > 0
1201
+ && typeof args.workspace === 'string'
1202
+ && args.workspace.trim().length > 0;
1203
+ if (!args.historySessionId && !canBindFromLiveSession) {
1132
1204
  return {
1133
1205
  messages: [],
1134
1206
  hasMore: false,
@@ -1150,10 +1222,17 @@ function readCliProviderNativeHistory(agentStr: string, args: {
1150
1222
  sessionStartedAtMs: args.sessionStartedAtMs,
1151
1223
  envOverrides: args.envOverrides,
1152
1224
  });
1153
- // Native transcripts are keyed by provider/runtime session identity. Falling
1154
- // back to workspace makes concurrent local Codex/Hermes sessions alias each
1155
- // other when they share the same cwd.
1156
- return { ...(sessionHistory as any), lookup: 'session' };
1225
+ const boundProviderSessionId = typeof (sessionHistory as any)?.providerSessionId === 'string'
1226
+ ? (sessionHistory as any).providerSessionId.trim()
1227
+ : '';
1228
+ // A fresh live session can be bound without a provider id when the native
1229
+ // reader matched both cwd and session_meta.timestamp to spawnedAtMs.
1230
+ return {
1231
+ ...(sessionHistory as any),
1232
+ lookup: args.historySessionId || (canBindFromLiveSession && boundProviderSessionId)
1233
+ ? 'session'
1234
+ : 'workspace',
1235
+ };
1157
1236
  }
1158
1237
 
1159
1238
  function readLiveCodexWorkspaceNativeHistory(agentStr: string, args: {
@@ -2117,11 +2196,21 @@ export async function handleReadChat(h: CommandHelpers, args: any): Promise<Comm
2117
2196
  ? resolveCliNativeHistorySessionId(args, historySessionId, providerSessionId)
2118
2197
  : undefined;
2119
2198
  const targetSessionId = typeof args?.targetSessionId === 'string' ? args.targetSessionId.trim() : '';
2199
+ const skipLiveNativeHistoryWithoutProviderSession = shouldSkipLiveCliNativeHistoryWithoutProviderSession({
2200
+ adapter,
2201
+ providerType,
2202
+ readChatArgs: args,
2203
+ nativeHistorySessionId,
2204
+ parsedProviderSessionId: providerSessionId,
2205
+ });
2206
+ const nativeHistoryReadSessionId = skipLiveNativeHistoryWithoutProviderSession
2207
+ ? undefined
2208
+ : nativeHistorySessionId;
2120
2209
  const exactNativeHistoryScope = Boolean(
2121
2210
  (typeof args?.historySessionId === 'string' && args.historySessionId.trim())
2122
2211
  || (typeof args?.providerSessionId === 'string' && args.providerSessionId.trim())
2123
2212
  || providerSessionId
2124
- || (nativeHistorySessionId && nativeHistorySessionId !== targetSessionId)
2213
+ || (nativeHistoryReadSessionId && nativeHistoryReadSessionId !== targetSessionId)
2125
2214
  || ((h.currentSession as any)?.sessionId === args?.targetSessionId && typeof (h.currentSession as any)?.providerSessionId === 'string' && (h.currentSession as any).providerSessionId.trim())
2126
2215
  );
2127
2216
 
@@ -2132,7 +2221,7 @@ export async function handleReadChat(h: CommandHelpers, args: any): Promise<Comm
2132
2221
  try {
2133
2222
  nativeHistory = readCliProviderNativeHistory(agentStr, {
2134
2223
  canonicalHistory: provider?.nativeHistory,
2135
- historySessionId: nativeHistorySessionId,
2224
+ historySessionId: nativeHistoryReadSessionId,
2136
2225
  workspace,
2137
2226
  offset: 0,
2138
2227
  limit: nativeHistoryLimit,
@@ -2151,20 +2240,21 @@ export async function handleReadChat(h: CommandHelpers, args: any): Promise<Comm
2151
2240
 
2152
2241
  // 2. Compute safeMapping with the same rules the v1 code used so the
2153
2242
  // machine sees the same observation it always would have.
2154
- const nativeMessages: ChatMessage[] = nativeHistory && Array.isArray(nativeHistory.messages)
2243
+ let nativeMessages: ChatMessage[] = nativeHistory && Array.isArray(nativeHistory.messages)
2155
2244
  ? normalizeAndFilterNativeHistory(h, agentStr, args, nativeHistory.messages as ChatMessage[], nativeHistory.providerSessionId)
2156
2245
  : [];
2157
- const historyProviderSessionId = typeof nativeHistory?.providerSessionId === 'string'
2246
+ const sessionStartedAtMs = sessionStartedAtMsFromRegistry(h, args?.targetSessionId);
2247
+ let historyProviderSessionId = typeof nativeHistory?.providerSessionId === 'string'
2158
2248
  ? nativeHistory.providerSessionId
2159
- : readHistorySessionIdFromMessages(nativeMessages) || nativeHistorySessionId || historySessionId;
2160
- const lookup = nativeHistory?.lookup === 'workspace' ? 'workspace' : 'session';
2161
- const nativeHistorySessionForMapping = adapter.cliType === 'antigravity-cli'
2249
+ : readHistorySessionIdFromMessages(nativeMessages) || nativeHistoryReadSessionId || historySessionId;
2250
+ let lookup = nativeHistory?.lookup === 'workspace' ? 'workspace' : 'session';
2251
+ let nativeHistorySessionForMapping = adapter.cliType === 'antigravity-cli'
2162
2252
  && historyProviderSessionId
2163
- && nativeHistorySessionId
2164
- && historyProviderSessionId !== nativeHistorySessionId
2253
+ && nativeHistoryReadSessionId
2254
+ && historyProviderSessionId !== nativeHistoryReadSessionId
2165
2255
  ? undefined
2166
- : nativeHistorySessionId;
2167
- const safeMapping = supportsNative && nativeHistory
2256
+ : nativeHistoryReadSessionId;
2257
+ let safeMapping = supportsNative && nativeHistory
2168
2258
  ? hasSafeNativeHistoryMapping({
2169
2259
  historySessionId: lookup === 'workspace' ? undefined : nativeHistorySessionForMapping,
2170
2260
  providerSessionId: lookup === 'workspace' ? undefined : historyProviderSessionId || providerSessionId,
@@ -2174,6 +2264,64 @@ export async function handleReadChat(h: CommandHelpers, args: any): Promise<Comm
2174
2264
  requireWorkspaceContentOverlap: lookup === 'workspace' && !exactNativeHistoryScope,
2175
2265
  })
2176
2266
  : false;
2267
+ if (skipLiveNativeHistoryWithoutProviderSession && (!safeMapping || returnedMessages.length === 0)) {
2268
+ nativeHistory = null;
2269
+ nativeMessages = [];
2270
+ historyProviderSessionId = undefined;
2271
+ lookup = 'session';
2272
+ safeMapping = false;
2273
+ }
2274
+ const mayRetryUnsafeAutoDetectedCodexSession = adapter.cliType === 'codex-cli'
2275
+ && !getExplicitHistorySessionId(args)
2276
+ && Boolean(sessionStartedAtMs && sessionStartedAtMs > 0)
2277
+ && !skipLiveNativeHistoryWithoutProviderSession
2278
+ && !safeMapping;
2279
+ if (mayRetryUnsafeAutoDetectedCodexSession) {
2280
+ try {
2281
+ nativeHistory = readCliProviderNativeHistory(agentStr, {
2282
+ canonicalHistory: provider?.nativeHistory,
2283
+ historySessionId: undefined,
2284
+ workspace,
2285
+ offset: 0,
2286
+ limit: nativeHistoryLimit,
2287
+ excludeRecentCount: 0,
2288
+ historyBehavior: provider?.historyBehavior,
2289
+ scripts: provider?.scripts as any,
2290
+ excludeInProgressTurn: returnedStatus === 'waiting_approval',
2291
+ sessionStartedAtMs,
2292
+ envOverrides: sessionSpawnEnvFromAdapter(h, args?.targetSessionId),
2293
+ });
2294
+ nativeHistoryError = undefined;
2295
+ nativeMessages = nativeHistory && Array.isArray(nativeHistory.messages)
2296
+ ? normalizeAndFilterNativeHistory(h, agentStr, args, nativeHistory.messages as ChatMessage[], nativeHistory.providerSessionId)
2297
+ : [];
2298
+ historyProviderSessionId = typeof nativeHistory?.providerSessionId === 'string'
2299
+ ? nativeHistory.providerSessionId
2300
+ : readHistorySessionIdFromMessages(nativeMessages);
2301
+ lookup = nativeHistory?.lookup === 'workspace' ? 'workspace' : 'session';
2302
+ nativeHistorySessionForMapping = undefined;
2303
+ safeMapping = supportsNative && nativeHistory
2304
+ ? hasSafeNativeHistoryMapping({
2305
+ historySessionId: lookup === 'workspace' ? undefined : historyProviderSessionId,
2306
+ providerSessionId: lookup === 'workspace' ? undefined : historyProviderSessionId,
2307
+ workspace,
2308
+ nativeMessages,
2309
+ ptyMessages: returnedMessages,
2310
+ requireWorkspaceContentOverlap: lookup === 'workspace' && !exactNativeHistoryScope,
2311
+ })
2312
+ : false;
2313
+ } catch (error: any) {
2314
+ nativeHistoryError = error;
2315
+ nativeHistory = null;
2316
+ nativeMessages = [];
2317
+ historyProviderSessionId = undefined;
2318
+ safeMapping = false;
2319
+ }
2320
+ }
2321
+ const trustedExactNativeIdentity = lookup !== 'workspace'
2322
+ && Boolean(nativeHistoryReadSessionId)
2323
+ && Boolean(historyProviderSessionId)
2324
+ && nativeHistoryReadSessionId === historyProviderSessionId;
2177
2325
 
2178
2326
  // 3. Drive ChatSourceMachine — one observation per readChat call,
2179
2327
  // keyed by (providerType, sessionKey-for-this-call). targetSessionId
@@ -2193,6 +2341,7 @@ export async function handleReadChat(h: CommandHelpers, args: any): Promise<Comm
2193
2341
  nativeHistoryResult: nativeHistory,
2194
2342
  nativeHistoryError,
2195
2343
  safeMapping,
2344
+ trustedExactNativeIdentity,
2196
2345
  sessionWorkspace,
2197
2346
  intendedWorkspace,
2198
2347
  ptyMessages: returnedMessages,
@@ -2207,6 +2356,9 @@ export async function handleReadChat(h: CommandHelpers, args: any): Promise<Comm
2207
2356
  selectedProviderSessionId = historyProviderSessionId || providerSessionId;
2208
2357
  selectedTranscriptAuthority = 'provider';
2209
2358
  selectedCoverage = nativeHistory?.hasMore ? 'tail' : 'full';
2359
+ if (selectedProviderSessionId && selectedProviderSessionId !== providerSessionId) {
2360
+ adapter.updateRuntimeMeta?.({ providerSessionId: selectedProviderSessionId });
2361
+ }
2210
2362
  } else if (supportsNative) {
2211
2363
  // Native not selected. Two preserved v1 fallbacks before settling
2212
2364
  // on PTY: (a) Codex-only live workspace native probe; (b) unsafe-
@@ -2224,7 +2376,9 @@ export async function handleReadChat(h: CommandHelpers, args: any): Promise<Comm
2224
2376
  && liveCurrentRuntimePtySafe
2225
2377
  && !(typeof args?.providerSessionId === 'string' && args.providerSessionId.trim())
2226
2378
  && !(providerSessionId && providerSessionId.trim())
2227
- && (!historyProviderSessionId || historyProviderSessionId === nativeHistorySessionId || historyProviderSessionId === historySessionId);
2379
+ && !nativeHistoryReadSessionId
2380
+ && (!historyProviderSessionId || historyProviderSessionId === nativeHistoryReadSessionId || historyProviderSessionId === historySessionId)
2381
+ && !skipLiveNativeHistoryWithoutProviderSession;
2228
2382
  const liveWorkspaceNativeHistory = mayProbeLiveCodexWorkspaceNative
2229
2383
  ? readLiveCodexWorkspaceNativeHistory(agentStr, {
2230
2384
  canonicalHistory: provider?.nativeHistory,
@@ -2269,6 +2423,9 @@ export async function handleReadChat(h: CommandHelpers, args: any): Promise<Comm
2269
2423
  selectedProviderSessionId = liveWorkspaceNativeProviderSessionId || providerSessionId;
2270
2424
  selectedTranscriptAuthority = 'provider';
2271
2425
  selectedCoverage = (liveWorkspaceNativeHistory as any).hasMore ? 'tail' : 'full';
2426
+ if (selectedProviderSessionId && selectedProviderSessionId !== providerSessionId) {
2427
+ adapter.updateRuntimeMeta?.({ providerSessionId: selectedProviderSessionId });
2428
+ }
2272
2429
  messageSource = liveDecision.messageSource;
2273
2430
  (messageSource as any).selectedDaemonSource = 'live-workspace-native-history';
2274
2431
  (messageSource as any).runtimeMappingSafe = true;
@@ -2406,6 +2563,10 @@ export async function handleReadChat(h: CommandHelpers, args: any): Promise<Comm
2406
2563
  nativeMessages: historyMessages,
2407
2564
  })
2408
2565
  : false;
2566
+ const trustedExactNativeIdentity = lookup !== 'workspace'
2567
+ && Boolean(historySessionId)
2568
+ && Boolean(historyProviderSessionId)
2569
+ && historySessionId === historyProviderSessionId;
2409
2570
 
2410
2571
  const machineSessionKey = String(
2411
2572
  args?.targetSessionId
@@ -2420,6 +2581,7 @@ export async function handleReadChat(h: CommandHelpers, args: any): Promise<Comm
2420
2581
  sessionId: machineSessionKey,
2421
2582
  nativeHistoryResult: history,
2422
2583
  safeMapping,
2584
+ trustedExactNativeIdentity,
2423
2585
  sessionWorkspace: workspace,
2424
2586
  intendedWorkspace,
2425
2587
  ptyMessages: [],
@@ -1305,6 +1305,10 @@ export class DaemonCliManager {
1305
1305
  } else {
1306
1306
  await adapter.sendMessage(message);
1307
1307
  }
1308
+ const targetInstance = this.deps.getInstanceManager()?.getInstance(key) as
1309
+ | { recordAcknowledgedUserInput?: (input: unknown) => void }
1310
+ | undefined;
1311
+ targetInstance?.recordAcknowledgedUserInput?.(input);
1308
1312
  return {
1309
1313
  success: true,
1310
1314
  status: BUSY_AGENT_STATUSES.has(currentStatus) ? currentStatus : 'generating',