@adhdev/daemon-core 0.9.82-rc.381 → 0.9.82-rc.383

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.
@@ -156,8 +156,18 @@ export declare class DaemonCommandRouter {
156
156
  * the wider plural-shape scan so a controlbar/modal command targeting a non-primary remote
157
157
  * session still resolves its owner — the singular readCachedInlineMeshActiveSessions semantics
158
158
  * other consumers depend on stay untouched.
159
+ *
160
+ * CANCEL-STOP-RELAY: the session-id cache scan above only matches when the coordinator's
161
+ * cached status snapshot already lists the worker's session id in a recognized active-sessions
162
+ * shape. A worktree-clone worker session whose id form/timing differs from the cached snapshot
163
+ * (or is simply not yet reflected) misses the scan, so a stop that carries the authoritative
164
+ * owning nodeId (mesh_queue_cancel knows assignedNodeId) used to silently fail to forward.
165
+ * `ownerNodeIdHint` adds a deterministic fallback: when the session-id scan misses, resolve the
166
+ * owner daemonId by matching the node by id (meshNodeIdMatches — same form-tolerant compare the
167
+ * rest of the router uses, no new raw compare). The same self-loopback guard applies to both
168
+ * paths, so a coordinator-hosted node is still never force-forwarded to a remote form of itself.
159
169
  */
160
- resolveRemoteMeshSessionOwnerDaemonId(sessionId: string): string | undefined;
170
+ resolveRemoteMeshSessionOwnerDaemonId(sessionId: string, ownerNodeIdHint?: string): string | undefined;
161
171
  /**
162
172
  * Candidate nodes for remote-session owner resolution: the cached inline-mesh nodes (which
163
173
  * carry each node's primary session) plus the nodes from every cached aggregate mesh-status
package/dist/index.js CHANGED
@@ -383,10 +383,10 @@ function readInjected(value) {
383
383
  }
384
384
  function getDaemonBuildInfo() {
385
385
  if (cached) return cached;
386
- const commit = readInjected(true ? "18afac213951f79c502feb6b25b7399fe4d709b3" : void 0) ?? "unknown";
387
- const commitShort = readInjected(true ? "18afac21" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
388
- const version = readInjected(true ? "0.9.82-rc.381" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
389
- const builtAt = readInjected(true ? "2026-06-25T11:44:40.598Z" : void 0);
386
+ const commit = readInjected(true ? "6cca365bcea9757dd350c6bac460ca5a169a9280" : void 0) ?? "unknown";
387
+ const commitShort = readInjected(true ? "6cca365b" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
388
+ const version = readInjected(true ? "0.9.82-rc.383" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
389
+ const builtAt = readInjected(true ? "2026-06-25T15:14:41.579Z" : void 0);
390
390
  cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
391
391
  return cached;
392
392
  }
@@ -8581,6 +8581,109 @@ var init_mesh_active_work = __esm({
8581
8581
  }
8582
8582
  });
8583
8583
 
8584
+ // src/mesh/mesh-scheduling-runtime.ts
8585
+ var mesh_scheduling_runtime_exports = {};
8586
+ __export(mesh_scheduling_runtime_exports, {
8587
+ buildMeshSchedulingRuntime: () => buildMeshSchedulingRuntime
8588
+ });
8589
+ function isReadonly(task) {
8590
+ return task.taskMode === "live_debug_readonly";
8591
+ }
8592
+ function isAssigned(task) {
8593
+ return task.status === "assigned";
8594
+ }
8595
+ function buildMeshSchedulingRuntime(mesh, queue) {
8596
+ const strategy = normalizeMeshSchedulingStrategy(mesh?.policy?.schedulingStrategy);
8597
+ const maxParallelTasks = resolveMaxParallelTasks(mesh?.policy?.maxParallelTasks);
8598
+ const maxReadonlyParallelTasks = Math.max(2, maxParallelTasks * 2);
8599
+ const assignedTasks = (Array.isArray(queue) ? queue : []).filter(isAssigned);
8600
+ const activeWriteAssigned = assignedTasks.filter((t) => !isReadonly(t)).length;
8601
+ const activeReadonlyAssigned = assignedTasks.filter(isReadonly).length;
8602
+ const globalWriteCapReached = activeWriteAssigned >= maxParallelTasks;
8603
+ const globalReadonlyCapReached = activeReadonlyAssigned >= maxReadonlyParallelTasks;
8604
+ const writeAssignedByNode = /* @__PURE__ */ new Map();
8605
+ const assignedByNode = /* @__PURE__ */ new Map();
8606
+ const providerCountByNode = /* @__PURE__ */ new Map();
8607
+ for (const task of assignedTasks) {
8608
+ const nodeId = typeof task.assignedNodeId === "string" ? task.assignedNodeId.trim() : "";
8609
+ if (!nodeId) continue;
8610
+ assignedByNode.set(nodeId, (assignedByNode.get(nodeId) ?? 0) + 1);
8611
+ if (!isReadonly(task)) {
8612
+ writeAssignedByNode.set(nodeId, (writeAssignedByNode.get(nodeId) ?? 0) + 1);
8613
+ }
8614
+ const provider = typeof task.assignedProviderType === "string" ? task.assignedProviderType : "";
8615
+ if (provider) {
8616
+ let byProvider = providerCountByNode.get(nodeId);
8617
+ if (!byProvider) {
8618
+ byProvider = /* @__PURE__ */ new Map();
8619
+ providerCountByNode.set(nodeId, byProvider);
8620
+ }
8621
+ byProvider.set(provider, (byProvider.get(provider) ?? 0) + 1);
8622
+ }
8623
+ }
8624
+ const nodes = [];
8625
+ for (const rawNode of Array.isArray(mesh?.nodes) ? mesh.nodes : []) {
8626
+ const nodeId = normalizeMeshNodeId(rawNode);
8627
+ if (!nodeId) continue;
8628
+ const policy = rawNode?.policy || void 0;
8629
+ const load4 = assignedByNode.get(nodeId) ?? 0;
8630
+ const schedulingPriority = resolveNodeSchedulingPriority(policy);
8631
+ const capReasons = [];
8632
+ if (globalWriteCapReached) capReasons.push("global_max_parallel_tasks_reached");
8633
+ if ((writeAssignedByNode.get(nodeId) ?? 0) > 0) capReasons.push("node_has_active_assignment");
8634
+ let providerRoles;
8635
+ const declaredRoles = Array.isArray(policy?.providerRoles) ? policy.providerRoles : [];
8636
+ if (declaredRoles.length) {
8637
+ const byProvider = providerCountByNode.get(nodeId);
8638
+ providerRoles = [];
8639
+ for (const role of declaredRoles) {
8640
+ if (!role || typeof role !== "object") continue;
8641
+ const providerType = typeof role.providerType === "string" ? role.providerType.trim() : "";
8642
+ if (!providerType) continue;
8643
+ const maxParallel = resolveProviderMaxParallel(policy, providerType);
8644
+ const activeAssigned = byProvider?.get(providerType) ?? 0;
8645
+ const capReached = maxParallel !== void 0 && activeAssigned >= maxParallel;
8646
+ providerRoles.push({
8647
+ providerType,
8648
+ ...maxParallel !== void 0 ? { maxParallel } : {},
8649
+ activeAssigned,
8650
+ capReached
8651
+ });
8652
+ if (capReached) capReasons.push(`max_provider_parallel_reached:${providerType}`);
8653
+ }
8654
+ if (!providerRoles.length) providerRoles = void 0;
8655
+ }
8656
+ const maxConcurrentSessions = Number(policy?.maxConcurrentSessions);
8657
+ const hasSessionCap = Number.isFinite(maxConcurrentSessions) && maxConcurrentSessions >= 0;
8658
+ nodes.push({
8659
+ nodeId,
8660
+ load: load4,
8661
+ schedulingPriority,
8662
+ ...hasSessionCap ? { maxConcurrentSessions: Math.floor(maxConcurrentSessions) } : {},
8663
+ ...providerRoles ? { providerRoles } : {},
8664
+ capReached: capReasons.length > 0,
8665
+ capReasons
8666
+ });
8667
+ }
8668
+ return {
8669
+ strategy,
8670
+ maxParallelTasks,
8671
+ maxReadonlyParallelTasks,
8672
+ activeWriteAssigned,
8673
+ activeReadonlyAssigned,
8674
+ globalWriteCapReached,
8675
+ globalReadonlyCapReached,
8676
+ nodes
8677
+ };
8678
+ }
8679
+ var init_mesh_scheduling_runtime = __esm({
8680
+ "src/mesh/mesh-scheduling-runtime.ts"() {
8681
+ "use strict";
8682
+ init_repo_mesh_types();
8683
+ init_dist();
8684
+ }
8685
+ });
8686
+
8584
8687
  // src/mesh/mesh-events-utils.ts
