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

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.
Files changed (55) hide show
  1. package/dist/boot/daemon-lifecycle.d.ts +1 -0
  2. package/dist/commands/cli-manager.d.ts +2 -1
  3. package/dist/commands/mesh-coordinator.d.ts +13 -0
  4. package/dist/commands/router.d.ts +5 -1
  5. package/dist/config/chat-history.d.ts +1 -0
  6. package/dist/git/git-commands.d.ts +2 -0
  7. package/dist/git/git-types.d.ts +2 -0
  8. package/dist/index.d.ts +2 -2
  9. package/dist/index.js +15461 -14552
  10. package/dist/index.js.map +1 -1
  11. package/dist/index.mjs +14411 -13502
  12. package/dist/index.mjs.map +1 -1
  13. package/dist/mesh/beads-db.d.ts +1 -0
  14. package/dist/mesh/mesh-events.d.ts +46 -1
  15. package/dist/mesh/mesh-work-queue.d.ts +1 -0
  16. package/dist/providers/cli-provider-instance.d.ts +4 -0
  17. package/dist/providers/contracts.d.ts +32 -1
  18. package/dist/providers/native-history/dispatcher.d.ts +2 -0
  19. package/dist/providers/sdk/v1/types/common/index.d.ts +35 -1
  20. package/dist/providers/spec/cli-adapter.d.ts +1 -0
  21. package/dist/providers/spec/driver.d.ts +6 -1
  22. package/dist/providers/spec/native-history-executor.d.ts +2 -0
  23. package/dist/providers/spec/schema.gen.d.ts +22 -0
  24. package/dist/providers/spec/types.d.ts +10 -0
  25. package/dist/repo-mesh-types.d.ts +6 -0
  26. package/package.json +1 -1
  27. package/src/boot/daemon-lifecycle.ts +2 -0
  28. package/src/commands/chat-commands.ts +206 -18
  29. package/src/commands/cli-manager.ts +56 -14
  30. package/src/commands/mesh-coordinator.ts +110 -5
  31. package/src/commands/router.ts +146 -21
  32. package/src/config/chat-history.ts +4 -0
  33. package/src/git/git-commands.ts +20 -2
  34. package/src/git/git-status.ts +35 -6
  35. package/src/git/git-types.ts +2 -0
  36. package/src/index.ts +2 -2
  37. package/src/mesh/beads-db.ts +4 -0
  38. package/src/mesh/mesh-events.ts +264 -4
  39. package/src/mesh/mesh-work-queue.ts +4 -0
  40. package/src/providers/cli-provider-instance.ts +122 -13
  41. package/src/providers/contracts.d.ts +55 -0
  42. package/src/providers/contracts.ts +36 -1
  43. package/src/providers/native-history/dispatcher.ts +126 -17
  44. package/src/providers/provider-loader.ts +4 -7
  45. package/src/providers/provider-schema.ts +56 -1
  46. package/src/providers/sdk/v1/schemas/cli/provider.schema.json +46 -0
  47. package/src/providers/sdk/v1/types/common/index.ts +19 -0
  48. package/src/providers/spec/cli-adapter.ts +32 -5
  49. package/src/providers/spec/driver.ts +68 -1
  50. package/src/providers/spec/evaluator.ts +11 -1
  51. package/src/providers/spec/native-history-executor.ts +93 -27
  52. package/src/providers/spec/schema.gen.ts +12 -1
  53. package/src/providers/spec/schema.json +21 -1
  54. package/src/providers/spec/types.ts +10 -0
  55. package/src/repo-mesh-types.ts +6 -0
@@ -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: {
@@ -1299,6 +1378,15 @@ function hasVisibleAssistantMessage(messages: unknown[] | undefined): boolean {
1299
1378
  });
1300
1379
  }
1301
1380
 
