@adhdev/daemon-core 0.9.82-rc.550 → 0.9.82-rc.552
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 +8 -0
- package/dist/commands/router.d.ts +10 -0
- package/dist/index.js +23 -6
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +23 -6
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
- package/src/boot/daemon-lifecycle.ts +9 -0
- package/src/commands/med-family/cli-agent.ts +46 -5
- package/src/commands/router.ts +10 -0
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.552",
|
|
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",
|
|
@@ -47,8 +47,8 @@
|
|
|
47
47
|
"author": "vilmire",
|
|
48
48
|
"license": "AGPL-3.0-or-later",
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@adhdev/mesh-shared": "0.9.82-rc.
|
|
51
|
-
"@adhdev/session-host-core": "0.9.82-rc.
|
|
50
|
+
"@adhdev/mesh-shared": "0.9.82-rc.552",
|
|
51
|
+
"@adhdev/session-host-core": "0.9.82-rc.552",
|
|
52
52
|
"@agentclientprotocol/sdk": "^0.16.1",
|
|
53
53
|
"ajv": "^8.20.0",
|
|
54
54
|
"ajv-formats": "^3.0.1",
|
|
@@ -96,6 +96,14 @@ export interface DaemonInitConfig {
|
|
|
96
96
|
getMeshPeerConnectionStatus?: (daemonId: string) => Record<string, unknown> | null;
|
|
97
97
|
/** Cloud-only: P2P dashboard metadata sync after the core forwarder handles a mesh event. */
|
|
98
98
|
onMeshCoordinatorEventForwarded?: (payload: Record<string, unknown>) => void;
|
|
99
|
+
/**
|
|
100
|
+
* Cloud-only: refresh THIS daemon's own coordinator mirror for a self-hosted mesh session
|
|
101
|
+
* (coordinator == this daemon), used by the SELF-DIAL branch of set_conversation_prefs so a
|
|
102
|
+
* locally coordinated session updates its mirror in-process instead of P2P-dialing its own id
|
|
103
|
+
* (refused as SELF_DIAL). Injected by daemon-cloud (updateMeshOwnedSession + dashboard flush);
|
|
104
|
+
* absent on standalone (no coordinator mirror).
|
|
105
|
+
*/
|
|
106
|
+
updateLocalMeshOwnedSession?: (payload: Record<string, unknown>) => void;
|
|
99
107
|
}
|
|
100
108
|
|
|
101
109
|
// ─── Result ───
|
|
@@ -378,6 +386,7 @@ export async function initDaemonComponents(config: DaemonInitConfig): Promise<Da
|
|
|
378
386
|
statusVersion: config.statusVersion,
|
|
379
387
|
getMeshPeerConnectionStatus: config.getMeshPeerConnectionStatus,
|
|
380
388
|
dispatchMeshCommand: config.dispatchMeshCommand,
|
|
389
|
+
updateLocalMeshOwnedSession: config.updateLocalMeshOwnedSession,
|
|
381
390
|
getCdpLogFn: config.getCdpLogFn || ((ideType: string) => LOG.forComponent(`CDP:${ideType}`).asLogFn()),
|
|
382
391
|
});
|
|
383
392
|
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* + ctx.launchIde — no executeDaemonCommand recursion) or CLI/ACP restarts.
|
|
9
9
|
* Extracted verbatim from executeDaemonCommand.
|
|
10
10
|
*/
|
|
11
|
-
import { meshNodeIdMatches } from '@adhdev/mesh-shared';
|
|
11
|
+
import { meshNodeIdMatches, daemonIdsEquivalent } from '@adhdev/mesh-shared';
|
|
12
12
|
import { supportsExplicitSessionResume } from '../cli-manager.js';
|
|
13
13
|
import { loadState } from '../../config/state-store.js';
|
|
14
14
|
import { getRecentActivity } from '../../config/recent-activity.js';
|
|
@@ -19,8 +19,13 @@ import { LOG } from '../../logging/logger.js';
|
|
|
19
19
|
import { readStringValue } from '../router.js';
|
|
20
20
|
import type { MedFamilyContext, MedFamilyHandler } from './types.js';
|
|
21
21
|
|
|
22
|
-
/**
|
|
23
|
-
|
|
22
|
+
/**
|
|
23
|
+
* Outcome of the coordinator-mirror refresh: not a mesh worker (no-op), refreshed via the remote
|
|
24
|
+
* relay, refreshed locally (self-hosted coordinator == this daemon — no P2P dial), or failed.
|
|
25
|
+
* 'refreshed-local' and 'refreshed' both mean the mirror is now fresh; the caller reports them
|
|
26
|
+
* identically (mirrorRefreshed, no mirrorStale) so a self-hosted toggle never rolls back.
|
|
27
|
+
*/
|
|
28
|
+
type MirrorForwardOutcome = 'skipped' | 'refreshed' | 'refreshed-local' | 'failed';
|
|
24
29
|
|
|
25
30
|
/**
|
|
26
31
|
* MESH-WORKER-PREFS Fix B: when a mesh WORKER session's per-conversation Hide/Mute is toggled
|
|
@@ -41,6 +46,17 @@ type MirrorForwardOutcome = 'skipped' | 'refreshed' | 'failed';
|
|
|
41
46
|
* once on failure, and reports the outcome so the handler can flag a stale mirror to the caller
|
|
42
47
|
* instead of returning an unqualified success. It never rejects — a failure is reported, not thrown,
|
|
43
48
|
* so the local write (already applied) still returns success with a mirrorStale marker.
|
|
49
|
+
*
|
|
50
|
+
* SELF-DIAL (mission fix/cloud-local-hide-self-dial): a self-hosted mesh session — one this daemon
|
|
51
|
+
* both coordinates AND hosts — carries a meshCoordinatorDaemonId equal to this daemon's own id.
|
|
52
|
+
* Dispatching the mirror refresh over P2P to that id self-dials, which the mesh manager REFUSES
|
|
53
|
+
* (SELF_DIAL) → the old code reported that refusal as 'failed' → mirrorStale → the dashboard
|
|
54
|
+
* dropped its optimistic overlay and the toggle appeared to do nothing (the exact CLOUD-local
|
|
55
|
+
* hide/mute "무반응" defect). The remote-worker relay path (coordinatorDaemonId != this daemon)
|
|
56
|
+
* is unchanged. When the coordinator IS this daemon we skip the dial entirely and refresh the
|
|
57
|
+
* local coordinator mirror directly via updateLocalMeshOwnedSession (the cloud runtime wires it to
|
|
58
|
+
* the same updateMeshOwnedSession + dashboard flush the remote mesh_forward_event consumer runs),
|
|
59
|
+
* reporting 'refreshed-local' so no rollback occurs.
|
|
44
60
|
*/
|
|
45
61
|
async function forwardConversationPrefsToCoordinator(
|
|
46
62
|
ctx: MedFamilyContext,
|
|
@@ -74,6 +90,29 @@ async function forwardConversationPrefsToCoordinator(
|
|
|
74
90
|
sessionSettings: { ...patch },
|
|
75
91
|
};
|
|
76
92
|
|
|
93
|
+
// SELF-DIAL guard: the coordinator anchor resolves to THIS daemon. Refresh the local mirror
|
|
94
|
+
// in-process instead of dispatching a P2P command to our own id (which the mesh manager
|
|
95
|
+
// refuses as SELF_DIAL, formerly surfacing as mirrorStale → a false rollback). Uses the
|
|
96
|
+
// machine-core-canonicalizing daemonIdsEquivalent — a raw === would miss a same-machine anchor
|
|
97
|
+
// that arrives in a different id form (daemon_mach_X vs mach_X), the repeatedly-regressed
|
|
98
|
+
// daemon-id form-mismatch class in this repo, and self-dial anyway.
|
|
99
|
+
const selfDaemonId = readNonEmptyString((ctx.deps as any).statusInstanceId);
|
|
100
|
+
if (selfDaemonId && daemonIdsEquivalent(coordinatorDaemonId, selfDaemonId)) {
|
|
101
|
+
const refreshLocal = ctx.deps.updateLocalMeshOwnedSession;
|
|
102
|
+
if (refreshLocal) {
|
|
103
|
+
try {
|
|
104
|
+
refreshLocal(payload);
|
|
105
|
+
return 'refreshed-local';
|
|
106
|
+
} catch (e: any) {
|
|
107
|
+
LOG.warn('Mesh', `[Mesh] set_conversation_prefs local coordinator-mirror refresh failed: ${e?.message || e}`);
|
|
108
|
+
return 'failed';
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
// No local mirror hook (e.g. standalone) — the live instance write already applied is the
|
|
112
|
+
// single source of truth, so treat the self-hosted case as refreshed rather than dialing.
|
|
113
|
+
return 'refreshed-local';
|
|
114
|
+
}
|
|
115
|
+
|
|
77
116
|
// Await the mirror refresh (Fix 4). One retry: a transient P2P blip on the coordinator
|
|
78
117
|
// channel shouldn't strand the mirror stale when the worker's own state already moved.
|
|
79
118
|
for (let attempt = 0; attempt < 2; attempt++) {
|
|
@@ -174,10 +213,12 @@ export const cliAgentHandlers: Record<string, MedFamilyHandler> = {
|
|
|
174
213
|
success: true,
|
|
175
214
|
sessionId,
|
|
176
215
|
...patch,
|
|
177
|
-
// Only surface the mirror status for a genuine mesh
|
|
216
|
+
// Only surface the mirror status for a genuine mesh session (refreshed/failed);
|
|
178
217
|
// a non-mesh session ('skipped') carries no mirror field, so nothing changes for it.
|
|
218
|
+
// A self-hosted session ('refreshed-local' — coordinator == this daemon) refreshed its
|
|
219
|
+
// own mirror in-process and is reported as fresh so the dashboard never rolls back.
|
|
179
220
|
...(mirror === 'failed' ? { mirrorStale: true } : {}),
|
|
180
|
-
...(mirror === 'refreshed' ? { mirrorRefreshed: true } : {}),
|
|
221
|
+
...(mirror === 'refreshed' || mirror === 'refreshed-local' ? { mirrorRefreshed: true } : {}),
|
|
181
222
|
};
|
|
182
223
|
},
|
|
183
224
|
|
package/src/commands/router.ts
CHANGED
|
@@ -158,6 +158,16 @@ export interface CommandRouterDeps {
|
|
|
158
158
|
getMeshPeerConnectionStatus?: (daemonId: string) => Record<string, unknown> | null;
|
|
159
159
|
/** Dispatch a command to a remote mesh node via P2P/relay. Injected by cloud runtime; absent in standalone. */
|
|
160
160
|
dispatchMeshCommand?: (daemonId: string, cmd: string, args: Record<string, unknown>) => Promise<unknown>;
|
|
161
|
+
/**
|
|
162
|
+
* Refresh THIS daemon's own coordinator mirror (adhdev-daemon meshOwnedSessions) for a
|
|
163
|
+
* self-hosted mesh session, applying the same `mesh_forward_event`-shaped payload the remote
|
|
164
|
+
* relay would carry — used by the SELF-DIAL branch of set_conversation_prefs so a locally
|
|
165
|
+
* coordinated session (coordinatorDaemonId == this daemon) updates its mirror directly instead
|
|
166
|
+
* of dispatching a P2P command to its own id (which the mesh manager refuses as SELF_DIAL).
|
|
167
|
+
* Injected by the cloud runtime (calls updateMeshOwnedSession + flushes the dashboard
|
|
168
|
+
* subscription); absent in standalone (no coordinator mirror there).
|
|
169
|
+
*/
|
|
170
|
+
updateLocalMeshOwnedSession?: (payload: Record<string, unknown>) => void;
|
|
161
171
|
}
|
|
162
172
|
|
|
163
173
|
export interface CommandRouterResult {
|