@adhdev/daemon-core 0.9.82-rc.406 → 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 +224 -69
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +223 -69
- 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 +219 -47
- 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.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 ? "
|
|
398
|
-
const commitShort = readInjected(true ? "
|
|
399
|
-
const version = readInjected(true ? "0.9.82-rc.
|
|
400
|
-
const builtAt = readInjected(true ? "2026-06-
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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)
|
|
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
|
-
|
|
816
|
-
const
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
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:
|
|
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
|
|
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
|
-
...
|
|
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
|
-
|
|
4885
|
-
|
|
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
|
|
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
|
|
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
|
|
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) => !
|
|
9675
|
-
const activeReadonlyAssigned = assignedTasks.filter(
|
|
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 (!
|
|
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
|
|
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(
|
|
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
|
|
12340
|
-
if (
|
|
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
|
|
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
|
}
|
|
@@ -16366,6 +16441,17 @@ function resolveReconcileIntervalMs() {
|
|
|
16366
16441
|
}
|
|
16367
16442
|
return DEFAULT_RECONCILE_INTERVAL_MS;
|
|
16368
16443
|
}
|
|
16444
|
+
function resolveTunedReconcileMs(envName, def, min, max) {
|
|
16445
|
+
const raw = readNonEmptyString2(process.env[envName]);
|
|
16446
|
+
if (raw) {
|
|
16447
|
+
const parsed = Number.parseInt(raw, 10);
|
|
16448
|
+
if (Number.isFinite(parsed) && parsed >= min && parsed <= max) return parsed;
|
|
16449
|
+
}
|
|
16450
|
+
return def;
|
|
16451
|
+
}
|
|
16452
|
+
function resolveAckedDeathDeadlineMs() {
|
|
16453
|
+
return resolveTunedReconcileMs("MESH_INFLIGHT_ACKED_DEATH_DEADLINE_MS", 8 * 6e4, 0, 60 * 6e4);
|
|
16454
|
+
}
|
|
16369
16455
|
function inFlightSynthKey(meshId, taskId) {
|
|
16370
16456
|
return `${meshId}::${taskId}`;
|
|
16371
16457
|
}
|
|
@@ -16942,15 +17028,42 @@ function unwrapReadChatPayload(raw) {
|
|
|
16942
17028
|
function readChatPayloadStatus(payload) {
|
|
16943
17029
|
return readNonEmptyString2(payload?.status).toLowerCase();
|
|
16944
17030
|
}
|
|
17031
|
+
function realTerminalEmitPendingForTask(meshId, taskId) {
|
|
17032
|
+
let pending;
|
|
17033
|
+
try {
|
|
17034
|
+
pending = getPendingMeshCoordinatorEvents(meshId);
|
|
17035
|
+
} catch {
|
|
17036
|
+
return false;
|
|
17037
|
+
}
|
|
17038
|
+
return pending.some((e) => readNonEmptyString2(e.metadataEvent?.taskId) === taskId && (e.event === "agent:generating_completed" || e.event === "agent:stopped"));
|
|
17039
|
+
}
|
|
17040
|
+
async function reprobeWorkerStatus(components, args) {
|
|
17041
|
+
try {
|
|
17042
|
+
if (args.isLocalNode) {
|
|
17043
|
+
const r = await components.commandHandler.handle("read_chat", args.readArgs);
|
|
17044
|
+
if (r && r.success === false) return null;
|
|
17045
|
+
return readChatPayloadStatus(unwrapReadChatPayload(r));
|
|
17046
|
+
}
|
|
17047
|
+
if (components.dispatchMeshCommand) {
|
|
17048
|
+
const r = await components.dispatchMeshCommand(args.nodeDaemonId, "read_chat", args.readArgs);
|
|
17049
|
+
const p = unwrapReadChatPayload(r);
|
|
17050
|
+
if (p && p.success === false) return null;
|
|
17051
|
+
return readChatPayloadStatus(p);
|
|
17052
|
+
}
|
|
17053
|
+
} catch {
|
|
17054
|
+
return null;
|
|
17055
|
+
}
|
|
17056
|
+
return null;
|
|
17057
|
+
}
|
|
16945
17058
|
async function reconcileUnterminatedDirectDispatches(components, mesh, selfIds, localDaemonId) {
|
|
16946
17059
|
const dispatches = getActiveDirectDispatches(mesh.id);
|
|
16947
17060
|
if (dispatches.length === 0) return;
|
|
16948
17061
|
const activeTaskKeys = new Set(
|
|
16949
17062
|
dispatches.map((d) => readNonEmptyString2(d.taskId)).filter(Boolean).map((taskId) => inFlightSynthKey(mesh.id, taskId))
|
|
16950
17063
|
);
|
|
16951
|
-
for (const key of
|
|
17064
|
+
for (const key of inFlightAckedHoldState.keys()) {
|
|
16952
17065
|
if (key.startsWith(`${mesh.id}::`) && !activeTaskKeys.has(key)) {
|
|
16953
|
-
|
|
17066
|
+
inFlightAckedHoldState.delete(key);
|
|
16954
17067
|
}
|
|
16955
17068
|
}
|
|
16956
17069
|
const dispatchMeshCommand = components.dispatchMeshCommand;
|
|
@@ -16971,35 +17084,63 @@ async function reconcileUnterminatedDirectDispatches(components, mesh, selfIds,
|
|
|
16971
17084
|
...node?.workspace ? { workspace: node.workspace } : {},
|
|
16972
17085
|
...providerType ? { agentType: providerType, providerType } : {}
|
|
16973
17086
|
};
|
|
17087
|
+
const synthKey = inFlightSynthKey(mesh.id, taskId);
|
|
17088
|
+
const isAcked = dispatch.status === "acked";
|
|
16974
17089
|
let payload = null;
|
|
17090
|
+
let readFailed = false;
|
|
16975
17091
|
try {
|
|
16976
17092
|
if (isLocalNode) {
|
|
16977
17093
|
const result = await components.commandHandler.handle("read_chat", readArgs);
|
|
16978
|
-
if (result && result.success === false)
|
|
16979
|
-
|
|
17094
|
+
if (result && result.success === false) {
|
|
17095
|
+
readFailed = true;
|
|
17096
|
+
} else {
|
|
17097
|
+
payload = unwrapReadChatPayload(result);
|
|
17098
|
+
}
|
|
16980
17099
|
} else if (dispatchMeshCommand) {
|
|
16981
17100
|
const result = await dispatchMeshCommand(nodeDaemonId, "read_chat", readArgs);
|
|
16982
17101
|
payload = unwrapReadChatPayload(result);
|
|
16983
|
-
if (payload && payload.success === false)
|
|
17102
|
+
if (payload && payload.success === false) {
|
|
17103
|
+
payload = null;
|
|
17104
|
+
readFailed = true;
|
|
17105
|
+
}
|
|
16984
17106
|
} else {
|
|
16985
17107
|
continue;
|
|
16986
17108
|
}
|
|
16987
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
|
+
}
|
|
16988
17123
|
continue;
|
|
16989
17124
|
}
|
|
16990
|
-
|
|
16991
|
-
const
|
|
17125
|
+
inFlightAckedHoldState.set(synthKey, { liveConfirmedSinceAck: true, consecutiveReadFailures: 0 });
|
|
17126
|
+
const nowMs = Date.now();
|
|
16992
17127
|
if (readChatPayloadStatus(payload) !== "idle") {
|
|
16993
|
-
inFlightIdleObservationCounts.delete(synthKey);
|
|
16994
17128
|
continue;
|
|
16995
17129
|
}
|
|
16996
|
-
if (
|
|
16997
|
-
const
|
|
16998
|
-
|
|
16999
|
-
|
|
17000
|
-
|
|
17130
|
+
if (isAcked) {
|
|
17131
|
+
const ackedAtMs = Date.parse(readNonEmptyString2(dispatch.updatedAt));
|
|
17132
|
+
const sinceAckMs = Number.isFinite(ackedAtMs) ? nowMs - ackedAtMs : Number.POSITIVE_INFINITY;
|
|
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.`);
|
|
17001
17136
|
continue;
|
|
17002
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).`);
|
|
17139
|
+
}
|
|
17140
|
+
if (realTerminalEmitPendingForTask(mesh.id, taskId)) {
|
|
17141
|
+
inFlightAckedHoldState.delete(synthKey);
|
|
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`);
|
|
17143
|
+
continue;
|
|
17003
17144
|
}
|
|
17004
17145
|
const messages = Array.isArray(payload.messages) ? payload.messages : [];
|
|
17005
17146
|
const evidence = extractFinalAssistantSummaryEvidence(messages);
|
|
@@ -17017,6 +17158,12 @@ async function reconcileUnterminatedDirectDispatches(components, mesh, selfIds,
|
|
|
17017
17158
|
}, `transcriptAt=${evidence.transcriptMessageAt} < dispatchedAt=${dispatch.dispatchedAt}`);
|
|
17018
17159
|
continue;
|
|
17019
17160
|
}
|
|
17161
|
+
const reprobeStatus = await reprobeWorkerStatus(components, { isLocalNode, nodeDaemonId, readArgs });
|
|
17162
|
+
if (reprobeStatus && reprobeStatus !== "idle") {
|
|
17163
|
+
inFlightAckedHoldState.delete(synthKey);
|
|
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`);
|
|
17165
|
+
continue;
|
|
17166
|
+
}
|
|
17020
17167
|
const providerSessionId = readNonEmptyString2(payload.providerSessionId);
|
|
17021
17168
|
const coordinatorDaemonId = selfIds.find((id) => !!id);
|
|
17022
17169
|
try {
|
|
@@ -17155,7 +17302,7 @@ function setupMeshReconcileLoop(components) {
|
|
|
17155
17302
|
}
|
|
17156
17303
|
};
|
|
17157
17304
|
}
|
|
17158
|
-
var DEFAULT_RECONCILE_INTERVAL_MS, DEFAULT_AUTO_PRUNE_MIN_AGE_MS,
|
|
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;
|
|
17159
17306
|
var init_mesh_reconcile_loop = __esm({
|
|
17160
17307
|
"src/mesh/mesh-reconcile-loop.ts"() {
|
|
17161
17308
|
"use strict";
|
|
@@ -17177,8 +17324,8 @@ var init_mesh_reconcile_loop = __esm({
|
|
|
17177
17324
|
init_chat_message_normalization();
|
|
17178
17325
|
DEFAULT_RECONCILE_INTERVAL_MS = 4e3;
|
|
17179
17326
|
DEFAULT_AUTO_PRUNE_MIN_AGE_MS = 24 * 60 * 6e4;
|
|
17180
|
-
|
|
17181
|
-
|
|
17327
|
+
ACKED_DEATH_CONSECUTIVE_READ_FAILURES = 3;
|
|
17328
|
+
inFlightAckedHoldState = /* @__PURE__ */ new Map();
|
|
17182
17329
|
coordinatorModalParkState = /* @__PURE__ */ new Map();
|
|
17183
17330
|
heldEventLedgerRecorded = /* @__PURE__ */ new Set();
|
|
17184
17331
|
ASSIGNED_STRANDED_DEADLINE_MS = 5 * 6e4;
|
|
@@ -23785,7 +23932,7 @@ function validateMutatingMessage(value) {
|
|
|
23785
23932
|
async function gitCheckpoint(workspace, message, includeUntracked) {
|
|
23786
23933
|
const repo = await resolveGitRepository(workspace);
|
|
23787
23934
|
const repoRoot = repo.repoRoot;
|
|
23788
|
-
const statusResult = await getGitRepoStatus(workspace);
|
|
23935
|
+
const statusResult = await getGitRepoStatus(workspace, { forceFresh: true });
|
|
23789
23936
|
if (statusResult.hasConflicts) {
|
|
23790
23937
|
throw new GitCommandError("conflict", "Repository has conflicts \u2014 resolve before checkpointing");
|
|
23791
23938
|
}
|
|
@@ -52586,7 +52733,10 @@ async function alignRefinerySubmodulesAfterMerge(repoRoot, previousBaseHead, cur
|
|
|
52586
52733
|
const preStatus = await getGitRepoStatus(repoRoot, {
|
|
52587
52734
|
includeSubmodules: true,
|
|
52588
52735
|
submoduleIgnorePaths: options.submoduleIgnorePaths,
|
|
52589
|
-
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
|
|
52590
52740
|
});
|
|
52591
52741
|
const outOfSyncPaths = (preStatus.submodules || []).filter((submodule) => submodule.dirty || submodule.outOfSync || !!submodule.error).map((submodule) => submodule.path);
|
|
52592
52742
|
const updatePaths = [.../* @__PURE__ */ new Set([...changedGitlinkPaths, ...outOfSyncPaths])].sort();
|
|
@@ -52615,7 +52765,10 @@ async function alignRefinerySubmodulesAfterMerge(repoRoot, previousBaseHead, cur
|
|
|
52615
52765
|
const postStatus = await getGitRepoStatus(repoRoot, {
|
|
52616
52766
|
includeSubmodules: true,
|
|
52617
52767
|
submoduleIgnorePaths: options.submoduleIgnorePaths,
|
|
52618
|
-
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
|
|
52619
52772
|
});
|
|
52620
52773
|
const remaining = (postStatus.submodules || []).filter((submodule) => updatePaths.includes(submodule.path) && (submodule.dirty || submodule.outOfSync || !!submodule.error));
|
|
52621
52774
|
return {
|
|
@@ -64070,6 +64223,7 @@ export {
|
|
|
64070
64223
|
isSessionHostLiveRuntime,
|
|
64071
64224
|
isSessionHostRecoverySnapshot,
|
|
64072
64225
|
isSetupComplete,
|
|
64226
|
+
isTaskReadonly,
|
|
64073
64227
|
isUserFacingChatMessage,
|
|
64074
64228
|
killIdeProcess,
|
|
64075
64229
|
launchIDE,
|