@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/git/git-status.d.ts +34 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +176 -84
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +175 -84
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/mesh-queue-assignment.d.ts +1 -1
- package/dist/mesh/mesh-work-queue.d.ts +35 -1
- package/package.json +2 -2
- package/src/cli-adapters/terminal-backends/ghostty-vt-backend.ts +11 -1
- package/src/git/git-commands.ts +4 -1
- package/src/git/git-status.ts +219 -31
- package/src/index.ts +1 -1
- package/src/mesh/mesh-fast-forward.ts +5 -1
- package/src/mesh/mesh-queue-assignment.ts +8 -8
- package/src/mesh/mesh-reconcile-loop.ts +151 -94
- package/src/mesh/mesh-refine-gates.ts +6 -0
- package/src/mesh/mesh-runtime-store.ts +6 -5
- package/src/mesh/mesh-scheduling-runtime.ts +4 -7
- package/src/mesh/mesh-work-queue.ts +49 -8
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 ? "
|
|
403
|
-
const commitShort = readInjected(true ? "
|
|
404
|
-
const version = readInjected(true ? "0.9.82-rc.
|
|
405
|
-
const builtAt = readInjected(true ? "2026-06-
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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)
|
|
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
|
-
|
|
821
|
-
const
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
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:
|
|
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
|
|
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
|
-
...
|
|
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
|
-
|
|
4891
|
-
|
|
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
|
|
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
|
|
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
|
|
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) => !
|
|
9682
|
-
const activeReadonlyAssigned = assignedTasks.filter(
|
|
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 (!
|
|
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
|
|
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(
|
|
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
|
|
12344
|
-
if (
|
|
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
|
|
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
|
|
16383
|
-
return resolveTunedReconcileMs("
|
|
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
|
|
17069
|
+
for (const key of inFlightAckedHoldState.keys()) {
|
|
16998
17070
|
if (key.startsWith(`${mesh.id}::`) && !activeTaskKeys.has(key)) {
|
|
16999
|
-
|
|
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)
|
|
17025
|
-
|
|
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)
|
|
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
|
-
|
|
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 (
|
|
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
|
|
17054
|
-
|
|
17055
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
17249
|
-
|
|
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,
|