@adhdev/daemon-core 0.9.82-rc.461 → 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 ? "ed8842e811aa362a2b4cc530498bc1fc7e1a7e4a" : void 0) ?? "unknown";
408
- const commitShort = readInjected(true ? "ed8842e8" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
409
- const version = readInjected(true ? "0.9.82-rc.461" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
410
- const builtAt = readInjected(true ? "2026-07-04T15:00:03.344Z" : 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
  }
@@ -11475,6 +11475,37 @@ import { randomUUID as randomUUID8 } from "crypto";
11475
11475
  function normalizeCoordinatorDaemonIds(coordinatorDaemonId) {
11476
11476
  return expandDaemonIdForms(coordinatorDaemonId);
11477
11477
  }
11478
+ function isMeshProtocolV2EnforceEnabled() {
11479
+ const raw = readNonEmptyString2(process.env.MESH_PROTOCOL_V2_ENFORCE);
11480
+ if (!raw) return false;
11481
+ const v = raw.trim().toLowerCase();
11482
+ return v === "1" || v === "true" || v === "on" || v === "yes";
11483
+ }
11484
+ function ledgerRecordQuarantinedEvent(event, reason) {
11485
+ try {
11486
+ const finalSummary = readMeshCompletionSummary(event.metadataEvent || {});
11487
+ appendLedgerEntry(event.meshId, {
11488
+ kind: "event_held",
11489
+ ...event.nodeId ? { nodeId: event.nodeId } : {},
11490
+ payload: {
11491
+ event: event.event,
11492
+ reason,
11493
+ recoverable: true,
11494
+ nodeLabel: event.nodeLabel,
11495
+ ...event.workspace ? { workspace: event.workspace } : {},
11496
+ targetCoordinatorDaemonId: event.targetCoordinatorDaemonId ?? null,
11497
+ ...readNonEmptyString2(event.eventId) ? { eventId: event.eventId } : {},
11498
+ queuedAt: event.queuedAt,
11499
+ ...finalSummary ? { finalSummary } : {}
11500
+ }
11501
+ });
11502
+ } catch (e) {
11503
+ LOG.warn("MeshEventsV2", `Failed to ledger-record v2-quarantined ${event.event} for mesh ${event.meshId}: ${e?.message || e}`);
11504
+ }
11505
+ }
11506
+ function getMeshV2DrainCounters() {
11507
+ return { ...meshV2DrainCounters };
11508
+ }
11478
11509
  function warnV2Once(key2, message) {
11479
11510
  if (warnedV2Violations.has(key2)) return;
11480
11511
  warnedV2Violations.add(key2);
@@ -11506,12 +11537,22 @@ function identityDeliversTo(intendedFor, drainer) {
11506
11537
  }
11507
11538
  function routeV2EventsForDrainer(events, drainer, ctx) {
11508
11539
  if (!drainer) return events;
11540
+ const enforce = isMeshProtocolV2EnforceEnabled();
11509
11541
  const bump = (k) => {
11510
11542
  if (ctx.countMetrics) meshV2DrainCounters[k]++;
11511
11543
  };
11512
11544
  const kept = [];
11513
11545
  for (const event of events) {
11514
11546
  if (!isV2Event(event)) {
11547
+ if (enforce) {
11548
+ bump("v1UnversionedQuarantined");
11549
+ if (ctx.countMetrics) ledgerRecordQuarantinedEvent(event, "v2_enforce_unversioned_quarantined");
11550
+ warnV2Once(
11551
+ `${event.meshId}::${event.eventId ?? event.event}::v1-quarantined`,
11552
+ `v2 ENFORCE: unversioned ${event.event} on mesh ${event.meshId} QUARANTINED (no v2 envelope \u2014 held back, not delivered; ledger-recorded recoverable). A producer path still emits v1.`
11553
+ );
11554
+ continue;
11555
+ }
11515
11556
  bump("v1BroadcastAccepted");
11516
11557
  kept.push(event);
11517
11558
  continue;
@@ -11520,6 +11561,15 @@ function routeV2EventsForDrainer(events, drainer, ctx) {
11520
11561
  try {
11521
11562
  validated = assertPendingMeshCoordinatorEventV2(event);
11522
11563
  } catch (e) {
11564
+ if (enforce) {
11565
+ bump("v2ValidationFailedQuarantined");
11566
+ if (ctx.countMetrics) ledgerRecordQuarantinedEvent(event, "v2_enforce_validation_failed_quarantined");
11567
+ warnV2Once(
11568
+ `${event.meshId}::${event.eventId ?? event.event}::invalid-quarantined`,
11569
+ `v2 ENFORCE: envelope validation failed for ${event.event} on mesh ${event.meshId} \u2014 QUARANTINED (held back, not delivered; ledger-recorded recoverable): ${e?.message || e}`
11570
+ );
11571
+ continue;
11572
+ }
11523
11573
  bump("v2ValidationFailedAccepted");
11524
11574
  warnV2Once(
11525
11575
  `${event.meshId}::${event.eventId ?? event.event}::invalid`,
@@ -12101,7 +12151,15 @@ var init_mesh_events_pending = __esm({
12101
12151
  * coordinatorRunId change orphaned them). */
12102
12152
  v2ReattributedToDrainer: 0,
12103
12153
  /** v1 (unversioned) events passed through as broadcast (rollout baseline). */
12104
- v1BroadcastAccepted: 0
12154
+ v1BroadcastAccepted: 0,
12155
+ /** T6 enforce: v2 events that FAILED validation and were QUARANTINED (held back
12156
+ * from delivery, not dropped). Non-zero here means a producer is still emitting a
12157
+ * malformed envelope after enforce was turned on. */
12158
+ v2ValidationFailedQuarantined: 0,
12159
+ /** T6 enforce: v1 (unversioned) events QUARANTINED because no v2 envelope could be
12160
+ * derived at emit time. Non-zero here means a producer path still emits v1 after
12161
+ * enforce — it should reach 0 once every node is on a v2-stamping build. */
12162
+ v1UnversionedQuarantined: 0
12105
12163
  };
12106
12164
  warnedV2Violations = /* @__PURE__ */ new Set();
12107
12165
  TERMINAL_COMPLETION_EVENTS = /* @__PURE__ */ new Set(["agent:generating_completed", "agent:stopped"]);
@@ -18308,6 +18366,21 @@ function resolveAckedDeathDeadlineMs() {
18308
18366
  function resolveAckedTranscriptFastTrackGraceMs() {
18309
18367
  return resolveTunedReconcileMs("MESH_INFLIGHT_ACKED_TRANSCRIPT_FASTTRACK_GRACE_MS", 4e4, 0, 5 * 6e4);
18310
18368
  }
18369
+ function getMeshV2BackstopCounters() {
18370
+ return { ...meshV2BackstopCounters };
18371
+ }
18372
+ function meshProtocolV2EnforceOn() {
18373
+ const raw = process.env.MESH_PROTOCOL_V2_ENFORCE;
18374
+ if (typeof raw !== "string") return false;
18375
+ const v = raw.trim().toLowerCase();
18376
+ return v === "1" || v === "true" || v === "on" || v === "yes";
18377
+ }
18378
+ function recordBackstopFire(kind, detail) {
18379
+ meshV2BackstopCounters[kind]++;
18380
+ if (meshProtocolV2EnforceOn()) {
18381
+ LOG.warn("MeshReconcileV2", `v2 ENFORCE last-resort backstop fired (${kind}): ${detail}. Under a healthy v2 completion contract this should be 0 \u2014 a worker's real terminal emit was lost/late.`);
18382
+ }
18383
+ }
18311
18384
  function inFlightSynthKey(meshId, taskId) {
18312
18385
  return `${meshId}::${taskId}`;
18313
18386
  }
@@ -19222,6 +19295,7 @@ async function reconcileUnterminatedDirectDispatches(components, mesh, selfIds,
19222
19295
  };
19223
19296
  const synthKey = inFlightSynthKey(mesh.id, taskId);
19224
19297
  const isAcked = dispatch.status === "acked";
19298
+ let backstopKind;
19225
19299
  let payload = null;
19226
19300
  let readFailed = false;
19227
19301
  try {
@@ -19286,6 +19360,7 @@ async function reconcileUnterminatedDirectDispatches(components, mesh, selfIds,
19286
19360
  const idleHeldMs = nowMs - idleSinceMs;
19287
19361
  if (idleHeldMs >= fastTrackGraceMs) {
19288
19362
  fastTrackReady = true;
19363
+ backstopKind = "ackedHoldFastTrackFired";
19289
19364
  LOG.info("MeshReconcile", `Acked-hold transcript fast-track: task ${taskId} on node ${nodeId} (mesh ${mesh.id}) read idle WITH a final assistant message for ${Math.round(idleHeldMs / 1e3)}s continuous (grace ${Math.round(fastTrackGraceMs / 1e3)}s) \u2014 promoting the synth ahead of the ${Math.round(deathDeadlineMs / 1e3)}s death backstop; the worker's real emit was lost/late and a later one no-ops idempotently.`);
19290
19365
  }
19291
19366
  } else if (holdState?.transcriptIdleSinceMs !== void 0) {
@@ -19296,6 +19371,7 @@ async function reconcileUnterminatedDirectDispatches(components, mesh, selfIds,
19296
19371
  continue;
19297
19372
  }
19298
19373
  if (!fastTrackReady) {
19374
+ backstopKind = "ackedHoldDeathDeadlineFired";
19299
19375
  LOG.warn("MeshReconcile", `Acked-hold death deadline reached: task ${taskId} on node ${nodeId} (mesh ${mesh.id}) still idle ${Math.round(sinceAckMs / 1e3)}s after the ack (deadline ${Math.round(deathDeadlineMs / 1e3)}s) \u2014 synthesizing the missing completion as a notification-loss net (a real emit, if it ever lands, no-ops idempotently).`);
19300
19376
  }
19301
19377
  }
@@ -19340,6 +19416,7 @@ async function reconcileUnterminatedDirectDispatches(components, mesh, selfIds,
19340
19416
  source: "daemon_reconcile_transcript_completion"
19341
19417
  });
19342
19418
  if (result.reconciled) {
19419
+ recordBackstopFire(backstopKind ?? "phase4SynthesisFired", `task ${taskId} on node ${nodeId} (mesh ${mesh.id}), kind=${result.kind}`);
19343
19420
  LOG.info("MeshReconcile", `Synthesized missing completion (${result.kind}) for task ${taskId} on node ${nodeId} (mesh ${mesh.id})`);
19344
19421
  }
19345
19422
  } catch (e) {
@@ -19469,7 +19546,7 @@ function setupMeshReconcileLoop(components) {
19469
19546
  }
19470
19547
  };
19471
19548
  }
19472
- var DEFAULT_RECONCILE_INTERVAL_MS, DEFAULT_AUTO_PRUNE_MIN_AGE_MS, DEFAULT_PENDING_HELD_DRAIN_ESCALATE_MS, ACKED_DEATH_CONSECUTIVE_READ_FAILURES, inFlightAckedHoldState, rehydratedHoldMeshes, coordinatorModalParkState, heldEventLedgerRecorded, ASSIGNED_STRANDED_DEADLINE_MS, DELIVERED_NO_TURN_DEADLINE_MS, RECLAIM_UNKNOWN_GRACE_TICKS, deliveredNoTurnUnknownStreak, STRICT_SESSION_MATCH_TTL_MS, unresolvedForwardRejectionCounts, MAX_FORWARD_REJECTIONS;
19549
+ var DEFAULT_RECONCILE_INTERVAL_MS, DEFAULT_AUTO_PRUNE_MIN_AGE_MS, DEFAULT_PENDING_HELD_DRAIN_ESCALATE_MS, ACKED_DEATH_CONSECUTIVE_READ_FAILURES, inFlightAckedHoldState, rehydratedHoldMeshes, meshV2BackstopCounters, coordinatorModalParkState, heldEventLedgerRecorded, ASSIGNED_STRANDED_DEADLINE_MS, DELIVERED_NO_TURN_DEADLINE_MS, RECLAIM_UNKNOWN_GRACE_TICKS, deliveredNoTurnUnknownStreak, STRICT_SESSION_MATCH_TTL_MS, unresolvedForwardRejectionCounts, MAX_FORWARD_REJECTIONS;
19473
19550
  var init_mesh_reconcile_loop = __esm({
19474
19551
  "src/mesh/mesh-reconcile-loop.ts"() {
19475
19552
  "use strict";
@@ -19497,6 +19574,14 @@ var init_mesh_reconcile_loop = __esm({
19497
19574
  ACKED_DEATH_CONSECUTIVE_READ_FAILURES = 3;
19498
19575
  inFlightAckedHoldState = /* @__PURE__ */ new Map();
19499
19576
  rehydratedHoldMeshes = /* @__PURE__ */ new Set();
19577
+ meshV2BackstopCounters = {
19578
+ /** PHASE-4 transcript synthesis actually reconciled a missing completion. */
19579
+ phase4SynthesisFired: 0,
19580
+ /** Acked-hold transcript fast-track promoted a synth ahead of the death deadline. */
19581
+ ackedHoldFastTrackFired: 0,
19582
+ /** Acked-hold death-deadline backstop released a held synth (the 8-min net). */
19583
+ ackedHoldDeathDeadlineFired: 0
19584
+ };
19500
19585
  coordinatorModalParkState = /* @__PURE__ */ new Map();
19501
19586
  heldEventLedgerRecorded = /* @__PURE__ */ new Set();
19502
19587
  ASSIGNED_STRANDED_DEADLINE_MS = 5 * 6e4;
@@ -19516,9 +19601,12 @@ __export(mesh_events_exports, {
19516
19601
  __resetMeshWorkspaceCacheForTests: () => __resetMeshWorkspaceCacheForTests,
19517
19602
  clearPendingMeshCoordinatorEvents: () => clearPendingMeshCoordinatorEvents,
19518
19603
  drainPendingMeshCoordinatorEvents: () => drainPendingMeshCoordinatorEvents,
19604
+ getMeshV2BackstopCounters: () => getMeshV2BackstopCounters,
19605
+ getMeshV2DrainCounters: () => getMeshV2DrainCounters,
19519
19606
  getPendingMeshCoordinatorEvents: () => getPendingMeshCoordinatorEvents,
19520
19607
  handleMeshForwardEvent: () => handleMeshForwardEvent,
19521
19608
  isMeshCoordinatorEvent: () => isMeshCoordinatorEvent,
19609
+ isMeshProtocolV2EnforceEnabled: () => isMeshProtocolV2EnforceEnabled,
19522
19610
  isSessionActivelyGenerating: () => isSessionActivelyGenerating,
19523
19611
  queuePendingMeshCoordinatorEvent: () => queuePendingMeshCoordinatorEvent,
19524
19612
  readV2EnvelopeFromWire: () => readV2EnvelopeFromWire,
@@ -40191,15 +40279,37 @@ function executeSqlite(src, input) {
40191
40279
  }
40192
40280
  try {
40193
40281
  const requested = input.providerSessionId || "";
40194
- const resolveMessagesFor = (sessionId2) => {
40195
- if (!sessionId2) return null;
40196
- let rows;
40197
- try {
40198
- rows = db.prepare(src.message_query).all(sessionId2);
40199
- } catch {
40200
- 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
+ }
40201
40294
  }
40202
- 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;
40203
40313
  };
40204
40314
  const resolveNewestSessionId = () => {
40205
40315
  let sessionRow;
@@ -40256,6 +40366,20 @@ function executeSqlite(src, input) {
40256
40366
  }
40257
40367
  }
40258
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
+ }
40259
40383
  function expandPath2(template, input, opts) {
40260
40384
  if (!template) return null;
40261
40385
  let out = template;
@@ -42880,6 +43004,19 @@ var CliProviderInstance = class _CliProviderInstance {
42880
43004
  }
42881
43005
  return probe;
42882
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
+ }
42883
43020
  readExternalCompletionMessages() {
42884
43021
  const adapterOwnsMessagesElsewhere = this.adapter?.chatMessagesOwnedExternally === true;
42885
43022
  if (!adapterOwnsMessagesElsewhere) return null;
@@ -42900,6 +43037,7 @@ var CliProviderInstance = class _CliProviderInstance {
42900
43037
  historyBehavior: this.provider.historyBehavior,
42901
43038
  scripts: this.provider.scripts,
42902
43039
  sessionStartedAtMs: this.startedAt,
43040
+ envOverrides: this.spawnedEnvOverrides(),
42903
43041
  forceRefresh: true
42904
43042
  });
42905
43043
  if (restoredHistory.source !== "provider-native") {
@@ -43425,10 +43563,10 @@ var CliProviderInstance = class _CliProviderInstance {
43425
43563
  if (buttonIndex < 0 || !hasReliableConsentAnchor) {
43426
43564
  return autoApproveActive;
43427
43565
  }
43566
+ const affirmativeAnchor = normalizeApprovalLabel(buttonLabel);
43428
43567
  const modalSignature = [
43429
43568
  typeof modal?.message === "string" ? modal.message.trim() : "",
43430
- buttons.join("|"),
43431
- buttonIndex
43569
+ affirmativeAnchor
43432
43570
  ].join("::");
43433
43571
  const approvalEntrySeq = typeof adapterStatus?.approvalEntrySeq === "number" ? adapterStatus.approvalEntrySeq : 0;
43434
43572
  const busySignature = `${approvalEntrySeq}::${modalSignature}`;
@@ -48477,14 +48615,44 @@ function openDb() {
48477
48615
  return null;
48478
48616
  }
48479
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
+ }
48480
48645
  function loadMessagesForSession(db, sessionId) {
48646
+ const clusterIds = resolveClusterSessionIds(db, sessionId);
48647
+ if (clusterIds.length === 0) return [];
48648
+ const placeholders = clusterIds.map(() => "?").join(", ");
48481
48649
  const rows = db.prepare(
48482
48650
  `SELECT id, role, COALESCE(NULLIF(content, ''), tool_calls) AS content, timestamp
48483
48651
  FROM messages
48484
- WHERE session_id = ?
48652
+ WHERE session_id IN (${placeholders})
48485
48653
  AND ((content IS NOT NULL AND content != '') OR (tool_calls IS NOT NULL AND tool_calls != ''))
48486
48654
  ORDER BY timestamp ASC, id ASC`
48487
- ).all(sessionId);
48655
+ ).all(...clusterIds);
48488
48656
  const out = [];
48489
48657
  for (const r of rows) {
48490
48658
  const role = normalizeHermesRole(r.role);
@@ -53040,7 +53208,12 @@ var meshEventsHandlers = {
53040
53208
  return { success: true, events: [], heldForBusyLocalCoordinator: true, hasLiveCliCoordinator };
53041
53209
  }
53042
53210
  const events = drainPendingMeshCoordinatorEvents(meshId || void 0, coordinatorDaemonId);
53043
- return { success: true, events, hasLiveCliCoordinator, ...selfCoordinatorInboxRead ? { surfacedForSelfCoordinator: true } : {} };
53211
+ const meshProtocolV2Counters = {
53212
+ enforce: isMeshProtocolV2EnforceEnabled(),
53213
+ drain: { ...getMeshV2DrainCounters() },
53214
+ backstop: { ...getMeshV2BackstopCounters() }
53215
+ };
53216
+ return { success: true, events, hasLiveCliCoordinator, meshProtocolV2Counters, ...selfCoordinatorInboxRead ? { surfacedForSelfCoordinator: true } : {} };
53044
53217
  },
53045
53218
  interactive_prompt_response: async (ctx, args) => {
53046
53219
  const sessionId = typeof args?.targetSessionId === "string" && args.targetSessionId.trim() ? args.targetSessionId.trim() : typeof args?.sessionId === "string" && args.sessionId.trim() ? args.sessionId.trim() : "";
@@ -54066,6 +54239,11 @@ var meshStatusHandlers = {
54066
54239
  const callerCoordinatorDaemonId = typeof args?.coordinatorDaemonId === "string" && args.coordinatorDaemonId.trim() ? args.coordinatorDaemonId.trim() : ctx.deps.statusInstanceId || void 0;
54067
54240
  const pendingCoordinatorEvents = getPendingMeshCoordinatorEvents(meshId, callerCoordinatorDaemonId);
54068
54241
  const unroutableDeliveries = getRecentUnroutableDeliveries();
54242
+ const meshProtocolV2Counters = {
54243
+ enforce: isMeshProtocolV2EnforceEnabled(),
54244
+ drain: { ...getMeshV2DrainCounters() },
54245
+ backstop: { ...getMeshV2BackstopCounters() }
54246
+ };
54069
54247
  const previewFreshness = (() => {
54070
54248
  const localRepoRoot = nodeStatuses.map((node) => readStringValue(node?.git?.repoRoot, node?.repoRoot, node?.workspace)).find((candidate) => !!candidate && fs27.existsSync(candidate));
54071
54249
  return localRepoRoot ? buildPreviewFreshness(localRepoRoot) : void 0;
@@ -54155,6 +54333,7 @@ var meshStatusHandlers = {
54155
54333
  ...historicalSessions ? { historicalSessions } : {},
54156
54334
  ...pendingCoordinatorEvents.length > 0 ? { pendingCoordinatorEvents } : {},
54157
54335
  ...unroutableDeliveries.length > 0 ? { unroutableDeliveries } : {},
54336
+ meshProtocolV2Counters,
54158
54337
  activeRefineJobs: Array.from(ctx.runningRefineJobs.values()).filter((job) => job.meshId === meshId).map((job) => ({
54159
54338
  jobId: job.jobId,
54160
54339
  nodeId: job.targetNodeId,
@@ -54164,12 +54343,13 @@ var meshStatusHandlers = {
54164
54343
  targetCoordinatorDaemonId: job.targetCoordinatorDaemonId
54165
54344
  }))
54166
54345
  };
54167
- const { pendingCoordinatorEvents: _pendingCoordinatorEvents, unroutableDeliveries: _unroutableDeliveries, ...cacheableStatusResult } = statusResult;
54346
+ const { pendingCoordinatorEvents: _pendingCoordinatorEvents, unroutableDeliveries: _unroutableDeliveries, meshProtocolV2Counters: _meshProtocolV2Counters, ...cacheableStatusResult } = statusResult;
54168
54347
  const rememberedStatus = verboseMissions ? cacheableStatusResult : ctx.rememberAggregateMeshStatus(meshId, cacheableStatusResult, refreshReason);
54169
54348
  const returnedStatus = {
54170
54349
  ...rememberedStatus,
54171
54350
  ...pendingCoordinatorEvents.length > 0 ? { pendingCoordinatorEvents } : {},
54172
- ...unroutableDeliveries.length > 0 ? { unroutableDeliveries } : {}
54351
+ ...unroutableDeliveries.length > 0 ? { unroutableDeliveries } : {},
54352
+ meshProtocolV2Counters
54173
54353
  };
54174
54354
  logRepoMeshStatusDebug("return_live", {
54175
54355
  meshId,
@@ -54412,7 +54592,6 @@ cleanOldFiles();
54412
54592
  // src/commands/router.ts
54413
54593
  init_debug_trace();
54414
54594
  init_mesh_host_ownership();
54415
- init_mesh_work_queue();
54416
54595
  import * as fs33 from "fs";
54417
54596
 
54418
54597
  // src/mesh/mesh-node-identity.ts
@@ -58806,6 +58985,177 @@ async function cleanupMeshSessions(self, args) {
58806
58985
  };
58807
58986
  }
58808
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
+
58809
59159
  // src/mesh/mesh-coordinator-config.ts
58810
59160
  init_logger();
58811
59161
  import * as yaml5 from "js-yaml";
@@ -58974,7 +59324,8 @@ var DaemonCommandRouter = class {
58974
59324
  * on disk) clears the tombstone and merges normally, preserving clone
58975
59325
  * worktree visibility and legitimate node re-creation. */
58976
59326
  removedInlineMeshNodeIds = /* @__PURE__ */ new Map();
58977
- /** 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`. */
58978
59329
  aggregateMeshStatusCache = /* @__PURE__ */ new Map();
58979
59330
  /** Shared per-peer git_status probe dedup + recently-probed reuse gate.
58980
59331
  * Spans separate mesh_status/get_mesh calls so the dashboard auto-retry
@@ -58996,135 +59347,19 @@ var DaemonCommandRouter = class {
58996
59347
  constructor(deps) {
58997
59348
  this.deps = deps;
58998
59349
  }
58999
- cloneJsonValue(value) {
59000
- if (typeof structuredClone === "function") return structuredClone(value);
59001
- return JSON.parse(JSON.stringify(value));
59002
- }
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.
59003
59355
  hydrateCachedAggregateMeshStatusFromInline(snapshot, mesh, options) {
59004
- if (!mesh || typeof mesh !== "object" || !Array.isArray(mesh.nodes) || !Array.isArray(snapshot?.nodes)) return snapshot;
59005
- const inlineNodesById = /* @__PURE__ */ new Map();
59006
- for (const node of mesh.nodes) {
59007
- const nodeId = readInlineMeshNodeId(node);
59008
- if (nodeId) inlineNodesById.set(nodeId, node);
59009
- }
59010
- if (!inlineNodesById.size) return snapshot;
59011
- let changed = false;
59012
- const unavailableNodeIds = /* @__PURE__ */ new Set();
59013
- const sourceOfTruth = readObjectRecord(snapshot.sourceOfTruth);
59014
- const directPeerTruth = readObjectRecord(sourceOfTruth.directPeerTruth);
59015
- const deadNodeIds = /* @__PURE__ */ new Set();
59016
- for (const node of mesh.nodes) {
59017
- if (!isDeadLocalWorktreeNode(node)) continue;
59018
- const deadId = readInlineMeshNodeId(node);
59019
- if (deadId) deadNodeIds.add(deadId);
59020
- }
59021
- let droppedDeadUnavailable = false;
59022
- for (const entry of Array.isArray(directPeerTruth.unavailableNodeIds) ? directPeerTruth.unavailableNodeIds : []) {
59023
- const nodeId = readStringValue(entry);
59024
- if (!nodeId) continue;
59025
- if (deadNodeIds.has(nodeId)) {
59026
- droppedDeadUnavailable = true;
59027
- continue;
59028
- }
59029
- unavailableNodeIds.add(nodeId);
59030
- }
59031
- if (droppedDeadUnavailable) changed = true;
59032
- const nodes = snapshot.nodes.map((statusNode) => {
59033
- const nodeId = normalizeMeshNodeId(statusNode);
59034
- const inlineNode = nodeId ? inlineNodesById.get(nodeId) : void 0;
59035
- if (!inlineNode) return statusNode;
59036
- const liveGit = buildInlineMeshTransitGitStatus(inlineNode);
59037
- if (!liveGit) return statusNode;
59038
- const nextStatus = { ...statusNode };
59039
- nextStatus.git = liveGit;
59040
- nextStatus.health = deriveMeshNodeHealthFromGit(liveGit);
59041
- applyInlineMeshBranchConvergence(mesh, inlineNode, nextStatus);
59042
- nextStatus.launchReady = readBooleanValue(nextStatus.launchReady) ?? true;
59043
- const connection = readObjectRecord(nextStatus.connection);
59044
- const connectionState = readStringValue(connection.state);
59045
- const connectionReported = readBooleanValue(connection.reported) ?? false;
59046
- if (!connectionReported || connectionState === "unknown") {
59047
- nextStatus.connection = buildLivePeerGitConnection(connection);
59048
- }
59049
- delete nextStatus.gitProbePending;
59050
- const error = readStringValue(nextStatus.error);
59051
- if (error && /pending_git|git probe|live peer git snapshot|no peer git snapshot/i.test(error)) delete nextStatus.error;
59052
- if (!readStringValue(nextStatus.machineStatus)) nextStatus.machineStatus = "online";
59053
- if (nodeId) unavailableNodeIds.delete(nodeId);
59054
- changed = true;
59055
- return nextStatus;
59056
- });
59057
- const aggregateDirectTruthSatisfied = sourceOfTruth.coordinatorOwnsLiveTruth === true || directPeerTruth.satisfied === true;
59058
- if (!changed && !(options?.requireDirectPeerTruth && unavailableNodeIds.size > 0 && !aggregateDirectTruthSatisfied)) return snapshot;
59059
- const nextSourceOfTruth = {
59060
- ...sourceOfTruth,
59061
- ...Object.keys(directPeerTruth).length ? {
59062
- directPeerTruth: {
59063
- ...directPeerTruth,
59064
- satisfied: options?.requireDirectPeerTruth === true ? aggregateDirectTruthSatisfied || unavailableNodeIds.size === 0 : directPeerTruth.satisfied,
59065
- unavailableNodeIds: [...unavailableNodeIds]
59066
- },
59067
- ...options?.requireDirectPeerTruth === true ? {
59068
- coordinatorOwnsLiveTruth: aggregateDirectTruthSatisfied || unavailableNodeIds.size === 0,
59069
- currentStatus: aggregateDirectTruthSatisfied || unavailableNodeIds.size === 0 ? "live_git_and_session_probes" : "direct_peer_truth_unavailable"
59070
- } : {}
59071
- } : {}
59072
- };
59073
- return {
59074
- ...snapshot,
59075
- ...options?.requireDirectPeerTruth === true && unavailableNodeIds.size > 0 && !aggregateDirectTruthSatisfied ? {
59076
- success: false,
59077
- code: "mesh_direct_peer_truth_unavailable",
59078
- error: "Selected coordinator could not confirm direct mesh truth for every remote node yet."
59079
- } : {},
59080
- sourceOfTruth: nextSourceOfTruth,
59081
- branchConvergenceSummary: summarizeInlineMeshBranchConvergence(nodes),
59082
- nodes
59083
- };
59356
+ return hydrateCachedAggregateMeshStatusFromInline(this, snapshot, mesh, options);
59084
59357
  }
59085
59358
  getCachedAggregateMeshStatus(meshId, mesh, options) {
59086
- const cached3 = this.aggregateMeshStatusCache.get(meshId);
59087
- if (!cached3?.snapshot || cached3.snapshot.success !== true || !Array.isArray(cached3.snapshot.nodes)) return null;
59088
- if (cached3.queueRevision !== getMeshQueueRevision(meshId)) return null;
59089
- let snapshot = this.cloneJsonValue(cached3.snapshot);
59090
- snapshot = this.hydrateCachedAggregateMeshStatusFromInline(snapshot, mesh, options);
59091
- if (!options?.allowStalePending && shouldRefreshStalePendingAggregate(snapshot, options)) return null;
59092
- const ageMs = Math.max(0, Date.now() - cached3.builtAt);
59093
- const sourceOfTruth = snapshot.sourceOfTruth && typeof snapshot.sourceOfTruth === "object" ? snapshot.sourceOfTruth : {};
59094
- snapshot.sourceOfTruth = {
59095
- ...sourceOfTruth,
59096
- aggregateSnapshot: {
59097
- ...sourceOfTruth.aggregateSnapshot && typeof sourceOfTruth.aggregateSnapshot === "object" ? sourceOfTruth.aggregateSnapshot : {},
59098
- owner: "coordinator_daemon_memory",
59099
- cached: true,
59100
- source: "memory",
59101
- refreshReason: "memory_cache_hit",
59102
- ageMs,
59103
- cachedAt: new Date(cached3.builtAt).toISOString(),
59104
- returnedAt: (/* @__PURE__ */ new Date()).toISOString()
59105
- }
59106
- };
59107
- return snapshot;
59359
+ return getCachedAggregateMeshStatus(this, meshId, mesh, options);
59108
59360
  }
59109
59361
  rememberAggregateMeshStatus(meshId, snapshot, refreshReason) {
59110
- if (!snapshot || typeof snapshot !== "object" || snapshot.success !== true || !Array.isArray(snapshot.nodes)) return snapshot;
59111
- const builtAt = Date.now();
59112
- const next = this.cloneJsonValue(snapshot);
59113
- const sourceOfTruth = next.sourceOfTruth && typeof next.sourceOfTruth === "object" ? next.sourceOfTruth : {};
59114
- next.sourceOfTruth = {
59115
- ...sourceOfTruth,
59116
- aggregateSnapshot: {
59117
- owner: "coordinator_daemon_memory",
59118
- cached: false,
59119
- source: "live_refresh",
59120
- refreshReason,
59121
- ageMs: 0,
59122
- cachedAt: new Date(builtAt).toISOString(),
59123
- returnedAt: new Date(builtAt).toISOString()
59124
- }
59125
- };
59126
- this.aggregateMeshStatusCache.set(meshId, { builtAt, snapshot: this.cloneJsonValue(next), queueRevision: getMeshQueueRevision(meshId) });
59127
- return next;
59362
+ return rememberAggregateMeshStatus(this, meshId, snapshot, refreshReason);
59128
59363
  }
59129
59364
  getCachedInlineMeshNodes() {
59130
59365
  const nodes = [];
@@ -59135,82 +59370,13 @@ var DaemonCommandRouter = class {
59135
59370
  }
59136
59371
  return nodes;
59137
59372
  }
59138
- /**
59139
- * Resolve the REMOTE worker daemonId that owns a given session, when the session
59140
- * belongs to a mesh node hosted on a DIFFERENT daemon than this coordinator.
59141
- *
59142
- * The coordinator does not host remote-worker session instances in its own
59143
- * instanceManager/sessionRegistry — only their cached mesh-node metadata. A
59144
- * dashboard-issued session-scoped command (invoke_provider_script / resolve_action /
59145
- * set_mode / …) lands on the coordinator with a targetSessionId the coordinator can't
59146
- * find locally, and without forwarding it dies as "Live session not found". send_chat
59147
- * happens to survive (its target resolves to the worker by another route), but the
59148
- * controlbar commands do not — so the controlbar buttons appear to do nothing.
59149
- *
59150
- * Mirror the existing node-level remote-forward pattern (fast_forward_mesh_node etc.):
59151
- * scan the candidate mesh nodes for the one hosting the targetSessionId, and return its
59152
- * daemonId when that daemonId is a remote daemon (i.e. not this coordinator's own
59153
- * statusInstanceId). Returns undefined for a locally-hosted session (no forward — execute
59154
- * locally as before) or when ownership can't be resolved.
59155
- *
59156
- * The candidate set spans BOTH the cached inline-mesh nodes and the live aggregate
59157
- * mesh-status snapshots. The inline cache reliably carries only each node's single primary
59158
- * session (cachedStatus.activeSession), so a worker hosting more than one session exposes its
59159
- * non-primary sessions only on the aggregate snapshot nodes (status.activeSessions /
59160
- * activeSessionDetails, built from live session records). collectMeshNodeHostedSessionIds does
59161
- * the wider plural-shape scan so a controlbar/modal command targeting a non-primary remote
59162
- * session still resolves its owner — the singular readCachedInlineMeshActiveSessions semantics
59163
- * other consumers depend on stay untouched.
59164
- *
59165
- * CANCEL-STOP-RELAY: the session-id cache scan above only matches when the coordinator's
59166
- * cached status snapshot already lists the worker's session id in a recognized active-sessions
59167
- * shape. A worktree-clone worker session whose id form/timing differs from the cached snapshot
59168
- * (or is simply not yet reflected) misses the scan, so a stop that carries the authoritative
59169
- * owning nodeId (mesh_queue_cancel knows assignedNodeId) used to silently fail to forward.
59170
- * `ownerNodeIdHint` adds a deterministic fallback: when the session-id scan misses, resolve the
59171
- * owner daemonId by matching the node by id (meshNodeIdMatches — same form-tolerant compare the
59172
- * rest of the router uses, no new raw compare). The same self-loopback guard applies to both
59173
- * paths, so a coordinator-hosted node is still never force-forwarded to a remote form of itself.
59174
- */
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.
59175
59378
  resolveRemoteMeshSessionOwnerDaemonId(sessionId, ownerNodeIdHint) {
59176
- const trimmed = typeof sessionId === "string" ? sessionId.trim() : "";
59177
- const nodeHint = typeof ownerNodeIdHint === "string" ? ownerNodeIdHint.trim() : "";
59178
- if (!trimmed && !nodeHint) return void 0;
59179
- const selfDaemonId = this.deps.statusInstanceId;
59180
- const candidates = this.collectMeshSessionOwnerCandidateNodes();
59181
- if (trimmed) {
59182
- for (const node of candidates) {
59183
- if (!collectMeshNodeHostedSessionIds(node).has(trimmed)) continue;
59184
- const nodeDaemonId = readMeshNodeDaemonId(readObjectRecord(node));
59185
- if (!nodeDaemonId) continue;
59186
- if (selfDaemonId && daemonIdsEquivalent(nodeDaemonId, selfDaemonId)) return void 0;
59187
- return nodeDaemonId;
59188
- }
59189
- }
59190
- if (nodeHint) {
59191
- for (const node of candidates) {
59192
- if (!meshNodeIdMatches(node, nodeHint)) continue;
59193
- const nodeDaemonId = readMeshNodeDaemonId(readObjectRecord(node));
59194
- if (!nodeDaemonId) continue;
59195
- if (selfDaemonId && daemonIdsEquivalent(nodeDaemonId, selfDaemonId)) return void 0;
59196
- return nodeDaemonId;
59197
- }
59198
- }
59199
- return void 0;
59200
- }
59201
- /**
59202
- * Candidate nodes for remote-session owner resolution: the cached inline-mesh nodes (which
59203
- * carry each node's primary session) plus the nodes from every cached aggregate mesh-status
59204
- * snapshot (which carry each node's full live session list). getCachedInlineMeshNodes()
59205
- * returns a fresh array, so appending the aggregate nodes never mutates cached state.
59206
- */
59207
- collectMeshSessionOwnerCandidateNodes() {
59208
- const nodes = this.getCachedInlineMeshNodes();
59209
- for (const cached3 of this.aggregateMeshStatusCache.values()) {
59210
- const snapshotNodes = cached3?.snapshot?.nodes;
59211
- if (Array.isArray(snapshotNodes)) nodes.push(...snapshotNodes);
59212
- }
59213
- return nodes;
59379
+ return resolveRemoteMeshSessionOwnerDaemonId(this, sessionId, ownerNodeIdHint);
59214
59380
  }
59215
59381
  getCachedInlineMesh(meshId, inlineMesh) {
59216
59382
  if (inlineMesh && typeof inlineMesh === "object") {