@adhdev/daemon-core 0.9.82-rc.407 → 0.9.82-rc.408

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
@@ -394,10 +394,10 @@ function readInjected(value) {
394
394
  }
395
395
  function getDaemonBuildInfo() {
396
396
  if (cached) return cached;
397
- const commit = readInjected(true ? "bfd7d9b1d38a7d1f4709fbad2627c56b5a1ae342" : void 0) ?? "unknown";
398
- const commitShort = readInjected(true ? "bfd7d9b1" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
399
- const version = readInjected(true ? "0.9.82-rc.407" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
400
- const builtAt = readInjected(true ? "2026-06-28T06:12:15.473Z" : void 0);
397
+ const commit = readInjected(true ? "b6de7b335f9b6b6bfb202135c2ae017429182efa" : void 0) ?? "unknown";
398
+ const commitShort = readInjected(true ? "b6de7b33" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
399
+ const version = readInjected(true ? "0.9.82-rc.408" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
400
+ const builtAt = readInjected(true ? "2026-06-28T07:53:15.742Z" : void 0);
401
401
  cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
402
402
  return cached;
403
403
  }
@@ -650,6 +650,11 @@ var init_change_impact_config = __esm({
650
650
  });
651
651
 
652
652
  // src/git/git-status.ts
653
+ function statusCacheKey(workspace, options) {
654
+ const includeSubmodules = options.includeSubmodules !== false;
655
+ const refreshUpstream = options.refreshUpstream === true;
656
+ return `${workspace}\0sub=${includeSubmodules ? 1 : 0}\0up=${refreshUpstream ? 1 : 0}`;
657
+ }
653
658
  function isTransientGitFailure(error) {
654
659
  return error.reason === "timeout" || error.reason === "git_command_failed";
655
660
  }
@@ -657,15 +662,22 @@ async function getGitRepoStatus(workspace, options = {}) {
657
662
  const lastCheckedAt = Date.now();
658
663
  const includeSubmodules = options.includeSubmodules !== false;
659
664
  const effectiveOptions = options.timeoutMs === void 0 ? { ...options, timeoutMs: GIT_STATUS_TIMEOUT_MS } : options;
665
+ const cacheKey = statusCacheKey(workspace, options);
666
+ if (!options.forceFresh) {
667
+ const cached3 = lastKnownGoodStatus.get(cacheKey);
668
+ if (cached3 && lastCheckedAt - cached3.cachedAt < GIT_STATUS_CACHE_TTL_MS) {
669
+ return cached3.status;
670
+ }
671
+ }
660
672
  try {
661
673
  const repo = await resolveGitRepository(workspace, effectiveOptions);
662
674
  const status = await collectGitRepoStatus(repo, includeSubmodules, lastCheckedAt, effectiveOptions);
663
- lastKnownGoodStatus.set(workspace, status);
675
+ lastKnownGoodStatus.set(cacheKey, { status, cachedAt: lastCheckedAt });
664
676
  return status;
665
677
  } catch (error) {
666
678
  const gitError = error instanceof GitCommandError ? error : new GitCommandError("git_command_failed", "Failed to read Git status", { cause: error });
667
679
  if (isTransientGitFailure(gitError)) {
668
- const cached3 = lastKnownGoodStatus.get(workspace);
680
+ const cached3 = lastKnownGoodStatus.get(cacheKey)?.status;
669
681
  if (cached3) {
670
682
  return {
671
683
  ...cached3,
@@ -684,19 +696,25 @@ async function collectGitRepoStatus(repo, includeSubmodules, lastCheckedAt, opti
684
696
  let upstreamProbe = getInitialUpstreamProbe(parsed);
685
697
  if (options.refreshUpstream) {
686
698
  upstreamProbe = await refreshTrackedUpstream(repo, parsed, options);
687
- if (upstreamProbe.upstreamStatus === "fresh") {
699
+ if (upstreamProbe.upstreamStatus === "fresh" && upstreamProbe.didFetch) {
688
700
  parsed = await readPorcelainStatus(repo, options);
689
701
  }
690
702
  }
691
703
  const head = await readHead(repo, options);
692
704
  const stashCount = await readStashCount(repo, options);
693
705
  let submodules;
706
+ let submoduleHeadOids = /* @__PURE__ */ new Map();
694
707
  if (includeSubmodules) {
695
- submodules = await getSubmoduleStatuses(repo, options);
708
+ const subResult = await getSubmoduleStatuses(repo, options);
709
+ submodules = subResult.submodules;
710
+ submoduleHeadOids = subResult.headOidByPath;
696
711
  }
697
712
  const submoduleDirty = (submodules || []).some((submodule) => submodule.dirty || submodule.outOfSync || !!submodule.error);
698
713
  const dirty = parsed.staged + parsed.modified + parsed.untracked + parsed.deleted + parsed.renamed > 0 || parsed.conflictFiles.length > 0 || stashCount > 0 || submoduleDirty;
699
- const daemonBuildBehind = await detectDaemonBuildBehind(repo, submodules, options);
714
+ const daemonBuildBehind = await detectDaemonBuildBehind(repo, submodules, options, {
715
+ rootHeadOid: parsed.headOid,
716
+ submoduleHeadOids
717
+ });
700
718
  return {
701
719
  workspace: repo.workspace,
702
720
  repoRoot: repo.repoRoot,
@@ -799,25 +817,50 @@ function resolveChangeImpactConfigForRepo(repoRoot, options) {
799
817
  changeImpactConfigCache.set(repoRoot, { sourceKey: loaded.sourceKey, config });
800
818
  return { config, sourceKey: loaded.sourceKey };
801
819
  }
802
- async function detectDaemonBuildBehind(repo, submodules, options) {
820
+ async function detectDaemonBuildBehind(repo, submodules, options, headOids = { rootHeadOid: null, submoduleHeadOids: /* @__PURE__ */ new Map() }) {
803
821
  const build = options.daemonBuildInfo ?? getDaemonBuildInfo();
804
822
  if (!build.commit || build.commit === "unknown") return void 0;
805
823
  const { config, sourceKey: configKey } = resolveChangeImpactConfigForRepo(repo.repoRoot, options);
806
824
  const policy = resolveChangeImpactPolicy(config);
807
825
  const scopes = [
808
- { scope: "root", repoPath: repo.repoRoot || repo.workspace }
826
+ { scope: "root", repoPath: repo.repoRoot || repo.workspace, knownHeadOid: headOids.rootHeadOid }
809
827
  ];
810
828
  for (const sub of submodules || []) {
811
- if (sub.repoPath && !sub.error) scopes.push({ scope: sub.path, repoPath: sub.repoPath });
829
+ if (sub.repoPath && !sub.error) {
830
+ scopes.push({ scope: sub.path, repoPath: sub.repoPath, knownHeadOid: headOids.submoduleHeadOids.get(sub.path) ?? null });
831
+ }
812
832
  }
813
- for (const { scope, repoPath } of scopes) {
833
+ for (const { scope, repoPath, knownHeadOid } of scopes) {
814
834
  try {
815
- await runGit(repoPath, ["cat-file", "-e", `${build.commit}^{commit}`], options);
816
- const headResult = await runGit(repoPath, ["rev-parse", "HEAD"], options);
817
- const head = headResult.stdout.trim();
818
- if (!head || head === build.commit) continue;
819
- await runGit(repoPath, ["merge-base", "--is-ancestor", build.commit, "HEAD"], options);
835
+ let head = knownHeadOid;
836
+ const ancestryKey = head ? `${repoPath}::${build.commit}::${head}` : null;
837
+ if (ancestryKey) {
838
+ const cachedVerdict = buildBehindAncestryCache.get(ancestryKey);
839
+ if (cachedVerdict === false) continue;
840
+ if (cachedVerdict === void 0) {
841
+ if (head === build.commit) {
842
+ buildBehindAncestryCache.set(ancestryKey, false);
843
+ continue;
844
+ }
845
+ await runGit(repoPath, ["cat-file", "-e", `${build.commit}^{commit}`], options);
846
+ try {
847
+ await runGit(repoPath, ["merge-base", "--is-ancestor", build.commit, "HEAD"], options);
848
+ } catch {
849
+ buildBehindAncestryCache.set(ancestryKey, false);
850
+ continue;
851
+ }
852
+ buildBehindAncestryCache.set(ancestryKey, true);
853
+ }
854
+ } else {
855
+ await runGit(repoPath, ["cat-file", "-e", `${build.commit}^{commit}`], options);
856
+ const headResult = await runGit(repoPath, ["rev-parse", "HEAD"], options);
857
+ head = headResult.stdout.trim();
858
+ if (!head || head === build.commit) continue;
859
+ await runGit(repoPath, ["merge-base", "--is-ancestor", build.commit, "HEAD"], options);
860
+ buildBehindAncestryCache.set(`${repoPath}::${build.commit}::${head}`, true);
861
+ }
820
862
  const evalKey = `${repoPath}\0${build.commit}\0${head}\0${configKey}`;
863
+ if (!head) continue;
821
864
  let evaluated = changeImpactEvalCache.get(evalKey);
822
865
  if (!evaluated) {
823
866
  evaluated = await classifyDaemonBuildChange(repoPath, build.commit, options, policy);
@@ -859,6 +902,15 @@ async function refreshTrackedUpstream(repo, parsed, options) {
859
902
  if (!parsed.upstream || !parsed.branch) {
860
903
  return { upstreamStatus: "no_upstream" };
861
904
  }
905
+ const now = Date.now();
906
+ const lastFetch = upstreamFetchedAt.get(repo.workspace);
907
+ if (!options.forceFresh && lastFetch !== void 0 && now - lastFetch < GIT_FETCH_THROTTLE_MS) {
908
+ return {
909
+ upstreamStatus: "fresh",
910
+ upstreamFetchedAt: lastFetch,
911
+ didFetch: false
912
+ };
913
+ }
862
914
  const remoteName = await readBranchRemote(repo, parsed.branch, options) ?? inferRemoteName(parsed.upstream);
863
915
  if (!remoteName) {
864
916
  return {
@@ -868,9 +920,12 @@ async function refreshTrackedUpstream(repo, parsed, options) {
868
920
  }
869
921
  try {
870
922
  await runGit(repo, ["fetch", "--quiet", "--prune", "--no-tags", remoteName], options);
923
+ const fetchedAt = Date.now();
924
+ upstreamFetchedAt.set(repo.workspace, fetchedAt);
871
925
  return {
872
926
  upstreamStatus: "fresh",
873
- upstreamFetchedAt: Date.now()
927
+ upstreamFetchedAt: fetchedAt,
928
+ didFetch: true
874
929
  };
875
930
  } catch (error) {
876
931
  return {
@@ -903,6 +958,7 @@ function formatGitError(error) {
903
958
  function parsePorcelainV2Status(output) {
904
959
  const parsed = {
905
960
  branch: null,
961
+ headOid: null,
906
962
  upstream: null,
907
963
  ahead: 0,
908
964
  behind: 0,
@@ -915,6 +971,11 @@ function parsePorcelainV2Status(output) {
915
971
  };
916
972
  for (const line of output.split("\n")) {
917
973
  if (!line) continue;
974
+ if (line.startsWith("# branch.oid ")) {
975
+ const oid = line.slice("# branch.oid ".length).trim();
976
+ parsed.headOid = oid && oid !== "(initial)" && /^[0-9a-f]{7,64}$/.test(oid) ? oid : null;
977
+ continue;
978
+ }
918
979
  if (line.startsWith("# branch.head ")) {
919
980
  const branch = line.slice("# branch.head ".length).trim();
920
981
  parsed.branch = branch && branch !== "(detached)" ? branch : null;
@@ -1012,25 +1073,27 @@ function emptyStatus(workspace, lastCheckedAt, error) {
1012
1073
  };
1013
1074
  }
1014
1075
  async function getSubmoduleStatuses(repo, options) {
1015
- if (!repo.repoRoot) return [];
1076
+ if (!repo.repoRoot) return { submodules: [], headOidByPath: /* @__PURE__ */ new Map() };
1016
1077
  try {
1017
- const submodules = await deriveSubmoduleGitlinkStatuses(repo, options);
1078
+ const { submodules, headOidByPath } = await deriveSubmoduleGitlinkStatuses(repo, options);
1018
1079
  await Promise.all(submodules.map((submodule) => enrichSubmoduleWorktreeStatus(repo, submodule, options)));
1019
- return submodules;
1080
+ return { submodules, headOidByPath };
1020
1081
  } catch {
1021
- return [];
1082
+ return { submodules: [], headOidByPath: /* @__PURE__ */ new Map() };
1022
1083
  }
1023
1084
  }
1024
1085
  async function deriveSubmoduleGitlinkStatuses(repo, options) {
1025
- if (!repo.repoRoot) return [];
1086
+ if (!repo.repoRoot) return { submodules: [], headOidByPath: /* @__PURE__ */ new Map() };
1026
1087
  const paths = await readSubmodulePaths(repo, options);
1027
1088
  const ignoreSet = new Set(options.submoduleIgnorePaths || []);
1028
1089
  const lastCheckedAt = Date.now();
1090
+ const headOidByPath = /* @__PURE__ */ new Map();
1029
1091
  const entries = await Promise.all(
1030
1092
  paths.filter((path43) => !ignoreSet.has(path43)).map(async (path43) => {
1031
1093
  const repoPath = repo.repoRoot + "/" + path43;
1032
1094
  const expected = await readGitlinkExpectedSha(repo, path43, options);
1033
1095
  const actual = await readSubmoduleHeadSha(repo, repoPath, options);
1096
+ if (actual) headOidByPath.set(path43, actual);
1034
1097
  const outOfSync = actual === null ? true : expected !== null && expected !== actual;
1035
1098
  return {
1036
1099
  path: path43,
@@ -1044,7 +1107,7 @@ async function deriveSubmoduleGitlinkStatuses(repo, options) {
1044
1107
  };
1045
1108
  })
1046
1109
  );
1047
- return entries;
1110
+ return { submodules: entries, headOidByPath };
1048
1111
  }
1049
1112
  async function readSubmodulePaths(repo, options) {
1050
1113
  if (!repo.repoRoot) return [];
@@ -1101,16 +1164,20 @@ async function enrichSubmoduleWorktreeStatus(repo, submodule, options) {
1101
1164
  submodule.error = formatGitError(error);
1102
1165
  }
1103
1166
  }
1104
- var lastKnownGoodStatus, changeImpactEvalCache, changeImpactConfigCache, DEFAULT_DAEMON_RUNTIME_PACKAGES, DEFAULT_WEB_ONLY_PACKAGES, DEFAULT_IMPACT_TARGETS;
1167
+ var GIT_STATUS_CACHE_TTL_MS, lastKnownGoodStatus, changeImpactEvalCache, changeImpactConfigCache, buildBehindAncestryCache, GIT_FETCH_THROTTLE_MS, upstreamFetchedAt, DEFAULT_DAEMON_RUNTIME_PACKAGES, DEFAULT_WEB_ONLY_PACKAGES, DEFAULT_IMPACT_TARGETS;
1105
1168
  var init_git_status = __esm({
1106
1169
  "src/git/git-status.ts"() {
1107
1170
  "use strict";
1108
1171
  init_git_executor();
1109
1172
  init_build_info();
1110
1173
  init_change_impact_config();
1174
+ GIT_STATUS_CACHE_TTL_MS = 1500;
1111
1175
  lastKnownGoodStatus = /* @__PURE__ */ new Map();
1112
1176
  changeImpactEvalCache = /* @__PURE__ */ new Map();
1113
1177
  changeImpactConfigCache = /* @__PURE__ */ new Map();
1178
+ buildBehindAncestryCache = /* @__PURE__ */ new Map();
1179
+ GIT_FETCH_THROTTLE_MS = 3e4;
1180
+ upstreamFetchedAt = /* @__PURE__ */ new Map();
1114
1181
  DEFAULT_DAEMON_RUNTIME_PACKAGES = [
1115
1182
  "daemon-core",
1116
1183
  "daemon-standalone",
@@ -2989,7 +3056,7 @@ function normalizeGitStatus(status, node, options) {
2989
3056
  const repoRoot = readString3(status.repoRoot, status.repo_root, node.repoRoot, node.repo_root, status.workspace, node.workspace) || void 0;
2990
3057
  const submodules = readGitSubmodules(status.submodules, repoRoot);
2991
3058
  const upstreamStatus = readString3(status.upstreamStatus, status.upstream_status);
2992
- const upstreamFetchedAt = readNumber(status.upstreamFetchedAt, status.upstream_fetched_at);
3059
+ const upstreamFetchedAt2 = readNumber(status.upstreamFetchedAt, status.upstream_fetched_at);
2993
3060
  const upstreamFetchError = readString3(status.upstreamFetchError, status.upstream_fetch_error);
2994
3061
  const error = readString3(status.error);
2995
3062
  const staged = readNumber(status.staged) ?? 0;
@@ -3006,7 +3073,7 @@ function normalizeGitStatus(status, node, options) {
3006
3073
  headMessage: readString3(status.headMessage) ?? null,
3007
3074
  upstream: readString3(status.upstream) ?? null,
3008
3075
  upstreamStatus: upstreamStatus ?? "unchecked",
3009
- ...upstreamFetchedAt !== void 0 ? { upstreamFetchedAt } : {},
3076
+ ...upstreamFetchedAt2 !== void 0 ? { upstreamFetchedAt: upstreamFetchedAt2 } : {},
3010
3077
  ...upstreamFetchError ? { upstreamFetchError } : {},
3011
3078
  ahead: readNumber(status.ahead) ?? 0,
3012
3079
  behind: readNumber(status.behind) ?? 0,
@@ -4678,6 +4745,7 @@ __export(mesh_work_queue_exports, {
4678
4745
  getQueue: () => getQueue,
4679
4746
  hasPendingDependents: () => hasPendingDependents,
4680
4747
  insertDirectDispatch: () => insertDirectDispatch,
4748
+ isTaskReadonly: () => isTaskReadonly,
4681
4749
  markStaleDirectDispatches: () => markStaleDirectDispatches,
4682
4750
  nodeSatisfiesRequiredTags: () => nodeSatisfiesRequiredTags,
4683
4751
  normalizeMeshCapabilityTags: () => normalizeMeshCapabilityTags,
@@ -4694,6 +4762,10 @@ __export(mesh_work_queue_exports, {
4694
4762
  validateMeshTaskModeRequest: () => validateMeshTaskModeRequest
4695
4763
  });
4696
4764
  import { randomUUID as randomUUID6 } from "crypto";
4765
+ function isTaskReadonly(task) {
4766
+ if (!task) return false;
4767
+ return task.readonly === true || task.taskMode === "live_debug_readonly";
4768
+ }
4697
4769
  function hasNegationBefore(text, matchIndex) {
4698
4770
  const before = text.slice(0, matchIndex);
4699
4771
  const clauseStart = Math.max(
@@ -4879,13 +4951,11 @@ function normalizeMeshTaskMode(value) {
4879
4951
  const normalized = value.trim();
4880
4952
  return MESH_TASK_MODES.includes(normalized) ? normalized : void 0;
4881
4953
  }
4882
- function validateMeshTaskModeRequest(mode, message) {
4954
+ function validateMeshTaskModeRequest(mode, message, readonly) {
4883
4955
  const taskMode = normalizeMeshTaskMode(mode);
4884
- if (!taskMode) {
4885
- return { valid: true, violations: [] };
4886
- }
4887
- if (taskMode !== "live_debug_readonly") {
4888
- return { valid: true, taskMode, violations: [] };
4956
+ const isReadonly = isTaskReadonly({ readonly, taskMode });
4957
+ if (!isReadonly) {
4958
+ return taskMode ? { valid: true, taskMode, violations: [] } : { valid: true, violations: [] };
4889
4959
  }
4890
4960
  const text = message || "";
4891
4961
  const violations = LIVE_DEBUG_READONLY_FORBIDDEN.filter((rule) => patternHasRealMutation(rule.pattern, text)).map((rule) => rule.label);
@@ -5012,7 +5082,8 @@ function assertNoDependencyCycle(meshId, newTaskId, dependsOn) {
5012
5082
  }
5013
5083
  function enqueueTask(meshId, message, opts) {
5014
5084
  requireMeshHostQueueOwner(opts);
5015
- const modeValidation = validateMeshTaskModeRequest(opts?.taskMode, message);
5085
+ const readonly = opts?.readonly === true;
5086
+ const modeValidation = validateMeshTaskModeRequest(opts?.taskMode, message, readonly);
5016
5087
  if (!modeValidation.valid) {
5017
5088
  throw new Error(`live_debug_readonly_guardrail_violation: forbidden operations (${modeValidation.violations.join(", ")})`);
5018
5089
  }
@@ -5036,6 +5107,7 @@ function enqueueTask(meshId, message, opts) {
5036
5107
  message,
5037
5108
  status: "pending",
5038
5109
  taskMode: modeValidation.taskMode,
5110
+ ...readonly ? { readonly: true } : {},
5039
5111
  targetNodeId: opts?.targetNodeId,
5040
5112
  targetSessionId: opts?.targetSessionId,
5041
5113
  requiredTags: resolvedRequiredTags,
@@ -5054,7 +5126,8 @@ function recordDirectDispatchTask(meshId, message, opts) {
5054
5126
  if (!missionId) return null;
5055
5127
  const taskId = typeof opts.id === "string" ? opts.id.trim() : "";
5056
5128
  if (!taskId) return null;
5057
- const modeValidation = validateMeshTaskModeRequest(opts.taskMode, message);
5129
+ const readonly = opts.readonly === true;
5130
+ const modeValidation = validateMeshTaskModeRequest(opts.taskMode, message, readonly);
5058
5131
  if (!modeValidation.valid) {
5059
5132
  throw new Error(`live_debug_readonly_guardrail_violation: forbidden operations (${modeValidation.violations.join(", ")})`);
5060
5133
  }
@@ -5069,6 +5142,7 @@ function recordDirectDispatchTask(meshId, message, opts) {
5069
5142
  message,
5070
5143
  status: "assigned",
5071
5144
  ...modeValidation.taskMode ? { taskMode: modeValidation.taskMode } : {},
5145
+ ...readonly ? { readonly: true } : {},
5072
5146
  missionId,
5073
5147
  ...opts.assignedNodeId ? { targetNodeId: opts.assignedNodeId, assignedNodeId: opts.assignedNodeId } : {},
5074
5148
  ...opts.assignedSessionId ? { targetSessionId: opts.assignedSessionId, assignedSessionId: opts.assignedSessionId } : {},
@@ -6048,7 +6122,7 @@ var init_mesh_runtime_store = __esm({
6048
6122
  return deps.every((depId) => depStatus.get(depId) === "completed");
6049
6123
  };
6050
6124
  const nodeConflictAllows = (candidate) => {
6051
- if (candidate.taskMode === "live_debug_readonly") return true;
6125
+ if (isTaskReadonly(candidate)) return true;
6052
6126
  return !nodeBusy;
6053
6127
  };
6054
6128
  const nodeIsWorktree = opts?.nodeIsWorktree === true;
@@ -9260,7 +9334,7 @@ var init_mesh_fast_forward = __esm({
9260
9334
  "use strict";
9261
9335
  init_git_status();
9262
9336
  init_git_executor();
9263
- STATUS_OPTIONS = { refreshUpstream: true, includeSubmodules: true, timeoutMs: 15e3 };
9337
+ STATUS_OPTIONS = { refreshUpstream: true, includeSubmodules: true, timeoutMs: 15e3, forceFresh: true };
9264
9338
  }
9265
9339
  });
9266
9340
 
@@ -9660,9 +9734,6 @@ var mesh_scheduling_runtime_exports = {};
9660
9734
  __export(mesh_scheduling_runtime_exports, {
9661
9735
  buildMeshSchedulingRuntime: () => buildMeshSchedulingRuntime
9662
9736
  });
9663
- function isReadonly(task) {
9664
- return task.taskMode === "live_debug_readonly";
9665
- }
9666
9737
  function isAssigned(task) {
9667
9738
  return task.status === "assigned";
9668
9739
  }
@@ -9671,8 +9742,8 @@ function buildMeshSchedulingRuntime(mesh, queue) {
9671
9742
  const maxParallelTasks = resolveMaxParallelTasks(mesh?.policy?.maxParallelTasks);
9672
9743
  const maxReadonlyParallelTasks = resolveMaxReadonlyParallelTasks(maxParallelTasks);
9673
9744
  const assignedTasks = (Array.isArray(queue) ? queue : []).filter(isAssigned);
9674
- const activeWriteAssigned = assignedTasks.filter((t) => !isReadonly(t)).length;
9675
- const activeReadonlyAssigned = assignedTasks.filter(isReadonly).length;
9745
+ const activeWriteAssigned = assignedTasks.filter((t) => !isTaskReadonly(t)).length;
9746
+ const activeReadonlyAssigned = assignedTasks.filter(isTaskReadonly).length;
9676
9747
  const globalWriteCapReached = activeWriteAssigned >= maxParallelTasks;
9677
9748
  const globalReadonlyCapReached = activeReadonlyAssigned >= maxReadonlyParallelTasks;
9678
9749
  const writeAssignedByNode = /* @__PURE__ */ new Map();
@@ -9682,7 +9753,7 @@ function buildMeshSchedulingRuntime(mesh, queue) {
9682
9753
  const nodeId = typeof task.assignedNodeId === "string" ? task.assignedNodeId.trim() : "";
9683
9754
  if (!nodeId) continue;
9684
9755
  assignedByNode.set(nodeId, (assignedByNode.get(nodeId) ?? 0) + 1);
9685
- if (!isReadonly(task)) {
9756
+ if (!isTaskReadonly(task)) {
9686
9757
  writeAssignedByNode.set(nodeId, (writeAssignedByNode.get(nodeId) ?? 0) + 1);
9687
9758
  }
9688
9759
  const provider = typeof task.assignedProviderType === "string" ? task.assignedProviderType : "";
@@ -9755,6 +9826,7 @@ var init_mesh_scheduling_runtime = __esm({
9755
9826
  "use strict";
9756
9827
  init_repo_mesh_types();
9757
9828
  init_dist();
9829
+ init_mesh_work_queue();
9758
9830
  }
9759
9831
  });
9760
9832
 
@@ -12157,10 +12229,10 @@ function resolveAutoLaunchTarget(components, node) {
12157
12229
  return { mode: "remote", daemonId, coordinatorDaemonId };
12158
12230
  }
12159
12231
  function activeWriteAssignedCount(meshId) {
12160
- return getQueue(meshId, { status: ["assigned"] }).filter((task) => task.taskMode !== "live_debug_readonly").length;
12232
+ return getQueue(meshId, { status: ["assigned"] }).filter((task) => !isTaskReadonly(task)).length;
12161
12233
  }
12162
12234
  function activeReadonlyAssignedCount(meshId) {
12163
- return getQueue(meshId, { status: ["assigned"] }).filter((task) => task.taskMode === "live_debug_readonly").length;
12235
+ return getQueue(meshId, { status: ["assigned"] }).filter(isTaskReadonly).length;
12164
12236
  }
12165
12237
  function nodeHasActiveAssignment(meshId, nodeId) {
12166
12238
  return getQueue(meshId, { status: ["assigned"] }).some((task) => task.assignedNodeId === nodeId);
@@ -12336,8 +12408,8 @@ async function maybeAutoLaunchOneQueueSession(components, meshId, mesh) {
12336
12408
  );
12337
12409
  const maxReadonlyParallelTasks = resolveMaxReadonlyParallelTasks(maxParallelTasks, schedulingOverride?.readonlyMultiplier);
12338
12410
  for (const task of pending) {
12339
- const isReadonly2 = task.taskMode === "live_debug_readonly";
12340
- if (isReadonly2) {
12411
+ const isReadonly = isTaskReadonly(task);
12412
+ if (isReadonly) {
12341
12413
  if (activeReadonlyAssignedCount(meshId) >= maxReadonlyParallelTasks) {
12342
12414
  markAutoLaunch(meshId, task.id, { status: "skipped", reason: "max_readonly_parallel_tasks_reached" });
12343
12415
  continue;
@@ -12419,7 +12491,7 @@ async function maybeAutoLaunchOneQueueSession(components, meshId, mesh) {
12419
12491
  sweepExpiredCooldowns();
12420
12492
  continue;
12421
12493
  }
12422
- if (task.taskMode !== "live_debug_readonly" && nodeHasActiveAssignment(meshId, nodeId)) {
12494
+ if (!isTaskReadonly(task) && nodeHasActiveAssignment(meshId, nodeId)) {
12423
12495
  markAutoLaunch(meshId, task.id, { status: "skipped", reason: "node_has_active_assignment", nodeId });
12424
12496
  continue;
12425
12497
  }
@@ -13166,6 +13238,9 @@ function isModuleNotFoundError(error, ref) {
13166
13238
  const code = "code" in error ? error.code : void 0;
13167
13239
  return code === "MODULE_NOT_FOUND" && message.includes(ref);
13168
13240
  }
13241
+ function runtimeTriplet() {
13242
+ return `${process.platform}-${process.arch}-node${process.versions.modules}`;
13243
+ }
13169
13244
  function normalizeBinding(mod, ref) {
13170
13245
  const binding = mod?.default?.createTerminal ? mod.default : mod?.createTerminal ? mod : null;
13171
13246
  if (!binding) {
@@ -13200,7 +13275,7 @@ function loadGhosttyVtBinding() {
13200
13275
  }
13201
13276
  cachedBinding = null;
13202
13277
  cachedBindingError = new Error(
13203
- `ghostty-vt binding unavailable (${errors.join("; ") || "no candidates tried"})`
13278
+ `ghostty-vt binding unavailable for runtime ${runtimeTriplet()} (${errors.join("; ") || "no candidates tried"})`
13204
13279
  );
13205
13280
  throw cachedBindingError;
13206
13281
  }
@@ -16374,11 +16449,8 @@ function resolveTunedReconcileMs(envName, def, min, max) {
16374
16449
  }
16375
16450
  return def;
16376
16451
  }
16377
- function resolveMinIdleSettleMs() {
16378
- return resolveTunedReconcileMs("MESH_INFLIGHT_MIN_IDLE_SETTLE_MS", 16e3, 0, 12e4);
16379
- }
16380
- function resolveAckedTurnSettleMs() {
16381
- return resolveTunedReconcileMs("MESH_INFLIGHT_ACKED_TURN_SETTLE_MS", 2e4, 0, 18e4);
16452
+ function resolveAckedDeathDeadlineMs() {
16453
+ return resolveTunedReconcileMs("MESH_INFLIGHT_ACKED_DEATH_DEADLINE_MS", 8 * 6e4, 0, 60 * 6e4);
16382
16454
  }
16383
16455
  function inFlightSynthKey(meshId, taskId) {
16384
16456
  return `${meshId}::${taskId}`;
@@ -16989,9 +17061,9 @@ async function reconcileUnterminatedDirectDispatches(components, mesh, selfIds,
16989
17061
  const activeTaskKeys = new Set(
16990
17062
  dispatches.map((d) => readNonEmptyString2(d.taskId)).filter(Boolean).map((taskId) => inFlightSynthKey(mesh.id, taskId))
16991
17063
  );
16992
- for (const key of inFlightIdleObservationCounts.keys()) {
17064
+ for (const key of inFlightAckedHoldState.keys()) {
16993
17065
  if (key.startsWith(`${mesh.id}::`) && !activeTaskKeys.has(key)) {
16994
- inFlightIdleObservationCounts.delete(key);
17066
+ inFlightAckedHoldState.delete(key);
16995
17067
  }
16996
17068
  }
16997
17069
  const dispatchMeshCommand = components.dispatchMeshCommand;
@@ -17012,49 +17084,61 @@ async function reconcileUnterminatedDirectDispatches(components, mesh, selfIds,
17012
17084
  ...node?.workspace ? { workspace: node.workspace } : {},
17013
17085
  ...providerType ? { agentType: providerType, providerType } : {}
17014
17086
  };
17087
+ const synthKey = inFlightSynthKey(mesh.id, taskId);
17088
+ const isAcked = dispatch.status === "acked";
17015
17089
  let payload = null;
17090
+ let readFailed = false;
17016
17091
  try {
17017
17092
  if (isLocalNode) {
17018
17093
  const result = await components.commandHandler.handle("read_chat", readArgs);
17019
- if (result && result.success === false) continue;
17020
- payload = unwrapReadChatPayload(result);
17094
+ if (result && result.success === false) {
17095
+ readFailed = true;
17096
+ } else {
17097
+ payload = unwrapReadChatPayload(result);
17098
+ }
17021
17099
  } else if (dispatchMeshCommand) {
17022
17100
  const result = await dispatchMeshCommand(nodeDaemonId, "read_chat", readArgs);
17023
17101
  payload = unwrapReadChatPayload(result);
17024
- if (payload && payload.success === false) continue;
17102
+ if (payload && payload.success === false) {
17103
+ payload = null;
17104
+ readFailed = true;
17105
+ }
17025
17106
  } else {
17026
17107
  continue;
17027
17108
  }
17028
17109
  } catch {
17110
+ readFailed = true;
17111
+ }
17112
+ if (!payload && !readFailed) continue;
17113
+ if (readFailed || !payload) {
17114
+ if (isAcked) {
17115
+ const prior = inFlightAckedHoldState.get(synthKey);
17116
+ const failures = (prior?.consecutiveReadFailures ?? 0) + 1;
17117
+ const liveConfirmedSinceAck = prior?.liveConfirmedSinceAck ?? false;
17118
+ inFlightAckedHoldState.set(synthKey, { liveConfirmedSinceAck, consecutiveReadFailures: failures });
17119
+ if (liveConfirmedSinceAck && failures >= ACKED_DEATH_CONSECUTIVE_READ_FAILURES) {
17120
+ LOG.warn("MeshReconcile", `Acked-hold death signal: task ${taskId} on node ${nodeId} (mesh ${mesh.id}) read_chat failed ${failures}x consecutively after a live-confirmed ack \u2014 worker session presumed gone mid-turn; releasing the indefinite synth hold to the stranded-reclaim / orphan-prune nets`);
17121
+ }
17122
+ }
17029
17123
  continue;
17030
17124
  }
17031
- if (!payload) continue;
17032
- const synthKey = inFlightSynthKey(mesh.id, taskId);
17125
+ inFlightAckedHoldState.set(synthKey, { liveConfirmedSinceAck: true, consecutiveReadFailures: 0 });
17033
17126
  const nowMs = Date.now();
17034
17127
  if (readChatPayloadStatus(payload) !== "idle") {
17035
- inFlightIdleObservationCounts.delete(synthKey);
17036
17128
  continue;
17037
17129
  }
17038
- if (dispatch.status === "acked") {
17039
- const prior = inFlightIdleObservationCounts.get(synthKey);
17040
- const firstIdleAtMs = prior?.firstIdleAtMs ?? nowMs;
17041
- const idleStreak = (prior?.count ?? 0) + 1;
17042
- inFlightIdleObservationCounts.set(synthKey, { count: idleStreak, firstIdleAtMs });
17043
- const idleSettleMs = nowMs - firstIdleAtMs;
17044
- const minIdleSettleMs = resolveMinIdleSettleMs();
17045
- const ackedTurnSettleMs = resolveAckedTurnSettleMs();
17130
+ if (isAcked) {
17046
17131
  const ackedAtMs = Date.parse(readNonEmptyString2(dispatch.updatedAt));
17047
17132
  const sinceAckMs = Number.isFinite(ackedAtMs) ? nowMs - ackedAtMs : Number.POSITIVE_INFINITY;
17048
- const tickGuardMet = idleStreak >= REQUIRED_CONSECUTIVE_IDLE_TICKS_FOR_INFLIGHT_SYNTH;
17049
- const settleGuardMet = idleSettleMs >= minIdleSettleMs;
17050
- const ackGuardMet = sinceAckMs >= ackedTurnSettleMs;
17051
- if (!tickGuardMet || !settleGuardMet || !ackGuardMet) {
17052
- LOG.info("MeshReconcile", `In-flight synth hold: task ${taskId} on node ${nodeId} (mesh ${mesh.id}) idle ${idleStreak}/${REQUIRED_CONSECUTIVE_IDLE_TICKS_FOR_INFLIGHT_SYNTH} tick(s), settle ${Math.round(idleSettleMs / 1e3)}s/${Math.round(minIdleSettleMs / 1e3)}s, since-ack ${Number.isFinite(sinceAckMs) ? Math.round(sinceAckMs / 1e3) + "s" : "\u221E"}/${Math.round(ackedTurnSettleMs / 1e3)}s \u2014 deferring completion synth until the worker's turn genuinely settles (guards against a mid-turn idle window pre-empting the real completion)`);
17133
+ const deathDeadlineMs = resolveAckedDeathDeadlineMs();
17134
+ if (sinceAckMs < deathDeadlineMs) {
17135
+ LOG.info("MeshReconcile", `Acked-hold: task ${taskId} on node ${nodeId} (mesh ${mesh.id}) read idle ${Number.isFinite(sinceAckMs) ? Math.round(sinceAckMs / 1e3) + "s" : "\u221E"} since the generating_started ack \u2014 HOLDING synth indefinitely (worker is alive and will emit; a later real emit is idempotent). Death backstop fires at ${Math.round(deathDeadlineMs / 1e3)}s or on consecutive read failures.`);
17053
17136
  continue;
17054
17137
  }
17138
+ LOG.warn("MeshReconcile", `Acked-hold death deadline reached: task ${taskId} on node ${nodeId} (mesh ${mesh.id}) still idle ${Math.round(sinceAckMs / 1e3)}s after the ack (deadline ${Math.round(deathDeadlineMs / 1e3)}s) \u2014 synthesizing the missing completion as a notification-loss net (a real emit, if it ever lands, no-ops idempotently).`);
17055
17139
  }
17056
17140
  if (realTerminalEmitPendingForTask(mesh.id, taskId)) {
17057
- inFlightIdleObservationCounts.delete(synthKey);
17141
+ inFlightAckedHoldState.delete(synthKey);
17058
17142
  LOG.info("MeshReconcile", `Worker-emit priority: task ${taskId} on node ${nodeId} (mesh ${mesh.id}) has a real terminal completion already queued \u2014 yielding synth to the worker's own emit`);
17059
17143
  continue;
17060
17144
  }
@@ -17076,7 +17160,7 @@ async function reconcileUnterminatedDirectDispatches(components, mesh, selfIds,
17076
17160
  }
17077
17161
  const reprobeStatus = await reprobeWorkerStatus(components, { isLocalNode, nodeDaemonId, readArgs });
17078
17162
  if (reprobeStatus && reprobeStatus !== "idle") {
17079
- inFlightIdleObservationCounts.delete(synthKey);
17163
+ inFlightAckedHoldState.delete(synthKey);
17080
17164
  LOG.info("MeshReconcile", `Live re-probe defer: task ${taskId} on node ${nodeId} (mesh ${mesh.id}) read '${reprobeStatus}' at synth-commit time \u2014 worker resumed generating; deferring synth to a later tick`);
17081
17165
  continue;
17082
17166
  }
@@ -17218,7 +17302,7 @@ function setupMeshReconcileLoop(components) {
17218
17302
  }
17219
17303
  };
17220
17304
  }
17221
- var DEFAULT_RECONCILE_INTERVAL_MS, DEFAULT_AUTO_PRUNE_MIN_AGE_MS, REQUIRED_CONSECUTIVE_IDLE_TICKS_FOR_INFLIGHT_SYNTH, inFlightIdleObservationCounts, coordinatorModalParkState, heldEventLedgerRecorded, ASSIGNED_STRANDED_DEADLINE_MS, STRICT_SESSION_MATCH_TTL_MS, unresolvedForwardRejectionCounts, MAX_FORWARD_REJECTIONS;
17305
+ var DEFAULT_RECONCILE_INTERVAL_MS, DEFAULT_AUTO_PRUNE_MIN_AGE_MS, ACKED_DEATH_CONSECUTIVE_READ_FAILURES, inFlightAckedHoldState, coordinatorModalParkState, heldEventLedgerRecorded, ASSIGNED_STRANDED_DEADLINE_MS, STRICT_SESSION_MATCH_TTL_MS, unresolvedForwardRejectionCounts, MAX_FORWARD_REJECTIONS;
17222
17306
  var init_mesh_reconcile_loop = __esm({
17223
17307
  "src/mesh/mesh-reconcile-loop.ts"() {
17224
17308
  "use strict";
@@ -17240,8 +17324,8 @@ var init_mesh_reconcile_loop = __esm({
17240
17324
  init_chat_message_normalization();
17241
17325
  DEFAULT_RECONCILE_INTERVAL_MS = 4e3;
17242
17326
  DEFAULT_AUTO_PRUNE_MIN_AGE_MS = 24 * 60 * 6e4;
17243
- REQUIRED_CONSECUTIVE_IDLE_TICKS_FOR_INFLIGHT_SYNTH = 2;
17244
- inFlightIdleObservationCounts = /* @__PURE__ */ new Map();
17327
+ ACKED_DEATH_CONSECUTIVE_READ_FAILURES = 3;
17328
+ inFlightAckedHoldState = /* @__PURE__ */ new Map();
17245
17329
  coordinatorModalParkState = /* @__PURE__ */ new Map();
17246
17330
  heldEventLedgerRecorded = /* @__PURE__ */ new Set();
17247
17331
  ASSIGNED_STRANDED_DEADLINE_MS = 5 * 6e4;
@@ -23848,7 +23932,7 @@ function validateMutatingMessage(value) {
23848
23932
  async function gitCheckpoint(workspace, message, includeUntracked) {
23849
23933
  const repo = await resolveGitRepository(workspace);
23850
23934
  const repoRoot = repo.repoRoot;
23851
- const statusResult = await getGitRepoStatus(workspace);
23935
+ const statusResult = await getGitRepoStatus(workspace, { forceFresh: true });
23852
23936
  if (statusResult.hasConflicts) {
23853
23937
  throw new GitCommandError("conflict", "Repository has conflicts \u2014 resolve before checkpointing");
23854
23938
  }
@@ -52649,7 +52733,10 @@ async function alignRefinerySubmodulesAfterMerge(repoRoot, previousBaseHead, cur
52649
52733
  const preStatus = await getGitRepoStatus(repoRoot, {
52650
52734
  includeSubmodules: true,
52651
52735
  submoduleIgnorePaths: options.submoduleIgnorePaths,
52652
- timeoutMs: 15e3
52736
+ timeoutMs: 15e3,
52737
+ // Decision path — the out-of-sync submodule set drives a mutating `submodule
52738
+ // update`. Must not act on a TTL-cached status; bypass the C1 cache.
52739
+ forceFresh: true
52653
52740
  });
52654
52741
  const outOfSyncPaths = (preStatus.submodules || []).filter((submodule) => submodule.dirty || submodule.outOfSync || !!submodule.error).map((submodule) => submodule.path);
52655
52742
  const updatePaths = [.../* @__PURE__ */ new Set([...changedGitlinkPaths, ...outOfSyncPaths])].sort();
@@ -52678,7 +52765,10 @@ async function alignRefinerySubmodulesAfterMerge(repoRoot, previousBaseHead, cur
52678
52765
  const postStatus = await getGitRepoStatus(repoRoot, {
52679
52766
  includeSubmodules: true,
52680
52767
  submoduleIgnorePaths: options.submoduleIgnorePaths,
52681
- timeoutMs: 15e3
52768
+ timeoutMs: 15e3,
52769
+ // Re-read AFTER `submodule update` mutated the tree — MUST be fresh, never the
52770
+ // cached preStatus from moments ago (which would falsely report still-dirty).
52771
+ forceFresh: true
52682
52772
  });
52683
52773
  const remaining = (postStatus.submodules || []).filter((submodule) => updatePaths.includes(submodule.path) && (submodule.dirty || submodule.outOfSync || !!submodule.error));
52684
52774
  return {
@@ -64133,6 +64223,7 @@ export {
64133
64223
  isSessionHostLiveRuntime,
64134
64224
  isSessionHostRecoverySnapshot,
64135
64225
  isSetupComplete,
64226
+ isTaskReadonly,
64136
64227
  isUserFacingChatMessage,
64137
64228
  killIdeProcess,
64138
64229
  launchIDE,