1381
+ function hasFinalVisibleAssistantMessage(messages: unknown[] | undefined): boolean {
1382
+ if (!Array.isArray(messages)) return false;
1383
+ const visible = filterUserFacingChatMessages(messages as ChatMessage[]);
1384
+ const last = visible[visible.length - 1] as ChatMessage | undefined;
1385
+ const role = typeof last?.role === 'string' ? last.role.trim().toLowerCase() : '';
1386
+ const content = last ? flattenContent(last.content).trim() : '';
1387
+ return (role === 'assistant' || role === 'model') && content.length > 0;
1388
+ }
1389
+
1302
1390
  function shouldTrustCliAdapterTerminalStatus(parsedStatus: unknown, activeModal: unknown, adapter: CliAdapter, adapterStatus: any): boolean {
1303
1391
  if (!isGeneratingLikeStatus(parsedStatus)) return false;
1304
1392
  if (hasNonEmptyModalButtons(activeModal)) return false;
@@ -2117,11 +2205,21 @@ export async function handleReadChat(h: CommandHelpers, args: any): Promise<Comm
2117
2205
  ? resolveCliNativeHistorySessionId(args, historySessionId, providerSessionId)
2118
2206
  : undefined;
2119
2207
  const targetSessionId = typeof args?.targetSessionId === 'string' ? args.targetSessionId.trim() : '';
2208
+ const skipLiveNativeHistoryWithoutProviderSession = shouldSkipLiveCliNativeHistoryWithoutProviderSession({
2209
+ adapter,
2210
+ providerType,
2211
+ readChatArgs: args,
2212
+ nativeHistorySessionId,
2213
+ parsedProviderSessionId: providerSessionId,
2214
+ });
2215
+ const nativeHistoryReadSessionId = skipLiveNativeHistoryWithoutProviderSession
2216
+ ? undefined
2217
+ : nativeHistorySessionId;
2120
2218
  const exactNativeHistoryScope = Boolean(
2121
2219
  (typeof args?.historySessionId === 'string' && args.historySessionId.trim())
2122
2220
  || (typeof args?.providerSessionId === 'string' && args.providerSessionId.trim())
2123
2221
  || providerSessionId
2124
- || (nativeHistorySessionId && nativeHistorySessionId !== targetSessionId)
2222
+ || (nativeHistoryReadSessionId && nativeHistoryReadSessionId !== targetSessionId)
2125
2223
  || ((h.currentSession as any)?.sessionId === args?.targetSessionId && typeof (h.currentSession as any)?.providerSessionId === 'string' && (h.currentSession as any).providerSessionId.trim())
2126
2224
  );
2127
2225
 
@@ -2132,7 +2230,7 @@ export async function handleReadChat(h: CommandHelpers, args: any): Promise<Comm
2132
2230
  try {
2133
2231
  nativeHistory = readCliProviderNativeHistory(agentStr, {
2134
2232
  canonicalHistory: provider?.nativeHistory,
2135
- historySessionId: nativeHistorySessionId,
2233
+ historySessionId: nativeHistoryReadSessionId,
2136
2234
  workspace,
2137
2235
  offset: 0,
2138
2236
  limit: nativeHistoryLimit,
@@ -2151,20 +2249,21 @@ export async function handleReadChat(h: CommandHelpers, args: any): Promise<Comm
2151
2249
 
2152
2250
  // 2. Compute safeMapping with the same rules the v1 code used so the
2153
2251
  // machine sees the same observation it always would have.
2154
- const nativeMessages: ChatMessage[] = nativeHistory && Array.isArray(nativeHistory.messages)
2252
+ let nativeMessages: ChatMessage[] = nativeHistory && Array.isArray(nativeHistory.messages)
2155
2253
  ? normalizeAndFilterNativeHistory(h, agentStr, args, nativeHistory.messages as ChatMessage[], nativeHistory.providerSessionId)
2156
2254
  : [];
2157
- const historyProviderSessionId = typeof nativeHistory?.providerSessionId === 'string'
2255
+ const sessionStartedAtMs = sessionStartedAtMsFromRegistry(h, args?.targetSessionId);
2256
+ let historyProviderSessionId = typeof nativeHistory?.providerSessionId === 'string'
2158
2257
  ? nativeHistory.providerSessionId
2159
- : readHistorySessionIdFromMessages(nativeMessages) || nativeHistorySessionId || historySessionId;
2160
- const lookup = nativeHistory?.lookup === 'workspace' ? 'workspace' : 'session';
2161
- const nativeHistorySessionForMapping = adapter.cliType === 'antigravity-cli'
2258
+ : readHistorySessionIdFromMessages(nativeMessages) || nativeHistoryReadSessionId || historySessionId;
2259
+ let lookup = nativeHistory?.lookup === 'workspace' ? 'workspace' : 'session';
2260
+ let nativeHistorySessionForMapping = adapter.cliType === 'antigravity-cli'
2162
2261
  && historyProviderSessionId
2163
- && nativeHistorySessionId
2164
- && historyProviderSessionId !== nativeHistorySessionId
2262
+ && nativeHistoryReadSessionId
2263
+ && historyProviderSessionId !== nativeHistoryReadSessionId
2165
2264
  ? undefined
2166
- : nativeHistorySessionId;
2167
- const safeMapping = supportsNative && nativeHistory
2265
+ : nativeHistoryReadSessionId;
2266
+ let safeMapping = supportsNative && nativeHistory
2168
2267
  ? hasSafeNativeHistoryMapping({
2169
2268
  historySessionId: lookup === 'workspace' ? undefined : nativeHistorySessionForMapping,
2170
2269
  providerSessionId: lookup === 'workspace' ? undefined : historyProviderSessionId || providerSessionId,
@@ -2174,6 +2273,64 @@ export async function handleReadChat(h: CommandHelpers, args: any): Promise<Comm
2174
2273
  requireWorkspaceContentOverlap: lookup === 'workspace' && !exactNativeHistoryScope,
2175
2274
  })
2176
2275
  : false;
2276
+ if (skipLiveNativeHistoryWithoutProviderSession && (!safeMapping || returnedMessages.length === 0)) {
2277
+ nativeHistory = null;
2278
+ nativeMessages = [];
2279
+ historyProviderSessionId = undefined;
2280
+ lookup = 'session';
2281
+ safeMapping = false;
2282
+ }
2283
+ const mayRetryUnsafeAutoDetectedCodexSession = adapter.cliType === 'codex-cli'
2284
+ && !getExplicitHistorySessionId(args)
2285
+ && Boolean(sessionStartedAtMs && sessionStartedAtMs > 0)
2286
+ && !skipLiveNativeHistoryWithoutProviderSession
2287
+ && !safeMapping;
2288
+ if (mayRetryUnsafeAutoDetectedCodexSession) {
2289
+ try {
2290
+ nativeHistory = readCliProviderNativeHistory(agentStr, {
2291
+ canonicalHistory: provider?.nativeHistory,
2292
+ historySessionId: undefined,
2293
+ workspace,
2294
+ offset: 0,
2295
+ limit: nativeHistoryLimit,
2296
+ excludeRecentCount: 0,
2297
+ historyBehavior: provider?.historyBehavior,
2298
+ scripts: provider?.scripts as any,
2299
+ excludeInProgressTurn: returnedStatus === 'waiting_approval',
2300
+ sessionStartedAtMs,
2301
+ envOverrides: sessionSpawnEnvFromAdapter(h, args?.targetSessionId),
2302
+ });
2303
+ nativeHistoryError = undefined;
2304
+ nativeMessages = nativeHistory && Array.isArray(nativeHistory.messages)
2305
+ ? normalizeAndFilterNativeHistory(h, agentStr, args, nativeHistory.messages as ChatMessage[], nativeHistory.providerSessionId)
2306
+ : [];
2307
+ historyProviderSessionId = typeof nativeHistory?.providerSessionId === 'string'
2308
+ ? nativeHistory.providerSessionId
2309
+ : readHistorySessionIdFromMessages(nativeMessages);
2310
+ lookup = nativeHistory?.lookup === 'workspace' ? 'workspace' : 'session';
2311
+ nativeHistorySessionForMapping = undefined;
2312
+ safeMapping = supportsNative && nativeHistory
2313
+ ? hasSafeNativeHistoryMapping({
2314
+ historySessionId: lookup === 'workspace' ? undefined : historyProviderSessionId,
2315
+ providerSessionId: lookup === 'workspace' ? undefined : historyProviderSessionId,
2316
+ workspace,
2317
+ nativeMessages,
2318
+ ptyMessages: returnedMessages,
2319
+ requireWorkspaceContentOverlap: lookup === 'workspace' && !exactNativeHistoryScope,
2320
+ })
2321
+ : false;
2322
+ } catch (error: any) {
2323
+ nativeHistoryError = error;
2324
+ nativeHistory = null;
2325
+ nativeMessages = [];
2326
+ historyProviderSessionId = undefined;
2327
+ safeMapping = false;
2328
+ }
2329
+ }
2330
+ const trustedExactNativeIdentity = lookup !== 'workspace'
2331
+ && Boolean(nativeHistoryReadSessionId)
2332
+ && Boolean(historyProviderSessionId)
2333
+ && nativeHistoryReadSessionId === historyProviderSessionId;
2177
2334
 
2178
2335
  // 3. Drive ChatSourceMachine — one observation per readChat call,
2179
2336
  // keyed by (providerType, sessionKey-for-this-call). targetSessionId
@@ -2193,6 +2350,7 @@ export async function handleReadChat(h: CommandHelpers, args: any): Promise<Comm
2193
2350
  nativeHistoryResult: nativeHistory,
2194
2351
  nativeHistoryError,
2195
2352
  safeMapping,
2353
+ trustedExactNativeIdentity,
2196
2354
  sessionWorkspace,
2197
2355
  intendedWorkspace,
2198
2356
  ptyMessages: returnedMessages,
@@ -2207,6 +2365,9 @@ export async function handleReadChat(h: CommandHelpers, args: any): Promise<Comm
2207
2365
  selectedProviderSessionId = historyProviderSessionId || providerSessionId;
2208
2366
  selectedTranscriptAuthority = 'provider';
2209
2367
  selectedCoverage = nativeHistory?.hasMore ? 'tail' : 'full';
2368
+ if (selectedProviderSessionId && selectedProviderSessionId !== providerSessionId) {
2369
+ adapter.updateRuntimeMeta?.({ providerSessionId: selectedProviderSessionId });
2370
+ }
2210
2371
  } else if (supportsNative) {
2211
2372
  // Native not selected. Two preserved v1 fallbacks before settling
2212
2373
  // on PTY: (a) Codex-only live workspace native probe; (b) unsafe-
@@ -2224,7 +2385,9 @@ export async function handleReadChat(h: CommandHelpers, args: any): Promise<Comm
2224
2385
  && liveCurrentRuntimePtySafe
2225
2386
  && !(typeof args?.providerSessionId === 'string' && args.providerSessionId.trim())
2226
2387
  && !(providerSessionId && providerSessionId.trim())
2227
- && (!historyProviderSessionId || historyProviderSessionId === nativeHistorySessionId || historyProviderSessionId === historySessionId);
2388
+ && !nativeHistoryReadSessionId
2389
+ && (!historyProviderSessionId || historyProviderSessionId === nativeHistoryReadSessionId || historyProviderSessionId === historySessionId)
2390
+ && !skipLiveNativeHistoryWithoutProviderSession;
2228
2391
  const liveWorkspaceNativeHistory = mayProbeLiveCodexWorkspaceNative
2229
2392
  ? readLiveCodexWorkspaceNativeHistory(agentStr, {
2230
2393
  canonicalHistory: provider?.nativeHistory,
@@ -2269,6 +2432,9 @@ export async function handleReadChat(h: CommandHelpers, args: any): Promise<Comm
2269
2432
  selectedProviderSessionId = liveWorkspaceNativeProviderSessionId || providerSessionId;
2270
2433
  selectedTranscriptAuthority = 'provider';
2271
2434
  selectedCoverage = (liveWorkspaceNativeHistory as any).hasMore ? 'tail' : 'full';
2435
+ if (selectedProviderSessionId && selectedProviderSessionId !== providerSessionId) {
2436
+ adapter.updateRuntimeMeta?.({ providerSessionId: selectedProviderSessionId });
2437
+ }
2272
2438
  messageSource = liveDecision.messageSource;
2273
2439
  (messageSource as any).selectedDaemonSource = 'live-workspace-native-history';
2274
2440
  (messageSource as any).runtimeMappingSafe = true;
@@ -2322,6 +2488,23 @@ export async function handleReadChat(h: CommandHelpers, args: any): Promise<Comm
2322
2488
  });
2323
2489
  }
2324
2490
  }
2491
+ if (
2492
+ isGeneratingLikeStatus(selectedStatus)
2493
+ && selectedTranscriptAuthority === 'provider'
2494
+ && !hasNonEmptyModalButtons(activeModal)
2495
+ && hasFinalVisibleAssistantMessage(selectedMessages)
2496
+ ) {
2497
+ selectedStatus = 'idle';
2498
+ selectedMessages = finalizeStreamingMessagesWhenIdle(selectedMessages, selectedStatus);
2499
+ messageSource = {
2500
+ ...messageSource,
2501
+ statusReconciled: {
2502
+ from: returnedStatus,
2503
+ to: 'idle',
2504
+ reason: 'provider_native_final_assistant',
2505
+ },
2506
+ };
2507
+ }
2325
2508
  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}`);
2326
2509
  return buildReadChatCommandResult({
2327
2510
  messages: selectedMessages,
@@ -2406,6 +2589,10 @@ export async function handleReadChat(h: CommandHelpers, args: any): Promise<Comm
2406
2589
  nativeMessages: historyMessages,
2407
2590
  })
2408
2591
  : false;
2592
+ const trustedExactNativeIdentity = lookup !== 'workspace'
2593
+ && Boolean(historySessionId)
2594
+ && Boolean(historyProviderSessionId)
2595
+ && historySessionId === historyProviderSessionId;
2409
2596
 
2410
2597
  const machineSessionKey = String(
2411
2598
  args?.targetSessionId
@@ -2420,6 +2607,7 @@ export async function handleReadChat(h: CommandHelpers, args: any): Promise<Comm
2420
2607
  sessionId: machineSessionKey,
2421
2608
  nativeHistoryResult: history,
2422
2609
  safeMapping,
2610
+ trustedExactNativeIdentity,
2423
2611
  sessionWorkspace: workspace,
2424
2612
  intendedWorkspace,
2425
2613
  ptyMessages: [],
@@ -25,7 +25,7 @@ import { CliProviderInstance } from '../providers/cli-provider-instance.js';
25
25
  import { AcpProviderInstance } from '../providers/acp-provider-instance.js';
26
26
  import type { ProviderInstanceManager } from '../providers/provider-instance-manager.js';
27
27
  import { ProviderLoader } from '../providers/provider-loader.js';
28
- import { normalizeInputEnvelope, type ProviderModule, type ProviderResumeCapability } from '../providers/contracts.js';
28
+ import { normalizeInputEnvelope, type MeshCoordinatorDelegatedWorkerIsolation, type ProviderModule, type ProviderResumeCapability } from '../providers/contracts.js';
29
29
  import { assertProviderSupportsDeclaredInput, assertTextOnlyInput } from '../providers/provider-input-support.js';
30
30
  import type { CliAdapter } from '../cli-adapter-types.js';
31
31
  import type { PtyTransportFactory } from '../cli-adapters/pty-transport.js';
@@ -247,18 +247,19 @@ type CliStartOptions = {
247
247
  extraEnv?: Record<string, string>;
248
248
  };
249
249
 
250
- const COORDINATOR_DELEGATED_ENV_UNSETS: Record<string, string> = {
251
- ADHDEV_INLINE_MESH: '',
252
- ADHDEV_MCP_TRANSPORT: '',
253
- ADHDEV_MESH_ID: '',
254
- HERMES_EPHEMERAL_SYSTEM_PROMPT: '',
255
- };
250
+ const DEFAULT_COORDINATOR_DELEGATED_ENV_UNSETS = [
251
+ 'ADHDEV_INLINE_MESH',
252
+ 'ADHDEV_MCP_TRANSPORT',
253
+ 'ADHDEV_MESH_ID',
254
+ 'HERMES_EPHEMERAL_SYSTEM_PROMPT',
255
+ ] as const;
256
256
 
257
257
  export interface CoordinatorDelegatedCliLaunchOptionsInput {
258
258
  cliType: string;
259
259
  workspace: string;
260
260
  cliArgs?: string[];
261
261
  env?: Record<string, string>;
262
+ isolation?: MeshCoordinatorDelegatedWorkerIsolation;
262
263
  }
263
264
 
264
265
  export interface CoordinatorDelegatedCliLaunchOptions {
@@ -270,6 +271,21 @@ function hasCliArg(args: string[], flag: string): boolean {
270
271
  return args.some((arg) => arg === flag || arg.startsWith(`${flag}=`));
271
272
  }
272
273
 
274
+ function hasConfigOverride(args: string[], key: string): boolean {
275
+ for (let index = 0; index < args.length; index += 1) {
276
+ const arg = args[index];
277
+ const next = args[index + 1];
278
+ if ((arg === '-c' || arg === '--config') && typeof next === 'string') {
279
+ if (next === key || next.startsWith(`${key}=`) || next.startsWith(`${key}.`)) return true;
280
+ }
281
+ if (arg.startsWith('--config=')) {
282
+ const value = arg.slice('--config='.length);
283
+ if (value === key || value.startsWith(`${key}=`) || value.startsWith(`${key}.`)) return true;
284
+ }
285
+ }
286
+ return false;
287
+ }
288
+
273
289
  function ensureEmptyDelegatedMcpConfig(workspace: string): string {
274
290
  const baseDir = path.join(os.tmpdir(), 'adhdev-delegated-agent-empty-mcp');
275
291
  mkdirSync(baseDir, { recursive: true });
@@ -282,12 +298,31 @@ function ensureEmptyDelegatedMcpConfig(workspace: string): string {
282
298
  export function buildCoordinatorDelegatedCliLaunchOptions(
283
299
  input: CoordinatorDelegatedCliLaunchOptionsInput,
284
300
  ): CoordinatorDelegatedCliLaunchOptions {
285
- const cliType = String(input.cliType || '').trim();
286
301
  const cliArgs = Array.isArray(input.cliArgs) ? [...input.cliArgs] : [];
287
- const env: Record<string, string> = { ...(input.env || {}), ...COORDINATOR_DELEGATED_ENV_UNSETS };
302
+ const env: Record<string, string> = { ...(input.env || {}) };
303
+ const envUnsets = new Set<string>(DEFAULT_COORDINATOR_DELEGATED_ENV_UNSETS);
304
+ for (const key of input.isolation?.env?.unset || []) {
305
+ if (typeof key === 'string' && key.trim()) envUnsets.add(key.trim());
306
+ }
307
+ for (const key of envUnsets) env[key] = '';
288
308
 
289
- if (cliType === 'claude-cli' && !hasCliArg(cliArgs, '--mcp-config')) {
290
- cliArgs.unshift('--mcp-config', ensureEmptyDelegatedMcpConfig(input.workspace));
309
+ for (const rule of input.isolation?.args || []) {
310
+ if (!rule || typeof rule !== 'object') continue;
311
+ if (rule.mode === 'empty_mcp_config') {
312
+ if (rule.flag && !hasCliArg(cliArgs, rule.flag)) {
313
+ cliArgs.unshift(rule.flag, ensureEmptyDelegatedMcpConfig(input.workspace));
314
+ }
315
+ if (rule.strictFlag && !hasCliArg(cliArgs, rule.strictFlag)) {
316
+ cliArgs.unshift(rule.strictFlag);
317
+ }
318
+ continue;
319
+ }
320
+ if (rule.mode === 'config_override') {
321
+ const key = String(rule.dedupeKey || rule.key || '').trim();
322
+ const flag = String(rule.flag || '').trim();
323
+ if (!key || !flag || hasConfigOverride(cliArgs, key)) continue;
324
+ cliArgs.unshift(flag, `${rule.key}=${rule.value}`);
325
+ }
291
326
  }
292
327
 
293
328
  return { cliArgs, env };
@@ -1090,6 +1125,8 @@ export class DaemonCliManager {
1090
1125
  const launchSource = resolved.source;
1091
1126
  if (!cliType) throw new Error('cliType required');
1092
1127
 
1128
+ const providerType = this.providerLoader.resolveAlias(cliType);
1129
+ const provLookup = this.providerLoader.getMeta(providerType) as ProviderModule | undefined;
1093
1130
  const settingsOverride = args?.settings && typeof args.settings === 'object' ? args.settings : undefined;
1094
1131
  const delegatedLaunch = settingsOverride?.launchedByCoordinator === true
1095
1132
  ? buildCoordinatorDelegatedCliLaunchOptions({
@@ -1097,6 +1134,7 @@ export class DaemonCliManager {
1097
1134
  workspace: dir,
1098
1135
  cliArgs: args?.cliArgs,
1099
1136
  env: args?.env,
1137
+ isolation: provLookup?.meshCoordinator?.delegatedWorkerIsolation,
1100
1138
  })
1101
1139
  : null;
1102
1140
  // Untrusted-provider gate: an external source that ships JS
@@ -1104,15 +1142,15 @@ export class DaemonCliManager {
1104
1142
  // launch. Dashboards add `confirmExternalUntrusted: true` to
1105
1143
  // the launch args after showing the trust modal. Without
1106
1144
  // that ack we refuse to spawn and tell the caller why.
1107
- const provLookup = this.providerLoader.getMeta(this.providerLoader.resolveAlias(cliType)) as any;
1108
- const provTrust = provLookup?._sourceTrust;
1145
+ const provMeta = provLookup as any;
1146
+ const provTrust = provMeta?._sourceTrust;
1109
1147
  if (provTrust === 'external-untrusted' && args?.confirmExternalUntrusted !== true) {
1110
1148
  return {
1111
1149
  success: false,
1112
1150
  error: 'untrusted_external_provider',
1113
1151
  provider: {
1114
1152
  type: provLookup?.type ?? cliType,
1115
- sourceName: provLookup?._sourceName ?? null,
1153
+ sourceName: provMeta?._sourceName ?? null,
1116
1154
  trust: provTrust,
1117
1155
  },
1118
1156
  hint: 'Resend launch_cli with confirmExternalUntrusted=true after the user explicitly approves running JavaScript from this 3rd-party source.',
@@ -1305,6 +1343,10 @@ export class DaemonCliManager {
1305
1343
  } else {
1306
1344
  await adapter.sendMessage(message);
1307
1345
  }
1346
+ const targetInstance = this.deps.getInstanceManager()?.getInstance(key) as
1347
+ | { recordAcknowledgedUserInput?: (input: unknown) => void }
1348
+ | undefined;
1349
+ targetInstance?.recordAcknowledgedUserInput?.(input);
1308
1350
  return {
1309
1351
  success: true,
1310
1352
  status: BUSY_AGENT_STATUSES.has(currentStatus) ? currentStatus : 'generating',