@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.mjs
CHANGED
|
@@ -183,7 +183,7 @@ var init_repo_mesh_types = __esm({
|
|
|
183
183
|
"checkpoint_then_continue"
|
|
184
184
|
]);
|
|
185
185
|
MESH_MAX_PARALLEL_TASKS_MIN = 1;
|
|
186
|
-
MESH_MAX_PARALLEL_TASKS_MAX =
|
|
186
|
+
MESH_MAX_PARALLEL_TASKS_MAX = 64;
|
|
187
187
|
DEFAULT_MESH_READONLY_MULTIPLIER = 2;
|
|
188
188
|
}
|
|
189
189
|
});
|
|
@@ -404,10 +404,10 @@ function readInjected(value) {
|
|
|
404
404
|
}
|
|
405
405
|
function getDaemonBuildInfo() {
|
|
406
406
|
if (cached) return cached;
|
|
407
|
-
const commit = readInjected(true ? "
|
|
408
|
-
const commitShort = readInjected(true ? "
|
|
409
|
-
const version = readInjected(true ? "0.9.82-rc.
|
|
410
|
-
const builtAt = readInjected(true ? "2026-07-
|
|
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
|
-
|
|
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,
|
|
@@ -3306,6 +3341,11 @@ function updateNode(meshId, nodeId, opts) {
|
|
|
3306
3341
|
node.reportedDaemonBuildVersion = opts.reportedDaemonBuildVersion.trim();
|
|
3307
3342
|
}
|
|
3308
3343
|
if (opts.policy) node.policy = { ...node.policy, ...opts.policy };
|
|
3344
|
+
if (Object.prototype.hasOwnProperty.call(opts, "capabilities")) {
|
|
3345
|
+
const tags = normalizeCapabilityTags(opts.capabilities);
|
|
3346
|
+
if (tags && tags.length) node.capabilities = tags;
|
|
3347
|
+
else delete node.capabilities;
|
|
3348
|
+
}
|
|
3309
3349
|
if (opts.worktreeBootstrap) node.worktreeBootstrap = opts.worktreeBootstrap;
|
|
3310
3350
|
if (Object.prototype.hasOwnProperty.call(opts, "systemPrompt")) {
|
|
3311
3351
|
if (opts.systemPrompt && opts.systemPrompt.trim()) {
|
|
@@ -3394,12 +3434,26 @@ function removeMagiKindPanel(kind) {
|
|
|
3394
3434
|
saveMeshConfig(stored);
|
|
3395
3435
|
return true;
|
|
3396
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
|
+
}
|
|
3397
3450
|
var mergeMeshPolicy, MAGI_KIND_PANEL_KINDS, MAX_MAGI_KIND_SLOTS;
|
|
3398
3451
|
var init_mesh_config = __esm({
|
|
3399
3452
|
"src/config/mesh-config.ts"() {
|
|
3400
3453
|
"use strict";
|
|
3401
3454
|
init_hash();
|
|
3402
3455
|
init_config();
|
|
3456
|
+
init_dist();
|
|
3403
3457
|
init_repo_mesh_types();
|
|
3404
3458
|
init_mesh_host_ownership();
|
|
3405
3459
|
mergeMeshPolicy = mergeAndNormalizePolicy;
|
|
@@ -3499,6 +3553,7 @@ Default branch: \`${mesh.defaultBranch}\`` : ""}`);
|
|
|
3499
3553
|
if (operatingNotes) sections.push(operatingNotes);
|
|
3500
3554
|
}
|
|
3501
3555
|
sections.push(buildPolicySection(mergeAndNormalizePolicy(void 0, mesh.policy)));
|
|
3556
|
+
sections.push(buildBrainPresetsSection());
|
|
3502
3557
|
sections.push(TOOLS_SECTION);
|
|
3503
3558
|
sections.push(TOOL_EXPOSURE_PREFLIGHT_SECTION);
|
|
3504
3559
|
sections.push(WORKFLOW_SECTION);
|
|
@@ -3598,6 +3653,21 @@ function buildNodeConfigSection(mesh) {
|
|
|
3598
3653
|
}).filter(Boolean) : [];
|
|
3599
3654
|
const providerRolesSuffix = providerRoles.length ? ` | caps: ${providerRoles.join(", ")}` : "";
|
|
3600
3655
|
lines.push(`- ${explicitLabel} nodeId: \`${n.id}\` | workspace: \`${n.workspace}\`${n.daemonId ? ` | daemon: \`${n.daemonId}\`` : ""}${providerPriority}${providerRolesSuffix}${suffix}`);
|
|
3656
|
+
const routingTags = [];
|
|
3657
|
+
const custom = Array.isArray(n.capabilities) ? n.capabilities : [];
|
|
3658
|
+
for (const t of custom) {
|
|
3659
|
+
const s2 = typeof t === "string" ? t.trim() : "";
|
|
3660
|
+
if (s2) routingTags.push(s2);
|
|
3661
|
+
}
|
|
3662
|
+
const tagOs = (n.userOverrides?.platform || n.reportedPlatform || "").toString().trim();
|
|
3663
|
+
const tagArch = (n.userOverrides?.arch || n.reportedArch || "").toString().trim();
|
|
3664
|
+
if (tagOs) routingTags.push(`os=${tagOs}`);
|
|
3665
|
+
if (tagArch) routingTags.push(`arch=${tagArch}`);
|
|
3666
|
+
const wtBranch = typeof n.worktreeBranch === "string" ? n.worktreeBranch.trim() : "";
|
|
3667
|
+
if (n.isLocalWorktree && wtBranch) routingTags.push(`worktree=${wtBranch}`);
|
|
3668
|
+
if (routingTags.length) {
|
|
3669
|
+
lines.push(` \u{1F3F7}\uFE0F routing tags: ${routingTags.map((t) => `\`${t}\``).join(", ")}`);
|
|
3670
|
+
}
|
|
3601
3671
|
const nodePrompt = typeof n.systemPrompt === "string" ? n.systemPrompt.trim() : "";
|
|
3602
3672
|
if (nodePrompt) {
|
|
3603
3673
|
lines.push(` \u{1F4CC} Node instruction: ${indentFollowing(nodePrompt, " ")}`);
|
|
@@ -3672,6 +3742,34 @@ function truncateNote(text) {
|
|
|
3672
3742
|
if (text.length <= OPERATING_NOTE_MAX_CHARS) return text;
|
|
3673
3743
|
return `${text.slice(0, OPERATING_NOTE_MAX_CHARS).trimEnd()}\u2026 [truncated]`;
|
|
3674
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
|
+
}
|
|
3675
3773
|
function buildPolicySection(policy) {
|
|
3676
3774
|
const rules = [];
|
|
3677
3775
|
if (policy.requirePreTaskCheckpoint) rules.push("- Create a git checkpoint **before** starting each task");
|
|
@@ -3699,6 +3797,8 @@ function buildRulesSection(coordinatorCliType) {
|
|
|
3699
3797
|
- **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.
|
|
3700
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\`.
|
|
3701
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.
|
|
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.
|
|
3702
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.
|
|
3703
3803
|
- **Verify via git, not source.** Use \`mesh_git_status\` to confirm side effects. Treat agent summaries as self-reports, not verification.
|
|
3704
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).
|
|
@@ -3725,6 +3825,8 @@ var init_coordinator_prompt = __esm({
|
|
|
3725
3825
|
"src/mesh/coordinator-prompt.ts"() {
|
|
3726
3826
|
"use strict";
|
|
3727
3827
|
init_repo_mesh_types();
|
|
3828
|
+
init_mesh_config();
|
|
3829
|
+
init_dist();
|
|
3728
3830
|
PROMPT_SOFT_CAP_BYTES = 60 * 1024;
|
|
3729
3831
|
OPERATING_NOTES_PROMPT_CAP = 20;
|
|
3730
3832
|
OPERATING_NOTE_MAX_CHARS = 300;
|
|
@@ -3785,6 +3887,7 @@ Before doing any coordinator work, confirm that the actual callable tool list in
|
|
|
3785
3887
|
3. **Queue / Delegate** \u2014 The Mesh uses an autonomous pull-based Work Queue:
|
|
3786
3888
|
a. **General Tasks**: Enqueue tasks using \`mesh_enqueue_task\`. Idle node agents will automatically pull tasks from the queue and begin working.
|
|
3787
3889
|
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.
|
|
3890
|
+
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.
|
|
3788
3891
|
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.
|
|
3789
3892
|
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.
|
|
3790
3893
|
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.
|
|
@@ -4234,6 +4337,9 @@ function shouldDeliverPendingEventToCoordinator(event, drainer) {
|
|
|
4234
4337
|
if (!event.intendedFor) return false;
|
|
4235
4338
|
return coordinatorIdentityEquals(event.intendedFor, drainer);
|
|
4236
4339
|
}
|
|
4340
|
+
function isTerminalTaskEvent(eventName) {
|
|
4341
|
+
return TERMINAL_TASK_EVENTS.has(eventName);
|
|
4342
|
+
}
|
|
4237
4343
|
function defaultScopeForEvent(eventName) {
|
|
4238
4344
|
if (TERMINAL_TASK_EVENTS.has(eventName) || COORDINATOR_ALERT_EVENTS.has(eventName)) return "unicast";
|
|
4239
4345
|
return "broadcast";
|
|
@@ -4250,7 +4356,11 @@ function buildPendingEventEmitStamp(opts) {
|
|
|
4250
4356
|
let scope = opts.scope ?? defaultScopeForEvent(opts.eventName);
|
|
4251
4357
|
let intendedFor = opts.intendedFor;
|
|
4252
4358
|
if (scope === "unicast" && !intendedFor) {
|
|
4253
|
-
|
|
4359
|
+
if (isTerminalTaskEvent(opts.eventName)) {
|
|
4360
|
+
intendedFor = opts.dispatchedBy;
|
|
4361
|
+
} else {
|
|
4362
|
+
scope = "broadcast";
|
|
4363
|
+
}
|
|
4254
4364
|
}
|
|
4255
4365
|
if (scope !== "unicast") intendedFor = void 0;
|
|
4256
4366
|
return {
|
|
@@ -5712,6 +5822,18 @@ function enqueueTask(meshId, message, opts) {
|
|
|
5712
5822
|
const priority = normalizeMeshTaskPriority(opts?.priority);
|
|
5713
5823
|
const notBefore = resolveNotBefore(opts?.notBefore);
|
|
5714
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
|
+
}
|
|
5715
5837
|
const result = withQueueLock(meshId, () => {
|
|
5716
5838
|
if (MeshRuntimeStore.getInstance().findQueueEntryById(meshId, id)) {
|
|
5717
5839
|
throw new Error(`duplicate_task_id: task '${id}' already exists in mesh '${meshId}'`);
|
|
@@ -5743,7 +5865,8 @@ function enqueueTask(meshId, message, opts) {
|
|
|
5743
5865
|
...maxRetries !== void 0 ? { maxRetries } : {},
|
|
5744
5866
|
...typeof opts?.missionId === "string" && opts.missionId.trim() ? { missionId: opts.missionId.trim() } : {},
|
|
5745
5867
|
...typeof opts?.consensusGroupId === "string" && opts.consensusGroupId.trim() ? { consensusGroupId: opts.consensusGroupId.trim() } : {},
|
|
5746
|
-
...
|
|
5868
|
+
...effectiveModel ? { model: effectiveModel } : {},
|
|
5869
|
+
...effectiveThinkingLevel ? { thinkingLevel: effectiveThinkingLevel } : {},
|
|
5747
5870
|
...typeof opts?.sourceCoordinatorSessionId === "string" && opts.sourceCoordinatorSessionId.trim() ? { sourceCoordinatorSessionId: opts.sourceCoordinatorSessionId.trim() } : {},
|
|
5748
5871
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5749
5872
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -7317,6 +7440,27 @@ var init_mesh_runtime_store = __esm({
|
|
|
7317
7440
|
`).get(meshId, taskId);
|
|
7318
7441
|
return !!row;
|
|
7319
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
|
+
}
|
|
7320
7464
|
expireStaleSessionDeliveries(meshId) {
|
|
7321
7465
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
7322
7466
|
this.db.prepare(`
|
|
@@ -8408,6 +8552,17 @@ function routeV2EventsForDrainer(events, drainer, ctx) {
|
|
|
8408
8552
|
continue;
|
|
8409
8553
|
}
|
|
8410
8554
|
if (validated.scope !== "unicast") {
|
|
8555
|
+
if (validated.scope === "broadcast" && isTerminalTaskEvent(validated.event)) {
|
|
8556
|
+
const deliverSelfFallback = event.dispatchedBySelfFallback && daemonIdsEquivalent(validated.dispatchedBy.daemonId, drainer.daemonId);
|
|
8557
|
+
if (deliverSelfFallback || identityDeliversTo(validated.dispatchedBy, drainer)) {
|
|
8558
|
+
ctx.batchSeen.add(eventId);
|
|
8559
|
+
bump("v2Delivered");
|
|
8560
|
+
kept.push(event);
|
|
8561
|
+
} else {
|
|
8562
|
+
bump("v2RoutedAway");
|
|
8563
|
+
}
|
|
8564
|
+
continue;
|
|
8565
|
+
}
|
|
8411
8566
|
if (shouldDeliverPendingEventToCoordinator(validated, drainer)) {
|
|
8412
8567
|
ctx.batchSeen.add(eventId);
|
|
8413
8568
|
bump("v2Delivered");
|
|
@@ -8671,13 +8826,15 @@ function stampPendingEventV2(event, hint) {
|
|
|
8671
8826
|
scope: hint?.scope ?? (selfFallback ? "broadcast" : void 0)
|
|
8672
8827
|
});
|
|
8673
8828
|
if (!stamp) return event;
|
|
8829
|
+
const dispatchedBySelfFallback = selfFallback && stamp.scope === "broadcast";
|
|
8674
8830
|
return {
|
|
8675
8831
|
...event,
|
|
8676
8832
|
protocolVersion: stamp.protocolVersion,
|
|
8677
8833
|
eventId: stamp.eventId,
|
|
8678
8834
|
scope: stamp.scope,
|
|
8679
8835
|
dispatchedBy: stamp.dispatchedBy,
|
|
8680
|
-
...stamp.intendedFor ? { intendedFor: stamp.intendedFor } : {}
|
|
8836
|
+
...stamp.intendedFor ? { intendedFor: stamp.intendedFor } : {},
|
|
8837
|
+
...dispatchedBySelfFallback ? { dispatchedBySelfFallback: true } : {}
|
|
8681
8838
|
};
|
|
8682
8839
|
}
|
|
8683
8840
|
function readCoordinatorIdentityFromWire(raw) {
|
|
@@ -15210,8 +15367,23 @@ function mergeInlineCacheOnlyNodes(localMesh, cachedMesh) {
|
|
|
15210
15367
|
if (!cachedId) return false;
|
|
15211
15368
|
return !localNodes.some((localNode) => meshNodeIdMatches(localNode, cachedId));
|
|
15212
15369
|
});
|
|
15213
|
-
|
|
15214
|
-
|
|
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] };
|
|
15215
15387
|
}
|
|
15216
15388
|
function warnDispatchWarmupGetterMissingOnce(daemonId) {
|
|
15217
15389
|
if (dispatchWarmupGetterMissingWarned.has(daemonId)) return;
|
|
@@ -16081,7 +16253,9 @@ async function maybeAutoLaunchOneQueueSession(components, meshId, mesh) {
|
|
|
16081
16253
|
settings: remoteSettings,
|
|
16082
16254
|
// MAGI-KIND-PANEL model axis: forward the task's model override so the
|
|
16083
16255
|
// remote worker session launches with it (initialModel). Best-effort.
|
|
16084
|
-
...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() } : {}
|
|
16085
16259
|
});
|
|
16086
16260
|
} catch (e) {
|
|
16087
16261
|
markAutoLaunch(meshId, task.id, { status: "failed", reason: `remote_launch_dispatch_failed: ${e?.message || String(e)}`, nodeId, providerType: resolved.providerType });
|
|
@@ -16110,7 +16284,9 @@ async function maybeAutoLaunchOneQueueSession(components, meshId, mesh) {
|
|
|
16110
16284
|
settings: launchSettings,
|
|
16111
16285
|
// MAGI-KIND-PANEL model axis: local launch forwards the task's model
|
|
16112
16286
|
// override as initialModel (CLI → modelLaunchArgs; ACP → setConfigOption).
|
|
16113
|
-
...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() } : {}
|
|
16114
16290
|
});
|
|
16115
16291
|
if (!launchResult?.success) {
|
|
16116
16292
|
const reason = launchResult?.error || "launch_cli_failed";
|
|
@@ -18670,6 +18846,8 @@ function buildAvailableProviders(providerLoader) {
|
|
|
18670
18846
|
...sourceLayer ? { sourceLayer } : {},
|
|
18671
18847
|
...sourceName ? { sourceName } : {},
|
|
18672
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 } : {},
|
|
18673
18851
|
...provider.binary ? { binary: provider.binary } : {},
|
|
18674
18852
|
...provider.status ? { status: provider.status } : {},
|
|
18675
18853
|
...provider.details ? { details: provider.details } : {},
|
|
@@ -21006,7 +21184,34 @@ function recoverStrandedAssignedDispatches(components, meshId, store) {
|
|
|
21006
21184
|
for (const row of assigned) {
|
|
21007
21185
|
const dispatchedAtMs = Date.parse(row.dispatchTimestamp ?? "");
|
|
21008
21186
|
if (!Number.isFinite(dispatchedAtMs)) continue;
|
|
21009
|
-
|
|
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;
|
|
21010
21215
|
const terminal = findTerminalLedgerEvidenceForTask({
|
|
21011
21216
|
meshId,
|
|
21012
21217
|
taskId: row.id
|
|
@@ -21521,7 +21726,7 @@ function setupMeshReconcileLoop(components) {
|
|
|
21521
21726
|
}
|
|
21522
21727
|
};
|
|
21523
21728
|
}
|
|
21524
|
-
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;
|
|
21525
21730
|
var init_mesh_reconcile_loop = __esm({
|
|
21526
21731
|
"src/mesh/mesh-reconcile-loop.ts"() {
|
|
21527
21732
|
"use strict";
|
|
@@ -21551,6 +21756,7 @@ var init_mesh_reconcile_loop = __esm({
|
|
|
21551
21756
|
heldEventLedgerRecorded = /* @__PURE__ */ new Set();
|
|
21552
21757
|
ASSIGNED_STRANDED_DEADLINE_MS = 5 * 6e4;
|
|
21553
21758
|
DELIVERED_NO_TURN_DEADLINE_MS = 15 * 6e4;
|
|
21759
|
+
ASSIGNED_DELIVERED_UNCONSUMED_REDRIVE_MS = 25e3;
|
|
21554
21760
|
RECLAIM_UNKNOWN_GRACE_TICKS = 3;
|
|
21555
21761
|
deliveredNoTurnUnknownStreak = /* @__PURE__ */ new Map();
|
|
21556
21762
|
ZOMBIE_ASSIGNED_MIN_AGE_MS = 30 * 60 * 1e3;
|
|
@@ -21826,6 +22032,35 @@ var init_provider_schema = __esm({
|
|
|
21826
22032
|
items: { type: "string" },
|
|
21827
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."
|
|
21828
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
|
+
},
|
|
21829
22064
|
scriptCallBudgetMs: {
|
|
21830
22065
|
type: "integer",
|
|
21831
22066
|
minimum: 1,
|
|
@@ -39760,6 +39995,53 @@ var statusMetaHandlers = {
|
|
|
39760
39995
|
|
|
39761
39996
|
// src/commands/low-family/coordinator-prompt.ts
|
|
39762
39997
|
var coordinatorPromptHandlers = {
|
|
39998
|
+
/**
|
|
39999
|
+
* Render the coordinator system prompt for a mesh + CLI type, so the
|
|
40000
|
+
* dashboard can show the operator exactly what a coordinator session
|
|
40001
|
+
* receives by default. This resolves the mesh, applies its repo-mesh
|
|
40002
|
+
* config, and runs the SAME buildCoordinatorSystemPrompt the launch path
|
|
40003
|
+
* uses — minus the runtime-only best-effort sections (mission / recent
|
|
40004
|
+
* activity / operating notes), which are launch-scope and not part of the
|
|
40005
|
+
* static "default base" an operator is trying to preview here.
|
|
40006
|
+
*
|
|
40007
|
+
* It respects mesh-level and user-file override/append layering, so the
|
|
40008
|
+
* preview reflects the effective prompt: with no overrides configured it
|
|
40009
|
+
* shows the pure daemon default; with an override set it shows that.
|
|
40010
|
+
*/
|
|
40011
|
+
coordinator_prompt_preview: async (ctx, args) => {
|
|
40012
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
40013
|
+
const cliType = typeof args?.cliType === "string" && args.cliType.trim() ? args.cliType.trim() : "claude-cli";
|
|
40014
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
40015
|
+
try {
|
|
40016
|
+
let mesh = null;
|
|
40017
|
+
if (ctx.getMeshForCommand) {
|
|
40018
|
+
const resolved = await ctx.getMeshForCommand(meshId);
|
|
40019
|
+
mesh = resolved?.mesh ?? null;
|
|
40020
|
+
}
|
|
40021
|
+
if (!mesh) {
|
|
40022
|
+
const { getMesh: getMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
40023
|
+
mesh = getMesh2(meshId);
|
|
40024
|
+
}
|
|
40025
|
+
if (!mesh) return { success: false, error: `mesh not found: ${meshId}` };
|
|
40026
|
+
let effectiveMesh = mesh;
|
|
40027
|
+
try {
|
|
40028
|
+
const { loadRepoMeshJsonConfig: loadRepoMeshJsonConfig2, applyRepoMeshConfig: applyRepoMeshConfig2 } = await Promise.resolve().then(() => (init_mesh_json_config(), mesh_json_config_exports));
|
|
40029
|
+
const workspace = typeof mesh?.workspace === "string" ? mesh.workspace : void 0;
|
|
40030
|
+
if (workspace) {
|
|
40031
|
+
const loaded = loadRepoMeshJsonConfig2(workspace);
|
|
40032
|
+
if (loaded?.sourceType !== "invalid") {
|
|
40033
|
+
effectiveMesh = applyRepoMeshConfig2(mesh, loaded?.config);
|
|
40034
|
+
}
|
|
40035
|
+
}
|
|
40036
|
+
} catch {
|
|
40037
|
+
}
|
|
40038
|
+
const { buildCoordinatorSystemPrompt: buildCoordinatorSystemPrompt2 } = await Promise.resolve().then(() => (init_coordinator_prompt(), coordinator_prompt_exports));
|
|
40039
|
+
const prompt = buildCoordinatorSystemPrompt2({ mesh: effectiveMesh, coordinatorCliType: cliType });
|
|
40040
|
+
return { success: true, prompt, cliType, meshId, bytes: Buffer.byteLength(prompt, "utf8") };
|
|
40041
|
+
} catch (error) {
|
|
40042
|
+
return { success: false, error: error?.message || String(error) };
|
|
40043
|
+
}
|
|
40044
|
+
},
|
|
39763
40045
|
list_coordinator_prompts: async (_ctx, _args) => {
|
|
39764
40046
|
const fs41 = await import("fs");
|
|
39765
40047
|
const path45 = await import("path");
|
|
@@ -44462,6 +44744,7 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
44462
44744
|
this.presentationMode = "chat";
|
|
44463
44745
|
this.providerSessionId = options?.providerSessionId;
|
|
44464
44746
|
this.launchMode = options?.launchMode || "new";
|
|
44747
|
+
this.initialThinkingLevel = options?.initialThinkingLevel;
|
|
44465
44748
|
this.onProviderSessionResolved = options?.onProviderSessionResolved;
|
|
44466
44749
|
this.adapter = createCliAdapter(provider, workingDir, cliArgs, options?.extraEnv || {}, transportFactory);
|
|
44467
44750
|
if (this.providerSessionId) {
|
|
@@ -44683,6 +44966,7 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
44683
44966
|
presentationMode;
|
|
44684
44967
|
providerSessionId;
|
|
44685
44968
|
launchMode;
|
|
44969
|
+
initialThinkingLevel;
|
|
44686
44970
|
startedAt = Date.now();
|
|
44687
44971
|
onProviderSessionResolved;
|
|
44688
44972
|
refreshProviderDefinition(provider) {
|
|
@@ -44711,6 +44995,7 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
44711
44995
|
});
|
|
44712
44996
|
await this.adapter.spawn();
|
|
44713
44997
|
await this.enforceFreshSessionLaunchIfNeeded();
|
|
44998
|
+
await this.applyInitialThinkingLevelViaControl();
|
|
44714
44999
|
this.maybeAppendRuntimeRecoveryMessage(this.adapter.getRuntimeMetadata());
|
|
44715
45000
|
if (this.providerSessionId && this.shouldHydrateExistingProviderHistory()) {
|
|
44716
45001
|
this.restorePersistedHistoryFromCurrentSession();
|
|
@@ -45328,6 +45613,43 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
45328
45613
|
}
|
|
45329
45614
|
this.applyProviderResponse(parsed.payload, { phase: "immediate" });
|
|
45330
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
|
+
}
|
|
45331
45653
|
completionHasFinalAssistantMessage(messages, turnStartedAt) {
|
|
45332
45654
|
const visibleMessages = (Array.isArray(messages) ? messages : []).filter((message) => isUserFacingChatMessage(message));
|
|
45333
45655
|
const lastVisible = visibleMessages[visibleMessages.length - 1];
|
|
@@ -48439,7 +48761,13 @@ function expandResumeArgs(template, sessionId) {
|
|
|
48439
48761
|
function expandModelLaunchArgs(template, model) {
|
|
48440
48762
|
const m = typeof model === "string" ? model.trim() : "";
|
|
48441
48763
|
if (!m || !Array.isArray(template) || template.length === 0) return void 0;
|
|
48442
|
-
return template.map((part) => 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);
|
|
48443
48771
|
}
|
|
48444
48772
|
function readSubcommandSessionId(args, subcommands) {
|
|
48445
48773
|
const resumeIndex = args.findIndex((arg) => subcommands.includes(arg));
|
|
@@ -48823,6 +49151,15 @@ ${installInfo}`
|
|
|
48823
49151
|
LOG.warn("CLI", `[ACP] Initial model set failed: ${e?.message}`);
|
|
48824
49152
|
}
|
|
48825
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
|
+
}
|
|
48826
49163
|
this.persistRecentActivity({
|
|
48827
49164
|
kind: "acp",
|
|
48828
49165
|
providerType: normalizedType,
|
|
@@ -48858,7 +49195,13 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
48858
49195
|
if (initialModel && !modelLaunchArgs) {
|
|
48859
49196
|
LOG.warn("CLI", `[${normalizedType}] initialModel='${initialModel}' requested but provider declares no modelLaunchArgs template \u2014 launching without model selection.`);
|
|
48860
49197
|
}
|
|
48861
|
-
const
|
|
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);
|
|
48862
49205
|
const resolvedCliArgs = sessionBinding.cliArgs;
|
|
48863
49206
|
const instanceManager = this.deps.getInstanceManager();
|
|
48864
49207
|
if (provider && instanceManager) {
|
|
@@ -48876,6 +49219,10 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
48876
49219
|
providerSessionId: sessionBinding.providerSessionId,
|
|
48877
49220
|
launchMode: sessionBinding.launchMode,
|
|
48878
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 } : {},
|
|
48879
49226
|
onProviderSessionResolved: ({ providerSessionId, providerName, providerType, workspace }) => {
|
|
48880
49227
|
this.persistRecentActivity({
|
|
48881
49228
|
kind: "cli",
|
|
@@ -49223,7 +49570,8 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
49223
49570
|
{
|
|
49224
49571
|
resumeSessionId: args?.resumeSessionId,
|
|
49225
49572
|
settingsOverride,
|
|
49226
|
-
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() } : {}
|
|
49227
49575
|
}
|
|
49228
49576
|
);
|
|
49229
49577
|
return {
|
|
@@ -49668,6 +50016,12 @@ var KNOWN_PROVIDER_FIELDS = /* @__PURE__ */ new Set([
|
|
|
49668
50016
|
"providerVersion",
|
|
49669
50017
|
"status",
|
|
49670
50018
|
"details",
|
|
50019
|
+
"modelLaunchArgs",
|
|
50020
|
+
"modelOptions",
|
|
50021
|
+
"thinkingLaunchArgs",
|
|
50022
|
+
"thinkingLevelMap",
|
|
50023
|
+
"thinkingLevelOptions",
|
|
50024
|
+
"thinkingControlId",
|
|
49671
50025
|
"sendDelayMs",
|
|
49672
50026
|
"sendKey",
|
|
49673
50027
|
"submitStrategy",
|
|
@@ -54381,6 +54735,26 @@ var meshCrudHandlers = {
|
|
|
54381
54735
|
return { success: false, error: e.message };
|
|
54382
54736
|
}
|
|
54383
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
|
+
},
|
|
54384
54758
|
add_mesh_node: async (ctx, args) => {
|
|
54385
54759
|
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
54386
54760
|
const workspace = typeof args?.workspace === "string" ? args.workspace.trim() : "";
|
|
@@ -54402,13 +54776,15 @@ var meshCrudHandlers = {
|
|
|
54402
54776
|
const daemonId = typeof args?.daemonId === "string" && args.daemonId.trim() ? args.daemonId.trim() : void 0;
|
|
54403
54777
|
const machineId = typeof args?.machineId === "string" && args.machineId.trim() ? args.machineId.trim() : void 0;
|
|
54404
54778
|
const repoRoot = typeof args?.repoRoot === "string" && args.repoRoot.trim() ? args.repoRoot.trim() : void 0;
|
|
54779
|
+
const capabilities = Array.isArray(args?.capabilities) ? args.capabilities.map((t) => typeof t === "string" ? t.trim() : "").filter(Boolean) : void 0;
|
|
54405
54780
|
const node = addNode2(meshId, {
|
|
54406
54781
|
workspace,
|
|
54407
54782
|
...repoRoot ? { repoRoot } : {},
|
|
54408
54783
|
...daemonId ? { daemonId } : {},
|
|
54409
54784
|
...machineId ? { machineId } : {},
|
|
54410
54785
|
...policy ? { policy } : {},
|
|
54411
|
-
...role ? { role } : {}
|
|
54786
|
+
...role ? { role } : {},
|
|
54787
|
+
...capabilities && capabilities.length ? { capabilities } : {}
|
|
54412
54788
|
});
|
|
54413
54789
|
if (!node) return { success: false, error: "Mesh not found" };
|
|
54414
54790
|
ctx.invalidateAggregateMeshStatus(meshId);
|
|
@@ -54450,6 +54826,9 @@ var meshCrudHandlers = {
|
|
|
54450
54826
|
} else if (args?.systemPrompt === null) {
|
|
54451
54827
|
patch.systemPrompt = void 0;
|
|
54452
54828
|
}
|
|
54829
|
+
if (Array.isArray(args?.capabilities)) {
|
|
54830
|
+
patch.capabilities = args.capabilities.map((t) => typeof t === "string" ? t.trim() : "").filter(Boolean);
|
|
54831
|
+
}
|
|
54453
54832
|
const node = updateNode2(meshId, nodeId, patch);
|
|
54454
54833
|
if (!node) return { success: false, error: "Mesh node not found" };
|
|
54455
54834
|
ctx.invalidateAggregateMeshStatus(meshId);
|