@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.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
|
}
|
|
@@ -16371,6 +16446,17 @@ function resolveReconcileIntervalMs() {
|
|
|
16371
16446
|
}
|
|
16372
16447
|
return DEFAULT_RECONCILE_INTERVAL_MS;
|
|
16373
16448
|
}
|
|
16449
|
+
function resolveTunedReconcileMs(envName, def, min, max) {
|
|
16450
|
+
const raw = readNonEmptyString2(process.env[envName]);
|
|
16451
|
+
if (raw) {
|
|
16452
|
+
const parsed = Number.parseInt(raw, 10);
|
|
16453
|
+
if (Number.isFinite(parsed) && parsed >= min && parsed <= max) return parsed;
|
|
16454
|
+
}
|
|
16455
|
+
return def;
|
|
16456
|
+
}
|
|
16457
|
+
function resolveAckedDeathDeadlineMs() {
|
|
16458
|
+
return resolveTunedReconcileMs("MESH_INFLIGHT_ACKED_DEATH_DEADLINE_MS", 8 * 6e4, 0, 60 * 6e4);
|
|
16459
|
+
}
|
|
16374
16460
|
function inFlightSynthKey(meshId, taskId) {
|
|
16375
16461
|
return `${meshId}::${taskId}`;
|
|
16376
16462
|
}
|
|
@@ -16947,15 +17033,42 @@ function unwrapReadChatPayload(raw) {
|
|
|
16947
17033
|
function readChatPayloadStatus(payload) {
|
|
16948
17034
|
return readNonEmptyString2(payload?.status).toLowerCase();
|
|
16949
17035
|
}
|
|
17036
|
+
function realTerminalEmitPendingForTask(meshId, taskId) {
|
|
17037
|
+
let pending;
|
|
17038
|
+
try {
|
|
17039
|
+
pending = getPendingMeshCoordinatorEvents(meshId);
|
|
17040
|
+
} catch {
|
|
17041
|
+
return false;
|
|
17042
|
+
}
|
|
17043
|
+
return pending.some((e) => readNonEmptyString2(e.metadataEvent?.taskId) === taskId && (e.event === "agent:generating_completed" || e.event === "agent:stopped"));
|
|
17044
|
+
}
|
|
17045
|
+
async function reprobeWorkerStatus(components, args) {
|
|
17046
|
+
try {
|
|
17047
|
+
if (args.isLocalNode) {
|
|
17048
|
+
const r = await components.commandHandler.handle("read_chat", args.readArgs);
|
|
17049
|
+
if (r && r.success === false) return null;
|
|
17050
|
+
return readChatPayloadStatus(unwrapReadChatPayload(r));
|
|
17051
|
+
}
|
|
17052
|
+
if (components.dispatchMeshCommand) {
|
|
17053
|
+
const r = await components.dispatchMeshCommand(args.nodeDaemonId, "read_chat", args.readArgs);
|
|
17054
|
+
const p = unwrapReadChatPayload(r);
|
|
17055
|
+
if (p && p.success === false) return null;
|
|
17056
|
+
return readChatPayloadStatus(p);
|
|
17057
|
+
}
|
|
17058
|
+
} catch {
|
|
17059
|
+
return null;
|
|
17060
|
+
}
|
|
17061
|
+
return null;
|
|
17062
|
+
}
|
|
16950
17063
|
async function reconcileUnterminatedDirectDispatches(components, mesh, selfIds, localDaemonId) {
|
|
16951
17064
|
const dispatches = getActiveDirectDispatches(mesh.id);
|
|
16952
17065
|
if (dispatches.length === 0) return;
|
|
16953
17066
|
const activeTaskKeys = new Set(
|
|
16954
17067
|
dispatches.map((d) => readNonEmptyString2(d.taskId)).filter(Boolean).map((taskId) => inFlightSynthKey(mesh.id, taskId))
|
|
16955
17068
|
);
|
|
16956
|
-
for (const key of
|
|
17069
|
+
for (const key of inFlightAckedHoldState.keys()) {
|
|
16957
17070
|
if (key.startsWith(`${mesh.id}::`) && !activeTaskKeys.has(key)) {
|
|
16958
|
-
|
|
17071
|
+
inFlightAckedHoldState.delete(key);
|
|
16959
17072
|
}
|
|
16960
17073
|
}
|
|
16961
17074
|
const dispatchMeshCommand = components.dispatchMeshCommand;
|
|
@@ -16976,35 +17089,63 @@ async function reconcileUnterminatedDirectDispatches(components, mesh, selfIds,
|
|
|
16976
17089
|
...node?.workspace ? { workspace: node.workspace } : {},
|
|
16977
17090
|
...providerType ? { agentType: providerType, providerType } : {}
|
|
16978
17091
|
};
|
|
17092
|
+
const synthKey = inFlightSynthKey(mesh.id, taskId);
|
|
17093
|
+
const isAcked = dispatch.status === "acked";
|
|
16979
17094
|
let payload = null;
|
|
17095
|
+
let readFailed = false;
|
|
16980
17096
|
try {
|
|
16981
17097
|
if (isLocalNode) {
|
|
16982
17098
|
const result = await components.commandHandler.handle("read_chat", readArgs);
|
|
16983
|
-
if (result && result.success === false)
|
|
16984
|
-
|
|
17099
|
+
if (result && result.success === false) {
|
|
17100
|
+
readFailed = true;
|
|
17101
|
+
} else {
|
|
17102
|
+
payload = unwrapReadChatPayload(result);
|
|
17103
|
+
}
|
|
16985
17104
|
} else if (dispatchMeshCommand) {
|
|
16986
17105
|
const result = await dispatchMeshCommand(nodeDaemonId, "read_chat", readArgs);
|
|
16987
17106
|
payload = unwrapReadChatPayload(result);
|
|
16988
|
-
if (payload && payload.success === false)
|
|
17107
|
+
if (payload && payload.success === false) {
|
|
17108
|
+
payload = null;
|
|
17109
|
+
readFailed = true;
|
|
17110
|
+
}
|
|
16989
17111
|
} else {
|
|
16990
17112
|
continue;
|
|
16991
17113
|
}
|
|
16992
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
|
+
}
|
|
16993
17128
|
continue;
|
|
16994
17129
|
}
|
|
16995
|
-
|
|
16996
|
-
const
|
|
17130
|
+
inFlightAckedHoldState.set(synthKey, { liveConfirmedSinceAck: true, consecutiveReadFailures: 0 });
|
|
17131
|
+
const nowMs = Date.now();
|
|
16997
17132
|
if (readChatPayloadStatus(payload) !== "idle") {
|
|
16998
|
-
inFlightIdleObservationCounts.delete(synthKey);
|
|
16999
17133
|
continue;
|
|
17000
17134
|
}
|
|
17001
|
-
if (
|
|
17002
|
-
const
|
|
17003
|
-
|
|
17004
|
-
|
|
17005
|
-
|
|
17135
|
+
if (isAcked) {
|
|
17136
|
+
const ackedAtMs = Date.parse(readNonEmptyString2(dispatch.updatedAt));
|
|
17137
|
+
const sinceAckMs = Number.isFinite(ackedAtMs) ? nowMs - ackedAtMs : Number.POSITIVE_INFINITY;
|
|
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.`);
|
|
17006
17141
|
continue;
|
|
17007
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).`);
|
|
17144
|
+
}
|
|
17145
|
+
if (realTerminalEmitPendingForTask(mesh.id, taskId)) {
|
|
17146
|
+
inFlightAckedHoldState.delete(synthKey);
|
|
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`);
|
|
17148
|
+
continue;
|
|
17008
17149
|
}
|
|
17009
17150
|
const messages = Array.isArray(payload.messages) ? payload.messages : [];
|
|
17010
17151
|
const evidence = extractFinalAssistantSummaryEvidence(messages);
|
|
@@ -17022,6 +17163,12 @@ async function reconcileUnterminatedDirectDispatches(components, mesh, selfIds,
|
|
|
17022
17163
|
}, `transcriptAt=${evidence.transcriptMessageAt} < dispatchedAt=${dispatch.dispatchedAt}`);
|
|
17023
17164
|
continue;
|
|
17024
17165
|
}
|
|
17166
|
+
const reprobeStatus = await reprobeWorkerStatus(components, { isLocalNode, nodeDaemonId, readArgs });
|
|
17167
|
+
if (reprobeStatus && reprobeStatus !== "idle") {
|
|
17168
|
+
inFlightAckedHoldState.delete(synthKey);
|
|
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`);
|
|
17170
|
+
continue;
|
|
17171
|
+
}
|
|
17025
17172
|
const providerSessionId = readNonEmptyString2(payload.providerSessionId);
|
|
17026
17173
|
const coordinatorDaemonId = selfIds.find((id) => !!id);
|
|
17027
17174
|
try {
|
|
@@ -17160,7 +17307,7 @@ function setupMeshReconcileLoop(components) {
|
|
|
17160
17307
|
}
|
|
17161
17308
|
};
|
|
17162
17309
|
}
|
|
17163
|
-
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;
|
|
17164
17311
|
var init_mesh_reconcile_loop = __esm({
|
|
17165
17312
|
"src/mesh/mesh-reconcile-loop.ts"() {
|
|
17166
17313
|
"use strict";
|
|
@@ -17182,8 +17329,8 @@ var init_mesh_reconcile_loop = __esm({
|
|
|
17182
17329
|
init_chat_message_normalization();
|
|
17183
17330
|
DEFAULT_RECONCILE_INTERVAL_MS = 4e3;
|
|
17184
17331
|
DEFAULT_AUTO_PRUNE_MIN_AGE_MS = 24 * 60 * 6e4;
|
|
17185
|
-
|
|
17186
|
-
|
|
17332
|
+
ACKED_DEATH_CONSECUTIVE_READ_FAILURES = 3;
|
|
17333
|
+
inFlightAckedHoldState = /* @__PURE__ */ new Map();
|
|
17187
17334
|
coordinatorModalParkState = /* @__PURE__ */ new Map();
|
|
17188
17335
|
heldEventLedgerRecorded = /* @__PURE__ */ new Set();
|
|
17189
17336
|
ASSIGNED_STRANDED_DEADLINE_MS = 5 * 6e4;
|
|
@@ -23075,6 +23222,7 @@ __export(index_exports, {
|
|
|
23075
23222
|
isSessionHostLiveRuntime: () => isSessionHostLiveRuntime,
|
|
23076
23223
|
isSessionHostRecoverySnapshot: () => isSessionHostRecoverySnapshot,
|
|
23077
23224
|
isSetupComplete: () => isSetupComplete,
|
|
23225
|
+
isTaskReadonly: () => isTaskReadonly,
|
|
23078
23226
|
isUserFacingChatMessage: () => isUserFacingChatMessage,
|
|
23079
23227
|
killIdeProcess: () => killIdeProcess,
|
|
23080
23228
|
launchIDE: () => launchIDE,
|
|
@@ -24166,7 +24314,7 @@ function validateMutatingMessage(value) {
|
|
|
24166
24314
|
async function gitCheckpoint(workspace, message, includeUntracked) {
|
|
24167
24315
|
const repo = await resolveGitRepository(workspace);
|
|
24168
24316
|
const repoRoot = repo.repoRoot;
|
|
24169
|
-
const statusResult = await getGitRepoStatus(workspace);
|
|
24317
|
+
const statusResult = await getGitRepoStatus(workspace, { forceFresh: true });
|
|
24170
24318
|
if (statusResult.hasConflicts) {
|
|
24171
24319
|
throw new GitCommandError("conflict", "Repository has conflicts \u2014 resolve before checkpointing");
|
|
24172
24320
|
}
|
|
@@ -52962,7 +53110,10 @@ async function alignRefinerySubmodulesAfterMerge(repoRoot, previousBaseHead, cur
|
|
|
52962
53110
|
const preStatus = await getGitRepoStatus(repoRoot, {
|
|
52963
53111
|
includeSubmodules: true,
|
|
52964
53112
|
submoduleIgnorePaths: options.submoduleIgnorePaths,
|
|
52965
|
-
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
|
|
52966
53117
|
});
|
|
52967
53118
|
const outOfSyncPaths = (preStatus.submodules || []).filter((submodule) => submodule.dirty || submodule.outOfSync || !!submodule.error).map((submodule) => submodule.path);
|
|
52968
53119
|
const updatePaths = [.../* @__PURE__ */ new Set([...changedGitlinkPaths, ...outOfSyncPaths])].sort();
|
|
@@ -52991,7 +53142,10 @@ async function alignRefinerySubmodulesAfterMerge(repoRoot, previousBaseHead, cur
|
|
|
52991
53142
|
const postStatus = await getGitRepoStatus(repoRoot, {
|
|
52992
53143
|
includeSubmodules: true,
|
|
52993
53144
|
submoduleIgnorePaths: options.submoduleIgnorePaths,
|
|
52994
|
-
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
|
|
52995
53149
|
});
|
|
52996
53150
|
const remaining = (postStatus.submodules || []).filter((submodule) => updatePaths.includes(submodule.path) && (submodule.dirty || submodule.outOfSync || !!submodule.error));
|
|
52997
53151
|
return {
|
|
@@ -64440,6 +64594,7 @@ var V1_CONTRACT_VERSION = "1.0.0";
|
|
|
64440
64594
|
isSessionHostLiveRuntime,
|
|
64441
64595
|
isSessionHostRecoverySnapshot,
|
|
64442
64596
|
isSetupComplete,
|
|
64597
|
+
isTaskReadonly,
|
|
64443
64598
|
isUserFacingChatMessage,
|
|
64444
64599
|
killIdeProcess,
|
|
64445
64600
|
launchIDE,
|