8585
8688
  function readNonEmptyString2(value) {
8586
8689
  return typeof value === "string" && value.trim() ? value.trim() : "";
@@ -13810,6 +13913,20 @@ function recoverMeshIdByNodeId(nodeId) {
13810
13913
  }
13811
13914
  return "";
13812
13915
  }
13916
+ function recoverMeshIdByCoordinatorAndNode(coordinatorDaemonId, nodeId) {
13917
+ if (!coordinatorDaemonId) return "";
13918
+ const hosted = listMeshes().filter((mesh) => {
13919
+ const host = resolveMeshHostStatus(mesh);
13920
+ return host.role === "host" && (!host.hostDaemonId || daemonIdsEquivalent(host.hostDaemonId, coordinatorDaemonId));
13921
+ });
13922
+ if (hosted.length === 0) return "";
13923
+ if (nodeId) {
13924
+ const byNode = hosted.find((mesh) => Array.isArray(mesh.nodes) && mesh.nodes.some((n) => meshNodeIdMatches(n, nodeId)));
13925
+ if (byNode) return readNonEmptyString2(byNode.id);
13926
+ return "";
13927
+ }
13928
+ return hosted.length === 1 ? readNonEmptyString2(hosted[0].id) : "";
13929
+ }
13813
13930
  function resolveForwardEventMeshId(components, payload) {
13814
13931
  const direct = readNonEmptyString2(payload.meshId);
13815
13932
  if (direct) return direct;
@@ -14556,7 +14673,10 @@ function handleMeshForwardEvent(components, payload) {
14556
14673
  }
14557
14674
  const nodeId = readNonEmptyString2(payload.nodeId);
14558
14675
  const workspace = readNonEmptyString2(payload.workspace);
14559
- const meshId = readNonEmptyString2(payload.meshId) || (workspace ? readNonEmptyString2(getCachedMeshByWorkspace(workspace)?.id) : "") || recoverMeshIdByNodeId(nodeId);
14676
+ const meshId = readNonEmptyString2(payload.meshId) || (workspace ? readNonEmptyString2(getCachedMeshByWorkspace(workspace)?.id) : "") || recoverMeshIdByNodeId(nodeId) || recoverMeshIdByCoordinatorAndNode(
14677
+ readNonEmptyString2(payload.meshCoordinatorDaemonId) || readNonEmptyString2(payload.coordinatorDaemonId),
14678
+ nodeId
14679
+ );
14560
14680
  if (!meshId) {
14561
14681
  traceMeshEventDrop("meshId_required", {
14562
14682
  taskId: payload.taskId,
@@ -14611,7 +14731,12 @@ function forwardUnresolvedDelegateEvent(components, routing, event) {
14611
14731
  ...event,
14612
14732
  event: eventName,
14613
14733
  nodeId: readNonEmptyString2(routing.nodeId) || readNonEmptyString2(event.meshNodeId) || void 0,
14614
- workspace: readNonEmptyString2(routing.workspace) || readNonEmptyString2(event.workspace) || void 0
14734
+ workspace: readNonEmptyString2(routing.workspace) || readNonEmptyString2(event.workspace) || void 0,
14735
+ // Fix B: carry the resolved coordinator anchor so the coordinator's receive-side
14736
+ // recovery (recoverMeshIdByCoordinatorAndNode) can match this forward to one of the
14737
+ // meshes it hosts when workspace + nodeId both miss. routing.coordinatorDaemonId is
14738
+ // the same anchor this forward is addressed to (coordinatorDaemonId below).
14739
+ meshCoordinatorDaemonId: coordinatorDaemonId
14615
14740
  };
14616
14741
  const resolvedMeshId = resolveForwardEventMeshId(components, payload);
14617
14742
  if (resolvedMeshId) payload.meshId = resolvedMeshId;
@@ -14740,6 +14865,7 @@ var init_mesh_event_forwarding = __esm({
14740
14865
  init_mesh_runtime_store();
14741
14866
  init_mesh_events_pending();
14742
14867
  init_mesh_routing();
14868
+ init_mesh_host_ownership();
14743
14869
  init_mesh_unresolved_forward_outbox();
14744
14870
  init_mesh_event_trace();
14745
14871
  init_snapshot();
@@ -15031,8 +15157,7 @@ async function runMeshReconcileTick(components) {
15031
15157
  const idleCoordinators = meshCoordinators.filter((c) => c.idle);
15032
15158
  const generatingCoordinators = meshCoordinators.filter((c) => !c.idle && !c.modalParked);
15033
15159
  const modalParkedCoordinators = meshCoordinators.filter((c) => !c.idle && c.modalParked);
15034
- const targetCoordinators = idleCoordinators.length > 0 ? idleCoordinators : generatingCoordinators;
15035
- const forceOnly = idleCoordinators.length === 0;
15160
+ const targetCoordinators = idleCoordinators;
15036
15161
  if (targetCoordinators.length === 0) {
15037
15162
  if (modalParkedCoordinators.length > 0) {
15038
15163
  const liveSessionIds = new Set(
@@ -15099,6 +15224,23 @@ async function runMeshReconcileTick(components) {
15099
15224
  modalParkedCoordinators.length
15100
15225
  );
15101
15226
  }
15227
+ } else if (generatingCoordinators.length > 0) {
15228
+ let hasPending = true;
15229
+ if (store) {
15230
+ try {
15231
+ hasPending = store.pendingEventCount(meshId) > 0;
15232
+ } catch {
15233
+ }
15234
+ }
15235
+ if (hasPending) {
15236
+ LOG.info("MeshReconcile", `Reconcile skip \u2192 generating: holding pending event(s) for mesh ${meshId} (${generatingCoordinators.length} coordinator(s) busy; events left queued for the next idle tick)`);
15237
+ recordHeldTerminalEventsToLedger(
15238
+ meshId,
15239
+ drainDaemonIds.length > 0 ? drainDaemonIds : localDaemonId ? [localDaemonId] : [],
15240
+ "generating_no_idle_coordinator",
15241
+ generatingCoordinators.length
15242
+ );
15243
+ }
15102
15244
  }
15103
15245
  continue;
15104
15246
  }
@@ -15112,16 +15254,14 @@ async function runMeshReconcileTick(components) {
15112
15254
  try {
15113
15255
  pendingEvents = drainPendingMeshCoordinatorEvents(
15114
15256
  meshId,
15115
- drainDaemonIds.length > 0 ? drainDaemonIds : localDaemonId,
15116
- forceOnly ? { onlyEvents: MESH_FORCE_INJECT_EVENTS } : void 0
15257
+ drainDaemonIds.length > 0 ? drainDaemonIds : localDaemonId
15117
15258
  );
15118
15259
  } catch (e) {
15119
15260
  LOG.warn("MeshReconcile", `Drain failed for mesh ${meshId}: ${e?.message || e}`);
15120
15261
  continue;
15121
15262
  }
15122
15263
  if (pendingEvents.length === 0) continue;
15123
- const mode = forceOnly ? "force-drain \u2192 generating" : "inject \u2192 idle";
15124
- LOG.info("MeshReconcile", `Reconcile ${mode}: ${pendingEvents.length} pending event(s) \u2192 ${targetCoordinators.length} coordinator(s) for mesh ${meshId}`);
15264
+ LOG.info("MeshReconcile", `Reconcile inject \u2192 idle: ${pendingEvents.length} pending event(s) \u2192 ${targetCoordinators.length} coordinator(s) for mesh ${meshId}`);
15125
15265
  for (const pending of pendingEvents) {
15126
15266
  const wantSession = readNonEmptyString2(pending.targetCoordinatorSessionId);
15127
15267
  if (wantSession) {
@@ -23355,102 +23495,7 @@ function buildMeshLedgerReconciliationEvidence(meshId, replicas) {
23355
23495
  init_mesh_work_queue();
23356
23496
  init_mesh_active_work();
23357
23497
  init_mesh_refine_status();
23358
-
23359
- // src/mesh/mesh-scheduling-runtime.ts
23360
- init_repo_mesh_types();
23361
- init_dist();
23362
- function isReadonly(task) {
23363
- return task.taskMode === "live_debug_readonly";
23364
- }
23365
- function isAssigned(task) {
23366
- return task.status === "assigned";
23367
- }
23368
- function buildMeshSchedulingRuntime(mesh, queue) {
23369
- const strategy = normalizeMeshSchedulingStrategy(mesh?.policy?.schedulingStrategy);
23370
- const maxParallelTasks = resolveMaxParallelTasks(mesh?.policy?.maxParallelTasks);
23371
- const maxReadonlyParallelTasks = Math.max(2, maxParallelTasks * 2);
23372
- const assignedTasks = (Array.isArray(queue) ? queue : []).filter(isAssigned);
23373
- const activeWriteAssigned = assignedTasks.filter((t) => !isReadonly(t)).length;
23374
- const activeReadonlyAssigned = assignedTasks.filter(isReadonly).length;
23375
- const globalWriteCapReached = activeWriteAssigned >= maxParallelTasks;
23376
- const globalReadonlyCapReached = activeReadonlyAssigned >= maxReadonlyParallelTasks;
23377
- const writeAssignedByNode = /* @__PURE__ */ new Map();
23378
- const assignedByNode = /* @__PURE__ */ new Map();
23379
- const providerCountByNode = /* @__PURE__ */ new Map();
23380
- for (const task of assignedTasks) {
23381
- const nodeId = typeof task.assignedNodeId === "string" ? task.assignedNodeId.trim() : "";
23382
- if (!nodeId) continue;
23383
- assignedByNode.set(nodeId, (assignedByNode.get(nodeId) ?? 0) + 1);
23384
- if (!isReadonly(task)) {
23385
- writeAssignedByNode.set(nodeId, (writeAssignedByNode.get(nodeId) ?? 0) + 1);
23386
- }
23387
- const provider = typeof task.assignedProviderType === "string" ? task.assignedProviderType : "";
23388
- if (provider) {
23389
- let byProvider = providerCountByNode.get(nodeId);
23390
- if (!byProvider) {
23391
- byProvider = /* @__PURE__ */ new Map();
23392
- providerCountByNode.set(nodeId, byProvider);
23393
- }
23394
- byProvider.set(provider, (byProvider.get(provider) ?? 0) + 1);
23395
- }
23396
- }
23397
- const nodes = [];
23398
- for (const rawNode of Array.isArray(mesh?.nodes) ? mesh.nodes : []) {
23399
- const nodeId = normalizeMeshNodeId(rawNode);
23400
- if (!nodeId) continue;
23401
- const policy = rawNode?.policy || void 0;
23402
- const load4 = assignedByNode.get(nodeId) ?? 0;
23403
- const schedulingPriority = resolveNodeSchedulingPriority(policy);
23404
- const capReasons = [];
23405
- if (globalWriteCapReached) capReasons.push("global_max_parallel_tasks_reached");
23406
- if ((writeAssignedByNode.get(nodeId) ?? 0) > 0) capReasons.push("node_has_active_assignment");
23407
- let providerRoles;
23408
- const declaredRoles = Array.isArray(policy?.providerRoles) ? policy.providerRoles : [];
23409
- if (declaredRoles.length) {
23410
- const byProvider = providerCountByNode.get(nodeId);
23411
- providerRoles = [];
23412
- for (const role of declaredRoles) {
23413
- if (!role || typeof role !== "object") continue;
23414
- const providerType = typeof role.providerType === "string" ? role.providerType.trim() : "";
23415
- if (!providerType) continue;
23416
- const maxParallel = resolveProviderMaxParallel(policy, providerType);
23417
- const activeAssigned = byProvider?.get(providerType) ?? 0;
23418
- const capReached = maxParallel !== void 0 && activeAssigned >= maxParallel;
23419
- providerRoles.push({
23420
- providerType,
23421
- ...maxParallel !== void 0 ? { maxParallel } : {},
23422
- activeAssigned,
23423
- capReached
23424
- });
23425
- if (capReached) capReasons.push(`max_provider_parallel_reached:${providerType}`);
23426
- }
23427
- if (!providerRoles.length) providerRoles = void 0;
23428
- }
23429
- const maxConcurrentSessions = Number(policy?.maxConcurrentSessions);
23430
- const hasSessionCap = Number.isFinite(maxConcurrentSessions) && maxConcurrentSessions >= 0;
23431
- nodes.push({
23432
- nodeId,
23433
- load: load4,
23434
- schedulingPriority,
23435
- ...hasSessionCap ? { maxConcurrentSessions: Math.floor(maxConcurrentSessions) } : {},
23436
- ...providerRoles ? { providerRoles } : {},
23437
- capReached: capReasons.length > 0,
23438
- capReasons
23439
- });
23440
- }
23441
- return {
23442
- strategy,
23443
- maxParallelTasks,
23444
- maxReadonlyParallelTasks,
23445
- activeWriteAssigned,
23446
- activeReadonlyAssigned,
23447
- globalWriteCapReached,
23448
- globalReadonlyCapReached,
23449
- nodes
23450
- };
23451
- }
23452
-
23453
- // src/index.ts
23498
+ init_mesh_scheduling_runtime();
23454
23499
  init_mesh_host_ownership();
23455
23500
  init_mesh_events();
23456
23501
  init_mesh_events_utils();
@@ -39233,9 +39278,35 @@ var CliProviderInstance = class _CliProviderInstance {
39233
39278
  * terminal state. Leaving meshNodeFor pinned would route this session's
39234
39279
  * subsequent unrelated turns (e.g. ad-hoc dashboard chats) to the
39235
39280
  * coordinator as if they were task completions.
39281
+ *
39282
+ * MESHID-DROP-ON-DETACH (Fix C): a coordinator-LAUNCHED worker session
39283
+ * (launchedByCoordinator) holds its mesh membership (meshNodeFor / meshNodeId /
39284
+ * meshCoordinatorDaemonId) at the SESSION level — set once at launch
39285
+ * (mesh_launch_session / queue auto-launch), independent of any single task.
39286
+ * The original detach wiped meshNodeFor + meshNodeId together with the
39287
+ * task-level meshActiveTaskId, so the FIRST task completion stripped the
39288
+ * membership and EVERY subsequent completion forwarded with meshId absent —
39289
+ * resolveWorkerDelegateRouting fell to mesh_unresolved and the coordinator
39290
+ * rejected the forward "meshId required". For a launched member we therefore
39291
+ * clear ONLY the task-level marker (meshActiveTaskId) and preserve the
39292
+ * session-level membership so its next task's completion still resolves.
39293
+ * A task-less ad-hoc turn on a preserved-membership session is NOT misrouted:
39294
+ * its completion carries no taskId and the session holds no active assignment,
39295
+ * so the forwarder's WARMUPGAP guard skips the dispatch-row flip (it only
39296
+ * injects a benign task-less notification). A NON-launched session (a plain CLI
39297
+ * session adopted by mesh_send_task --direct, launchedByCoordinator falsy)
39298
+ * keeps the original full clear so an ad-hoc session is never left pinned.
39236
39299
  */
39237
39300
  detachMeshAssignment() {
39238
39301
  if (!this.settings.meshNodeFor && !this.settings.meshActiveTaskId && !this.settings.meshNodeId) return;
39302
+ if (this.settings.launchedByCoordinator === true) {
39303
+ if (!this.settings.meshActiveTaskId) return;
39304
+ const { meshActiveTaskId: meshActiveTaskId2, ...rest2 } = this.settings;
39305
+ void meshActiveTaskId2;
39306
+ this.settings = rest2;
39307
+ this.adapter.updateRuntimeSettings?.(this.settings);
39308
+ return;
39309
+ }
39239
39310
  const { meshNodeFor, meshNodeId, meshActiveTaskId, ...rest } = this.settings;
39240
39311
  void meshNodeFor;
39241
39312
  void meshActiveTaskId;
@@ -49104,6 +49175,9 @@ var meshStatusHandlers = {
49104
49175
  const { getMeshQueueStats: getMeshQueueStats2, getQueue: getQueue2 } = await Promise.resolve().then(() => (init_mesh_work_queue(), mesh_work_queue_exports));
49105
49176
  const queue = getQueue2(meshId);
49106
49177
  const queueSummary = getMeshQueueStats2(meshId);
49178
+ const { buildMeshSchedulingRuntime: buildMeshSchedulingRuntime2 } = await Promise.resolve().then(() => (init_mesh_scheduling_runtime(), mesh_scheduling_runtime_exports));
49179
+ const schedulingRuntime = buildMeshSchedulingRuntime2(mesh, queue);
49180
+ const schedulingByNode = new Map(schedulingRuntime.nodes.map((n) => [n.nodeId, n]));
49107
49181
  const { readLedgerEntries: readLedgerEntries2, getLedgerSummary: getLedgerSummary2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
49108
49182
  const ledgerEntries = readLedgerEntries2(meshId, { tail: 20 });
49109
49183
  const asyncRefineLedgerEntries = readLedgerEntries2(meshId, { tail: 100 });
@@ -49218,6 +49292,11 @@ var meshStatusHandlers = {
49218
49292
  activeSessionDetails: [],
49219
49293
  launchReady: false
49220
49294
  };
49295
+ const nodeScheduling = schedulingByNode.get(nodeId);
49296
+ if (nodeScheduling) {
49297
+ const { nodeId: _omitNodeId, ...nodeSchedulingRest } = nodeScheduling;
49298
+ status.scheduling = nodeSchedulingRest;
49299
+ }
49221
49300
  if (isSelfNode) {
49222
49301
  status.connection = {
49223
49302
  perspective: "selected_coordinator",
@@ -49418,6 +49497,19 @@ var meshStatusHandlers = {
49418
49497
  branchConvergenceSummary: summarizeInlineMeshBranchConvergence(nodeStatuses),
49419
49498
  ...previewFreshness ? { previewFreshness, deployFreshness: previewFreshness } : {},
49420
49499
  nodes: nodeStatuses,
49500
+ // Mesh-level scheduling rollup (strategy + global cap consumption). Mirrors
49501
+ // the MCP `mesh_status` tool's `scheduling` block field-for-field so both
49502
+ // surfaces read the same runtime; per-node detail lives on each
49503
+ // nodes[].scheduling above.
49504
+ scheduling: {
49505
+ strategy: schedulingRuntime.strategy,
49506
+ maxParallelTasks: schedulingRuntime.maxParallelTasks,
49507
+ maxReadonlyParallelTasks: schedulingRuntime.maxReadonlyParallelTasks,
49508
+ activeWriteAssigned: schedulingRuntime.activeWriteAssigned,
49509
+ activeReadonlyAssigned: schedulingRuntime.activeReadonlyAssigned,
49510
+ globalWriteCapReached: schedulingRuntime.globalWriteCapReached,
49511
+ globalReadonlyCapReached: schedulingRuntime.globalReadonlyCapReached
49512
+ },
49421
49513
  queue: { tasks: queue, summary: queueSummary },
49422
49514
  ledger: { entries: ledgerEntries, summary: ledgerSummary },
49423
49515
  ...missions.length > 0 ? { missions } : {},
@@ -52362,17 +52454,40 @@ var DaemonCommandRouter = class {
52362
52454
  * the wider plural-shape scan so a controlbar/modal command targeting a non-primary remote
52363
52455
  * session still resolves its owner — the singular readCachedInlineMeshActiveSessions semantics
52364
52456
  * other consumers depend on stay untouched.
52457
+ *
52458
+ * CANCEL-STOP-RELAY: the session-id cache scan above only matches when the coordinator's
52459
+ * cached status snapshot already lists the worker's session id in a recognized active-sessions
52460
+ * shape. A worktree-clone worker session whose id form/timing differs from the cached snapshot
52461
+ * (or is simply not yet reflected) misses the scan, so a stop that carries the authoritative
52462
+ * owning nodeId (mesh_queue_cancel knows assignedNodeId) used to silently fail to forward.
52463
+ * `ownerNodeIdHint` adds a deterministic fallback: when the session-id scan misses, resolve the
52464
+ * owner daemonId by matching the node by id (meshNodeIdMatches — same form-tolerant compare the
52465
+ * rest of the router uses, no new raw compare). The same self-loopback guard applies to both
52466
+ * paths, so a coordinator-hosted node is still never force-forwarded to a remote form of itself.
52365
52467
  */
52366
- resolveRemoteMeshSessionOwnerDaemonId(sessionId) {
52468
+ resolveRemoteMeshSessionOwnerDaemonId(sessionId, ownerNodeIdHint) {
52367
52469
  const trimmed = typeof sessionId === "string" ? sessionId.trim() : "";
52368
- if (!trimmed) return void 0;
52470
+ const nodeHint = typeof ownerNodeIdHint === "string" ? ownerNodeIdHint.trim() : "";
52471
+ if (!trimmed && !nodeHint) return void 0;
52369
52472
  const selfDaemonId = this.deps.statusInstanceId;
52370
- for (const node of this.collectMeshSessionOwnerCandidateNodes()) {
52371
- if (!collectMeshNodeHostedSessionIds(node).has(trimmed)) continue;
52372
- const nodeDaemonId = readMeshNodeDaemonId(readObjectRecord(node));
52373
- if (!nodeDaemonId) continue;
52374
- if (selfDaemonId && daemonIdsEquivalent(nodeDaemonId, selfDaemonId)) return void 0;
52375
- return nodeDaemonId;
52473
+ const candidates = this.collectMeshSessionOwnerCandidateNodes();
52474
+ if (trimmed) {
52475
+ for (const node of candidates) {
52476
+ if (!collectMeshNodeHostedSessionIds(node).has(trimmed)) continue;
52477
+ const nodeDaemonId = readMeshNodeDaemonId(readObjectRecord(node));
52478
+ if (!nodeDaemonId) continue;
52479
+ if (selfDaemonId && daemonIdsEquivalent(nodeDaemonId, selfDaemonId)) return void 0;
52480
+ return nodeDaemonId;
52481
+ }
52482
+ }
52483
+ if (nodeHint) {
52484
+ for (const node of candidates) {
52485
+ if (!meshNodeIdMatches(node, nodeHint)) continue;
52486
+ const nodeDaemonId = readMeshNodeDaemonId(readObjectRecord(node));
52487
+ if (!nodeDaemonId) continue;
52488
+ if (selfDaemonId && daemonIdsEquivalent(nodeDaemonId, selfDaemonId)) return void 0;
52489
+ return nodeDaemonId;
52490
+ }
52376
52491
  }
52377
52492
  return void 0;
52378
52493
  }
@@ -54506,7 +54621,9 @@ ${hintLines.join("\n")}` : "",
54506
54621
  const localInstance = this.deps.instanceManager?.getInstance(targetSessionId);
54507
54622
  const localRegistry = this.deps.sessionRegistry?.get?.(targetSessionId);
54508
54623
  if (!localInstance && !localRegistry) {
54509
- const ownerDaemonId = this.resolveRemoteMeshSessionOwnerDaemonId(targetSessionId);
54624
+ const meshContext = readObjectRecord(args?.meshContext);
54625
+ const ownerNodeIdHint = readStringValue(meshContext.nodeId);
54626
+ const ownerDaemonId = this.resolveRemoteMeshSessionOwnerDaemonId(targetSessionId, ownerNodeIdHint);
54510
54627
  if (ownerDaemonId) {
54511
54628
  LOG.info("Mesh", `[Mesh] Forwarding session-scoped '${cmd}' for remote worker session ${targetSessionId.split("_")[0]} \u2192 daemon ${ownerDaemonId.slice(0, 12)}`);
54512
54629
  const forwarded = await this.deps.dispatchMeshCommand(ownerDaemonId, cmd, {