@adhdev/daemon-core 0.9.82-rc.462 → 0.9.82-rc.463

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.mjs CHANGED
@@ -404,10 +404,10 @@ function readInjected(value) {
404
404
  }
405
405
  function getDaemonBuildInfo() {
406
406
  if (cached) return cached;
407
- const commit = readInjected(true ? "1481e2078cc0eceea283a2370cccb4cd9102e4ff" : void 0) ?? "unknown";
408
- const commitShort = readInjected(true ? "1481e207" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
409
- const version = readInjected(true ? "0.9.82-rc.462" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
410
- const builtAt = readInjected(true ? "2026-07-04T16:50:21.874Z" : void 0);
407
+ const commit = readInjected(true ? "3441855fe9c04e158a4dc94eed196b7bcba1647e" : void 0) ?? "unknown";
408
+ const commitShort = readInjected(true ? "3441855f" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
409
+ const version = readInjected(true ? "0.9.82-rc.463" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
410
+ const builtAt = readInjected(true ? "2026-07-05T02:56:26.902Z" : void 0);
411
411
  cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
412
412
  return cached;
413
413
  }
@@ -40279,15 +40279,37 @@ function executeSqlite(src, input) {
40279
40279
  }
40280
40280
  try {
40281
40281
  const requested = input.providerSessionId || "";
40282
- const resolveMessagesFor = (sessionId2) => {
40283
- if (!sessionId2) return null;
40284
- let rows;
40285
- try {
40286
- rows = db.prepare(src.message_query).all(sessionId2);
40287
- } catch {
40288
- return null;
40282
+ const resolveClusterIds = (anchorId) => {
40283
+ const ids = /* @__PURE__ */ new Set();
40284
+ if (anchorId) ids.add(anchorId);
40285
+ if (src.session_cluster_query && anchorId) {
40286
+ try {
40287
+ const rows = db.prepare(src.session_cluster_query).all(anchorId);
40288
+ for (const row of rows) {
40289
+ const idRaw = Object.values(row)[0];
40290
+ if (idRaw != null && String(idRaw)) ids.add(String(idRaw));
40291
+ }
40292
+ } catch {
40293
+ }
40289
40294
  }
40290
- return rows && rows.length > 0 ? rows : null;
40295
+ return Array.from(ids);
40296
+ };
40297
+ const resolveMessagesFor = (anchorId) => {
40298
+ if (!anchorId) return null;
40299
+ const clusterIds = resolveClusterIds(anchorId);
40300
+ const merged = [];
40301
+ for (const id of clusterIds) {
40302
+ let rows;
40303
+ try {
40304
+ rows = db.prepare(src.message_query).all(id);
40305
+ } catch {
40306
+ continue;
40307
+ }
40308
+ if (rows && rows.length > 0) merged.push(...rows);
40309
+ }
40310
+ if (merged.length === 0) return null;
40311
+ if (clusterIds.length > 1) sortRowsByMappedTimestamp(merged, src.message_map);
40312
+ return merged;
40291
40313
  };
40292
40314
  const resolveNewestSessionId = () => {
40293
40315
  let sessionRow;
@@ -40344,6 +40366,20 @@ function executeSqlite(src, input) {
40344
40366
  }
40345
40367
  }
40346
40368
  }
40369
+ function sortRowsByMappedTimestamp(rows, map) {
40370
+ if (!map.timestamp_ms) return;
40371
+ const keyed = rows.map((row, index) => {
40372
+ const parsed = parseTimestamp(jsonPathGet(row, map.timestamp_ms));
40373
+ return { row, index, ts: parsed == null ? Number.NaN : parsed };
40374
+ });
40375
+ keyed.sort((a, b) => {
40376
+ const aHas = !Number.isNaN(a.ts);
40377
+ const bHas = !Number.isNaN(b.ts);
40378
+ if (aHas && bHas && a.ts !== b.ts) return a.ts - b.ts;
40379
+ return a.index - b.index;
40380
+ });
40381
+ for (let i = 0; i < keyed.length; i += 1) rows[i] = keyed[i].row;
40382
+ }
40347
40383
  function expandPath2(template, input, opts) {
40348
40384
  if (!template) return null;
40349
40385
  let out = template;
@@ -42968,6 +43004,19 @@ var CliProviderInstance = class _CliProviderInstance {
42968
43004
  }
42969
43005
  return probe;
42970
43006
  }
43007
+ /**
43008
+ * The spawned CLI's env overrides (e.g. the mesh coordinator points hermes
43009
+ * at a per-coordinator HERMES_HOME so its state.db lives in a tmpdir instead
43010
+ * of ~/.hermes). The native-history executor expands `${HERMES_HOME:-~/.hermes}`
43011
+ * from this map, so the completion gate MUST pass it through — otherwise the
43012
+ * gate reads ~/.hermes, finds no coordinator-session transcript, and
43013
+ * false-fires missing_final_assistant on every coordinator turn.
43014
+ */
43015
+ spawnedEnvOverrides() {
43016
+ const meta = typeof this.adapter?.getRuntimeMetadata === "function" ? this.adapter.getRuntimeMetadata() : void 0;
43017
+ const env = meta && typeof meta === "object" ? meta.spawnedEnv : void 0;
43018
+ return env && typeof env === "object" ? env : void 0;
43019
+ }
42971
43020
  readExternalCompletionMessages() {
42972
43021
  const adapterOwnsMessagesElsewhere = this.adapter?.chatMessagesOwnedExternally === true;
42973
43022
  if (!adapterOwnsMessagesElsewhere) return null;
@@ -42988,6 +43037,7 @@ var CliProviderInstance = class _CliProviderInstance {
42988
43037
  historyBehavior: this.provider.historyBehavior,
42989
43038
  scripts: this.provider.scripts,
42990
43039
  sessionStartedAtMs: this.startedAt,
43040
+ envOverrides: this.spawnedEnvOverrides(),
42991
43041
  forceRefresh: true
42992
43042
  });
42993
43043
  if (restoredHistory.source !== "provider-native") {
@@ -48565,14 +48615,44 @@ function openDb() {
48565
48615
  return null;
48566
48616
  }
48567
48617
  }
48618
+ function resolveClusterSessionIds(db, anchorId) {
48619
+ if (!anchorId) return [];
48620
+ try {
48621
+ const rows = db.prepare(
48622
+ `WITH RECURSIVE
48623
+ up(id) AS (
48624
+ SELECT id FROM sessions WHERE id = ?
48625
+ UNION
48626
+ SELECT s.parent_session_id FROM sessions s JOIN up ON s.id = up.id
48627
+ WHERE s.parent_session_id IS NOT NULL
48628
+ ),
48629
+ cluster(id) AS (
48630
+ SELECT id FROM up
48631
+ UNION
48632
+ SELECT s.id FROM sessions s JOIN cluster ON s.parent_session_id = cluster.id
48633
+ )
48634
+ SELECT id FROM cluster`
48635
+ ).all(anchorId);
48636
+ const ids = /* @__PURE__ */ new Set([anchorId]);
48637
+ for (const r of rows) {
48638
+ if (r && r.id != null && String(r.id)) ids.add(String(r.id));
48639
+ }
48640
+ return Array.from(ids);
48641
+ } catch {
48642
+ return [anchorId];
48643
+ }
48644
+ }
48568
48645
  function loadMessagesForSession(db, sessionId) {
48646
+ const clusterIds = resolveClusterSessionIds(db, sessionId);
48647
+ if (clusterIds.length === 0) return [];
48648
+ const placeholders = clusterIds.map(() => "?").join(", ");
48569
48649
  const rows = db.prepare(
48570
48650
  `SELECT id, role, COALESCE(NULLIF(content, ''), tool_calls) AS content, timestamp
48571
48651
  FROM messages
48572
- WHERE session_id = ?
48652
+ WHERE session_id IN (${placeholders})
48573
48653
  AND ((content IS NOT NULL AND content != '') OR (tool_calls IS NOT NULL AND tool_calls != ''))
48574
48654
  ORDER BY timestamp ASC, id ASC`
48575
- ).all(sessionId);
48655
+ ).all(...clusterIds);
48576
48656
  const out = [];
48577
48657
  for (const r of rows) {
48578
48658
  const role = normalizeHermesRole(r.role);
@@ -54512,7 +54592,6 @@ cleanOldFiles();
54512
54592
  // src/commands/router.ts
54513
54593
  init_debug_trace();
54514
54594
  init_mesh_host_ownership();
54515
- init_mesh_work_queue();
54516
54595
  import * as fs33 from "fs";
54517
54596
 
54518
54597
  // src/mesh/mesh-node-identity.ts
@@ -58906,6 +58985,177 @@ async function cleanupMeshSessions(self, args) {
58906
58985
  };
58907
58986
  }
58908
58987
 
58988
+ // src/commands/router-aggregate-status.ts
58989
+ init_dist();
58990
+ init_mesh_work_queue();
58991
+ function cloneJsonValue(value) {
58992
+ if (typeof structuredClone === "function") return structuredClone(value);
58993
+ return JSON.parse(JSON.stringify(value));
58994
+ }
58995
+ function hydrateCachedAggregateMeshStatusFromInline(self, snapshot, mesh, options) {
58996
+ if (!mesh || typeof mesh !== "object" || !Array.isArray(mesh.nodes) || !Array.isArray(snapshot?.nodes)) return snapshot;
58997
+ const inlineNodesById = /* @__PURE__ */ new Map();
58998
+ for (const node of mesh.nodes) {
58999
+ const nodeId = readInlineMeshNodeId(node);
59000
+ if (nodeId) inlineNodesById.set(nodeId, node);
59001
+ }
59002
+ if (!inlineNodesById.size) return snapshot;
59003
+ let changed = false;
59004
+ const unavailableNodeIds = /* @__PURE__ */ new Set();
59005
+ const sourceOfTruth = readObjectRecord(snapshot.sourceOfTruth);
59006
+ const directPeerTruth = readObjectRecord(sourceOfTruth.directPeerTruth);
59007
+ const deadNodeIds = /* @__PURE__ */ new Set();
59008
+ for (const node of mesh.nodes) {
59009
+ if (!isDeadLocalWorktreeNode(node)) continue;
59010
+ const deadId = readInlineMeshNodeId(node);
59011
+ if (deadId) deadNodeIds.add(deadId);
59012
+ }
59013
+ let droppedDeadUnavailable = false;
59014
+ for (const entry of Array.isArray(directPeerTruth.unavailableNodeIds) ? directPeerTruth.unavailableNodeIds : []) {
59015
+ const nodeId = readStringValue(entry);
59016
+ if (!nodeId) continue;
59017
+ if (deadNodeIds.has(nodeId)) {
59018
+ droppedDeadUnavailable = true;
59019
+ continue;
59020
+ }
59021
+ unavailableNodeIds.add(nodeId);
59022
+ }
59023
+ if (droppedDeadUnavailable) changed = true;
59024
+ const nodes = snapshot.nodes.map((statusNode) => {
59025
+ const nodeId = normalizeMeshNodeId(statusNode);
59026
+ const inlineNode = nodeId ? inlineNodesById.get(nodeId) : void 0;
59027
+ if (!inlineNode) return statusNode;
59028
+ const liveGit = buildInlineMeshTransitGitStatus(inlineNode);
59029
+ if (!liveGit) return statusNode;
59030
+ const nextStatus = { ...statusNode };
59031
+ nextStatus.git = liveGit;
59032
+ nextStatus.health = deriveMeshNodeHealthFromGit(liveGit);
59033
+ applyInlineMeshBranchConvergence(mesh, inlineNode, nextStatus);
59034
+ nextStatus.launchReady = readBooleanValue(nextStatus.launchReady) ?? true;
59035
+ const connection = readObjectRecord(nextStatus.connection);
59036
+ const connectionState = readStringValue(connection.state);
59037
+ const connectionReported = readBooleanValue(connection.reported) ?? false;
59038
+ if (!connectionReported || connectionState === "unknown") {
59039
+ nextStatus.connection = buildLivePeerGitConnection(connection);
59040
+ }
59041
+ delete nextStatus.gitProbePending;
59042
+ const error = readStringValue(nextStatus.error);
59043
+ if (error && /pending_git|git probe|live peer git snapshot|no peer git snapshot/i.test(error)) delete nextStatus.error;
59044
+ if (!readStringValue(nextStatus.machineStatus)) nextStatus.machineStatus = "online";
59045
+ if (nodeId) unavailableNodeIds.delete(nodeId);
59046
+ changed = true;
59047
+ return nextStatus;
59048
+ });
59049
+ const aggregateDirectTruthSatisfied = sourceOfTruth.coordinatorOwnsLiveTruth === true || directPeerTruth.satisfied === true;
59050
+ if (!changed && !(options?.requireDirectPeerTruth && unavailableNodeIds.size > 0 && !aggregateDirectTruthSatisfied)) return snapshot;
59051
+ const nextSourceOfTruth = {
59052
+ ...sourceOfTruth,
59053
+ ...Object.keys(directPeerTruth).length ? {
59054
+ directPeerTruth: {
59055
+ ...directPeerTruth,
59056
+ satisfied: options?.requireDirectPeerTruth === true ? aggregateDirectTruthSatisfied || unavailableNodeIds.size === 0 : directPeerTruth.satisfied,
59057
+ unavailableNodeIds: [...unavailableNodeIds]
59058
+ },
59059
+ ...options?.requireDirectPeerTruth === true ? {
59060
+ coordinatorOwnsLiveTruth: aggregateDirectTruthSatisfied || unavailableNodeIds.size === 0,
59061
+ currentStatus: aggregateDirectTruthSatisfied || unavailableNodeIds.size === 0 ? "live_git_and_session_probes" : "direct_peer_truth_unavailable"
59062
+ } : {}
59063
+ } : {}
59064
+ };
59065
+ return {
59066
+ ...snapshot,
59067
+ ...options?.requireDirectPeerTruth === true && unavailableNodeIds.size > 0 && !aggregateDirectTruthSatisfied ? {
59068
+ success: false,
59069
+ code: "mesh_direct_peer_truth_unavailable",
59070
+ error: "Selected coordinator could not confirm direct mesh truth for every remote node yet."
59071
+ } : {},
59072
+ sourceOfTruth: nextSourceOfTruth,
59073
+ branchConvergenceSummary: summarizeInlineMeshBranchConvergence(nodes),
59074
+ nodes
59075
+ };
59076
+ }
59077
+ function getCachedAggregateMeshStatus(self, meshId, mesh, options) {
59078
+ const cached3 = self.aggregateMeshStatusCache.get(meshId);
59079
+ if (!cached3?.snapshot || cached3.snapshot.success !== true || !Array.isArray(cached3.snapshot.nodes)) return null;
59080
+ if (cached3.queueRevision !== getMeshQueueRevision(meshId)) return null;
59081
+ let snapshot = cloneJsonValue(cached3.snapshot);
59082
+ snapshot = hydrateCachedAggregateMeshStatusFromInline(self, snapshot, mesh, options);
59083
+ if (!options?.allowStalePending && shouldRefreshStalePendingAggregate(snapshot, options)) return null;
59084
+ const ageMs = Math.max(0, Date.now() - cached3.builtAt);
59085
+ const sourceOfTruth = snapshot.sourceOfTruth && typeof snapshot.sourceOfTruth === "object" ? snapshot.sourceOfTruth : {};
59086
+ snapshot.sourceOfTruth = {
59087
+ ...sourceOfTruth,
59088
+ aggregateSnapshot: {
59089
+ ...sourceOfTruth.aggregateSnapshot && typeof sourceOfTruth.aggregateSnapshot === "object" ? sourceOfTruth.aggregateSnapshot : {},
59090
+ owner: "coordinator_daemon_memory",
59091
+ cached: true,
59092
+ source: "memory",
59093
+ refreshReason: "memory_cache_hit",
59094
+ ageMs,
59095
+ cachedAt: new Date(cached3.builtAt).toISOString(),
59096
+ returnedAt: (/* @__PURE__ */ new Date()).toISOString()
59097
+ }
59098
+ };
59099
+ return snapshot;
59100
+ }
59101
+ function rememberAggregateMeshStatus(self, meshId, snapshot, refreshReason) {
59102
+ if (!snapshot || typeof snapshot !== "object" || snapshot.success !== true || !Array.isArray(snapshot.nodes)) return snapshot;
59103
+ const builtAt = Date.now();
59104
+ const next = cloneJsonValue(snapshot);
59105
+ const sourceOfTruth = next.sourceOfTruth && typeof next.sourceOfTruth === "object" ? next.sourceOfTruth : {};
59106
+ next.sourceOfTruth = {
59107
+ ...sourceOfTruth,
59108
+ aggregateSnapshot: {
59109
+ owner: "coordinator_daemon_memory",
59110
+ cached: false,
59111
+ source: "live_refresh",
59112
+ refreshReason,
59113
+ ageMs: 0,
59114
+ cachedAt: new Date(builtAt).toISOString(),
59115
+ returnedAt: new Date(builtAt).toISOString()
59116
+ }
59117
+ };
59118
+ self.aggregateMeshStatusCache.set(meshId, { builtAt, snapshot: cloneJsonValue(next), queueRevision: getMeshQueueRevision(meshId) });
59119
+ return next;
59120
+ }
59121
+
59122
+ // src/commands/router-mesh-session-owner.ts
59123
+ init_dist();
59124
+ function resolveRemoteMeshSessionOwnerDaemonId(self, sessionId, ownerNodeIdHint) {
59125
+ const trimmed = typeof sessionId === "string" ? sessionId.trim() : "";
59126
+ const nodeHint = typeof ownerNodeIdHint === "string" ? ownerNodeIdHint.trim() : "";
59127
+ if (!trimmed && !nodeHint) return void 0;
59128
+ const selfDaemonId = self.deps.statusInstanceId;
59129
+ const candidates = collectMeshSessionOwnerCandidateNodes(self);
59130
+ if (trimmed) {
59131
+ for (const node of candidates) {
59132
+ if (!collectMeshNodeHostedSessionIds(node).has(trimmed)) continue;
59133
+ const nodeDaemonId = readMeshNodeDaemonId(readObjectRecord(node));
59134
+ if (!nodeDaemonId) continue;
59135
+ if (selfDaemonId && daemonIdsEquivalent(nodeDaemonId, selfDaemonId)) return void 0;
59136
+ return nodeDaemonId;
59137
+ }
59138
+ }
59139
+ if (nodeHint) {
59140
+ for (const node of candidates) {
59141
+ if (!meshNodeIdMatches(node, nodeHint)) continue;
59142
+ const nodeDaemonId = readMeshNodeDaemonId(readObjectRecord(node));
59143
+ if (!nodeDaemonId) continue;
59144
+ if (selfDaemonId && daemonIdsEquivalent(nodeDaemonId, selfDaemonId)) return void 0;
59145
+ return nodeDaemonId;
59146
+ }
59147
+ }
59148
+ return void 0;
59149
+ }
59150
+ function collectMeshSessionOwnerCandidateNodes(self) {
59151
+ const nodes = self.getCachedInlineMeshNodes();
59152
+ for (const cached3 of self.aggregateMeshStatusCache.values()) {
59153
+ const snapshotNodes = cached3?.snapshot?.nodes;
59154
+ if (Array.isArray(snapshotNodes)) nodes.push(...snapshotNodes);
59155
+ }
59156
+ return nodes;
59157
+ }
59158
+
58909
59159
  // src/mesh/mesh-coordinator-config.ts
58910
59160
  init_logger();
58911
59161
  import * as yaml5 from "js-yaml";
@@ -59074,7 +59324,8 @@ var DaemonCommandRouter = class {
59074
59324
  * on disk) clears the tombstone and merges normally, preserving clone
59075
59325
  * worktree visibility and legitimate node re-creation. */
59076
59326
  removedInlineMeshNodeIds = /* @__PURE__ */ new Map();
59077
- /** Coordinator-owned whole-mesh aggregate status snapshots. Browser callers read this by default. */
59327
+ /** Coordinator-owned whole-mesh aggregate status snapshots. Browser callers read this by default.
59328
+ * Public (not private) so the extracted ./router-aggregate-status.ts orchestration can reach it via `self`. */
59078
59329
  aggregateMeshStatusCache = /* @__PURE__ */ new Map();
59079
59330
  /** Shared per-peer git_status probe dedup + recently-probed reuse gate.
59080
59331
  * Spans separate mesh_status/get_mesh calls so the dashboard auto-retry
@@ -59096,135 +59347,19 @@ var DaemonCommandRouter = class {
59096
59347
  constructor(deps) {
59097
59348
  this.deps = deps;
59098
59349
  }
59099
- cloneJsonValue(value) {
59100
- if (typeof structuredClone === "function") return structuredClone(value);
59101
- return JSON.parse(JSON.stringify(value));
59102
- }
59350
+ // ─── Aggregate mesh-status cache ────────────────────────────────────
59351
+ // Implementation lives in ./router-aggregate-status.ts (behavior-preserving
59352
+ // code move). Kept here as thin delegators: getCachedAggregateMeshStatus /
59353
+ // rememberAggregateMeshStatus are bound into HighFamilyContext, so callers
59354
+ // reach these via `self.` for correct instance dispatch.
59103
59355
  hydrateCachedAggregateMeshStatusFromInline(snapshot, mesh, options) {
59104
- if (!mesh || typeof mesh !== "object" || !Array.isArray(mesh.nodes) || !Array.isArray(snapshot?.nodes)) return snapshot;
59105
- const inlineNodesById = /* @__PURE__ */ new Map();
59106
- for (const node of mesh.nodes) {
59107
- const nodeId = readInlineMeshNodeId(node);
59108
- if (nodeId) inlineNodesById.set(nodeId, node);
59109
- }
59110
- if (!inlineNodesById.size) return snapshot;
59111
- let changed = false;
59112
- const unavailableNodeIds = /* @__PURE__ */ new Set();
59113
- const sourceOfTruth = readObjectRecord(snapshot.sourceOfTruth);
59114
- const directPeerTruth = readObjectRecord(sourceOfTruth.directPeerTruth);
59115
- const deadNodeIds = /* @__PURE__ */ new Set();
59116
- for (const node of mesh.nodes) {
59117
- if (!isDeadLocalWorktreeNode(node)) continue;
59118
- const deadId = readInlineMeshNodeId(node);
59119
- if (deadId) deadNodeIds.add(deadId);
59120
- }
59121
- let droppedDeadUnavailable = false;
59122
- for (const entry of Array.isArray(directPeerTruth.unavailableNodeIds) ? directPeerTruth.unavailableNodeIds : []) {
59123
- const nodeId = readStringValue(entry);
59124
- if (!nodeId) continue;
59125
- if (deadNodeIds.has(nodeId)) {
59126
- droppedDeadUnavailable = true;
59127
- continue;
59128
- }
59129
- unavailableNodeIds.add(nodeId);
59130
- }
59131
- if (droppedDeadUnavailable) changed = true;
59132
- const nodes = snapshot.nodes.map((statusNode) => {
59133
- const nodeId = normalizeMeshNodeId(statusNode);
59134
- const inlineNode = nodeId ? inlineNodesById.get(nodeId) : void 0;
59135
- if (!inlineNode) return statusNode;
59136
- const liveGit = buildInlineMeshTransitGitStatus(inlineNode);
59137
- if (!liveGit) return statusNode;
59138
- const nextStatus = { ...statusNode };
59139
- nextStatus.git = liveGit;
59140
- nextStatus.health = deriveMeshNodeHealthFromGit(liveGit);
59141
- applyInlineMeshBranchConvergence(mesh, inlineNode, nextStatus);
59142
- nextStatus.launchReady = readBooleanValue(nextStatus.launchReady) ?? true;
59143
- const connection = readObjectRecord(nextStatus.connection);
59144
- const connectionState = readStringValue(connection.state);
59145
- const connectionReported = readBooleanValue(connection.reported) ?? false;
59146
- if (!connectionReported || connectionState === "unknown") {
59147
- nextStatus.connection = buildLivePeerGitConnection(connection);
59148
- }
59149
- delete nextStatus.gitProbePending;
59150
- const error = readStringValue(nextStatus.error);
59151
- if (error && /pending_git|git probe|live peer git snapshot|no peer git snapshot/i.test(error)) delete nextStatus.error;
59152
- if (!readStringValue(nextStatus.machineStatus)) nextStatus.machineStatus = "online";
59153
- if (nodeId) unavailableNodeIds.delete(nodeId);
59154
- changed = true;
59155
- return nextStatus;
59156
- });
59157
- const aggregateDirectTruthSatisfied = sourceOfTruth.coordinatorOwnsLiveTruth === true || directPeerTruth.satisfied === true;
59158
- if (!changed && !(options?.requireDirectPeerTruth && unavailableNodeIds.size > 0 && !aggregateDirectTruthSatisfied)) return snapshot;
59159
- const nextSourceOfTruth = {
59160
- ...sourceOfTruth,
59161
- ...Object.keys(directPeerTruth).length ? {
59162
- directPeerTruth: {
59163
- ...directPeerTruth,
59164
- satisfied: options?.requireDirectPeerTruth === true ? aggregateDirectTruthSatisfied || unavailableNodeIds.size === 0 : directPeerTruth.satisfied,
59165
- unavailableNodeIds: [...unavailableNodeIds]
59166
- },
59167
- ...options?.requireDirectPeerTruth === true ? {
59168
- coordinatorOwnsLiveTruth: aggregateDirectTruthSatisfied || unavailableNodeIds.size === 0,
59169
- currentStatus: aggregateDirectTruthSatisfied || unavailableNodeIds.size === 0 ? "live_git_and_session_probes" : "direct_peer_truth_unavailable"
59170
- } : {}
59171
- } : {}
59172
- };
59173
- return {
59174
- ...snapshot,
59175
- ...options?.requireDirectPeerTruth === true && unavailableNodeIds.size > 0 && !aggregateDirectTruthSatisfied ? {
59176
- success: false,
59177
- code: "mesh_direct_peer_truth_unavailable",
59178
- error: "Selected coordinator could not confirm direct mesh truth for every remote node yet."
59179
- } : {},
59180
- sourceOfTruth: nextSourceOfTruth,
59181
- branchConvergenceSummary: summarizeInlineMeshBranchConvergence(nodes),
59182
- nodes
59183
- };
59356
+ return hydrateCachedAggregateMeshStatusFromInline(this, snapshot, mesh, options);
59184
59357
  }
59185
59358
  getCachedAggregateMeshStatus(meshId, mesh, options) {
59186
- const cached3 = this.aggregateMeshStatusCache.get(meshId);
59187
- if (!cached3?.snapshot || cached3.snapshot.success !== true || !Array.isArray(cached3.snapshot.nodes)) return null;
59188
- if (cached3.queueRevision !== getMeshQueueRevision(meshId)) return null;
59189
- let snapshot = this.cloneJsonValue(cached3.snapshot);
59190
- snapshot = this.hydrateCachedAggregateMeshStatusFromInline(snapshot, mesh, options);
59191
- if (!options?.allowStalePending && shouldRefreshStalePendingAggregate(snapshot, options)) return null;
59192
- const ageMs = Math.max(0, Date.now() - cached3.builtAt);
59193
- const sourceOfTruth = snapshot.sourceOfTruth && typeof snapshot.sourceOfTruth === "object" ? snapshot.sourceOfTruth : {};
59194
- snapshot.sourceOfTruth = {
59195
- ...sourceOfTruth,
59196
- aggregateSnapshot: {
59197
- ...sourceOfTruth.aggregateSnapshot && typeof sourceOfTruth.aggregateSnapshot === "object" ? sourceOfTruth.aggregateSnapshot : {},
59198
- owner: "coordinator_daemon_memory",
59199
- cached: true,
59200
- source: "memory",
59201
- refreshReason: "memory_cache_hit",
59202
- ageMs,
59203
- cachedAt: new Date(cached3.builtAt).toISOString(),
59204
- returnedAt: (/* @__PURE__ */ new Date()).toISOString()
59205
- }
59206
- };
59207
- return snapshot;
59359
+ return getCachedAggregateMeshStatus(this, meshId, mesh, options);
59208
59360
  }
59209
59361
  rememberAggregateMeshStatus(meshId, snapshot, refreshReason) {
59210
- if (!snapshot || typeof snapshot !== "object" || snapshot.success !== true || !Array.isArray(snapshot.nodes)) return snapshot;
59211
- const builtAt = Date.now();
59212
- const next = this.cloneJsonValue(snapshot);
59213
- const sourceOfTruth = next.sourceOfTruth && typeof next.sourceOfTruth === "object" ? next.sourceOfTruth : {};
59214
- next.sourceOfTruth = {
59215
- ...sourceOfTruth,
59216
- aggregateSnapshot: {
59217
- owner: "coordinator_daemon_memory",
59218
- cached: false,
59219
- source: "live_refresh",
59220
- refreshReason,
59221
- ageMs: 0,
59222
- cachedAt: new Date(builtAt).toISOString(),
59223
- returnedAt: new Date(builtAt).toISOString()
59224
- }
59225
- };
59226
- this.aggregateMeshStatusCache.set(meshId, { builtAt, snapshot: this.cloneJsonValue(next), queueRevision: getMeshQueueRevision(meshId) });
59227
- return next;
59362
+ return rememberAggregateMeshStatus(this, meshId, snapshot, refreshReason);
59228
59363
  }
59229
59364
  getCachedInlineMeshNodes() {
59230
59365
  const nodes = [];
@@ -59235,82 +59370,13 @@ var DaemonCommandRouter = class {
59235
59370
  }
59236
59371
  return nodes;
59237
59372
  }
59238
- /**
59239
- * Resolve the REMOTE worker daemonId that owns a given session, when the session
59240
- * belongs to a mesh node hosted on a DIFFERENT daemon than this coordinator.
59241
- *
59242
- * The coordinator does not host remote-worker session instances in its own
59243
- * instanceManager/sessionRegistry — only their cached mesh-node metadata. A
59244
- * dashboard-issued session-scoped command (invoke_provider_script / resolve_action /
59245
- * set_mode / …) lands on the coordinator with a targetSessionId the coordinator can't
59246
- * find locally, and without forwarding it dies as "Live session not found". send_chat
59247
- * happens to survive (its target resolves to the worker by another route), but the
59248
- * controlbar commands do not — so the controlbar buttons appear to do nothing.
59249
- *
59250
- * Mirror the existing node-level remote-forward pattern (fast_forward_mesh_node etc.):
59251
- * scan the candidate mesh nodes for the one hosting the targetSessionId, and return its
59252
- * daemonId when that daemonId is a remote daemon (i.e. not this coordinator's own
59253
- * statusInstanceId). Returns undefined for a locally-hosted session (no forward — execute
59254
- * locally as before) or when ownership can't be resolved.
59255
- *
59256
- * The candidate set spans BOTH the cached inline-mesh nodes and the live aggregate
59257
- * mesh-status snapshots. The inline cache reliably carries only each node's single primary
59258
- * session (cachedStatus.activeSession), so a worker hosting more than one session exposes its
59259
- * non-primary sessions only on the aggregate snapshot nodes (status.activeSessions /
59260
- * activeSessionDetails, built from live session records). collectMeshNodeHostedSessionIds does
59261
- * the wider plural-shape scan so a controlbar/modal command targeting a non-primary remote
59262
- * session still resolves its owner — the singular readCachedInlineMeshActiveSessions semantics
59263
- * other consumers depend on stay untouched.
59264
- *
59265
- * CANCEL-STOP-RELAY: the session-id cache scan above only matches when the coordinator's
59266
- * cached status snapshot already lists the worker's session id in a recognized active-sessions
59267
- * shape. A worktree-clone worker session whose id form/timing differs from the cached snapshot
59268
- * (or is simply not yet reflected) misses the scan, so a stop that carries the authoritative
59269
- * owning nodeId (mesh_queue_cancel knows assignedNodeId) used to silently fail to forward.
59270
- * `ownerNodeIdHint` adds a deterministic fallback: when the session-id scan misses, resolve the
59271
- * owner daemonId by matching the node by id (meshNodeIdMatches — same form-tolerant compare the
59272
- * rest of the router uses, no new raw compare). The same self-loopback guard applies to both
59273
- * paths, so a coordinator-hosted node is still never force-forwarded to a remote form of itself.
59274
- */
59373
+ // ─── Remote mesh-session owner resolution ───────────────────────────
59374
+ // Implementation lives in ./router-mesh-session-owner.ts (behavior-preserving
59375
+ // code move). resolveRemoteMeshSessionOwnerDaemonId stays public (the [Z]
59376
+ // session-scoped forward in executeDaemonCommand and a unit test call it), so
59377
+ // it's kept here as a thin delegator.
59275
59378
  resolveRemoteMeshSessionOwnerDaemonId(sessionId, ownerNodeIdHint) {
59276
- const trimmed = typeof sessionId === "string" ? sessionId.trim() : "";
59277
- const nodeHint = typeof ownerNodeIdHint === "string" ? ownerNodeIdHint.trim() : "";
59278
- if (!trimmed && !nodeHint) return void 0;
59279
- const selfDaemonId = this.deps.statusInstanceId;
59280
- const candidates = this.collectMeshSessionOwnerCandidateNodes();
59281
- if (trimmed) {
59282
- for (const node of candidates) {
59283
- if (!collectMeshNodeHostedSessionIds(node).has(trimmed)) continue;
59284
- const nodeDaemonId = readMeshNodeDaemonId(readObjectRecord(node));
59285
- if (!nodeDaemonId) continue;
59286
- if (selfDaemonId && daemonIdsEquivalent(nodeDaemonId, selfDaemonId)) return void 0;
59287
- return nodeDaemonId;
59288
- }
59289
- }
59290
- if (nodeHint) {
59291
- for (const node of candidates) {
59292
- if (!meshNodeIdMatches(node, nodeHint)) continue;
59293
- const nodeDaemonId = readMeshNodeDaemonId(readObjectRecord(node));
59294
- if (!nodeDaemonId) continue;
59295
- if (selfDaemonId && daemonIdsEquivalent(nodeDaemonId, selfDaemonId)) return void 0;
59296
- return nodeDaemonId;
59297
- }
59298
- }
59299
- return void 0;
59300
- }
59301
- /**
59302
- * Candidate nodes for remote-session owner resolution: the cached inline-mesh nodes (which
59303
- * carry each node's primary session) plus the nodes from every cached aggregate mesh-status
59304
- * snapshot (which carry each node's full live session list). getCachedInlineMeshNodes()
59305
- * returns a fresh array, so appending the aggregate nodes never mutates cached state.
59306
- */
59307
- collectMeshSessionOwnerCandidateNodes() {
59308
- const nodes = this.getCachedInlineMeshNodes();
59309
- for (const cached3 of this.aggregateMeshStatusCache.values()) {
59310
- const snapshotNodes = cached3?.snapshot?.nodes;
59311
- if (Array.isArray(snapshotNodes)) nodes.push(...snapshotNodes);
59312
- }
59313
- return nodes;
59379
+ return resolveRemoteMeshSessionOwnerDaemonId(this, sessionId, ownerNodeIdHint);
59314
59380
  }
59315
59381
  getCachedInlineMesh(meshId, inlineMesh) {
59316
59382
  if (inlineMesh && typeof inlineMesh === "object") {