@adhdev/daemon-core 0.9.82-rc.439 → 0.9.82-rc.440
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/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.440",
|
|
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.440",
|
|
50
50
|
"@adhdev/session-host-core": "*",
|
|
51
51
|
"@agentclientprotocol/sdk": "^0.16.1",
|
|
52
52
|
"ajv": "^8.20.0",
|
|
@@ -732,6 +732,29 @@ export const meshCrudHandlers: Record<string, MedFamilyHandler> = {
|
|
|
732
732
|
// keeps showing up in the dashboard graph until the cache
|
|
733
733
|
// ages out on its own.
|
|
734
734
|
if (removed) ctx.invalidateAggregateMeshStatus(meshId);
|
|
735
|
+
// MESH-INLINE-NODE-RESURRECTION: removeInlineMeshNode only mutates
|
|
736
|
+
// the in-memory inlineMeshCache + tombstones — it does NOT touch
|
|
737
|
+
// the file-backed config (meshes.json). When the SAME node also
|
|
738
|
+
// lives in meshes.json (a worktree node that was persisted to the
|
|
739
|
+
// file config, then resolved through the inline cache on removal),
|
|
740
|
+
// the file record survives. On daemon restart the in-memory
|
|
741
|
+
// tombstone is lost, getMesh falls back to the file config, and
|
|
742
|
+
// mesh-status renders the dead node again. So a node present in
|
|
743
|
+
// BOTH the inline cache AND meshes.json must be spliced+saved from
|
|
744
|
+
// the file config here too. Pure-inline meshes (no matching file
|
|
745
|
+
// mesh/node) are untouched — getMesh returns undefined and we skip.
|
|
746
|
+
try {
|
|
747
|
+
const { getMesh, removeNode } = await import('../../config/mesh-config.js');
|
|
748
|
+
const fileMesh = getMesh(meshId);
|
|
749
|
+
const fileNode = fileMesh?.nodes?.find((n: any) => meshNodeIdMatches(n, nodeId));
|
|
750
|
+
if (fileNode?.id) {
|
|
751
|
+
const fileRemoved = removeNode(meshId, fileNode.id);
|
|
752
|
+
if (fileRemoved) {
|
|
753
|
+
removed = true;
|
|
754
|
+
ctx.invalidateAggregateMeshStatus(meshId);
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
} catch { /* file config absent / unreadable — inline-only mesh, nothing to durably delete */ }
|
|
735
758
|
// Node was already absent from the inline mesh (e.g. removed by a
|
|
736
759
|
// prior refine cleanup). Treat as removed so caller gets removed:true.
|
|
737
760
|
if (!removed && !node) removed = true;
|
|
@@ -70,10 +70,17 @@ function openDb(): any | null {
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
function loadMessagesForSession(db: any, sessionId: string): NativeHistoryMessage[] {
|
|
73
|
+
// Assistant turns whose finish_reason='tool_calls' persist an EMPTY
|
|
74
|
+
// `content` — their payload lives in the `tool_calls` column. Filtering on
|
|
75
|
+
// `content != ''` alone drops those rows, so a turn whose terminal message
|
|
76
|
+
// is a tool call surfaces zero assistant bubbles. Accept a row when either
|
|
77
|
+
// `content` OR `tool_calls` is non-empty, and project `tool_calls` into the
|
|
78
|
+
// content slot when `content` is empty so the bubble still carries text.
|
|
73
79
|
const rows: any[] = db.prepare(
|
|
74
|
-
`SELECT id, role, content, timestamp
|
|
80
|
+
`SELECT id, role, COALESCE(NULLIF(content, ''), tool_calls) AS content, timestamp
|
|
75
81
|
FROM messages
|
|
76
|
-
WHERE session_id = ?
|
|
82
|
+
WHERE session_id = ?
|
|
83
|
+
AND ((content IS NOT NULL AND content != '') OR (tool_calls IS NOT NULL AND tool_calls != ''))
|
|
77
84
|
ORDER BY timestamp ASC, id ASC`,
|
|
78
85
|
).all(sessionId);
|
|
79
86
|
const out: NativeHistoryMessage[] = [];
|
|
@@ -115,10 +122,16 @@ export function readSession(sessionPath: string, requestedSessionId?: string): N
|
|
|
115
122
|
sessionId = pinned;
|
|
116
123
|
} else {
|
|
117
124
|
// No bound id yet (discovery): pick the newest source='cli'
|
|
118
|
-
// session that has at least one persisted message.
|
|
125
|
+
// session that has at least one persisted message. Use an
|
|
126
|
+
// EXISTS check against `messages` rather than the denormalized
|
|
127
|
+
// `message_count` column — a freshly-started session already
|
|
128
|
+
// has message rows while `message_count` (DEFAULT 0) can still
|
|
129
|
+
// lag at 0, and the old predicate excluded exactly that
|
|
130
|
+
// just-created session, resolving to nothing.
|
|
119
131
|
const row: any = db.prepare(
|
|
120
132
|
`SELECT id, started_at FROM sessions
|
|
121
|
-
WHERE source = 'cli'
|
|
133
|
+
WHERE source = 'cli'
|
|
134
|
+
AND EXISTS (SELECT 1 FROM messages m WHERE m.session_id = sessions.id)
|
|
122
135
|
ORDER BY started_at DESC LIMIT 1`,
|
|
123
136
|
).get();
|
|
124
137
|
if (!row) return null;
|
|
@@ -185,7 +198,8 @@ export async function listSessions(_watchPath: string): Promise<NativeHistorySes
|
|
|
185
198
|
const rows: any[] = db.prepare(
|
|
186
199
|
`SELECT id, started_at, ended_at, message_count, title
|
|
187
200
|
FROM sessions
|
|
188
|
-
WHERE source = 'cli'
|
|
201
|
+
WHERE source = 'cli'
|
|
202
|
+
AND EXISTS (SELECT 1 FROM messages m WHERE m.session_id = sessions.id)
|
|
189
203
|
ORDER BY started_at DESC LIMIT 100`,
|
|
190
204
|
).all();
|
|
191
205
|
const mtime = statMtimeMs(HERMES_STATE_DB);
|