@adhdev/daemon-core 0.9.82-rc.440 → 0.9.82-rc.441
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/index.js +56 -14
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +56 -14
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/commands/chat-commands-read.ts +131 -11
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adhdev/daemon-core",
|
|
3
|
-
"version": "0.9.82-rc.
|
|
3
|
+
"version": "0.9.82-rc.441",
|
|
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",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"author": "vilmire",
|
|
47
47
|
"license": "AGPL-3.0-or-later",
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@adhdev/mesh-shared": "0.9.82-rc.
|
|
49
|
+
"@adhdev/mesh-shared": "0.9.82-rc.441",
|
|
50
50
|
"@adhdev/session-host-core": "*",
|
|
51
51
|
"@agentclientprotocol/sdk": "^0.16.1",
|
|
52
52
|
"ajv": "^8.20.0",
|
|
@@ -50,6 +50,34 @@ const HOT_TAIL_MIN_LIMIT = 60;
|
|
|
50
50
|
// and routes solely through canonicalHistory.contractVersion +
|
|
51
51
|
// isNativeSourceCanonicalHistory().
|
|
52
52
|
const CLI_NATIVE_TRANSCRIPT_PROVIDERS = new Set(['codex-cli', 'claude-cli', 'hermes-cli', 'antigravity-cli']);
|
|
53
|
+
|
|
54
|
+
// Last successfully-bound provider-native session id, keyed by the mesh session
|
|
55
|
+
// id (targetSessionId) the read was scoped to. The live pin lives on the
|
|
56
|
+
// CliProviderInstance and is torn down when the turn ends; a *post-turn* read
|
|
57
|
+
// then finds historySessionId empty AND canBindFromLiveSession=false (no live
|
|
58
|
+
// spawnedAtMs), so readCliProviderNativeHistory would fail closed with
|
|
59
|
+
// native_history_workspace_only_lookup_unsafe and surface providerSessionId=null
|
|
60
|
+
// + zero rows even though the transcript is physically present in state.db.
|
|
61
|
+
// Persisting the last resolved id here lets that later read reuse the known pin
|
|
62
|
+
// and run the native query normally instead of fail-closing. Refreshed on every
|
|
63
|
+
// successful bind; never lets an empty id clear a known pin. Keyed by mesh
|
|
64
|
+
// session id so pins never alias across distinct sessions sharing a workspace.
|
|
65
|
+
const lastBoundProviderSessionIdByMeshSession = new Map<string, string>();
|
|
66
|
+
|
|
67
|
+
function recordBoundProviderSessionId(meshSessionId: string | undefined, providerSessionId: string | undefined): void {
|
|
68
|
+
const key = typeof meshSessionId === 'string' ? meshSessionId.trim() : '';
|
|
69
|
+
const value = typeof providerSessionId === 'string' ? providerSessionId.trim() : '';
|
|
70
|
+
if (!key || !value) return;
|
|
71
|
+
lastBoundProviderSessionIdByMeshSession.set(key, value);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function getBoundProviderSessionIdPin(meshSessionId: string | undefined): string | undefined {
|
|
75
|
+
const key = typeof meshSessionId === 'string' ? meshSessionId.trim() : '';
|
|
76
|
+
if (!key) return undefined;
|
|
77
|
+
const pinned = lastBoundProviderSessionIdByMeshSession.get(key);
|
|
78
|
+
return pinned && pinned.trim() ? pinned.trim() : undefined;
|
|
79
|
+
}
|
|
80
|
+
|
|
53
81
|
const warnedLegacyNativeAllowlistHits = new Set<string>();
|
|
54
82
|
function warnLegacyNativeAllowlistHit(providerType: string): void {
|
|
55
83
|
if (warnedLegacyNativeAllowlistHits.has(providerType)) return;
|
|
@@ -1055,13 +1083,49 @@ function readCliProviderNativeHistory(agentStr: string, args: {
|
|
|
1055
1083
|
excludeInProgressTurn?: boolean;
|
|
1056
1084
|
sessionStartedAtMs?: number;
|
|
1057
1085
|
envOverrides?: Record<string, string>;
|
|
1086
|
+
// Last provider-native session id previously bound for this mesh session
|
|
1087
|
+
// (see lastBoundProviderSessionIdByMeshSession). When historySessionId is
|
|
1088
|
+
// empty and no live session can be bound (post-turn read), reuse this pin so
|
|
1089
|
+
// the native query runs against the known session instead of fail-closing.
|
|
1090
|
+
pinnedProviderSessionId?: string;
|
|
1091
|
+
// Opt-in last-resort: when there is no caller session id, no live binding,
|
|
1092
|
+
// and NO pin was ever recorded, allow a workspace-scoped read (newest
|
|
1093
|
+
// session in state.db with rows for this workspace). Strictly behind the pin
|
|
1094
|
+
// — it never fires when pinnedProviderSessionId is set — and still subject to
|
|
1095
|
+
// the downstream hasSafeNativeHistoryMapping workspace-overlap gate. Only the
|
|
1096
|
+
// read_chat path opts in, and only with a concrete workspace.
|
|
1097
|
+
allowWorkspaceLatestFallback?: boolean;
|
|
1058
1098
|
}): ReturnType<typeof readProviderChatHistory> & { lookup: 'session' | 'workspace' } {
|
|
1059
1099
|
const canBindFromLiveSession = !args.historySessionId
|
|
1060
1100
|
&& typeof args.sessionStartedAtMs === 'number'
|
|
1061
1101
|
&& args.sessionStartedAtMs > 0
|
|
1062
1102
|
&& typeof args.workspace === 'string'
|
|
1063
1103
|
&& args.workspace.trim().length > 0;
|
|
1064
|
-
|
|
1104
|
+
const pinnedProviderSessionId = typeof args.pinnedProviderSessionId === 'string'
|
|
1105
|
+
? args.pinnedProviderSessionId.trim()
|
|
1106
|
+
: '';
|
|
1107
|
+
// Pin reuse (PRIMARY): a later read whose live binding is gone
|
|
1108
|
+
// (historySessionId empty, no live spawnedAtMs) can still resolve to the
|
|
1109
|
+
// session it was last bound to. Read THAT session directly by threading the
|
|
1110
|
+
// pin through as historySessionId — same code path an explicit session read
|
|
1111
|
+
// takes — instead of fail-closing. Never overrides a caller-supplied
|
|
1112
|
+
// historySessionId; only kicks in when there is none.
|
|
1113
|
+
const effectiveHistorySessionId = args.historySessionId || (!canBindFromLiveSession ? pinnedProviderSessionId : '');
|
|
1114
|
+
// Last-resort workspace-latest (b): only when nothing above resolved a
|
|
1115
|
+
// session id AND no pin exists AND the caller opted in with a workspace.
|
|
1116
|
+
// Strictly behind pin reuse — pinnedProviderSessionId being set disables it.
|
|
1117
|
+
const workspaceLatestFallback = !effectiveHistorySessionId
|
|
1118
|
+
&& !canBindFromLiveSession
|
|
1119
|
+
&& !pinnedProviderSessionId
|
|
1120
|
+
&& args.allowWorkspaceLatestFallback === true
|
|
1121
|
+
&& typeof args.workspace === 'string'
|
|
1122
|
+
&& args.workspace.trim().length > 0;
|
|
1123
|
+
if (!effectiveHistorySessionId && !canBindFromLiveSession && !workspaceLatestFallback) {
|
|
1124
|
+
// No caller session id, no live binding, no known pin, no opted-in
|
|
1125
|
+
// workspace-latest. This is the genuinely-unresolvable case — a
|
|
1126
|
+
// workspace-only lookup here could alias a concurrent session sharing the
|
|
1127
|
+
// cwd, so fail closed as before. The pin/live/workspace-latest paths are
|
|
1128
|
+
// all checked AHEAD of this so a resolvable session is never dropped here.
|
|
1065
1129
|
return {
|
|
1066
1130
|
messages: [],
|
|
1067
1131
|
hasMore: false,
|
|
@@ -1072,7 +1136,7 @@ function readCliProviderNativeHistory(agentStr: string, args: {
|
|
|
1072
1136
|
}
|
|
1073
1137
|
const sessionHistory = readProviderChatHistory(agentStr, {
|
|
1074
1138
|
canonicalHistory: args.canonicalHistory,
|
|
1075
|
-
historySessionId:
|
|
1139
|
+
historySessionId: effectiveHistorySessionId || undefined,
|
|
1076
1140
|
workspace: args.workspace,
|
|
1077
1141
|
offset: args.offset,
|
|
1078
1142
|
limit: args.limit,
|
|
@@ -1087,10 +1151,11 @@ function readCliProviderNativeHistory(agentStr: string, args: {
|
|
|
1087
1151
|
? (sessionHistory as any).providerSessionId.trim()
|
|
1088
1152
|
: '';
|
|
1089
1153
|
// A fresh live session can be bound without a provider id when the native
|
|
1090
|
-
// reader matched both cwd and session_meta.timestamp to spawnedAtMs.
|
|
1154
|
+
// reader matched both cwd and session_meta.timestamp to spawnedAtMs. A
|
|
1155
|
+
// pin-bound read is always session-scoped (we passed an explicit id).
|
|
1091
1156
|
return {
|
|
1092
1157
|
...(sessionHistory as any),
|
|
1093
|
-
lookup:
|
|
1158
|
+
lookup: effectiveHistorySessionId || (canBindFromLiveSession && boundProviderSessionId)
|
|
1094
1159
|
? 'session'
|
|
1095
1160
|
: 'workspace',
|
|
1096
1161
|
};
|
|
@@ -1476,6 +1541,7 @@ export async function handleChatHistory(h: CommandHelpers, args: any): Promise<C
|
|
|
1476
1541
|
scripts: provider?.scripts as any,
|
|
1477
1542
|
sessionStartedAtMs: sessionStartedAtMsFromRegistry(h, args?.targetSessionId),
|
|
1478
1543
|
envOverrides: sessionSpawnEnvFromAdapter(h, args?.targetSessionId),
|
|
1544
|
+
pinnedProviderSessionId: getBoundProviderSessionIdPin(args?.targetSessionId),
|
|
1479
1545
|
})
|
|
1480
1546
|
: readProviderChatHistory(agentStr, {
|
|
1481
1547
|
canonicalHistory: provider?.nativeHistory,
|
|
@@ -1495,6 +1561,9 @@ export async function handleChatHistory(h: CommandHelpers, args: any): Promise<C
|
|
|
1495
1561
|
const historyProviderSessionId = typeof (result as any)?.providerSessionId === 'string'
|
|
1496
1562
|
? (result as any).providerSessionId
|
|
1497
1563
|
: readHistorySessionIdFromMessages(messages) || historySessionId;
|
|
1564
|
+
if (typeof (result as any)?.providerSessionId === 'string' && (result as any).providerSessionId.trim()) {
|
|
1565
|
+
recordBoundProviderSessionId(args?.targetSessionId, (result as any).providerSessionId.trim());
|
|
1566
|
+
}
|
|
1498
1567
|
const safeMapping = hasSafeNativeHistoryMapping({
|
|
1499
1568
|
historySessionId: lookup === 'workspace' ? undefined : historySessionId,
|
|
1500
1569
|
providerSessionId: lookup === 'workspace' ? undefined : historyProviderSessionId,
|
|
@@ -1702,8 +1771,24 @@ export async function handleReadChat(h: CommandHelpers, args: any): Promise<Comm
|
|
|
1702
1771
|
scripts: provider?.scripts as any,
|
|
1703
1772
|
excludeInProgressTurn: returnedStatus === 'waiting_approval',
|
|
1704
1773
|
sessionStartedAtMs: sessionStartedAtMsFromRegistry(h, args?.targetSessionId),
|
|
1705
|
-
|
|
1774
|
+
envOverrides: sessionSpawnEnvFromAdapter(h, args?.targetSessionId),
|
|
1775
|
+
pinnedProviderSessionId: getBoundProviderSessionIdPin(targetSessionId),
|
|
1776
|
+
// Last-resort only when no pin was ever recorded for this
|
|
1777
|
+
// session; the downstream workspace-overlap safety gate
|
|
1778
|
+
// still filters an aliased session out.
|
|
1779
|
+
allowWorkspaceLatestFallback: !getBoundProviderSessionIdPin(targetSessionId),
|
|
1706
1780
|
});
|
|
1781
|
+
// Refresh the per-mesh-session pin whenever a native read
|
|
1782
|
+
// resolves a concrete provider-native session id. A later
|
|
1783
|
+
// post-turn read (live binding gone) can then reuse it
|
|
1784
|
+
// instead of fail-closing. Only a non-empty resolved id
|
|
1785
|
+
// updates the pin; an empty result never clears a known one.
|
|
1786
|
+
const resolvedProviderSessionId = typeof nativeHistory?.providerSessionId === 'string'
|
|
1787
|
+
? nativeHistory.providerSessionId.trim()
|
|
1788
|
+
: '';
|
|
1789
|
+
if (resolvedProviderSessionId) {
|
|
1790
|
+
recordBoundProviderSessionId(targetSessionId, resolvedProviderSessionId);
|
|
1791
|
+
}
|
|
1707
1792
|
} catch (error: any) {
|
|
1708
1793
|
nativeHistoryError = error;
|
|
1709
1794
|
nativeHistory = null;
|
|
@@ -2026,10 +2111,32 @@ export async function handleReadChat(h: CommandHelpers, args: any): Promise<Comm
|
|
|
2026
2111
|
const intendedWorkspace = argsWorkspace;
|
|
2027
2112
|
const supportsNative = supportsCliNativeTranscript(agentStr, provider)
|
|
2028
2113
|
&& isNativeSourceCanonicalHistory(provider?.nativeHistory);
|
|
2114
|
+
// Post-turn read (no live adapter): getHistorySessionId falls back to
|
|
2115
|
+
// the daemon runtime session id when no provider-native id was ever
|
|
2116
|
+
// registered. That runtime id is NOT a real provider session, so a
|
|
2117
|
+
// native read keyed on it resolves nothing (providerSessionId=null,
|
|
2118
|
+
// zero rows) even though the transcript is present in state.db. When
|
|
2119
|
+
// this is that runtime fallback (historySessionId === targetSid and no
|
|
2120
|
+
// explicit id was passed) and we hold a pin from an earlier bound
|
|
2121
|
+
// read, prefer the pin so the query hits the real session.
|
|
2122
|
+
const pinnedProviderSessionIdForHistory = getBoundProviderSessionIdPin(targetSid);
|
|
2123
|
+
const historySessionIdIsRuntimeFallback = Boolean(
|
|
2124
|
+
targetSid
|
|
2125
|
+
&& historySessionId === targetSid
|
|
2126
|
+
&& !getExplicitHistorySessionId(args),
|
|
2127
|
+
);
|
|
2128
|
+
// When this is the runtime fallback (not a real provider id): prefer
|
|
2129
|
+
// the pin if we have one, else drop the runtime id entirely so the
|
|
2130
|
+
// pin-reuse / workspace-latest logic inside readCliProviderNativeHistory
|
|
2131
|
+
// can engage (passing the runtime id as historySessionId would pin the
|
|
2132
|
+
// query to a non-existent session and never reach those paths).
|
|
2133
|
+
const effectiveHistorySessionIdForRead = historySessionIdIsRuntimeFallback
|
|
2134
|
+
? (pinnedProviderSessionIdForHistory || undefined)
|
|
2135
|
+
: historySessionId;
|
|
2029
2136
|
const history = supportsNative
|
|
2030
2137
|
? readCliProviderNativeHistory(agentStr, {
|
|
2031
2138
|
canonicalHistory: provider?.nativeHistory,
|
|
2032
|
-
historySessionId,
|
|
2139
|
+
historySessionId: effectiveHistorySessionIdForRead,
|
|
2033
2140
|
workspace,
|
|
2034
2141
|
offset: 0,
|
|
2035
2142
|
limit: historyLimit,
|
|
@@ -2037,7 +2144,11 @@ export async function handleReadChat(h: CommandHelpers, args: any): Promise<Comm
|
|
|
2037
2144
|
historyBehavior: provider?.historyBehavior,
|
|
2038
2145
|
scripts: provider?.scripts as any,
|
|
2039
2146
|
sessionStartedAtMs: sessionStartedAtMsFromRegistry(h, args?.targetSessionId),
|
|
2040
|
-
|
|
2147
|
+
envOverrides: sessionSpawnEnvFromAdapter(h, args?.targetSessionId),
|
|
2148
|
+
pinnedProviderSessionId: pinnedProviderSessionIdForHistory,
|
|
2149
|
+
// Last-resort only when no pin was ever recorded AND the
|
|
2150
|
+
// runtime fallback did not resolve a real provider session.
|
|
2151
|
+
allowWorkspaceLatestFallback: !pinnedProviderSessionIdForHistory && historySessionIdIsRuntimeFallback,
|
|
2041
2152
|
})
|
|
2042
2153
|
: readProviderChatHistory(agentStr, {
|
|
2043
2154
|
canonicalHistory: provider?.nativeHistory,
|
|
@@ -2055,19 +2166,28 @@ export async function handleReadChat(h: CommandHelpers, args: any): Promise<Comm
|
|
|
2055
2166
|
: [];
|
|
2056
2167
|
const historyProviderSessionId = typeof (history as any)?.providerSessionId === 'string'
|
|
2057
2168
|
? (history as any).providerSessionId
|
|
2058
|
-
: readHistorySessionIdFromMessages(historyMessages) ||
|
|
2169
|
+
: readHistorySessionIdFromMessages(historyMessages) || effectiveHistorySessionIdForRead;
|
|
2170
|
+
// Refresh the pin whenever this path resolves a real provider id.
|
|
2171
|
+
if (typeof (history as any)?.providerSessionId === 'string' && (history as any).providerSessionId.trim()) {
|
|
2172
|
+
recordBoundProviderSessionId(targetSid, (history as any).providerSessionId.trim());
|
|
2173
|
+
}
|
|
2174
|
+
// Use the id we actually read with (pin / real provider id), NOT the
|
|
2175
|
+
// raw runtime-fallback historySessionId — otherwise the mapping guard
|
|
2176
|
+
// compares the stamped messages' real id against the runtime id and
|
|
2177
|
+
// fails closed, undoing the pin reuse.
|
|
2178
|
+
const mappingSessionId = effectiveHistorySessionIdForRead;
|
|
2059
2179
|
const safeMapping = supportsNative
|
|
2060
2180
|
? hasSafeNativeHistoryMapping({
|
|
2061
|
-
historySessionId: lookup === 'workspace' ? undefined :
|
|
2181
|
+
historySessionId: lookup === 'workspace' ? undefined : mappingSessionId,
|
|
2062
2182
|
providerSessionId: lookup === 'workspace' ? undefined : historyProviderSessionId,
|
|
2063
2183
|
workspace,
|
|
2064
2184
|
nativeMessages: historyMessages,
|
|
2065
2185
|
})
|
|
2066
2186
|
: false;
|
|
2067
2187
|
const trustedExactNativeIdentity = lookup !== 'workspace'
|
|
2068
|
-
&& Boolean(
|
|
2188
|
+
&& Boolean(mappingSessionId)
|
|
2069
2189
|
&& Boolean(historyProviderSessionId)
|
|
2070
|
-
&&
|
|
2190
|
+
&& mappingSessionId === historyProviderSessionId;
|
|
2071
2191
|
|
|
2072
2192
|
const machineSessionKey = String(
|
|
2073
2193
|
args?.targetSessionId
|