@adhdev/daemon-core 0.9.82-rc.485 → 0.9.82-rc.487
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/git/git-status.d.ts +23 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +343 -55
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +342 -55
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/mesh-queue-assignment.d.ts +4 -0
- package/dist/mesh/mesh-refine-gates.d.ts +29 -0
- package/dist/mesh/mesh-work-queue.d.ts +9 -0
- package/dist/repo-mesh-types.d.ts +18 -2
- package/dist/shared-types.d.ts +8 -0
- package/dist/status/snapshot.d.ts +1 -0
- package/package.json +3 -3
- package/src/commands/handler.ts +21 -1
- package/src/commands/high-family/mesh-coordinator-launch.ts +17 -1
- package/src/commands/high-family/mesh-status.ts +8 -0
- package/src/commands/med-family/cli-agent.ts +29 -0
- package/src/commands/router-refine.ts +27 -2
- package/src/git/git-status.ts +84 -29
- package/src/index.ts +1 -1
- package/src/mesh/coordinator-prompt.ts +4 -1
- package/src/mesh/mesh-queue-assignment.ts +164 -27
- package/src/mesh/mesh-refine-gates.ts +113 -7
- package/src/mesh/mesh-work-queue.ts +14 -0
- package/src/repo-mesh-types.ts +28 -3
- package/src/shared-types.ts +8 -0
- package/src/status/builders.ts +45 -2
- package/src/status/snapshot.ts +1 -1
package/dist/index.js
CHANGED
|
@@ -145,7 +145,8 @@ var init_repo_mesh_types = __esm({
|
|
|
145
145
|
"first_eligible",
|
|
146
146
|
"least_loaded",
|
|
147
147
|
"round_robin",
|
|
148
|
-
"priority_only"
|
|
148
|
+
"priority_only",
|
|
149
|
+
"fitness"
|
|
149
150
|
];
|
|
150
151
|
DEFAULT_MESH_SCHEDULING_STRATEGY = "first_eligible";
|
|
151
152
|
MESH_CONVERGE_REFINE_TAG = "converge=refine";
|
|
@@ -157,7 +158,11 @@ var init_repo_mesh_types = __esm({
|
|
|
157
158
|
allowAutoPublishSubmoduleMainCommits: false,
|
|
158
159
|
requireApprovalForDestructiveGit: true,
|
|
159
160
|
dirtyWorkspaceBehavior: "warn",
|
|
160
|
-
|
|
161
|
+
// Mesh-wide task cap is effectively unlimited by default: the real concurrency
|
|
162
|
+
// limits live per node / per capability slot (ORCHESTRATION_NODE_SLOTS.md), so a
|
|
163
|
+
// global ceiling is rarely meaningful. The UI hides this control; set it via the
|
|
164
|
+
// API only to impose a deliberate mesh-wide cap.
|
|
165
|
+
maxParallelTasks: 200,
|
|
161
166
|
// Coordinator-spawned worker sessions default to hidden so the dashboard is not
|
|
162
167
|
// flooded with mesh noise tabs/notifications. Users can still surface or unmute
|
|
163
168
|
// any specific session manually; that override is preserved per-device.
|
|
@@ -409,10 +414,10 @@ function readInjected(value) {
|
|
|
409
414
|
}
|
|
410
415
|
function getDaemonBuildInfo() {
|
|
411
416
|
if (cached) return cached;
|
|
412
|
-
const commit = readInjected(true ? "
|
|
413
|
-
const commitShort = readInjected(true ? "
|
|
414
|
-
const version = readInjected(true ? "0.9.82-rc.
|
|
415
|
-
const builtAt = readInjected(true ? "2026-07-
|
|
417
|
+
const commit = readInjected(true ? "ef3ded0f5df148982ed222411ea08c6ab0fdb39b" : void 0) ?? "unknown";
|
|
418
|
+
const commitShort = readInjected(true ? "ef3ded0f" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
419
|
+
const version = readInjected(true ? "0.9.82-rc.487" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
420
|
+
const builtAt = readInjected(true ? "2026-07-10T01:53:17.254Z" : void 0);
|
|
416
421
|
cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
|
|
417
422
|
return cached;
|
|
418
423
|
}
|
|
@@ -784,30 +789,41 @@ function isNonRuntimeRootFile(file, policy) {
|
|
|
784
789
|
}
|
|
785
790
|
return false;
|
|
786
791
|
}
|
|
792
|
+
function classifyChangedFileList(files, policy) {
|
|
793
|
+
if (files.length === 0) {
|
|
794
|
+
return { isDaemonAffecting: true, affectedPackages: [] };
|
|
795
|
+
}
|
|
796
|
+
const pkgs = /* @__PURE__ */ new Set();
|
|
797
|
+
let sawRuntimeAmbiguousNonPackage = false;
|
|
798
|
+
for (const file of files) {
|
|
799
|
+
const match = file.match(/(?:^|\/)packages\/([^/]+)\//);
|
|
800
|
+
if (!match) {
|
|
801
|
+
if (!isNonRuntimeRootFile(file, policy)) sawRuntimeAmbiguousNonPackage = true;
|
|
802
|
+
continue;
|
|
803
|
+
}
|
|
804
|
+
pkgs.add(match[1]);
|
|
805
|
+
}
|
|
806
|
+
const affectedPackages = [...pkgs].sort();
|
|
807
|
+
const allBenign = !sawRuntimeAmbiguousNonPackage && affectedPackages.every((p) => policy.webOnlyPackages.has(p) && !policy.daemonRuntimePackages.has(p));
|
|
808
|
+
return { isDaemonAffecting: !allBenign, affectedPackages };
|
|
809
|
+
}
|
|
787
810
|
async function classifyDaemonBuildChange(repoPath, buildCommit, options, policy) {
|
|
788
811
|
try {
|
|
789
812
|
const diff = await runGit(repoPath, ["diff", "--name-only", `${buildCommit}..HEAD`], options);
|
|
790
813
|
const files = diff.stdout.split("\n").map((line) => line.trim()).filter(Boolean);
|
|
791
|
-
|
|
792
|
-
return { isDaemonAffecting: true, affectedPackages: [] };
|
|
793
|
-
}
|
|
794
|
-
const pkgs = /* @__PURE__ */ new Set();
|
|
795
|
-
let sawRuntimeAmbiguousNonPackage = false;
|
|
796
|
-
for (const file of files) {
|
|
797
|
-
const match = file.match(/(?:^|\/)packages\/([^/]+)\//);
|
|
798
|
-
if (!match) {
|
|
799
|
-
if (!isNonRuntimeRootFile(file, policy)) sawRuntimeAmbiguousNonPackage = true;
|
|
800
|
-
continue;
|
|
801
|
-
}
|
|
802
|
-
pkgs.add(match[1]);
|
|
803
|
-
}
|
|
804
|
-
const affectedPackages = [...pkgs].sort();
|
|
805
|
-
const allBenign = !sawRuntimeAmbiguousNonPackage && affectedPackages.every((p) => policy.webOnlyPackages.has(p) && !policy.daemonRuntimePackages.has(p));
|
|
806
|
-
return { isDaemonAffecting: !allBenign, affectedPackages };
|
|
814
|
+
return classifyChangedFileList(files, policy);
|
|
807
815
|
} catch {
|
|
808
816
|
return { isDaemonAffecting: true, affectedPackages: [] };
|
|
809
817
|
}
|
|
810
818
|
}
|
|
819
|
+
async function classifyChangedPackages(repoPath, fromRef, toRef, options = {}) {
|
|
820
|
+
const repo = await resolveGitRepository(repoPath, options);
|
|
821
|
+
const { config } = resolveChangeImpactConfigForRepo(repo.repoRoot, options);
|
|
822
|
+
const policy = resolveChangeImpactPolicy(config);
|
|
823
|
+
const diff = await runGit(repoPath, ["diff", "--name-only", `${fromRef}..${toRef}`], options);
|
|
824
|
+
const files = diff.stdout.split("\n").map((line) => line.trim()).filter(Boolean);
|
|
825
|
+
return classifyChangedFileList(files, policy);
|
|
826
|
+
}
|
|
811
827
|
function resolveChangeImpactConfigForRepo(repoRoot, options) {
|
|
812
828
|
if (options.changeImpactConfig === null) {
|
|
813
829
|
return { config: null, sourceKey: "forced-default" };
|
|
@@ -2798,6 +2814,74 @@ function normalizeDifficultyBrainMap(raw) {
|
|
|
2798
2814
|
}
|
|
2799
2815
|
return out;
|
|
2800
2816
|
}
|
|
2817
|
+
function normalizeNodeCapabilitySlot(raw) {
|
|
2818
|
+
const r = raw && typeof raw === "object" ? raw : {};
|
|
2819
|
+
const provider = typeof r.provider === "string" ? r.provider.trim() : "";
|
|
2820
|
+
if (!provider) return null;
|
|
2821
|
+
const model = typeof r.model === "string" ? r.model.trim() : "";
|
|
2822
|
+
const thinkingLevel = typeof r.thinkingLevel === "string" ? r.thinkingLevel.trim() : "";
|
|
2823
|
+
const difficulty = Array.isArray(r.difficulty) ? r.difficulty.filter(isMeshTaskDifficulty) : [];
|
|
2824
|
+
const capability = Array.isArray(r.capability) ? r.capability.filter((t) => typeof t === "string" && !!t.trim()).map((t) => t.trim()) : [];
|
|
2825
|
+
const maxParallelNum = Number(r.maxParallel);
|
|
2826
|
+
const maxParallel = Number.isFinite(maxParallelNum) && maxParallelNum > 0 ? Math.floor(maxParallelNum) : void 0;
|
|
2827
|
+
return {
|
|
2828
|
+
provider,
|
|
2829
|
+
...model ? { model } : {},
|
|
2830
|
+
...thinkingLevel ? { thinkingLevel } : {},
|
|
2831
|
+
...difficulty.length ? { difficulty } : {},
|
|
2832
|
+
...capability.length ? { capability } : {},
|
|
2833
|
+
...maxParallel !== void 0 ? { maxParallel } : {}
|
|
2834
|
+
};
|
|
2835
|
+
}
|
|
2836
|
+
function normalizeNodeCapabilitySlots(raw) {
|
|
2837
|
+
if (!Array.isArray(raw)) return [];
|
|
2838
|
+
const out = [];
|
|
2839
|
+
for (const entry of raw) {
|
|
2840
|
+
const slot = normalizeNodeCapabilitySlot(entry);
|
|
2841
|
+
if (slot) out.push(slot);
|
|
2842
|
+
}
|
|
2843
|
+
return out;
|
|
2844
|
+
}
|
|
2845
|
+
function deriveSlotsFromLegacy(input) {
|
|
2846
|
+
const priority = Array.isArray(input.providerPriority) ? input.providerPriority.filter((p) => typeof p === "string" && !!p.trim()).map((p) => p.trim()) : [];
|
|
2847
|
+
if (priority.length === 0) return [];
|
|
2848
|
+
const roleCap = /* @__PURE__ */ new Map();
|
|
2849
|
+
for (const role of input.providerRoles || []) {
|
|
2850
|
+
if (role && typeof role.providerType === "string" && Number.isFinite(role.maxParallel)) {
|
|
2851
|
+
roleCap.set(role.providerType.trim(), Math.floor(Number(role.maxParallel)));
|
|
2852
|
+
}
|
|
2853
|
+
}
|
|
2854
|
+
const brains = input.difficultyBrains || {};
|
|
2855
|
+
const byProvider = /* @__PURE__ */ new Map();
|
|
2856
|
+
const shared = [];
|
|
2857
|
+
for (const diff of MESH_TASK_DIFFICULTIES) {
|
|
2858
|
+
const b = brains[diff];
|
|
2859
|
+
if (!b) continue;
|
|
2860
|
+
const entry = { difficulty: diff, model: b.model, thinkingLevel: b.thinkingLevel };
|
|
2861
|
+
if (b.provider) {
|
|
2862
|
+
const list = byProvider.get(b.provider) ?? [];
|
|
2863
|
+
list.push(entry);
|
|
2864
|
+
byProvider.set(b.provider, list);
|
|
2865
|
+
} else {
|
|
2866
|
+
shared.push(entry);
|
|
2867
|
+
}
|
|
2868
|
+
}
|
|
2869
|
+
return priority.map((provider) => {
|
|
2870
|
+
const specific = byProvider.get(provider) || [];
|
|
2871
|
+
const applied = specific.length ? specific : shared;
|
|
2872
|
+
const difficulty = applied.map((a) => a.difficulty);
|
|
2873
|
+
const model = applied.find((a) => a.model)?.model;
|
|
2874
|
+
const thinkingLevel = applied.find((a) => a.thinkingLevel)?.thinkingLevel;
|
|
2875
|
+
const maxParallel = roleCap.get(provider);
|
|
2876
|
+
return {
|
|
2877
|
+
provider,
|
|
2878
|
+
...model ? { model } : {},
|
|
2879
|
+
...thinkingLevel ? { thinkingLevel } : {},
|
|
2880
|
+
...difficulty.length ? { difficulty } : {},
|
|
2881
|
+
...maxParallel !== void 0 ? { maxParallel } : {}
|
|
2882
|
+
};
|
|
2883
|
+
});
|
|
2884
|
+
}
|
|
2801
2885
|
var DAEMON_ID_PREFIXES, MAGI_RAW_ANSWER_CAP, MESH_TASK_DIFFICULTIES, DEFAULT_DIFFICULTY_BRAINS, CANONICAL_MESH_TOOL_NAMES, CANONICAL_MESH_TOOL_COUNT;
|
|
2802
2886
|
var init_dist = __esm({
|
|
2803
2887
|
"../mesh-shared/dist/index.mjs"() {
|
|
@@ -2853,7 +2937,9 @@ var init_dist = __esm({
|
|
|
2853
2937
|
"mesh_magi_review",
|
|
2854
2938
|
"mesh_magi_collect",
|
|
2855
2939
|
"mesh_magi_kind_panel_set",
|
|
2856
|
-
"mesh_magi_kind_panel_list"
|
|
2940
|
+
"mesh_magi_kind_panel_list",
|
|
2941
|
+
"mesh_node_slots_set",
|
|
2942
|
+
"mesh_node_slots_list"
|
|
2857
2943
|
];
|
|
2858
2944
|
CANONICAL_MESH_TOOL_COUNT = CANONICAL_MESH_TOOL_NAMES.length;
|
|
2859
2945
|
}
|
|
@@ -3802,6 +3888,7 @@ function buildRulesSection(coordinatorCliType) {
|
|
|
3802
3888
|
- **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
3889
|
- **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
3890
|
- **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.
|
|
3891
|
+
- **Retune node profiles when routing is a poor fit \u2014 but only with approval.** A node's capability slots (its provider/model/thinking + difficulty range + capability tags, seen via \`mesh_node_slots_list\`) are what task\u2192node fitness routing matches against. If you notice a persistent mismatch \u2014 e.g. every \`difficult\` task lands on a node whose only slot is a cheap model, or a capability a node clearly has isn't declared \u2014 you MAY propose a slot change with \`mesh_node_slots_set\` (write=false). That returns current-vs-proposed; present that diff to the user with a one-line reason and apply (write=true) ONLY after they approve. It is a WHOLESALE replacement of the node's slots, so include the slots you want to keep. Never rewrite a node's profile silently or without a clear routing reason.
|
|
3805
3892
|
- **Respect explicit provider requests.** Map: Hermes \u2192 \`hermes-cli\`, Claude/Claude Code \u2192 \`claude-cli\`, Codex \u2192 \`codex-cli\`, Gemini \u2192 \`gemini-cli\`, Antigravity \u2192 \`antigravity-cli\`. Never substitute the coordinator's own runtime.
|
|
3806
3893
|
- **Verify via git, not source.** Use \`mesh_git_status\` to confirm side effects. Treat agent summaries as self-reports, not verification.
|
|
3807
3894
|
- **Limit parallelism.** Start with 1\u20132 tasks; scale only on success. Never duplicate a session because \`mesh_read_chat\` shows no final message while tool/terminal activity is ongoing. This caps *concurrent* load \u2014 it does not mean serialize independent work: when a new, independent request arrives and there is headroom under \`maxParallelTasks\`, dispatch it right away rather than waiting for an in-flight task or a user nudge (read-only diagnosis especially, since it has no merge cost).
|
|
@@ -3882,7 +3969,9 @@ var init_coordinator_prompt = __esm({
|
|
|
3882
3969
|
| \`mesh_magi_review\` | Cross-verify a read-only investigation across a standing panel of independent mesh agents (different machines/providers) instead of a single worker |
|
|
3883
3970
|
| \`mesh_magi_collect\` | Collect + synthesize a previously dispatched MAGI fan-out by its consensus group id (async companion to mesh_magi_review wait:false) |
|
|
3884
3971
|
| \`mesh_magi_kind_panel_set\` | Bind a task_kind \u2192 MAGI kind-panel slots (the SOLE MAGI panel-resolution surface; machine-local, wholesale replacement \u2014 approve current-vs-new first) |
|
|
3885
|
-
| \`mesh_magi_kind_panel_list\` | List configured task_kind \u2192 MAGI kind-panel slot bindings (machine-local, read-only)
|
|
3972
|
+
| \`mesh_magi_kind_panel_list\` | List configured task_kind \u2192 MAGI kind-panel slot bindings (machine-local, read-only) |
|
|
3973
|
+
| \`mesh_node_slots_list\` | List a node's capability slots (its AI-tool profile: provider/model/thinking + difficulty range + capability tags), read-only |
|
|
3974
|
+
| \`mesh_node_slots_set\` | PROPOSE (dry-run) or APPLY a node's capability slots \u2014 how you autonomously retune a node's tool profile; WHOLESALE replacement, present current-vs-proposed and get user approval before write=true |`;
|
|
3886
3975
|
TOOL_EXPOSURE_PREFLIGHT_SECTION = `## Tool Exposure Preflight
|
|
3887
3976
|
|
|
3888
3977
|
Before doing any coordinator work, confirm that the actual callable tool list includes \`mesh_status\` and the other \`mesh_*\` tools from the table above. If this Repo Mesh coordinator prompt is present but the callable \`mesh_*\` tools are missing, the MCP server/tool manifest is stale or not injected yet. Do not substitute terminal/file/git tools, do not inspect or edit the repository directly, and do not continue as a non-mesh local coding agent. Stop immediately and tell the user to run \`/reload-mcp\` or start a fresh coordinator session so ADHDev can reconnect \`adhdev-mesh\`.`;
|
|
@@ -5830,6 +5919,7 @@ function enqueueTask(meshId, message, opts) {
|
|
|
5830
5919
|
const maxRetries = typeof opts?.maxRetries === "number" && Number.isFinite(opts.maxRetries) && opts.maxRetries >= 0 ? Math.floor(opts.maxRetries) : void 0;
|
|
5831
5920
|
let effectiveModel = typeof opts?.model === "string" && opts.model.trim() ? opts.model.trim() : void 0;
|
|
5832
5921
|
let effectiveThinkingLevel = typeof opts?.thinkingLevel === "string" && opts.thinkingLevel.trim() ? opts.thinkingLevel.trim() : void 0;
|
|
5922
|
+
const taskDifficulty = isMeshTaskDifficulty(opts?.difficulty) ? opts.difficulty : void 0;
|
|
5833
5923
|
if (isMeshTaskDifficulty(opts?.difficulty)) {
|
|
5834
5924
|
try {
|
|
5835
5925
|
const preset = getDifficultyBrains()[opts.difficulty];
|
|
@@ -5873,6 +5963,7 @@ function enqueueTask(meshId, message, opts) {
|
|
|
5873
5963
|
...typeof opts?.consensusGroupId === "string" && opts.consensusGroupId.trim() ? { consensusGroupId: opts.consensusGroupId.trim() } : {},
|
|
5874
5964
|
...effectiveModel ? { model: effectiveModel } : {},
|
|
5875
5965
|
...effectiveThinkingLevel ? { thinkingLevel: effectiveThinkingLevel } : {},
|
|
5966
|
+
...taskDifficulty ? { difficulty: taskDifficulty } : {},
|
|
5876
5967
|
...typeof opts?.sourceCoordinatorSessionId === "string" && opts.sourceCoordinatorSessionId.trim() ? { sourceCoordinatorSessionId: opts.sourceCoordinatorSessionId.trim() } : {},
|
|
5877
5968
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5878
5969
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -15862,8 +15953,16 @@ function nodeHasActiveAssignment(meshId, nodeId) {
|
|
|
15862
15953
|
function nodeActiveLoad(meshId, nodeId) {
|
|
15863
15954
|
return MeshRuntimeStore.getInstance().nodeActiveAssignmentCount(meshId, nodeId);
|
|
15864
15955
|
}
|
|
15956
|
+
function meshHasExplicitSlots(mesh) {
|
|
15957
|
+
const nodes = Array.isArray(mesh?.nodes) ? mesh.nodes : [];
|
|
15958
|
+
return nodes.some((n) => normalizeNodeCapabilitySlots(n?.policy?.slots).length > 0);
|
|
15959
|
+
}
|
|
15865
15960
|
function resolveSchedulingStrategy(mesh) {
|
|
15866
|
-
|
|
15961
|
+
const raw = mesh?.policy?.schedulingStrategy;
|
|
15962
|
+
if (typeof raw === "string" && raw.trim()) {
|
|
15963
|
+
return normalizeMeshSchedulingStrategy(raw);
|
|
15964
|
+
}
|
|
15965
|
+
return meshHasExplicitSlots(mesh) ? "fitness" : normalizeMeshSchedulingStrategy(void 0);
|
|
15867
15966
|
}
|
|
15868
15967
|
function buildSchedulingPool(localCandidates, remoteCandidates) {
|
|
15869
15968
|
const pool = [...localCandidates, ...remoteCandidates].map((c) => ({
|
|
@@ -15877,10 +15976,68 @@ function buildSchedulingPool(localCandidates, remoteCandidates) {
|
|
|
15877
15976
|
}));
|
|
15878
15977
|
return { pool, uniqueNodes };
|
|
15879
15978
|
}
|
|
15979
|
+
function resolveNodeCapabilitySlots(node) {
|
|
15980
|
+
const explicit = normalizeNodeCapabilitySlots(node?.policy?.slots);
|
|
15981
|
+
if (explicit.length) return explicit;
|
|
15982
|
+
let difficultyBrains;
|
|
15983
|
+
try {
|
|
15984
|
+
difficultyBrains = getDifficultyBrains();
|
|
15985
|
+
} catch {
|
|
15986
|
+
difficultyBrains = void 0;
|
|
15987
|
+
}
|
|
15988
|
+
return deriveSlotsFromLegacy({
|
|
15989
|
+
providerPriority: normalizeProviderPriority(node?.policy),
|
|
15990
|
+
providerRoles: Array.isArray(node?.policy?.providerRoles) ? node.policy.providerRoles : void 0,
|
|
15991
|
+
difficultyBrains
|
|
15992
|
+
});
|
|
15993
|
+
}
|
|
15994
|
+
function scoreSlotForTask(slot, task) {
|
|
15995
|
+
let score = 1;
|
|
15996
|
+
const diff = isMeshTaskDifficulty(task.difficulty) ? task.difficulty : void 0;
|
|
15997
|
+
if (diff) {
|
|
15998
|
+
if (slot.difficulty?.length) {
|
|
15999
|
+
score += slot.difficulty.includes(diff) ? 100 : 0;
|
|
16000
|
+
} else {
|
|
16001
|
+
score += 20;
|
|
16002
|
+
}
|
|
16003
|
+
}
|
|
16004
|
+
const req = task.requiredTags?.filter((t) => !!t) ?? [];
|
|
16005
|
+
if (req.length) {
|
|
16006
|
+
const cap = new Set(slot.capability ?? []);
|
|
16007
|
+
const covered = req.every((t) => cap.has(t));
|
|
16008
|
+
score += covered ? 30 : 0;
|
|
16009
|
+
}
|
|
16010
|
+
return score;
|
|
16011
|
+
}
|
|
16012
|
+
function bestSlotForTask(node, task) {
|
|
16013
|
+
const slots = resolveNodeCapabilitySlots(node);
|
|
16014
|
+
if (!slots.length) return null;
|
|
16015
|
+
let best = null;
|
|
16016
|
+
for (const slot of slots) {
|
|
16017
|
+
const score = scoreSlotForTask(slot, task);
|
|
16018
|
+
if (!best || score > best.score) best = { slot, score };
|
|
16019
|
+
}
|
|
16020
|
+
return best;
|
|
16021
|
+
}
|
|
16022
|
+
function nodeFitnessForTask(node, task) {
|
|
16023
|
+
return bestSlotForTask(node, task)?.score ?? 0;
|
|
16024
|
+
}
|
|
15880
16025
|
function orderEligibleNodes(meshId, strategy, nodes, opts) {
|
|
15881
16026
|
if (strategy === "first_eligible" || nodes.length <= 1) {
|
|
15882
16027
|
return nodes;
|
|
15883
16028
|
}
|
|
16029
|
+
if (strategy === "fitness" && opts?.task) {
|
|
16030
|
+
const task = opts.task;
|
|
16031
|
+
return [...nodes].sort((a, b) => {
|
|
16032
|
+
const fitDelta = nodeFitnessForTask(b.node, task) - nodeFitnessForTask(a.node, task);
|
|
16033
|
+
if (fitDelta !== 0) return fitDelta;
|
|
16034
|
+
const prioDelta = resolveNodeSchedulingPriority(b.node?.policy) - resolveNodeSchedulingPriority(a.node?.policy);
|
|
16035
|
+
if (prioDelta !== 0) return prioDelta;
|
|
16036
|
+
const loadDelta = nodeActiveLoad(meshId, a.nodeId) - nodeActiveLoad(meshId, b.nodeId);
|
|
16037
|
+
if (loadDelta !== 0) return loadDelta;
|
|
16038
|
+
return a.index - b.index;
|
|
16039
|
+
});
|
|
16040
|
+
}
|
|
15884
16041
|
const priorityOf = (n) => resolveNodeSchedulingPriority(n.node?.policy);
|
|
15885
16042
|
let rotation = 0;
|
|
15886
16043
|
if (strategy === "least_loaded" || strategy === "round_robin") {
|
|
@@ -16024,13 +16181,15 @@ function markAutoLaunch(meshId, taskId, args) {
|
|
|
16024
16181
|
retractActionableSkipIfPreviouslyNotified(meshId, taskId);
|
|
16025
16182
|
}
|
|
16026
16183
|
}
|
|
16027
|
-
async function resolveUsableProvider(components, nodeId, node, requiredTags) {
|
|
16028
|
-
const providerPriority = normalizeProviderPriority(node?.policy);
|
|
16029
|
-
if (!providerPriority.length) return { reason: "missing_provider_priority" };
|
|
16184
|
+
async function resolveUsableProvider(components, nodeId, node, requiredTags, task) {
|
|
16030
16185
|
const providerLoader = components.providerLoader;
|
|
16031
16186
|
if (!providerLoader) return { reason: "provider_loader_unavailable" };
|
|
16187
|
+
const slots = resolveNodeCapabilitySlots(node);
|
|
16188
|
+
if (!slots.length) return { reason: "missing_provider_priority" };
|
|
16189
|
+
const orderedSlots = task ? [...slots].sort((a, b) => scoreSlotForTask(b, task) - scoreSlotForTask(a, task)) : slots;
|
|
16032
16190
|
const failed = [];
|
|
16033
|
-
for (const
|
|
16191
|
+
for (const slot of orderedSlots) {
|
|
16192
|
+
const requestedType = slot.provider;
|
|
16034
16193
|
const normalizedType = typeof providerLoader.resolveAlias === "function" ? providerLoader.resolveAlias(requestedType) : requestedType;
|
|
16035
16194
|
if (requiredTags?.length && !nodeSatisfiesRequiredTags(requiredTags, buildMeshNodeCapabilityTags(node, normalizedType))) {
|
|
16036
16195
|
failed.push(`${requestedType}: required_tags_mismatch`);
|
|
@@ -16055,7 +16214,13 @@ async function resolveUsableProvider(components, nodeId, node, requiredTags) {
|
|
|
16055
16214
|
}], false);
|
|
16056
16215
|
}
|
|
16057
16216
|
components.onStatusChange?.();
|
|
16058
|
-
if (detected)
|
|
16217
|
+
if (detected) {
|
|
16218
|
+
return {
|
|
16219
|
+
providerType: normalizedType,
|
|
16220
|
+
...slot.model ? { model: slot.model } : {},
|
|
16221
|
+
...slot.thinkingLevel ? { thinkingLevel: slot.thinkingLevel } : {}
|
|
16222
|
+
};
|
|
16223
|
+
}
|
|
16059
16224
|
failed.push(`${requestedType}: not detected`);
|
|
16060
16225
|
}
|
|
16061
16226
|
return { reason: `provider_priority_unusable: ${failed.join("; ") || nodeId}` };
|
|
@@ -16183,7 +16348,9 @@ async function maybeAutoLaunchOneQueueSession(components, meshId, mesh) {
|
|
|
16183
16348
|
meshId,
|
|
16184
16349
|
strategy,
|
|
16185
16350
|
candidateNodes.map((node, index) => ({ nodeId: readMeshNodeId(node), node, index })).filter((c) => c.nodeId),
|
|
16186
|
-
|
|
16351
|
+
// Auto-launch drains one task at a time, so the task IS in scope here —
|
|
16352
|
+
// pass it through for the 'fitness' strategy's task→slot ranking.
|
|
16353
|
+
{ bumpCursor: true, task: { difficulty: task.difficulty, requiredTags: task.requiredTags } }
|
|
16187
16354
|
).map((c) => c.node);
|
|
16188
16355
|
for (const node of orderedCandidateNodes) {
|
|
16189
16356
|
const nodeId = readMeshNodeId(node);
|
|
@@ -16230,11 +16397,13 @@ async function maybeAutoLaunchOneQueueSession(components, meshId, mesh) {
|
|
|
16230
16397
|
}
|
|
16231
16398
|
autoLaunchInProgress.add(launchKey);
|
|
16232
16399
|
try {
|
|
16233
|
-
const resolved = await resolveUsableProvider(components, nodeId, node, task.requiredTags);
|
|
16400
|
+
const resolved = await resolveUsableProvider(components, nodeId, node, task.requiredTags, { difficulty: task.difficulty, requiredTags: task.requiredTags });
|
|
16234
16401
|
if (!resolved.providerType) {
|
|
16235
16402
|
markAutoLaunch(meshId, task.id, { status: "skipped", reason: resolved.reason || "provider_unusable", nodeId });
|
|
16236
16403
|
continue;
|
|
16237
16404
|
}
|
|
16405
|
+
const effectiveModel = typeof task.model === "string" && task.model.trim() ? task.model.trim() : resolved.model;
|
|
16406
|
+
const effectiveThinkingLevel = typeof task.thinkingLevel === "string" && task.thinkingLevel.trim() ? task.thinkingLevel.trim() : resolved.thinkingLevel;
|
|
16238
16407
|
const providerCap = resolveProviderMaxParallel(node?.policy, resolved.providerType);
|
|
16239
16408
|
if (providerCap !== void 0 && activeProviderAssignedCount(meshId, nodeId, resolved.providerType) >= providerCap) {
|
|
16240
16409
|
markAutoLaunch(meshId, task.id, { status: "skipped", reason: "max_provider_parallel_reached", nodeId, providerType: resolved.providerType });
|
|
@@ -16268,9 +16437,10 @@ async function maybeAutoLaunchOneQueueSession(components, meshId, mesh) {
|
|
|
16268
16437
|
settings: remoteSettings,
|
|
16269
16438
|
// MAGI-KIND-PANEL model axis: forward the task's model override so the
|
|
16270
16439
|
// remote worker session launches with it (initialModel). Best-effort.
|
|
16271
|
-
|
|
16272
|
-
|
|
16273
|
-
|
|
16440
|
+
// Slot-aware: task override wins, else the matched slot's model.
|
|
16441
|
+
...effectiveModel ? { initialModel: effectiveModel } : {},
|
|
16442
|
+
// BRAIN-ROUTING thinking axis: forward the effective thinking level (initialThinkingLevel).
|
|
16443
|
+
...effectiveThinkingLevel ? { initialThinkingLevel: effectiveThinkingLevel } : {}
|
|
16274
16444
|
});
|
|
16275
16445
|
} catch (e) {
|
|
16276
16446
|
markAutoLaunch(meshId, task.id, { status: "failed", reason: `remote_launch_dispatch_failed: ${e?.message || String(e)}`, nodeId, providerType: resolved.providerType });
|
|
@@ -16297,11 +16467,11 @@ async function maybeAutoLaunchOneQueueSession(components, meshId, mesh) {
|
|
|
16297
16467
|
cliType: resolved.providerType,
|
|
16298
16468
|
dir: node.workspace,
|
|
16299
16469
|
settings: launchSettings,
|
|
16300
|
-
// MAGI-KIND-PANEL model axis: local launch forwards the
|
|
16301
|
-
// override as initialModel (CLI → modelLaunchArgs; ACP → setConfigOption).
|
|
16302
|
-
...
|
|
16303
|
-
// BRAIN-ROUTING thinking axis: forward the
|
|
16304
|
-
...
|
|
16470
|
+
// MAGI-KIND-PANEL model axis: local launch forwards the effective model
|
|
16471
|
+
// (task override, else matched slot) as initialModel (CLI → modelLaunchArgs; ACP → setConfigOption).
|
|
16472
|
+
...effectiveModel ? { initialModel: effectiveModel } : {},
|
|
16473
|
+
// BRAIN-ROUTING thinking axis: forward the effective thinking level (initialThinkingLevel).
|
|
16474
|
+
...effectiveThinkingLevel ? { initialThinkingLevel: effectiveThinkingLevel } : {}
|
|
16305
16475
|
});
|
|
16306
16476
|
if (!launchResult?.success) {
|
|
16307
16477
|
const reason = launchResult?.error || "launch_cli_failed";
|
|
@@ -16436,7 +16606,7 @@ async function triggerMeshQueue(components, meshId) {
|
|
|
16436
16606
|
const aPrio = resolveNodeSchedulingPriority(a.node?.policy);
|
|
16437
16607
|
const bPrio = resolveNodeSchedulingPriority(b.node?.policy);
|
|
16438
16608
|
if (aPrio !== bPrio) return bPrio - aPrio;
|
|
16439
|
-
if (strategy === "least_loaded" || strategy === "round_robin") {
|
|
16609
|
+
if (strategy === "least_loaded" || strategy === "round_robin" || strategy === "fitness") {
|
|
16440
16610
|
const loadDelta = nodeActiveLoad(meshId, a.nodeId) - nodeActiveLoad(meshId, b.nodeId);
|
|
16441
16611
|
if (loadDelta !== 0) return loadDelta;
|
|
16442
16612
|
}
|
|
@@ -18431,6 +18601,22 @@ var init_provider_input_support = __esm({
|
|
|
18431
18601
|
});
|
|
18432
18602
|
|
|
18433
18603
|
// src/status/builders.ts
|
|
18604
|
+
function isCoordinatorSpawnedHiddenWorker(settings) {
|
|
18605
|
+
if (!settings) return false;
|
|
18606
|
+
return settings.launchedByCoordinator === true && typeof settings.meshNodeFor === "string" && settings.meshNodeFor.trim().length > 0 && settings.spawnedSessionVisibility === "hidden";
|
|
18607
|
+
}
|
|
18608
|
+
function resolveSurfaceHidden(settings) {
|
|
18609
|
+
if (!settings) return false;
|
|
18610
|
+
if (settings.userHidden === true) return true;
|
|
18611
|
+
if (settings.userHidden === false) return false;
|
|
18612
|
+
return settings.spawnedSessionVisibility === "hidden" || isCoordinatorSpawnedHiddenWorker(settings);
|
|
18613
|
+
}
|
|
18614
|
+
function resolveMuted(settings) {
|
|
18615
|
+
if (!settings) return false;
|
|
18616
|
+
if (settings.userMuted === true) return true;
|
|
18617
|
+
if (settings.userMuted === false) return false;
|
|
18618
|
+
return isCoordinatorSpawnedHiddenWorker(settings);
|
|
18619
|
+
}
|
|
18434
18620
|
function getActiveChatOptions(profile) {
|
|
18435
18621
|
if (profile === "full") return {};
|
|
18436
18622
|
return LIVE_STATUS_ACTIVE_CHAT_OPTIONS;
|
|
@@ -18636,7 +18822,8 @@ function buildCliSession(state, options) {
|
|
|
18636
18822
|
settings: state.settings,
|
|
18637
18823
|
...coordinator && { coordinator },
|
|
18638
18824
|
...meshQueueStats && { meshQueueStats },
|
|
18639
|
-
...state.settings
|
|
18825
|
+
...resolveSurfaceHidden(state.settings) && { surfaceHidden: true },
|
|
18826
|
+
...resolveMuted(state.settings) && { muted: true }
|
|
18640
18827
|
};
|
|
18641
18828
|
}
|
|
18642
18829
|
function buildAcpSession(state, options) {
|
|
@@ -18677,7 +18864,8 @@ function buildAcpSession(state, options) {
|
|
|
18677
18864
|
settings: state.settings,
|
|
18678
18865
|
...coordinator && { coordinator },
|
|
18679
18866
|
...meshQueueStats && { meshQueueStats },
|
|
18680
|
-
...state.settings
|
|
18867
|
+
...resolveSurfaceHidden(state.settings) && { surfaceHidden: true },
|
|
18868
|
+
...resolveMuted(state.settings) && { muted: true }
|
|
18681
18869
|
};
|
|
18682
18870
|
}
|
|
18683
18871
|
function buildSessionEntries(allStates, cdpManagers, options = {}) {
|
|
@@ -27639,6 +27827,7 @@ __export(index_exports, {
|
|
|
27639
27827
|
appendRemoteLedgerEntries: () => appendRemoteLedgerEntries,
|
|
27640
27828
|
assertNoDependencyCycle: () => assertNoDependencyCycle,
|
|
27641
27829
|
buildAssistantChatMessage: () => buildAssistantChatMessage,
|
|
27830
|
+
buildAvailableProviders: () => buildAvailableProviders,
|
|
27642
27831
|
buildChatMessage: () => buildChatMessage,
|
|
27643
27832
|
buildChatMessageSignature: () => buildChatMessageSignature,
|
|
27644
27833
|
buildChatTailDeliverySignature: () => buildChatTailDeliverySignature,
|
|
@@ -39497,11 +39686,15 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
39497
39686
|
if (!manifestPath) continue;
|
|
39498
39687
|
try {
|
|
39499
39688
|
const m = JSON.parse(fs41.readFileSync(manifestPath, "utf-8"));
|
|
39689
|
+
const modelOptions = Array.isArray(m.modelOptions) ? m.modelOptions.filter((x) => typeof x === "string" && !!x.trim()) : [];
|
|
39690
|
+
const thinkingLevelOptions = Array.isArray(m.thinkingLevelOptions) ? m.thinkingLevelOptions.filter((x) => typeof x === "string" && !!x.trim()) : [];
|
|
39500
39691
|
items.push({
|
|
39501
39692
|
type,
|
|
39502
39693
|
category,
|
|
39503
39694
|
version: typeof m.providerVersion === "string" ? m.providerVersion : "0.0.0",
|
|
39504
|
-
path: manifestPath
|
|
39695
|
+
path: manifestPath,
|
|
39696
|
+
...modelOptions.length ? { modelOptions } : {},
|
|
39697
|
+
...thinkingLevelOptions.length ? { thinkingLevelOptions } : {}
|
|
39505
39698
|
});
|
|
39506
39699
|
} catch {
|
|
39507
39700
|
}
|
|
@@ -50285,6 +50478,31 @@ var cliAgentHandlers = {
|
|
|
50285
50478
|
record_provider_pty: async (ctx, args) => {
|
|
50286
50479
|
return ctx.deps.cliManager.handleCliCommand("record_provider_pty", args);
|
|
50287
50480
|
},
|
|
50481
|
+
// Daemon-owned per-session user Mute/Hide. Replaces the old browser-local
|
|
50482
|
+
// localStorage layer: the user's manual hide/mute for a conversation is stored
|
|
50483
|
+
// in-memory on the live session's settings (userHidden / userMuted) and rides
|
|
50484
|
+
// the SAME status snapshot pipeline as the coordinator-policy surfaceHidden
|
|
50485
|
+
// flag, so every client of this daemon sees the same state. In-memory only —
|
|
50486
|
+
// resets on daemon restart (coordinator-spawned sessions re-derive their hidden
|
|
50487
|
+
// default from mesh policy on relaunch). Passing null/undefined for a field
|
|
50488
|
+
// leaves it unchanged; pass an explicit boolean to set, or false to clear an
|
|
50489
|
+
// earlier hide/mute (e.g. unmute a coordinator-spawned worker overrides the
|
|
50490
|
+
// policy default until restart).
|
|
50491
|
+
set_conversation_prefs: async (ctx, args) => {
|
|
50492
|
+
const sessionId = readStringValue(args?.sessionId, args?.targetSessionId, args?.instanceId);
|
|
50493
|
+
if (!sessionId) return { success: false, error: "sessionId required" };
|
|
50494
|
+
const inst = ctx.deps.instanceManager.getInstance(sessionId);
|
|
50495
|
+
if (!inst || typeof inst.updateSettings !== "function") {
|
|
50496
|
+
return { success: false, error: "Session not found or does not support preferences" };
|
|
50497
|
+
}
|
|
50498
|
+
const patch = {};
|
|
50499
|
+
if (typeof args?.hidden === "boolean") patch.userHidden = args.hidden;
|
|
50500
|
+
if (typeof args?.muted === "boolean") patch.userMuted = args.muted;
|
|
50501
|
+
if (!Object.keys(patch).length) return { success: false, error: "Nothing to update (hidden and/or muted required)" };
|
|
50502
|
+
inst.updateSettings(patch);
|
|
50503
|
+
ctx.deps.onStatusChange?.();
|
|
50504
|
+
return { success: true, sessionId, ...patch };
|
|
50505
|
+
},
|
|
50288
50506
|
agent_command: async (ctx, args) => {
|
|
50289
50507
|
{
|
|
50290
50508
|
const dispatchSessionId = readStringValue(args?.targetSessionId, args?.sessionId, args?.instanceId);
|
|
@@ -56546,6 +56764,8 @@ var meshCoordinatorLaunchHandlers = {
|
|
|
56546
56764
|
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
56547
56765
|
let cliType = typeof args?.cliType === "string" ? args.cliType.trim() : "";
|
|
56548
56766
|
const extraSystemPrompt = typeof args?.extraSystemPrompt === "string" ? args.extraSystemPrompt.trim() : "";
|
|
56767
|
+
const initialModel = typeof args?.initialModel === "string" && args.initialModel.trim() ? args.initialModel.trim() : null;
|
|
56768
|
+
const initialThinkingLevel = typeof args?.initialThinkingLevel === "string" && args.initialThinkingLevel.trim() ? args.initialThinkingLevel.trim() : null;
|
|
56549
56769
|
if (!meshId) return { success: false, error: "meshId required" };
|
|
56550
56770
|
try {
|
|
56551
56771
|
const { buildCoordinatorSystemPrompt: buildCoordinatorSystemPrompt2 } = await Promise.resolve().then(() => (init_coordinator_prompt(), coordinator_prompt_exports));
|
|
@@ -56816,7 +57036,9 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
56816
57036
|
dir: workspace,
|
|
56817
57037
|
cliArgs: cliCmdArgs.length > 0 ? cliCmdArgs : void 0,
|
|
56818
57038
|
env: Object.keys(cliCmdEnv).length > 0 ? cliCmdEnv : void 0,
|
|
56819
|
-
settings: { meshCoordinatorFor: meshId }
|
|
57039
|
+
settings: { meshCoordinatorFor: meshId },
|
|
57040
|
+
...initialModel ? { initialModel } : {},
|
|
57041
|
+
...initialThinkingLevel ? { initialThinkingLevel } : {}
|
|
56820
57042
|
});
|
|
56821
57043
|
if (cliCmdLaunch?.success && cliCmdContextFilePath) {
|
|
56822
57044
|
const stripPath = cliCmdContextFilePath;
|
|
@@ -57001,7 +57223,9 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
57001
57223
|
env: Object.keys(launchEnv).length > 0 ? launchEnv : void 0,
|
|
57002
57224
|
settings: {
|
|
57003
57225
|
meshCoordinatorFor: meshId
|
|
57004
|
-
}
|
|
57226
|
+
},
|
|
57227
|
+
...initialModel ? { initialModel } : {},
|
|
57228
|
+
...initialThinkingLevel ? { initialThinkingLevel } : {}
|
|
57005
57229
|
});
|
|
57006
57230
|
if (launchResult?.success && autoImportContextFilePath) {
|
|
57007
57231
|
const stripPath = autoImportContextFilePath;
|
|
@@ -57360,6 +57584,11 @@ var meshStatusHandlers = {
|
|
|
57360
57584
|
...node.reportedProviderVersions && typeof node.reportedProviderVersions === "object" ? { providerVersions: node.reportedProviderVersions } : {},
|
|
57361
57585
|
...typeof node.reportedDaemonBuildVersion === "string" && node.reportedDaemonBuildVersion ? { daemonBuildVersion: node.reportedDaemonBuildVersion } : {},
|
|
57362
57586
|
providerPriority,
|
|
57587
|
+
// ORCHESTRATION_NODE_SLOTS.md: surface the node's capability
|
|
57588
|
+
// slots so the dashboard slot editor can read them. Only
|
|
57589
|
+
// emitted when explicitly configured (derived-from-legacy
|
|
57590
|
+
// slots stay implicit — the editor shows the legacy fields).
|
|
57591
|
+
...Array.isArray(node.policy?.slots) && node.policy.slots.length ? { slots: normalizeNodeCapabilitySlots(node.policy.slots) } : {},
|
|
57363
57592
|
activeSessions: [],
|
|
57364
57593
|
activeSessionDetails: [],
|
|
57365
57594
|
launchReady: false
|
|
@@ -58001,6 +58230,7 @@ function orderMeshRefineBatchNodes(changeAreas) {
|
|
|
58001
58230
|
|
|
58002
58231
|
// src/commands/router-refine.ts
|
|
58003
58232
|
init_repo_mesh_types();
|
|
58233
|
+
init_git_status();
|
|
58004
58234
|
init_mesh_node_identity();
|
|
58005
58235
|
|
|
58006
58236
|
// src/mesh/mesh-refine-gates.ts
|
|
@@ -58941,6 +59171,41 @@ async function runMeshRefineValidationGate(mesh, workspace, opts) {
|
|
|
58941
59171
|
if (fs31.existsSync((0, import_path14.join)(cwd, "node_modules"))) return false;
|
|
58942
59172
|
return ["package-lock.json", "npm-shrinkwrap.json", "pnpm-lock.yaml", "yarn.lock", "bun.lockb", "bun.lock"].some((lock) => fs31.existsSync((0, import_path14.join)(cwd, lock)));
|
|
58943
59173
|
};
|
|
59174
|
+
const needsNodeModules = (candidate, cwd) => isPackageManagerValidation(candidate) && dependenciesLikelyMissing(cwd);
|
|
59175
|
+
const isDaemonScopedCommand = (candidate) => {
|
|
59176
|
+
const haystack = [candidate.command, ...candidate.args || [], candidate.displayCommand || ""].join(" ").toLowerCase();
|
|
59177
|
+
if (candidate.category === "typecheck") return false;
|
|
59178
|
+
if (/\btypecheck\b/.test(haystack)) return false;
|
|
59179
|
+
if (/\bweb-core\b|\bweb-cloud\b|\bweb-standalone\b|\btest:web\b/.test(haystack)) return false;
|
|
59180
|
+
return /\bdaemon-core\b|\bdaemon-cloud\b|\btest:daemon\b|check-vendor-drift/.test(haystack);
|
|
59181
|
+
};
|
|
59182
|
+
const scopeUnaffectedDaemon = opts?.changeImpact?.isDaemonAffecting === false;
|
|
59183
|
+
const skippedDaemonCommands = [];
|
|
59184
|
+
const commandsToRun = [];
|
|
59185
|
+
for (const candidate of selection.commands) {
|
|
59186
|
+
if (scopeUnaffectedDaemon && isDaemonScopedCommand(candidate)) {
|
|
59187
|
+
skippedDaemonCommands.push(candidate.displayCommand);
|
|
59188
|
+
summary.commandsRun.push({
|
|
59189
|
+
command: candidate.command,
|
|
59190
|
+
args: candidate.args,
|
|
59191
|
+
displayCommand: candidate.displayCommand,
|
|
59192
|
+
category: candidate.category,
|
|
59193
|
+
source: candidate.source,
|
|
59194
|
+
passed: true,
|
|
59195
|
+
skipped: true,
|
|
59196
|
+
skipReason: "unaffected_daemon_scope"
|
|
59197
|
+
});
|
|
59198
|
+
continue;
|
|
59199
|
+
}
|
|
59200
|
+
commandsToRun.push(candidate);
|
|
59201
|
+
}
|
|
59202
|
+
if (opts?.changeImpact) {
|
|
59203
|
+
summary.changeImpact = {
|
|
59204
|
+
isDaemonAffecting: opts.changeImpact.isDaemonAffecting,
|
|
59205
|
+
affectedPackages: opts.changeImpact.affectedPackages,
|
|
59206
|
+
...skippedDaemonCommands.length ? { skippedDaemonCommands } : {}
|
|
59207
|
+
};
|
|
59208
|
+
}
|
|
58944
59209
|
if (runLegacyBootstrapCommands) {
|
|
58945
59210
|
summary.bootstrap = { stage: "legacy" };
|
|
58946
59211
|
for (const candidate of selection.bootstrapCommands) {
|
|
@@ -58975,23 +59240,22 @@ async function runMeshRefineValidationGate(mesh, workspace, opts) {
|
|
|
58975
59240
|
}
|
|
58976
59241
|
}
|
|
58977
59242
|
}
|
|
58978
|
-
|
|
59243
|
+
let missingDepsBlocked = false;
|
|
59244
|
+
for (const candidate of commandsToRun) {
|
|
58979
59245
|
const startedAt = Date.now();
|
|
58980
59246
|
const cwd = candidate.cwd ? (0, import_path14.resolve)(workspace, candidate.cwd) : workspace;
|
|
58981
59247
|
const timeout = candidate.timeoutMs || REFINE_VALIDATION_TIMEOUT_MS;
|
|
58982
59248
|
const bootstrapProvidedDependencies = summary.bootstrap?.stage === "cached" || summary.bootstrap?.stage === "ran" || summary.bootstrap?.stage === "legacy";
|
|
58983
|
-
if (!bootstrapProvidedDependencies &&
|
|
59249
|
+
if (!bootstrapProvidedDependencies && needsNodeModules(candidate, cwd)) {
|
|
58984
59250
|
summary.commandsRun.push(commandRecord(candidate, cwd, startedAt, {
|
|
58985
|
-
stderr: "Dependencies appear to be missing: package.json and a lockfile are present, but node_modules is absent. Configure validation.bootstrapCommands in repo mesh/refine config if Refinery should install/bootstrap before validation."
|
|
59251
|
+
stderr: "Dependencies appear to be missing: package.json and a lockfile are present, but node_modules is absent. Configure validation.bootstrapCommands (or .adhdev/worktree_bootstrap.json) in repo mesh/refine config if Refinery should install/bootstrap before validation."
|
|
58986
59252
|
}, false, {
|
|
58987
59253
|
exitCode: null,
|
|
58988
59254
|
skipped: true,
|
|
58989
59255
|
failureKind: "missing_dependencies"
|
|
58990
59256
|
}));
|
|
58991
|
-
|
|
58992
|
-
|
|
58993
|
-
summary.failureCode = "missing_dependencies";
|
|
58994
|
-
return summary;
|
|
59257
|
+
missingDepsBlocked = true;
|
|
59258
|
+
continue;
|
|
58995
59259
|
}
|
|
58996
59260
|
const resolvedCommand = resolveWin32Executable(candidate.command);
|
|
58997
59261
|
const spawn5 = buildWin32ExecFileSpawn(resolvedCommand, candidate.args);
|
|
@@ -59027,6 +59291,12 @@ async function runMeshRefineValidationGate(mesh, workspace, opts) {
|
|
|
59027
59291
|
return summary;
|
|
59028
59292
|
}
|
|
59029
59293
|
}
|
|
59294
|
+
if (missingDepsBlocked) {
|
|
59295
|
+
summary.status = "failed";
|
|
59296
|
+
summary.failureKind = "missing_dependencies";
|
|
59297
|
+
summary.failureCode = "missing_dependencies";
|
|
59298
|
+
return summary;
|
|
59299
|
+
}
|
|
59030
59300
|
summary.status = "passed";
|
|
59031
59301
|
return summary;
|
|
59032
59302
|
}
|
|
@@ -59234,7 +59504,20 @@ async function refineResolveRefsStage(self, meshId, nodeId, args, refineStages)
|
|
|
59234
59504
|
const { stdout: branchHeadStdout } = await execFileAsync4("git", ["rev-parse", branch], { cwd: node.workspace, encoding: "utf8" });
|
|
59235
59505
|
const baseHead = baseHeadRaw;
|
|
59236
59506
|
const branchHead = branchHeadStdout.trim();
|
|
59237
|
-
|
|
59507
|
+
let changeImpact;
|
|
59508
|
+
try {
|
|
59509
|
+
changeImpact = await classifyChangedPackages(node.workspace, baseHead, branchHead);
|
|
59510
|
+
} catch {
|
|
59511
|
+
changeImpact = void 0;
|
|
59512
|
+
}
|
|
59513
|
+
recordMeshRefineStage(refineStages, "resolve_refs", "passed", resolveStarted, {
|
|
59514
|
+
branch,
|
|
59515
|
+
baseBranch,
|
|
59516
|
+
baseHead,
|
|
59517
|
+
branchHead,
|
|
59518
|
+
...changeImpact ? { changeImpact } : {},
|
|
59519
|
+
...fetchWarning ? { fetchWarning } : {}
|
|
59520
|
+
});
|
|
59238
59521
|
return {
|
|
59239
59522
|
kind: "continue",
|
|
59240
59523
|
ctx: {
|
|
@@ -59251,6 +59534,7 @@ async function refineResolveRefsStage(self, meshId, nodeId, args, refineStages)
|
|
|
59251
59534
|
baseBranch,
|
|
59252
59535
|
baseHead,
|
|
59253
59536
|
branchHead,
|
|
59537
|
+
changeImpact,
|
|
59254
59538
|
validationSummary: void 0,
|
|
59255
59539
|
patchEquivalence: void 0,
|
|
59256
59540
|
submoduleReachability: void 0
|
|
@@ -59261,6 +59545,9 @@ async function refineValidationStage(self, ctx) {
|
|
|
59261
59545
|
const { mesh, node, branch, baseBranch, refineStages } = ctx;
|
|
59262
59546
|
const validationStarted = Date.now();
|
|
59263
59547
|
const validationSummary = await runMeshRefineValidationGate(mesh, node.workspace, {
|
|
59548
|
+
// (a) Scope the validation command set by coarse change-impact (resolved
|
|
59549
|
+
// in resolve_refs). Undefined → gate runs the full command set (fail-open).
|
|
59550
|
+
changeImpact: ctx.changeImpact,
|
|
59264
59551
|
// M2-2: consume the node's persisted bootstrap state; persist re-runs.
|
|
59265
59552
|
persistedBootstrapState: node.worktreeBootstrap,
|
|
59266
59553
|
onBootstrapStateChange: (state) => {
|
|
@@ -59280,7 +59567,7 @@ async function refineValidationStage(self, ctx) {
|
|
|
59280
59567
|
if (validationSummary.status === "failed") {
|
|
59281
59568
|
const firstFailedCmd = Array.isArray(validationSummary.commandsRun) ? validationSummary.commandsRun.find((c) => c.success === false) : void 0;
|
|
59282
59569
|
const buildValidationFailedError = () => {
|
|
59283
|
-
const base = validationSummary.failureCode === "missing_dependencies" ? "Refinery validation dependencies are missing; merge/refine was not attempted.
|
|
59570
|
+
const base = validationSummary.failureCode === "missing_dependencies" ? "Refinery validation dependencies are missing for a change-affected package; merge/refine was not attempted. To make this self-service, either (1) configure .adhdev/worktree_bootstrap.json (or validation.bootstrapCommands in .adhdev/refine.json) so Refinery installs deps before validation, or (2) converge the branch via the documented manual fast-forward-only bypass (rebase onto the fetched base, verify strict ancestry, then push ff-only) instead of the refine gate." : validationSummary.failureCode === "dependency_bootstrap_failed" ? "Refinery dependency/bootstrap command failed; merge/refine was not attempted." : validationSummary.failureCode === "spawn_resolution_failed" ? validationSummary.spawnResolutionError || "Refinery validation command could not be spawned (executable not found); merge/refine was not attempted." : "Refinery validation gate failed; merge/refine was not attempted.";
|
|
59284
59571
|
if (!firstFailedCmd) return base;
|
|
59285
59572
|
const cmdName = typeof firstFailedCmd.displayCommand === "string" ? firstFailedCmd.displayCommand : typeof firstFailedCmd.command === "string" ? [firstFailedCmd.command, ...Array.isArray(firstFailedCmd.args) ? firstFailedCmd.args : []].join(" ").trim() : typeof firstFailedCmd.cmd === "string" ? firstFailedCmd.cmd : "";
|
|
59286
59573
|
const rawOutput = [firstFailedCmd.stdout, firstFailedCmd.stderr, firstFailedCmd.output].filter((s2) => typeof s2 === "string" && s2.length > 0).join("\n");
|
|
@@ -70224,6 +70511,7 @@ var V1_CONTRACT_VERSION = "1.0.0";
|
|
|
70224
70511
|
appendRemoteLedgerEntries,
|
|
70225
70512
|
assertNoDependencyCycle,
|
|
70226
70513
|
buildAssistantChatMessage,
|
|
70514
|
+
buildAvailableProviders,
|
|
70227
70515
|
buildChatMessage,
|
|
70228
70516
|
buildChatMessageSignature,
|
|
70229
70517
|
buildChatTailDeliverySignature,
|