@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.mjs
CHANGED
|
@@ -348,10 +348,10 @@ function readInjected(value) {
|
|
|
348
348
|
}
|
|
349
349
|
function getDaemonBuildInfo() {
|
|
350
350
|
if (cached) return cached;
|
|
351
|
-
const commit = readInjected(true ? "
|
|
352
|
-
const commitShort = readInjected(true ? "
|
|
353
|
-
const version = readInjected(true ? "0.9.82-rc.
|
|
354
|
-
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);
|
|
355
355
|
cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
|
|
356
356
|
return cached;
|
|
357
357
|
}
|
|
@@ -677,14 +677,79 @@ function emptyStatus(workspace, lastCheckedAt, error) {
|
|
|
677
677
|
async function getSubmoduleStatuses(repo, options) {
|
|
678
678
|
if (!repo.repoRoot) return [];
|
|
679
679
|
try {
|
|
680
|
-
const
|
|
681
|
-
const submodules = parseSubmoduleStatusOutput(result.stdout, repo.repoRoot, options.submoduleIgnorePaths);
|
|
680
|
+
const submodules = await deriveSubmoduleGitlinkStatuses(repo, options);
|
|
682
681
|
await Promise.all(submodules.map((submodule) => enrichSubmoduleWorktreeStatus(repo, submodule, options)));
|
|
683
682
|
return submodules;
|
|
684
683
|
} catch {
|
|
685
684
|
return [];
|
|
686
685
|
}
|
|
687
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
|
+
}
|
|
688
753
|
async function enrichSubmoduleWorktreeStatus(repo, submodule, options) {
|
|
689
754
|
try {
|
|
690
755
|
const result = await runGit(repo, ["status", "--porcelain=v2", "--branch"], {
|
|
@@ -699,28 +764,6 @@ async function enrichSubmoduleWorktreeStatus(repo, submodule, options) {
|
|
|
699
764
|
submodule.error = formatGitError(error);
|
|
700
765
|
}
|
|
701
766
|
}
|
|
702
|
-
function parseSubmoduleStatusOutput(output, repoRoot, ignorePaths) {
|
|
703
|
-
const submodules = [];
|
|
704
|
-
const ignoreSet = new Set(ignorePaths || []);
|
|
705
|
-
for (const line of output.split("\n")) {
|
|
706
|
-
if (!line.trim()) continue;
|
|
707
|
-
const match = line.match(/^([\-+U\s])([0-9a-f]{40})\s+(\S+)(?:\s+\(([^)]+)\))?/);
|
|
708
|
-
if (!match) continue;
|
|
709
|
-
const prefix = match[1];
|
|
710
|
-
const commit = match[2];
|
|
711
|
-
const path41 = match[3];
|
|
712
|
-
if (ignoreSet.has(path41)) continue;
|
|
713
|
-
submodules.push({
|
|
714
|
-
path: path41,
|
|
715
|
-
commit,
|
|
716
|
-
repoPath: repoRoot + "/" + path41,
|
|
717
|
-
dirty: prefix === "U",
|
|
718
|
-
outOfSync: prefix === "-" || prefix === "+",
|
|
719
|
-
lastCheckedAt: Date.now()
|
|
720
|
-
});
|
|
721
|
-
}
|
|
722
|
-
return submodules;
|
|
723
|
-
}
|
|
724
767
|
var lastKnownGoodStatus, DAEMON_RUNTIME_PACKAGES, WEB_ONLY_PACKAGES;
|
|
725
768
|
var init_git_status = __esm({
|
|
726
769
|
"src/git/git-status.ts"() {
|
|
@@ -3949,6 +3992,18 @@ var init_mesh_runtime_store = __esm({
|
|
|
3949
3992
|
`).get(meshId, nodeId);
|
|
3950
3993
|
return row?.count ?? 0;
|
|
3951
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
|
+
}
|
|
3952
4007
|
/**
|
|
3953
4008
|
* Read the current per-mesh round-robin cursor (0 when unset). Used to rotate
|
|
3954
4009
|
* the tie-break winner among nodes tied at the least load.
|
|
@@ -8882,7 +8937,7 @@ async function triggerMeshQueue(components, meshId) {
|
|
|
8882
8937
|
}
|
|
8883
8938
|
const remoteCandidates = [];
|
|
8884
8939
|
for (const idle of remoteSessions) {
|
|
8885
|
-
const node = mesh.nodes.find((n) => n
|
|
8940
|
+
const node = mesh.nodes.find((n) => meshNodeIdMatches(n, idle.nodeId));
|
|
8886
8941
|
if (node) {
|
|
8887
8942
|
remoteIdleSessionsChecked += 1;
|
|
8888
8943
|
remoteCandidates.push({ nodeId: idle.nodeId, sessionId: idle.sessionId, providerType: idle.providerType, origin: "remote", node });
|
|
@@ -9685,6 +9740,21 @@ async function runMeshReconcileTick(components) {
|
|
|
9685
9740
|
}
|
|
9686
9741
|
}
|
|
9687
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
|
+
}
|
|
9688
9758
|
const coordinators = findLiveCoordinators(components);
|
|
9689
9759
|
if (coordinators.length === 0) {
|
|
9690
9760
|
return;
|
|
@@ -42945,7 +43015,15 @@ var MESH_DIRECT_PROBE_MAX_RETRIES = 2;
|
|
|
42945
43015
|
function readMeshConnectionState(connection) {
|
|
42946
43016
|
return readStringValue(connection?.state);
|
|
42947
43017
|
}
|
|
43018
|
+
function isMeshConnectionDefinitivelyDown(connection) {
|
|
43019
|
+
if (!connection) return true;
|
|
43020
|
+
const state = readMeshConnectionState(connection);
|
|
43021
|
+
return state === "failed" || state === "closed" || state === "disconnected";
|
|
43022
|
+
}
|
|
42948
43023
|
async function probeRemoteMeshGitStatusWithRetry(args) {
|
|
43024
|
+
if (args.getConnection && isMeshConnectionDefinitivelyDown(args.getConnection(args.daemonId))) {
|
|
43025
|
+
return null;
|
|
43026
|
+
}
|
|
42949
43027
|
for (let attempt = 0; attempt <= MESH_DIRECT_PROBE_MAX_RETRIES; attempt += 1) {
|
|
42950
43028
|
if (attempt > 0) {
|
|
42951
43029
|
const connection = args.getConnection?.(args.daemonId);
|