@adhdev/daemon-core 0.9.82-rc.380 → 0.9.82-rc.382

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.d.ts CHANGED
@@ -7,8 +7,8 @@ export type { ChatBubbleState, ChatMessage, ExtensionInfo, CommandResult as Core
7
7
  export type { SessionEntry, CompactSessionEntry, CompactDaemonEntry, CloudDaemonSummaryEntry, DashboardBootstrapDaemonEntry, VersionUpdateReason, CloudStatusReportPayload, DaemonStatusEventPayload, DashboardStatusEventPayload, SessionTransport, SessionKind, SessionCapability, AgentSessionStream, ReadChatCursor, ReadChatSyncResult, TransportTopic, SessionChatTailSubscriptionParams, SessionRuntimeOutputSubscriptionParams, MachineRuntimeSubscriptionParams, SessionHostDiagnosticsSubscriptionParams, SessionModalSubscriptionParams, DaemonMetadataSubscriptionParams, WorkspaceGitSubscriptionParams, SessionChatTailUpdate, MachineRuntimeUpdate, SessionHostDiagnosticsUpdate, SessionModalUpdate, DaemonMetadataUpdate, TopicUpdateEnvelope, SubscribeRequest, UnsubscribeRequest, StandaloneWsStatusPayload, AvailableProviderInfo, AcpConfigOption, AcpMode, ProviderControlSchema, StatusReportPayload, MachineInfo, SessionHostDiagnosticsSnapshot, SessionHostRecord, SessionHostWriteOwner, SessionHostAttachedClient, SessionHostLogEntry, SessionHostRequestTrace, SessionHostRuntimeTransition, DetectedIdeInfo, WorkspaceEntry, ProviderSummaryItem, ProviderSummaryMetadata, ProviderState, ProviderStatus, ProviderErrorReason, SessionActiveChatData, ActiveChatData, IdeProviderState, CliProviderState, AcpProviderState, ExtensionProviderState, MessageInputSupport, InputMediaStrategyDescriptor, InputAttachmentStrategy, InputMediaType, } from './shared-types.js';
8
8
  export type { InteractivePrompt, InteractiveQuestion, InteractiveOption, InteractivePromptResponse, InteractiveAnswer, } from './providers/types/interactive-prompt.js';
9
9
  export { normalizeInteractivePrompt, normalizeInteractivePromptResponse, buildClaudeInteractiveToolResult, interactivePromptFromClaudeAskUserQuestion, detectClaudeAskUserQuestionPromptFromJson, } from './providers/types/interactive-prompt.js';
10
- export type { RepoMesh, RepoMeshDaemonRole, RepoMeshHostMetadata, RepoMeshHostPairingMetadata, RepoMeshHostStatus, RepoMeshNode, RepoMeshNodeHealth, RepoMeshPolicy, RepoMeshNodePolicy, RepoMeshRelatedRepo, RepoMeshNodeCapabilities, DetectedCommand, ProjectContextSnapshot, ProjectContextSource, RepoMeshCoordinatorConfig, LocalMeshConfig, LocalMeshEntry, LocalMeshNodeEntry, RepoMeshStatus, RepoMeshNodeStatus, RepoMeshPeerConnectionStatus, RepoMeshPeerConnectionState, RepoMeshPeerConnectionTransport, RepoMeshSessionStatus, RepoMeshQueueTask, RepoMeshQueueTaskStatus, RepoMeshQueueSummary, RepoMeshQueueStatus, RepoMeshLedgerEntryStatus, RepoMeshLedgerSummaryStatus, RepoMeshLedgerStatus, MeshAsyncJobLifecycle, RepoMeshSchedulingStrategy, } from './repo-mesh-types.js';
11
- export { DEFAULT_MESH_POLICY, resolveDelegatedWorkerAutoApprove, MESH_SCHEDULING_STRATEGIES, DEFAULT_MESH_SCHEDULING_STRATEGY, normalizeMeshSchedulingStrategy, resolveNodeSchedulingPriority, MESH_CONVERGE_REFINE_TAG, MESH_CONVERGE_FAST_FORWARD_TAG, resolveAutoConvergeCodeChange, } from './repo-mesh-types.js';
10
+ export type { RepoMesh, RepoMeshDaemonRole, RepoMeshHostMetadata, RepoMeshHostPairingMetadata, RepoMeshHostStatus, RepoMeshNode, RepoMeshNodeHealth, RepoMeshPolicy, RepoMeshNodePolicy, RepoMeshRelatedRepo, RepoMeshNodeCapabilities, DetectedCommand, ProjectContextSnapshot, ProjectContextSource, RepoMeshCoordinatorConfig, LocalMeshConfig, LocalMeshEntry, LocalMeshNodeEntry, RepoMeshStatus, RepoMeshNodeStatus, RepoMeshPeerConnectionStatus, RepoMeshPeerConnectionState, RepoMeshPeerConnectionTransport, RepoMeshSessionStatus, RepoMeshQueueTask, RepoMeshQueueTaskStatus, RepoMeshQueueSummary, RepoMeshQueueStatus, RepoMeshLedgerEntryStatus, RepoMeshLedgerSummaryStatus, RepoMeshLedgerStatus, MeshAsyncJobLifecycle, RepoMeshSchedulingStrategy, RepoMeshSchedulingStatus, RepoMeshNodeSchedulingStatus, RepoMeshNodeProviderSchedulingStatus, } from './repo-mesh-types.js';
11
+ export { DEFAULT_MESH_POLICY, resolveDelegatedWorkerAutoApprove, MESH_SCHEDULING_STRATEGIES, DEFAULT_MESH_SCHEDULING_STRATEGY, normalizeMeshSchedulingStrategy, resolveNodeSchedulingPriority, resolveProviderMaxParallel, mergeAndNormalizePolicy, normalizeAutoFastForwardPolicy, resolveMaxParallelTasks, MESH_MAX_PARALLEL_TASKS_MIN, MESH_MAX_PARALLEL_TASKS_MAX, MESH_CONVERGE_REFINE_TAG, MESH_CONVERGE_FAST_FORWARD_TAG, resolveAutoConvergeCodeChange, } from './repo-mesh-types.js';
12
12
  export * from './git/index.js';
13
13
  import type { RuntimeWriteOwner as _RuntimeWriteOwner } from './shared-types-extra.js';
14
14
  import type { RuntimeAttachedClient as _RuntimeAttachedClient } from './shared-types-extra.js';
@@ -58,6 +58,8 @@ export type { StaleDirectPruneClassification, StaleDirectPruneResult, PruneStale
58
58
  export type { MeshActiveWorkRecord, MeshActiveWorkStatus, MeshActiveWorkSummary, MeshActiveWorkSource, MeshStaleDirectWorkSummary } from './mesh/mesh-active-work.js';
59
59
  export { buildMeshAsyncRefineJobs, summarizeMeshAsyncRefineJobs, STALE_TERMINAL_REFINE_WINDOW_MS, RECENT_TERMINAL_REFINE_CAP } from './mesh/mesh-refine-status.js';
60
60
  export type { MeshAsyncRefineJobStatus, MeshAsyncRefineJobSummary, MeshAsyncRefineJobsSummary } from './mesh/mesh-refine-status.js';
61
+ export { buildMeshSchedulingRuntime } from './mesh/mesh-scheduling-runtime.js';
62
+ export type { MeshSchedulingRuntime, MeshNodeSchedulingRuntime, MeshNodeProviderSchedulingRuntime } from './mesh/mesh-scheduling-runtime.js';
61
63
  export { buildMeshHostRequiredFailure, createDefaultMeshHostMetadata, isMeshHostOwner, normalizeMeshDaemonRole, requireMeshHostQueueOwner, resolveMeshHostStatus } from './mesh/mesh-host-ownership.js';
62
64
  export { triggerMeshQueue, drainPendingMeshCoordinatorEvents, getPendingMeshCoordinatorEvents, clearPendingMeshCoordinatorEvents, queuePendingMeshCoordinatorEvent, reconcileDirectDispatchCompletionFromTranscript } from './mesh/mesh-events.js';
63
65
  export type { PendingMeshCoordinatorEvent } from './mesh/mesh-events.js';
package/dist/index.js CHANGED
@@ -43,6 +43,56 @@ function resolveNodeSchedulingPriority(nodePolicy) {
43
43
  function resolveAutoConvergeCodeChange(policy) {
44
44
  return policy?.autoConvergeCodeChange === true;
45
45
  }
46
+ function resolveMaxParallelTasks(value) {
47
+ const n = Number(value);
48
+ if (!Number.isFinite(n)) return DEFAULT_MESH_POLICY.maxParallelTasks;
49
+ return Math.max(MESH_MAX_PARALLEL_TASKS_MIN, Math.min(MESH_MAX_PARALLEL_TASKS_MAX, Math.floor(n)));
50
+ }
51
+ function normalizeAutoFastForwardPolicy(value) {
52
+ const record = value && typeof value === "object" && !Array.isArray(value) ? value : {};
53
+ const maxBehind = Number(record.maxBehind);
54
+ return {
55
+ enabled: record.enabled !== false,
56
+ ...Number.isFinite(maxBehind) && maxBehind >= 0 ? { maxBehind: Math.floor(maxBehind) } : {},
57
+ requireCleanSubmodules: record.requireCleanSubmodules !== false
58
+ };
59
+ }
60
+ function mergeAndNormalizePolicy(base, patch) {
61
+ const autoFastForward = normalizeAutoFastForwardPolicy({
62
+ ...DEFAULT_MESH_POLICY.autoFastForward,
63
+ ...base?.autoFastForward && typeof base.autoFastForward === "object" ? base.autoFastForward : {},
64
+ ...patch?.autoFastForward && typeof patch.autoFastForward === "object" ? patch.autoFastForward : {}
65
+ });
66
+ const policy = {
67
+ ...DEFAULT_MESH_POLICY,
68
+ ...base || {},
69
+ ...patch || {},
70
+ autoFastForward
71
+ };
72
+ if (!DIRTY_WORKSPACE_BEHAVIORS.has(policy.dirtyWorkspaceBehavior)) {
73
+ policy.dirtyWorkspaceBehavior = "warn";
74
+ }
75
+ policy.maxParallelTasks = resolveMaxParallelTasks(policy.maxParallelTasks);
76
+ policy.allowAutoPublishSubmoduleMainCommits = policy.allowAutoPublishSubmoduleMainCommits === true;
77
+ if (!SESSION_CLEANUP_MODES.has(policy.sessionCleanupOnNodeRemove)) {
78
+ policy.sessionCleanupOnNodeRemove = "preserve";
79
+ }
80
+ if (!SPAWNED_SESSION_VISIBILITY_MODES.has(policy.spawnedSessionVisibility)) {
81
+ policy.spawnedSessionVisibility = DEFAULT_MESH_POLICY.spawnedSessionVisibility;
82
+ }
83
+ const normalizedStrategy = normalizeMeshSchedulingStrategy(policy.schedulingStrategy);
84
+ if (normalizedStrategy === "first_eligible") {
85
+ delete policy.schedulingStrategy;
86
+ } else {
87
+ policy.schedulingStrategy = normalizedStrategy;
88
+ }
89
+ if (policy.autoConvergeCodeChange === true) {
90
+ policy.autoConvergeCodeChange = true;
91
+ } else {
92
+ delete policy.autoConvergeCodeChange;
93
+ }
94
+ return policy;
95
+ }
46
96
  function resolveDelegatedWorkerAutoApprove(meshPolicy, nodePolicy) {
47
97
  if (typeof nodePolicy?.delegatedWorkerAutoApprove === "boolean") {
48
98
  return nodePolicy.delegatedWorkerAutoApprove;
@@ -67,7 +117,7 @@ function resolveProviderMaxParallel(nodePolicy, providerType) {
67
117
  }
68
118
  return void 0;
69
119
  }
70
- var MESH_SCHEDULING_STRATEGIES, DEFAULT_MESH_SCHEDULING_STRATEGY, MESH_CONVERGE_REFINE_TAG, MESH_CONVERGE_FAST_FORWARD_TAG, DEFAULT_MESH_POLICY;
120
+ var MESH_SCHEDULING_STRATEGIES, DEFAULT_MESH_SCHEDULING_STRATEGY, MESH_CONVERGE_REFINE_TAG, MESH_CONVERGE_FAST_FORWARD_TAG, DEFAULT_MESH_POLICY, SESSION_CLEANUP_MODES, SPAWNED_SESSION_VISIBILITY_MODES, DIRTY_WORKSPACE_BEHAVIORS, MESH_MAX_PARALLEL_TASKS_MIN, MESH_MAX_PARALLEL_TASKS_MAX;
71
121
  var init_repo_mesh_types = __esm({
72
122
  "src/repo-mesh-types.ts"() {
73
123
  "use strict";
@@ -97,6 +147,23 @@ var init_repo_mesh_types = __esm({
97
147
  autoFastForward: { enabled: true },
98
148
  maxTaskRetries: 1
99
149
  };
150
+ SESSION_CLEANUP_MODES = /* @__PURE__ */ new Set([
151
+ "preserve",
152
+ "stop",
153
+ "delete_stopped",
154
+ "stop_and_delete"
155
+ ]);
156
+ SPAWNED_SESSION_VISIBILITY_MODES = /* @__PURE__ */ new Set([
157
+ "visible",
158
+ "hidden"
159
+ ]);
160
+ DIRTY_WORKSPACE_BEHAVIORS = /* @__PURE__ */ new Set([
161
+ "block",
162
+ "warn",
163
+ "checkpoint_then_continue"
164
+ ]);
165
+ MESH_MAX_PARALLEL_TASKS_MIN = 1;
166
+ MESH_MAX_PARALLEL_TASKS_MAX = 8;
100
167
  }
101
168
  });
102
169
 
@@ -316,10 +383,10 @@ function readInjected(value) {
316
383
  }
317
384
  function getDaemonBuildInfo() {
318
385
  if (cached) return cached;
319
- const commit = readInjected(true ? "5fff0bee3f6a8e8f00989177c53d1d2a1cf607ad" : void 0) ?? "unknown";
320
- const commitShort = readInjected(true ? "5fff0bee" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
321
- const version = readInjected(true ? "0.9.82-rc.380" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
322
- const builtAt = readInjected(true ? "2026-06-25T10:07:36.562Z" : void 0);
386
+ const commit = readInjected(true ? "70741c4fe19c6f71bcef702e7e149d963d6fd916" : void 0) ?? "unknown";
387
+ const commitShort = readInjected(true ? "70741c4f" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
388
+ const version = readInjected(true ? "0.9.82-rc.382" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
389
+ const builtAt = readInjected(true ? "2026-06-25T13:31:28.133Z" : void 0);
323
390
  cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
324
391
  return cached;
325
392
  }
@@ -2369,52 +2436,6 @@ function normalizeRepoIdentity(remoteUrl) {
2369
2436
  if (sshMatch) return `${sshMatch[1]}/${sshMatch[2]}`;
2370
2437
  return identity;
2371
2438
  }
2372
- function mergeMeshPolicy(base, patch) {
2373
- const autoFastForward = normalizeAutoFastForwardPolicy({
2374
- ...DEFAULT_MESH_POLICY.autoFastForward,
2375
- ...base?.autoFastForward && typeof base.autoFastForward === "object" ? base.autoFastForward : {},
2376
- ...patch?.autoFastForward && typeof patch.autoFastForward === "object" ? patch.autoFastForward : {}
2377
- });
2378
- const policy = {
2379
- ...DEFAULT_MESH_POLICY,
2380
- ...base || {},
2381
- ...patch || {},
2382
- autoFastForward
2383
- };
2384
- if (!["block", "warn", "checkpoint_then_continue"].includes(policy.dirtyWorkspaceBehavior)) {
2385
- policy.dirtyWorkspaceBehavior = "warn";
2386
- }
2387
- const maxParallelTasks = Number(policy.maxParallelTasks);
2388
- policy.maxParallelTasks = Number.isFinite(maxParallelTasks) ? Math.max(1, Math.min(8, Math.floor(maxParallelTasks))) : 2;
2389
- policy.allowAutoPublishSubmoduleMainCommits = policy.allowAutoPublishSubmoduleMainCommits === true;
2390
- if (!SESSION_CLEANUP_MODES.has(String(policy.sessionCleanupOnNodeRemove))) {
2391
- policy.sessionCleanupOnNodeRemove = "preserve";
2392
- }
2393
- if (!SPAWNED_SESSION_VISIBILITY_MODES.has(String(policy.spawnedSessionVisibility))) {
2394
- policy.spawnedSessionVisibility = DEFAULT_MESH_POLICY.spawnedSessionVisibility;
2395
- }
2396
- const normalizedStrategy = normalizeMeshSchedulingStrategy(policy.schedulingStrategy);
2397
- if (normalizedStrategy === "first_eligible") {
2398
- delete policy.schedulingStrategy;
2399
- } else {
2400
- policy.schedulingStrategy = normalizedStrategy;
2401
- }
2402
- if (policy.autoConvergeCodeChange === true) {
2403
- policy.autoConvergeCodeChange = true;
2404
- } else {
2405
- delete policy.autoConvergeCodeChange;
2406
- }
2407
- return policy;
2408
- }
2409
- function normalizeAutoFastForwardPolicy(value) {
2410
- const record = value && typeof value === "object" && !Array.isArray(value) ? value : {};
2411
- const maxBehind = Number(record.maxBehind);
2412
- return {
2413
- enabled: record.enabled !== false,
2414
- ...Number.isFinite(maxBehind) && maxBehind >= 0 ? { maxBehind: Math.floor(maxBehind) } : {},
2415
- requireCleanSubmodules: record.requireCleanSubmodules !== false
2416
- };
2417
- }
2418
2439
  function listMeshes() {
2419
2440
  return loadMeshConfig().meshes;
2420
2441
  }
@@ -2713,7 +2734,7 @@ function updateNode(meshId, nodeId, opts) {
2713
2734
  saveMeshConfig(config);
2714
2735
  return node;
2715
2736
  }
2716
- var import_fs3, import_path3, import_crypto3, SESSION_CLEANUP_MODES, SPAWNED_SESSION_VISIBILITY_MODES;
2737
+ var import_fs3, import_path3, import_crypto3, mergeMeshPolicy;
2717
2738
  var init_mesh_config = __esm({
2718
2739
  "src/config/mesh-config.ts"() {
2719
2740
  "use strict";
@@ -2724,8 +2745,7 @@ var init_mesh_config = __esm({
2724
2745
  init_config();
2725
2746
  init_repo_mesh_types();
2726
2747
  init_mesh_host_ownership();
2727
- SESSION_CLEANUP_MODES = /* @__PURE__ */ new Set(["preserve", "stop", "delete_stopped", "stop_and_delete"]);
2728
- SPAWNED_SESSION_VISIBILITY_MODES = /* @__PURE__ */ new Set(["visible", "hidden"]);
2748
+ mergeMeshPolicy = mergeAndNormalizePolicy;
2729
2749
  }
2730
2750
  });
2731
2751
 
@@ -3046,7 +3066,7 @@ Default branch: \`${mesh.defaultBranch}\`` : ""}`);
3046
3066
  if (recentActivity) sections.push(recentActivity);
3047
3067
  const operatingNotes = buildOperatingNotesSection(ctx.operatingNotes);
3048
3068
  if (operatingNotes) sections.push(operatingNotes);
3049
- sections.push(buildPolicySection({ ...DEFAULT_MESH_POLICY, ...mesh.policy || {} }));
3069
+ sections.push(buildPolicySection(mergeAndNormalizePolicy(void 0, mesh.policy)));
3050
3070
  sections.push(TOOLS_SECTION);
3051
3071
  sections.push(TOOL_EXPOSURE_PREFLIGHT_SECTION);
3052
3072
  sections.push(WORKFLOW_SECTION);
@@ -3079,7 +3099,7 @@ function expandPromptPlaceholders(template, ctx) {
3079
3099
  mission: ctx.missionSection?.trim() || "",
3080
3100
  recentActivity: buildRecentActivitySection(ctx.recentActivity) || "",
3081
3101
  operatingNotes: buildOperatingNotesSection(ctx.operatingNotes) || "",
3082
- policy: buildPolicySection({ ...DEFAULT_MESH_POLICY, ...mesh.policy || {} }),
3102
+ policy: buildPolicySection(mergeAndNormalizePolicy(void 0, mesh.policy)),
3083
3103
  tools: TOOLS_SECTION,
3084
3104
  workflow: WORKFLOW_SECTION,
3085
3105
  rules: buildRulesSection(coordinatorCliType),
@@ -5748,6 +5768,28 @@ var init_mesh_runtime_store = __esm({
5748
5768
  AND status NOT IN ('completed', 'failed')
5749
5769
  `).run({ status, meshId, sessionId, updatedAt: now });
5750
5770
  }
5771
+ /**
5772
+ * MESH-DISPATCH-MISROUTE (fix 3, consumer residual): resolve the task_id of the SINGLE
5773
+ * non-terminal direct dispatch a session owns. Returns the task_id only when the session
5774
+ * holds exactly ONE active ('dispatched'/'acked') row — the case where a taskId-less
5775
+ * lifecycle event (a legacy/relayed worker whose producer never stamped meshActiveTaskId)
5776
+ * unambiguously belongs to that one dispatch. With zero rows there is nothing to ack; with
5777
+ * two or more (a re-dispatch/nudge sibling) the firing event's owner is ambiguous, so we
5778
+ * return null and the caller MUST NOT fall back to the session_id sweep that would flip a
5779
+ * sibling row ("may flip a sibling dispatch row"). This narrows the legacy fallback to the
5780
+ * only safe case instead of removing the producer-side TASKIDLESS stamp's safety net.
5781
+ */
5782
+ getSoleActiveDirectDispatchTaskId(meshId, sessionId) {
5783
+ if (!sessionId) return null;
5784
+ const rows = this.db.prepare(`
5785
+ SELECT task_id FROM mesh_direct_dispatches
5786
+ WHERE mesh_id = ? AND session_id = ?
5787
+ AND status NOT IN ('completed', 'failed', 'stale')
5788
+ `).all(meshId, sessionId);
5789
+ if (rows.length !== 1) return null;
5790
+ const taskId = typeof rows[0]?.task_id === "string" ? rows[0].task_id.trim() : "";
5791
+ return taskId || null;
5792
+ }
5751
5793
  cleanupTerminalDirectDispatches(olderThanMs) {
5752
5794
  const cutoff = new Date(Date.now() - olderThanMs).toISOString();
5753
5795
  this.db.prepare(`
@@ -8539,6 +8581,109 @@ var init_mesh_active_work = __esm({
8539
8581
  }
8540
8582
  });
8541
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
+
8542
8687
  // src/mesh/mesh-events-utils.ts
8543
8688
  function readNonEmptyString2(value) {
8544
8689
  return typeof value === "string" && value.trim() ? value.trim() : "";
@@ -10819,8 +10964,8 @@ async function maybeAutoLaunchOneQueueSession(components, meshId, mesh) {
10819
10964
  const maxParallelTasks = Math.max(1, Math.floor(Number(mesh?.policy?.maxParallelTasks) || 2));
10820
10965
  const maxReadonlyParallelTasks = Math.max(2, maxParallelTasks * 2);
10821
10966
  for (const task of pending) {
10822
- const isReadonly = task.taskMode === "live_debug_readonly";
10823
- if (isReadonly) {
10967
+ const isReadonly2 = task.taskMode === "live_debug_readonly";
10968
+ if (isReadonly2) {
10824
10969
  if (activeReadonlyAssignedCount(meshId) >= maxReadonlyParallelTasks) {
10825
10970
  markAutoLaunch(meshId, task.id, { status: "skipped", reason: "max_readonly_parallel_tasks_reached" });
10826
10971
  continue;
@@ -13768,6 +13913,20 @@ function recoverMeshIdByNodeId(nodeId) {
13768
13913
  }
13769
13914
  return "";
13770
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
+ }
13771
13930
  function resolveForwardEventMeshId(components, payload) {
13772
13931
  const direct = readNonEmptyString2(payload.meshId);
13773
13932
  if (direct) return direct;
@@ -14249,8 +14408,19 @@ function injectMeshSystemMessage(components, args) {
14249
14408
  }
14250
14409
  if (sessionId) {
14251
14410
  const startedTaskId = readNonEmptyString2(args.metadataEvent.taskId) || void 0;
14252
- if (startedTaskId || sessionHasActiveAssignment(args.meshId, sessionId)) {
14411
+ if (startedTaskId) {
14253
14412
  updateDirectDispatchStatus(args.meshId, sessionId, "acked", startedTaskId);
14413
+ } else if (sessionHasActiveAssignment(args.meshId, sessionId)) {
14414
+ const soleTaskId = (() => {
14415
+ try {
14416
+ return MeshRuntimeStore.getInstance().getSoleActiveDirectDispatchTaskId(args.meshId, sessionId);
14417
+ } catch {
14418
+ return null;
14419
+ }
14420
+ })();
14421
+ if (soleTaskId) {
14422
+ updateDirectDispatchStatus(args.meshId, sessionId, "acked", soleTaskId);
14423
+ }
14254
14424
  }
14255
14425
  const activeDeliveries = (() => {
14256
14426
  try {
@@ -14503,7 +14673,10 @@ function handleMeshForwardEvent(components, payload) {
14503
14673
  }
14504
14674
  const nodeId = readNonEmptyString2(payload.nodeId);
14505
14675
  const workspace = readNonEmptyString2(payload.workspace);
14506
- 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
+ );
14507
14680
  if (!meshId) {
14508
14681
  traceMeshEventDrop("meshId_required", {
14509
14682
  taskId: payload.taskId,
@@ -14558,7 +14731,12 @@ function forwardUnresolvedDelegateEvent(components, routing, event) {
14558
14731
  ...event,
14559
14732
  event: eventName,
14560
14733
  nodeId: readNonEmptyString2(routing.nodeId) || readNonEmptyString2(event.meshNodeId) || void 0,
14561
- 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
14562
14740
  };
14563
14741
  const resolvedMeshId = resolveForwardEventMeshId(components, payload);
14564
14742
  if (resolvedMeshId) payload.meshId = resolvedMeshId;
@@ -14687,6 +14865,7 @@ var init_mesh_event_forwarding = __esm({
14687
14865
  init_mesh_runtime_store();
14688
14866
  init_mesh_events_pending();
14689
14867
  init_mesh_routing();
14868
+ init_mesh_host_ownership();
14690
14869
  init_mesh_unresolved_forward_outbox();
14691
14870
  init_mesh_event_trace();
14692
14871
  init_snapshot();
@@ -21110,6 +21289,8 @@ __export(index_exports, {
21110
21289
  MAX_LEDGER_SLICE_LIMIT: () => MAX_LEDGER_SLICE_LIMIT,
21111
21290
  MESH_CONVERGE_FAST_FORWARD_TAG: () => MESH_CONVERGE_FAST_FORWARD_TAG,
21112
21291
  MESH_CONVERGE_REFINE_TAG: () => MESH_CONVERGE_REFINE_TAG,
21292
+ MESH_MAX_PARALLEL_TASKS_MAX: () => MESH_MAX_PARALLEL_TASKS_MAX,
21293
+ MESH_MAX_PARALLEL_TASKS_MIN: () => MESH_MAX_PARALLEL_TASKS_MIN,
21113
21294
  MESH_MISSION_STATUSES: () => MESH_MISSION_STATUSES,
21114
21295
  MESH_NODE_LIVE_TRUTH_MARKER: () => MESH_NODE_LIVE_TRUTH_MARKER,
21115
21296
  MESH_REFINE_CONFIG_LOCATIONS: () => MESH_REFINE_CONFIG_LOCATIONS,
@@ -21160,6 +21341,7 @@ __export(index_exports, {
21160
21341
  buildMeshNodeCapabilityTags: () => buildMeshNodeCapabilityTags,
21161
21342
  buildMeshNodeDataFreshness: () => buildMeshNodeDataFreshness,
21162
21343
  buildMeshNodeProbeFreshness: () => buildMeshNodeProbeFreshness,
21344
+ buildMeshSchedulingRuntime: () => buildMeshSchedulingRuntime,
21163
21345
  buildMissionPromptSection: () => buildMissionPromptSection,
21164
21346
  buildP2pRelayFailurePayload: () => buildP2pRelayFailurePayload,
21165
21347
  buildPinnedGlobalInstallCommand: () => buildPinnedGlobalInstallCommand,
@@ -21308,11 +21490,13 @@ __export(index_exports, {
21308
21490
  markSetupComplete: () => markSetupComplete,
21309
21491
  markStaleDirectDispatches: () => markStaleDirectDispatches,
21310
21492
  maybeRunDaemonUpgradeHelperFromEnv: () => maybeRunDaemonUpgradeHelperFromEnv,
21493
+ mergeAndNormalizePolicy: () => mergeAndNormalizePolicy,
21311
21494
  meshNodeIdMatches: () => meshNodeIdMatches,
21312
21495
  namedKeyToAnsi: () => namedKeyToAnsi,
21313
21496
  namedKeysToAnsi: () => namedKeysToAnsi,
21314
21497
  nodeSatisfiesRequiredTags: () => nodeSatisfiesRequiredTags,
21315
21498
  normalizeActiveChatData: () => normalizeActiveChatData,
21499
+ normalizeAutoFastForwardPolicy: () => normalizeAutoFastForwardPolicy,
21316
21500
  normalizeChatMessage: () => normalizeChatMessage,
21317
21501
  normalizeChatMessageKind: () => normalizeChatMessageKind,
21318
21502
  normalizeChatMessages: () => normalizeChatMessages,
@@ -21374,11 +21558,13 @@ __export(index_exports, {
21374
21558
  resolveDelegatedWorkerAutoApprove: () => resolveDelegatedWorkerAutoApprove,
21375
21559
  resolveDeliveryDecision: () => resolveDeliveryDecision,
21376
21560
  resolveGitRepository: () => resolveGitRepository,
21561
+ resolveMaxParallelTasks: () => resolveMaxParallelTasks,
21377
21562
  resolveMeshHostStatus: () => resolveMeshHostStatus,
21378
21563
  resolveMeshNodeAttribution: () => resolveMeshNodeAttribution,
21379
21564
  resolveMeshRefineValidationPlan: () => resolveMeshRefineValidationPlan,
21380
21565
  resolveMeshSurfacedSessionPreview: () => resolveMeshSurfacedSessionPreview,
21381
21566
  resolveNodeSchedulingPriority: () => resolveNodeSchedulingPriority,
21567
+ resolveProviderMaxParallel: () => resolveProviderMaxParallel,
21382
21568
  resolveSessionHostAppName: () => resolveSessionHostAppName,
21383
21569
  resolveSessionHostAppNameResolution: () => resolveSessionHostAppNameResolution,
21384
21570
  resolveWorktreePath: () => resolveWorktreePath,
@@ -23295,6 +23481,7 @@ function buildMeshLedgerReconciliationEvidence(meshId, replicas) {
23295
23481
  init_mesh_work_queue();
23296
23482
  init_mesh_active_work();
23297
23483
  init_mesh_refine_status();
23484
+ init_mesh_scheduling_runtime();
23298
23485
  init_mesh_host_ownership();
23299
23486
  init_mesh_events();
23300
23487
  init_mesh_events_utils();
@@ -39077,9 +39264,35 @@ var CliProviderInstance = class _CliProviderInstance {
39077
39264
  * terminal state. Leaving meshNodeFor pinned would route this session's
39078
39265
  * subsequent unrelated turns (e.g. ad-hoc dashboard chats) to the
39079
39266
  * coordinator as if they were task completions.
39267
+ *
39268
+ * MESHID-DROP-ON-DETACH (Fix C): a coordinator-LAUNCHED worker session
39269
+ * (launchedByCoordinator) holds its mesh membership (meshNodeFor / meshNodeId /
39270
+ * meshCoordinatorDaemonId) at the SESSION level — set once at launch
39271
+ * (mesh_launch_session / queue auto-launch), independent of any single task.
39272
+ * The original detach wiped meshNodeFor + meshNodeId together with the
39273
+ * task-level meshActiveTaskId, so the FIRST task completion stripped the
39274
+ * membership and EVERY subsequent completion forwarded with meshId absent —
39275
+ * resolveWorkerDelegateRouting fell to mesh_unresolved and the coordinator
39276
+ * rejected the forward "meshId required". For a launched member we therefore
39277
+ * clear ONLY the task-level marker (meshActiveTaskId) and preserve the
39278
+ * session-level membership so its next task's completion still resolves.
39279
+ * A task-less ad-hoc turn on a preserved-membership session is NOT misrouted:
39280
+ * its completion carries no taskId and the session holds no active assignment,
39281
+ * so the forwarder's WARMUPGAP guard skips the dispatch-row flip (it only
39282
+ * injects a benign task-less notification). A NON-launched session (a plain CLI
39283
+ * session adopted by mesh_send_task --direct, launchedByCoordinator falsy)
39284
+ * keeps the original full clear so an ad-hoc session is never left pinned.
39080
39285
  */
39081
39286
  detachMeshAssignment() {
39082
39287
  if (!this.settings.meshNodeFor && !this.settings.meshActiveTaskId && !this.settings.meshNodeId) return;
39288
+ if (this.settings.launchedByCoordinator === true) {
39289
+ if (!this.settings.meshActiveTaskId) return;
39290
+ const { meshActiveTaskId: meshActiveTaskId2, ...rest2 } = this.settings;
39291
+ void meshActiveTaskId2;
39292
+ this.settings = rest2;
39293
+ this.adapter.updateRuntimeSettings?.(this.settings);
39294
+ return;
39295
+ }
39083
39296
  const { meshNodeFor, meshNodeId, meshActiveTaskId, ...rest } = this.settings;
39084
39297
  void meshNodeFor;
39085
39298
  void meshActiveTaskId;
@@ -48948,6 +49161,9 @@ var meshStatusHandlers = {
48948
49161
  const { getMeshQueueStats: getMeshQueueStats2, getQueue: getQueue2 } = await Promise.resolve().then(() => (init_mesh_work_queue(), mesh_work_queue_exports));
48949
49162
  const queue = getQueue2(meshId);
48950
49163
  const queueSummary = getMeshQueueStats2(meshId);
49164
+ const { buildMeshSchedulingRuntime: buildMeshSchedulingRuntime2 } = await Promise.resolve().then(() => (init_mesh_scheduling_runtime(), mesh_scheduling_runtime_exports));
49165
+ const schedulingRuntime = buildMeshSchedulingRuntime2(mesh, queue);
49166
+ const schedulingByNode = new Map(schedulingRuntime.nodes.map((n) => [n.nodeId, n]));
48951
49167
  const { readLedgerEntries: readLedgerEntries2, getLedgerSummary: getLedgerSummary2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
48952
49168
  const ledgerEntries = readLedgerEntries2(meshId, { tail: 20 });
48953
49169
  const asyncRefineLedgerEntries = readLedgerEntries2(meshId, { tail: 100 });
@@ -49062,6 +49278,11 @@ var meshStatusHandlers = {
49062
49278
  activeSessionDetails: [],
49063
49279
  launchReady: false
49064
49280
  };
49281
+ const nodeScheduling = schedulingByNode.get(nodeId);
49282
+ if (nodeScheduling) {
49283
+ const { nodeId: _omitNodeId, ...nodeSchedulingRest } = nodeScheduling;
49284
+ status.scheduling = nodeSchedulingRest;
49285
+ }
49065
49286
  if (isSelfNode) {
49066
49287
  status.connection = {
49067
49288
  perspective: "selected_coordinator",
@@ -49262,6 +49483,19 @@ var meshStatusHandlers = {
49262
49483
  branchConvergenceSummary: summarizeInlineMeshBranchConvergence(nodeStatuses),
49263
49484
  ...previewFreshness ? { previewFreshness, deployFreshness: previewFreshness } : {},
49264
49485
  nodes: nodeStatuses,
49486
+ // Mesh-level scheduling rollup (strategy + global cap consumption). Mirrors
49487
+ // the MCP `mesh_status` tool's `scheduling` block field-for-field so both
49488
+ // surfaces read the same runtime; per-node detail lives on each
49489
+ // nodes[].scheduling above.
49490
+ scheduling: {
49491
+ strategy: schedulingRuntime.strategy,
49492
+ maxParallelTasks: schedulingRuntime.maxParallelTasks,
49493
+ maxReadonlyParallelTasks: schedulingRuntime.maxReadonlyParallelTasks,
49494
+ activeWriteAssigned: schedulingRuntime.activeWriteAssigned,
49495
+ activeReadonlyAssigned: schedulingRuntime.activeReadonlyAssigned,
49496
+ globalWriteCapReached: schedulingRuntime.globalWriteCapReached,
49497
+ globalReadonlyCapReached: schedulingRuntime.globalReadonlyCapReached
49498
+ },
49265
49499
  queue: { tasks: queue, summary: queueSummary },
49266
49500
  ledger: { entries: ledgerEntries, summary: ledgerSummary },
49267
49501
  ...missions.length > 0 ? { missions } : {},
@@ -62572,6 +62806,8 @@ var V1_CONTRACT_VERSION = "1.0.0";
62572
62806
  MAX_LEDGER_SLICE_LIMIT,
62573
62807
  MESH_CONVERGE_FAST_FORWARD_TAG,
62574
62808
  MESH_CONVERGE_REFINE_TAG,
62809
+ MESH_MAX_PARALLEL_TASKS_MAX,
62810
+ MESH_MAX_PARALLEL_TASKS_MIN,
62575
62811
  MESH_MISSION_STATUSES,
62576
62812
  MESH_NODE_LIVE_TRUTH_MARKER,
62577
62813
  MESH_REFINE_CONFIG_LOCATIONS,
@@ -62622,6 +62858,7 @@ var V1_CONTRACT_VERSION = "1.0.0";
62622
62858
  buildMeshNodeCapabilityTags,
62623
62859
  buildMeshNodeDataFreshness,
62624
62860
  buildMeshNodeProbeFreshness,
62861
+ buildMeshSchedulingRuntime,
62625
62862
  buildMissionPromptSection,
62626
62863
  buildP2pRelayFailurePayload,
62627
62864
  buildPinnedGlobalInstallCommand,
@@ -62770,11 +63007,13 @@ var V1_CONTRACT_VERSION = "1.0.0";
62770
63007
  markSetupComplete,
62771
63008
  markStaleDirectDispatches,
62772
63009
  maybeRunDaemonUpgradeHelperFromEnv,
63010
+ mergeAndNormalizePolicy,
62773
63011
  meshNodeIdMatches,
62774
63012
  namedKeyToAnsi,
62775
63013
  namedKeysToAnsi,
62776
63014
  nodeSatisfiesRequiredTags,
62777
63015
  normalizeActiveChatData,
63016
+ normalizeAutoFastForwardPolicy,
62778
63017
  normalizeChatMessage,
62779
63018
  normalizeChatMessageKind,
62780
63019
  normalizeChatMessages,
@@ -62836,11 +63075,13 @@ var V1_CONTRACT_VERSION = "1.0.0";
62836
63075
  resolveDelegatedWorkerAutoApprove,
62837
63076
  resolveDeliveryDecision,
62838
63077
  resolveGitRepository,
63078
+ resolveMaxParallelTasks,
62839
63079
  resolveMeshHostStatus,
62840
63080
  resolveMeshNodeAttribution,
62841
63081
  resolveMeshRefineValidationPlan,
62842
63082
  resolveMeshSurfacedSessionPreview,
62843
63083
  resolveNodeSchedulingPriority,
63084
+ resolveProviderMaxParallel,
62844
63085
  resolveSessionHostAppName,
62845
63086
  resolveSessionHostAppNameResolution,
62846
63087
  resolveWorktreePath,