@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.
- package/dist/boot/daemon-lifecycle.d.ts +1 -0
- package/dist/commands/cli-manager.d.ts +2 -1
- package/dist/commands/mesh-coordinator.d.ts +13 -0
- package/dist/commands/router.d.ts +5 -1
- package/dist/config/chat-history.d.ts +1 -0
- package/dist/git/git-commands.d.ts +2 -0
- package/dist/git/git-types.d.ts +2 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +15461 -14552
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +14411 -13502
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/beads-db.d.ts +1 -0
- package/dist/mesh/mesh-events.d.ts +46 -1
- package/dist/mesh/mesh-work-queue.d.ts +1 -0
- package/dist/providers/cli-provider-instance.d.ts +4 -0
- package/dist/providers/contracts.d.ts +32 -1
- package/dist/providers/native-history/dispatcher.d.ts +2 -0
- package/dist/providers/sdk/v1/types/common/index.d.ts +35 -1
- package/dist/providers/spec/cli-adapter.d.ts +1 -0
- package/dist/providers/spec/driver.d.ts +6 -1
- package/dist/providers/spec/native-history-executor.d.ts +2 -0
- package/dist/providers/spec/schema.gen.d.ts +22 -0
- package/dist/providers/spec/types.d.ts +10 -0
- package/dist/repo-mesh-types.d.ts +6 -0
- package/package.json +1 -1
- package/src/boot/daemon-lifecycle.ts +2 -0
- package/src/commands/chat-commands.ts +206 -18
- package/src/commands/cli-manager.ts +56 -14
- package/src/commands/mesh-coordinator.ts +110 -5
- package/src/commands/router.ts +146 -21
- package/src/config/chat-history.ts +4 -0
- package/src/git/git-commands.ts +20 -2
- package/src/git/git-status.ts +35 -6
- package/src/git/git-types.ts +2 -0
- package/src/index.ts +2 -2
- package/src/mesh/beads-db.ts +4 -0
- package/src/mesh/mesh-events.ts +264 -4
- package/src/mesh/mesh-work-queue.ts +4 -0
- package/src/providers/cli-provider-instance.ts +122 -13
- package/src/providers/contracts.d.ts +55 -0
- package/src/providers/contracts.ts +36 -1
- package/src/providers/native-history/dispatcher.ts +126 -17
- package/src/providers/provider-loader.ts +4 -7
- package/src/providers/provider-schema.ts +56 -1
- package/src/providers/sdk/v1/schemas/cli/provider.schema.json +46 -0
- package/src/providers/sdk/v1/types/common/index.ts +19 -0
- package/src/providers/spec/cli-adapter.ts +32 -5
- package/src/providers/spec/driver.ts +68 -1
- package/src/providers/spec/evaluator.ts +11 -1
- package/src/providers/spec/native-history-executor.ts +93 -27
- package/src/providers/spec/schema.gen.ts +12 -1
- package/src/providers/spec/schema.json +21 -1
- package/src/providers/spec/types.ts +10 -0
- 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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
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
|
-
|| (
|
|
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:
|
|
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
|
-
|
|
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
|
|
2255
|
+
const sessionStartedAtMs = sessionStartedAtMsFromRegistry(h, args?.targetSessionId);
|
|
2256
|
+
let historyProviderSessionId = typeof nativeHistory?.providerSessionId === 'string'
|
|
2158
2257
|
? nativeHistory.providerSessionId
|
|
2159
|
-
: readHistorySessionIdFromMessages(nativeMessages) ||
|
|
2160
|
-
|
|
2161
|
-
|
|
2258
|
+
: readHistorySessionIdFromMessages(nativeMessages) || nativeHistoryReadSessionId || historySessionId;
|
|
2259
|
+
let lookup = nativeHistory?.lookup === 'workspace' ? 'workspace' : 'session';
|
|
2260
|
+
let nativeHistorySessionForMapping = adapter.cliType === 'antigravity-cli'
|
|
2162
2261
|
&& historyProviderSessionId
|
|
2163
|
-
&&
|
|
2164
|
-
&& historyProviderSessionId !==
|
|
2262
|
+
&& nativeHistoryReadSessionId
|
|
2263
|
+
&& historyProviderSessionId !== nativeHistoryReadSessionId
|
|
2165
2264
|
? undefined
|
|
2166
|
-
:
|
|
2167
|
-
|
|
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
|
-
&&
|
|
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
|
|
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 || {})
|
|
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
|
-
|
|
290
|
-
|
|
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
|
|
1108
|
-
const provTrust =
|
|
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:
|
|
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',
|