@adhdev/daemon-core 0.9.82-rc.484 → 0.9.82-rc.486

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.js CHANGED
@@ -145,7 +145,8 @@ var init_repo_mesh_types = __esm({
145
145
  "first_eligible",
146
146
  "least_loaded",
147
147
  "round_robin",
148
- "priority_only"
148
+ "priority_only",
149
+ "fitness"
149
150
  ];
150
151
  DEFAULT_MESH_SCHEDULING_STRATEGY = "first_eligible";
151
152
  MESH_CONVERGE_REFINE_TAG = "converge=refine";
@@ -157,7 +158,11 @@ var init_repo_mesh_types = __esm({
157
158
  allowAutoPublishSubmoduleMainCommits: false,
158
159
  requireApprovalForDestructiveGit: true,
159
160
  dirtyWorkspaceBehavior: "warn",
160
- maxParallelTasks: 2,
161
+ // Mesh-wide task cap is effectively unlimited by default: the real concurrency
162
+ // limits live per node / per capability slot (ORCHESTRATION_NODE_SLOTS.md), so a
163
+ // global ceiling is rarely meaningful. The UI hides this control; set it via the
164
+ // API only to impose a deliberate mesh-wide cap.
165
+ maxParallelTasks: 200,
161
166
  // Coordinator-spawned worker sessions default to hidden so the dashboard is not
162
167
  // flooded with mesh noise tabs/notifications. Users can still surface or unmute
163
168
  // any specific session manually; that override is preserved per-device.
@@ -409,10 +414,10 @@ function readInjected(value) {
409
414
  }
410
415
  function getDaemonBuildInfo() {
411
416
  if (cached) return cached;
412
- const commit = readInjected(true ? "a503a00d57fbcdc84cd252c6d5caee90cfae6706" : void 0) ?? "unknown";
413
- const commitShort = readInjected(true ? "a503a00d" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
414
- const version = readInjected(true ? "0.9.82-rc.484" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
415
- const builtAt = readInjected(true ? "2026-07-08T13:24:54.463Z" : void 0);
417
+ const commit = readInjected(true ? "cae0f42043ded25e4d3bed93d9f658035c09e007" : void 0) ?? "unknown";
418
+ const commitShort = readInjected(true ? "cae0f420" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
419
+ const version = readInjected(true ? "0.9.82-rc.486" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
420
+ const builtAt = readInjected(true ? "2026-07-09T23:19:53.642Z" : void 0);
416
421
  cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
417
422
  return cached;
418
423
  }
@@ -2798,6 +2803,74 @@ function normalizeDifficultyBrainMap(raw) {
2798
2803
  }
2799
2804
  return out;
2800
2805
  }
2806
+ function normalizeNodeCapabilitySlot(raw) {
2807
+ const r = raw && typeof raw === "object" ? raw : {};
2808
+ const provider = typeof r.provider === "string" ? r.provider.trim() : "";
2809
+ if (!provider) return null;
2810
+ const model = typeof r.model === "string" ? r.model.trim() : "";
2811
+ const thinkingLevel = typeof r.thinkingLevel === "string" ? r.thinkingLevel.trim() : "";
2812
+ const difficulty = Array.isArray(r.difficulty) ? r.difficulty.filter(isMeshTaskDifficulty) : [];
2813
+ const capability = Array.isArray(r.capability) ? r.capability.filter((t) => typeof t === "string" && !!t.trim()).map((t) => t.trim()) : [];
2814
+ const maxParallelNum = Number(r.maxParallel);
2815
+ const maxParallel = Number.isFinite(maxParallelNum) && maxParallelNum > 0 ? Math.floor(maxParallelNum) : void 0;
2816
+ return {
2817
+ provider,
2818
+ ...model ? { model } : {},
2819
+ ...thinkingLevel ? { thinkingLevel } : {},
2820
+ ...difficulty.length ? { difficulty } : {},
2821
+ ...capability.length ? { capability } : {},
2822
+ ...maxParallel !== void 0 ? { maxParallel } : {}
2823
+ };
2824
+ }
2825
+ function normalizeNodeCapabilitySlots(raw) {
2826
+ if (!Array.isArray(raw)) return [];
2827
+ const out = [];
2828
+ for (const entry of raw) {
2829
+ const slot = normalizeNodeCapabilitySlot(entry);
2830
+ if (slot) out.push(slot);
2831
+ }
2832
+ return out;
2833
+ }
2834
+ function deriveSlotsFromLegacy(input) {
2835
+ const priority = Array.isArray(input.providerPriority) ? input.providerPriority.filter((p) => typeof p === "string" && !!p.trim()).map((p) => p.trim()) : [];
2836
+ if (priority.length === 0) return [];
2837
+ const roleCap = /* @__PURE__ */ new Map();
2838
+ for (const role of input.providerRoles || []) {
2839
+ if (role && typeof role.providerType === "string" && Number.isFinite(role.maxParallel)) {
2840
+ roleCap.set(role.providerType.trim(), Math.floor(Number(role.maxParallel)));
2841
+ }
2842
+ }
2843
+ const brains = input.difficultyBrains || {};
2844
+ const byProvider = /* @__PURE__ */ new Map();
2845
+ const shared = [];
2846
+ for (const diff of MESH_TASK_DIFFICULTIES) {
2847
+ const b = brains[diff];
2848
+ if (!b) continue;
2849
+ const entry = { difficulty: diff, model: b.model, thinkingLevel: b.thinkingLevel };
2850
+ if (b.provider) {
2851
+ const list = byProvider.get(b.provider) ?? [];
2852
+ list.push(entry);
2853
+ byProvider.set(b.provider, list);
2854
+ } else {
2855
+ shared.push(entry);
2856
+ }
2857
+ }
2858
+ return priority.map((provider) => {
2859
+ const specific = byProvider.get(provider) || [];
2860
+ const applied = specific.length ? specific : shared;
2861
+ const difficulty = applied.map((a) => a.difficulty);
2862
+ const model = applied.find((a) => a.model)?.model;
2863
+ const thinkingLevel = applied.find((a) => a.thinkingLevel)?.thinkingLevel;
2864
+ const maxParallel = roleCap.get(provider);
2865
+ return {
2866
+ provider,
2867
+ ...model ? { model } : {},
2868
+ ...thinkingLevel ? { thinkingLevel } : {},
2869
+ ...difficulty.length ? { difficulty } : {},
2870
+ ...maxParallel !== void 0 ? { maxParallel } : {}
2871
+ };
2872
+ });
2873
+ }
2801
2874
  var DAEMON_ID_PREFIXES, MAGI_RAW_ANSWER_CAP, MESH_TASK_DIFFICULTIES, DEFAULT_DIFFICULTY_BRAINS, CANONICAL_MESH_TOOL_NAMES, CANONICAL_MESH_TOOL_COUNT;
2802
2875
  var init_dist = __esm({
2803
2876
  "../mesh-shared/dist/index.mjs"() {
@@ -2853,7 +2926,9 @@ var init_dist = __esm({
2853
2926
  "mesh_magi_review",
2854
2927
  "mesh_magi_collect",
2855
2928
  "mesh_magi_kind_panel_set",
2856
- "mesh_magi_kind_panel_list"
2929
+ "mesh_magi_kind_panel_list",
2930
+ "mesh_node_slots_set",
2931
+ "mesh_node_slots_list"
2857
2932
  ];
2858
2933
  CANONICAL_MESH_TOOL_COUNT = CANONICAL_MESH_TOOL_NAMES.length;
2859
2934
  }
@@ -3802,6 +3877,7 @@ function buildRulesSection(coordinatorCliType) {
3802
3877
  - **Reuse idle sessions.** For follow-up, retry, commit/push, or cleanup on the same issue, send only the delta to the existing idle session. Start fresh only for independent work, provider mismatch, transcript contamination, or required worktree isolation.
3803
3878
  - **Worktree affinity.** A worktree is a durable per-branch workspace; keep all of a branch's code_change/fix/review work on its worktree node by targeting \`required_tags: ["worktree=<branch>"]\` or \`target_node_id\`. Get the id/branch from the \`mesh_clone_node\` result or a live \`mesh_status\` \u2014 the Configured Nodes snapshot won't list a worktree cloned after launch. Untargeted same-branch follow-ups drift to the base node. Only \`convergence\` (merge/push) runs on the base, never pinned to the worktree.
3804
3879
  - **Classify task difficulty to save tokens.** For each task you enqueue, judge its execution difficulty and pass \`difficulty\`: \`easy\` (extraction, renames, doc tweaks, trivial fixes), \`medium\` (ordinary feature/bugfix work), \`difficult\` (architecture, tricky debugging, multi-file refactors, subtle reasoning), or \`freeform\`. The mesh's per-difficulty brain preset then runs easy tasks on a cheaper model at low reasoning effort and hard tasks on a stronger model at high effort \u2014 real token savings on simple work. The current presets are shown in the "Brain presets" section below. You may still pass an explicit \`model\`/\`thinkingLevel\` to override the preset for one task.
3880
+ - **Retune node profiles when routing is a poor fit \u2014 but only with approval.** A node's capability slots (its provider/model/thinking + difficulty range + capability tags, seen via \`mesh_node_slots_list\`) are what task\u2192node fitness routing matches against. If you notice a persistent mismatch \u2014 e.g. every \`difficult\` task lands on a node whose only slot is a cheap model, or a capability a node clearly has isn't declared \u2014 you MAY propose a slot change with \`mesh_node_slots_set\` (write=false). That returns current-vs-proposed; present that diff to the user with a one-line reason and apply (write=true) ONLY after they approve. It is a WHOLESALE replacement of the node's slots, so include the slots you want to keep. Never rewrite a node's profile silently or without a clear routing reason.
3805
3881
  - **Respect explicit provider requests.** Map: Hermes \u2192 \`hermes-cli\`, Claude/Claude Code \u2192 \`claude-cli\`, Codex \u2192 \`codex-cli\`, Gemini \u2192 \`gemini-cli\`, Antigravity \u2192 \`antigravity-cli\`. Never substitute the coordinator's own runtime.
3806
3882
  - **Verify via git, not source.** Use \`mesh_git_status\` to confirm side effects. Treat agent summaries as self-reports, not verification.
3807
3883
  - **Limit parallelism.** Start with 1\u20132 tasks; scale only on success. Never duplicate a session because \`mesh_read_chat\` shows no final message while tool/terminal activity is ongoing. This caps *concurrent* load \u2014 it does not mean serialize independent work: when a new, independent request arrives and there is headroom under \`maxParallelTasks\`, dispatch it right away rather than waiting for an in-flight task or a user nudge (read-only diagnosis especially, since it has no merge cost).
@@ -3882,7 +3958,9 @@ var init_coordinator_prompt = __esm({
3882
3958
  | \`mesh_magi_review\` | Cross-verify a read-only investigation across a standing panel of independent mesh agents (different machines/providers) instead of a single worker |
3883
3959
  | \`mesh_magi_collect\` | Collect + synthesize a previously dispatched MAGI fan-out by its consensus group id (async companion to mesh_magi_review wait:false) |
3884
3960
  | \`mesh_magi_kind_panel_set\` | Bind a task_kind \u2192 MAGI kind-panel slots (the SOLE MAGI panel-resolution surface; machine-local, wholesale replacement \u2014 approve current-vs-new first) |
3885
- | \`mesh_magi_kind_panel_list\` | List configured task_kind \u2192 MAGI kind-panel slot bindings (machine-local, read-only) |`;
3961
+ | \`mesh_magi_kind_panel_list\` | List configured task_kind \u2192 MAGI kind-panel slot bindings (machine-local, read-only) |
3962
+ | \`mesh_node_slots_list\` | List a node's capability slots (its AI-tool profile: provider/model/thinking + difficulty range + capability tags), read-only |
3963
+ | \`mesh_node_slots_set\` | PROPOSE (dry-run) or APPLY a node's capability slots \u2014 how you autonomously retune a node's tool profile; WHOLESALE replacement, present current-vs-proposed and get user approval before write=true |`;
3886
3964
  TOOL_EXPOSURE_PREFLIGHT_SECTION = `## Tool Exposure Preflight
3887
3965
 
3888
3966
  Before doing any coordinator work, confirm that the actual callable tool list includes \`mesh_status\` and the other \`mesh_*\` tools from the table above. If this Repo Mesh coordinator prompt is present but the callable \`mesh_*\` tools are missing, the MCP server/tool manifest is stale or not injected yet. Do not substitute terminal/file/git tools, do not inspect or edit the repository directly, and do not continue as a non-mesh local coding agent. Stop immediately and tell the user to run \`/reload-mcp\` or start a fresh coordinator session so ADHDev can reconnect \`adhdev-mesh\`.`;
@@ -5830,6 +5908,7 @@ function enqueueTask(meshId, message, opts) {
5830
5908
  const maxRetries = typeof opts?.maxRetries === "number" && Number.isFinite(opts.maxRetries) && opts.maxRetries >= 0 ? Math.floor(opts.maxRetries) : void 0;
5831
5909
  let effectiveModel = typeof opts?.model === "string" && opts.model.trim() ? opts.model.trim() : void 0;
5832
5910
  let effectiveThinkingLevel = typeof opts?.thinkingLevel === "string" && opts.thinkingLevel.trim() ? opts.thinkingLevel.trim() : void 0;
5911
+ const taskDifficulty = isMeshTaskDifficulty(opts?.difficulty) ? opts.difficulty : void 0;
5833
5912
  if (isMeshTaskDifficulty(opts?.difficulty)) {
5834
5913
  try {
5835
5914
  const preset = getDifficultyBrains()[opts.difficulty];
@@ -5873,6 +5952,7 @@ function enqueueTask(meshId, message, opts) {
5873
5952
  ...typeof opts?.consensusGroupId === "string" && opts.consensusGroupId.trim() ? { consensusGroupId: opts.consensusGroupId.trim() } : {},
5874
5953
  ...effectiveModel ? { model: effectiveModel } : {},
5875
5954
  ...effectiveThinkingLevel ? { thinkingLevel: effectiveThinkingLevel } : {},
5955
+ ...taskDifficulty ? { difficulty: taskDifficulty } : {},
5876
5956
  ...typeof opts?.sourceCoordinatorSessionId === "string" && opts.sourceCoordinatorSessionId.trim() ? { sourceCoordinatorSessionId: opts.sourceCoordinatorSessionId.trim() } : {},
5877
5957
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
5878
5958
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
@@ -15355,6 +15435,24 @@ function getMeshWithCache(components, meshId) {
15355
15435
  if (!cachedMesh) return localMesh;
15356
15436
  return mergeInlineCacheOnlyNodes(localMesh, cachedMesh);
15357
15437
  }
15438
+ function bootstrapEpochMs(bootstrap) {
15439
+ const raw = readNonEmptyString2(bootstrap?.startedAt) || readNonEmptyString2(bootstrap?.completedAt);
15440
+ if (!raw) return 0;
15441
+ const parsed = Date.parse(raw);
15442
+ return Number.isFinite(parsed) ? parsed : 0;
15443
+ }
15444
+ function inlineBootstrapIsFresher(inlineBootstrap, configBootstrap) {
15445
+ const inlineStatus = readNonEmptyString2(inlineBootstrap?.status);
15446
+ if (!inlineStatus) return false;
15447
+ const configStatus = readNonEmptyString2(configBootstrap?.status);
15448
+ const inlineTerminal = BOOTSTRAP_TERMINAL_STATUSES.has(inlineStatus);
15449
+ const configTerminal = !!configStatus && BOOTSTRAP_TERMINAL_STATUSES.has(configStatus);
15450
+ if (configTerminal) {
15451
+ return inlineTerminal && inlineStatus !== configStatus && bootstrapEpochMs(inlineBootstrap) > bootstrapEpochMs(configBootstrap);
15452
+ }
15453
+ if (inlineTerminal) return true;
15454
+ return bootstrapEpochMs(inlineBootstrap) > bootstrapEpochMs(configBootstrap);
15455
+ }
15358
15456
  function mergeInlineCacheOnlyNodes(localMesh, cachedMesh) {
15359
15457
  const localNodes = Array.isArray(localMesh?.nodes) ? localMesh.nodes : [];
15360
15458
  const cachedNodes = Array.isArray(cachedMesh?.nodes) ? cachedMesh.nodes : [];
@@ -15371,8 +15469,8 @@ function mergeInlineCacheOnlyNodes(localMesh, cachedMesh) {
15371
15469
  const localId = readMeshNodeId(localNode);
15372
15470
  if (!localId) continue;
15373
15471
  const inlineMatch = cachedNodes.find((cachedNode) => meshNodeIdMatches(cachedNode, localId));
15374
- const inlineBootstrapStatus = readNonEmptyString2(inlineMatch?.worktreeBootstrap?.status);
15375
- if (!inlineMatch || !inlineBootstrapStatus) continue;
15472
+ if (!inlineMatch) continue;
15473
+ if (!inlineBootstrapIsFresher(inlineMatch.worktreeBootstrap, localNode.worktreeBootstrap)) continue;
15376
15474
  if (!overlaid) {
15377
15475
  overlaidLocalNodes = [...localNodes];
15378
15476
  overlaid = true;
@@ -15844,8 +15942,16 @@ function nodeHasActiveAssignment(meshId, nodeId) {
15844
15942
  function nodeActiveLoad(meshId, nodeId) {
15845
15943
  return MeshRuntimeStore.getInstance().nodeActiveAssignmentCount(meshId, nodeId);
15846
15944
  }
15945
+ function meshHasExplicitSlots(mesh) {
15946
+ const nodes = Array.isArray(mesh?.nodes) ? mesh.nodes : [];
15947
+ return nodes.some((n) => normalizeNodeCapabilitySlots(n?.policy?.slots).length > 0);
15948
+ }
15847
15949
  function resolveSchedulingStrategy(mesh) {
15848
- return normalizeMeshSchedulingStrategy(mesh?.policy?.schedulingStrategy);
15950
+ const raw = mesh?.policy?.schedulingStrategy;
15951
+ if (typeof raw === "string" && raw.trim()) {
15952
+ return normalizeMeshSchedulingStrategy(raw);
15953
+ }
15954
+ return meshHasExplicitSlots(mesh) ? "fitness" : normalizeMeshSchedulingStrategy(void 0);
15849
15955
  }
15850
15956
  function buildSchedulingPool(localCandidates, remoteCandidates) {
15851
15957
  const pool = [...localCandidates, ...remoteCandidates].map((c) => ({
@@ -15859,10 +15965,68 @@ function buildSchedulingPool(localCandidates, remoteCandidates) {
15859
15965
  }));
15860
15966
  return { pool, uniqueNodes };
15861
15967
  }
15968
+ function resolveNodeCapabilitySlots(node) {
15969
+ const explicit = normalizeNodeCapabilitySlots(node?.policy?.slots);
15970
+ if (explicit.length) return explicit;
15971
+ let difficultyBrains;
15972
+ try {
15973
+ difficultyBrains = getDifficultyBrains();
15974
+ } catch {
15975
+ difficultyBrains = void 0;
15976
+ }
15977
+ return deriveSlotsFromLegacy({
15978
+ providerPriority: normalizeProviderPriority(node?.policy),
15979
+ providerRoles: Array.isArray(node?.policy?.providerRoles) ? node.policy.providerRoles : void 0,
15980
+ difficultyBrains
15981
+ });
15982
+ }
15983
+ function scoreSlotForTask(slot, task) {
15984
+ let score = 1;
15985
+ const diff = isMeshTaskDifficulty(task.difficulty) ? task.difficulty : void 0;
15986
+ if (diff) {
15987
+ if (slot.difficulty?.length) {
15988
+ score += slot.difficulty.includes(diff) ? 100 : 0;
15989
+ } else {
15990
+ score += 20;
15991
+ }
15992
+ }
15993
+ const req = task.requiredTags?.filter((t) => !!t) ?? [];
15994
+ if (req.length) {
15995
+ const cap = new Set(slot.capability ?? []);
15996
+ const covered = req.every((t) => cap.has(t));
15997
+ score += covered ? 30 : 0;
15998
+ }
15999
+ return score;
16000
+ }
16001
+ function bestSlotForTask(node, task) {
16002
+ const slots = resolveNodeCapabilitySlots(node);
16003
+ if (!slots.length) return null;
16004
+ let best = null;
16005
+ for (const slot of slots) {
16006
+ const score = scoreSlotForTask(slot, task);
16007
+ if (!best || score > best.score) best = { slot, score };
16008
+ }
16009
+ return best;
16010
+ }
16011
+ function nodeFitnessForTask(node, task) {
16012
+ return bestSlotForTask(node, task)?.score ?? 0;
16013
+ }
15862
16014
  function orderEligibleNodes(meshId, strategy, nodes, opts) {
15863
16015
  if (strategy === "first_eligible" || nodes.length <= 1) {
15864
16016
  return nodes;
15865
16017
  }
16018
+ if (strategy === "fitness" && opts?.task) {
16019
+ const task = opts.task;
16020
+ return [...nodes].sort((a, b) => {
16021
+ const fitDelta = nodeFitnessForTask(b.node, task) - nodeFitnessForTask(a.node, task);
16022
+ if (fitDelta !== 0) return fitDelta;
16023
+ const prioDelta = resolveNodeSchedulingPriority(b.node?.policy) - resolveNodeSchedulingPriority(a.node?.policy);
16024
+ if (prioDelta !== 0) return prioDelta;
16025
+ const loadDelta = nodeActiveLoad(meshId, a.nodeId) - nodeActiveLoad(meshId, b.nodeId);
16026
+ if (loadDelta !== 0) return loadDelta;
16027
+ return a.index - b.index;
16028
+ });
16029
+ }
15866
16030
  const priorityOf = (n) => resolveNodeSchedulingPriority(n.node?.policy);
15867
16031
  let rotation = 0;
15868
16032
  if (strategy === "least_loaded" || strategy === "round_robin") {
@@ -16006,13 +16170,15 @@ function markAutoLaunch(meshId, taskId, args) {
16006
16170
  retractActionableSkipIfPreviouslyNotified(meshId, taskId);
16007
16171
  }
16008
16172
  }
16009
- async function resolveUsableProvider(components, nodeId, node, requiredTags) {
16010
- const providerPriority = normalizeProviderPriority(node?.policy);
16011
- if (!providerPriority.length) return { reason: "missing_provider_priority" };
16173
+ async function resolveUsableProvider(components, nodeId, node, requiredTags, task) {
16012
16174
  const providerLoader = components.providerLoader;
16013
16175
  if (!providerLoader) return { reason: "provider_loader_unavailable" };
16176
+ const slots = resolveNodeCapabilitySlots(node);
16177
+ if (!slots.length) return { reason: "missing_provider_priority" };
16178
+ const orderedSlots = task ? [...slots].sort((a, b) => scoreSlotForTask(b, task) - scoreSlotForTask(a, task)) : slots;
16014
16179
  const failed = [];
16015
- for (const requestedType of providerPriority) {
16180
+ for (const slot of orderedSlots) {
16181
+ const requestedType = slot.provider;
16016
16182
  const normalizedType = typeof providerLoader.resolveAlias === "function" ? providerLoader.resolveAlias(requestedType) : requestedType;
16017
16183
  if (requiredTags?.length && !nodeSatisfiesRequiredTags(requiredTags, buildMeshNodeCapabilityTags(node, normalizedType))) {
16018
16184
  failed.push(`${requestedType}: required_tags_mismatch`);
@@ -16037,7 +16203,13 @@ async function resolveUsableProvider(components, nodeId, node, requiredTags) {
16037
16203
  }], false);
16038
16204
  }
16039
16205
  components.onStatusChange?.();
16040
- if (detected) return { providerType: normalizedType };
16206
+ if (detected) {
16207
+ return {
16208
+ providerType: normalizedType,
16209
+ ...slot.model ? { model: slot.model } : {},
16210
+ ...slot.thinkingLevel ? { thinkingLevel: slot.thinkingLevel } : {}
16211
+ };
16212
+ }
16041
16213
  failed.push(`${requestedType}: not detected`);
16042
16214
  }
16043
16215
  return { reason: `provider_priority_unusable: ${failed.join("; ") || nodeId}` };
@@ -16165,7 +16337,9 @@ async function maybeAutoLaunchOneQueueSession(components, meshId, mesh) {
16165
16337
  meshId,
16166
16338
  strategy,
16167
16339
  candidateNodes.map((node, index) => ({ nodeId: readMeshNodeId(node), node, index })).filter((c) => c.nodeId),
16168
- { bumpCursor: true }
16340
+ // Auto-launch drains one task at a time, so the task IS in scope here —
16341
+ // pass it through for the 'fitness' strategy's task→slot ranking.
16342
+ { bumpCursor: true, task: { difficulty: task.difficulty, requiredTags: task.requiredTags } }
16169
16343
  ).map((c) => c.node);
16170
16344
  for (const node of orderedCandidateNodes) {
16171
16345
  const nodeId = readMeshNodeId(node);
@@ -16212,11 +16386,13 @@ async function maybeAutoLaunchOneQueueSession(components, meshId, mesh) {
16212
16386
  }
16213
16387
  autoLaunchInProgress.add(launchKey);
16214
16388
  try {
16215
- const resolved = await resolveUsableProvider(components, nodeId, node, task.requiredTags);
16389
+ const resolved = await resolveUsableProvider(components, nodeId, node, task.requiredTags, { difficulty: task.difficulty, requiredTags: task.requiredTags });
16216
16390
  if (!resolved.providerType) {
16217
16391
  markAutoLaunch(meshId, task.id, { status: "skipped", reason: resolved.reason || "provider_unusable", nodeId });
16218
16392
  continue;
16219
16393
  }
16394
+ const effectiveModel = typeof task.model === "string" && task.model.trim() ? task.model.trim() : resolved.model;
16395
+ const effectiveThinkingLevel = typeof task.thinkingLevel === "string" && task.thinkingLevel.trim() ? task.thinkingLevel.trim() : resolved.thinkingLevel;
16220
16396
  const providerCap = resolveProviderMaxParallel(node?.policy, resolved.providerType);
16221
16397
  if (providerCap !== void 0 && activeProviderAssignedCount(meshId, nodeId, resolved.providerType) >= providerCap) {
16222
16398
  markAutoLaunch(meshId, task.id, { status: "skipped", reason: "max_provider_parallel_reached", nodeId, providerType: resolved.providerType });
@@ -16250,9 +16426,10 @@ async function maybeAutoLaunchOneQueueSession(components, meshId, mesh) {
16250
16426
  settings: remoteSettings,
16251
16427
  // MAGI-KIND-PANEL model axis: forward the task's model override so the
16252
16428
  // remote worker session launches with it (initialModel). Best-effort.
16253
- ...typeof task.model === "string" && task.model.trim() ? { initialModel: task.model.trim() } : {},
16254
- // BRAIN-ROUTING thinking axis: forward the task's thinking level (initialThinkingLevel).
16255
- ...typeof task.thinkingLevel === "string" && task.thinkingLevel.trim() ? { initialThinkingLevel: task.thinkingLevel.trim() } : {}
16429
+ // Slot-aware: task override wins, else the matched slot's model.
16430
+ ...effectiveModel ? { initialModel: effectiveModel } : {},
16431
+ // BRAIN-ROUTING thinking axis: forward the effective thinking level (initialThinkingLevel).
16432
+ ...effectiveThinkingLevel ? { initialThinkingLevel: effectiveThinkingLevel } : {}
16256
16433
  });
16257
16434
  } catch (e) {
16258
16435
  markAutoLaunch(meshId, task.id, { status: "failed", reason: `remote_launch_dispatch_failed: ${e?.message || String(e)}`, nodeId, providerType: resolved.providerType });
@@ -16279,11 +16456,11 @@ async function maybeAutoLaunchOneQueueSession(components, meshId, mesh) {
16279
16456
  cliType: resolved.providerType,
16280
16457
  dir: node.workspace,
16281
16458
  settings: launchSettings,
16282
- // MAGI-KIND-PANEL model axis: local launch forwards the task's model
16283
- // override as initialModel (CLI → modelLaunchArgs; ACP → setConfigOption).
16284
- ...typeof task.model === "string" && task.model.trim() ? { initialModel: task.model.trim() } : {},
16285
- // BRAIN-ROUTING thinking axis: forward the task's thinking level (initialThinkingLevel).
16286
- ...typeof task.thinkingLevel === "string" && task.thinkingLevel.trim() ? { initialThinkingLevel: task.thinkingLevel.trim() } : {}
16459
+ // MAGI-KIND-PANEL model axis: local launch forwards the effective model
16460
+ // (task override, else matched slot) as initialModel (CLI → modelLaunchArgs; ACP → setConfigOption).
16461
+ ...effectiveModel ? { initialModel: effectiveModel } : {},
16462
+ // BRAIN-ROUTING thinking axis: forward the effective thinking level (initialThinkingLevel).
16463
+ ...effectiveThinkingLevel ? { initialThinkingLevel: effectiveThinkingLevel } : {}
16287
16464
  });
16288
16465
  if (!launchResult?.success) {
16289
16466
  const reason = launchResult?.error || "launch_cli_failed";
@@ -16418,7 +16595,7 @@ async function triggerMeshQueue(components, meshId) {
16418
16595
  const aPrio = resolveNodeSchedulingPriority(a.node?.policy);
16419
16596
  const bPrio = resolveNodeSchedulingPriority(b.node?.policy);
16420
16597
  if (aPrio !== bPrio) return bPrio - aPrio;
16421
- if (strategy === "least_loaded" || strategy === "round_robin") {
16598
+ if (strategy === "least_loaded" || strategy === "round_robin" || strategy === "fitness") {
16422
16599
  const loadDelta = nodeActiveLoad(meshId, a.nodeId) - nodeActiveLoad(meshId, b.nodeId);
16423
16600
  if (loadDelta !== 0) return loadDelta;
16424
16601
  }
@@ -16521,7 +16698,7 @@ function runIdleMaintenanceThenAssignQueue(components, args) {
16521
16698
  });
16522
16699
  });
16523
16700
  }
16524
- var import_fs13, IDLE_AUTO_FAST_FORWARD_THROTTLE_MS, idleAutoFastForwardLastAttempt, DISPATCH_CONFIRM_TIMEOUT_MS, DISPATCH_CONNECT_TIMEOUT_MS, dispatchWarmupGetterMissingWarned, LOCAL_LAUNCH_READY_TIMEOUT_MS, LOCAL_LAUNCH_READY_POLL_MS, autoLaunchInProgress, autoLaunchCooldownUntil, AUTO_LAUNCH_COOLDOWN_MS, AUTO_LAUNCH_AWAIT_CLAIM_MS, AUTO_LAUNCH_AWAIT_CLAIM_BACKOFF_CAP_CYCLES, AUTO_LAUNCH_REMOTE_IDLE_TTL_MS, autoLaunchAwaitClaimBackoff, lastAutoLaunchLedgerKey, AUTO_LAUNCH_LEDGER_DEDUP_MAX, ACTIONABLE_SKIP_REASON_PREFIXES, TRANSIENT_TARGET_NODE_BOOTSTRAP_PENDING_REASON, lastActionableSkipNotified;
16701
+ var import_fs13, IDLE_AUTO_FAST_FORWARD_THROTTLE_MS, idleAutoFastForwardLastAttempt, BOOTSTRAP_TERMINAL_STATUSES, DISPATCH_CONFIRM_TIMEOUT_MS, DISPATCH_CONNECT_TIMEOUT_MS, dispatchWarmupGetterMissingWarned, LOCAL_LAUNCH_READY_TIMEOUT_MS, LOCAL_LAUNCH_READY_POLL_MS, autoLaunchInProgress, autoLaunchCooldownUntil, AUTO_LAUNCH_COOLDOWN_MS, AUTO_LAUNCH_AWAIT_CLAIM_MS, AUTO_LAUNCH_AWAIT_CLAIM_BACKOFF_CAP_CYCLES, AUTO_LAUNCH_REMOTE_IDLE_TTL_MS, autoLaunchAwaitClaimBackoff, lastAutoLaunchLedgerKey, AUTO_LAUNCH_LEDGER_DEDUP_MAX, ACTIONABLE_SKIP_REASON_PREFIXES, TRANSIENT_TARGET_NODE_BOOTSTRAP_PENDING_REASON, lastActionableSkipNotified;
16525
16702
  var init_mesh_queue_assignment = __esm({
16526
16703
  "src/mesh/mesh-queue-assignment.ts"() {
16527
16704
  "use strict";
@@ -16549,6 +16726,7 @@ var init_mesh_queue_assignment = __esm({
16549
16726
  init_mesh_task_inflight();
16550
16727
  IDLE_AUTO_FAST_FORWARD_THROTTLE_MS = 30 * 60 * 1e3;
16551
16728
  idleAutoFastForwardLastAttempt = /* @__PURE__ */ new Map();
16729
+ BOOTSTRAP_TERMINAL_STATUSES = /* @__PURE__ */ new Set(["complete", "failed"]);
16552
16730
  DISPATCH_CONFIRM_TIMEOUT_MS = 12e4;
16553
16731
  DISPATCH_CONNECT_TIMEOUT_MS = MESH_CONNECT_TIMEOUT_MS;
16554
16732
  dispatchWarmupGetterMissingWarned = /* @__PURE__ */ new Set();
@@ -18412,6 +18590,22 @@ var init_provider_input_support = __esm({
18412
18590
  });
18413
18591
 
18414
18592
  // src/status/builders.ts
18593
+ function isCoordinatorSpawnedHiddenWorker(settings) {
18594
+ if (!settings) return false;
18595
+ return settings.launchedByCoordinator === true && typeof settings.meshNodeFor === "string" && settings.meshNodeFor.trim().length > 0 && settings.spawnedSessionVisibility === "hidden";
18596
+ }
18597
+ function resolveSurfaceHidden(settings) {
18598
+ if (!settings) return false;
18599
+ if (settings.userHidden === true) return true;
18600
+ if (settings.userHidden === false) return false;
18601
+ return settings.spawnedSessionVisibility === "hidden" || isCoordinatorSpawnedHiddenWorker(settings);
18602
+ }
18603
+ function resolveMuted(settings) {
18604
+ if (!settings) return false;
18605
+ if (settings.userMuted === true) return true;
18606
+ if (settings.userMuted === false) return false;
18607
+ return isCoordinatorSpawnedHiddenWorker(settings);
18608
+ }
18415
18609
  function getActiveChatOptions(profile) {
18416
18610
  if (profile === "full") return {};
18417
18611
  return LIVE_STATUS_ACTIVE_CHAT_OPTIONS;
@@ -18617,7 +18811,8 @@ function buildCliSession(state, options) {
18617
18811
  settings: state.settings,
18618
18812
  ...coordinator && { coordinator },
18619
18813
  ...meshQueueStats && { meshQueueStats },
18620
- ...state.settings?.spawnedSessionVisibility === "hidden" && { surfaceHidden: true }
18814
+ ...resolveSurfaceHidden(state.settings) && { surfaceHidden: true },
18815
+ ...resolveMuted(state.settings) && { muted: true }
18621
18816
  };
18622
18817
  }
18623
18818
  function buildAcpSession(state, options) {
@@ -18658,7 +18853,8 @@ function buildAcpSession(state, options) {
18658
18853
  settings: state.settings,
18659
18854
  ...coordinator && { coordinator },
18660
18855
  ...meshQueueStats && { meshQueueStats },
18661
- ...state.settings?.spawnedSessionVisibility === "hidden" && { surfaceHidden: true }
18856
+ ...resolveSurfaceHidden(state.settings) && { surfaceHidden: true },
18857
+ ...resolveMuted(state.settings) && { muted: true }
18662
18858
  };
18663
18859
  }
18664
18860
  function buildSessionEntries(allStates, cdpManagers, options = {}) {
@@ -25495,6 +25691,13 @@ var init_provider_cli_adapter = __esm({
25495
25691
  lastScreenSnapshot = "";
25496
25692
  lastScreenText = "";
25497
25693
  lastScreenSnapshotReadAt = Number.NEGATIVE_INFINITY;
25694
+ // (FALSEIDLE Path-C) Count of CONSECUTIVE getStatus polls that observed a
25695
+ // gate-eligible static-idle screen (detect=idle, no modal, quiet, empty
25696
+ // partial buffer). For a mesh/autonomous worker we require several such
25697
+ // polls in a row before confirming static-idle (see getStatus), so a
25698
+ // single momentarily-silent point-sample of a still-live turn cannot flip
25699
+ // it. Reset to 0 the instant any poll is ineligible.
25700
+ staticIdlePollStreak = 0;
25498
25701
  // Server log forwarding
25499
25702
  serverConn = null;
25500
25703
  logBuffer = [];
@@ -25560,6 +25763,13 @@ var init_provider_cli_adapter = __esm({
25560
25763
  static MAX_ACCUMULATED_BUFFER = 262144;
25561
25764
  parsedStatusCache = null;
25562
25765
  static SCREEN_SNAPSHOT_MIN_INTERVAL_MS = 250;
25766
+ // (FALSEIDLE Path-C) Consecutive gate-eligible getStatus polls a mesh/autonomous
25767
+ // session must show before the poll-static-idle confirm fires. 2 = one extra
25768
+ // status tick of hysteresis: enough to reject a single momentary-silence
25769
+ // point-sample of a still-live turn, cheap enough not to materially delay a
25770
+ // genuine boot-wedge release (the wedge screen is stably static, so it clears
25771
+ // every consecutive poll and confirms on the 2nd).
25772
+ static STATIC_IDLE_POLL_CONFIRM_COUNT = 2;
25563
25773
  providerResolutionMeta;
25564
25774
  getBufferState() {
25565
25775
  const build = (droppedChars, maxChars) => droppedChars > 0 ? { truncated: true, droppedChars, maxChars } : void 0;
@@ -25631,6 +25841,18 @@ ${lastSnapshot}`;
25631
25841
  getStatusActivityHoldMs() {
25632
25842
  return this.timeouts.statusActivityHold;
25633
25843
  }
25844
+ // (FALSEIDLE Path-C) Whether this session is a mesh worker or coordinator's
25845
+ // own autonomous session. Mirrors CliProviderInstance.isAutonomousMeshSession
25846
+ // over the runtimeSettings the instance mirrors down via updateRuntimeSettings
25847
+ // (meshNodeFor / meshActiveTaskId / meshNodeId / launchedByCoordinator =
25848
+ // isMeshWorkerSession, plus meshCoordinatorFor for the coordinator's own turn).
25849
+ // Such a session has no human at the keyboard to correct a premature idle, so
25850
+ // the poll-static-idle confirm is debounced for it (multiple consecutive idle
25851
+ // polls) rather than fired on a single point-sample.
25852
+ isAutonomousMeshSession() {
25853
+ const s2 = this.runtimeSettings;
25854
+ return !!(s2?.meshNodeFor || s2?.meshActiveTaskId || s2?.meshNodeId || s2?.launchedByCoordinator || s2?.meshCoordinatorFor);
25855
+ }
25634
25856
  // Resolved timeouts
25635
25857
  timeouts;
25636
25858
  // Provider approval key mapping
@@ -26018,14 +26240,27 @@ ${lastSnapshot}`;
26018
26240
  if (allowParse && this.engine.currentStatus === "generating" && !this.engine.currentTurnScope && !this.engine.activeModal) {
26019
26241
  const now = Date.now();
26020
26242
  const quietForMs = this.lastNonEmptyOutputAt ? now - this.lastNonEmptyOutputAt : Number.MAX_SAFE_INTEGER;
26243
+ let eligible = false;
26021
26244
  if (quietForMs >= this.getStatusActivityHoldMs()) {
26022
26245
  const screenText = this.terminalScreen.getText();
26023
26246
  const pollDetect = this.runDetectStatus(screenText || this.recentOutputBuffer);
26024
26247
  const pollModal = this.runParseApproval(screenText) || this.runParseApproval(this.recentOutputBuffer);
26025
- if (pollDetect === "idle" && !pollModal) {
26248
+ const partial = this.getPartialResponse();
26249
+ const partialPending = typeof partial === "string" && partial.trim().length > 0;
26250
+ eligible = pollDetect === "idle" && !pollModal && !partialPending;
26251
+ }
26252
+ if (eligible) {
26253
+ const requiredStreak = this.isAutonomousMeshSession() ? _ProviderCliAdapter.STATIC_IDLE_POLL_CONFIRM_COUNT : 1;
26254
+ this.staticIdlePollStreak += 1;
26255
+ if (this.staticIdlePollStreak >= requiredStreak) {
26026
26256
  this.engine.confirmPollStaticIdle("poll_static_idle");
26257
+ this.staticIdlePollStreak = 0;
26027
26258
  }
26259
+ } else {
26260
+ this.staticIdlePollStreak = 0;
26028
26261
  }
26262
+ } else {
26263
+ this.staticIdlePollStreak = 0;
26029
26264
  }
26030
26265
  let effectiveStatus = this.projectEffectiveStatus(startupModal);
26031
26266
  let effectiveModal = startupModal || this.engine.activeModal;
@@ -27581,6 +27816,7 @@ __export(index_exports, {
27581
27816
  appendRemoteLedgerEntries: () => appendRemoteLedgerEntries,
27582
27817
  assertNoDependencyCycle: () => assertNoDependencyCycle,
27583
27818
  buildAssistantChatMessage: () => buildAssistantChatMessage,
27819
+ buildAvailableProviders: () => buildAvailableProviders,
27584
27820
  buildChatMessage: () => buildChatMessage,
27585
27821
  buildChatMessageSignature: () => buildChatMessageSignature,
27586
27822
  buildChatTailDeliverySignature: () => buildChatTailDeliverySignature,
@@ -39439,11 +39675,15 @@ ${formatManifestValidationIssues2(validation.issues)}`,
39439
39675
  if (!manifestPath) continue;
39440
39676
  try {
39441
39677
  const m = JSON.parse(fs41.readFileSync(manifestPath, "utf-8"));
39678
+ const modelOptions = Array.isArray(m.modelOptions) ? m.modelOptions.filter((x) => typeof x === "string" && !!x.trim()) : [];
39679
+ const thinkingLevelOptions = Array.isArray(m.thinkingLevelOptions) ? m.thinkingLevelOptions.filter((x) => typeof x === "string" && !!x.trim()) : [];
39442
39680
  items.push({
39443
39681
  type,
39444
39682
  category,
39445
39683
  version: typeof m.providerVersion === "string" ? m.providerVersion : "0.0.0",
39446
- path: manifestPath
39684
+ path: manifestPath,
39685
+ ...modelOptions.length ? { modelOptions } : {},
39686
+ ...thinkingLevelOptions.length ? { thinkingLevelOptions } : {}
39447
39687
  });
39448
39688
  } catch {
39449
39689
  }
@@ -50227,6 +50467,31 @@ var cliAgentHandlers = {
50227
50467
  record_provider_pty: async (ctx, args) => {
50228
50468
  return ctx.deps.cliManager.handleCliCommand("record_provider_pty", args);
50229
50469
  },
50470
+ // Daemon-owned per-session user Mute/Hide. Replaces the old browser-local
50471
+ // localStorage layer: the user's manual hide/mute for a conversation is stored
50472
+ // in-memory on the live session's settings (userHidden / userMuted) and rides
50473
+ // the SAME status snapshot pipeline as the coordinator-policy surfaceHidden
50474
+ // flag, so every client of this daemon sees the same state. In-memory only —
50475
+ // resets on daemon restart (coordinator-spawned sessions re-derive their hidden
50476
+ // default from mesh policy on relaunch). Passing null/undefined for a field
50477
+ // leaves it unchanged; pass an explicit boolean to set, or false to clear an
50478
+ // earlier hide/mute (e.g. unmute a coordinator-spawned worker overrides the
50479
+ // policy default until restart).
50480
+ set_conversation_prefs: async (ctx, args) => {
50481
+ const sessionId = readStringValue(args?.sessionId, args?.targetSessionId, args?.instanceId);
50482
+ if (!sessionId) return { success: false, error: "sessionId required" };
50483
+ const inst = ctx.deps.instanceManager.getInstance(sessionId);
50484
+ if (!inst || typeof inst.updateSettings !== "function") {
50485
+ return { success: false, error: "Session not found or does not support preferences" };
50486
+ }
50487
+ const patch = {};
50488
+ if (typeof args?.hidden === "boolean") patch.userHidden = args.hidden;
50489
+ if (typeof args?.muted === "boolean") patch.userMuted = args.muted;
50490
+ if (!Object.keys(patch).length) return { success: false, error: "Nothing to update (hidden and/or muted required)" };
50491
+ inst.updateSettings(patch);
50492
+ ctx.deps.onStatusChange?.();
50493
+ return { success: true, sessionId, ...patch };
50494
+ },
50230
50495
  agent_command: async (ctx, args) => {
50231
50496
  {
50232
50497
  const dispatchSessionId = readStringValue(args?.targetSessionId, args?.sessionId, args?.instanceId);
@@ -56488,6 +56753,8 @@ var meshCoordinatorLaunchHandlers = {
56488
56753
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
56489
56754
  let cliType = typeof args?.cliType === "string" ? args.cliType.trim() : "";
56490
56755
  const extraSystemPrompt = typeof args?.extraSystemPrompt === "string" ? args.extraSystemPrompt.trim() : "";
56756
+ const initialModel = typeof args?.initialModel === "string" && args.initialModel.trim() ? args.initialModel.trim() : null;
56757
+ const initialThinkingLevel = typeof args?.initialThinkingLevel === "string" && args.initialThinkingLevel.trim() ? args.initialThinkingLevel.trim() : null;
56491
56758
  if (!meshId) return { success: false, error: "meshId required" };
56492
56759
  try {
56493
56760
  const { buildCoordinatorSystemPrompt: buildCoordinatorSystemPrompt2 } = await Promise.resolve().then(() => (init_coordinator_prompt(), coordinator_prompt_exports));
@@ -56758,7 +57025,9 @@ ${ptyResult.output.slice(-2e3)}`);
56758
57025
  dir: workspace,
56759
57026
  cliArgs: cliCmdArgs.length > 0 ? cliCmdArgs : void 0,
56760
57027
  env: Object.keys(cliCmdEnv).length > 0 ? cliCmdEnv : void 0,
56761
- settings: { meshCoordinatorFor: meshId }
57028
+ settings: { meshCoordinatorFor: meshId },
57029
+ ...initialModel ? { initialModel } : {},
57030
+ ...initialThinkingLevel ? { initialThinkingLevel } : {}
56762
57031
  });
56763
57032
  if (cliCmdLaunch?.success && cliCmdContextFilePath) {
56764
57033
  const stripPath = cliCmdContextFilePath;
@@ -56943,7 +57212,9 @@ ${ptyResult.output.slice(-2e3)}`);
56943
57212
  env: Object.keys(launchEnv).length > 0 ? launchEnv : void 0,
56944
57213
  settings: {
56945
57214
  meshCoordinatorFor: meshId
56946
- }
57215
+ },
57216
+ ...initialModel ? { initialModel } : {},
57217
+ ...initialThinkingLevel ? { initialThinkingLevel } : {}
56947
57218
  });
56948
57219
  if (launchResult?.success && autoImportContextFilePath) {
56949
57220
  const stripPath = autoImportContextFilePath;
@@ -57302,6 +57573,11 @@ var meshStatusHandlers = {
57302
57573
  ...node.reportedProviderVersions && typeof node.reportedProviderVersions === "object" ? { providerVersions: node.reportedProviderVersions } : {},
57303
57574
  ...typeof node.reportedDaemonBuildVersion === "string" && node.reportedDaemonBuildVersion ? { daemonBuildVersion: node.reportedDaemonBuildVersion } : {},
57304
57575
  providerPriority,
57576
+ // ORCHESTRATION_NODE_SLOTS.md: surface the node's capability
57577
+ // slots so the dashboard slot editor can read them. Only
57578
+ // emitted when explicitly configured (derived-from-legacy
57579
+ // slots stay implicit — the editor shows the legacy fields).
57580
+ ...Array.isArray(node.policy?.slots) && node.policy.slots.length ? { slots: normalizeNodeCapabilitySlots(node.policy.slots) } : {},
57305
57581
  activeSessions: [],
57306
57582
  activeSessionDetails: [],
57307
57583
  launchReady: false
@@ -70166,6 +70442,7 @@ var V1_CONTRACT_VERSION = "1.0.0";
70166
70442
  appendRemoteLedgerEntries,
70167
70443
  assertNoDependencyCycle,
70168
70444
  buildAssistantChatMessage,
70445
+ buildAvailableProviders,
70169
70446
  buildChatMessage,
70170
70447
  buildChatMessageSignature,
70171
70448
  buildChatTailDeliverySignature,