@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.js CHANGED
@@ -399,10 +399,10 @@ function readInjected(value) {
399
399
  }
400
400
  function getDaemonBuildInfo() {
401
401
  if (cached) return cached;
402
- const commit = readInjected(true ? "bfd7d9b1d38a7d1f4709fbad2627c56b5a1ae342" : void 0) ?? "unknown";
403
- const commitShort = readInjected(true ? "bfd7d9b1" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
404
- const version = readInjected(true ? "0.9.82-rc.407" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
405
- const builtAt = readInjected(true ? "2026-06-28T06:12:15.473Z" : void 0);
402
+ const commit = readInjected(true ? "b6de7b335f9b6b6bfb202135c2ae017429182efa" : void 0) ?? "unknown";
403
+ const commitShort = readInjected(true ? "b6de7b33" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
404
+ const version = readInjected(true ? "0.9.82-rc.408" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
405
+ const builtAt = readInjected(true ? "2026-06-28T07:53:15.742Z" : void 0);
406
406
  cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
407
407
  return cached;
408
408
  }
@@ -655,6 +655,11 @@ var init_change_impact_config = __esm({
655
655
  });
656
656
 
657
657
  // src/git/git-status.ts
658
+ function statusCacheKey(workspace, options) {
659
+ const includeSubmodules = options.includeSubmodules !== false;
660
+ const refreshUpstream = options.refreshUpstream === true;
661
+ return `${workspace}\0sub=${includeSubmodules ? 1 : 0}\0up=${refreshUpstream ? 1 : 0}`;
662
+ }
658
663
  function isTransientGitFailure(error) {
659
664
  return error.reason === "timeout" || error.reason === "git_command_failed";
660
665
  }
@@ -662,15 +667,22 @@ async function getGitRepoStatus(workspace, options = {}) {
662
667
  const lastCheckedAt = Date.now();
663
668
  const includeSubmodules = options.includeSubmodules !== false;
664
669
  const effectiveOptions = options.timeoutMs === void 0 ? { ...options, timeoutMs: GIT_STATUS_TIMEOUT_MS } : options;
670
+ const cacheKey = statusCacheKey(workspace, options);
671
+ if (!options.forceFresh) {
672
+ const cached3 = lastKnownGoodStatus.get(cacheKey);
673
+ if (cached3 && lastCheckedAt - cached3.cachedAt < GIT_STATUS_CACHE_TTL_MS) {
674
+ return cached3.status;
675
+ }
676
+ }
665
677
  try {
666
678
  const repo = await resolveGitRepository(workspace, effectiveOptions);
667
679
  const status = await collectGitRepoStatus(repo, includeSubmodules, lastCheckedAt, effectiveOptions);
668
- lastKnownGoodStatus.set(workspace, status);
680
+ lastKnownGoodStatus.set(cacheKey, { status, cachedAt: lastCheckedAt });
669
681
  return status;
670
682
  } catch (error) {
671
683
  const gitError = error instanceof GitCommandError ? error : new GitCommandError("git_command_failed", "Failed to read Git status", { cause: error });
672
684
  if (isTransientGitFailure(gitError)) {
673
- const cached3 = lastKnownGoodStatus.get(workspace);
685
+ const cached3 = lastKnownGoodStatus.get(cacheKey)?.status;
674
686
  if (cached3) {
675
687
  return {
676
688
  ...cached3,
@@ -689,19 +701,25 @@ async function collectGitRepoStatus(repo, includeSubmodules, lastCheckedAt, opti
689
701
  let upstreamProbe = getInitialUpstreamProbe(parsed);
690
702
  if (options.refreshUpstream) {
691
703
  upstreamProbe = await refreshTrackedUpstream(repo, parsed, options);
692
- if (upstreamProbe.upstreamStatus === "fresh") {
704
+ if (upstreamProbe.upstreamStatus === "fresh" && upstreamProbe.didFetch) {
693
705
  parsed = await readPorcelainStatus(repo, options);
694
706
  }
695
707
  }
696
708
  const head = await readHead(repo, options);
697
709
  const stashCount = await readStashCount(repo, options);
698
710
  let submodules;
711
+ let submoduleHeadOids = /* @__PURE__ */ new Map();
699
712
  if (includeSubmodules) {
700
- submodules = await getSubmoduleStatuses(repo, options);
713
+ const subResult = await getSubmoduleStatuses(repo, options);
714
+ submodules = subResult.submodules;
715
+ submoduleHeadOids = subResult.headOidByPath;
701
716
  }
702
717
  const submoduleDirty = (submodules || []).some((submodule) => submodule.dirty || submodule.outOfSync || !!submodule.error);
703
718
  const dirty = parsed.staged + parsed.modified + parsed.untracked + parsed.deleted + parsed.renamed > 0 || parsed.conflictFiles.length > 0 || stashCount > 0 || submoduleDirty;
704
- const daemonBuildBehind = await detectDaemonBuildBehind(repo, submodules, options);
719
+ const daemonBuildBehind = await detectDaemonBuildBehind(repo, submodules, options, {
720
+ rootHeadOid: parsed.headOid,
721
+ submoduleHeadOids
722
+ });
705
723
  return {
706
724
  workspace: repo.workspace,
707
725
  repoRoot: repo.repoRoot,
@@ -804,25 +822,50 @@ function resolveChangeImpactConfigForRepo(repoRoot, options) {
804
822
  changeImpactConfigCache.set(repoRoot, { sourceKey: loaded.sourceKey, config });
805
823
  return { config, sourceKey: loaded.sourceKey };
806
824
  }
807
- async function detectDaemonBuildBehind(repo, submodules, options) {
825
+ async function detectDaemonBuildBehind(repo, submodules, options, headOids = { rootHeadOid: null, submoduleHeadOids: /* @__PURE__ */ new Map() }) {
808
826
  const build = options.daemonBuildInfo ?? getDaemonBuildInfo();
809
827
  if (!build.commit || build.commit === "unknown") return void 0;
810
828
  const { config, sourceKey: configKey } = resolveChangeImpactConfigForRepo(repo.repoRoot, options);
811
829
  const policy = resolveChangeImpactPolicy(config);
812
830
  const scopes = [
813
- { scope: "root", repoPath: repo.repoRoot || repo.workspace }
831
+ { scope: "root", repoPath: repo.repoRoot || repo.workspace, knownHeadOid: headOids.rootHeadOid }
814
832
  ];
815
833
  for (const sub of submodules || []) {
816
- if (sub.repoPath && !sub.error) scopes.push({ scope: sub.path, repoPath: sub.repoPath });
834
+ if (sub.repoPath && !sub.error) {
835
+ scopes.push({ scope: sub.path, repoPath: sub.repoPath, knownHeadOid: headOids.submoduleHeadOids.get(sub.path) ?? null });
836
+ }
817
837
  }
818
- for (const { scope, repoPath } of scopes) {
838
+ for (const { scope, repoPath, knownHeadOid } of scopes) {
819
839
  try {
820
- await runGit(repoPath, ["cat-file", "-e", `${build.commit}^{commit}`], options);
821
- const headResult = await runGit(repoPath, ["rev-parse", "HEAD"], options);
822
- const head = headResult.stdout.trim();
823
- if (!head || head === build.commit) continue;
824
- await runGit(repoPath, ["merge-base", "--is-ancestor", build.commit, "HEAD"], options);
840
+ let head = knownHeadOid;
841
+ const ancestryKey = head ? `${repoPath}::${build.commit}::${head}` : null;
842
+ if (ancestryKey) {
843
+ const cachedVerdict = buildBehindAncestryCache.get(ancestryKey);
844
+ if (cachedVerdict === false) continue;
845
+ if (cachedVerdict === void 0) {
846
+ if (head === build.commit) {
847
+ buildBehindAncestryCache.set(ancestryKey, false);
848
+ continue;
849
+ }
850
+ await runGit(repoPath, ["cat-file", "-e", `${build.commit}^{commit}`], options);
851
+ try {
852
+ await runGit(repoPath, ["merge-base", "--is-ancestor", build.commit, "HEAD"], options);
853
+ } catch {
854
+ buildBehindAncestryCache.set(ancestryKey, false);
855
+ continue;
856
+ }
857
+ buildBehindAncestryCache.set(ancestryKey, true);
858
+ }
859
+ } else {
860
+ await runGit(repoPath, ["cat-file", "-e", `${build.commit}^{commit}`], options);
861
+ const headResult = await runGit(repoPath, ["rev-parse", "HEAD"], options);
862
+ head = headResult.stdout.trim();
863
+ if (!head || head === build.commit) continue;
864
+ await runGit(repoPath, ["merge-base", "--is-ancestor", build.commit, "HEAD"], options);
865
+ buildBehindAncestryCache.set(`${repoPath}::${build.commit}::${head}`, true);
866
+ }
825
867
  const evalKey = `${repoPath}\0${build.commit}\0${head}\0${configKey}`;
868
+ if (!head) continue;
826
869
  let evaluated = changeImpactEvalCache.get(evalKey);
827
870
  if (!evaluated) {
828
871
  evaluated = await classifyDaemonBuildChange(repoPath, build.commit, options, policy);
@@ -864,6 +907,15 @@ async function refreshTrackedUpstream(repo, parsed, options) {
864
907
  if (!parsed.upstream || !parsed.branch) {
865
908
  return { upstreamStatus: "no_upstream" };
866
909
  }
910
+ const now = Date.now();
911
+ const lastFetch = upstreamFetchedAt.get(repo.workspace);
912
+ if (!options.forceFresh && lastFetch !== void 0 && now - lastFetch < GIT_FETCH_THROTTLE_MS) {
913
+ return {
914
+ upstreamStatus: "fresh",
915
+ upstreamFetchedAt: lastFetch,
916
+ didFetch: false
917
+ };
918
+ }
867
919
  const remoteName = await readBranchRemote(repo, parsed.branch, options) ?? inferRemoteName(parsed.upstream);
868
920
  if (!remoteName) {
869
921
  return {
@@ -873,9 +925,12 @@ async function refreshTrackedUpstream(repo, parsed, options) {
873
925
  }
874
926
  try {
875
927
  await runGit(repo, ["fetch", "--quiet", "--prune", "--no-tags", remoteName], options);
928
+ const fetchedAt = Date.now();
929
+ upstreamFetchedAt.set(repo.workspace, fetchedAt);
876
930
  return {
877
931
  upstreamStatus: "fresh",
878
- upstreamFetchedAt: Date.now()
932
+ upstreamFetchedAt: fetchedAt,
933
+ didFetch: true
879
934
  };
880
935
  } catch (error) {
881
936
  return {
@@ -908,6 +963,7 @@ function formatGitError(error) {
908
963
  function parsePorcelainV2Status(output) {
909
964
  const parsed = {
910
965
  branch: null,
966
+ headOid: null,
911
967
  upstream: null,
912
968
  ahead: 0,
913
969
  behind: 0,
@@ -920,6 +976,11 @@ function parsePorcelainV2Status(output) {
920
976
  };
921
977
  for (const line of output.split("\n")) {
922
978
  if (!line) continue;
979
+ if (line.startsWith("# branch.oid ")) {
980
+ const oid = line.slice("# branch.oid ".length).trim();
981
+ parsed.headOid = oid && oid !== "(initial)" && /^[0-9a-f]{7,64}$/.test(oid) ? oid : null;
982
+ continue;
983
+ }
923
984
  if (line.startsWith("# branch.head ")) {
924
985
  const branch = line.slice("# branch.head ".length).trim();
925
986
  parsed.branch = branch && branch !== "(detached)" ? branch : null;
@@ -1017,25 +1078,27 @@ function emptyStatus(workspace, lastCheckedAt, error) {
1017
1078
  };
1018
1079
  }
1019
1080
  async function getSubmoduleStatuses(repo, options) {
1020
- if (!repo.repoRoot) return [];
1081
+ if (!repo.repoRoot) return { submodules: [], headOidByPath: /* @__PURE__ */ new Map() };
1021
1082
  try {
1022
- const submodules = await deriveSubmoduleGitlinkStatuses(repo, options);
1083
+ const { submodules, headOidByPath } = await deriveSubmoduleGitlinkStatuses(repo, options);
1023
1084
  await Promise.all(submodules.map((submodule) => enrichSubmoduleWorktreeStatus(repo, submodule, options)));
1024
- return submodules;
1085
+ return { submodules, headOidByPath };
1025
1086
  } catch {
1026
- return [];
1087
+ return { submodules: [], headOidByPath: /* @__PURE__ */ new Map() };
1027
1088
  }
1028
1089
  }
1029
1090
  async function deriveSubmoduleGitlinkStatuses(repo, options) {
1030
- if (!repo.repoRoot) return [];
1091
+ if (!repo.repoRoot) return { submodules: [], headOidByPath: /* @__PURE__ */ new Map() };
1031
1092
  const paths = await readSubmodulePaths(repo, options);
1032
1093
  const ignoreSet = new Set(options.submoduleIgnorePaths || []);
1033
1094
  const lastCheckedAt = Date.now();
1095
+ const headOidByPath = /* @__PURE__ */ new Map();
1034
1096
  const entries = await Promise.all(
1035
1097
  paths.filter((path43) => !ignoreSet.has(path43)).map(async (path43) => {
1036
1098
  const repoPath = repo.repoRoot + "/" + path43;
1037
1099
  const expected = await readGitlinkExpectedSha(repo, path43, options);
1038
1100
  const actual = await readSubmoduleHeadSha(repo, repoPath, options);
1101
+ if (actual) headOidByPath.set(path43, actual);
1039
1102
  const outOfSync = actual === null ? true : expected !== null && expected !== actual;
1040
1103
  return {
1041
1104
  path: path43,
@@ -1049,7 +1112,7 @@ async function deriveSubmoduleGitlinkStatuses(repo, options) {
1049
1112
  };
1050
1113
  })
1051
1114
  );
1052
- return entries;
1115
+ return { submodules: entries, headOidByPath };
1053
1116
  }
1054
1117
  async function readSubmodulePaths(repo, options) {
1055
1118
  if (!repo.repoRoot) return [];
@@ -1106,16 +1169,20 @@ async function enrichSubmoduleWorktreeStatus(repo, submodule, options) {
1106
1169
  submodule.error = formatGitError(error);
1107
1170
  }
1108
1171
  }
1109
- var lastKnownGoodStatus, changeImpactEvalCache, changeImpactConfigCache, DEFAULT_DAEMON_RUNTIME_PACKAGES, DEFAULT_WEB_ONLY_PACKAGES, DEFAULT_IMPACT_TARGETS;
1172
+ 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;
1110
1173
  var init_git_status = __esm({
1111
1174
  "src/git/git-status.ts"() {
1112
1175
  "use strict";
1113
1176
  init_git_executor();
1114
1177
  init_build_info();
1115
1178
  init_change_impact_config();
1179
+ GIT_STATUS_CACHE_TTL_MS = 1500;
1116
1180
  lastKnownGoodStatus = /* @__PURE__ */ new Map();
1117
1181
  changeImpactEvalCache = /* @__PURE__ */ new Map();
1118
1182
  changeImpactConfigCache = /* @__PURE__ */ new Map();
1183
+ buildBehindAncestryCache = /* @__PURE__ */ new Map();
1184
+ GIT_FETCH_THROTTLE_MS = 3e4;
1185
+ upstreamFetchedAt = /* @__PURE__ */ new Map();
1119
1186
  DEFAULT_DAEMON_RUNTIME_PACKAGES = [
1120
1187
  "daemon-core",
1121
1188
  "daemon-standalone",
@@ -2995,7 +3062,7 @@ function normalizeGitStatus(status, node, options) {
2995
3062
  const repoRoot = readString3(status.repoRoot, status.repo_root, node.repoRoot, node.repo_root, status.workspace, node.workspace) || void 0;
2996
3063
  const submodules = readGitSubmodules(status.submodules, repoRoot);
2997
3064
  const upstreamStatus = readString3(status.upstreamStatus, status.upstream_status);
2998
- const upstreamFetchedAt = readNumber(status.upstreamFetchedAt, status.upstream_fetched_at);
3065
+ const upstreamFetchedAt2 = readNumber(status.upstreamFetchedAt, status.upstream_fetched_at);
2999
3066
  const upstreamFetchError = readString3(status.upstreamFetchError, status.upstream_fetch_error);
3000
3067
  const error = readString3(status.error);
3001
3068
  const staged = readNumber(status.staged) ?? 0;
@@ -3012,7 +3079,7 @@ function normalizeGitStatus(status, node, options) {
3012
3079
  headMessage: readString3(status.headMessage) ?? null,
3013
3080
  upstream: readString3(status.upstream) ?? null,
3014
3081
  upstreamStatus: upstreamStatus ?? "unchecked",
3015
- ...upstreamFetchedAt !== void 0 ? { upstreamFetchedAt } : {},
3082
+ ...upstreamFetchedAt2 !== void 0 ? { upstreamFetchedAt: upstreamFetchedAt2 } : {},
3016
3083
  ...upstreamFetchError ? { upstreamFetchError } : {},
3017
3084
  ahead: readNumber(status.ahead) ?? 0,
3018
3085
  behind: readNumber(status.behind) ?? 0,
@@ -4685,6 +4752,7 @@ __export(mesh_work_queue_exports, {
4685
4752
  getQueue: () => getQueue,
4686
4753
  hasPendingDependents: () => hasPendingDependents,
4687
4754
  insertDirectDispatch: () => insertDirectDispatch,
4755
+ isTaskReadonly: () => isTaskReadonly,
4688
4756
  markStaleDirectDispatches: () => markStaleDirectDispatches,
4689
4757
  nodeSatisfiesRequiredTags: () => nodeSatisfiesRequiredTags,
4690
4758
  normalizeMeshCapabilityTags: () => normalizeMeshCapabilityTags,
@@ -4700,6 +4768,10 @@ __export(mesh_work_queue_exports, {
4700
4768
  updateTaskStatus: () => updateTaskStatus,
4701
4769
  validateMeshTaskModeRequest: () => validateMeshTaskModeRequest
4702
4770
  });
4771
+ function isTaskReadonly(task) {
4772
+ if (!task) return false;
4773
+ return task.readonly === true || task.taskMode === "live_debug_readonly";
4774
+ }
4703
4775
  function hasNegationBefore(text, matchIndex) {
4704
4776
  const before = text.slice(0, matchIndex);
4705
4777
  const clauseStart = Math.max(
@@ -4885,13 +4957,11 @@ function normalizeMeshTaskMode(value) {
4885
4957
  const normalized = value.trim();
4886
4958
  return MESH_TASK_MODES.includes(normalized) ? normalized : void 0;
4887
4959
  }
4888
- function validateMeshTaskModeRequest(mode, message) {
4960
+ function validateMeshTaskModeRequest(mode, message, readonly) {
4889
4961
  const taskMode = normalizeMeshTaskMode(mode);
4890
- if (!taskMode) {
4891
- return { valid: true, violations: [] };
4892
- }
4893
- if (taskMode !== "live_debug_readonly") {
4894
- return { valid: true, taskMode, violations: [] };
4962
+ const isReadonly = isTaskReadonly({ readonly, taskMode });
4963
+ if (!isReadonly) {
4964
+ return taskMode ? { valid: true, taskMode, violations: [] } : { valid: true, violations: [] };
4895
4965
  }
4896
4966
  const text = message || "";
4897
4967
  const violations = LIVE_DEBUG_READONLY_FORBIDDEN.filter((rule) => patternHasRealMutation(rule.pattern, text)).map((rule) => rule.label);
@@ -5018,7 +5088,8 @@ function assertNoDependencyCycle(meshId, newTaskId, dependsOn) {
5018
5088
  }
5019
5089
  function enqueueTask(meshId, message, opts) {
5020
5090
  requireMeshHostQueueOwner(opts);
5021
- const modeValidation = validateMeshTaskModeRequest(opts?.taskMode, message);
5091
+ const readonly = opts?.readonly === true;
5092
+ const modeValidation = validateMeshTaskModeRequest(opts?.taskMode, message, readonly);
5022
5093
  if (!modeValidation.valid) {
5023
5094
  throw new Error(`live_debug_readonly_guardrail_violation: forbidden operations (${modeValidation.violations.join(", ")})`);
5024
5095
  }
@@ -5042,6 +5113,7 @@ function enqueueTask(meshId, message, opts) {
5042
5113
  message,
5043
5114
  status: "pending",
5044
5115
  taskMode: modeValidation.taskMode,
5116
+ ...readonly ? { readonly: true } : {},
5045
5117
  targetNodeId: opts?.targetNodeId,
5046
5118
  targetSessionId: opts?.targetSessionId,
5047
5119
  requiredTags: resolvedRequiredTags,
@@ -5060,7 +5132,8 @@ function recordDirectDispatchTask(meshId, message, opts) {
5060
5132
  if (!missionId) return null;
5061
5133
  const taskId = typeof opts.id === "string" ? opts.id.trim() : "";
5062
5134
  if (!taskId) return null;
5063
- const modeValidation = validateMeshTaskModeRequest(opts.taskMode, message);
5135
+ const readonly = opts.readonly === true;
5136
+ const modeValidation = validateMeshTaskModeRequest(opts.taskMode, message, readonly);
5064
5137
  if (!modeValidation.valid) {
5065
5138
  throw new Error(`live_debug_readonly_guardrail_violation: forbidden operations (${modeValidation.violations.join(", ")})`);
5066
5139
  }
@@ -5075,6 +5148,7 @@ function recordDirectDispatchTask(meshId, message, opts) {
5075
5148
  message,
5076
5149
  status: "assigned",
5077
5150
  ...modeValidation.taskMode ? { taskMode: modeValidation.taskMode } : {},
5151
+ ...readonly ? { readonly: true } : {},
5078
5152
  missionId,
5079
5153
  ...opts.assignedNodeId ? { targetNodeId: opts.assignedNodeId, assignedNodeId: opts.assignedNodeId } : {},
5080
5154
  ...opts.assignedSessionId ? { targetSessionId: opts.assignedSessionId, assignedSessionId: opts.assignedSessionId } : {},
@@ -6055,7 +6129,7 @@ var init_mesh_runtime_store = __esm({
6055
6129
  return deps.every((depId) => depStatus.get(depId) === "completed");
6056
6130
  };
6057
6131
  const nodeConflictAllows = (candidate) => {
6058
- if (candidate.taskMode === "live_debug_readonly") return true;
6132
+ if (isTaskReadonly(candidate)) return true;
6059
6133
  return !nodeBusy;
6060
6134
  };
6061
6135
  const nodeIsWorktree = opts?.nodeIsWorktree === true;
@@ -9267,7 +9341,7 @@ var init_mesh_fast_forward = __esm({
9267
9341
  "use strict";
9268
9342
  init_git_status();
9269
9343
  init_git_executor();
9270
- STATUS_OPTIONS = { refreshUpstream: true, includeSubmodules: true, timeoutMs: 15e3 };
9344
+ STATUS_OPTIONS = { refreshUpstream: true, includeSubmodules: true, timeoutMs: 15e3, forceFresh: true };
9271
9345
  }
9272
9346
  });
9273
9347
 
@@ -9667,9 +9741,6 @@ var mesh_scheduling_runtime_exports = {};
9667
9741
  __export(mesh_scheduling_runtime_exports, {
9668
9742
  buildMeshSchedulingRuntime: () => buildMeshSchedulingRuntime
9669
9743
  });
9670
- function isReadonly(task) {
9671
- return task.taskMode === "live_debug_readonly";
9672
- }
9673
9744
  function isAssigned(task) {
9674
9745
  return task.status === "assigned";
9675
9746
  }
@@ -9678,8 +9749,8 @@ function buildMeshSchedulingRuntime(mesh, queue) {
9678
9749
  const maxParallelTasks = resolveMaxParallelTasks(mesh?.policy?.maxParallelTasks);
9679
9750
  const maxReadonlyParallelTasks = resolveMaxReadonlyParallelTasks(maxParallelTasks);
9680
9751
  const assignedTasks = (Array.isArray(queue) ? queue : []).filter(isAssigned);
9681
- const activeWriteAssigned = assignedTasks.filter((t) => !isReadonly(t)).length;
9682
- const activeReadonlyAssigned = assignedTasks.filter(isReadonly).length;
9752
+ const activeWriteAssigned = assignedTasks.filter((t) => !isTaskReadonly(t)).length;
9753
+ const activeReadonlyAssigned = assignedTasks.filter(isTaskReadonly).length;
9683
9754
  const globalWriteCapReached = activeWriteAssigned >= maxParallelTasks;
9684
9755
  const globalReadonlyCapReached = activeReadonlyAssigned >= maxReadonlyParallelTasks;
9685
9756
  const writeAssignedByNode = /* @__PURE__ */ new Map();
@@ -9689,7 +9760,7 @@ function buildMeshSchedulingRuntime(mesh, queue) {
9689
9760
  const nodeId = typeof task.assignedNodeId === "string" ? task.assignedNodeId.trim() : "";
9690
9761
  if (!nodeId) continue;
9691
9762
  assignedByNode.set(nodeId, (assignedByNode.get(nodeId) ?? 0) + 1);
9692
- if (!isReadonly(task)) {
9763
+ if (!isTaskReadonly(task)) {
9693
9764
  writeAssignedByNode.set(nodeId, (writeAssignedByNode.get(nodeId) ?? 0) + 1);
9694
9765
  }
9695
9766
  const provider = typeof task.assignedProviderType === "string" ? task.assignedProviderType : "";
@@ -9762,6 +9833,7 @@ var init_mesh_scheduling_runtime = __esm({
9762
9833
  "use strict";
9763
9834
  init_repo_mesh_types();
9764
9835
  init_dist();
9836
+ init_mesh_work_queue();
9765
9837
  }
9766
9838
  });
9767
9839
 
@@ -12161,10 +12233,10 @@ function resolveAutoLaunchTarget(components, node) {
12161
12233
  return { mode: "remote", daemonId, coordinatorDaemonId };
12162
12234
  }
12163
12235
  function activeWriteAssignedCount(meshId) {
12164
- return getQueue(meshId, { status: ["assigned"] }).filter((task) => task.taskMode !== "live_debug_readonly").length;
12236
+ return getQueue(meshId, { status: ["assigned"] }).filter((task) => !isTaskReadonly(task)).length;
12165
12237
  }
12166
12238
  function activeReadonlyAssignedCount(meshId) {
12167
- return getQueue(meshId, { status: ["assigned"] }).filter((task) => task.taskMode === "live_debug_readonly").length;
12239
+ return getQueue(meshId, { status: ["assigned"] }).filter(isTaskReadonly).length;
12168
12240
  }
12169
12241
  function nodeHasActiveAssignment(meshId, nodeId) {
12170
12242
  return getQueue(meshId, { status: ["assigned"] }).some((task) => task.assignedNodeId === nodeId);
@@ -12340,8 +12412,8 @@ async function maybeAutoLaunchOneQueueSession(components, meshId, mesh) {
12340
12412
  );
12341
12413
  const maxReadonlyParallelTasks = resolveMaxReadonlyParallelTasks(maxParallelTasks, schedulingOverride?.readonlyMultiplier);
12342
12414
  for (const task of pending) {
12343
- const isReadonly2 = task.taskMode === "live_debug_readonly";
12344
- if (isReadonly2) {
12415
+ const isReadonly = isTaskReadonly(task);
12416
+ if (isReadonly) {
12345
12417
  if (activeReadonlyAssignedCount(meshId) >= maxReadonlyParallelTasks) {
12346
12418
  markAutoLaunch(meshId, task.id, { status: "skipped", reason: "max_readonly_parallel_tasks_reached" });
12347
12419
  continue;
@@ -12423,7 +12495,7 @@ async function maybeAutoLaunchOneQueueSession(components, meshId, mesh) {
12423
12495
  sweepExpiredCooldowns();
12424
12496
  continue;
12425
12497
  }
12426
- if (task.taskMode !== "live_debug_readonly" && nodeHasActiveAssignment(meshId, nodeId)) {
12498
+ if (!isTaskReadonly(task) && nodeHasActiveAssignment(meshId, nodeId)) {
12427
12499
  markAutoLaunch(meshId, task.id, { status: "skipped", reason: "node_has_active_assignment", nodeId });
12428
12500
  continue;
12429
12501
  }
@@ -13171,6 +13243,9 @@ function isModuleNotFoundError(error, ref) {
13171
13243
  const code = "code" in error ? error.code : void 0;
13172
13244
  return code === "MODULE_NOT_FOUND" && message.includes(ref);
13173
13245
  }
13246
+ function runtimeTriplet() {
13247
+ return `${process.platform}-${process.arch}-node${process.versions.modules}`;
13248
+ }
13174
13249
  function normalizeBinding(mod, ref) {
13175
13250
  const binding = mod?.default?.createTerminal ? mod.default : mod?.createTerminal ? mod : null;
13176
13251
  if (!binding) {
@@ -13205,7 +13280,7 @@ function loadGhosttyVtBinding() {
13205
13280
  }
13206
13281
  cachedBinding = null;
13207
13282
  cachedBindingError = new Error(
13208
- `ghostty-vt binding unavailable (${errors.join("; ") || "no candidates tried"})`
13283
+ `ghostty-vt binding unavailable for runtime ${runtimeTriplet()} (${errors.join("; ") || "no candidates tried"})`
13209
13284
  );
13210
13285
  throw cachedBindingError;
13211
13286
  }
@@ -16379,11 +16454,8 @@ function resolveTunedReconcileMs(envName, def, min, max) {
16379
16454
  }
16380
16455
  return def;
16381
16456
  }
16382
- function resolveMinIdleSettleMs() {
16383
- return resolveTunedReconcileMs("MESH_INFLIGHT_MIN_IDLE_SETTLE_MS", 16e3, 0, 12e4);
16384
- }
16385
- function resolveAckedTurnSettleMs() {
16386
- return resolveTunedReconcileMs("MESH_INFLIGHT_ACKED_TURN_SETTLE_MS", 2e4, 0, 18e4);
16457
+ function resolveAckedDeathDeadlineMs() {
16458
+ return resolveTunedReconcileMs("MESH_INFLIGHT_ACKED_DEATH_DEADLINE_MS", 8 * 6e4, 0, 60 * 6e4);
16387
16459
  }
16388
16460
  function inFlightSynthKey(meshId, taskId) {
16389
16461
  return `${meshId}::${taskId}`;
@@ -16994,9 +17066,9 @@ async function reconcileUnterminatedDirectDispatches(components, mesh, selfIds,
16994
17066
  const activeTaskKeys = new Set(
16995
17067
  dispatches.map((d) => readNonEmptyString2(d.taskId)).filter(Boolean).map((taskId) => inFlightSynthKey(mesh.id, taskId))
16996
17068
  );
16997
- for (const key of inFlightIdleObservationCounts.keys()) {
17069
+ for (const key of inFlightAckedHoldState.keys()) {
16998
17070
  if (key.startsWith(`${mesh.id}::`) && !activeTaskKeys.has(key)) {
16999
- inFlightIdleObservationCounts.delete(key);
17071
+ inFlightAckedHoldState.delete(key);
17000
17072
  }
17001
17073
  }
17002
17074
  const dispatchMeshCommand = components.dispatchMeshCommand;
@@ -17017,49 +17089,61 @@ async function reconcileUnterminatedDirectDispatches(components, mesh, selfIds,
17017
17089
  ...node?.workspace ? { workspace: node.workspace } : {},
17018
17090
  ...providerType ? { agentType: providerType, providerType } : {}
17019
17091
  };
17092
+ const synthKey = inFlightSynthKey(mesh.id, taskId);
17093
+ const isAcked = dispatch.status === "acked";
17020
17094
  let payload = null;
17095
+ let readFailed = false;
17021
17096
  try {
17022
17097
  if (isLocalNode) {
17023
17098
  const result = await components.commandHandler.handle("read_chat", readArgs);
17024
- if (result && result.success === false) continue;
17025
- payload = unwrapReadChatPayload(result);
17099
+ if (result && result.success === false) {
17100
+ readFailed = true;
17101
+ } else {
17102
+ payload = unwrapReadChatPayload(result);
17103
+ }
17026
17104
  } else if (dispatchMeshCommand) {
17027
17105
  const result = await dispatchMeshCommand(nodeDaemonId, "read_chat", readArgs);
17028
17106
  payload = unwrapReadChatPayload(result);
17029
- if (payload && payload.success === false) continue;
17107
+ if (payload && payload.success === false) {
17108
+ payload = null;
17109
+ readFailed = true;
17110
+ }
17030
17111
  } else {
17031
17112
  continue;
17032
17113
  }
17033
17114
  } catch {
17115
+ readFailed = true;
17116
+ }
17117
+ if (!payload && !readFailed) continue;
17118
+ if (readFailed || !payload) {
17119
+ if (isAcked) {
17120
+ const prior = inFlightAckedHoldState.get(synthKey);
17121
+ const failures = (prior?.consecutiveReadFailures ?? 0) + 1;
17122
+ const liveConfirmedSinceAck = prior?.liveConfirmedSinceAck ?? false;
17123
+ inFlightAckedHoldState.set(synthKey, { liveConfirmedSinceAck, consecutiveReadFailures: failures });
17124
+ if (liveConfirmedSinceAck && failures >= ACKED_DEATH_CONSECUTIVE_READ_FAILURES) {
17125
+ 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`);
17126
+ }
17127
+ }
17034
17128
  continue;
17035
17129
  }
17036
- if (!payload) continue;
17037
- const synthKey = inFlightSynthKey(mesh.id, taskId);
17130
+ inFlightAckedHoldState.set(synthKey, { liveConfirmedSinceAck: true, consecutiveReadFailures: 0 });
17038
17131
  const nowMs = Date.now();
17039
17132
  if (readChatPayloadStatus(payload) !== "idle") {
17040
- inFlightIdleObservationCounts.delete(synthKey);
17041
17133
  continue;
17042
17134
  }
17043
- if (dispatch.status === "acked") {
17044
- const prior = inFlightIdleObservationCounts.get(synthKey);
17045
- const firstIdleAtMs = prior?.firstIdleAtMs ?? nowMs;
17046
- const idleStreak = (prior?.count ?? 0) + 1;
17047
- inFlightIdleObservationCounts.set(synthKey, { count: idleStreak, firstIdleAtMs });
17048
- const idleSettleMs = nowMs - firstIdleAtMs;
17049
- const minIdleSettleMs = resolveMinIdleSettleMs();
17050
- const ackedTurnSettleMs = resolveAckedTurnSettleMs();
17135
+ if (isAcked) {
17051
17136
  const ackedAtMs = Date.parse(readNonEmptyString2(dispatch.updatedAt));
17052
17137
  const sinceAckMs = Number.isFinite(ackedAtMs) ? nowMs - ackedAtMs : Number.POSITIVE_INFINITY;
17053
- const tickGuardMet = idleStreak >= REQUIRED_CONSECUTIVE_IDLE_TICKS_FOR_INFLIGHT_SYNTH;
17054
- const settleGuardMet = idleSettleMs >= minIdleSettleMs;
17055
- const ackGuardMet = sinceAckMs >= ackedTurnSettleMs;
17056
- if (!tickGuardMet || !settleGuardMet || !ackGuardMet) {
17057
- 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)`);
17138
+ const deathDeadlineMs = resolveAckedDeathDeadlineMs();
17139
+ if (sinceAckMs < deathDeadlineMs) {
17140
+ 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.`);
17058
17141
  continue;
17059
17142
  }
17143
+ 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).`);
17060
17144
  }
17061
17145
  if (realTerminalEmitPendingForTask(mesh.id, taskId)) {
17062
- inFlightIdleObservationCounts.delete(synthKey);
17146
+ inFlightAckedHoldState.delete(synthKey);
17063
17147
  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`);
17064
17148
  continue;
17065
17149
  }
@@ -17081,7 +17165,7 @@ async function reconcileUnterminatedDirectDispatches(components, mesh, selfIds,
17081
17165
  }
17082
17166
  const reprobeStatus = await reprobeWorkerStatus(components, { isLocalNode, nodeDaemonId, readArgs });
17083
17167
  if (reprobeStatus && reprobeStatus !== "idle") {
17084
- inFlightIdleObservationCounts.delete(synthKey);
17168
+ inFlightAckedHoldState.delete(synthKey);
17085
17169
  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`);
17086
17170
  continue;
17087
17171
  }
@@ -17223,7 +17307,7 @@ function setupMeshReconcileLoop(components) {
17223
17307
  }
17224
17308
  };
17225
17309
  }
17226
- 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;
17310
+ 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;
17227
17311
  var init_mesh_reconcile_loop = __esm({
17228
17312
  "src/mesh/mesh-reconcile-loop.ts"() {
17229
17313
  "use strict";
@@ -17245,8 +17329,8 @@ var init_mesh_reconcile_loop = __esm({
17245
17329
  init_chat_message_normalization();
17246
17330
  DEFAULT_RECONCILE_INTERVAL_MS = 4e3;
17247
17331
  DEFAULT_AUTO_PRUNE_MIN_AGE_MS = 24 * 60 * 6e4;
17248
- REQUIRED_CONSECUTIVE_IDLE_TICKS_FOR_INFLIGHT_SYNTH = 2;
17249
- inFlightIdleObservationCounts = /* @__PURE__ */ new Map();
17332
+ ACKED_DEATH_CONSECUTIVE_READ_FAILURES = 3;
17333
+ inFlightAckedHoldState = /* @__PURE__ */ new Map();
17250
17334
  coordinatorModalParkState = /* @__PURE__ */ new Map();
17251
17335
  heldEventLedgerRecorded = /* @__PURE__ */ new Set();
17252
17336
  ASSIGNED_STRANDED_DEADLINE_MS = 5 * 6e4;
@@ -23138,6 +23222,7 @@ __export(index_exports, {
23138
23222
  isSessionHostLiveRuntime: () => isSessionHostLiveRuntime,
23139
23223
  isSessionHostRecoverySnapshot: () => isSessionHostRecoverySnapshot,
23140
23224
  isSetupComplete: () => isSetupComplete,
23225
+ isTaskReadonly: () => isTaskReadonly,
23141
23226
  isUserFacingChatMessage: () => isUserFacingChatMessage,
23142
23227
  killIdeProcess: () => killIdeProcess,
23143
23228
  launchIDE: () => launchIDE,
@@ -24229,7 +24314,7 @@ function validateMutatingMessage(value) {
24229
24314
  async function gitCheckpoint(workspace, message, includeUntracked) {
24230
24315
  const repo = await resolveGitRepository(workspace);
24231
24316
  const repoRoot = repo.repoRoot;
24232
- const statusResult = await getGitRepoStatus(workspace);
24317
+ const statusResult = await getGitRepoStatus(workspace, { forceFresh: true });
24233
24318
  if (statusResult.hasConflicts) {
24234
24319
  throw new GitCommandError("conflict", "Repository has conflicts \u2014 resolve before checkpointing");
24235
24320
  }
@@ -53025,7 +53110,10 @@ async function alignRefinerySubmodulesAfterMerge(repoRoot, previousBaseHead, cur
53025
53110
  const preStatus = await getGitRepoStatus(repoRoot, {
53026
53111
  includeSubmodules: true,
53027
53112
  submoduleIgnorePaths: options.submoduleIgnorePaths,
53028
- timeoutMs: 15e3
53113
+ timeoutMs: 15e3,
53114
+ // Decision path — the out-of-sync submodule set drives a mutating `submodule
53115
+ // update`. Must not act on a TTL-cached status; bypass the C1 cache.
53116
+ forceFresh: true
53029
53117
  });
53030
53118
  const outOfSyncPaths = (preStatus.submodules || []).filter((submodule) => submodule.dirty || submodule.outOfSync || !!submodule.error).map((submodule) => submodule.path);
53031
53119
  const updatePaths = [.../* @__PURE__ */ new Set([...changedGitlinkPaths, ...outOfSyncPaths])].sort();
@@ -53054,7 +53142,10 @@ async function alignRefinerySubmodulesAfterMerge(repoRoot, previousBaseHead, cur
53054
53142
  const postStatus = await getGitRepoStatus(repoRoot, {
53055
53143
  includeSubmodules: true,
53056
53144
  submoduleIgnorePaths: options.submoduleIgnorePaths,
53057
- timeoutMs: 15e3
53145
+ timeoutMs: 15e3,
53146
+ // Re-read AFTER `submodule update` mutated the tree — MUST be fresh, never the
53147
+ // cached preStatus from moments ago (which would falsely report still-dirty).
53148
+ forceFresh: true
53058
53149
  });
53059
53150
  const remaining = (postStatus.submodules || []).filter((submodule) => updatePaths.includes(submodule.path) && (submodule.dirty || submodule.outOfSync || !!submodule.error));
53060
53151
  return {
@@ -64503,6 +64594,7 @@ var V1_CONTRACT_VERSION = "1.0.0";
64503
64594
  isSessionHostLiveRuntime,
64504
64595
  isSessionHostRecoverySnapshot,
64505
64596
  isSetupComplete,
64597
+ isTaskReadonly,
64506
64598
  isUserFacingChatMessage,
64507
64599
  killIdeProcess,
64508
64600
  launchIDE,