@adhdev/daemon-core 0.9.82-rc.316 → 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/index.js +107 -29
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +107 -29
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/mesh-runtime-store.d.ts +6 -0
- package/package.json +2 -2
- package/src/commands/router.ts +32 -0
- package/src/git/git-status.ts +122 -41
- 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/dist/index.js
CHANGED
|
@@ -353,10 +353,10 @@ function readInjected(value) {
|
|
|
353
353
|
}
|
|
354
354
|
function getDaemonBuildInfo() {
|
|
355
355
|
if (cached) return cached;
|
|
356
|
-
const commit = readInjected(true ? "
|
|
357
|
-
const commitShort = readInjected(true ? "
|
|
358
|
-
const version = readInjected(true ? "0.9.82-rc.
|
|
359
|
-
const builtAt = readInjected(true ? "2026-06-
|
|
356
|
+
const commit = readInjected(true ? "b4484284652748bf8096f40a00eb5cb463963576" : void 0) ?? "unknown";
|
|
357
|
+
const commitShort = readInjected(true ? "b4484284" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
358
|
+
const version = readInjected(true ? "0.9.82-rc.317" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
359
|
+
const builtAt = readInjected(true ? "2026-06-18T08:55:18.955Z" : void 0);
|
|
360
360
|
cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
|
|
361
361
|
return cached;
|
|
362
362
|
}
|
|
@@ -682,14 +682,79 @@ function emptyStatus(workspace, lastCheckedAt, error) {
|
|
|
682
682
|
async function getSubmoduleStatuses(repo, options) {
|
|
683
683
|
if (!repo.repoRoot) return [];
|
|
684
684
|
try {
|
|
685
|
-
const
|
|
686
|
-
const submodules = parseSubmoduleStatusOutput(result.stdout, repo.repoRoot, options.submoduleIgnorePaths);
|
|
685
|
+
const submodules = await deriveSubmoduleGitlinkStatuses(repo, options);
|
|
687
686
|
await Promise.all(submodules.map((submodule) => enrichSubmoduleWorktreeStatus(repo, submodule, options)));
|
|
688
687
|
return submodules;
|
|
689
688
|
} catch {
|
|
690
689
|
return [];
|
|
691
690
|
}
|
|
692
691
|
}
|
|
692
|
+
async function deriveSubmoduleGitlinkStatuses(repo, options) {
|
|
693
|
+
if (!repo.repoRoot) return [];
|
|
694
|
+
const paths = await readSubmodulePaths(repo, options);
|
|
695
|
+
const ignoreSet = new Set(options.submoduleIgnorePaths || []);
|
|
696
|
+
const lastCheckedAt = Date.now();
|
|
697
|
+
const entries = await Promise.all(
|
|
698
|
+
paths.filter((path41) => !ignoreSet.has(path41)).map(async (path41) => {
|
|
699
|
+
const repoPath = repo.repoRoot + "/" + path41;
|
|
700
|
+
const expected = await readGitlinkExpectedSha(repo, path41, options);
|
|
701
|
+
const actual = await readSubmoduleHeadSha(repo, repoPath, options);
|
|
702
|
+
const outOfSync = actual === null ? true : expected !== null && expected !== actual;
|
|
703
|
+
return {
|
|
704
|
+
path: path41,
|
|
705
|
+
// Prefer the recorded gitlink SHA (matches the legacy column); fall back
|
|
706
|
+
// to the checked-out SHA so the field is never empty when both are known.
|
|
707
|
+
commit: expected ?? actual ?? "",
|
|
708
|
+
repoPath,
|
|
709
|
+
dirty: false,
|
|
710
|
+
outOfSync,
|
|
711
|
+
lastCheckedAt
|
|
712
|
+
};
|
|
713
|
+
})
|
|
714
|
+
);
|
|
715
|
+
return entries;
|
|
716
|
+
}
|
|
717
|
+
async function readSubmodulePaths(repo, options) {
|
|
718
|
+
if (!repo.repoRoot) return [];
|
|
719
|
+
const gitmodulesPath = repo.repoRoot + "/.gitmodules";
|
|
720
|
+
try {
|
|
721
|
+
const result = await runGit(
|
|
722
|
+
repo,
|
|
723
|
+
["config", "--file", gitmodulesPath, "--get-regexp", "^submodule\\..*\\.path$"],
|
|
724
|
+
options
|
|
725
|
+
);
|
|
726
|
+
const paths = [];
|
|
727
|
+
for (const line of result.stdout.split("\n")) {
|
|
728
|
+
const spaceIdx = line.indexOf(" ");
|
|
729
|
+
if (spaceIdx < 0) continue;
|
|
730
|
+
const value = line.slice(spaceIdx + 1).trim();
|
|
731
|
+
if (value) paths.push(value);
|
|
732
|
+
}
|
|
733
|
+
return paths;
|
|
734
|
+
} catch {
|
|
735
|
+
return [];
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
async function readGitlinkExpectedSha(repo, submodulePath, options) {
|
|
739
|
+
try {
|
|
740
|
+
const result = await runGit(repo, ["ls-tree", "HEAD", submodulePath], options);
|
|
741
|
+
const line = result.stdout.split("\n").find((l) => l.trim().length > 0);
|
|
742
|
+
if (!line) return null;
|
|
743
|
+
const match = line.match(/^\s*\d+\s+commit\s+([0-9a-f]{40})\b/);
|
|
744
|
+
return match ? match[1] : null;
|
|
745
|
+
} catch {
|
|
746
|
+
return null;
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
async function readSubmoduleHeadSha(repo, repoPath, options) {
|
|
750
|
+
try {
|
|
751
|
+
const result = await runGit(repo, ["rev-parse", "HEAD"], { ...options, cwd: repoPath });
|
|
752
|
+
const sha = result.stdout.trim();
|
|
753
|
+
return /^[0-9a-f]{40}$/.test(sha) ? sha : null;
|
|
754
|
+
} catch {
|
|
755
|
+
return null;
|
|
756
|
+
}
|
|
757
|
+
}
|
|
693
758
|
async function enrichSubmoduleWorktreeStatus(repo, submodule, options) {
|
|
694
759
|
try {
|
|
695
760
|
const result = await runGit(repo, ["status", "--porcelain=v2", "--branch"], {
|
|
@@ -704,28 +769,6 @@ async function enrichSubmoduleWorktreeStatus(repo, submodule, options) {
|
|
|
704
769
|
submodule.error = formatGitError(error);
|
|
705
770
|
}
|
|
706
771
|
}
|
|
707
|
-
function parseSubmoduleStatusOutput(output, repoRoot, ignorePaths) {
|
|
708
|
-
const submodules = [];
|
|
709
|
-
const ignoreSet = new Set(ignorePaths || []);
|
|
710
|
-
for (const line of output.split("\n")) {
|
|
711
|
-
if (!line.trim()) continue;
|
|
712
|
-
const match = line.match(/^([\-+U\s])([0-9a-f]{40})\s+(\S+)(?:\s+\(([^)]+)\))?/);
|
|
713
|
-
if (!match) continue;
|
|
714
|
-
const prefix = match[1];
|
|
715
|
-
const commit = match[2];
|
|
716
|
-
const path41 = match[3];
|
|
717
|
-
if (ignoreSet.has(path41)) continue;
|
|
718
|
-
submodules.push({
|
|
719
|
-
path: path41,
|
|
720
|
-
commit,
|
|
721
|
-
repoPath: repoRoot + "/" + path41,
|
|
722
|
-
dirty: prefix === "U",
|
|
723
|
-
outOfSync: prefix === "-" || prefix === "+",
|
|
724
|
-
lastCheckedAt: Date.now()
|
|
725
|
-
});
|
|
726
|
-
}
|
|
727
|
-
return submodules;
|
|
728
|
-
}
|
|
729
772
|
var lastKnownGoodStatus, DAEMON_RUNTIME_PACKAGES, WEB_ONLY_PACKAGES;
|
|
730
773
|
var init_git_status = __esm({
|
|
731
774
|
"src/git/git-status.ts"() {
|
|
@@ -3955,6 +3998,18 @@ var init_mesh_runtime_store = __esm({
|
|
|
3955
3998
|
`).get(meshId, nodeId);
|
|
3956
3999
|
return row?.count ?? 0;
|
|
3957
4000
|
}
|
|
4001
|
+
/**
|
|
4002
|
+
* O(1) count of queue tasks in 'pending' status for a mesh. A COUNT(*) over the
|
|
4003
|
+
* indexed status column, so it avoids JSON.parse-ing every queue row — used as a
|
|
4004
|
+
* cheap guard before the reconcile loop runs a full triggerMeshQueue scan.
|
|
4005
|
+
*/
|
|
4006
|
+
pendingQueueTaskCount(meshId) {
|
|
4007
|
+
const row = this.db.prepare(`
|
|
4008
|
+
SELECT COUNT(*) as count FROM mesh_queue
|
|
4009
|
+
WHERE mesh_id = ? AND status = 'pending'
|
|
4010
|
+
`).get(meshId);
|
|
4011
|
+
return row?.count ?? 0;
|
|
4012
|
+
}
|
|
3958
4013
|
/**
|
|
3959
4014
|
* Read the current per-mesh round-robin cursor (0 when unset). Used to rotate
|
|
3960
4015
|
* the tie-break winner among nodes tied at the least load.
|
|
@@ -8888,7 +8943,7 @@ async function triggerMeshQueue(components, meshId) {
|
|
|
8888
8943
|
}
|
|
8889
8944
|
const remoteCandidates = [];
|
|
8890
8945
|
for (const idle of remoteSessions) {
|
|
8891
|
-
const node = mesh.nodes.find((n) => n
|
|
8946
|
+
const node = mesh.nodes.find((n) => meshNodeIdMatches(n, idle.nodeId));
|
|
8892
8947
|
if (node) {
|
|
8893
8948
|
remoteIdleSessionsChecked += 1;
|
|
8894
8949
|
remoteCandidates.push({ nodeId: idle.nodeId, sessionId: idle.sessionId, providerType: idle.providerType, origin: "remote", node });
|
|
@@ -9692,6 +9747,21 @@ async function runMeshReconcileTick(components) {
|
|
|
9692
9747
|
}
|
|
9693
9748
|
}
|
|
9694
9749
|
}
|
|
9750
|
+
for (const mesh of listMeshes()) {
|
|
9751
|
+
const selfIds = resolveCoordinatorSelfIds(mesh, drainDaemonIds);
|
|
9752
|
+
if (!daemonHostsMesh(mesh, selfIds)) continue;
|
|
9753
|
+
if (store) {
|
|
9754
|
+
try {
|
|
9755
|
+
if (store.pendingQueueTaskCount(mesh.id) === 0) continue;
|
|
9756
|
+
} catch {
|
|
9757
|
+
}
|
|
9758
|
+
}
|
|
9759
|
+
try {
|
|
9760
|
+
await triggerMeshQueue(components, mesh.id);
|
|
9761
|
+
} catch (e) {
|
|
9762
|
+
LOG.warn("MeshReconcile", `Pending-claim recovery trigger failed for mesh ${mesh.id}: ${e?.message || e}`);
|
|
9763
|
+
}
|
|
9764
|
+
}
|
|
9695
9765
|
const coordinators = findLiveCoordinators(components);
|
|
9696
9766
|
if (coordinators.length === 0) {
|
|
9697
9767
|
return;
|
|
@@ -43297,7 +43367,15 @@ var MESH_DIRECT_PROBE_MAX_RETRIES = 2;
|
|
|
43297
43367
|
function readMeshConnectionState(connection) {
|
|
43298
43368
|
return readStringValue(connection?.state);
|
|
43299
43369
|
}
|
|
43370
|
+
function isMeshConnectionDefinitivelyDown(connection) {
|
|
43371
|
+
if (!connection) return true;
|
|
43372
|
+
const state = readMeshConnectionState(connection);
|
|
43373
|
+
return state === "failed" || state === "closed" || state === "disconnected";
|
|
43374
|
+
}
|
|
43300
43375
|
async function probeRemoteMeshGitStatusWithRetry(args) {
|
|
43376
|
+
if (args.getConnection && isMeshConnectionDefinitivelyDown(args.getConnection(args.daemonId))) {
|
|
43377
|
+
return null;
|
|
43378
|
+
}
|
|
43301
43379
|
for (let attempt = 0; attempt <= MESH_DIRECT_PROBE_MAX_RETRIES; attempt += 1) {
|
|
43302
43380
|
if (attempt > 0) {
|
|
43303
43381
|
const connection = args.getConnection?.(args.daemonId);
|