@adhdev/daemon-core 0.9.82-rc.482 → 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/commands/cli-manager.d.ts +20 -0
- package/dist/config/mesh-config.d.ts +19 -1
- package/dist/index.js +398 -19
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +398 -19
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/contracts.d.ts +27 -4
- package/dist/mesh/mesh-events-pending.d.ts +12 -0
- package/dist/mesh/mesh-runtime-store.d.ts +14 -0
- package/dist/mesh/mesh-work-queue.d.ts +17 -0
- package/dist/providers/cli-provider-instance.d.ts +14 -0
- package/dist/providers/contracts.d.ts +47 -0
- package/dist/repo-mesh-types.d.ts +11 -2
- package/dist/shared-types.d.ts +4 -0
- package/package.json +3 -3
- package/src/commands/cli-manager.ts +64 -3
- package/src/commands/low-family/coordinator-prompt.ts +53 -0
- package/src/commands/med-family/mesh-crud.ts +35 -0
- package/src/config/mesh-config.ts +42 -1
- package/src/mesh/contracts.ts +42 -7
- package/src/mesh/coordinator-prompt.ts +55 -0
- package/src/mesh/mesh-events-pending.ts +54 -0
- package/src/mesh/mesh-queue-assignment.ts +46 -4
- package/src/mesh/mesh-reconcile-loop.ts +69 -1
- package/src/mesh/mesh-runtime-store.ts +22 -0
- package/src/mesh/mesh-work-queue.ts +36 -3
- package/src/providers/cli-provider-instance.ts +46 -0
- package/src/providers/contracts.ts +47 -0
- package/src/providers/provider-schema.ts +6 -0
- package/src/providers/sdk/v1/schemas/cli/provider.schema.json +29 -0
- package/src/repo-mesh-types.ts +11 -2
- package/src/shared-types.ts +4 -0
- package/src/status/snapshot.ts +4 -0
package/dist/index.js
CHANGED
|
@@ -188,7 +188,7 @@ var init_repo_mesh_types = __esm({
|
|
|
188
188
|
"checkpoint_then_continue"
|
|
189
189
|
]);
|
|
190
190
|
MESH_MAX_PARALLEL_TASKS_MIN = 1;
|
|
191
|
-
MESH_MAX_PARALLEL_TASKS_MAX =
|
|
191
|
+
MESH_MAX_PARALLEL_TASKS_MAX = 64;
|
|
192
192
|
DEFAULT_MESH_READONLY_MULTIPLIER = 2;
|
|
193
193
|
}
|
|
194
194
|
});
|
|
@@ -409,10 +409,10 @@ function readInjected(value) {
|
|
|
409
409
|
}
|
|
410
410
|
function getDaemonBuildInfo() {
|
|
411
411
|
if (cached) return cached;
|
|
412
|
-
const commit = readInjected(true ? "
|
|
413
|
-
const commitShort = readInjected(true ? "
|
|
414
|
-
const version = readInjected(true ? "0.9.82-rc.
|
|
415
|
-
const builtAt = readInjected(true ? "2026-07-
|
|
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);
|
|
416
416
|
cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
|
|
417
417
|
return cached;
|
|
418
418
|
}
|
|
@@ -2771,12 +2771,45 @@ function summarizeGitShape(status) {
|
|
|
2771
2771
|
submodules
|
|
2772
2772
|
};
|
|
2773
2773
|
}
|
|
2774
|
-
|
|
2774
|
+
function isMeshTaskDifficulty(value) {
|
|
2775
|
+
return typeof value === "string" && MESH_TASK_DIFFICULTIES.includes(value);
|
|
2776
|
+
}
|
|
2777
|
+
function normalizeThinkingLevel(value) {
|
|
2778
|
+
const v = typeof value === "string" ? value.trim().toLowerCase() : "";
|
|
2779
|
+
return v === "low" || v === "medium" || v === "high" ? v : void 0;
|
|
2780
|
+
}
|
|
2781
|
+
function normalizeBrainSlot(raw) {
|
|
2782
|
+
const r = raw && typeof raw === "object" ? raw : {};
|
|
2783
|
+
const provider = typeof r.provider === "string" ? r.provider.trim() : "";
|
|
2784
|
+
const model = typeof r.model === "string" ? r.model.trim() : "";
|
|
2785
|
+
const thinkingLevel = normalizeThinkingLevel(r.thinkingLevel);
|
|
2786
|
+
return {
|
|
2787
|
+
...provider ? { provider } : {},
|
|
2788
|
+
...model ? { model } : {},
|
|
2789
|
+
...thinkingLevel ? { thinkingLevel } : {}
|
|
2790
|
+
};
|
|
2791
|
+
}
|
|
2792
|
+
function normalizeDifficultyBrainMap(raw) {
|
|
2793
|
+
const out = {};
|
|
2794
|
+
if (!raw || typeof raw !== "object") return out;
|
|
2795
|
+
for (const key2 of MESH_TASK_DIFFICULTIES) {
|
|
2796
|
+
const slot = normalizeBrainSlot(raw[key2]);
|
|
2797
|
+
if (slot.provider || slot.model || slot.thinkingLevel) out[key2] = slot;
|
|
2798
|
+
}
|
|
2799
|
+
return out;
|
|
2800
|
+
}
|
|
2801
|
+
var DAEMON_ID_PREFIXES, MAGI_RAW_ANSWER_CAP, MESH_TASK_DIFFICULTIES, DEFAULT_DIFFICULTY_BRAINS, CANONICAL_MESH_TOOL_NAMES, CANONICAL_MESH_TOOL_COUNT;
|
|
2775
2802
|
var init_dist = __esm({
|
|
2776
2803
|
"../mesh-shared/dist/index.mjs"() {
|
|
2777
2804
|
"use strict";
|
|
2778
2805
|
DAEMON_ID_PREFIXES = ["daemon_", "standalone_"];
|
|
2779
2806
|
MAGI_RAW_ANSWER_CAP = 4e3;
|
|
2807
|
+
MESH_TASK_DIFFICULTIES = ["easy", "medium", "difficult", "freeform"];
|
|
2808
|
+
DEFAULT_DIFFICULTY_BRAINS = {
|
|
2809
|
+
easy: { model: "haiku", thinkingLevel: "low" },
|
|
2810
|
+
medium: { model: "sonnet", thinkingLevel: "medium" },
|
|
2811
|
+
difficult: { model: "opus", thinkingLevel: "high" }
|
|
2812
|
+
};
|
|
2780
2813
|
CANONICAL_MESH_TOOL_NAMES = [
|
|
2781
2814
|
"mesh_status",
|
|
2782
2815
|
"mesh_list_nodes",
|
|
@@ -2917,6 +2950,7 @@ __export(mesh_config_exports, {
|
|
|
2917
2950
|
createMesh: () => createMesh,
|
|
2918
2951
|
createMeshHostPairingToken: () => createMeshHostPairingToken,
|
|
2919
2952
|
deleteMesh: () => deleteMesh,
|
|
2953
|
+
getDifficultyBrains: () => getDifficultyBrains,
|
|
2920
2954
|
getMagiKindPanel: () => getMagiKindPanel,
|
|
2921
2955
|
getMesh: () => getMesh,
|
|
2922
2956
|
getMeshByRepo: () => getMeshByRepo,
|
|
@@ -2927,6 +2961,7 @@ __export(mesh_config_exports, {
|
|
|
2927
2961
|
normalizeRepoIdentity: () => normalizeRepoIdentity,
|
|
2928
2962
|
removeMagiKindPanel: () => removeMagiKindPanel,
|
|
2929
2963
|
removeNode: () => removeNode,
|
|
2964
|
+
setDifficultyBrains: () => setDifficultyBrains,
|
|
2930
2965
|
setMagiKindPanel: () => setMagiKindPanel,
|
|
2931
2966
|
tokenIdForManualPairing: () => tokenIdForManualPairing,
|
|
2932
2967
|
updateMesh: () => updateMesh,
|
|
@@ -3309,6 +3344,11 @@ function updateNode(meshId, nodeId, opts) {
|
|
|
3309
3344
|
node.reportedDaemonBuildVersion = opts.reportedDaemonBuildVersion.trim();
|
|
3310
3345
|
}
|
|
3311
3346
|
if (opts.policy) node.policy = { ...node.policy, ...opts.policy };
|
|
3347
|
+
if (Object.prototype.hasOwnProperty.call(opts, "capabilities")) {
|
|
3348
|
+
const tags = normalizeCapabilityTags(opts.capabilities);
|
|
3349
|
+
if (tags && tags.length) node.capabilities = tags;
|
|
3350
|
+
else delete node.capabilities;
|
|
3351
|
+
}
|
|
3312
3352
|
if (opts.worktreeBootstrap) node.worktreeBootstrap = opts.worktreeBootstrap;
|
|
3313
3353
|
if (Object.prototype.hasOwnProperty.call(opts, "systemPrompt")) {
|
|
3314
3354
|
if (opts.systemPrompt && opts.systemPrompt.trim()) {
|
|
@@ -3397,6 +3437,19 @@ function removeMagiKindPanel(kind) {
|
|
|
3397
3437
|
saveMeshConfig(stored);
|
|
3398
3438
|
return true;
|
|
3399
3439
|
}
|
|
3440
|
+
function getDifficultyBrains() {
|
|
3441
|
+
const stored = loadMeshConfig().difficultyBrains;
|
|
3442
|
+
const normalized = normalizeDifficultyBrainMap(stored);
|
|
3443
|
+
return Object.keys(normalized).length > 0 ? normalized : { ...DEFAULT_DIFFICULTY_BRAINS };
|
|
3444
|
+
}
|
|
3445
|
+
function setDifficultyBrains(map) {
|
|
3446
|
+
const normalized = normalizeDifficultyBrainMap(map);
|
|
3447
|
+
const stored = loadMeshConfig();
|
|
3448
|
+
if (Object.keys(normalized).length > 0) stored.difficultyBrains = normalized;
|
|
3449
|
+
else delete stored.difficultyBrains;
|
|
3450
|
+
saveMeshConfig(stored);
|
|
3451
|
+
return normalized;
|
|
3452
|
+
}
|
|
3400
3453
|
var import_fs3, import_path3, import_crypto3, mergeMeshPolicy, MAGI_KIND_PANEL_KINDS, MAX_MAGI_KIND_SLOTS;
|
|
3401
3454
|
var init_mesh_config = __esm({
|
|
3402
3455
|
"src/config/mesh-config.ts"() {
|
|
@@ -3406,6 +3459,7 @@ var init_mesh_config = __esm({
|
|
|
3406
3459
|
import_crypto3 = require("crypto");
|
|
3407
3460
|
init_hash();
|
|
3408
3461
|
init_config();
|
|
3462
|
+
init_dist();
|
|
3409
3463
|
init_repo_mesh_types();
|
|
3410
3464
|
init_mesh_host_ownership();
|
|
3411
3465
|
mergeMeshPolicy = mergeAndNormalizePolicy;
|
|
@@ -3502,6 +3556,7 @@ Default branch: \`${mesh.defaultBranch}\`` : ""}`);
|
|
|
3502
3556
|
if (operatingNotes) sections.push(operatingNotes);
|
|
3503
3557
|
}
|
|
3504
3558
|
sections.push(buildPolicySection(mergeAndNormalizePolicy(void 0, mesh.policy)));
|
|
3559
|
+
sections.push(buildBrainPresetsSection());
|
|
3505
3560
|
sections.push(TOOLS_SECTION);
|
|
3506
3561
|
sections.push(TOOL_EXPOSURE_PREFLIGHT_SECTION);
|
|
3507
3562
|
sections.push(WORKFLOW_SECTION);
|
|
@@ -3601,6 +3656,21 @@ function buildNodeConfigSection(mesh) {
|
|
|
3601
3656
|
}).filter(Boolean) : [];
|
|
3602
3657
|
const providerRolesSuffix = providerRoles.length ? ` | caps: ${providerRoles.join(", ")}` : "";
|
|
3603
3658
|
lines.push(`- ${explicitLabel} nodeId: \`${n.id}\` | workspace: \`${n.workspace}\`${n.daemonId ? ` | daemon: \`${n.daemonId}\`` : ""}${providerPriority}${providerRolesSuffix}${suffix}`);
|
|
3659
|
+
const routingTags = [];
|
|
3660
|
+
const custom = Array.isArray(n.capabilities) ? n.capabilities : [];
|
|
3661
|
+
for (const t of custom) {
|
|
3662
|
+
const s2 = typeof t === "string" ? t.trim() : "";
|
|
3663
|
+
if (s2) routingTags.push(s2);
|
|
3664
|
+
}
|
|
3665
|
+
const tagOs = (n.userOverrides?.platform || n.reportedPlatform || "").toString().trim();
|
|
3666
|
+
const tagArch = (n.userOverrides?.arch || n.reportedArch || "").toString().trim();
|
|
3667
|
+
if (tagOs) routingTags.push(`os=${tagOs}`);
|
|
3668
|
+
if (tagArch) routingTags.push(`arch=${tagArch}`);
|
|
3669
|
+
const wtBranch = typeof n.worktreeBranch === "string" ? n.worktreeBranch.trim() : "";
|
|
3670
|
+
if (n.isLocalWorktree && wtBranch) routingTags.push(`worktree=${wtBranch}`);
|
|
3671
|
+
if (routingTags.length) {
|
|
3672
|
+
lines.push(` \u{1F3F7}\uFE0F routing tags: ${routingTags.map((t) => `\`${t}\``).join(", ")}`);
|
|
3673
|
+
}
|
|
3604
3674
|
const nodePrompt = typeof n.systemPrompt === "string" ? n.systemPrompt.trim() : "";
|
|
3605
3675
|
if (nodePrompt) {
|
|
3606
3676
|
lines.push(` \u{1F4CC} Node instruction: ${indentFollowing(nodePrompt, " ")}`);
|
|
@@ -3675,6 +3745,34 @@ function truncateNote(text) {
|
|
|
3675
3745
|
if (text.length <= OPERATING_NOTE_MAX_CHARS) return text;
|
|
3676
3746
|
return `${text.slice(0, OPERATING_NOTE_MAX_CHARS).trimEnd()}\u2026 [truncated]`;
|
|
3677
3747
|
}
|
|
3748
|
+
function buildBrainPresetsSection() {
|
|
3749
|
+
let brains;
|
|
3750
|
+
try {
|
|
3751
|
+
brains = getDifficultyBrains();
|
|
3752
|
+
} catch {
|
|
3753
|
+
brains = {};
|
|
3754
|
+
}
|
|
3755
|
+
const lines = [
|
|
3756
|
+
"## Brain presets",
|
|
3757
|
+
"",
|
|
3758
|
+
"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.",
|
|
3759
|
+
""
|
|
3760
|
+
];
|
|
3761
|
+
for (const key2 of MESH_TASK_DIFFICULTIES) {
|
|
3762
|
+
const slot = brains[key2];
|
|
3763
|
+
if (!slot || !slot.provider && !slot.model && !slot.thinkingLevel) {
|
|
3764
|
+
lines.push(`- **${key2}**: (no preset \u2014 ordinary routing)`);
|
|
3765
|
+
continue;
|
|
3766
|
+
}
|
|
3767
|
+
const parts = [
|
|
3768
|
+
slot.provider ? `provider: \`${slot.provider}\`` : "",
|
|
3769
|
+
slot.model ? `model: \`${slot.model}\`` : "",
|
|
3770
|
+
slot.thinkingLevel ? `thinking: \`${slot.thinkingLevel}\`` : ""
|
|
3771
|
+
].filter(Boolean).join(" | ");
|
|
3772
|
+
lines.push(`- **${key2}**: ${parts}`);
|
|
3773
|
+
}
|
|
3774
|
+
return lines.join("\n");
|
|
3775
|
+
}
|
|
3678
3776
|
function buildPolicySection(policy) {
|
|
3679
3777
|
const rules = [];
|
|
3680
3778
|
if (policy.requirePreTaskCheckpoint) rules.push("- Create a git checkpoint **before** starting each task");
|
|
@@ -3702,6 +3800,8 @@ function buildRulesSection(coordinatorCliType) {
|
|
|
3702
3800
|
- **Route, don't implement.** Delegate all code reading, analysis, and execution to node agents. Never read source files or run commands in the coordinator \u2014 keep context lean.
|
|
3703
3801
|
- **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\`.
|
|
3704
3802
|
- **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
|
+
- **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
|
+
- **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.
|
|
3705
3805
|
- **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.
|
|
3706
3806
|
- **Verify via git, not source.** Use \`mesh_git_status\` to confirm side effects. Treat agent summaries as self-reports, not verification.
|
|
3707
3807
|
- **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).
|
|
@@ -3731,6 +3831,8 @@ var init_coordinator_prompt = __esm({
|
|
|
3731
3831
|
os2 = __toESM(require("os"));
|
|
3732
3832
|
path8 = __toESM(require("path"));
|
|
3733
3833
|
init_repo_mesh_types();
|
|
3834
|
+
init_mesh_config();
|
|
3835
|
+
init_dist();
|
|
3734
3836
|
PROMPT_SOFT_CAP_BYTES = 60 * 1024;
|
|
3735
3837
|
OPERATING_NOTES_PROMPT_CAP = 20;
|
|
3736
3838
|
OPERATING_NOTE_MAX_CHARS = 300;
|
|
@@ -3791,6 +3893,7 @@ Before doing any coordinator work, confirm that the actual callable tool list in
|
|
|
3791
3893
|
3. **Queue / Delegate** \u2014 The Mesh uses an autonomous pull-based Work Queue:
|
|
3792
3894
|
a. **General Tasks**: Enqueue tasks using \`mesh_enqueue_task\`. Idle node agents will automatically pull tasks from the queue and begin working.
|
|
3793
3895
|
b. **Node Preparation**: Reuse an existing idle session on the correct node/provider before launching a new chat/session. Call \`mesh_launch_session\` only when no suitable session exists, when the user explicitly asks for a fresh provider/session, or when branch/worktree isolation requires it. If you need branch isolation for parallel work, call \`mesh_clone_node\` to create a worktree node first.
|
|
3896
|
+
b1. **Keep a branch's work on its worktree (worktree affinity).** A worktree node is a durable per-branch workspace, not a one-task throwaway \u2014 implement, review, and fix for the same branch all belong on the SAME worktree, and it lives until its work is converged (merged/pushed) and it is cleaned up. So once you clone a worktree for a branch, route every subsequent \`code_change\`/\`validation\`/fix task for that branch back to that same node: pass \`required_tags: ["worktree=<branch>"]\` or \`target_node_id: <that worktree node's id>\`. **Where to get the node id / tag:** the \`mesh_clone_node\` result returns the new node's \`id\` and \`worktreeBranch\` directly \u2014 use them immediately. The Configured Nodes list in this prompt is a launch-time snapshot and will NOT list a worktree you cloned after this session started, so do not rely on it for freshly-cloned worktrees; take the id/branch from the \`mesh_clone_node\` result, or call \`mesh_status\` to re-list the live nodes (each worktree there advertises its \`worktree=<branch>\` tag). Do NOT leave same-branch follow-ups untargeted \u2014 an untargeted task is claimed by whichever node polls first (usually the base machine node), which strands the work off the branch's worktree. The ONE exception is a \`convergence\` task (merge/push): that is base-only and must NOT be pinned to the worktree.
|
|
3794
3897
|
c. **Targeted Tasks**: Use \`mesh_send_task\` only when you need to bypass the queue and force a specific node to execute a task immediately.
|
|
3795
3898
|
d. For the first dispatch of a new task, provide a **complete, self-contained** instruction that includes all context the agent needs (file paths, line numbers, what to change, why). Do not send partial instructions expecting future follow-up.
|
|
3796
3899
|
e. For a continuation of the same issue in an existing session, send a concise **delta instruction**: current verified state, the exact failed/blocked step, the newly approved action, and final reporting requirements. Do not resend the full original task or open a new chat solely to continue the same work; that wastes coordinator and worker context.
|
|
@@ -4241,6 +4344,9 @@ function shouldDeliverPendingEventToCoordinator(event, drainer) {
|
|
|
4241
4344
|
if (!event.intendedFor) return false;
|
|
4242
4345
|
return coordinatorIdentityEquals(event.intendedFor, drainer);
|
|
4243
4346
|
}
|
|
4347
|
+
function isTerminalTaskEvent(eventName) {
|
|
4348
|
+
return TERMINAL_TASK_EVENTS.has(eventName);
|
|
4349
|
+
}
|
|
4244
4350
|
function defaultScopeForEvent(eventName) {
|
|
4245
4351
|
if (TERMINAL_TASK_EVENTS.has(eventName) || COORDINATOR_ALERT_EVENTS.has(eventName)) return "unicast";
|
|
4246
4352
|
return "broadcast";
|
|
@@ -4257,7 +4363,11 @@ function buildPendingEventEmitStamp(opts) {
|
|
|
4257
4363
|
let scope = opts.scope ?? defaultScopeForEvent(opts.eventName);
|
|
4258
4364
|
let intendedFor = opts.intendedFor;
|
|
4259
4365
|
if (scope === "unicast" && !intendedFor) {
|
|
4260
|
-
|
|
4366
|
+
if (isTerminalTaskEvent(opts.eventName)) {
|
|
4367
|
+
intendedFor = opts.dispatchedBy;
|
|
4368
|
+
} else {
|
|
4369
|
+
scope = "broadcast";
|
|
4370
|
+
}
|
|
4261
4371
|
}
|
|
4262
4372
|
if (scope !== "unicast") intendedFor = void 0;
|
|
4263
4373
|
return {
|
|
@@ -5718,6 +5828,18 @@ function enqueueTask(meshId, message, opts) {
|
|
|
5718
5828
|
const priority = normalizeMeshTaskPriority(opts?.priority);
|
|
5719
5829
|
const notBefore = resolveNotBefore(opts?.notBefore);
|
|
5720
5830
|
const maxRetries = typeof opts?.maxRetries === "number" && Number.isFinite(opts.maxRetries) && opts.maxRetries >= 0 ? Math.floor(opts.maxRetries) : void 0;
|
|
5831
|
+
let effectiveModel = typeof opts?.model === "string" && opts.model.trim() ? opts.model.trim() : void 0;
|
|
5832
|
+
let effectiveThinkingLevel = typeof opts?.thinkingLevel === "string" && opts.thinkingLevel.trim() ? opts.thinkingLevel.trim() : void 0;
|
|
5833
|
+
if (isMeshTaskDifficulty(opts?.difficulty)) {
|
|
5834
|
+
try {
|
|
5835
|
+
const preset = getDifficultyBrains()[opts.difficulty];
|
|
5836
|
+
if (preset) {
|
|
5837
|
+
if (!effectiveModel && preset.model) effectiveModel = preset.model;
|
|
5838
|
+
if (!effectiveThinkingLevel && preset.thinkingLevel) effectiveThinkingLevel = preset.thinkingLevel;
|
|
5839
|
+
}
|
|
5840
|
+
} catch {
|
|
5841
|
+
}
|
|
5842
|
+
}
|
|
5721
5843
|
const result = withQueueLock(meshId, () => {
|
|
5722
5844
|
if (MeshRuntimeStore.getInstance().findQueueEntryById(meshId, id)) {
|
|
5723
5845
|
throw new Error(`duplicate_task_id: task '${id}' already exists in mesh '${meshId}'`);
|
|
@@ -5749,7 +5871,8 @@ function enqueueTask(meshId, message, opts) {
|
|
|
5749
5871
|
...maxRetries !== void 0 ? { maxRetries } : {},
|
|
5750
5872
|
...typeof opts?.missionId === "string" && opts.missionId.trim() ? { missionId: opts.missionId.trim() } : {},
|
|
5751
5873
|
...typeof opts?.consensusGroupId === "string" && opts.consensusGroupId.trim() ? { consensusGroupId: opts.consensusGroupId.trim() } : {},
|
|
5752
|
-
...
|
|
5874
|
+
...effectiveModel ? { model: effectiveModel } : {},
|
|
5875
|
+
...effectiveThinkingLevel ? { thinkingLevel: effectiveThinkingLevel } : {},
|
|
5753
5876
|
...typeof opts?.sourceCoordinatorSessionId === "string" && opts.sourceCoordinatorSessionId.trim() ? { sourceCoordinatorSessionId: opts.sourceCoordinatorSessionId.trim() } : {},
|
|
5754
5877
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5755
5878
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -7324,6 +7447,27 @@ var init_mesh_runtime_store = __esm({
|
|
|
7324
7447
|
`).get(meshId, taskId);
|
|
7325
7448
|
return !!row;
|
|
7326
7449
|
}
|
|
7450
|
+
/**
|
|
7451
|
+
* DELIVERED-NOT-CONSUMED re-drive support: true when at least one delivery record for
|
|
7452
|
+
* the task has reached a CONSUMED status ('acked' / 'completed'). Distinct from
|
|
7453
|
+
* {@link taskHasConfirmedDelivery} ('delivered' | 'acked' | 'completed'): a delivery is
|
|
7454
|
+
* flipped to 'delivered' the instant the transport hands the dispatch off, but only
|
|
7455
|
+
* flipped to 'acked' when the worker's agent:generating_started event arrives (see the
|
|
7456
|
+
* generating_started handler in mesh-event-forwarding) — i.e. when the session has
|
|
7457
|
+
* actually begun the turn. That distinction is the cross-daemon consumption signal the
|
|
7458
|
+
* short-grace re-drive uses: a row whose delivery is 'delivered' but never 'acked' was
|
|
7459
|
+
* handed to a REMOTE worker that never started generating — the remote autoLaunch
|
|
7460
|
+
* delivered≠consumed gap — even when the session's busy verdict is UNKNOWN (not locally
|
|
7461
|
+
* observable). Indexed by (mesh_id, task_id).
|
|
7462
|
+
*/
|
|
7463
|
+
taskDeliveryConsumed(meshId, taskId) {
|
|
7464
|
+
const row = this.db.prepare(`
|
|
7465
|
+
SELECT 1 FROM mesh_session_delivery
|
|
7466
|
+
WHERE mesh_id = ? AND task_id = ? AND status IN ('acked','completed')
|
|
7467
|
+
LIMIT 1
|
|
7468
|
+
`).get(meshId, taskId);
|
|
7469
|
+
return !!row;
|
|
7470
|
+
}
|
|
7327
7471
|
expireStaleSessionDeliveries(meshId) {
|
|
7328
7472
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
7329
7473
|
this.db.prepare(`
|
|
@@ -8412,6 +8556,17 @@ function routeV2EventsForDrainer(events, drainer, ctx) {
|
|
|
8412
8556
|
continue;
|
|
8413
8557
|
}
|
|
8414
8558
|
if (validated.scope !== "unicast") {
|
|
8559
|
+
if (validated.scope === "broadcast" && isTerminalTaskEvent(validated.event)) {
|
|
8560
|
+
const deliverSelfFallback = event.dispatchedBySelfFallback && daemonIdsEquivalent(validated.dispatchedBy.daemonId, drainer.daemonId);
|
|
8561
|
+
if (deliverSelfFallback || identityDeliversTo(validated.dispatchedBy, drainer)) {
|
|
8562
|
+
ctx.batchSeen.add(eventId);
|
|
8563
|
+
bump("v2Delivered");
|
|
8564
|
+
kept.push(event);
|
|
8565
|
+
} else {
|
|
8566
|
+
bump("v2RoutedAway");
|
|
8567
|
+
}
|
|
8568
|
+
continue;
|
|
8569
|
+
}
|
|
8415
8570
|
if (shouldDeliverPendingEventToCoordinator(validated, drainer)) {
|
|
8416
8571
|
ctx.batchSeen.add(eventId);
|
|
8417
8572
|
bump("v2Delivered");
|
|
@@ -8675,13 +8830,15 @@ function stampPendingEventV2(event, hint) {
|
|
|
8675
8830
|
scope: hint?.scope ?? (selfFallback ? "broadcast" : void 0)
|
|
8676
8831
|
});
|
|
8677
8832
|
if (!stamp) return event;
|
|
8833
|
+
const dispatchedBySelfFallback = selfFallback && stamp.scope === "broadcast";
|
|
8678
8834
|
return {
|
|
8679
8835
|
...event,
|
|
8680
8836
|
protocolVersion: stamp.protocolVersion,
|
|
8681
8837
|
eventId: stamp.eventId,
|
|
8682
8838
|
scope: stamp.scope,
|
|
8683
8839
|
dispatchedBy: stamp.dispatchedBy,
|
|
8684
|
-
...stamp.intendedFor ? { intendedFor: stamp.intendedFor } : {}
|
|
8840
|
+
...stamp.intendedFor ? { intendedFor: stamp.intendedFor } : {},
|
|
8841
|
+
...dispatchedBySelfFallback ? { dispatchedBySelfFallback: true } : {}
|
|
8685
8842
|
};
|
|
8686
8843
|
}
|
|
8687
8844
|
function readCoordinatorIdentityFromWire(raw) {
|
|
@@ -15207,8 +15364,23 @@ function mergeInlineCacheOnlyNodes(localMesh, cachedMesh) {
|
|
|
15207
15364
|
if (!cachedId) return false;
|
|
15208
15365
|
return !localNodes.some((localNode) => meshNodeIdMatches(localNode, cachedId));
|
|
15209
15366
|
});
|
|
15210
|
-
|
|
15211
|
-
|
|
15367
|
+
let overlaidLocalNodes = localNodes;
|
|
15368
|
+
let overlaid = false;
|
|
15369
|
+
for (let i = 0; i < localNodes.length; i++) {
|
|
15370
|
+
const localNode = localNodes[i];
|
|
15371
|
+
const localId = readMeshNodeId(localNode);
|
|
15372
|
+
if (!localId) continue;
|
|
15373
|
+
const inlineMatch = cachedNodes.find((cachedNode) => meshNodeIdMatches(cachedNode, localId));
|
|
15374
|
+
const inlineBootstrapStatus = readNonEmptyString2(inlineMatch?.worktreeBootstrap?.status);
|
|
15375
|
+
if (!inlineMatch || !inlineBootstrapStatus) continue;
|
|
15376
|
+
if (!overlaid) {
|
|
15377
|
+
overlaidLocalNodes = [...localNodes];
|
|
15378
|
+
overlaid = true;
|
|
15379
|
+
}
|
|
15380
|
+
overlaidLocalNodes[i] = { ...localNode, worktreeBootstrap: inlineMatch.worktreeBootstrap };
|
|
15381
|
+
}
|
|
15382
|
+
if (!cacheOnly.length && !overlaid) return localMesh;
|
|
15383
|
+
return { ...localMesh, nodes: [...overlaidLocalNodes, ...cacheOnly] };
|
|
15212
15384
|
}
|
|
15213
15385
|
function warnDispatchWarmupGetterMissingOnce(daemonId) {
|
|
15214
15386
|
if (dispatchWarmupGetterMissingWarned.has(daemonId)) return;
|
|
@@ -16078,7 +16250,9 @@ async function maybeAutoLaunchOneQueueSession(components, meshId, mesh) {
|
|
|
16078
16250
|
settings: remoteSettings,
|
|
16079
16251
|
// MAGI-KIND-PANEL model axis: forward the task's model override so the
|
|
16080
16252
|
// remote worker session launches with it (initialModel). Best-effort.
|
|
16081
|
-
...typeof task.model === "string" && task.model.trim() ? { initialModel: task.model.trim() } : {}
|
|
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() } : {}
|
|
16082
16256
|
});
|
|
16083
16257
|
} catch (e) {
|
|
16084
16258
|
markAutoLaunch(meshId, task.id, { status: "failed", reason: `remote_launch_dispatch_failed: ${e?.message || String(e)}`, nodeId, providerType: resolved.providerType });
|
|
@@ -16107,7 +16281,9 @@ async function maybeAutoLaunchOneQueueSession(components, meshId, mesh) {
|
|
|
16107
16281
|
settings: launchSettings,
|
|
16108
16282
|
// MAGI-KIND-PANEL model axis: local launch forwards the task's model
|
|
16109
16283
|
// override as initialModel (CLI → modelLaunchArgs; ACP → setConfigOption).
|
|
16110
|
-
...typeof task.model === "string" && task.model.trim() ? { initialModel: task.model.trim() } : {}
|
|
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() } : {}
|
|
16111
16287
|
});
|
|
16112
16288
|
if (!launchResult?.success) {
|
|
16113
16289
|
const reason = launchResult?.error || "launch_cli_failed";
|
|
@@ -18667,6 +18843,8 @@ function buildAvailableProviders(providerLoader) {
|
|
|
18667
18843
|
...sourceLayer ? { sourceLayer } : {},
|
|
18668
18844
|
...sourceName ? { sourceName } : {},
|
|
18669
18845
|
...provider.providerVersion ? { providerVersion: provider.providerVersion } : {},
|
|
18846
|
+
...Array.isArray(provider.modelOptions) && provider.modelOptions.length ? { modelOptions: provider.modelOptions } : {},
|
|
18847
|
+
...Array.isArray(provider.thinkingLevelOptions) && provider.thinkingLevelOptions.length ? { thinkingLevelOptions: provider.thinkingLevelOptions } : {},
|
|
18670
18848
|
...provider.binary ? { binary: provider.binary } : {},
|
|
18671
18849
|
...provider.status ? { status: provider.status } : {},
|
|
18672
18850
|
...provider.details ? { details: provider.details } : {},
|
|
@@ -21004,7 +21182,34 @@ function recoverStrandedAssignedDispatches(components, meshId, store) {
|
|
|
21004
21182
|
for (const row of assigned) {
|
|
21005
21183
|
const dispatchedAtMs = Date.parse(row.dispatchTimestamp ?? "");
|
|
21006
21184
|
if (!Number.isFinite(dispatchedAtMs)) continue;
|
|
21007
|
-
|
|
21185
|
+
const ageMs = nowMs - dispatchedAtMs;
|
|
21186
|
+
if (ageMs >= ASSIGNED_DELIVERED_UNCONSUMED_REDRIVE_MS && ageMs < ASSIGNED_STRANDED_DEADLINE_MS && store.taskHasConfirmedDelivery(meshId, row.id) && !store.taskDeliveryConsumed(meshId, row.id)) {
|
|
21187
|
+
const terminal2 = findTerminalLedgerEvidenceForTask({ meshId, taskId: row.id });
|
|
21188
|
+
if (terminal2) {
|
|
21189
|
+
const status = terminal2.kind === "task_completed" ? "completed" : "failed";
|
|
21190
|
+
updateTaskStatus(meshId, row.id, status);
|
|
21191
|
+
continue;
|
|
21192
|
+
}
|
|
21193
|
+
const verdict = row.assignedSessionId ? resolveSessionBusyVerdict(components, row.assignedSessionId) : "IDLE_CONFIRMED";
|
|
21194
|
+
if (verdict !== "GENERATING") {
|
|
21195
|
+
const redriven = reclaimStrandedAssignedTask(meshId, row.id, {
|
|
21196
|
+
reason: "delivered_not_consumed_redrive",
|
|
21197
|
+
ageMs
|
|
21198
|
+
});
|
|
21199
|
+
if (redriven) {
|
|
21200
|
+
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})`);
|
|
21201
|
+
traceMeshEventDrop("assigned_delivered_not_consumed_redrive", {
|
|
21202
|
+
taskId: row.id,
|
|
21203
|
+
sessionId: row.assignedSessionId,
|
|
21204
|
+
nodeId: row.assignedNodeId,
|
|
21205
|
+
meshId,
|
|
21206
|
+
event: "agent:generating_started"
|
|
21207
|
+
}, `delivered_not_consumed ${Math.round(ageMs / 1e3)}s \u2192 ${redriven.status}`);
|
|
21208
|
+
continue;
|
|
21209
|
+
}
|
|
21210
|
+
}
|
|
21211
|
+
}
|
|
21212
|
+
if (ageMs < ASSIGNED_STRANDED_DEADLINE_MS) continue;
|
|
21008
21213
|
const terminal = findTerminalLedgerEvidenceForTask({
|
|
21009
21214
|
meshId,
|
|
21010
21215
|
taskId: row.id
|
|
@@ -21519,7 +21724,7 @@ function setupMeshReconcileLoop(components) {
|
|
|
21519
21724
|
}
|
|
21520
21725
|
};
|
|
21521
21726
|
}
|
|
21522
|
-
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;
|
|
21727
|
+
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;
|
|
21523
21728
|
var init_mesh_reconcile_loop = __esm({
|
|
21524
21729
|
"src/mesh/mesh-reconcile-loop.ts"() {
|
|
21525
21730
|
"use strict";
|
|
@@ -21549,6 +21754,7 @@ var init_mesh_reconcile_loop = __esm({
|
|
|
21549
21754
|
heldEventLedgerRecorded = /* @__PURE__ */ new Set();
|
|
21550
21755
|
ASSIGNED_STRANDED_DEADLINE_MS = 5 * 6e4;
|
|
21551
21756
|
DELIVERED_NO_TURN_DEADLINE_MS = 15 * 6e4;
|
|
21757
|
+
ASSIGNED_DELIVERED_UNCONSUMED_REDRIVE_MS = 25e3;
|
|
21552
21758
|
RECLAIM_UNKNOWN_GRACE_TICKS = 3;
|
|
21553
21759
|
deliveredNoTurnUnknownStreak = /* @__PURE__ */ new Map();
|
|
21554
21760
|
ZOMBIE_ASSIGNED_MIN_AGE_MS = 30 * 60 * 1e3;
|
|
@@ -21824,6 +22030,35 @@ var init_provider_schema = __esm({
|
|
|
21824
22030
|
items: { type: "string" },
|
|
21825
22031
|
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."
|
|
21826
22032
|
},
|
|
22033
|
+
modelOptions: {
|
|
22034
|
+
type: "array",
|
|
22035
|
+
items: { type: "string" },
|
|
22036
|
+
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."
|
|
22037
|
+
},
|
|
22038
|
+
thinkingLaunchArgs: {
|
|
22039
|
+
type: "array",
|
|
22040
|
+
items: { type: "string" },
|
|
22041
|
+
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."
|
|
22042
|
+
},
|
|
22043
|
+
thinkingLevelMap: {
|
|
22044
|
+
type: "object",
|
|
22045
|
+
properties: {
|
|
22046
|
+
low: { type: "string" },
|
|
22047
|
+
medium: { type: "string" },
|
|
22048
|
+
high: { type: "string" }
|
|
22049
|
+
},
|
|
22050
|
+
additionalProperties: false,
|
|
22051
|
+
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."
|
|
22052
|
+
},
|
|
22053
|
+
thinkingLevelOptions: {
|
|
22054
|
+
type: "array",
|
|
22055
|
+
items: { type: "string" },
|
|
22056
|
+
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."
|
|
22057
|
+
},
|
|
22058
|
+
thinkingControlId: {
|
|
22059
|
+
type: "string",
|
|
22060
|
+
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> }."
|
|
22061
|
+
},
|
|
21827
22062
|
scriptCallBudgetMs: {
|
|
21828
22063
|
type: "integer",
|
|
21829
22064
|
minimum: 1,
|
|
@@ -40179,6 +40414,53 @@ var statusMetaHandlers = {
|
|
|
40179
40414
|
|
|
40180
40415
|
// src/commands/low-family/coordinator-prompt.ts
|
|
40181
40416
|
var coordinatorPromptHandlers = {
|
|
40417
|
+
/**
|
|
40418
|
+
* Render the coordinator system prompt for a mesh + CLI type, so the
|
|
40419
|
+
* dashboard can show the operator exactly what a coordinator session
|
|
40420
|
+
* receives by default. This resolves the mesh, applies its repo-mesh
|
|
40421
|
+
* config, and runs the SAME buildCoordinatorSystemPrompt the launch path
|
|
40422
|
+
* uses — minus the runtime-only best-effort sections (mission / recent
|
|
40423
|
+
* activity / operating notes), which are launch-scope and not part of the
|
|
40424
|
+
* static "default base" an operator is trying to preview here.
|
|
40425
|
+
*
|
|
40426
|
+
* It respects mesh-level and user-file override/append layering, so the
|
|
40427
|
+
* preview reflects the effective prompt: with no overrides configured it
|
|
40428
|
+
* shows the pure daemon default; with an override set it shows that.
|
|
40429
|
+
*/
|
|
40430
|
+
coordinator_prompt_preview: async (ctx, args) => {
|
|
40431
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
40432
|
+
const cliType = typeof args?.cliType === "string" && args.cliType.trim() ? args.cliType.trim() : "claude-cli";
|
|
40433
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
40434
|
+
try {
|
|
40435
|
+
let mesh = null;
|
|
40436
|
+
if (ctx.getMeshForCommand) {
|
|
40437
|
+
const resolved = await ctx.getMeshForCommand(meshId);
|
|
40438
|
+
mesh = resolved?.mesh ?? null;
|
|
40439
|
+
}
|
|
40440
|
+
if (!mesh) {
|
|
40441
|
+
const { getMesh: getMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
40442
|
+
mesh = getMesh2(meshId);
|
|
40443
|
+
}
|
|
40444
|
+
if (!mesh) return { success: false, error: `mesh not found: ${meshId}` };
|
|
40445
|
+
let effectiveMesh = mesh;
|
|
40446
|
+
try {
|
|
40447
|
+
const { loadRepoMeshJsonConfig: loadRepoMeshJsonConfig2, applyRepoMeshConfig: applyRepoMeshConfig2 } = await Promise.resolve().then(() => (init_mesh_json_config(), mesh_json_config_exports));
|
|
40448
|
+
const workspace = typeof mesh?.workspace === "string" ? mesh.workspace : void 0;
|
|
40449
|
+
if (workspace) {
|
|
40450
|
+
const loaded = loadRepoMeshJsonConfig2(workspace);
|
|
40451
|
+
if (loaded?.sourceType !== "invalid") {
|
|
40452
|
+
effectiveMesh = applyRepoMeshConfig2(mesh, loaded?.config);
|
|
40453
|
+
}
|
|
40454
|
+
}
|
|
40455
|
+
} catch {
|
|
40456
|
+
}
|
|
40457
|
+
const { buildCoordinatorSystemPrompt: buildCoordinatorSystemPrompt2 } = await Promise.resolve().then(() => (init_coordinator_prompt(), coordinator_prompt_exports));
|
|
40458
|
+
const prompt = buildCoordinatorSystemPrompt2({ mesh: effectiveMesh, coordinatorCliType: cliType });
|
|
40459
|
+
return { success: true, prompt, cliType, meshId, bytes: Buffer.byteLength(prompt, "utf8") };
|
|
40460
|
+
} catch (error) {
|
|
40461
|
+
return { success: false, error: error?.message || String(error) };
|
|
40462
|
+
}
|
|
40463
|
+
},
|
|
40182
40464
|
list_coordinator_prompts: async (_ctx, _args) => {
|
|
40183
40465
|
const fs41 = await import("fs");
|
|
40184
40466
|
const path45 = await import("path");
|
|
@@ -44881,6 +45163,7 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
44881
45163
|
this.presentationMode = "chat";
|
|
44882
45164
|
this.providerSessionId = options?.providerSessionId;
|
|
44883
45165
|
this.launchMode = options?.launchMode || "new";
|
|
45166
|
+
this.initialThinkingLevel = options?.initialThinkingLevel;
|
|
44884
45167
|
this.onProviderSessionResolved = options?.onProviderSessionResolved;
|
|
44885
45168
|
this.adapter = createCliAdapter(provider, workingDir, cliArgs, options?.extraEnv || {}, transportFactory);
|
|
44886
45169
|
if (this.providerSessionId) {
|
|
@@ -45102,6 +45385,7 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
45102
45385
|
presentationMode;
|
|
45103
45386
|
providerSessionId;
|
|
45104
45387
|
launchMode;
|
|
45388
|
+
initialThinkingLevel;
|
|
45105
45389
|
startedAt = Date.now();
|
|
45106
45390
|
onProviderSessionResolved;
|
|
45107
45391
|
refreshProviderDefinition(provider) {
|
|
@@ -45130,6 +45414,7 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
45130
45414
|
});
|
|
45131
45415
|
await this.adapter.spawn();
|
|
45132
45416
|
await this.enforceFreshSessionLaunchIfNeeded();
|
|
45417
|
+
await this.applyInitialThinkingLevelViaControl();
|
|
45133
45418
|
this.maybeAppendRuntimeRecoveryMessage(this.adapter.getRuntimeMetadata());
|
|
45134
45419
|
if (this.providerSessionId && this.shouldHydrateExistingProviderHistory()) {
|
|
45135
45420
|
this.restorePersistedHistoryFromCurrentSession();
|
|
@@ -45747,6 +46032,43 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
45747
46032
|
}
|
|
45748
46033
|
this.applyProviderResponse(parsed.payload, { phase: "immediate" });
|
|
45749
46034
|
}
|
|
46035
|
+
/**
|
|
46036
|
+
* BRAIN-ROUTING (runtime-control thinking axis): for a provider that selects
|
|
46037
|
+
* reasoning effort via a runtime control instead of a launch arg (e.g. hermes
|
|
46038
|
+
* `reasoning`), apply the requested initialThinkingLevel after spawn by invoking
|
|
46039
|
+
* that control's setScript. The provider names the control via thinkingControlId.
|
|
46040
|
+
* The standard level is mapped through thinkingLevelMap first (same as the
|
|
46041
|
+
* launch-arg path). Best-effort: any failure logs and never blocks launch.
|
|
46042
|
+
*/
|
|
46043
|
+
async applyInitialThinkingLevelViaControl() {
|
|
46044
|
+
const level = typeof this.initialThinkingLevel === "string" ? this.initialThinkingLevel.trim() : "";
|
|
46045
|
+
if (!level) return;
|
|
46046
|
+
const controlId = this.provider.thinkingControlId;
|
|
46047
|
+
if (!controlId) return;
|
|
46048
|
+
const controls = Array.isArray(this.provider.controls) ? this.provider.controls : [];
|
|
46049
|
+
const control = controls.find((c) => c && c.id === controlId);
|
|
46050
|
+
if (!control || !control.setScript) return;
|
|
46051
|
+
const map = this.provider.thinkingLevelMap;
|
|
46052
|
+
const mapped = map && typeof map[level] === "string" && map[level].trim() ? map[level].trim() : level;
|
|
46053
|
+
try {
|
|
46054
|
+
await waitForCliAdapterReady(this.adapter);
|
|
46055
|
+
const raw = await this.adapter.invokeScript(control.setScript, { value: mapped });
|
|
46056
|
+
const parsed = parseCliScriptResult(raw);
|
|
46057
|
+
if (!parsed.success) {
|
|
46058
|
+
LOG.warn("CLI", `[${this.type}] thinking control '${controlId}' set to '${mapped}' failed: ${parsed.payload?.error || "unknown"}`);
|
|
46059
|
+
return;
|
|
46060
|
+
}
|
|
46061
|
+
const cliCommand = getCliScriptCommand(parsed.payload);
|
|
46062
|
+
if (cliCommand?.type === "send_message" && cliCommand.text) {
|
|
46063
|
+
await this.adapter.sendMessage(cliCommand.text);
|
|
46064
|
+
} else if (cliCommand?.type === "pty_write" && cliCommand.text) {
|
|
46065
|
+
await this.adapter.writeRaw(cliCommand.text + "\r");
|
|
46066
|
+
}
|
|
46067
|
+
LOG.info("CLI", `[${this.type}] applied thinking level '${mapped}' via control '${controlId}'`);
|
|
46068
|
+
} catch (e) {
|
|
46069
|
+
LOG.warn("CLI", `[${this.type}] thinking control apply threw: ${e?.message || e}`);
|
|
46070
|
+
}
|
|
46071
|
+
}
|
|
45750
46072
|
completionHasFinalAssistantMessage(messages, turnStartedAt) {
|
|
45751
46073
|
const visibleMessages = (Array.isArray(messages) ? messages : []).filter((message) => isUserFacingChatMessage(message));
|
|
45752
46074
|
const lastVisible = visibleMessages[visibleMessages.length - 1];
|
|
@@ -48853,7 +49175,13 @@ function expandResumeArgs(template, sessionId) {
|
|
|
48853
49175
|
function expandModelLaunchArgs(template, model) {
|
|
48854
49176
|
const m = typeof model === "string" ? model.trim() : "";
|
|
48855
49177
|
if (!m || !Array.isArray(template) || template.length === 0) return void 0;
|
|
48856
|
-
return template.map((part) => part
|
|
49178
|
+
return template.map((part) => part.includes("{{model}}") ? part.split("{{model}}").join(m) : part);
|
|
49179
|
+
}
|
|
49180
|
+
function expandThinkingLaunchArgs(template, level, levelMap) {
|
|
49181
|
+
const raw = typeof level === "string" ? level.trim() : "";
|
|
49182
|
+
if (!raw || !Array.isArray(template) || template.length === 0) return void 0;
|
|
49183
|
+
const mapped = levelMap && typeof levelMap[raw] === "string" && levelMap[raw].trim() ? levelMap[raw].trim() : raw;
|
|
49184
|
+
return template.map((part) => part.includes("{{level}}") ? part.replace("{{level}}", mapped) : part);
|
|
48857
49185
|
}
|
|
48858
49186
|
function readSubcommandSessionId(args, subcommands) {
|
|
48859
49187
|
const resumeIndex = args.findIndex((arg) => subcommands.includes(arg));
|
|
@@ -49237,6 +49565,15 @@ ${installInfo}`
|
|
|
49237
49565
|
LOG.warn("CLI", `[ACP] Initial model set failed: ${e?.message}`);
|
|
49238
49566
|
}
|
|
49239
49567
|
}
|
|
49568
|
+
if (options?.initialThinkingLevel) {
|
|
49569
|
+
const lvl = options.initialThinkingLevel;
|
|
49570
|
+
try {
|
|
49571
|
+
await acpInstance.setConfigOption("thought_level", lvl);
|
|
49572
|
+
console.log(colorize("green", ` \u{1F9E0} Initial thinking level set: ${lvl}`));
|
|
49573
|
+
} catch (e) {
|
|
49574
|
+
LOG.warn("CLI", `[ACP] Initial thinking level set failed (provider may not support thought_level): ${e?.message}`);
|
|
49575
|
+
}
|
|
49576
|
+
}
|
|
49240
49577
|
this.persistRecentActivity({
|
|
49241
49578
|
kind: "acp",
|
|
49242
49579
|
providerType: normalizedType,
|
|
@@ -49272,7 +49609,13 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
49272
49609
|
if (initialModel && !modelLaunchArgs) {
|
|
49273
49610
|
LOG.warn("CLI", `[${normalizedType}] initialModel='${initialModel}' requested but provider declares no modelLaunchArgs template \u2014 launching without model selection.`);
|
|
49274
49611
|
}
|
|
49275
|
-
const
|
|
49612
|
+
const initialThinkingLevel = options?.initialThinkingLevel;
|
|
49613
|
+
const thinkingLaunchArgs = expandThinkingLaunchArgs(provider?.thinkingLaunchArgs, initialThinkingLevel, provider?.thinkingLevelMap);
|
|
49614
|
+
const cliArgsWithBrain = thinkingLaunchArgs ? [...thinkingLaunchArgs, ...cliArgsWithModel || []] : cliArgsWithModel;
|
|
49615
|
+
if (initialThinkingLevel && !thinkingLaunchArgs) {
|
|
49616
|
+
LOG.warn("CLI", `[${normalizedType}] initialThinkingLevel='${initialThinkingLevel}' requested but provider declares no thinkingLaunchArgs template \u2014 launching without thinking-level selection.`);
|
|
49617
|
+
}
|
|
49618
|
+
const sessionBinding = resolveCliSessionBinding(provider, normalizedType, cliArgsWithBrain, options?.resumeSessionId);
|
|
49276
49619
|
const resolvedCliArgs = sessionBinding.cliArgs;
|
|
49277
49620
|
const instanceManager = this.deps.getInstanceManager();
|
|
49278
49621
|
if (provider && instanceManager) {
|
|
@@ -49290,6 +49633,10 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
49290
49633
|
providerSessionId: sessionBinding.providerSessionId,
|
|
49291
49634
|
launchMode: sessionBinding.launchMode,
|
|
49292
49635
|
extraEnv: options?.extraEnv,
|
|
49636
|
+
// BRAIN-ROUTING: for a provider with no thinkingLaunchArgs but a
|
|
49637
|
+
// runtime reasoning control (hermes), apply the level post-launch.
|
|
49638
|
+
// The launch-arg providers (claude/codex) already consumed it at spawn.
|
|
49639
|
+
...options?.initialThinkingLevel && !provider?.thinkingLaunchArgs ? { initialThinkingLevel: options.initialThinkingLevel } : {},
|
|
49293
49640
|
onProviderSessionResolved: ({ providerSessionId, providerName, providerType, workspace }) => {
|
|
49294
49641
|
this.persistRecentActivity({
|
|
49295
49642
|
kind: "cli",
|
|
@@ -49637,7 +49984,8 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
49637
49984
|
{
|
|
49638
49985
|
resumeSessionId: args?.resumeSessionId,
|
|
49639
49986
|
settingsOverride,
|
|
49640
|
-
extraEnv: delegatedLaunch ? delegatedLaunch.env : args?.env
|
|
49987
|
+
extraEnv: delegatedLaunch ? delegatedLaunch.env : args?.env,
|
|
49988
|
+
...typeof args?.initialThinkingLevel === "string" && args.initialThinkingLevel.trim() ? { initialThinkingLevel: args.initialThinkingLevel.trim() } : {}
|
|
49641
49989
|
}
|
|
49642
49990
|
);
|
|
49643
49991
|
return {
|
|
@@ -50082,6 +50430,12 @@ var KNOWN_PROVIDER_FIELDS = /* @__PURE__ */ new Set([
|
|
|
50082
50430
|
"providerVersion",
|
|
50083
50431
|
"status",
|
|
50084
50432
|
"details",
|
|
50433
|
+
"modelLaunchArgs",
|
|
50434
|
+
"modelOptions",
|
|
50435
|
+
"thinkingLaunchArgs",
|
|
50436
|
+
"thinkingLevelMap",
|
|
50437
|
+
"thinkingLevelOptions",
|
|
50438
|
+
"thinkingControlId",
|
|
50085
50439
|
"sendDelayMs",
|
|
50086
50440
|
"sendKey",
|
|
50087
50441
|
"submitStrategy",
|
|
@@ -54795,6 +55149,26 @@ var meshCrudHandlers = {
|
|
|
54795
55149
|
return { success: false, error: e.message };
|
|
54796
55150
|
}
|
|
54797
55151
|
},
|
|
55152
|
+
// ─── Brain routing: per-difficulty brain presets (machine-local) ───
|
|
55153
|
+
// getDifficultyBrains returns the seeded defaults when nothing is configured,
|
|
55154
|
+
// so the editor always shows a usable mapping. set replaces the whole map.
|
|
55155
|
+
difficulty_brains_get: async (_ctx, _args) => {
|
|
55156
|
+
try {
|
|
55157
|
+
const { getDifficultyBrains: getDifficultyBrains2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
55158
|
+
return { success: true, difficultyBrains: getDifficultyBrains2() };
|
|
55159
|
+
} catch (e) {
|
|
55160
|
+
return { success: false, error: e.message };
|
|
55161
|
+
}
|
|
55162
|
+
},
|
|
55163
|
+
difficulty_brains_set: async (_ctx, args) => {
|
|
55164
|
+
try {
|
|
55165
|
+
const { setDifficultyBrains: setDifficultyBrains2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
55166
|
+
const difficultyBrains = setDifficultyBrains2(args?.difficultyBrains);
|
|
55167
|
+
return { success: true, difficultyBrains };
|
|
55168
|
+
} catch (e) {
|
|
55169
|
+
return { success: false, error: e.message };
|
|
55170
|
+
}
|
|
55171
|
+
},
|
|
54798
55172
|
add_mesh_node: async (ctx, args) => {
|
|
54799
55173
|
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
54800
55174
|
const workspace = typeof args?.workspace === "string" ? args.workspace.trim() : "";
|
|
@@ -54816,13 +55190,15 @@ var meshCrudHandlers = {
|
|
|
54816
55190
|
const daemonId = typeof args?.daemonId === "string" && args.daemonId.trim() ? args.daemonId.trim() : void 0;
|
|
54817
55191
|
const machineId = typeof args?.machineId === "string" && args.machineId.trim() ? args.machineId.trim() : void 0;
|
|
54818
55192
|
const repoRoot = typeof args?.repoRoot === "string" && args.repoRoot.trim() ? args.repoRoot.trim() : void 0;
|
|
55193
|
+
const capabilities = Array.isArray(args?.capabilities) ? args.capabilities.map((t) => typeof t === "string" ? t.trim() : "").filter(Boolean) : void 0;
|
|
54819
55194
|
const node = addNode2(meshId, {
|
|
54820
55195
|
workspace,
|
|
54821
55196
|
...repoRoot ? { repoRoot } : {},
|
|
54822
55197
|
...daemonId ? { daemonId } : {},
|
|
54823
55198
|
...machineId ? { machineId } : {},
|
|
54824
55199
|
...policy ? { policy } : {},
|
|
54825
|
-
...role ? { role } : {}
|
|
55200
|
+
...role ? { role } : {},
|
|
55201
|
+
...capabilities && capabilities.length ? { capabilities } : {}
|
|
54826
55202
|
});
|
|
54827
55203
|
if (!node) return { success: false, error: "Mesh not found" };
|
|
54828
55204
|
ctx.invalidateAggregateMeshStatus(meshId);
|
|
@@ -54864,6 +55240,9 @@ var meshCrudHandlers = {
|
|
|
54864
55240
|
} else if (args?.systemPrompt === null) {
|
|
54865
55241
|
patch.systemPrompt = void 0;
|
|
54866
55242
|
}
|
|
55243
|
+
if (Array.isArray(args?.capabilities)) {
|
|
55244
|
+
patch.capabilities = args.capabilities.map((t) => typeof t === "string" ? t.trim() : "").filter(Boolean);
|
|
55245
|
+
}
|
|
54867
55246
|
const node = updateNode2(meshId, nodeId, patch);
|
|
54868
55247
|
if (!node) return { success: false, error: "Mesh node not found" };
|
|
54869
55248
|
ctx.invalidateAggregateMeshStatus(meshId);
|