@adhdev/daemon-core 0.9.82-rc.315 → 0.9.82-rc.317
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/cli-adapter-types.d.ts +23 -0
- package/dist/cli-adapters/provider-cli-adapter.d.ts +9 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +309 -48
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +308 -52
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/mesh-runtime-store.d.ts +6 -0
- package/dist/mesh/mesh-work-queue.d.ts +22 -0
- package/dist/repo-mesh-types.d.ts +68 -0
- package/package.json +2 -2
- package/src/cli-adapter-types.ts +25 -0
- package/src/cli-adapters/provider-cli-adapter.ts +36 -1
- package/src/cli-adapters/provider-cli-shared.ts +19 -2
- package/src/commands/router.ts +42 -1
- package/src/config/mesh-config.ts +72 -1
- package/src/git/git-status.ts +122 -41
- package/src/index.ts +7 -1
- package/src/mesh/mesh-events-coordinator.ts +5 -1
- package/src/mesh/mesh-reconcile-loop.ts +31 -1
- package/src/mesh/mesh-runtime-store.ts +13 -0
- package/src/mesh/mesh-work-queue.ts +89 -11
- package/src/repo-mesh-types.ts +112 -0
package/dist/index.mjs
CHANGED
|
@@ -35,6 +35,35 @@ function resolveNodeSchedulingPriority(nodePolicy) {
|
|
|
35
35
|
const raw = Number(nodePolicy?.schedulingPriority);
|
|
36
36
|
return Number.isFinite(raw) ? raw : 0;
|
|
37
37
|
}
|
|
38
|
+
function resolveTaskAffinityRole(taskMode, policy) {
|
|
39
|
+
if (!taskMode) return null;
|
|
40
|
+
if (policy?.enabled === false) return null;
|
|
41
|
+
const override = policy?.byTaskMode && Object.prototype.hasOwnProperty.call(policy.byTaskMode, taskMode) ? policy.byTaskMode[taskMode] : void 0;
|
|
42
|
+
if (typeof override === "string") {
|
|
43
|
+
const trimmed = override.trim().toLowerCase();
|
|
44
|
+
return trimmed ? trimmed : null;
|
|
45
|
+
}
|
|
46
|
+
const fallback = DEFAULT_TASKMODE_ROLE_MAP[taskMode];
|
|
47
|
+
return fallback ?? null;
|
|
48
|
+
}
|
|
49
|
+
function resolveMeshRoleOptions(policy) {
|
|
50
|
+
const out = [...STANDARD_MESH_ROLES];
|
|
51
|
+
const seen = new Set(out);
|
|
52
|
+
const add = (raw) => {
|
|
53
|
+
if (typeof raw !== "string") return;
|
|
54
|
+
const role = raw.trim().toLowerCase();
|
|
55
|
+
if (!role || seen.has(role)) return;
|
|
56
|
+
seen.add(role);
|
|
57
|
+
out.push(role);
|
|
58
|
+
};
|
|
59
|
+
if (policy?.byTaskMode) {
|
|
60
|
+
for (const value of Object.values(policy.byTaskMode)) add(value);
|
|
61
|
+
}
|
|
62
|
+
if (Array.isArray(policy?.customRoles)) {
|
|
63
|
+
for (const value of policy.customRoles) add(value);
|
|
64
|
+
}
|
|
65
|
+
return out;
|
|
66
|
+
}
|
|
38
67
|
function resolveAutoConvergeCodeChange(policy) {
|
|
39
68
|
return policy?.autoConvergeCodeChange === true;
|
|
40
69
|
}
|
|
@@ -65,7 +94,7 @@ function resolveProviderMaxParallel(nodePolicy, providerType) {
|
|
|
65
94
|
if (!Number.isFinite(raw) || raw < 0) return void 0;
|
|
66
95
|
return Math.floor(raw);
|
|
67
96
|
}
|
|
68
|
-
var MESH_SCHEDULING_STRATEGIES, DEFAULT_MESH_SCHEDULING_STRATEGY, MESH_CONVERGE_REFINE_TAG, MESH_CONVERGE_FAST_FORWARD_TAG, DEFAULT_MESH_POLICY;
|
|
97
|
+
var MESH_SCHEDULING_STRATEGIES, DEFAULT_MESH_SCHEDULING_STRATEGY, MESH_CONVERGE_REFINE_TAG, MESH_CONVERGE_FAST_FORWARD_TAG, STANDARD_MESH_ROLES, DEFAULT_TASKMODE_ROLE_MAP, DEFAULT_MESH_POLICY;
|
|
69
98
|
var init_repo_mesh_types = __esm({
|
|
70
99
|
"src/repo-mesh-types.ts"() {
|
|
71
100
|
"use strict";
|
|
@@ -78,6 +107,14 @@ var init_repo_mesh_types = __esm({
|
|
|
78
107
|
DEFAULT_MESH_SCHEDULING_STRATEGY = "first_eligible";
|
|
79
108
|
MESH_CONVERGE_REFINE_TAG = "converge=refine";
|
|
80
109
|
MESH_CONVERGE_FAST_FORWARD_TAG = "converge=fast_forward";
|
|
110
|
+
STANDARD_MESH_ROLES = ["investigator", "coder", "validator", "converger"];
|
|
111
|
+
DEFAULT_TASKMODE_ROLE_MAP = {
|
|
112
|
+
live_debug_readonly: "investigator",
|
|
113
|
+
code_change: "coder",
|
|
114
|
+
launch_app: "coder",
|
|
115
|
+
validation: "validator",
|
|
116
|
+
convergence: "converger"
|
|
117
|
+
};
|
|
81
118
|
DEFAULT_MESH_POLICY = {
|
|
82
119
|
requirePreTaskCheckpoint: false,
|
|
83
120
|
requirePostTaskCheckpoint: true,
|
|
@@ -311,10 +348,10 @@ function readInjected(value) {
|
|
|
311
348
|
}
|
|
312
349
|
function getDaemonBuildInfo() {
|
|
313
350
|
if (cached) return cached;
|
|
314
|
-
const commit = readInjected(true ? "
|
|
315
|
-
const commitShort = readInjected(true ? "
|
|
316
|
-
const version = readInjected(true ? "0.9.82-rc.
|
|
317
|
-
const builtAt = readInjected(true ? "2026-06-
|
|
351
|
+
const commit = readInjected(true ? "b4484284652748bf8096f40a00eb5cb463963576" : void 0) ?? "unknown";
|
|
352
|
+
const commitShort = readInjected(true ? "b4484284" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
353
|
+
const version = readInjected(true ? "0.9.82-rc.317" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
354
|
+
const builtAt = readInjected(true ? "2026-06-18T08:55:18.955Z" : void 0);
|
|
318
355
|
cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
|
|
319
356
|
return cached;
|
|
320
357
|
}
|
|
@@ -640,14 +677,79 @@ function emptyStatus(workspace, lastCheckedAt, error) {
|
|
|
640
677
|
async function getSubmoduleStatuses(repo, options) {
|
|
641
678
|
if (!repo.repoRoot) return [];
|
|
642
679
|
try {
|
|
643
|
-
const
|
|
644
|
-
const submodules = parseSubmoduleStatusOutput(result.stdout, repo.repoRoot, options.submoduleIgnorePaths);
|
|
680
|
+
const submodules = await deriveSubmoduleGitlinkStatuses(repo, options);
|
|
645
681
|
await Promise.all(submodules.map((submodule) => enrichSubmoduleWorktreeStatus(repo, submodule, options)));
|
|
646
682
|
return submodules;
|
|
647
683
|
} catch {
|
|
648
684
|
return [];
|
|
649
685
|
}
|
|
650
686
|
}
|
|
687
|
+
async function deriveSubmoduleGitlinkStatuses(repo, options) {
|
|
688
|
+
if (!repo.repoRoot) return [];
|
|
689
|
+
const paths = await readSubmodulePaths(repo, options);
|
|
690
|
+
const ignoreSet = new Set(options.submoduleIgnorePaths || []);
|
|
691
|
+
const lastCheckedAt = Date.now();
|
|
692
|
+
const entries = await Promise.all(
|
|
693
|
+
paths.filter((path41) => !ignoreSet.has(path41)).map(async (path41) => {
|
|
694
|
+
const repoPath = repo.repoRoot + "/" + path41;
|
|
695
|
+
const expected = await readGitlinkExpectedSha(repo, path41, options);
|
|
696
|
+
const actual = await readSubmoduleHeadSha(repo, repoPath, options);
|
|
697
|
+
const outOfSync = actual === null ? true : expected !== null && expected !== actual;
|
|
698
|
+
return {
|
|
699
|
+
path: path41,
|
|
700
|
+
// Prefer the recorded gitlink SHA (matches the legacy column); fall back
|
|
701
|
+
// to the checked-out SHA so the field is never empty when both are known.
|
|
702
|
+
commit: expected ?? actual ?? "",
|
|
703
|
+
repoPath,
|
|
704
|
+
dirty: false,
|
|
705
|
+
outOfSync,
|
|
706
|
+
lastCheckedAt
|
|
707
|
+
};
|
|
708
|
+
})
|
|
709
|
+
);
|
|
710
|
+
return entries;
|
|
711
|
+
}
|
|
712
|
+
async function readSubmodulePaths(repo, options) {
|
|
713
|
+
if (!repo.repoRoot) return [];
|
|
714
|
+
const gitmodulesPath = repo.repoRoot + "/.gitmodules";
|
|
715
|
+
try {
|
|
716
|
+
const result = await runGit(
|
|
717
|
+
repo,
|
|
718
|
+
["config", "--file", gitmodulesPath, "--get-regexp", "^submodule\\..*\\.path$"],
|
|
719
|
+
options
|
|
720
|
+
);
|
|
721
|
+
const paths = [];
|
|
722
|
+
for (const line of result.stdout.split("\n")) {
|
|
723
|
+
const spaceIdx = line.indexOf(" ");
|
|
724
|
+
if (spaceIdx < 0) continue;
|
|
725
|
+
const value = line.slice(spaceIdx + 1).trim();
|
|
726
|
+
if (value) paths.push(value);
|
|
727
|
+
}
|
|
728
|
+
return paths;
|
|
729
|
+
} catch {
|
|
730
|
+
return [];
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
async function readGitlinkExpectedSha(repo, submodulePath, options) {
|
|
734
|
+
try {
|
|
735
|
+
const result = await runGit(repo, ["ls-tree", "HEAD", submodulePath], options);
|
|
736
|
+
const line = result.stdout.split("\n").find((l) => l.trim().length > 0);
|
|
737
|
+
if (!line) return null;
|
|
738
|
+
const match = line.match(/^\s*\d+\s+commit\s+([0-9a-f]{40})\b/);
|
|
739
|
+
return match ? match[1] : null;
|
|
740
|
+
} catch {
|
|
741
|
+
return null;
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
async function readSubmoduleHeadSha(repo, repoPath, options) {
|
|
745
|
+
try {
|
|
746
|
+
const result = await runGit(repo, ["rev-parse", "HEAD"], { ...options, cwd: repoPath });
|
|
747
|
+
const sha = result.stdout.trim();
|
|
748
|
+
return /^[0-9a-f]{40}$/.test(sha) ? sha : null;
|
|
749
|
+
} catch {
|
|
750
|
+
return null;
|
|
751
|
+
}
|
|
752
|
+
}
|
|
651
753
|
async function enrichSubmoduleWorktreeStatus(repo, submodule, options) {
|
|
652
754
|
try {
|
|
653
755
|
const result = await runGit(repo, ["status", "--porcelain=v2", "--branch"], {
|
|
@@ -662,28 +764,6 @@ async function enrichSubmoduleWorktreeStatus(repo, submodule, options) {
|
|
|
662
764
|
submodule.error = formatGitError(error);
|
|
663
765
|
}
|
|
664
766
|
}
|
|
665
|
-
function parseSubmoduleStatusOutput(output, repoRoot, ignorePaths) {
|
|
666
|
-
const submodules = [];
|
|
667
|
-
const ignoreSet = new Set(ignorePaths || []);
|
|
668
|
-
for (const line of output.split("\n")) {
|
|
669
|
-
if (!line.trim()) continue;
|
|
670
|
-
const match = line.match(/^([\-+U\s])([0-9a-f]{40})\s+(\S+)(?:\s+\(([^)]+)\))?/);
|
|
671
|
-
if (!match) continue;
|
|
672
|
-
const prefix = match[1];
|
|
673
|
-
const commit = match[2];
|
|
674
|
-
const path41 = match[3];
|
|
675
|
-
if (ignoreSet.has(path41)) continue;
|
|
676
|
-
submodules.push({
|
|
677
|
-
path: path41,
|
|
678
|
-
commit,
|
|
679
|
-
repoPath: repoRoot + "/" + path41,
|
|
680
|
-
dirty: prefix === "U",
|
|
681
|
-
outOfSync: prefix === "-" || prefix === "+",
|
|
682
|
-
lastCheckedAt: Date.now()
|
|
683
|
-
});
|
|
684
|
-
}
|
|
685
|
-
return submodules;
|
|
686
|
-
}
|
|
687
767
|
var lastKnownGoodStatus, DAEMON_RUNTIME_PACKAGES, WEB_ONLY_PACKAGES;
|
|
688
768
|
var init_git_status = __esm({
|
|
689
769
|
"src/git/git-status.ts"() {
|
|
@@ -1575,8 +1655,61 @@ function mergeMeshPolicy(base, patch) {
|
|
|
1575
1655
|
} else {
|
|
1576
1656
|
delete policy.autoConvergeCodeChange;
|
|
1577
1657
|
}
|
|
1658
|
+
const normalizedAffinity = normalizeTaskAffinityPolicy(policy.taskAffinity);
|
|
1659
|
+
if (normalizedAffinity) {
|
|
1660
|
+
policy.taskAffinity = normalizedAffinity;
|
|
1661
|
+
} else {
|
|
1662
|
+
delete policy.taskAffinity;
|
|
1663
|
+
}
|
|
1578
1664
|
return policy;
|
|
1579
1665
|
}
|
|
1666
|
+
function normalizeTaskAffinityPolicy(value) {
|
|
1667
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
1668
|
+
const record = value;
|
|
1669
|
+
const out = {};
|
|
1670
|
+
let hasContent = false;
|
|
1671
|
+
if (typeof record.enabled === "boolean") {
|
|
1672
|
+
out.enabled = record.enabled;
|
|
1673
|
+
if (record.enabled === false) hasContent = true;
|
|
1674
|
+
else delete out.enabled;
|
|
1675
|
+
}
|
|
1676
|
+
if (record.byTaskMode && typeof record.byTaskMode === "object" && !Array.isArray(record.byTaskMode)) {
|
|
1677
|
+
const byTaskMode = {};
|
|
1678
|
+
for (const [mode, raw] of Object.entries(record.byTaskMode)) {
|
|
1679
|
+
const modeKey = mode.trim();
|
|
1680
|
+
if (!modeKey) continue;
|
|
1681
|
+
if (typeof raw !== "string") continue;
|
|
1682
|
+
const role = raw.trim().toLowerCase();
|
|
1683
|
+
byTaskMode[modeKey] = role;
|
|
1684
|
+
if (role && !STANDARD_MESH_ROLES.includes(role)) {
|
|
1685
|
+
try {
|
|
1686
|
+
console.warn(`[mesh] task_affinity.byTaskMode.${modeKey}: custom role "${role}" is not a standard mesh role (${STANDARD_MESH_ROLES.join("/")}); routing still applies`);
|
|
1687
|
+
} catch {
|
|
1688
|
+
}
|
|
1689
|
+
}
|
|
1690
|
+
}
|
|
1691
|
+
if (Object.keys(byTaskMode).length > 0) {
|
|
1692
|
+
out.byTaskMode = byTaskMode;
|
|
1693
|
+
hasContent = true;
|
|
1694
|
+
}
|
|
1695
|
+
}
|
|
1696
|
+
if (Array.isArray(record.customRoles)) {
|
|
1697
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1698
|
+
const customRoles = [];
|
|
1699
|
+
for (const raw of record.customRoles) {
|
|
1700
|
+
if (typeof raw !== "string") continue;
|
|
1701
|
+
const role = raw.trim().toLowerCase();
|
|
1702
|
+
if (!role || seen.has(role)) continue;
|
|
1703
|
+
seen.add(role);
|
|
1704
|
+
customRoles.push(role);
|
|
1705
|
+
}
|
|
1706
|
+
if (customRoles.length > 0) {
|
|
1707
|
+
out.customRoles = customRoles;
|
|
1708
|
+
hasContent = true;
|
|
1709
|
+
}
|
|
1710
|
+
}
|
|
1711
|
+
return hasContent ? out : void 0;
|
|
1712
|
+
}
|
|
1580
1713
|
function normalizeAutoFastForwardPolicy(value) {
|
|
1581
1714
|
const record = value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
1582
1715
|
const maxBehind = Number(record.maxBehind);
|
|
@@ -2867,6 +3000,7 @@ __export(mesh_work_queue_exports, {
|
|
|
2867
3000
|
recordTaskAutoLaunch: () => recordTaskAutoLaunch,
|
|
2868
3001
|
requeueTask: () => requeueTask,
|
|
2869
3002
|
resolveConvergeRequiredTags: () => resolveConvergeRequiredTags,
|
|
3003
|
+
resolveTaskAffinityRequiredTags: () => resolveTaskAffinityRequiredTags,
|
|
2870
3004
|
updateDirectDispatchStatus: () => updateDirectDispatchStatus,
|
|
2871
3005
|
updateSessionTaskStatus: () => updateSessionTaskStatus,
|
|
2872
3006
|
updateTaskStatus: () => updateTaskStatus,
|
|
@@ -3006,6 +3140,31 @@ function resolveConvergeRequiredTags(meshId, taskMode, explicitRequiredTags, opt
|
|
|
3006
3140
|
if (!optedIn) return explicitRequiredTags;
|
|
3007
3141
|
return normalizeMeshCapabilityTags([...explicitRequiredTags, MESH_CONVERGE_REFINE_TAG]);
|
|
3008
3142
|
}
|
|
3143
|
+
function meshHasNodeAdvertisingRole(nodes, role) {
|
|
3144
|
+
if (!Array.isArray(nodes) || nodes.length === 0) return false;
|
|
3145
|
+
const wanted = `role=${role}`;
|
|
3146
|
+
return nodes.some((node) => buildMeshNodeCapabilityTags(node).includes(wanted));
|
|
3147
|
+
}
|
|
3148
|
+
function resolveTaskAffinityRequiredTags(meshId, taskMode, explicitRequiredTags, opts) {
|
|
3149
|
+
if (typeof opts?.targetNodeId === "string" && opts.targetNodeId.trim()) return explicitRequiredTags;
|
|
3150
|
+
if (opts?.callerSpecifiedRequiredTags === true) return explicitRequiredTags;
|
|
3151
|
+
let mesh;
|
|
3152
|
+
try {
|
|
3153
|
+
mesh = getMesh(meshId);
|
|
3154
|
+
} catch {
|
|
3155
|
+
return explicitRequiredTags;
|
|
3156
|
+
}
|
|
3157
|
+
const role = resolveTaskAffinityRole(taskMode, mesh?.policy?.taskAffinity);
|
|
3158
|
+
if (!role) return explicitRequiredTags;
|
|
3159
|
+
if (!meshHasNodeAdvertisingRole(mesh?.nodes, role)) {
|
|
3160
|
+
try {
|
|
3161
|
+
console.warn(`[mesh] task_affinity: no node advertises role=${role} for taskMode=${taskMode} in mesh ${meshId}; skipping injection (least_loaded fallback)`);
|
|
3162
|
+
} catch {
|
|
3163
|
+
}
|
|
3164
|
+
return explicitRequiredTags;
|
|
3165
|
+
}
|
|
3166
|
+
return normalizeMeshCapabilityTags([...explicitRequiredTags, `role=${role}`]);
|
|
3167
|
+
}
|
|
3009
3168
|
function withQueueLock(_meshId, fn) {
|
|
3010
3169
|
return MeshRuntimeStore.getInstance().transaction(fn);
|
|
3011
3170
|
}
|
|
@@ -3056,6 +3215,20 @@ function enqueueTask(meshId, message, opts) {
|
|
|
3056
3215
|
throw new Error(`duplicate_task_id: task '${id}' already exists in mesh '${meshId}'`);
|
|
3057
3216
|
}
|
|
3058
3217
|
assertNoDependencyCycle(meshId, id, dependsOn);
|
|
3218
|
+
const callerTags = normalizeMeshCapabilityTags(opts?.requiredTags);
|
|
3219
|
+
const callerSpecifiedRequiredTags = callerTags.length > 0;
|
|
3220
|
+
let resolvedRequiredTags = resolveConvergeRequiredTags(
|
|
3221
|
+
meshId,
|
|
3222
|
+
modeValidation.taskMode,
|
|
3223
|
+
callerTags,
|
|
3224
|
+
{ targetNodeId: opts?.targetNodeId }
|
|
3225
|
+
);
|
|
3226
|
+
resolvedRequiredTags = resolveTaskAffinityRequiredTags(
|
|
3227
|
+
meshId,
|
|
3228
|
+
modeValidation.taskMode,
|
|
3229
|
+
resolvedRequiredTags,
|
|
3230
|
+
{ targetNodeId: opts?.targetNodeId, callerSpecifiedRequiredTags }
|
|
3231
|
+
);
|
|
3059
3232
|
const entry = {
|
|
3060
3233
|
id,
|
|
3061
3234
|
meshId,
|
|
@@ -3064,15 +3237,7 @@ function enqueueTask(meshId, message, opts) {
|
|
|
3064
3237
|
taskMode: modeValidation.taskMode,
|
|
3065
3238
|
targetNodeId: opts?.targetNodeId,
|
|
3066
3239
|
targetSessionId: opts?.targetSessionId,
|
|
3067
|
-
|
|
3068
|
-
// tasks so they hard-filter onto refine-capable worktree nodes. No-op unless
|
|
3069
|
-
// the mesh opts in; explicit target_node_id / required_tags are preserved.
|
|
3070
|
-
requiredTags: resolveConvergeRequiredTags(
|
|
3071
|
-
meshId,
|
|
3072
|
-
modeValidation.taskMode,
|
|
3073
|
-
normalizeMeshCapabilityTags(opts?.requiredTags),
|
|
3074
|
-
{ targetNodeId: opts?.targetNodeId }
|
|
3075
|
-
),
|
|
3240
|
+
requiredTags: resolvedRequiredTags,
|
|
3076
3241
|
...dependsOn.length > 0 ? { dependsOn } : {},
|
|
3077
3242
|
...typeof opts?.missionId === "string" && opts.missionId.trim() ? { missionId: opts.missionId.trim() } : {},
|
|
3078
3243
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -3827,6 +3992,18 @@ var init_mesh_runtime_store = __esm({
|
|
|
3827
3992
|
`).get(meshId, nodeId);
|
|
3828
3993
|
return row?.count ?? 0;
|
|
3829
3994
|
}
|
|
3995
|
+
/**
|
|
3996
|
+
* O(1) count of queue tasks in 'pending' status for a mesh. A COUNT(*) over the
|
|
3997
|
+
* indexed status column, so it avoids JSON.parse-ing every queue row — used as a
|
|
3998
|
+
* cheap guard before the reconcile loop runs a full triggerMeshQueue scan.
|
|
3999
|
+
*/
|
|
4000
|
+
pendingQueueTaskCount(meshId) {
|
|
4001
|
+
const row = this.db.prepare(`
|
|
4002
|
+
SELECT COUNT(*) as count FROM mesh_queue
|
|
4003
|
+
WHERE mesh_id = ? AND status = 'pending'
|
|
4004
|
+
`).get(meshId);
|
|
4005
|
+
return row?.count ?? 0;
|
|
4006
|
+
}
|
|
3830
4007
|
/**
|
|
3831
4008
|
* Read the current per-mesh round-robin cursor (0 when unset). Used to rotate
|
|
3832
4009
|
* the tie-break winner among nodes tied at the least load.
|
|
@@ -8760,7 +8937,7 @@ async function triggerMeshQueue(components, meshId) {
|
|
|
8760
8937
|
}
|
|
8761
8938
|
const remoteCandidates = [];
|
|
8762
8939
|
for (const idle of remoteSessions) {
|
|
8763
|
-
const node = mesh.nodes.find((n) => n
|
|
8940
|
+
const node = mesh.nodes.find((n) => meshNodeIdMatches(n, idle.nodeId));
|
|
8764
8941
|
if (node) {
|
|
8765
8942
|
remoteIdleSessionsChecked += 1;
|
|
8766
8943
|
remoteCandidates.push({ nodeId: idle.nodeId, sessionId: idle.sessionId, providerType: idle.providerType, origin: "remote", node });
|
|
@@ -9563,6 +9740,21 @@ async function runMeshReconcileTick(components) {
|
|
|
9563
9740
|
}
|
|
9564
9741
|
}
|
|
9565
9742
|
}
|
|
9743
|
+
for (const mesh of listMeshes()) {
|
|
9744
|
+
const selfIds = resolveCoordinatorSelfIds(mesh, drainDaemonIds);
|
|
9745
|
+
if (!daemonHostsMesh(mesh, selfIds)) continue;
|
|
9746
|
+
if (store) {
|
|
9747
|
+
try {
|
|
9748
|
+
if (store.pendingQueueTaskCount(mesh.id) === 0) continue;
|
|
9749
|
+
} catch {
|
|
9750
|
+
}
|
|
9751
|
+
}
|
|
9752
|
+
try {
|
|
9753
|
+
await triggerMeshQueue(components, mesh.id);
|
|
9754
|
+
} catch (e) {
|
|
9755
|
+
LOG.warn("MeshReconcile", `Pending-claim recovery trigger failed for mesh ${mesh.id}: ${e?.message || e}`);
|
|
9756
|
+
}
|
|
9757
|
+
}
|
|
9566
9758
|
const coordinators = findLiveCoordinators(components);
|
|
9567
9759
|
if (coordinators.length === 0) {
|
|
9568
9760
|
return;
|
|
@@ -10959,8 +11151,24 @@ function findBinary(name) {
|
|
|
10959
11151
|
}
|
|
10960
11152
|
const isWin = os12.platform() === "win32";
|
|
10961
11153
|
const paths = (process.env.PATH || "").split(path17.delimiter);
|
|
11154
|
+
const extraDirs = [];
|
|
11155
|
+
if (isWin) {
|
|
11156
|
+
if (process.env.APPDATA) extraDirs.push(path17.join(process.env.APPDATA, "npm"));
|
|
11157
|
+
try {
|
|
11158
|
+
extraDirs.push(path17.dirname(process.execPath));
|
|
11159
|
+
} catch {
|
|
11160
|
+
}
|
|
11161
|
+
} else {
|
|
11162
|
+
extraDirs.push(path17.join(os12.homedir(), ".npm-global", "bin"));
|
|
11163
|
+
extraDirs.push("/usr/local/bin", "/opt/homebrew/bin");
|
|
11164
|
+
try {
|
|
11165
|
+
extraDirs.push(path17.dirname(process.execPath));
|
|
11166
|
+
} catch {
|
|
11167
|
+
}
|
|
11168
|
+
}
|
|
11169
|
+
const searchDirs = [...paths, ...extraDirs];
|
|
10962
11170
|
const exes = isWin ? [".exe", ".cmd", ".bat", ""] : [""];
|
|
10963
|
-
for (const p of
|
|
11171
|
+
for (const p of searchDirs) {
|
|
10964
11172
|
if (!p) continue;
|
|
10965
11173
|
for (const ext of exes) {
|
|
10966
11174
|
const fullPath = path17.join(p, trimmed + ext);
|
|
@@ -14357,6 +14565,37 @@ ${lastSnapshot}`;
|
|
|
14357
14565
|
if (!this.ptyProcess || typeof this.ptyProcess.getMetadata !== "function") return null;
|
|
14358
14566
|
return this.ptyProcess.getMetadata();
|
|
14359
14567
|
}
|
|
14568
|
+
/**
|
|
14569
|
+
* Launch metadata for the dashboard Session info panel. Re-derives the spawn plan
|
|
14570
|
+
* (pure — same inputs the live PTY was spawned with) so the dashboard sees the
|
|
14571
|
+
* resolved binary, full arg vector, and cwd without us having to persist it.
|
|
14572
|
+
* extraEnv values are intentionally dropped (keys only) so secrets passed at
|
|
14573
|
+
* launch time never reach the dashboard.
|
|
14574
|
+
*/
|
|
14575
|
+
getLaunchInfo() {
|
|
14576
|
+
let command;
|
|
14577
|
+
let args = [...this.extraArgs];
|
|
14578
|
+
try {
|
|
14579
|
+
const plan = resolveCliSpawnPlan({
|
|
14580
|
+
provider: this.provider,
|
|
14581
|
+
runtimeSettings: this.runtimeSettings,
|
|
14582
|
+
workingDir: this.workingDir,
|
|
14583
|
+
extraArgs: this.extraArgs,
|
|
14584
|
+
extraEnv: this.extraEnv
|
|
14585
|
+
});
|
|
14586
|
+
command = plan.binaryPath;
|
|
14587
|
+
args = plan.allArgs;
|
|
14588
|
+
} catch {
|
|
14589
|
+
}
|
|
14590
|
+
return {
|
|
14591
|
+
command,
|
|
14592
|
+
args,
|
|
14593
|
+
extraArgs: [...this.extraArgs],
|
|
14594
|
+
cwd: this.workingDir,
|
|
14595
|
+
extraEnvKeys: Object.keys(this.extraEnv || {}),
|
|
14596
|
+
providerSessionId: this.providerSessionId || void 0
|
|
14597
|
+
};
|
|
14598
|
+
}
|
|
14360
14599
|
updateRuntimeMeta(meta, replace = false) {
|
|
14361
14600
|
const nextProviderSessionId = typeof meta?.providerSessionId === "string" ? meta.providerSessionId.trim() : "";
|
|
14362
14601
|
if (nextProviderSessionId) {
|
|
@@ -18588,8 +18827,8 @@ async function detectIDEs(providerLoader) {
|
|
|
18588
18827
|
if (existsSync16(bundledCli)) resolvedCli = bundledCli;
|
|
18589
18828
|
}
|
|
18590
18829
|
if (!resolvedCli && appPath && os30 === "win32") {
|
|
18591
|
-
const { dirname:
|
|
18592
|
-
const appDir =
|
|
18830
|
+
const { dirname: dirname15 } = await import("path");
|
|
18831
|
+
const appDir = dirname15(appPath);
|
|
18593
18832
|
const candidates = [
|
|
18594
18833
|
`${appDir}\\\\bin\\\\${def.cli}.cmd`,
|
|
18595
18834
|
`${appDir}\\\\bin\\\\${def.cli}`,
|
|
@@ -41197,7 +41436,7 @@ init_mesh_refine_status();
|
|
|
41197
41436
|
|
|
41198
41437
|
// src/mesh/mesh-init.ts
|
|
41199
41438
|
import { existsSync as existsSync35, mkdirSync as mkdirSync15, writeFileSync as writeFileSync17 } from "fs";
|
|
41200
|
-
import { dirname as
|
|
41439
|
+
import { dirname as dirname8, join as join37 } from "path";
|
|
41201
41440
|
var MESH_INIT_REFINE_CONFIG_PATH = MESH_REFINE_CONFIG_LOCATIONS[0];
|
|
41202
41441
|
var MESH_INIT_WORKTREE_BOOTSTRAP_CONFIG_PATH = MESH_WORKTREE_BOOTSTRAP_CONFIG_LOCATIONS[0];
|
|
41203
41442
|
var CANDIDATE_STALE_INPUTS = [
|
|
@@ -41212,7 +41451,7 @@ var CANDIDATE_STALE_INPUTS = [
|
|
|
41212
41451
|
];
|
|
41213
41452
|
function writeConfigFile(workspace, relativePath, config) {
|
|
41214
41453
|
const target = join37(workspace, relativePath);
|
|
41215
|
-
mkdirSync15(
|
|
41454
|
+
mkdirSync15(dirname8(target), { recursive: true });
|
|
41216
41455
|
writeFileSync17(target, `${JSON.stringify(config, null, 2)}
|
|
41217
41456
|
`, "utf-8");
|
|
41218
41457
|
return target;
|
|
@@ -42776,7 +43015,15 @@ var MESH_DIRECT_PROBE_MAX_RETRIES = 2;
|
|
|
42776
43015
|
function readMeshConnectionState(connection) {
|
|
42777
43016
|
return readStringValue(connection?.state);
|
|
42778
43017
|
}
|
|
43018
|
+
function isMeshConnectionDefinitivelyDown(connection) {
|
|
43019
|
+
if (!connection) return true;
|
|
43020
|
+
const state = readMeshConnectionState(connection);
|
|
43021
|
+
return state === "failed" || state === "closed" || state === "disconnected";
|
|
43022
|
+
}
|
|
42779
43023
|
async function probeRemoteMeshGitStatusWithRetry(args) {
|
|
43024
|
+
if (args.getConnection && isMeshConnectionDefinitivelyDown(args.getConnection(args.daemonId))) {
|
|
43025
|
+
return null;
|
|
43026
|
+
}
|
|
42780
43027
|
for (let attempt = 0; attempt <= MESH_DIRECT_PROBE_MAX_RETRIES; attempt += 1) {
|
|
42781
43028
|
if (attempt > 0) {
|
|
42782
43029
|
const connection = args.getConnection?.(args.daemonId);
|
|
@@ -46757,6 +47004,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
46757
47004
|
if (!target && !coord) return { success: false, error: "Session not found", sessionId };
|
|
46758
47005
|
const adapter = target ? this.deps.cliManager.findAdapter(target.providerType, { instanceKey: sessionId })?.adapter : void 0;
|
|
46759
47006
|
const runtimeMeta = adapter && typeof adapter.getRuntimeMetadata === "function" ? adapter.getRuntimeMetadata() : void 0;
|
|
47007
|
+
const launchInfo = adapter && typeof adapter.getLaunchInfo === "function" ? adapter.getLaunchInfo() : void 0;
|
|
46760
47008
|
const providerType = target?.providerType || coord?.cliType || "";
|
|
46761
47009
|
const providerMetaForSession = providerType ? this.deps.providerLoader.resolve?.(providerType) || this.deps.providerLoader.getMeta(providerType) : void 0;
|
|
46762
47010
|
return {
|
|
@@ -46768,8 +47016,11 @@ ${hintLines.join("\n")}` : "",
|
|
|
46768
47016
|
transport: target?.transport,
|
|
46769
47017
|
workspace: target?.workspace || coord?.workspace,
|
|
46770
47018
|
spawnedAtMs: target?.spawnedAtMs || coord?.startedAt,
|
|
46771
|
-
providerSessionId
|
|
46772
|
-
|
|
47019
|
+
// providerSessionId now comes from the live adapter's launch info
|
|
47020
|
+
// (the registry target never carried it — it was always undefined).
|
|
47021
|
+
providerSessionId: launchInfo?.providerSessionId || target?.providerSessionId,
|
|
47022
|
+
runtimeMetadata: runtimeMeta,
|
|
47023
|
+
launch: launchInfo
|
|
46773
47024
|
},
|
|
46774
47025
|
coordinator: coord ? {
|
|
46775
47026
|
meshId: coord.meshId,
|
|
@@ -48610,7 +48861,7 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
48610
48861
|
};
|
|
48611
48862
|
}
|
|
48612
48863
|
const { existsSync: existsSync44, readFileSync: readFileSync35, writeFileSync: writeFileSync23, copyFileSync: copyFileSync4, mkdirSync: mkdirSync21 } = await import("fs");
|
|
48613
|
-
const { dirname:
|
|
48864
|
+
const { dirname: dirname15 } = await import("path");
|
|
48614
48865
|
const mcpConfigPath = coordinatorSetup.configPath;
|
|
48615
48866
|
const hermesManualFallback = cliType === "hermes-cli" && configFormat === "hermes_config_yaml" ? createHermesManualMeshCoordinatorSetup(meshId, workspace) : null;
|
|
48616
48867
|
let hermesBaseConfig = null;
|
|
@@ -48645,7 +48896,7 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
48645
48896
|
};
|
|
48646
48897
|
}
|
|
48647
48898
|
try {
|
|
48648
|
-
mkdirSync21(
|
|
48899
|
+
mkdirSync21(dirname15(mcpConfigPath), { recursive: true });
|
|
48649
48900
|
} catch (error) {
|
|
48650
48901
|
const message = `Could not prepare MCP config path for automatic setup: ${error?.message || error}`;
|
|
48651
48902
|
LOG.error("MeshCoordinator", message);
|
|
@@ -48655,7 +48906,7 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
48655
48906
|
const hadExistingMcpConfig = existsSync44(mcpConfigPath);
|
|
48656
48907
|
let existingMcpConfig = hermesBaseConfig?.config || {};
|
|
48657
48908
|
if (hermesBaseConfig) {
|
|
48658
|
-
copyHermesCoordinatorCredentialFiles(hermesBaseConfig.sourceHome,
|
|
48909
|
+
copyHermesCoordinatorCredentialFiles(hermesBaseConfig.sourceHome, dirname15(mcpConfigPath));
|
|
48659
48910
|
}
|
|
48660
48911
|
if (hadExistingMcpConfig) {
|
|
48661
48912
|
try {
|
|
@@ -48693,7 +48944,7 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
48693
48944
|
const cliArgs = [];
|
|
48694
48945
|
const launchEnv = {};
|
|
48695
48946
|
if (configFormat === "hermes_config_yaml") {
|
|
48696
|
-
launchEnv.HERMES_HOME =
|
|
48947
|
+
launchEnv.HERMES_HOME = dirname15(mcpConfigPath);
|
|
48697
48948
|
launchEnv.HERMES_IGNORE_USER_CONFIG = "";
|
|
48698
48949
|
}
|
|
48699
48950
|
let autoImportContextFilePath;
|
|
@@ -57718,11 +57969,11 @@ init_parse_session();
|
|
|
57718
57969
|
// src/providers/sdk/v1/fixture-tooling/replay.ts
|
|
57719
57970
|
init_provider_cli_shared();
|
|
57720
57971
|
import { readFileSync as readFileSync33 } from "fs";
|
|
57721
|
-
import { dirname as
|
|
57972
|
+
import { dirname as dirname13, resolve as resolve22 } from "path";
|
|
57722
57973
|
|
|
57723
57974
|
// src/providers/sdk/v1/validators/taint.ts
|
|
57724
57975
|
import { readFileSync as readFileSync34, existsSync as existsSync43 } from "fs";
|
|
57725
|
-
import { resolve as resolve23, dirname as
|
|
57976
|
+
import { resolve as resolve23, dirname as dirname14, join as join44 } from "path";
|
|
57726
57977
|
|
|
57727
57978
|
// src/providers/sdk/v1/validators/index.ts
|
|
57728
57979
|
init_manifest();
|
|
@@ -57827,6 +58078,7 @@ export {
|
|
|
57827
58078
|
DEFAULT_STATUS_INITIAL_REPORT_DELAY_MS,
|
|
57828
58079
|
DEFAULT_STATUS_P2P_REPORT_INTERVAL_MS,
|
|
57829
58080
|
DEFAULT_STATUS_SERVER_REPORT_INTERVAL_MS,
|
|
58081
|
+
DEFAULT_TASKMODE_ROLE_MAP,
|
|
57830
58082
|
DEV_SERVER_PORT,
|
|
57831
58083
|
DaemonAgentStreamManager,
|
|
57832
58084
|
DaemonCdpInitializer,
|
|
@@ -57866,6 +58118,7 @@ export {
|
|
|
57866
58118
|
RawTerminalAttachment,
|
|
57867
58119
|
STALE_TERMINAL_REFINE_WINDOW_MS,
|
|
57868
58120
|
STANDALONE_CDP_SCAN_INTERVAL_MS,
|
|
58121
|
+
STANDARD_MESH_ROLES,
|
|
57869
58122
|
SessionHostPtyTransportFactory,
|
|
57870
58123
|
TerminalAdapter,
|
|
57871
58124
|
TurnSnapshotTracker,
|
|
@@ -58099,9 +58352,12 @@ export {
|
|
|
58099
58352
|
resolveGitRepository,
|
|
58100
58353
|
resolveMeshHostStatus,
|
|
58101
58354
|
resolveMeshRefineValidationPlan,
|
|
58355
|
+
resolveMeshRoleOptions,
|
|
58102
58356
|
resolveNodeSchedulingPriority,
|
|
58103
58357
|
resolveSessionHostAppName,
|
|
58104
58358
|
resolveSessionHostAppNameResolution,
|
|
58359
|
+
resolveTaskAffinityRequiredTags,
|
|
58360
|
+
resolveTaskAffinityRole,
|
|
58105
58361
|
resolveWorktreePath,
|
|
58106
58362
|
runAsyncBatch,
|
|
58107
58363
|
runGit,
|