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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -404,10 +404,10 @@ function readInjected(value) {
404
404
  }
405
405
  function getDaemonBuildInfo() {
406
406
  if (cached) return cached;
407
- const commit = readInjected(true ? "0862a3f10fa9de60a46591c0894a7209534db2e2" : void 0) ?? "unknown";
408
- const commitShort = readInjected(true ? "0862a3f1" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
409
- const version = readInjected(true ? "0.9.82-rc.483" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
410
- const builtAt = readInjected(true ? "2026-07-08T04:27:00.139Z" : void 0);
407
+ const commit = readInjected(true ? "a503a00d57fbcdc84cd252c6d5caee90cfae6706" : void 0) ?? "unknown";
408
+ const commitShort = readInjected(true ? "a503a00d" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
409
+ const version = readInjected(true ? "0.9.82-rc.484" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
410
+ const builtAt = readInjected(true ? "2026-07-08T13:24:54.463Z" : void 0);
411
411
  cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
412
412
  return cached;
413
413
  }
@@ -2765,12 +2765,45 @@ function summarizeGitShape(status) {
2765
2765
  submodules
2766
2766
  };
2767
2767
  }
2768
- var DAEMON_ID_PREFIXES, MAGI_RAW_ANSWER_CAP, CANONICAL_MESH_TOOL_NAMES, CANONICAL_MESH_TOOL_COUNT;
2768
+ function isMeshTaskDifficulty(value) {
2769
+ return typeof value === "string" && MESH_TASK_DIFFICULTIES.includes(value);
2770
+ }
2771
+ function normalizeThinkingLevel(value) {
2772
+ const v = typeof value === "string" ? value.trim().toLowerCase() : "";
2773
+ return v === "low" || v === "medium" || v === "high" ? v : void 0;
2774
+ }
2775
+ function normalizeBrainSlot(raw) {
2776
+ const r = raw && typeof raw === "object" ? raw : {};
2777
+ const provider = typeof r.provider === "string" ? r.provider.trim() : "";
2778
+ const model = typeof r.model === "string" ? r.model.trim() : "";
2779
+ const thinkingLevel = normalizeThinkingLevel(r.thinkingLevel);
2780
+ return {
2781
+ ...provider ? { provider } : {},
2782
+ ...model ? { model } : {},
2783
+ ...thinkingLevel ? { thinkingLevel } : {}
2784
+ };
2785
+ }
2786
+ function normalizeDifficultyBrainMap(raw) {
2787
+ const out = {};
2788
+ if (!raw || typeof raw !== "object") return out;
2789
+ for (const key2 of MESH_TASK_DIFFICULTIES) {
2790
+ const slot = normalizeBrainSlot(raw[key2]);
2791
+ if (slot.provider || slot.model || slot.thinkingLevel) out[key2] = slot;
2792
+ }
2793
+ return out;
2794
+ }
2795
+ var DAEMON_ID_PREFIXES, MAGI_RAW_ANSWER_CAP, MESH_TASK_DIFFICULTIES, DEFAULT_DIFFICULTY_BRAINS, CANONICAL_MESH_TOOL_NAMES, CANONICAL_MESH_TOOL_COUNT;
2769
2796
  var init_dist = __esm({
2770
2797
  "../mesh-shared/dist/index.mjs"() {
2771
2798
  "use strict";
2772
2799
  DAEMON_ID_PREFIXES = ["daemon_", "standalone_"];
2773
2800
  MAGI_RAW_ANSWER_CAP = 4e3;
2801
+ MESH_TASK_DIFFICULTIES = ["easy", "medium", "difficult", "freeform"];
2802
+ DEFAULT_DIFFICULTY_BRAINS = {
2803
+ easy: { model: "haiku", thinkingLevel: "low" },
2804
+ medium: { model: "sonnet", thinkingLevel: "medium" },
2805
+ difficult: { model: "opus", thinkingLevel: "high" }
2806
+ };
2774
2807
  CANONICAL_MESH_TOOL_NAMES = [
2775
2808
  "mesh_status",
2776
2809
  "mesh_list_nodes",
@@ -2911,6 +2944,7 @@ __export(mesh_config_exports, {
2911
2944
  createMesh: () => createMesh,
2912
2945
  createMeshHostPairingToken: () => createMeshHostPairingToken,
2913
2946
  deleteMesh: () => deleteMesh,
2947
+ getDifficultyBrains: () => getDifficultyBrains,
2914
2948
  getMagiKindPanel: () => getMagiKindPanel,
2915
2949
  getMesh: () => getMesh,
2916
2950
  getMeshByRepo: () => getMeshByRepo,
@@ -2921,6 +2955,7 @@ __export(mesh_config_exports, {
2921
2955
  normalizeRepoIdentity: () => normalizeRepoIdentity,
2922
2956
  removeMagiKindPanel: () => removeMagiKindPanel,
2923
2957
  removeNode: () => removeNode,
2958
+ setDifficultyBrains: () => setDifficultyBrains,
2924
2959
  setMagiKindPanel: () => setMagiKindPanel,
2925
2960
  tokenIdForManualPairing: () => tokenIdForManualPairing,
2926
2961
  updateMesh: () => updateMesh,
@@ -3399,12 +3434,26 @@ function removeMagiKindPanel(kind) {
3399
3434
  saveMeshConfig(stored);
3400
3435
  return true;
3401
3436
  }
3437
+ function getDifficultyBrains() {
3438
+ const stored = loadMeshConfig().difficultyBrains;
3439
+ const normalized = normalizeDifficultyBrainMap(stored);
3440
+ return Object.keys(normalized).length > 0 ? normalized : { ...DEFAULT_DIFFICULTY_BRAINS };
3441
+ }
3442
+ function setDifficultyBrains(map) {
3443
+ const normalized = normalizeDifficultyBrainMap(map);
3444
+ const stored = loadMeshConfig();
3445
+ if (Object.keys(normalized).length > 0) stored.difficultyBrains = normalized;
3446
+ else delete stored.difficultyBrains;
3447
+ saveMeshConfig(stored);
3448
+ return normalized;
3449
+ }
3402
3450
  var mergeMeshPolicy, MAGI_KIND_PANEL_KINDS, MAX_MAGI_KIND_SLOTS;
3403
3451
  var init_mesh_config = __esm({
3404
3452
  "src/config/mesh-config.ts"() {
3405
3453
  "use strict";
3406
3454
  init_hash();
3407
3455
  init_config();
3456
+ init_dist();
3408
3457
  init_repo_mesh_types();
3409
3458
  init_mesh_host_ownership();
3410
3459
  mergeMeshPolicy = mergeAndNormalizePolicy;
@@ -3504,6 +3553,7 @@ Default branch: \`${mesh.defaultBranch}\`` : ""}`);
3504
3553
  if (operatingNotes) sections.push(operatingNotes);
3505
3554
  }
3506
3555
  sections.push(buildPolicySection(mergeAndNormalizePolicy(void 0, mesh.policy)));
3556
+ sections.push(buildBrainPresetsSection());
3507
3557
  sections.push(TOOLS_SECTION);
3508
3558
  sections.push(TOOL_EXPOSURE_PREFLIGHT_SECTION);
3509
3559
  sections.push(WORKFLOW_SECTION);
@@ -3692,6 +3742,34 @@ function truncateNote(text) {
3692
3742
  if (text.length <= OPERATING_NOTE_MAX_CHARS) return text;
3693
3743
  return `${text.slice(0, OPERATING_NOTE_MAX_CHARS).trimEnd()}\u2026 [truncated]`;
3694
3744
  }
3745
+ function buildBrainPresetsSection() {
3746
+ let brains;
3747
+ try {
3748
+ brains = getDifficultyBrains();
3749
+ } catch {
3750
+ brains = {};
3751
+ }
3752
+ const lines = [
3753
+ "## Brain presets",
3754
+ "",
3755
+ "When you pass `difficulty` on `mesh_enqueue_task`, it resolves to this model / thinking level (an explicit model/thinkingLevel on the task overrides it). Pick easy for trivial work to save tokens, difficult for hard reasoning.",
3756
+ ""
3757
+ ];
3758
+ for (const key2 of MESH_TASK_DIFFICULTIES) {
3759
+ const slot = brains[key2];
3760
+ if (!slot || !slot.provider && !slot.model && !slot.thinkingLevel) {
3761
+ lines.push(`- **${key2}**: (no preset \u2014 ordinary routing)`);
3762
+ continue;
3763
+ }
3764
+ const parts = [
3765
+ slot.provider ? `provider: \`${slot.provider}\`` : "",
3766
+ slot.model ? `model: \`${slot.model}\`` : "",
3767
+ slot.thinkingLevel ? `thinking: \`${slot.thinkingLevel}\`` : ""
3768
+ ].filter(Boolean).join(" | ");
3769
+ lines.push(`- **${key2}**: ${parts}`);
3770
+ }
3771
+ return lines.join("\n");
3772
+ }
3695
3773
  function buildPolicySection(policy) {
3696
3774
  const rules = [];
3697
3775
  if (policy.requirePreTaskCheckpoint) rules.push("- Create a git checkpoint **before** starting each task");
@@ -3720,6 +3798,7 @@ function buildRulesSection(coordinatorCliType) {
3720
3798
  - **Front-load task messages.** Include everything the agent needs (files, problem, expected fix) in \`mesh_enqueue_task\` / \`mesh_send_task\`. Append a structured result request at the end: ask the worker to conclude with a JSON block containing \`status\`, \`changedFiles\`, \`gitStatus\`, \`validationResults\`, \`errors\`, \`nextAction\`. The daemon parses this automatically; you can read it from \`mesh_task_history\`.
3721
3799
  - **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.
3722
3800
  - **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.
3801
+ - **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.
3723
3802
  - **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.
3724
3803
  - **Verify via git, not source.** Use \`mesh_git_status\` to confirm side effects. Treat agent summaries as self-reports, not verification.
3725
3804
  - **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).
@@ -3746,6 +3825,8 @@ var init_coordinator_prompt = __esm({
3746
3825
  "src/mesh/coordinator-prompt.ts"() {
3747
3826
  "use strict";
3748
3827
  init_repo_mesh_types();
3828
+ init_mesh_config();
3829
+ init_dist();
3749
3830
  PROMPT_SOFT_CAP_BYTES = 60 * 1024;
3750
3831
  OPERATING_NOTES_PROMPT_CAP = 20;
3751
3832
  OPERATING_NOTE_MAX_CHARS = 300;
@@ -5741,6 +5822,18 @@ function enqueueTask(meshId, message, opts) {
5741
5822
  const priority = normalizeMeshTaskPriority(opts?.priority);
5742
5823
  const notBefore = resolveNotBefore(opts?.notBefore);
5743
5824
  const maxRetries = typeof opts?.maxRetries === "number" && Number.isFinite(opts.maxRetries) && opts.maxRetries >= 0 ? Math.floor(opts.maxRetries) : void 0;
5825
+ let effectiveModel = typeof opts?.model === "string" && opts.model.trim() ? opts.model.trim() : void 0;
5826
+ let effectiveThinkingLevel = typeof opts?.thinkingLevel === "string" && opts.thinkingLevel.trim() ? opts.thinkingLevel.trim() : void 0;
5827
+ if (isMeshTaskDifficulty(opts?.difficulty)) {
5828
+ try {
5829
+ const preset = getDifficultyBrains()[opts.difficulty];
5830
+ if (preset) {
5831
+ if (!effectiveModel && preset.model) effectiveModel = preset.model;
5832
+ if (!effectiveThinkingLevel && preset.thinkingLevel) effectiveThinkingLevel = preset.thinkingLevel;
5833
+ }
5834
+ } catch {
5835
+ }
5836
+ }
5744
5837
  const result = withQueueLock(meshId, () => {
5745
5838
  if (MeshRuntimeStore.getInstance().findQueueEntryById(meshId, id)) {
5746
5839
  throw new Error(`duplicate_task_id: task '${id}' already exists in mesh '${meshId}'`);
@@ -5772,7 +5865,8 @@ function enqueueTask(meshId, message, opts) {
5772
5865
  ...maxRetries !== void 0 ? { maxRetries } : {},
5773
5866
  ...typeof opts?.missionId === "string" && opts.missionId.trim() ? { missionId: opts.missionId.trim() } : {},
5774
5867
  ...typeof opts?.consensusGroupId === "string" && opts.consensusGroupId.trim() ? { consensusGroupId: opts.consensusGroupId.trim() } : {},
5775
- ...typeof opts?.model === "string" && opts.model.trim() ? { model: opts.model.trim() } : {},
5868
+ ...effectiveModel ? { model: effectiveModel } : {},
5869
+ ...effectiveThinkingLevel ? { thinkingLevel: effectiveThinkingLevel } : {},
5776
5870
  ...typeof opts?.sourceCoordinatorSessionId === "string" && opts.sourceCoordinatorSessionId.trim() ? { sourceCoordinatorSessionId: opts.sourceCoordinatorSessionId.trim() } : {},
5777
5871
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
5778
5872
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
@@ -7346,6 +7440,27 @@ var init_mesh_runtime_store = __esm({
7346
7440
  `).get(meshId, taskId);
7347
7441
  return !!row;
7348
7442
  }
7443
+ /**
7444
+ * DELIVERED-NOT-CONSUMED re-drive support: true when at least one delivery record for
7445
+ * the task has reached a CONSUMED status ('acked' / 'completed'). Distinct from
7446
+ * {@link taskHasConfirmedDelivery} ('delivered' | 'acked' | 'completed'): a delivery is
7447
+ * flipped to 'delivered' the instant the transport hands the dispatch off, but only
7448
+ * flipped to 'acked' when the worker's agent:generating_started event arrives (see the
7449
+ * generating_started handler in mesh-event-forwarding) — i.e. when the session has
7450
+ * actually begun the turn. That distinction is the cross-daemon consumption signal the
7451
+ * short-grace re-drive uses: a row whose delivery is 'delivered' but never 'acked' was
7452
+ * handed to a REMOTE worker that never started generating — the remote autoLaunch
7453
+ * delivered≠consumed gap — even when the session's busy verdict is UNKNOWN (not locally
7454
+ * observable). Indexed by (mesh_id, task_id).
7455
+ */
7456
+ taskDeliveryConsumed(meshId, taskId) {
7457
+ const row = this.db.prepare(`
7458
+ SELECT 1 FROM mesh_session_delivery
7459
+ WHERE mesh_id = ? AND task_id = ? AND status IN ('acked','completed')
7460
+ LIMIT 1
7461
+ `).get(meshId, taskId);
7462
+ return !!row;
7463
+ }
7349
7464
  expireStaleSessionDeliveries(meshId) {
7350
7465
  const now = (/* @__PURE__ */ new Date()).toISOString();
7351
7466
  this.db.prepare(`
@@ -8438,7 +8553,8 @@ function routeV2EventsForDrainer(events, drainer, ctx) {
8438
8553
  }
8439
8554
  if (validated.scope !== "unicast") {
8440
8555
  if (validated.scope === "broadcast" && isTerminalTaskEvent(validated.event)) {
8441
- if (identityDeliversTo(validated.dispatchedBy, drainer)) {
8556
+ const deliverSelfFallback = event.dispatchedBySelfFallback && daemonIdsEquivalent(validated.dispatchedBy.daemonId, drainer.daemonId);
8557
+ if (deliverSelfFallback || identityDeliversTo(validated.dispatchedBy, drainer)) {
8442
8558
  ctx.batchSeen.add(eventId);
8443
8559
  bump("v2Delivered");
8444
8560
  kept.push(event);
@@ -8710,13 +8826,15 @@ function stampPendingEventV2(event, hint) {
8710
8826
  scope: hint?.scope ?? (selfFallback ? "broadcast" : void 0)
8711
8827
  });
8712
8828
  if (!stamp) return event;
8829
+ const dispatchedBySelfFallback = selfFallback && stamp.scope === "broadcast";
8713
8830
  return {
8714
8831
  ...event,
8715
8832
  protocolVersion: stamp.protocolVersion,
8716
8833
  eventId: stamp.eventId,
8717
8834
  scope: stamp.scope,
8718
8835
  dispatchedBy: stamp.dispatchedBy,
8719
- ...stamp.intendedFor ? { intendedFor: stamp.intendedFor } : {}
8836
+ ...stamp.intendedFor ? { intendedFor: stamp.intendedFor } : {},
8837
+ ...dispatchedBySelfFallback ? { dispatchedBySelfFallback: true } : {}
8720
8838
  };
8721
8839
  }
8722
8840
  function readCoordinatorIdentityFromWire(raw) {
@@ -15249,8 +15367,23 @@ function mergeInlineCacheOnlyNodes(localMesh, cachedMesh) {
15249
15367
  if (!cachedId) return false;
15250
15368
  return !localNodes.some((localNode) => meshNodeIdMatches(localNode, cachedId));
15251
15369
  });
15252
- if (!cacheOnly.length) return localMesh;
15253
- return { ...localMesh, nodes: [...localNodes, ...cacheOnly] };
15370
+ let overlaidLocalNodes = localNodes;
15371
+ let overlaid = false;
15372
+ for (let i = 0; i < localNodes.length; i++) {
15373
+ const localNode = localNodes[i];
15374
+ const localId = readMeshNodeId(localNode);
15375
+ if (!localId) continue;
15376
+ const inlineMatch = cachedNodes.find((cachedNode) => meshNodeIdMatches(cachedNode, localId));
15377
+ const inlineBootstrapStatus = readNonEmptyString2(inlineMatch?.worktreeBootstrap?.status);
15378
+ if (!inlineMatch || !inlineBootstrapStatus) continue;
15379
+ if (!overlaid) {
15380
+ overlaidLocalNodes = [...localNodes];
15381
+ overlaid = true;
15382
+ }
15383
+ overlaidLocalNodes[i] = { ...localNode, worktreeBootstrap: inlineMatch.worktreeBootstrap };
15384
+ }
15385
+ if (!cacheOnly.length && !overlaid) return localMesh;
15386
+ return { ...localMesh, nodes: [...overlaidLocalNodes, ...cacheOnly] };
15254
15387
  }
15255
15388
  function warnDispatchWarmupGetterMissingOnce(daemonId) {
15256
15389
  if (dispatchWarmupGetterMissingWarned.has(daemonId)) return;
@@ -16120,7 +16253,9 @@ async function maybeAutoLaunchOneQueueSession(components, meshId, mesh) {
16120
16253
  settings: remoteSettings,
16121
16254
  // MAGI-KIND-PANEL model axis: forward the task's model override so the
16122
16255
  // remote worker session launches with it (initialModel). Best-effort.
16123
- ...typeof task.model === "string" && task.model.trim() ? { initialModel: task.model.trim() } : {}
16256
+ ...typeof task.model === "string" && task.model.trim() ? { initialModel: task.model.trim() } : {},
16257
+ // BRAIN-ROUTING thinking axis: forward the task's thinking level (initialThinkingLevel).
16258
+ ...typeof task.thinkingLevel === "string" && task.thinkingLevel.trim() ? { initialThinkingLevel: task.thinkingLevel.trim() } : {}
16124
16259
  });
16125
16260
  } catch (e) {
16126
16261
  markAutoLaunch(meshId, task.id, { status: "failed", reason: `remote_launch_dispatch_failed: ${e?.message || String(e)}`, nodeId, providerType: resolved.providerType });
@@ -16149,7 +16284,9 @@ async function maybeAutoLaunchOneQueueSession(components, meshId, mesh) {
16149
16284
  settings: launchSettings,
16150
16285
  // MAGI-KIND-PANEL model axis: local launch forwards the task's model
16151
16286
  // override as initialModel (CLI → modelLaunchArgs; ACP → setConfigOption).
16152
- ...typeof task.model === "string" && task.model.trim() ? { initialModel: task.model.trim() } : {}
16287
+ ...typeof task.model === "string" && task.model.trim() ? { initialModel: task.model.trim() } : {},
16288
+ // BRAIN-ROUTING thinking axis: forward the task's thinking level (initialThinkingLevel).
16289
+ ...typeof task.thinkingLevel === "string" && task.thinkingLevel.trim() ? { initialThinkingLevel: task.thinkingLevel.trim() } : {}
16153
16290
  });
16154
16291
  if (!launchResult?.success) {
16155
16292
  const reason = launchResult?.error || "launch_cli_failed";
@@ -18709,6 +18846,8 @@ function buildAvailableProviders(providerLoader) {
18709
18846
  ...sourceLayer ? { sourceLayer } : {},
18710
18847
  ...sourceName ? { sourceName } : {},
18711
18848
  ...provider.providerVersion ? { providerVersion: provider.providerVersion } : {},
18849
+ ...Array.isArray(provider.modelOptions) && provider.modelOptions.length ? { modelOptions: provider.modelOptions } : {},
18850
+ ...Array.isArray(provider.thinkingLevelOptions) && provider.thinkingLevelOptions.length ? { thinkingLevelOptions: provider.thinkingLevelOptions } : {},
18712
18851
  ...provider.binary ? { binary: provider.binary } : {},
18713
18852
  ...provider.status ? { status: provider.status } : {},
18714
18853
  ...provider.details ? { details: provider.details } : {},
@@ -21045,7 +21184,34 @@ function recoverStrandedAssignedDispatches(components, meshId, store) {
21045
21184
  for (const row of assigned) {
21046
21185
  const dispatchedAtMs = Date.parse(row.dispatchTimestamp ?? "");
21047
21186
  if (!Number.isFinite(dispatchedAtMs)) continue;
21048
- if (nowMs - dispatchedAtMs < ASSIGNED_STRANDED_DEADLINE_MS) continue;
21187
+ const ageMs = nowMs - dispatchedAtMs;
21188
+ if (ageMs >= ASSIGNED_DELIVERED_UNCONSUMED_REDRIVE_MS && ageMs < ASSIGNED_STRANDED_DEADLINE_MS && store.taskHasConfirmedDelivery(meshId, row.id) && !store.taskDeliveryConsumed(meshId, row.id)) {
21189
+ const terminal2 = findTerminalLedgerEvidenceForTask({ meshId, taskId: row.id });
21190
+ if (terminal2) {
21191
+ const status = terminal2.kind === "task_completed" ? "completed" : "failed";
21192
+ updateTaskStatus(meshId, row.id, status);
21193
+ continue;
21194
+ }
21195
+ const verdict = row.assignedSessionId ? resolveSessionBusyVerdict(components, row.assignedSessionId) : "IDLE_CONFIRMED";
21196
+ if (verdict !== "GENERATING") {
21197
+ const redriven = reclaimStrandedAssignedTask(meshId, row.id, {
21198
+ reason: "delivered_not_consumed_redrive",
21199
+ ageMs
21200
+ });
21201
+ if (redriven) {
21202
+ LOG.warn("MeshReconcile", `Re-drove delivered-but-unconsumed task ${row.id} on mesh ${meshId} (node=${row.assignedNodeId ?? "?"} session=${row.assignedSessionId ?? "?"}, delivered but no generating_started in ${Math.round(ageMs / 1e3)}s, verdict ${verdict} \u2192 ${redriven.status})`);
21203
+ traceMeshEventDrop("assigned_delivered_not_consumed_redrive", {
21204
+ taskId: row.id,
21205
+ sessionId: row.assignedSessionId,
21206
+ nodeId: row.assignedNodeId,
21207
+ meshId,
21208
+ event: "agent:generating_started"
21209
+ }, `delivered_not_consumed ${Math.round(ageMs / 1e3)}s \u2192 ${redriven.status}`);
21210
+ continue;
21211
+ }
21212
+ }
21213
+ }
21214
+ if (ageMs < ASSIGNED_STRANDED_DEADLINE_MS) continue;
21049
21215
  const terminal = findTerminalLedgerEvidenceForTask({
21050
21216
  meshId,
21051
21217
  taskId: row.id
@@ -21560,7 +21726,7 @@ function setupMeshReconcileLoop(components) {
21560
21726
  }
21561
21727
  };
21562
21728
  }
21563
- var coordinatorModalParkState, heldEventLedgerRecorded, ASSIGNED_STRANDED_DEADLINE_MS, DELIVERED_NO_TURN_DEADLINE_MS, RECLAIM_UNKNOWN_GRACE_TICKS, deliveredNoTurnUnknownStreak, ZOMBIE_ASSIGNED_MIN_AGE_MS, STRICT_SESSION_MATCH_TTL_MS, unresolvedForwardRejectionCounts, MAX_FORWARD_REJECTIONS, UNRESOLVED_FORWARD_NUDGE_DELAY_MS, unresolvedForwardNudgeTimer, unresolvedForwardNudgeRunning;
21729
+ var coordinatorModalParkState, heldEventLedgerRecorded, ASSIGNED_STRANDED_DEADLINE_MS, DELIVERED_NO_TURN_DEADLINE_MS, ASSIGNED_DELIVERED_UNCONSUMED_REDRIVE_MS, RECLAIM_UNKNOWN_GRACE_TICKS, deliveredNoTurnUnknownStreak, ZOMBIE_ASSIGNED_MIN_AGE_MS, STRICT_SESSION_MATCH_TTL_MS, unresolvedForwardRejectionCounts, MAX_FORWARD_REJECTIONS, UNRESOLVED_FORWARD_NUDGE_DELAY_MS, unresolvedForwardNudgeTimer, unresolvedForwardNudgeRunning;
21564
21730
  var init_mesh_reconcile_loop = __esm({
21565
21731
  "src/mesh/mesh-reconcile-loop.ts"() {
21566
21732
  "use strict";
@@ -21590,6 +21756,7 @@ var init_mesh_reconcile_loop = __esm({
21590
21756
  heldEventLedgerRecorded = /* @__PURE__ */ new Set();
21591
21757
  ASSIGNED_STRANDED_DEADLINE_MS = 5 * 6e4;
21592
21758
  DELIVERED_NO_TURN_DEADLINE_MS = 15 * 6e4;
21759
+ ASSIGNED_DELIVERED_UNCONSUMED_REDRIVE_MS = 25e3;
21593
21760
  RECLAIM_UNKNOWN_GRACE_TICKS = 3;
21594
21761
  deliveredNoTurnUnknownStreak = /* @__PURE__ */ new Map();
21595
21762
  ZOMBIE_ASSIGNED_MIN_AGE_MS = 30 * 60 * 1e3;
@@ -21865,6 +22032,35 @@ var init_provider_schema = __esm({
21865
22032
  items: { type: "string" },
21866
22033
  description: "Template for expanding an initialModel selection into launch args. '{{model}}' is substituted with the model string (e.g. ['--model', '{{model}}'] \u2192 --model opus). Applied at launch when a model is requested for this CLI provider (MAGI kind-panel model axis). Absent \u2192 no launch-time model selection."
21867
22034
  },
22035
+ modelOptions: {
22036
+ type: "array",
22037
+ items: { type: "string" },
22038
+ description: "Suggested model values shown as dropdown options in the new-session dialog (brain-routing model axis), e.g. ['opus','sonnet','haiku']. Advisory \u2014 the UI still accepts free text, so a stale list never blocks an accepted model."
22039
+ },
22040
+ thinkingLaunchArgs: {
22041
+ type: "array",
22042
+ items: { type: "string" },
22043
+ description: "Template for expanding an initialThinkingLevel selection into launch args (brain-routing thinking axis, parallel to modelLaunchArgs). '{{level}}' is substituted with the provider-mapped reasoning-effort value (e.g. ['--effort', '{{level}}'] \u2192 --effort high; ['-c', 'model_reasoning_effort={{level}}']). Applied at launch when a thinking level is requested. Absent \u2192 no launch-time thinking selection."
22044
+ },
22045
+ thinkingLevelMap: {
22046
+ type: "object",
22047
+ properties: {
22048
+ low: { type: "string" },
22049
+ medium: { type: "string" },
22050
+ high: { type: "string" }
22051
+ },
22052
+ additionalProperties: false,
22053
+ description: "Optional map from the standard thinking levels (low/medium/high) to this provider's own reasoning-effort vocabulary, used to fill {{level}} in thinkingLaunchArgs. A level absent from the map passes through unchanged."
22054
+ },
22055
+ thinkingLevelOptions: {
22056
+ type: "array",
22057
+ items: { type: "string" },
22058
+ description: "Reasoning-effort values this provider accepts, shown as the thinking-level dropdown in the new-session dialog (e.g. ['low','medium','high','max']). Absent \u2192 the UI falls back to standard low/medium/high. Provider's own vocabulary, passed through verbatim."
22059
+ },
22060
+ thinkingControlId: {
22061
+ type: "string",
22062
+ description: "For a provider with no thinkingLaunchArgs but a runtime reasoning-effort control (e.g. hermes 'reasoning'), the controls[].id to drive at launch for the thinking level. The control's setScript is invoked with { value: <mapped level> }."
22063
+ },
21868
22064
  scriptCallBudgetMs: {
21869
22065
  type: "integer",
21870
22066
  minimum: 1,
@@ -44548,6 +44744,7 @@ var CliProviderInstance = class _CliProviderInstance {
44548
44744
  this.presentationMode = "chat";
44549
44745
  this.providerSessionId = options?.providerSessionId;
44550
44746
  this.launchMode = options?.launchMode || "new";
44747
+ this.initialThinkingLevel = options?.initialThinkingLevel;
44551
44748
  this.onProviderSessionResolved = options?.onProviderSessionResolved;
44552
44749
  this.adapter = createCliAdapter(provider, workingDir, cliArgs, options?.extraEnv || {}, transportFactory);
44553
44750
  if (this.providerSessionId) {
@@ -44769,6 +44966,7 @@ var CliProviderInstance = class _CliProviderInstance {
44769
44966
  presentationMode;
44770
44967
  providerSessionId;
44771
44968
  launchMode;
44969
+ initialThinkingLevel;
44772
44970
  startedAt = Date.now();
44773
44971
  onProviderSessionResolved;
44774
44972
  refreshProviderDefinition(provider) {
@@ -44797,6 +44995,7 @@ var CliProviderInstance = class _CliProviderInstance {
44797
44995
  });
44798
44996
  await this.adapter.spawn();
44799
44997
  await this.enforceFreshSessionLaunchIfNeeded();
44998
+ await this.applyInitialThinkingLevelViaControl();
44800
44999
  this.maybeAppendRuntimeRecoveryMessage(this.adapter.getRuntimeMetadata());
44801
45000
  if (this.providerSessionId && this.shouldHydrateExistingProviderHistory()) {
44802
45001
  this.restorePersistedHistoryFromCurrentSession();
@@ -45414,6 +45613,43 @@ var CliProviderInstance = class _CliProviderInstance {
45414
45613
  }
45415
45614
  this.applyProviderResponse(parsed.payload, { phase: "immediate" });
45416
45615
  }
45616
+ /**
45617
+ * BRAIN-ROUTING (runtime-control thinking axis): for a provider that selects
45618
+ * reasoning effort via a runtime control instead of a launch arg (e.g. hermes
45619
+ * `reasoning`), apply the requested initialThinkingLevel after spawn by invoking
45620
+ * that control's setScript. The provider names the control via thinkingControlId.
45621
+ * The standard level is mapped through thinkingLevelMap first (same as the
45622
+ * launch-arg path). Best-effort: any failure logs and never blocks launch.
45623
+ */
45624
+ async applyInitialThinkingLevelViaControl() {
45625
+ const level = typeof this.initialThinkingLevel === "string" ? this.initialThinkingLevel.trim() : "";
45626
+ if (!level) return;
45627
+ const controlId = this.provider.thinkingControlId;
45628
+ if (!controlId) return;
45629
+ const controls = Array.isArray(this.provider.controls) ? this.provider.controls : [];
45630
+ const control = controls.find((c) => c && c.id === controlId);
45631
+ if (!control || !control.setScript) return;
45632
+ const map = this.provider.thinkingLevelMap;
45633
+ const mapped = map && typeof map[level] === "string" && map[level].trim() ? map[level].trim() : level;
45634
+ try {
45635
+ await waitForCliAdapterReady(this.adapter);
45636
+ const raw = await this.adapter.invokeScript(control.setScript, { value: mapped });
45637
+ const parsed = parseCliScriptResult(raw);
45638
+ if (!parsed.success) {
45639
+ LOG.warn("CLI", `[${this.type}] thinking control '${controlId}' set to '${mapped}' failed: ${parsed.payload?.error || "unknown"}`);
45640
+ return;
45641
+ }
45642
+ const cliCommand = getCliScriptCommand(parsed.payload);
45643
+ if (cliCommand?.type === "send_message" && cliCommand.text) {
45644
+ await this.adapter.sendMessage(cliCommand.text);
45645
+ } else if (cliCommand?.type === "pty_write" && cliCommand.text) {
45646
+ await this.adapter.writeRaw(cliCommand.text + "\r");
45647
+ }
45648
+ LOG.info("CLI", `[${this.type}] applied thinking level '${mapped}' via control '${controlId}'`);
45649
+ } catch (e) {
45650
+ LOG.warn("CLI", `[${this.type}] thinking control apply threw: ${e?.message || e}`);
45651
+ }
45652
+ }
45417
45653
  completionHasFinalAssistantMessage(messages, turnStartedAt) {
45418
45654
  const visibleMessages = (Array.isArray(messages) ? messages : []).filter((message) => isUserFacingChatMessage(message));
45419
45655
  const lastVisible = visibleMessages[visibleMessages.length - 1];
@@ -48525,7 +48761,13 @@ function expandResumeArgs(template, sessionId) {
48525
48761
  function expandModelLaunchArgs(template, model) {
48526
48762
  const m = typeof model === "string" ? model.trim() : "";
48527
48763
  if (!m || !Array.isArray(template) || template.length === 0) return void 0;
48528
- return template.map((part) => part === "{{model}}" ? m : part);
48764
+ return template.map((part) => part.includes("{{model}}") ? part.split("{{model}}").join(m) : part);
48765
+ }
48766
+ function expandThinkingLaunchArgs(template, level, levelMap) {
48767
+ const raw = typeof level === "string" ? level.trim() : "";
48768
+ if (!raw || !Array.isArray(template) || template.length === 0) return void 0;
48769
+ const mapped = levelMap && typeof levelMap[raw] === "string" && levelMap[raw].trim() ? levelMap[raw].trim() : raw;
48770
+ return template.map((part) => part.includes("{{level}}") ? part.replace("{{level}}", mapped) : part);
48529
48771
  }
48530
48772
  function readSubcommandSessionId(args, subcommands) {
48531
48773
  const resumeIndex = args.findIndex((arg) => subcommands.includes(arg));
@@ -48909,6 +49151,15 @@ ${installInfo}`
48909
49151
  LOG.warn("CLI", `[ACP] Initial model set failed: ${e?.message}`);
48910
49152
  }
48911
49153
  }
49154
+ if (options?.initialThinkingLevel) {
49155
+ const lvl = options.initialThinkingLevel;
49156
+ try {
49157
+ await acpInstance.setConfigOption("thought_level", lvl);
49158
+ console.log(colorize("green", ` \u{1F9E0} Initial thinking level set: ${lvl}`));
49159
+ } catch (e) {
49160
+ LOG.warn("CLI", `[ACP] Initial thinking level set failed (provider may not support thought_level): ${e?.message}`);
49161
+ }
49162
+ }
48912
49163
  this.persistRecentActivity({
48913
49164
  kind: "acp",
48914
49165
  providerType: normalizedType,
@@ -48944,7 +49195,13 @@ Run 'adhdev doctor' for detailed diagnostics.`
48944
49195
  if (initialModel && !modelLaunchArgs) {
48945
49196
  LOG.warn("CLI", `[${normalizedType}] initialModel='${initialModel}' requested but provider declares no modelLaunchArgs template \u2014 launching without model selection.`);
48946
49197
  }
48947
- const sessionBinding = resolveCliSessionBinding(provider, normalizedType, cliArgsWithModel, options?.resumeSessionId);
49198
+ const initialThinkingLevel = options?.initialThinkingLevel;
49199
+ const thinkingLaunchArgs = expandThinkingLaunchArgs(provider?.thinkingLaunchArgs, initialThinkingLevel, provider?.thinkingLevelMap);
49200
+ const cliArgsWithBrain = thinkingLaunchArgs ? [...thinkingLaunchArgs, ...cliArgsWithModel || []] : cliArgsWithModel;
49201
+ if (initialThinkingLevel && !thinkingLaunchArgs) {
49202
+ LOG.warn("CLI", `[${normalizedType}] initialThinkingLevel='${initialThinkingLevel}' requested but provider declares no thinkingLaunchArgs template \u2014 launching without thinking-level selection.`);
49203
+ }
49204
+ const sessionBinding = resolveCliSessionBinding(provider, normalizedType, cliArgsWithBrain, options?.resumeSessionId);
48948
49205
  const resolvedCliArgs = sessionBinding.cliArgs;
48949
49206
  const instanceManager = this.deps.getInstanceManager();
48950
49207
  if (provider && instanceManager) {
@@ -48962,6 +49219,10 @@ Run 'adhdev doctor' for detailed diagnostics.`
48962
49219
  providerSessionId: sessionBinding.providerSessionId,
48963
49220
  launchMode: sessionBinding.launchMode,
48964
49221
  extraEnv: options?.extraEnv,
49222
+ // BRAIN-ROUTING: for a provider with no thinkingLaunchArgs but a
49223
+ // runtime reasoning control (hermes), apply the level post-launch.
49224
+ // The launch-arg providers (claude/codex) already consumed it at spawn.
49225
+ ...options?.initialThinkingLevel && !provider?.thinkingLaunchArgs ? { initialThinkingLevel: options.initialThinkingLevel } : {},
48965
49226
  onProviderSessionResolved: ({ providerSessionId, providerName, providerType, workspace }) => {
48966
49227
  this.persistRecentActivity({
48967
49228
  kind: "cli",
@@ -49309,7 +49570,8 @@ Run 'adhdev doctor' for detailed diagnostics.`
49309
49570
  {
49310
49571
  resumeSessionId: args?.resumeSessionId,
49311
49572
  settingsOverride,
49312
- extraEnv: delegatedLaunch ? delegatedLaunch.env : args?.env
49573
+ extraEnv: delegatedLaunch ? delegatedLaunch.env : args?.env,
49574
+ ...typeof args?.initialThinkingLevel === "string" && args.initialThinkingLevel.trim() ? { initialThinkingLevel: args.initialThinkingLevel.trim() } : {}
49313
49575
  }
49314
49576
  );
49315
49577
  return {
@@ -49754,6 +50016,12 @@ var KNOWN_PROVIDER_FIELDS = /* @__PURE__ */ new Set([
49754
50016
  "providerVersion",
49755
50017
  "status",
49756
50018
  "details",
50019
+ "modelLaunchArgs",
50020
+ "modelOptions",
50021
+ "thinkingLaunchArgs",
50022
+ "thinkingLevelMap",
50023
+ "thinkingLevelOptions",
50024
+ "thinkingControlId",
49757
50025
  "sendDelayMs",
49758
50026
  "sendKey",
49759
50027
  "submitStrategy",
@@ -54467,6 +54735,26 @@ var meshCrudHandlers = {
54467
54735
  return { success: false, error: e.message };
54468
54736
  }
54469
54737
  },
54738
+ // ─── Brain routing: per-difficulty brain presets (machine-local) ───
54739
+ // getDifficultyBrains returns the seeded defaults when nothing is configured,
54740
+ // so the editor always shows a usable mapping. set replaces the whole map.
54741
+ difficulty_brains_get: async (_ctx, _args) => {
54742
+ try {
54743
+ const { getDifficultyBrains: getDifficultyBrains2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
54744
+ return { success: true, difficultyBrains: getDifficultyBrains2() };
54745
+ } catch (e) {
54746
+ return { success: false, error: e.message };
54747
+ }
54748
+ },
54749
+ difficulty_brains_set: async (_ctx, args) => {
54750
+ try {
54751
+ const { setDifficultyBrains: setDifficultyBrains2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
54752
+ const difficultyBrains = setDifficultyBrains2(args?.difficultyBrains);
54753
+ return { success: true, difficultyBrains };
54754
+ } catch (e) {
54755
+ return { success: false, error: e.message };
54756
+ }
54757
+ },
54470
54758
  add_mesh_node: async (ctx, args) => {
54471
54759
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
54472
54760
  const workspace = typeof args?.workspace === "string" ? args.workspace.trim() : "";