@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.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 ? "930909642b3f28668483159d3a8f39d0a796c61a" : void 0) ?? "unknown";
352
- const commitShort = readInjected(true ? "93090964" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
353
- const version = readInjected(true ? "0.9.82-rc.316" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
354
- const builtAt = readInjected(true ? "2026-06-18T07:23:07.242Z" : void 0);
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 result = await runGit(repo, ["submodule", "status"], options);
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.id === idle.nodeId);
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);